Commit Graph

212 Commits

Author SHA1 Message Date
Guille Gonzalez
e66eeb4564 Refactor model 2026-01-02 15:24:11 +01:00
Guille Gonzalez
fbfc1d0ecf Add font infrastructure 2026-01-01 12:13:22 +01:00
Guille Gonzalez
5e8e93b53e Add helpers 2025-12-31 12:59:11 +01:00
Guille Gonzalez
f805b3adf5 Clean slate 2025-12-31 12:40:11 +01:00
Guille Gonzalez
d056918e1e Update .gitignore 2025-12-31 09:22:26 +01:00
Guille Gonzalez
5774724d18 Rename package and address warnings 2025-12-30 14:45:54 +01:00
mgriebling
c49362fcf1 Merge pull request #55 from nguillot/multiline-improvements
Add multiline line breaking improvements for mathematical equations
2025-11-27 12:05:13 -05:00
Nicolas Guillot
9da5aba6b2 multiline fix with square root on second line 2025-11-21 15:49:27 +01:00
Nicolas Guillot
8ce6da114c code cleaning: remove print statement 2025-11-18 09:01:00 +01:00
Nicolas Guillot
90767b7953 Add performance optimization: skip line breaking when remaining content fits
Implement early-exit optimization to avoid expensive width calculations when
we can determine that all remaining content will definitely fit on the current line.
2025-11-18 08:41:26 +01:00
Nicolas Guillot
3aa6c6c98b Fix line width calculation for expressions with superscripts/subscripts
The typesetter was incorrectly measuring line width when expressions contained
  superscripts or subscripts (e.g., b²). After rendering a superscript, the line
  is split into multiple display segments, but the width checking code was only
  measuring the current segment, not the total visual line width.

  Key changes:
  - Use currentPosition.x to track actual horizontal position across all segments
  - Calculate visualLineWidth = currentPosition.x + currentSegmentWidth
  - Pass remainingWidth (maxWidth - currentPosition.x) to findBestBreakPoint
  - Apply fix to both interatom breaking and inline text breaking

  This fixes truncation issues where content like "Δ=b²-4ac avec a=1..." was
  being clipped instead of wrapped to a new line.

  Before: Each segment checked in isolation → segments appeared to fit individually
          but total visual width exceeded maxWidth → content truncated/clipped

  After:  Total visual width tracked correctly → line breaking triggered when
          actual visual width exceeds maxWidth → content wraps properly
2025-11-17 17:51:30 +01:00
Nicolas Guillot
43c69240bd Fix word breaking: prevent splitting words with accented characters
Fixed line breaking that would split words like "équivaut" into "é" on one
  line and "quivaut" on the next line, even though they're part of the same word.

  Root cause analysis (from debug logging):
  When text contains accented characters in decomposed form (e + combining
  accent), the system processes them as separate atoms:
    1. "é" is processed as an accent atom, composed, and added to currentLine
    2. "quivaut " is processed as the next ordinary atom
    3. Before adding "quivaut ", checkAndPerformInteratomLineBreak() is called
    4. This function sees that adding "quivaut " would exceed maxWidth
    5. It breaks and flushes the line with "é" at the end
    6. "quivaut " starts on a new line

  Result: "é" appears alone at the end of one line, "quivaut " on the next.

  The fix:
  Modified checkAndPerformInteratomLineBreak() in MTTypesetter.swift to detect
  when we're about to break in the middle of a word.
2025-11-17 10:45:32 +01:00
Nicolas Guillot
cc1a7b8023 Fix inline mode rendering for large operators and fractions
This commit addresses three issues with math rendering:

  1. Large operator limits positioning (continued from previous commit)
  Modified makeLargeOp() and addLimitsToDisplay() to show limits above/below
  in both display and text (inline) modes:
    - Changed: op.limits && style == .display
    - To: op.limits && (style == .display || style == .text)

  This enables operators like \lim, \sum, and \prod to show subscripts/
  superscripts above and below even in inline mode \(...\), not just in
  display mode \[...\].

  2. Fraction font size issue
  Fixed fractions appearing too small in inline mode. Previously, fractions
  used one style level smaller than their parent (standard LaTeX behavior):
    - Display mode → fractions use text style (acceptable)
    - Text mode →

  Root cause:
  Inline delimiters \(...\) insert \textstyle, forcing text mode. In text
  mode, fractionStyle() returned style.inc(), making numerator/denominator
  use script style (two levels smaller than display). This made fraction
  numbers tiny compared to surrounding text in expressions like:
    \(\frac{a}{b} = c\) - a, b were script-sized while c was text-sized

  Solution:
  Modified fractionStyle() to return the SAME style instead of incrementing:
    func fractionStyle() -> MTLineStyle {
        return style  // Was: return style.inc()
    }

  This keeps fraction numerators/denominators at the same font size as
  regular text, preventing them from becoming too small. Spacing and
  positioning (numeratorShiftUp, etc.) still vary by parent style.

  3. Non-regression fixes
  Updated test expectations to match new fraction sizing behavior
