From 755d46819894f9ad5285526206892471e6e71ef8 Mon Sep 17 00:00:00 2001 From: Martin Haug Date: Wed, 1 Jun 2022 11:43:03 +0200 Subject: [PATCH] Fix inline nodes and decorations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also Code Review 👯‍♂️ --- src/library/text/deco.rs | 3 ++- src/library/text/par.rs | 5 +---- src/library/text/shaping.rs | 24 +++++++++++++----------- src/library/text/shift.rs | 25 +++++++++++-------------- tests/ref/text/baseline.png | Bin 6212 -> 6204 bytes tests/ref/text/shifts.png | Bin 2958 -> 7907 bytes tests/typ/text/shifts.typ | 7 +++++++ 7 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs index cec4ca9ef..c5217e8ef 100644 --- a/src/library/text/deco.rs +++ b/src/library/text/deco.rs @@ -90,6 +90,7 @@ pub fn decorate( deco: &Decoration, fonts: &FontStore, text: &Text, + shift: Length, pos: Point, width: Length, ) { @@ -102,7 +103,7 @@ pub fn decorate( }; let evade = deco.evade && deco.line != STRIKETHROUGH; - let offset = deco.offset.unwrap_or(-metrics.position.at(text.size)); + let offset = deco.offset.unwrap_or(-metrics.position.at(text.size)) - shift; let stroke = deco.stroke.unwrap_or(Stroke { paint: text.fill, thickness: metrics.thickness.at(text.size), diff --git a/src/library/text/par.rs b/src/library/text/par.rs index d86eb175a..695d80667 100644 --- a/src/library/text/par.rs +++ b/src/library/text/par.rs @@ -555,10 +555,7 @@ fn prepare<'a>( let shift = styles.get(TextNode::BASELINE); if !shift.is_zero() { - Arc::make_mut(&mut frame).baseline = Some( - frame.baseline.unwrap_or(frame.size.y) - - styles.get(TextNode::BASELINE), - ); + Arc::make_mut(&mut frame).translate(Point::with_y(shift)); } items.push(Item::Frame(frame)); diff --git a/src/library/text/shaping.rs b/src/library/text/shaping.rs index 67fabbd54..1f3d2f55f 100644 --- a/src/library/text/shaping.rs +++ b/src/library/text/shaping.rs @@ -86,12 +86,17 @@ impl<'a> ShapedText<'a> { let mut frame = Frame::new(size); frame.baseline = Some(top); + let shift = self.styles.get(TextNode::BASELINE); + let lang = self.styles.get(TextNode::LANG); + let decos = self.styles.get(TextNode::DECO); + let fill = self.styles.get(TextNode::FILL); + let link = self.styles.get(TextNode::LINK); + for ((face_id, y_offset), group) in self.glyphs.as_ref().group_by_key(|g| (g.face_id, g.y_offset)) { - let pos = Point::new(offset, top + y_offset.at(self.size)); + let pos = Point::new(offset, top + shift + y_offset.at(self.size)); - let fill = self.styles.get(TextNode::FILL); let glyphs = group .iter() .map(|glyph| Glyph { @@ -111,7 +116,7 @@ impl<'a> ShapedText<'a> { let text = Text { face_id, size: self.size, - lang: self.styles.get(TextNode::LANG), + lang, fill, glyphs, }; @@ -119,8 +124,8 @@ impl<'a> ShapedText<'a> { let width = text.width(); // Apply line decorations. - for deco in self.styles.get(TextNode::DECO) { - decorate(&mut frame, &deco, fonts, &text, pos, width); + for deco in &decos { + decorate(&mut frame, &deco, fonts, &text, shift, pos, width); } frame.insert(text_layer, pos, Element::Text(text)); @@ -128,8 +133,8 @@ impl<'a> ShapedText<'a> { } // Apply link if it exists. - if let Some(url) = self.styles.get(TextNode::LINK) { - frame.link(url.clone()); + if let Some(dest) = link { + frame.link(dest.clone()); } frame @@ -408,8 +413,6 @@ fn shape_segment<'a>( let cluster = info.cluster as usize; if info.glyph_id != 0 { - let baseline_shift = ctx.styles.get(TextNode::BASELINE); - // Add the glyph to the shaped output. // TODO: Don't ignore y_advance. ctx.glyphs.push(ShapedGlyph { @@ -417,8 +420,7 @@ fn shape_segment<'a>( glyph_id: info.glyph_id as u16, x_advance: face.to_em(pos[i].x_advance), x_offset: face.to_em(pos[i].x_offset), - y_offset: face.to_em(pos[i].y_offset) - + Em::from_length(baseline_shift, ctx.size), + y_offset: face.to_em(pos[i].y_offset), cluster: base + cluster, safe_to_break: !info.unsafe_to_break(), c: text[cluster ..].chars().next().unwrap(), diff --git a/src/library/text/shift.rs b/src/library/text/shift.rs index 3efa3720a..4eacd3c8a 100644 --- a/src/library/text/shift.rs +++ b/src/library/text/shift.rs @@ -17,7 +17,7 @@ pub type SuperNode = ShiftNode; /// Shift the text into subscript. pub type SubNode = ShiftNode; -#[node(showable)] +#[node] impl ShiftNode { /// Whether to prefer the dedicated sub- and superscript characters of the font. pub const TYPOGRAPHIC: bool = true; @@ -33,8 +33,8 @@ impl ShiftNode { } impl Show for ShiftNode { - fn unguard(&self, sel: Selector) -> ShowNode { - Self(self.0.unguard(sel)).pack() + fn unguard(&self, _: Selector) -> ShowNode { + Self(self.0.clone()).pack() } fn encode(&self, _: StyleChain) -> Dict { @@ -43,9 +43,9 @@ impl Show for ShiftNode { fn realize(&self, ctx: &mut Context, styles: StyleChain) -> TypResult { let mut transformed = None; - if styles.get(ShiftNode::::TYPOGRAPHIC) { + if styles.get(Self::TYPOGRAPHIC) { if let Some(text) = search_text(&self.0, S) { - if check_str_in_family(&mut ctx.fonts, &text, styles) { + if is_shapable(&mut ctx.fonts, &text, styles) { transformed = Some(Content::Text(text)); } } @@ -53,8 +53,8 @@ impl Show for ShiftNode { Ok(transformed.unwrap_or_else(|| { let mut map = StyleMap::new(); - map.set(TextNode::BASELINE, styles.get(ShiftNode::::BASELINE)); - map.set(TextNode::SIZE, styles.get(ShiftNode::::SIZE)); + map.set(TextNode::BASELINE, styles.get(Self::BASELINE)); + map.set(TextNode::SIZE, styles.get(Self::SIZE)); self.0.clone().styled_with_map(map) })) } @@ -73,9 +73,8 @@ fn search_text(content: &Content, mode: ScriptKind) -> Option { } None } - Content::Space => Some(EcoString::from(" ")), + Content::Space => Some(' '.into()), Content::Empty => Some(EcoString::new()), - Content::Styled(arc) => search_text(&arc.0, mode), Content::Sequence(seq) => { let mut full = EcoString::new(); for item in seq.iter() { @@ -92,11 +91,10 @@ fn search_text(content: &Content, mode: ScriptKind) -> Option { /// Checks whether the first retrievable family contains all code points of the /// given string. -fn check_str_in_family(fonts: &mut FontStore, text: &str, styles: StyleChain) -> bool { +fn is_shapable(fonts: &mut FontStore, text: &str, styles: StyleChain) -> bool { for family in styles.get(TextNode::FAMILY).iter() { if let Some(face_id) = fonts.select(family.as_str(), variant(styles)) { - let face = fonts.get(face_id); - let ttf = face.ttf(); + let ttf = fonts.get(face_id).ttf(); return text.chars().all(|c| ttf.glyph_index(c).is_some()); } } @@ -110,8 +108,7 @@ fn convert_script(text: &str, mode: ScriptKind) -> Option { let mut result = EcoString::with_capacity(text.len()); let converter = match mode { SUPERSCRIPT => to_superscript_codepoint, - SUBSCRIPT => to_subscript_codepoint, - _ => panic!("unknown script kind"), + SUBSCRIPT | _ => to_subscript_codepoint, }; for c in text.chars() { diff --git a/tests/ref/text/baseline.png b/tests/ref/text/baseline.png index 7baa016796f7c2892c1c9a5f635d157bc8fd8cc4..37bb19499cd871d9c47bd6cf10b4457d4cbd49ff 100644 GIT binary patch delta 1372 zcmV-i1*7`JFuX937Y@h>00000D?Y%j000;Ru_X=eLkWirABb11BpDI$wu$9rYt{W@2^csZ+JL)AQZf9+S@ib2bC;{q#Ke zdrr{Me^t3a{?y&~7mx*JG~?myu3`%emCjmg>GWcrJ}BC1+DA6erbFjCg*=_O~w zHj|6NWKyQOkUK#71^YO!fj$*-0bXhcKUS>pe`aSV|2tq2qXr7?hXLF|086m+5B7HX z3OMXqrfUn?Bn$BFFiVJNBE|A5?JLSafUn(Z^lNMAV*%zG%Cu=xdyt0URZf&OO@!06 zTwAqtsdwQ?6$d&g#X+`BgU{p)NUHW7SOOgG6l`@|V%QA1{hhB6EA{~AT1xYqHb{ia-u_P-L9PYzoO=RU0AGni1rba=0dC3hWE%$pkxnTr7pDP6 z+NWU=Z(7v}75V~Pmmfi1E|Bj$2=HzIe?X*20DczH5ayZ&(5@PcHCzV>u|n7(b^>e? z2c9%SEI@sAX79b^uf@&+2)EQ3N98)h5cdaAvj>cHzGya^&C|qjEMinagzGZGY&M(C z9!k?#c5-sLUVwK86(Jc&79T>p`ew7)Y#t!*(XpCU#i$^BERq1sBC1#reEopUf3LU- zA*>LNOEolv@5N@0ip|hT+w~S}1URB4Xabi8l#^0QYXs6nICyD0IZM6zHW3DhOn~G^ z4jy{E2s>o((aVW3RtT5nthBVWw6wGg$gdnknEL}5;Grx_vsfd*1vyVkkWr)d*7J#p zWo;ugZ?5hnAAcX42p@=4fE!|Re{mrY>|_DHvqH#o9d^uo*bC-QE(P`8u^?+_xH%6=&YOJ3D;O$s358zYT@$;Fl8dg{# zG^{)7CO4{<{b)s~N25$Ks+XJa%{0GmwWr!bV4&=`Y+?hagFpxQ=E6@}bkobnLuQmhg?%?XO!f2%> zc)ss6W#N`rTpay&0=d4QYI}s8EqoIod0;hJacmlJwu6gDw?EEy=n7rm0pJVYR3O7Q z8eqW-4z8Vk0mvEW<=p<)PkptgNFrYJ{RTMLs+4=%pPtkmqwP@G8k4N8Um?nS)butj z0pvY0L+w9b*oII--sP^7%o8F8cJx0DoHAs_k6THHKKGq0{z^_WJSyt(>wA@IX zCE{R{GTEn!HjVI;Cl*f%m$IQhG-|I-lLC`~7DfW=P?N|OGy-~Vll~TF0zS@@W*2k< e-2#)`7gQA1h$wF8v{%Id0000ZW_;e8xMQpJk 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 ZyX511b3Uc%L-86QC#5V|EN<-oe*jq|%G>|| literal 2958 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 V%bChGTl7!SHZ#6tRBqso`!{BwV59&5 diff --git a/tests/typ/text/shifts.typ b/tests/typ/text/shifts.typ index 624db7e1f..b70425c4e 100644 --- a/tests/typ/text/shifts.typ +++ b/tests/typ/text/shifts.typ @@ -10,3 +10,10 @@ --- #set super(typographic: false, baseline: -0.25em, size: 0.7em) n#super[1], n#sub[2], ... n#super[N] + +--- +#set underline(stroke: 0.5pt, offset: 0.15em) + +#underline[The claim#super[\[4\]]] has been disputed. \ +The claim#super[#underline[\[4\]]] has been disputed. \ +It really has been#super(box(text(baseline: 0pt, underline[\[4\]]))) \