Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 5626ee6

Browse files
committed
[[ Bug 18132 ]] Fix cluster computation for non-monotonic lines
CoreText can generate runs which reference chars in the string 'out of order' for certain unicode strings (the case which gave rise to the bug is from gujarati). This patch ensures that reasonable cluster information is always generated by ignoring the char range fetched from a CTRun, and computing it as the min/max indices in the string index array fetched from a CTRun.
1 parent 45d1b01 commit 5626ee6

2 files changed

Lines changed: 27 additions & 13 deletions

File tree

docs/notes/bugfix-18132.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Ensure complex unicode scripts render correctly to PDF.

engine/src/coretextlayout.mm

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,34 @@ bool MCTextLayout(const unichar_t *p_chars, uint32_t p_char_count, MCFontStruct
157157
CTRunRef t_run;
158158
t_run = (CTRunRef)t_run_id;
159159

160-
uint32_t t_glyph_count;
160+
CFIndex t_glyph_count;
161161
t_glyph_count = CTRunGetGlyphCount(t_run);
162162

163-
CFRange t_char_range;
164-
t_char_range = CTRunGetStringRange(t_run);
165-
166163
CGGlyph *t_glyphs;
167164
CGPoint *t_positions;
168165
CFIndex *t_indices;
169166
t_glyphs = new CGGlyph[t_glyph_count];
170167
t_positions = new CGPoint[t_glyph_count];
171168
t_indices = new CFIndex[t_glyph_count];
172-
CTRunGetGlyphs(t_run, CFRangeMake(0, 0), t_glyphs);
173-
CTRunGetPositions(t_run, CFRangeMake(0, 0), t_positions);
174-
CTRunGetStringIndices(t_run, CFRangeMake(0, 0), t_indices);
169+
CTRunGetGlyphs(t_run, CFRangeMake(0, t_glyph_count), t_glyphs);
170+
CTRunGetPositions(t_run, CFRangeMake(0, t_glyph_count), t_positions);
171+
CTRunGetStringIndices(t_run, CFRangeMake(0, t_glyph_count), t_indices);
175172

173+
// Work out the string range of the run - the value returned by
174+
// CTRunGetCharRange() can't be trusted as it considers a line
175+
// 'as a whole' rather than individual runs. (This can happen with
176+
// abugida scripts where you get several runs for one cluster due
177+
// to font fallback).
178+
CFIndex t_min_char_range = p_char_count;
179+
CFIndex t_max_char_range = 0;
180+
for(CFIndex i = 0; i < t_glyph_count; i++)
181+
{
182+
t_min_char_range = MCMin(t_min_char_range, t_indices[i]);
183+
t_max_char_range = MCMax(t_max_char_range, t_indices[i] + 1);
184+
}
185+
CFRange t_char_range = CFRangeMake(t_min_char_range,
186+
t_max_char_range - t_min_char_range);
187+
176188
MCTextLayoutGlyph *t_layout_glyphs;
177189
uint16_t *t_clusters;
178190
t_layout_glyphs = new MCTextLayoutGlyph[t_glyph_count];
@@ -185,25 +197,26 @@ bool MCTextLayout(const unichar_t *p_chars, uint32_t p_char_count, MCFontStruct
185197
}
186198

187199
// Compute the clusters.
188-
for(uint32_t i = 0; i < t_char_range . length; i++)
200+
for(CFIndex i = 0; i < t_char_range . length; i++)
189201
t_clusters[i] = 65535;
190-
for(uint32_t i = 0; i < t_glyph_count; i++)
191-
t_clusters[t_indices[i] - t_char_range . location] = MCMin((uint32_t)t_clusters[t_indices[i]], i);
202+
for(CFIndex i = 0; i < t_glyph_count; i++)
203+
t_clusters[t_indices[i] - t_char_range . location] = (uint16_t)MCMin(i, UINT16_MAX);
192204

193205
for(uint32_t i = 1; i < t_char_range . length; i++)
194206
{
195207
// If a cluster has 0xffff as its value it means it was never set and must be
196-
// part of a surrogate, so we set it to the previous char.
208+
// part of a surrogate (or an out of order cluster), so we just set it to the
209+
// previous char.
197210
if (t_clusters[i] == 0xffff)
198211
t_clusters[i] = t_clusters[i - 1];
199212
}
200213

201214
MCTextLayoutSpan t_span;
202215
t_span . chars = p_chars + t_char_range . location;
203216
t_span . clusters = t_clusters;
204-
t_span . char_count = t_char_range . length;
217+
t_span . char_count = (uint32_t)t_char_range . length;
205218
t_span . glyphs = t_layout_glyphs;
206-
t_span . glyph_count = t_glyph_count;
219+
t_span . glyph_count = (uint32_t)t_glyph_count;
207220
t_span . font = (void *)ctfont_from_ctfont((CTFontRef)CFDictionaryGetValue(CTRunGetAttributes(t_run), kCTFontAttributeName));
208221
p_callback(p_context, &t_span);
209222

0 commit comments

Comments
 (0)