mirror of
https://github.com/typst/typst
synced 2025-06-19 20:02:52 +08:00
WIP [no ci]
This commit is contained in:
parent
4a64a717e8
commit
616c626acb
@ -16,12 +16,12 @@ use crate::diag::{SourceResult, StrResult};
|
|||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
elem, func, scope, ty, Context, Dict, Element, Fields, IntoValue, Label,
|
elem, func, scope, ty, Context, Dict, Element, Fields, IntoValue, Label,
|
||||||
NativeElement, Recipe, RecipeIndex, Repr, Selector, Str, Style, StyleChain, Styles,
|
NativeElement, Recipe, RecipeIndex, Repr, Selector, Show, Str, Style, StyleChain,
|
||||||
Value,
|
Styles, Value,
|
||||||
};
|
};
|
||||||
use crate::introspection::Location;
|
use crate::introspection::{Locatable, Location};
|
||||||
use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides};
|
use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides};
|
||||||
use crate::model::{Destination, EmphElem, LinkElem, StrongElem};
|
use crate::model::{Destination, EmphElem, StrongElem};
|
||||||
use crate::pdf::{ArtifactElem, ArtifactKind};
|
use crate::pdf::{ArtifactElem, ArtifactKind};
|
||||||
use crate::text::UnderlineElem;
|
use crate::text::UnderlineElem;
|
||||||
|
|
||||||
@ -504,9 +504,9 @@ impl Content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Link the content somewhere.
|
/// Link the content somewhere.
|
||||||
pub fn linked(self, alt: Option<EcoString>, dest: Destination) -> Self {
|
pub fn linked(self, dest: Destination, alt: Option<EcoString>) -> Self {
|
||||||
self.styled(LinkElem::set_alt(alt))
|
let span = self.span();
|
||||||
.styled(LinkElem::set_current(Some(dest)))
|
LinkMarker::new(self, dest, alt).pack().spanned(span)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set alignments for this content.
|
/// Set alignments for this content.
|
||||||
@ -988,6 +988,26 @@ pub trait PlainText {
|
|||||||
fn plain_text(&self, text: &mut EcoString);
|
fn plain_text(&self, text: &mut EcoString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: remove `FrameItem::Link` and `FrameModifiers::dest`, then handle links by looking at tags
|
||||||
|
/// An element that associates the body of a link with the destination.
|
||||||
|
#[elem(Show, Locatable)]
|
||||||
|
pub struct LinkMarker {
|
||||||
|
/// The content.
|
||||||
|
#[required]
|
||||||
|
pub body: Content,
|
||||||
|
#[required]
|
||||||
|
pub dest: Destination,
|
||||||
|
#[required]
|
||||||
|
pub alt: Option<EcoString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Show for Packed<LinkMarker> {
|
||||||
|
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
|
||||||
|
Ok(self.body.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An error arising when trying to access a field of content.
|
/// An error arising when trying to access a field of content.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum FieldAccessError {
|
pub enum FieldAccessError {
|
||||||
|
@ -523,6 +523,8 @@ pub struct StyleChain<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StyleChain<'a> {
|
impl<'a> StyleChain<'a> {
|
||||||
|
pub const EMPTY: Self = Self { head: &[], tail: None };
|
||||||
|
|
||||||
/// Start a new style chain with root styles.
|
/// Start a new style chain with root styles.
|
||||||
pub fn new(root: &'a Styles) -> Self {
|
pub fn new(root: &'a Styles) -> Self {
|
||||||
Self { head: &root.0, tail: None }
|
Self { head: &root.0, tail: None }
|
||||||
|
@ -874,7 +874,7 @@ impl<'a> Generator<'a> {
|
|||||||
if let Some(location) = first_occurrences.get(item.key.as_str()) {
|
if let Some(location) = first_occurrences.get(item.key.as_str()) {
|
||||||
let dest = Destination::Location(*location);
|
let dest = Destination::Location(*location);
|
||||||
// TODO: accept user supplied alt text
|
// TODO: accept user supplied alt text
|
||||||
content = content.linked(None, dest);
|
content = content.linked(dest, None);
|
||||||
}
|
}
|
||||||
StrResult::Ok(content)
|
StrResult::Ok(content)
|
||||||
})
|
})
|
||||||
@ -1010,7 +1010,7 @@ impl ElemRenderer<'_> {
|
|||||||
if let Some(location) = (self.link)(i) {
|
if let Some(location) = (self.link)(i) {
|
||||||
let dest = Destination::Location(location);
|
let dest = Destination::Location(location);
|
||||||
// TODO: accept user supplied alt text
|
// TODO: accept user supplied alt text
|
||||||
content = content.linked(None, dest);
|
content = content.linked(dest, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ impl Show for Packed<FootnoteElem> {
|
|||||||
let loc = loc.variant(1);
|
let loc = loc.variant(1);
|
||||||
// Add zero-width weak spacing to make the footnote "sticky".
|
// Add zero-width weak spacing to make the footnote "sticky".
|
||||||
// TODO: accept user supplied alt text
|
// TODO: accept user supplied alt text
|
||||||
Ok(HElem::hole().pack() + sup.linked(None, Destination::Location(loc)))
|
Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc), None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ impl Show for Packed<FootnoteEntry> {
|
|||||||
.pack()
|
.pack()
|
||||||
.spanned(span)
|
.spanned(span)
|
||||||
// TODO: accept user supplied alt text
|
// TODO: accept user supplied alt text
|
||||||
.linked(None, Destination::Location(loc))
|
.linked(Destination::Location(loc), None)
|
||||||
.located(loc.variant(1));
|
.located(loc.variant(1));
|
||||||
|
|
||||||
Ok(Content::sequence([
|
Ok(Content::sequence([
|
||||||
|
@ -91,11 +91,6 @@ pub struct LinkElem {
|
|||||||
_ => args.expect("body")?,
|
_ => args.expect("body")?,
|
||||||
})]
|
})]
|
||||||
pub body: Content,
|
pub body: Content,
|
||||||
|
|
||||||
/// A destination style that should be applied to elements.
|
|
||||||
#[internal]
|
|
||||||
#[ghost]
|
|
||||||
pub current: Option<Destination>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LinkElem {
|
impl LinkElem {
|
||||||
@ -128,11 +123,11 @@ impl Show for Packed<LinkElem> {
|
|||||||
} else {
|
} else {
|
||||||
let alt = self.alt(styles);
|
let alt = self.alt(styles);
|
||||||
match &self.dest {
|
match &self.dest {
|
||||||
LinkTarget::Dest(dest) => body.linked(alt, dest.clone()),
|
LinkTarget::Dest(dest) => body.linked(dest.clone(), alt),
|
||||||
LinkTarget::Label(label) => {
|
LinkTarget::Label(label) => {
|
||||||
let elem = engine.introspector.query_label(*label).at(self.span())?;
|
let elem = engine.introspector.query_label(*label).at(self.span())?;
|
||||||
let dest = Destination::Location(elem.location().unwrap());
|
let dest = Destination::Location(elem.location().unwrap());
|
||||||
body.clone().linked(alt, dest)
|
body.clone().linked(dest, alt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -446,7 +446,7 @@ impl Show for Packed<OutlineEntry> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let loc = self.element_location().at(span)?;
|
let loc = self.element_location().at(span)?;
|
||||||
Ok(block.linked(Some(alt), Destination::Location(loc)))
|
Ok(block.linked(Destination::Location(loc), Some(alt)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ fn show_reference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: accept user supplied alt text
|
// TODO: accept user supplied alt text
|
||||||
Ok(content.linked(None, Destination::Location(loc)))
|
Ok(content.linked(Destination::Location(loc), None))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn a reference into a citation.
|
/// Turn a reference into a citation.
|
||||||
|
@ -30,10 +30,6 @@ pub(crate) fn handle_image(
|
|||||||
|
|
||||||
let interpolate = image.scaling() == Smart::Custom(ImageScaling::Smooth);
|
let interpolate = image.scaling() == Smart::Custom(ImageScaling::Smooth);
|
||||||
|
|
||||||
if let Some(alt) = image.alt() {
|
|
||||||
surface.start_alt_text(alt);
|
|
||||||
}
|
|
||||||
|
|
||||||
gc.image_spans.insert(span);
|
gc.image_spans.insert(span);
|
||||||
|
|
||||||
match image.kind() {
|
match image.kind() {
|
||||||
@ -62,10 +58,6 @@ pub(crate) fn handle_image(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if image.alt().is_some() {
|
|
||||||
surface.end_alt_text();
|
|
||||||
}
|
|
||||||
|
|
||||||
surface.pop();
|
surface.pop();
|
||||||
surface.reset_location();
|
surface.reset_location();
|
||||||
|
|
||||||
|
@ -9,10 +9,11 @@ use krilla::tagging::{
|
|||||||
use typst_library::foundations::{Content, StyleChain};
|
use typst_library::foundations::{Content, StyleChain};
|
||||||
use typst_library::introspection::Location;
|
use typst_library::introspection::Location;
|
||||||
use typst_library::model::{
|
use typst_library::model::{
|
||||||
CiteElem, FigureCaption, FigureElem, HeadingElem, LinkElem, OutlineElem,
|
CiteElem, FigureCaption, FigureElem, HeadingElem, LinkElem, Outlinable, OutlineElem,
|
||||||
OutlineEntry, RefElem,
|
OutlineEntry, RefElem,
|
||||||
};
|
};
|
||||||
use typst_library::pdf::{ArtifactElem, ArtifactKind, PdfTagElem, PdfTagKind};
|
use typst_library::pdf::{ArtifactElem, ArtifactKind, PdfTagElem, PdfTagKind};
|
||||||
|
use typst_library::visualize::ImageElem;
|
||||||
|
|
||||||
use crate::convert::GlobalContext;
|
use crate::convert::GlobalContext;
|
||||||
|
|
||||||
@ -177,7 +178,7 @@ pub(crate) fn handle_start(
|
|||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
} else if let Some(heading) = elem.to_packed::<HeadingElem>() {
|
} else if let Some(heading) = elem.to_packed::<HeadingElem>() {
|
||||||
let level = heading.resolve_level(StyleChain::default());
|
let level = heading.level();
|
||||||
let name = heading.body.plain_text().to_string();
|
let name = heading.body.plain_text().to_string();
|
||||||
match level.get() {
|
match level.get() {
|
||||||
1 => Tag::H1(Some(name)),
|
1 => Tag::H1(Some(name)),
|
||||||
@ -195,6 +196,25 @@ pub(crate) fn handle_start(
|
|||||||
} else if let Some(_) = elem.to_packed::<FigureElem>() {
|
} else if let Some(_) = elem.to_packed::<FigureElem>() {
|
||||||
let alt = None; // TODO
|
let alt = None; // TODO
|
||||||
Tag::Figure(alt)
|
Tag::Figure(alt)
|
||||||
|
} else if let Some(image) = elem.to_packed::<ImageElem>() {
|
||||||
|
let alt = image.alt(StyleChain::default()).map(|s| s.to_string());
|
||||||
|
|
||||||
|
end_open(gc, surface);
|
||||||
|
let id = surface.start_tagged(ContentTag::Other);
|
||||||
|
let mut node = TagNode::Leaf(id);
|
||||||
|
|
||||||
|
if let Some(Tag::Figure(alt_text)) = gc.tags.parent().0 {
|
||||||
|
// HACK: set alt text of outer figure tag, if the contained image
|
||||||
|
// has alt text specified
|
||||||
|
if alt_text.is_none() {
|
||||||
|
*alt_text = alt;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node = TagNode::Group(Tag::Figure(alt), vec![node]);
|
||||||
|
}
|
||||||
|
gc.tags.push(node);
|
||||||
|
|
||||||
|
return;
|
||||||
} else if let Some(_) = elem.to_packed::<FigureCaption>() {
|
} else if let Some(_) = elem.to_packed::<FigureCaption>() {
|
||||||
Tag::Caption
|
Tag::Caption
|
||||||
} else if let Some(_) = elem.to_packed::<LinkElem>() {
|
} else if let Some(_) = elem.to_packed::<LinkElem>() {
|
||||||
@ -212,9 +232,7 @@ pub(crate) fn handle_start(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// close previous marked-content and open a nested tag.
|
// close previous marked-content and open a nested tag.
|
||||||
if !gc.tags.stack.is_empty() {
|
end_open(gc, surface);
|
||||||
surface.end_tagged();
|
|
||||||
}
|
|
||||||
let id = surface.start_tagged(krilla::tagging::ContentTag::Other);
|
let id = surface.start_tagged(krilla::tagging::ContentTag::Other);
|
||||||
gc.tags.stack.push((loc, tag, vec![TagNode::Leaf(id)]));
|
gc.tags.stack.push((loc, tag, vec![TagNode::Leaf(id)]));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user