Line data Source code
1 : /*
2 : * Copyright © 2009,2010 Red Hat, Inc.
3 : * Copyright © 2010,2011,2012 Google, Inc.
4 : *
5 : * This is part of HarfBuzz, a text shaping library.
6 : *
7 : * Permission is hereby granted, without written agreement and without
8 : * license or royalty fees, to use, copy, modify, and distribute this
9 : * software and its documentation for any purpose, provided that the
10 : * above copyright notice and the following two paragraphs appear in
11 : * all copies of this software.
12 : *
13 : * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 : * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 : * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 : * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 : * DAMAGE.
18 : *
19 : * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 : * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 : * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 : * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 : * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 : *
25 : * Red Hat Author(s): Behdad Esfahbod
26 : * Google Author(s): Behdad Esfahbod
27 : */
28 :
29 : #define HB_SHAPER ot
30 : #define hb_ot_shaper_face_data_t hb_ot_layout_t
31 : #define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
32 : #include "hb-shaper-impl-private.hh"
33 :
34 : #include "hb-ot-shape-private.hh"
35 : #include "hb-ot-shape-complex-private.hh"
36 : #include "hb-ot-shape-fallback-private.hh"
37 : #include "hb-ot-shape-normalize-private.hh"
38 :
39 : #include "hb-ot-layout-private.hh"
40 : #include "hb-unicode-private.hh"
41 : #include "hb-set-private.hh"
42 :
43 :
44 : static hb_tag_t common_features[] = {
45 : HB_TAG('c','c','m','p'),
46 : HB_TAG('l','o','c','l'),
47 : HB_TAG('m','a','r','k'),
48 : HB_TAG('m','k','m','k'),
49 : HB_TAG('r','l','i','g'),
50 : };
51 :
52 :
53 : static hb_tag_t horizontal_features[] = {
54 : HB_TAG('c','a','l','t'),
55 : HB_TAG('c','l','i','g'),
56 : HB_TAG('c','u','r','s'),
57 : HB_TAG('k','e','r','n'),
58 : HB_TAG('l','i','g','a'),
59 : HB_TAG('r','c','l','t'),
60 : };
61 :
62 :
63 :
64 : static void
65 2 : hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
66 : const hb_segment_properties_t *props,
67 : const hb_feature_t *user_features,
68 : unsigned int num_user_features)
69 : {
70 2 : hb_ot_map_builder_t *map = &planner->map;
71 :
72 2 : map->add_global_bool_feature (HB_TAG('r','v','r','n'));
73 2 : map->add_gsub_pause (NULL);
74 :
75 2 : switch (props->direction) {
76 : case HB_DIRECTION_LTR:
77 2 : map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
78 2 : map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
79 2 : break;
80 : case HB_DIRECTION_RTL:
81 0 : map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
82 0 : map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
83 0 : break;
84 : case HB_DIRECTION_TTB:
85 : case HB_DIRECTION_BTT:
86 : case HB_DIRECTION_INVALID:
87 : default:
88 0 : break;
89 : }
90 :
91 2 : map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
92 2 : map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
93 2 : map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
94 :
95 2 : if (planner->shaper->collect_features)
96 0 : planner->shaper->collect_features (planner);
97 :
98 12 : for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
99 10 : map->add_global_bool_feature (common_features[i]);
100 :
101 2 : if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
102 14 : for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
103 12 : map->add_feature (horizontal_features[i], 1, F_GLOBAL |
104 12 : (horizontal_features[i] == HB_TAG('k','e','r','n') ?
105 12 : F_HAS_FALLBACK : F_NONE));
106 : else
107 : {
108 : /* We really want to find a 'vert' feature if there's any in the font, no
109 : * matter which script/langsys it is listed (or not) under.
110 : * See various bugs referenced from:
111 : * https://github.com/behdad/harfbuzz/issues/63 */
112 0 : map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
113 : }
114 :
115 2 : if (planner->shaper->override_features)
116 0 : planner->shaper->override_features (planner);
117 :
118 2 : for (unsigned int i = 0; i < num_user_features; i++) {
119 0 : const hb_feature_t *feature = &user_features[i];
120 0 : map->add_feature (feature->tag, feature->value,
121 0 : (feature->start == 0 && feature->end == (unsigned int) -1) ?
122 0 : F_GLOBAL : F_NONE);
123 : }
124 2 : }
125 :
126 :
127 : /*
128 : * shaper face data
129 : */
130 :
131 1052 : HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
132 :
133 : hb_ot_shaper_face_data_t *
134 4 : _hb_ot_shaper_face_data_create (hb_face_t *face)
135 : {
136 4 : return _hb_ot_layout_create (face);
137 : }
138 :
139 : void
140 2 : _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
141 : {
142 2 : _hb_ot_layout_destroy (data);
143 2 : }
144 :
145 :
146 : /*
147 : * shaper font data
148 : */
149 :
150 34 : HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
151 :
152 : struct hb_ot_shaper_font_data_t {};
153 :
154 : hb_ot_shaper_font_data_t *
155 2 : _hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
156 : {
157 2 : return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
158 : }
159 :
160 : void
161 0 : _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
162 : {
163 0 : }
164 :
165 :
166 : /*
167 : * shaper shape_plan data
168 : */
169 :
170 : hb_ot_shaper_shape_plan_data_t *
171 2 : _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
172 : const hb_feature_t *user_features,
173 : unsigned int num_user_features,
174 : const int *coords,
175 : unsigned int num_coords)
176 : {
177 2 : hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
178 2 : if (unlikely (!plan))
179 0 : return NULL;
180 :
181 4 : hb_ot_shape_planner_t planner (shape_plan);
182 :
183 2 : planner.shaper = hb_ot_shape_complex_categorize (&planner);
184 :
185 2 : hb_ot_shape_collect_features (&planner, &shape_plan->props,
186 2 : user_features, num_user_features);
187 :
188 2 : planner.compile (*plan, coords, num_coords);
189 :
190 2 : if (plan->shaper->data_create) {
191 0 : plan->data = plan->shaper->data_create (plan);
192 0 : if (unlikely (!plan->data))
193 0 : return NULL;
194 : }
195 :
196 2 : return plan;
197 : }
198 :
199 : void
200 0 : _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
201 : {
202 0 : if (plan->shaper->data_destroy)
203 0 : plan->shaper->data_destroy (const_cast<void *> (plan->data));
204 :
205 0 : plan->finish ();
206 :
207 0 : free (plan);
208 0 : }
209 :
210 :
211 : /*
212 : * shaper
213 : */
214 :
215 : struct hb_ot_shape_context_t
216 : {
217 : hb_ot_shape_plan_t *plan;
218 : hb_font_t *font;
219 : hb_face_t *face;
220 : hb_buffer_t *buffer;
221 : const hb_feature_t *user_features;
222 : unsigned int num_user_features;
223 :
224 : /* Transient stuff */
225 : bool fallback_positioning;
226 : bool fallback_glyph_classes;
227 : hb_direction_t target_direction;
228 : };
229 :
230 :
231 :
232 : /* Main shaper */
233 :
234 :
235 : /* Prepare */
236 :
237 : static void
238 34 : hb_set_unicode_props (hb_buffer_t *buffer)
239 : {
240 34 : unsigned int count = buffer->len;
241 34 : hb_glyph_info_t *info = buffer->info;
242 299 : for (unsigned int i = 0; i < count; i++)
243 265 : _hb_glyph_info_set_unicode_props (&info[i], buffer);
244 34 : }
245 :
246 : static void
247 34 : hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
248 : {
249 68 : if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
250 34 : buffer->context_len[0] ||
251 0 : _hb_glyph_info_get_general_category (&buffer->info[0]) !=
252 : HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
253 68 : return;
254 :
255 0 : if (!font->has_glyph (0x25CCu))
256 0 : return;
257 :
258 0 : hb_glyph_info_t dottedcircle = {0};
259 0 : dottedcircle.codepoint = 0x25CCu;
260 0 : _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
261 :
262 0 : buffer->clear_output ();
263 :
264 0 : buffer->idx = 0;
265 0 : hb_glyph_info_t info = dottedcircle;
266 0 : info.cluster = buffer->cur().cluster;
267 0 : info.mask = buffer->cur().mask;
268 0 : buffer->output_info (info);
269 0 : while (buffer->idx < buffer->len && !buffer->in_error)
270 0 : buffer->next_glyph ();
271 :
272 0 : buffer->swap_buffers ();
273 : }
274 :
275 : static void
276 34 : hb_form_clusters (hb_buffer_t *buffer)
277 : {
278 36 : if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
279 2 : buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
280 34 : return;
281 :
282 : /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
283 0 : unsigned int base = 0;
284 0 : unsigned int count = buffer->len;
285 0 : hb_glyph_info_t *info = buffer->info;
286 0 : for (unsigned int i = 1; i < count; i++)
287 : {
288 0 : if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
289 : !_hb_glyph_info_is_joiner (&info[i])))
290 : {
291 0 : buffer->merge_clusters (base, i);
292 0 : base = i;
293 : }
294 : }
295 0 : buffer->merge_clusters (base, count);
296 : }
297 :
298 : static void
299 34 : hb_ensure_native_direction (hb_buffer_t *buffer)
300 : {
301 34 : hb_direction_t direction = buffer->props.direction;
302 :
303 : /* TODO vertical:
304 : * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
305 : * Ogham fonts are supposed to be implemented BTT or not. Need to research that
306 : * first. */
307 68 : if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
308 34 : (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB))
309 : {
310 : /* Same loop as hb_form_clusters().
311 : * Since form_clusters() merged clusters already, we don't merge. */
312 0 : unsigned int base = 0;
313 0 : unsigned int count = buffer->len;
314 0 : hb_glyph_info_t *info = buffer->info;
315 0 : for (unsigned int i = 1; i < count; i++)
316 : {
317 0 : if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
318 : {
319 0 : if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
320 0 : buffer->merge_clusters (base, i);
321 0 : buffer->reverse_range (base, i);
322 :
323 0 : base = i;
324 : }
325 : }
326 0 : if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
327 0 : buffer->merge_clusters (base, count);
328 0 : buffer->reverse_range (base, count);
329 :
330 0 : buffer->reverse ();
331 :
332 0 : buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
333 : }
334 34 : }
335 :
336 :
337 : /* Substitute */
338 :
339 : static inline void
340 34 : hb_ot_mirror_chars (hb_ot_shape_context_t *c)
341 : {
342 34 : if (HB_DIRECTION_IS_FORWARD (c->target_direction))
343 34 : return;
344 :
345 0 : hb_buffer_t *buffer = c->buffer;
346 0 : hb_unicode_funcs_t *unicode = buffer->unicode;
347 0 : hb_mask_t rtlm_mask = c->plan->rtlm_mask;
348 :
349 0 : unsigned int count = buffer->len;
350 0 : hb_glyph_info_t *info = buffer->info;
351 0 : for (unsigned int i = 0; i < count; i++) {
352 0 : hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
353 0 : if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
354 0 : info[i].mask |= rtlm_mask;
355 : else
356 0 : info[i].codepoint = codepoint;
357 : }
358 : }
359 :
360 : static inline void
361 34 : hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
362 : {
363 36 : if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
364 2 : !c->plan->has_frac)
365 32 : return;
366 :
367 2 : hb_buffer_t *buffer = c->buffer;
368 :
369 : hb_mask_t pre_mask, post_mask;
370 2 : if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
371 : {
372 2 : pre_mask = c->plan->numr_mask | c->plan->frac_mask;
373 2 : post_mask = c->plan->frac_mask | c->plan->dnom_mask;
374 : }
375 : else
376 : {
377 0 : pre_mask = c->plan->frac_mask | c->plan->dnom_mask;
378 0 : post_mask = c->plan->numr_mask | c->plan->frac_mask;
379 : }
380 :
381 2 : unsigned int count = buffer->len;
382 2 : hb_glyph_info_t *info = buffer->info;
383 13 : for (unsigned int i = 0; i < count; i++)
384 : {
385 11 : if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
386 : {
387 0 : unsigned int start = i, end = i + 1;
388 0 : while (start &&
389 0 : _hb_glyph_info_get_general_category (&info[start - 1]) ==
390 : HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
391 0 : start--;
392 0 : while (end < count &&
393 0 : _hb_glyph_info_get_general_category (&info[end]) ==
394 : HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
395 0 : end++;
396 :
397 0 : for (unsigned int j = start; j < i; j++)
398 0 : info[j].mask |= pre_mask;
399 0 : info[i].mask |= c->plan->frac_mask;
400 0 : for (unsigned int j = i + 1; j < end; j++)
401 0 : info[j].mask |= post_mask;
402 :
403 0 : i = end - 1;
404 : }
405 : }
406 : }
407 :
408 : static inline void
409 34 : hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
410 : {
411 34 : hb_ot_map_t *map = &c->plan->map;
412 34 : hb_buffer_t *buffer = c->buffer;
413 :
414 34 : hb_mask_t global_mask = map->get_global_mask ();
415 34 : buffer->reset_masks (global_mask);
416 34 : }
417 :
418 : static inline void
419 34 : hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
420 : {
421 34 : hb_ot_map_t *map = &c->plan->map;
422 34 : hb_buffer_t *buffer = c->buffer;
423 :
424 34 : hb_ot_shape_setup_masks_fraction (c);
425 :
426 34 : if (c->plan->shaper->setup_masks)
427 0 : c->plan->shaper->setup_masks (c->plan, buffer, c->font);
428 :
429 34 : for (unsigned int i = 0; i < c->num_user_features; i++)
430 : {
431 0 : const hb_feature_t *feature = &c->user_features[i];
432 0 : if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
433 : unsigned int shift;
434 0 : hb_mask_t mask = map->get_mask (feature->tag, &shift);
435 0 : buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
436 : }
437 : }
438 34 : }
439 :
440 : static void
441 34 : hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
442 : {
443 34 : hb_buffer_t *buffer = c->buffer;
444 :
445 34 : if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
446 0 : (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
447 34 : return;
448 :
449 0 : unsigned int count = buffer->len;
450 0 : hb_glyph_info_t *info = buffer->info;
451 0 : hb_glyph_position_t *pos = buffer->pos;
452 0 : unsigned int i = 0;
453 0 : for (i = 0; i < count; i++)
454 0 : if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
455 0 : pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
456 : }
457 :
458 : static void
459 34 : hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
460 : {
461 34 : hb_buffer_t *buffer = c->buffer;
462 :
463 34 : if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
464 0 : (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
465 68 : return;
466 :
467 0 : unsigned int count = buffer->len;
468 0 : hb_glyph_info_t *info = buffer->info;
469 0 : hb_glyph_position_t *pos = buffer->pos;
470 0 : unsigned int i = 0;
471 0 : for (i = 0; i < count; i++)
472 : {
473 0 : if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
474 0 : break;
475 : }
476 :
477 : /* No default-ignorables found; return. */
478 0 : if (i == count)
479 0 : return;
480 :
481 : hb_codepoint_t space;
482 0 : if (c->font->get_nominal_glyph (' ', &space))
483 : {
484 : /* Replace default-ignorables with a zero-advance space glyph. */
485 0 : for (/*continue*/; i < count; i++)
486 : {
487 0 : if (_hb_glyph_info_is_default_ignorable (&info[i]))
488 0 : info[i].codepoint = space;
489 : }
490 : }
491 : else
492 : {
493 : /* Merge clusters and delete default-ignorables.
494 : * NOTE! We can't use out-buffer as we have positioning data. */
495 0 : unsigned int j = i;
496 0 : for (; i < count; i++)
497 : {
498 0 : if (_hb_glyph_info_is_default_ignorable (&info[i]))
499 : {
500 : /* Merge clusters.
501 : * Same logic as buffer->delete_glyph(), but for in-place removal. */
502 :
503 0 : unsigned int cluster = info[i].cluster;
504 0 : if (i + 1 < count && cluster == info[i + 1].cluster)
505 0 : continue; /* Cluster survives; do nothing. */
506 :
507 0 : if (j)
508 : {
509 : /* Merge cluster backward. */
510 0 : if (cluster < info[j - 1].cluster)
511 : {
512 0 : unsigned int old_cluster = info[j - 1].cluster;
513 0 : for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
514 0 : info[k - 1].cluster = cluster;
515 : }
516 0 : continue;
517 : }
518 :
519 0 : if (i + 1 < count)
520 0 : buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
521 :
522 0 : continue;
523 : }
524 :
525 0 : if (j != i)
526 : {
527 0 : info[j] = info[i];
528 0 : pos[j] = pos[i];
529 : }
530 0 : j++;
531 : }
532 0 : buffer->len = j;
533 : }
534 : }
535 :
536 :
537 : static inline void
538 34 : hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
539 : {
540 : /* Normalization process sets up glyph_index(), we just copy it. */
541 34 : unsigned int count = buffer->len;
542 34 : hb_glyph_info_t *info = buffer->info;
543 299 : for (unsigned int i = 0; i < count; i++)
544 265 : info[i].codepoint = info[i].glyph_index();
545 :
546 34 : buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
547 34 : }
548 :
549 : static inline void
550 29 : hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
551 : {
552 29 : unsigned int count = c->buffer->len;
553 29 : hb_glyph_info_t *info = c->buffer->info;
554 267 : for (unsigned int i = 0; i < count; i++)
555 : {
556 : hb_ot_layout_glyph_props_flags_t klass;
557 :
558 : /* Never mark default-ignorables as marks.
559 : * They won't get in the way of lookups anyway,
560 : * but having them as mark will cause them to be skipped
561 : * over if the lookup-flag says so, but at least for the
562 : * Mongolian variation selectors, looks like Uniscribe
563 : * marks them as non-mark. Some Mongolian fonts without
564 : * GDEF rely on this. Another notable character that
565 : * this applies to is COMBINING GRAPHEME JOINER. */
566 476 : klass = (_hb_glyph_info_get_general_category (&info[i]) !=
567 0 : HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
568 476 : _hb_glyph_info_is_default_ignorable (&info[i])) ?
569 : HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
570 : HB_OT_LAYOUT_GLYPH_PROPS_MARK;
571 238 : _hb_glyph_info_set_glyph_props (&info[i], klass);
572 : }
573 29 : }
574 :
575 : static inline void
576 34 : hb_ot_substitute_default (hb_ot_shape_context_t *c)
577 : {
578 34 : hb_buffer_t *buffer = c->buffer;
579 :
580 34 : hb_ot_shape_initialize_masks (c);
581 :
582 34 : hb_ot_mirror_chars (c);
583 :
584 34 : HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
585 :
586 34 : _hb_ot_shape_normalize (c->plan, buffer, c->font);
587 :
588 34 : hb_ot_shape_setup_masks (c);
589 :
590 : /* This is unfortunate to go here, but necessary... */
591 34 : if (c->fallback_positioning)
592 0 : _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
593 :
594 34 : hb_ot_map_glyphs_fast (buffer);
595 :
596 34 : HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
597 34 : }
598 :
599 : static inline void
600 34 : hb_ot_substitute_complex (hb_ot_shape_context_t *c)
601 : {
602 34 : hb_buffer_t *buffer = c->buffer;
603 :
604 34 : hb_ot_layout_substitute_start (c->font, buffer);
605 :
606 34 : if (!hb_ot_layout_has_glyph_classes (c->face))
607 29 : hb_synthesize_glyph_classes (c);
608 :
609 34 : c->plan->substitute (c->font, buffer);
610 :
611 34 : return;
612 : }
613 :
614 : static inline void
615 34 : hb_ot_substitute (hb_ot_shape_context_t *c)
616 : {
617 34 : hb_ot_substitute_default (c);
618 :
619 34 : _hb_buffer_allocate_gsubgpos_vars (c->buffer);
620 :
621 34 : hb_ot_substitute_complex (c);
622 34 : }
623 :
624 : /* Position */
625 :
626 : static inline void
627 0 : adjust_mark_offsets (hb_glyph_position_t *pos)
628 : {
629 0 : pos->x_offset -= pos->x_advance;
630 0 : pos->y_offset -= pos->y_advance;
631 0 : }
632 :
633 : static inline void
634 0 : zero_mark_width (hb_glyph_position_t *pos)
635 : {
636 0 : pos->x_advance = 0;
637 0 : pos->y_advance = 0;
638 0 : }
639 :
640 : static inline void
641 34 : zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
642 : {
643 34 : unsigned int count = buffer->len;
644 34 : hb_glyph_info_t *info = buffer->info;
645 299 : for (unsigned int i = 0; i < count; i++)
646 265 : if (_hb_glyph_info_is_mark (&info[i]))
647 : {
648 0 : if (adjust_offsets)
649 0 : adjust_mark_offsets (&buffer->pos[i]);
650 0 : zero_mark_width (&buffer->pos[i]);
651 : }
652 34 : }
653 :
654 : static inline void
655 34 : hb_ot_position_default (hb_ot_shape_context_t *c)
656 : {
657 34 : hb_direction_t direction = c->buffer->props.direction;
658 34 : unsigned int count = c->buffer->len;
659 34 : hb_glyph_info_t *info = c->buffer->info;
660 34 : hb_glyph_position_t *pos = c->buffer->pos;
661 :
662 34 : if (HB_DIRECTION_IS_HORIZONTAL (direction))
663 : {
664 299 : for (unsigned int i = 0; i < count; i++)
665 265 : pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
666 : /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
667 34 : if (c->font->has_glyph_h_origin_func ())
668 0 : for (unsigned int i = 0; i < count; i++)
669 0 : c->font->subtract_glyph_h_origin (info[i].codepoint,
670 0 : &pos[i].x_offset,
671 0 : &pos[i].y_offset);
672 : }
673 : else
674 : {
675 0 : for (unsigned int i = 0; i < count; i++)
676 : {
677 0 : pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
678 0 : c->font->subtract_glyph_v_origin (info[i].codepoint,
679 0 : &pos[i].x_offset,
680 0 : &pos[i].y_offset);
681 : }
682 : }
683 34 : if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
684 0 : _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
685 34 : }
686 :
687 : static inline void
688 34 : hb_ot_position_complex (hb_ot_shape_context_t *c)
689 : {
690 34 : hb_ot_layout_position_start (c->font, c->buffer);
691 :
692 34 : unsigned int count = c->buffer->len;
693 :
694 : /* If the font has no GPOS, AND, no fallback positioning will
695 : * happen, AND, direction is forward, then when zeroing mark
696 : * widths, we shift the mark with it, such that the mark
697 : * is positioned hanging over the previous glyph. When
698 : * direction is backward we don't shift and it will end up
699 : * hanging over the next glyph after the final reordering.
700 : * If fallback positinoing happens or GPOS is present, we don't
701 : * care.
702 : */
703 34 : bool adjust_offsets_when_zeroing = c->fallback_positioning &&
704 34 : !c->plan->shaper->fallback_position &&
705 34 : HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
706 :
707 34 : switch (c->plan->shaper->zero_width_marks)
708 : {
709 : case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
710 0 : zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
711 0 : break;
712 :
713 : default:
714 : case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
715 : case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
716 34 : break;
717 : }
718 :
719 34 : if (likely (!c->fallback_positioning))
720 : {
721 34 : hb_glyph_info_t *info = c->buffer->info;
722 34 : hb_glyph_position_t *pos = c->buffer->pos;
723 :
724 : /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
725 :
726 : /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
727 34 : if (c->font->has_glyph_h_origin_func ())
728 0 : for (unsigned int i = 0; i < count; i++)
729 0 : c->font->add_glyph_h_origin (info[i].codepoint,
730 0 : &pos[i].x_offset,
731 0 : &pos[i].y_offset);
732 :
733 34 : c->plan->position (c->font, c->buffer);
734 :
735 : /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
736 34 : if (c->font->has_glyph_h_origin_func ())
737 0 : for (unsigned int i = 0; i < count; i++)
738 0 : c->font->subtract_glyph_h_origin (info[i].codepoint,
739 0 : &pos[i].x_offset,
740 0 : &pos[i].y_offset);
741 :
742 : }
743 :
744 34 : switch (c->plan->shaper->zero_width_marks)
745 : {
746 : case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
747 34 : zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
748 34 : break;
749 :
750 : default:
751 : case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
752 : case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
753 0 : break;
754 : }
755 :
756 : /* Finishing off GPOS has to follow a certain order. */
757 34 : hb_ot_layout_position_finish_advances (c->font, c->buffer);
758 34 : hb_ot_zero_width_default_ignorables (c);
759 34 : hb_ot_layout_position_finish_offsets (c->font, c->buffer);
760 34 : }
761 :
762 : static inline void
763 34 : hb_ot_position (hb_ot_shape_context_t *c)
764 : {
765 34 : c->buffer->clear_positions ();
766 :
767 34 : hb_ot_position_default (c);
768 :
769 34 : hb_ot_position_complex (c);
770 :
771 34 : if (c->fallback_positioning && c->plan->shaper->fallback_position)
772 0 : _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
773 :
774 34 : if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
775 0 : hb_buffer_reverse (c->buffer);
776 :
777 : /* Visual fallback goes here. */
778 :
779 34 : if (c->fallback_positioning)
780 0 : _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
781 :
782 34 : _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
783 34 : }
784 :
785 :
786 : /* Pull it all together! */
787 :
788 : static void
789 34 : hb_ot_shape_internal (hb_ot_shape_context_t *c)
790 : {
791 34 : c->buffer->deallocate_var_all ();
792 34 : c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
793 34 : if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
794 : {
795 34 : c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
796 : (unsigned) HB_BUFFER_MAX_LEN_MIN);
797 : }
798 :
799 34 : bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan);
800 : //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face);
801 34 : c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face);
802 34 : c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face);
803 :
804 : /* Save the original direction, we use it later. */
805 34 : c->target_direction = c->buffer->props.direction;
806 :
807 34 : _hb_buffer_allocate_unicode_vars (c->buffer);
808 :
809 34 : c->buffer->clear_output ();
810 :
811 34 : hb_set_unicode_props (c->buffer);
812 34 : hb_insert_dotted_circle (c->buffer, c->font);
813 34 : hb_form_clusters (c->buffer);
814 :
815 34 : hb_ensure_native_direction (c->buffer);
816 :
817 34 : if (c->plan->shaper->preprocess_text)
818 0 : c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
819 :
820 34 : hb_ot_substitute (c);
821 34 : hb_ot_position (c);
822 :
823 34 : hb_ot_hide_default_ignorables (c);
824 :
825 34 : if (c->plan->shaper->postprocess_glyphs)
826 0 : c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
827 :
828 34 : _hb_buffer_deallocate_unicode_vars (c->buffer);
829 :
830 34 : c->buffer->props.direction = c->target_direction;
831 :
832 34 : c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
833 34 : c->buffer->deallocate_var_all ();
834 34 : }
835 :
836 :
837 : hb_bool_t
838 34 : _hb_ot_shape (hb_shape_plan_t *shape_plan,
839 : hb_font_t *font,
840 : hb_buffer_t *buffer,
841 : const hb_feature_t *features,
842 : unsigned int num_features)
843 : {
844 34 : hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
845 34 : hb_ot_shape_internal (&c);
846 :
847 34 : return true;
848 : }
849 :
850 :
851 : /**
852 : * hb_ot_shape_plan_collect_lookups:
853 : *
854 : * Since: 0.9.7
855 : **/
856 : void
857 0 : hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
858 : hb_tag_t table_tag,
859 : hb_set_t *lookup_indexes /* OUT */)
860 : {
861 : /* XXX Does the first part always succeed? */
862 0 : HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
863 0 : }
864 :
865 :
866 : /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
867 : static void
868 0 : add_char (hb_font_t *font,
869 : hb_unicode_funcs_t *unicode,
870 : hb_bool_t mirror,
871 : hb_codepoint_t u,
872 : hb_set_t *glyphs)
873 : {
874 : hb_codepoint_t glyph;
875 0 : if (font->get_nominal_glyph (u, &glyph))
876 0 : glyphs->add (glyph);
877 0 : if (mirror)
878 : {
879 0 : hb_codepoint_t m = unicode->mirroring (u);
880 0 : if (m != u && font->get_nominal_glyph (m, &glyph))
881 0 : glyphs->add (glyph);
882 : }
883 0 : }
884 :
885 :
886 : /**
887 : * hb_ot_shape_glyphs_closure:
888 : *
889 : * Since: 0.9.2
890 : **/
891 : void
892 0 : hb_ot_shape_glyphs_closure (hb_font_t *font,
893 : hb_buffer_t *buffer,
894 : const hb_feature_t *features,
895 : unsigned int num_features,
896 : hb_set_t *glyphs)
897 : {
898 0 : hb_ot_shape_plan_t plan;
899 :
900 0 : const char *shapers[] = {"ot", NULL};
901 0 : hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
902 0 : features, num_features, shapers);
903 :
904 0 : bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
905 :
906 0 : unsigned int count = buffer->len;
907 0 : hb_glyph_info_t *info = buffer->info;
908 0 : for (unsigned int i = 0; i < count; i++)
909 0 : add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
910 :
911 : hb_set_t lookups;
912 0 : lookups.init ();
913 0 : hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
914 :
915 : /* And find transitive closure. */
916 : hb_set_t copy;
917 0 : copy.init ();
918 0 : do {
919 0 : copy.set (glyphs);
920 0 : for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
921 0 : hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
922 0 : } while (!copy.is_equal (glyphs));
923 :
924 0 : hb_shape_plan_destroy (shape_plan);
925 0 : }
|