68
69
glyphs->glyphs[i].geometry.width = logical_rect.width;
72
basic_engine_shape (PangoEngineShape *engine,
76
const PangoAnalysis *analysis,
77
PangoGlyphString *glyphs)
73
/* The "RunIterator" helps us to iterate over the array of runs that is obtained from
74
* the CoreText type setter. Even though Pango considers the string that is passed to
75
* the shaping engine a single run, CoreText might consider it to consist out of
76
* multiple runs. Because of this, we have an interface around the CoreText array of
77
* runs that works like iterating a single array, which makes our job in the shaping
78
* engine function easier.
91
int current_run_number;
93
CFIndex *current_indices;
94
const CGGlyph *current_cgglyphs;
95
CTRunStatus current_run_status;
99
run_iterator_free_current_run (struct RunIterator *iter)
101
iter->current_run_number = -1;
102
iter->current_run = NULL;
103
iter->current_cgglyphs = NULL;
104
if (iter->current_indices)
105
free (iter->current_indices);
106
iter->current_indices = NULL;
110
run_iterator_set_current_run (struct RunIterator *iter,
111
const int run_number)
113
CFIndex ct_glyph_count;
115
run_iterator_free_current_run (iter);
117
iter->current_run_number = run_number;
118
iter->current_run = CFArrayGetValueAtIndex (iter->runs, run_number);
119
iter->current_run_status = CTRunGetStatus (iter->current_run);
120
iter->current_cgglyphs = CTRunGetGlyphsPtr (iter->current_run);
122
ct_glyph_count = CTRunGetGlyphCount (iter->current_run);
123
iter->current_indices = malloc (sizeof (CFIndex *) * ct_glyph_count);
124
CTRunGetStringIndices (iter->current_run, CFRangeMake (0, ct_glyph_count),
125
iter->current_indices);
131
run_iterator_get_glyph_count (struct RunIterator *iter)
133
CFIndex accumulator = 0;
136
for (i = 0; i < CFArrayGetCount (iter->runs); i++)
137
accumulator += CTRunGetGlyphCount (CFArrayGetValueAtIndex (iter->runs, i));
143
run_iterator_is_rtl (struct RunIterator *iter)
145
/* Assume run status is equal for all runs? */
146
CTRunStatus run_status = CTRunGetStatus (CFArrayGetValueAtIndex (iter->runs, 0));
148
return run_status & kCTRunStatusRightToLeft;
152
run_iterator_run_is_non_monotonic (struct RunIterator *iter)
154
CTRunStatus run_status = CTRunGetStatus (iter->current_run);
156
return run_status & kCTRunStatusNonMonotonic;
160
run_iterator_get_character (struct RunIterator *iter)
162
return CFStringGetCharacterAtIndex (iter->cstr, iter->current_indices[iter->ct_i]);
166
run_iterator_get_cgglyph (struct RunIterator *iter)
168
return iter->current_cgglyphs[iter->ct_i];
172
run_iterator_get_index (struct RunIterator *iter)
174
return iter->current_indices[iter->ct_i];
178
run_iterator_create (struct RunIterator *iter,
83
184
CFDictionaryRef attributes;
84
185
CFAttributedStringRef attstr;
85
PangoCoreTextFont *cfont = PANGO_CORE_TEXT_FONT (font);
86
PangoCoverage *coverage;
89
CTRunStatus run_status;
90
CFIndex i, glyph_count;
91
const CGGlyph *cgglyphs;
93
187
CFTypeRef keys[] = {
94
188
(CFTypeRef) kCTFontAttributeName
97
191
CFTypeRef values[] = {
98
pango_core_text_font_get_ctfont (cfont)
195
/* Initialize RunIterator structure */
196
iter->current_run_number = -1;
197
iter->current_run = NULL;
198
iter->current_indices = NULL;
199
iter->current_cgglyphs = NULL;
101
202
attributes = CFDictionaryCreate (kCFAllocatorDefault,
102
203
(const void **)keys,
103
204
(const void **)values,
108
209
copy = g_strndup (text, length + 1);
109
210
copy[length] = 0;
111
cstr = CFStringCreateWithCString (kCFAllocatorDefault, copy,
112
kCFStringEncodingUTF8);
212
iter->cstr = CFStringCreateWithCString (kCFAllocatorDefault, copy,
213
kCFStringEncodingUTF8);
115
216
attstr = CFAttributedStringCreate (kCFAllocatorDefault,
119
line = CTLineCreateWithAttributedString (attstr);
121
runs = CTLineGetGlyphRuns (line);
123
/* Since Pango divides things into runs already, we assume there is
124
* only a single run in this line.
126
run = CFArrayGetValueAtIndex (runs, 0);
127
run_status = CTRunGetStatus (run);
128
glyph_count = CTRunGetGlyphCount (run);
129
cgglyphs = CTRunGetGlyphsPtr (run);
132
pango_glyph_string_set_size (glyphs, glyph_count);
220
iter->line = CTLineCreateWithAttributedString (attstr);
221
iter->runs = CTLineGetGlyphRuns (iter->line);
224
CFRelease (attributes);
226
iter->total_ct_i = 0;
227
iter->glyph_count = run_iterator_get_glyph_count (iter);
229
/* If CoreText did not render any glyphs for this string (can happen,
230
* e.g. a run solely consisting of a BOM), glyph_count will be zero and
231
* we immediately set the iterator variable to indicate end of glyph list.
233
if (iter->glyph_count > 0)
234
run_iterator_set_current_run (iter, 0);
236
iter->total_ct_i = -1;
240
run_iterator_free (struct RunIterator *iter)
242
run_iterator_free_current_run (iter);
244
CFRelease (iter->line);
245
CFRelease (iter->cstr);
249
run_iterator_at_end (struct RunIterator *iter)
251
if (iter->total_ct_i == -1)
258
run_iterator_advance (struct RunIterator *iter)
260
if (iter->total_ct_i >= iter->glyph_count - 1)
262
run_iterator_free_current_run (iter);
263
iter->ct_i = iter->total_ct_i = -1;
270
if (iter->total_ct_i < iter->glyph_count &&
271
iter->ct_i >= CTRunGetGlyphCount (iter->current_run))
273
iter->current_run_number++;
274
run_iterator_set_current_run (iter, iter->current_run_number);
289
glyph_info_compare_func (gconstpointer a, gconstpointer b)
291
const struct GlyphInfo *gi_a = a;
292
const struct GlyphInfo *gi_b = b;
294
if (gi_a->index < gi_b->index)
296
else if (gi_a->index > gi_b->index)
303
glyph_info_free (gpointer data, gpointer user_data)
305
g_slice_free (struct GlyphInfo, data);
309
create_core_text_glyph_list (const char *text,
313
GSList *glyph_list = NULL;
314
struct RunIterator riter;
316
run_iterator_create (&riter, text, length, ctfont);
318
while (!run_iterator_at_end (&riter))
320
struct GlyphInfo *gi;
322
gi = g_slice_new (struct GlyphInfo);
323
gi->index = run_iterator_get_index (&riter);
324
gi->cgglyph = run_iterator_get_cgglyph (&riter);
325
gi->wc = run_iterator_get_character (&riter);
327
glyph_list = g_slist_prepend (glyph_list, gi);
329
run_iterator_advance (&riter);
332
glyph_list = g_slist_sort (glyph_list, glyph_info_compare_func);
334
run_iterator_free (&riter);
341
basic_engine_shape (PangoEngineShape *engine,
345
const PangoAnalysis *analysis,
346
PangoGlyphString *glyphs)
349
gulong n_chars, gs_i, gs_prev_i;
350
PangoCoreTextFont *cfont = PANGO_CORE_TEXT_FONT (font);
351
PangoCoverage *coverage;
355
/* We first fully iterate over the glyph sequence generated by CoreText and
356
* store this into a list, which is sorted after the iteration. We make a pass
357
* over the sorted linked list to build up the PangoGlyphString.
359
* We have to do this in order to properly handle a bunch of characteristics of the
360
* glyph sequence generated by the CoreText typesetter:
361
* # E.g. zero-width spaces do not end up in the CoreText glyph sequence. We have
362
* to manually account for the gap in the character indices.
363
* # Sometimes, CoreText generates two glyph for the same character index. We
364
* currently handle this "properly" as in we do not crash or corrupt memory,
365
* but that's about it.
366
* # Due to mismatches in size, the CoreText glyph sequence can either be longer or
367
* shorter than the PangoGlyphString. Note that the size of the PangoGlyphString
368
* should match the number of characters in "text".
370
* If performance becomes a problem, it is certainly possible to use a faster code
371
* that only does a single iteration over the string for "simple cases". Simple cases
372
* could include these that only consist out of one run (simple Latin text), which
373
* don't have gaps in the glyph sequence and which are monotonically
374
* increasing/decreasing.
376
* FIXME items for future fixing:
377
* # CoreText strings are UTF16, and the indices *often* refer to characters,
378
* but not *always*. Notable exception is when a character is encoded using
379
* two UTF16 code points. This are two characters in a CFString. At this point
380
* advancing a single character in the CFString and advancing a single character
381
* using g_utf8_next_char in the const char string goes out of sync.
382
* # We currently don't bother about LTR, Pango core appears to fix this up for us.
383
* (Even when we cared warnings were generated that strings were in the wrong
384
* order, this should be investigated).
385
* # When CoreText generates two glyphs for one character, only one is stored.
386
* This breaks the example strings for e.g. Georgian and Gothic.
389
glyph_list = create_core_text_glyph_list (text, length,
390
pango_core_text_font_get_ctfont (cfont));
392
/* Translate the glyph list to a PangoGlyphString */
393
n_chars = g_utf8_strlen (text, length);
394
pango_glyph_string_set_size (glyphs, n_chars);
396
glyph_iter = glyph_list;
133
398
coverage = pango_font_get_coverage (PANGO_FONT (cfont),
134
399
analysis->language);
136
for (i = 0; i < glyph_count; i++)
401
for (gs_prev_i = -1, gs_i = 0, p = text; gs_i < n_chars;
402
gs_prev_i = gs_i, gs_i++, p = g_utf8_next_char (p))
138
CFIndex real_i, prev_i;
140
gunichar mirrored_ch;
142
wc = g_utf8_get_char (p);
144
if (analysis->level % 2)
145
if (pango_get_mirror_char (wc, &mirrored_ch))
148
if (run_status & kCTRunStatusRightToLeft)
150
real_i = glyph_count - i - 1;
159
if (wc == 0xa0) /* non-break-space */
162
if (pango_is_zero_width (wc))
164
set_glyph (font, glyphs, real_i, p - text, PANGO_GLYPH_EMPTY);
404
struct GlyphInfo *gi = glyph_iter != NULL ? glyph_iter->data : NULL;
406
if (gi == NULL || gi->index > gs_i)
408
/* gs_i is behind, insert empty glyph */
409
set_glyph (font, glyphs, gs_i, p - text, PANGO_GLYPH_EMPTY);
412
else if (gi->index < gs_i)
414
while (gi && gi->index < gs_i)
416
glyph_iter = g_slist_next (glyph_iter);
418
gi = glyph_iter->data;
424
if (gi != NULL && gi->index == gs_i)
426
gunichar mirrored_ch;
168
427
PangoCoverageLevel result;
170
result = pango_coverage_get (coverage, wc);
429
if (analysis->level % 2)
430
if (g_unichar_get_mirror_char (gi->wc, &mirrored_ch))
431
gi->wc = mirrored_ch;
433
if (gi->wc == 0xa0) /* non-break-space */
436
result = pango_coverage_get (coverage, gi->wc);
172
438
if (result != PANGO_COVERAGE_NONE)
174
set_glyph (font, glyphs, real_i, p - text, cgglyphs[real_i]);
440
set_glyph (font, glyphs, gs_i, p - text, gi->cgglyph);
176
if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK)
442
if (g_unichar_type (gi->wc) == G_UNICODE_NON_SPACING_MARK)
180
446
PangoRectangle logical_rect, ink_rect;
182
glyphs->glyphs[real_i].geometry.width = MAX (glyphs->glyphs[prev_i].geometry.width,
183
glyphs->glyphs[prev_i].geometry.width);
184
glyphs->glyphs[prev_i].geometry.width = 0;
185
glyphs->log_clusters[real_i] = glyphs->log_clusters[prev_i];
448
glyphs->glyphs[gs_i].geometry.width = MAX (glyphs->glyphs[gs_prev_i].geometry.width,
449
glyphs->glyphs[gs_i].geometry.width);
450
glyphs->glyphs[gs_prev_i].geometry.width = 0;
451
glyphs->log_clusters[gs_i] = glyphs->log_clusters[gs_prev_i];
187
453
/* Some heuristics to try to guess how overstrike glyphs are
188
454
* done and compensate
190
pango_font_get_glyph_extents (font, glyphs->glyphs[real_i].glyph, &ink_rect, &logical_rect);
456
pango_font_get_glyph_extents (font, glyphs->glyphs[gs_i].glyph, &ink_rect, &logical_rect);
191
457
if (logical_rect.width == 0 && ink_rect.x == 0)
192
glyphs->glyphs[real_i].geometry.x_offset = (glyphs->glyphs[real_i].geometry.width - ink_rect.width) / 2;
458
glyphs->glyphs[gs_i].geometry.x_offset = (glyphs->glyphs[gs_i].geometry.width - ink_rect.width) / 2;
198
set_glyph (font, glyphs, real_i, p - text,
199
PANGO_GET_UNKNOWN_GLYPH (wc));
463
set_glyph (font, glyphs, gs_i, p - text, PANGO_GET_UNKNOWN_GLYPH (gi->wc));
465
glyph_iter = g_slist_next (glyph_iter);
203
p = g_utf8_next_char (p);
209
CFRelease (attributes);
210
469
pango_coverage_unref (coverage);
470
g_slist_foreach (glyph_list, glyph_info_free, NULL);
471
g_slist_free (glyph_list);