2025-11-17 10:12:45 +01:00
Nicolas Guillot
cb890fb787 Fix assert failures for unhandled atom types in inter-element spacing
Replace fatal asserts with explicit handling for all MTMathAtomType cases
  in getInterElementSpaceArrayIndexForType(). Previously, unhandled types
  (accent, number, variable, unaryOperator, underline, overline, boundary,
  space, style, table) would trigger assert failures and return Int.max,
  causing array out-of-bounds crashes.
2025-11-17 09:37:59 +01:00
Nicolas Guillot
b014be12b4 Add dynamic line height adjustment for multiline math display
Replace fixed fontSize × 1.5 spacing with adaptive height calculation based
  on actual line content (ascent + descent), providing better visual spacing
  for expressions with varying content heights.
2025-11-14 12:31:54 +01:00
Nicolas Guillot
ca0c3fbe07 Add break quality scoring
Implement aesthetic break point selection to prefer natural break locations
  (e.g., after operators) rather than arbitrary positions when line wrapping
  mathematical expressions.
2025-11-14 12:23:27 +01:00
Nicolas Guillot
4441528f46 Implement line breaking for scripted atoms and fix atom ordering 2025-11-14 10:45:51 +01:00
Nicolas Guillot
15269e87e5 Fix large operator positioning causing incorrect atom ordering
When rendering large operators (e.g., sum, integral) with scripts in text
  mode, the operator glyph was incorrectly positioned after its subscripts
  and superscripts instead of before them. This caused expressions like
  \sum_{i=1}^{n} i = \frac{n(n+1)}{2} to render with the equals sign
  appearing visually misplaced.

  Root cause:
  The line-breaking refactoring introduced double-positioning of large
  operators. makeLargeOp() internally sets the operator position, advances
  currentPosition.x, and adds script displays. However, the calling code
  then overwrote the position and advanced currentPosition.x again, causing:
  - Double-advancement leading to incorrect width calculations
  - Scripts positioned before the operator instead of after

  Solution:
  Save and restore typesetter state before/after line break dimension checks,
  then call makeLargeOp() once at the correct position after handling line
  breaks and inter-element spacing.
2025-11-14 10:32:10 +01:00
Nicolas Guillot
8cf87ef703 inline layout for all complex atom types
Extends the width-checking pattern from fractions/radicals to ALL remaining
  complex atom types, completing Priority 1 of the multiline implementation.

  Changes:
  - Large operators (∑, ∫, ∏): Now stay inline with height+width checking
    (breaks only if height > fontSize * 2.5 OR width exceeds constraint)
  - Delimiters (\left...\right): Stay inline with maxWidth propagation to
    inner content for proper nested wrapping
  - Colors (.color, .textcolor, .colorBox): All 3 types now stay inline with
    maxWidth propagation for proper nested wrapping
  - Matrices/tables: Small matrices can now stay inline with surrounding content
  - Width constraint propagation: All recursive createLineForMathList() calls
    now properly pass maxWidth parameter

Impact:
  Before: Complex atoms always forced line breaks, even when they fit
  After: ALL complex atoms intelligently stay inline when width permits

  Examples:
  - a + ∑ xᵢ + b → 1 line instead of 3
  - (a+b) + \left(\frac{c}{d}\right) + e → stays inline with wrapping
2025-11-14 09:53:14 +01:00
Nicolas Guillot
c5b737d9bb Line breaking for fractions and radicals fixes
Implement smart width-checking for complex mathematical displays to enable
  inline rendering when space permits, dramatically improving multiline layout.

  Changes:
  - Add shouldBreakBeforeDisplay() helper to check width before line breaks
  - Add performLineBreak() helper for clean line transitions
  - Modify fraction handling to stay inline when they fit within maxWidth
  - Modify radical handling to stay inline when they fit within maxWidth
  - Support radicals with degrees (cube roots, nth roots, etc.)
