summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorsitandr <60141933+sitandr@users.noreply.github.com>2023-06-20 17:58:22 +0300
committerGitHub <noreply@github.com>2023-06-20 16:58:22 +0200
commit03675fc429bd4e7aa71890922e359940cbf3c2ca (patch)
tree12ded38940afdc682e9d9d5b616ce2499992db15 /library
parent6c542ea1a4a0ee85069dad6974ff331851eff406 (diff)
Created new system for limits (fixes #1443) (#1452)
Diffstat (limited to 'library')
-rw-r--r--library/src/math/attach.rs79
-rw-r--r--library/src/math/fragment.rs37
-rw-r--r--library/src/math/op.rs8
-rw-r--r--library/src/math/stretch.rs1
4 files changed, 91 insertions, 34 deletions
diff --git a/library/src/math/attach.rs b/library/src/math/attach.rs
index cbf083c0..eee1e80e 100644
--- a/library/src/math/attach.rs
+++ b/library/src/math/attach.rs
@@ -77,18 +77,9 @@ impl LayoutMath for AttachElem {
let b = layout_attachment(ctx, Self::b)?;
ctx.unstyle();
- let as_limits = self.base().is::<LimitsElem>()
- || (!self.base().is::<ScriptsElem>()
- && ctx.style.size == MathSize::Display
- && base.class() == Some(MathClass::Large)
- && match &base {
- MathFragment::Variant(variant) => LIMITS.contains(&variant.c),
- MathFragment::Frame(fragment) => fragment.limits,
- _ => false,
- });
-
- let (t, tr) = if as_limits || tr.is_some() { (t, tr) } else { (None, t) };
- let (b, br) = if as_limits || br.is_some() { (b, br) } else { (None, b) };
+ let limits = base.limits().active(ctx);
+ let (t, tr) = if limits || tr.is_some() { (t, tr) } else { (None, t) };
+ let (b, br) = if limits || br.is_some() { (b, br) } else { (None, b) };
layout_attachments(ctx, base, [tl, t, tr, bl, b, br])
}
}
@@ -112,7 +103,10 @@ pub struct ScriptsElem {
impl LayoutMath for ScriptsElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- self.body().layout_math(ctx)
+ let mut fragment = ctx.layout_fragment(&self.body())?;
+ fragment.set_limits(Limits::Never);
+ ctx.push(fragment);
+ Ok(())
}
}
@@ -135,10 +129,56 @@ pub struct LimitsElem {
impl LayoutMath for LimitsElem {
#[tracing::instrument(skip(ctx))]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- self.body().layout_math(ctx)
+ let mut fragment = ctx.layout_fragment(&self.body())?;
+ fragment.set_limits(Limits::Always);
+ ctx.push(fragment);
+ Ok(())
}
}
+/// Describes in which situation a frame should use limits for attachments.
+#[derive(Debug, Copy, Clone)]
+pub enum Limits {
+ /// Always scripts.
+ Never,
+ /// Display limits only in `display` math.
+ Display,
+ /// Always limits.
+ Always,
+}
+
+impl Limits {
+ /// The default limit configuration if the given character is the base.
+ pub fn for_char(c: char) -> Self {
+ if Self::DEFAULT_TO_LIMITS.contains(&c) {
+ Limits::Display
+ } else {
+ Limits::Never
+ }
+ }
+
+ /// Whether limits should be displayed in this context
+ pub fn active(&self, ctx: &MathContext) -> bool {
+ match self {
+ Self::Always => true,
+ Self::Display => ctx.style.size == MathSize::Display,
+ Self::Never => false,
+ }
+ }
+
+ /// Unicode codepoints that should show attachments as limits in display
+ /// mode.
+ #[rustfmt::skip]
+ const DEFAULT_TO_LIMITS: &[char] = &[
+ /* ∏ */ '\u{220F}', /* ∐ */ '\u{2210}', /* ∑ */ '\u{2211}',
+ /* ⋀ */ '\u{22C0}', /* ⋁ */ '\u{22C1}',
+ /* ⋂ */ '\u{22C2}', /* ⋃ */ '\u{22C3}',
+ /* ⨀ */ '\u{2A00}', /* ⨁ */ '\u{2A01}', /* ⨂ */ '\u{2A02}',
+ /* ⨃ */ '\u{2A03}', /* ⨄ */ '\u{2A04}',
+ /* ⨅ */ '\u{2A05}', /* ⨆ */ '\u{2A06}',
+ ];
+}
+
macro_rules! measure {
($e: ident, $attr: ident) => {
$e.as_ref().map(|e| e.$attr()).unwrap_or_default()
@@ -358,14 +398,3 @@ fn is_atomic_text_frame(frame: &Frame) -> bool {
.filter(|item| !matches!(item, FrameItem::Meta(_, _)));
matches!(iter.next(), Some(FrameItem::Text(_))) && iter.next().is_none()
}
-
-/// Unicode codepoints that should have sub- and superscripts attached as limits.
-#[rustfmt::skip]
-const LIMITS: &[char] = &[
- /* ∏ */ '\u{220F}', /* ∐ */ '\u{2210}', /* ∑ */ '\u{2211}',
- /* ⋀ */ '\u{22C0}', /* ⋁ */ '\u{22C1}',
- /* ⋂ */ '\u{22C2}', /* ⋃ */ '\u{22C3}',
- /* ⨀ */ '\u{2A00}', /* ⨁ */ '\u{2A01}', /* ⨂ */ '\u{2A02}',
- /* ⨃ */ '\u{2A03}', /* ⨄ */ '\u{2A04}',
- /* ⨅ */ '\u{2A05}', /* ⨆ */ '\u{2A06}',
-];
diff --git a/library/src/math/fragment.rs b/library/src/math/fragment.rs
index 027ab7da..b70a3f7d 100644
--- a/library/src/math/fragment.rs
+++ b/library/src/math/fragment.rs
@@ -90,6 +90,15 @@ impl MathFragment {
}
}
+ pub fn set_limits(&mut self, limits: Limits) {
+ match self {
+ Self::Glyph(glyph) => glyph.limits = limits,
+ Self::Variant(variant) => variant.limits = limits,
+ Self::Frame(fragment) => fragment.limits = limits,
+ _ => {}
+ }
+ }
+
pub fn is_spaced(&self) -> bool {
match self {
MathFragment::Frame(frame) => frame.spaced,
@@ -113,6 +122,15 @@ impl MathFragment {
_ => Frame::new(self.size()),
}
}
+
+ pub fn limits(&self) -> Limits {
+ match self {
+ MathFragment::Glyph(glyph) => glyph.limits,
+ MathFragment::Variant(variant) => variant.limits,
+ MathFragment::Frame(fragment) => fragment.limits,
+ _ => Limits::Never,
+ }
+ }
}
impl From<GlyphFragment> for MathFragment {
@@ -149,6 +167,7 @@ pub struct GlyphFragment {
pub class: Option<MathClass>,
pub span: Span,
pub meta: Vec<Meta>,
+ pub limits: Limits,
}
impl GlyphFragment {
@@ -164,6 +183,10 @@ impl GlyphFragment {
}
pub fn with_id(ctx: &MathContext, c: char, id: GlyphId, span: Span) -> Self {
+ let class = match c {
+ ':' => Some(MathClass::Relation),
+ _ => unicode_math_class::class(c),
+ };
let mut fragment = Self {
id,
c,
@@ -175,11 +198,9 @@ impl GlyphFragment {
width: Abs::zero(),
ascent: Abs::zero(),
descent: Abs::zero(),
+ limits: Limits::for_char(c),
italics_correction: Abs::zero(),
- class: match c {
- ':' => Some(MathClass::Relation),
- _ => unicode_math_class::class(c),
- },
+ class,
span,
meta: MetaElem::data_in(ctx.styles()),
};
@@ -224,6 +245,7 @@ impl GlyphFragment {
italics_correction: self.italics_correction,
class: self.class,
span: self.span,
+ limits: self.limits,
frame: self.into_frame(),
}
}
@@ -268,6 +290,7 @@ pub struct VariantFragment {
pub font_size: Abs,
pub class: Option<MathClass>,
pub span: Span,
+ pub limits: Limits,
}
impl Debug for VariantFragment {
@@ -282,7 +305,7 @@ pub struct FrameFragment {
pub style: MathStyle,
pub font_size: Abs,
pub class: MathClass,
- pub limits: bool,
+ pub limits: Limits,
pub spaced: bool,
pub base_ascent: Abs,
}
@@ -296,7 +319,7 @@ impl FrameFragment {
font_size: ctx.size,
style: ctx.style,
class: MathClass::Normal,
- limits: false,
+ limits: Limits::Never,
spaced: false,
base_ascent,
}
@@ -306,7 +329,7 @@ impl FrameFragment {
Self { class, ..self }
}
- pub fn with_limits(self, limits: bool) -> Self {
+ pub fn with_limits(self, limits: Limits) -> Self {
Self { limits, ..self }
}
diff --git a/library/src/math/op.rs b/library/src/math/op.rs
index cc57eb61..8ad74c49 100644
--- a/library/src/math/op.rs
+++ b/library/src/math/op.rs
@@ -26,7 +26,7 @@ pub struct OpElem {
#[required]
pub text: EcoString,
- /// Whether the operator should force attachments to display as limits.
+ /// Whether the operator should show attachments as limits in display mode.
#[default(false)]
pub limits: bool,
}
@@ -39,7 +39,11 @@ impl LayoutMath for OpElem {
ctx.push(
FrameFragment::new(ctx, fragment.into_frame())
.with_class(MathClass::Large)
- .with_limits(self.limits(ctx.styles())),
+ .with_limits(if self.limits(ctx.styles()) {
+ Limits::Display
+ } else {
+ Limits::Never
+ }),
);
Ok(())
}
diff --git a/library/src/math/stretch.rs b/library/src/math/stretch.rs
index bbb0c9c4..910f7a81 100644
--- a/library/src/math/stretch.rs
+++ b/library/src/math/stretch.rs
@@ -185,6 +185,7 @@ fn assemble(
italics_correction: Abs::zero(),
class: base.class,
span: base.span,
+ limits: base.limits,
}
}