feat: [WIP] generate alt text for ref elements

This commit is contained in:
Tobias Schmitz 2025-07-03 18:38:54 +02:00
parent 254aadccfc
commit 3d4d548934
No known key found for this signature in database
4 changed files with 36 additions and 17 deletions

View File

@ -877,7 +877,7 @@ impl<'a> Generator<'a> {
renderer.display_elem_child(elem, &mut None, false)?; renderer.display_elem_child(elem, &mut None, false)?;
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(accessibility): generate alt text
content = content.linked(dest, None); content = content.linked(dest, None);
} }
StrResult::Ok(content) StrResult::Ok(content)
@ -1013,7 +1013,7 @@ impl ElemRenderer<'_> {
if let Some(hayagriva::ElemMeta::Entry(i)) = elem.meta { if let Some(hayagriva::ElemMeta::Entry(i)) = elem.meta {
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(accessibility): generate alt text
content = content.linked(dest, None); content = content.linked(dest, None);
} }
} }

View File

@ -147,7 +147,7 @@ impl Show for Packed<FootnoteElem> {
let sup = SuperElem::new(num).pack().spanned(span); let sup = SuperElem::new(num).pack().spanned(span);
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(accessibility): generate alt text
Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc), None)) Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc), None))
} }
} }
@ -297,7 +297,7 @@ impl Show for Packed<FootnoteEntry> {
let sup = SuperElem::new(num) let sup = SuperElem::new(num)
.pack() .pack()
.spanned(span) .spanned(span)
// TODO: accept user supplied alt text // TODO(accessibility): generate alt text
.linked(Destination::Location(loc), None) .linked(Destination::Location(loc), None)
.located(loc.variant(1)); .located(loc.variant(1));

View File

@ -2,7 +2,7 @@ use std::num::NonZeroUsize;
use std::str::FromStr; use std::str::FromStr;
use comemo::{Track, Tracked}; use comemo::{Track, Tracked};
use ecow::eco_format; use ecow::{eco_format, EcoString};
use smallvec::SmallVec; use smallvec::SmallVec;
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::{Get, NonZeroExt}; use typst_utils::{Get, NonZeroExt};
@ -23,7 +23,7 @@ use crate::layout::{
}; };
use crate::math::EquationElem; use crate::math::EquationElem;
use crate::model::{Destination, HeadingElem, NumberingPattern, ParElem, Refable}; use crate::model::{Destination, HeadingElem, NumberingPattern, ParElem, Refable};
use crate::text::{LocalName, SpaceElem, TextElem}; use crate::text::{LocalName, SmartQuoteElem, SmartQuotes, SpaceElem, TextElem};
/// A table of contents, figures, or other elements. /// A table of contents, figures, or other elements.
/// ///
@ -435,18 +435,11 @@ impl Show for Packed<OutlineEntry> {
let context = Context::new(None, Some(styles)); let context = Context::new(None, Some(styles));
let context = context.track(); let context = context.track();
// TODO: prefix should be wrapped in a `Lbl` structure element // TODO(accessibility): prefix should be wrapped in a `Lbl` structure element
let prefix = self.prefix(engine, context, span)?; let prefix = self.prefix(engine, context, span)?;
let body = self.body().at(span)?; let body = self.body().at(span)?;
let page = self.page(engine, context, span)?; let page = self.page(engine, context, span)?;
let alt = { let alt = alt_text(styles, &prefix, &body, &page);
// TODO: accept user supplied alt text
let prefix = prefix.as_ref().map(|p| p.plain_text()).unwrap_or_default();
let body = body.plain_text();
let page_str = PageElem::local_name_in(styles);
let page_nr = page.plain_text();
eco_format!("{prefix} \"{body}\", {page_str} {page_nr}")
};
let inner = self.inner(context, span, body, page)?; let inner = self.inner(context, span, body, page)?;
let block = if self.element.is::<EquationElem>() { let block = if self.element.is::<EquationElem>() {
let body = prefix.unwrap_or_default() + inner; let body = prefix.unwrap_or_default() + inner;
@ -704,6 +697,27 @@ cast! {
v: Content => v.unpack::<Self>().map_err(|_| "expected outline entry")? v: Content => v.unpack::<Self>().map_err(|_| "expected outline entry")?
} }
fn alt_text(
styles: StyleChain,
prefix: &Option<Content>,
body: &Content,
page: &Content,
) -> EcoString {
let prefix = prefix.as_ref().map(|p| p.plain_text()).unwrap_or_default();
let body = body.plain_text();
let page_str = PageElem::local_name_in(styles);
let page_nr = page.plain_text();
let quotes = SmartQuotes::get(
SmartQuoteElem::quotes_in(styles),
TextElem::lang_in(styles),
TextElem::region_in(styles),
SmartQuoteElem::alternative_in(styles),
);
let open = quotes.double_open;
let close = quotes.double_close;
eco_format!("{prefix} {open}{body}{close} {page_str} {page_nr}",)
}
/// Measures the width of a prefix. /// Measures the width of a prefix.
fn measure_prefix( fn measure_prefix(
engine: &mut Engine, engine: &mut Engine,

View File

@ -338,13 +338,18 @@ fn show_reference(
Smart::Custom(Some(supplement)) => supplement.resolve(engine, styles, [elem])?, Smart::Custom(Some(supplement)) => supplement.resolve(engine, styles, [elem])?,
}; };
let alt = {
let supplement = supplement.plain_text();
let numbering = numbers.plain_text();
eco_format!("{supplement} {numbering}",)
};
let mut content = numbers; let mut content = numbers;
if !supplement.is_empty() { if !supplement.is_empty() {
content = supplement + TextElem::packed("\u{a0}") + content; content = supplement + TextElem::packed("\u{a0}") + content;
} }
// TODO: accept user supplied alt text Ok(content.linked(Destination::Location(loc), Some(alt)))
Ok(content.linked(Destination::Location(loc), None))
} }
/// Turn a reference into a citation. /// Turn a reference into a citation.