2025-11-13 15:45:35 +01:00
Nicolas Guillot
cd9c3f7a37 add documentation 2025-11-13 15:08:55 +01:00
Nicolas Guillot
9f6f5a2934 [multiple lines] inter atoms line breaking support 2025-11-13 14:52:11 +01:00
mgriebling
48fcb899fc Merge pull request #54 from nguillot/dfrac_support
Add support for dfrac and tfrac LaTeX commands
2025-11-04 09:54:02 -05:00
mgriebling
51b3560eb1 Merge pull request #53 from nguillot/multiline-fixes
Add Unicode-aware line wrapping with conservative number protection
2025-11-04 09:53:34 -05:00
Nicolas Guillot
d2df078dc9 Add support for dfrac and tfrac LaTeX commands
Add display-style (dfrac) and text-style (tfrac) fraction commands
  to SwiftMath's LaTeX parser. These commands force fractions to render
  in specific styles regardless of context.

  Implementation:
  - Add dfrac parsing to prepend displaystyle to numerator/denominator
  - Add tfrac parsing to prepend textstyle to numerator/denominator
  - Implement in both parser functions in MTMathListBuilder.swift

  Testing:
  - Add testDisplayStyleFraction() for dfrac validation
  - Add testTextStyleFraction() for tfrac validation
  - Add testDisplayAndTextStyleFractions() for complex expressions
  - All 180 tests pass on macOS and iOS simulator

  Documentation:
  - Update MISSING_FEATURES.md (7/12 features now implemented, 58%)
  - Update README.md feature list to include dfrac and tfrac

  Fixes issue where equations like y'=-\dfrac{2}{x^{3}} would fail to
  parse with "Invalid command dfrac" error. This was blocking the
  StepByStep feature preview rendering.
2025-11-03 10:24:40 +01:00
Nicolas Guillot
ca0e514505 [multi line display] Fix line wrapping to respect width constraints and prevent text truncation 2025-10-27 13:33:29 +01:00
mgriebling
43faacf8de Merge pull request #52 from nguillot/latex_support_extension
Add comprehensive LaTeX support: matrices, delimiters, operators, and line wrapping
2025-10-05 09:38:49 -04:00
Nicolas Guillot
c7198ad9af [UI] add line wrapping functionality 2025-10-02 16:42:31 +02:00
Nicolas Guillot
11f57f7c6e add a fallback font system to render CJK text in the \text command 2025-10-01 14:11:00 +02:00
Nicolas Guillot
b67cc8fd38 [Test] fix MathFontTests on mac 2025-10-01 10:36:11 +02:00
Nicolas Guillot
fe00c5a96e add iiiint LaTeX command support 2025-10-01 10:30:03 +02:00
Nicolas Guillot
7a40cd704a pmatrix/bmatrix/vmatrix LaTeX command support 2025-10-01 10:22:56 +02:00
Nicolas Guillot
80db8c66fb smallmatrix LaTeX command support 2025-10-01 10:09:56 +02:00
Nicolas Guillot
e9ab64d844 substack LaTeX command support 2025-10-01 10:04:06 +02:00
Nicolas Guillot
7bd6ef660b [Test] add skipped tests to show what can be implemented 2025-09-30 20:20:59 +02:00
Nicolas Guillot
fc7e96acf5 [Test] increase LaTeX command coverage 2025-09-30 19:40:26 +02:00
Nicolas Guillot
61ef8dc4f8 supports all standard LaTeX math delimiters for both inline and display modes 2025-09-30 19:17:56 +02:00
Nicolas Guillot
6a5f64e402 fixup! [MTMathListBuilder] enhanced \begin{cases} environment support 2025-09-30 13:07:59 +02:00
Nicolas Guillot
7c9766f825 [MTMathListBuilder][MTTypesetter] add \cfrac support 2025-09-30 10:17:08 +02:00
Nicolas Guillot
225948c725 [MTMathListBuilder] enhanced \begin{cases} environment support
No Need to use the & character at line end. The previous notation is still supported.
2025-09-30 10:03:17 +02:00
Nicolas Guillot
5530f3910f [MTMathListBuilder] add support for some \not operators 2025-09-30 09:51:01 +02:00
Nicolas Guillot
4dcc7800d5 [MTMathAtomFactory] add support for /mod and /pmod 2025-09-30 09:35:29 +02:00
Nicolas Guillot
7f6cb02371 [MTMathAtomFactory] add support for /implies, /iint, /iiint, /nexists 2025-09-29 16:26:48 +02:00
mgriebling
fa8244ed03 Merge pull request #50 from raskavil/main
49: mathColor was used instead of mathColorbox
2025-08-03 08:48:30 -04:00
Vilém Raška
5011e4dd79 Fixed wrong reference
mathColor was used instead of mathColorbox
2025-08-02 15:09:03 +02:00
mgriebling
bc7fcfcab8 Merge pull request #46 from Lakr233/main
Fix a crash at cell spacer insertion loop
2025-07-31 15:21:37 -04:00
mgriebling
2398fdd42a Merge pull request #47 from jumhyn-browser/patch-1
Avoid crashing on unexpected color strings
2025-07-31 15:21:18 -04:00
Freddy Kellison-Linn
c7dcf78d11 Avoid crashing on unexpected color strings 2025-07-30 14:55:15 -04:00
Lakr
cfd646dcac Fix spacer insertion condition in table cell loop
Changed the condition to insert a spacer only when a table row has at least two cells, preventing out-of-bounds errors when accessing the second cell.
2025-07-03 15:13:23 +09:00
mgriebling
1e49ab4e85 Merge pull request #44 from trilorez/image-layout-info
Add layout info to MathImage
2025-05-22 10:22:16 -04:00