2 * Copyright © 2011,2012 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 * Google Author(s): Behdad Esfahbod
27 #include "hb-ot-shape-fallback-private.hh"
28 #include "hb-ot-layout-gsubgpos-private.hh"
31 recategorize_combining_class (hb_codepoint_t u
,
37 /* Thai / Lao need some per-character work. */
38 if ((u
& ~0xFF) == 0x0E00)
40 if (unlikely (klass
== 0))
53 klass
= HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
;
64 klass
= HB_UNICODE_COMBINING_CLASS_ABOVE
;
68 klass
= HB_UNICODE_COMBINING_CLASS_BELOW
;
72 /* Thai virama is below-right */
74 klass
= HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT
;
83 case HB_MODIFIED_COMBINING_CLASS_CCC10
: /* sheva */
84 case HB_MODIFIED_COMBINING_CLASS_CCC11
: /* hataf segol */
85 case HB_MODIFIED_COMBINING_CLASS_CCC12
: /* hataf patah */
86 case HB_MODIFIED_COMBINING_CLASS_CCC13
: /* hataf qamats */
87 case HB_MODIFIED_COMBINING_CLASS_CCC14
: /* hiriq */
88 case HB_MODIFIED_COMBINING_CLASS_CCC15
: /* tsere */
89 case HB_MODIFIED_COMBINING_CLASS_CCC16
: /* segol */
90 case HB_MODIFIED_COMBINING_CLASS_CCC17
: /* patah */
91 case HB_MODIFIED_COMBINING_CLASS_CCC18
: /* qamats */
92 case HB_MODIFIED_COMBINING_CLASS_CCC20
: /* qubuts */
93 case HB_MODIFIED_COMBINING_CLASS_CCC22
: /* meteg */
94 return HB_UNICODE_COMBINING_CLASS_BELOW
;
96 case HB_MODIFIED_COMBINING_CLASS_CCC23
: /* rafe */
97 return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE
;
99 case HB_MODIFIED_COMBINING_CLASS_CCC24
: /* shin dot */
100 return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
;
102 case HB_MODIFIED_COMBINING_CLASS_CCC25
: /* sin dot */
103 case HB_MODIFIED_COMBINING_CLASS_CCC19
: /* holam */
104 return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT
;
106 case HB_MODIFIED_COMBINING_CLASS_CCC26
: /* point varika */
107 return HB_UNICODE_COMBINING_CLASS_ABOVE
;
109 case HB_MODIFIED_COMBINING_CLASS_CCC21
: /* dagesh */
113 /* Arabic and Syriac */
115 case HB_MODIFIED_COMBINING_CLASS_CCC27
: /* fathatan */
116 case HB_MODIFIED_COMBINING_CLASS_CCC28
: /* dammatan */
117 case HB_MODIFIED_COMBINING_CLASS_CCC30
: /* fatha */
118 case HB_MODIFIED_COMBINING_CLASS_CCC31
: /* damma */
119 case HB_MODIFIED_COMBINING_CLASS_CCC33
: /* shadda */
120 case HB_MODIFIED_COMBINING_CLASS_CCC34
: /* sukun */
121 case HB_MODIFIED_COMBINING_CLASS_CCC35
: /* superscript alef */
122 case HB_MODIFIED_COMBINING_CLASS_CCC36
: /* superscript alaph */
123 return HB_UNICODE_COMBINING_CLASS_ABOVE
;
125 case HB_MODIFIED_COMBINING_CLASS_CCC29
: /* kasratan */
126 case HB_MODIFIED_COMBINING_CLASS_CCC32
: /* kasra */
127 return HB_UNICODE_COMBINING_CLASS_BELOW
;
132 case HB_MODIFIED_COMBINING_CLASS_CCC103
: /* sara u / sara uu */
133 return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT
;
135 case HB_MODIFIED_COMBINING_CLASS_CCC107
: /* mai */
136 return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
;
141 case HB_MODIFIED_COMBINING_CLASS_CCC118
: /* sign u / sign uu */
142 return HB_UNICODE_COMBINING_CLASS_BELOW
;
144 case HB_MODIFIED_COMBINING_CLASS_CCC122
: /* mai */
145 return HB_UNICODE_COMBINING_CLASS_ABOVE
;
150 case HB_MODIFIED_COMBINING_CLASS_CCC129
: /* sign aa */
151 return HB_UNICODE_COMBINING_CLASS_BELOW
;
153 case HB_MODIFIED_COMBINING_CLASS_CCC130
: /* sign i*/
154 return HB_UNICODE_COMBINING_CLASS_ABOVE
;
156 case HB_MODIFIED_COMBINING_CLASS_CCC132
: /* sign u */
157 return HB_UNICODE_COMBINING_CLASS_BELOW
;
165 _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t
*plan HB_UNUSED
,
166 hb_font_t
*font HB_UNUSED
,
169 unsigned int count
= buffer
->len
;
170 for (unsigned int i
= 0; i
< count
; i
++)
171 if (_hb_glyph_info_get_general_category (&buffer
->info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
) {
172 unsigned int combining_class
= _hb_glyph_info_get_modified_combining_class (&buffer
->info
[i
]);
173 combining_class
= recategorize_combining_class (buffer
->info
[i
].codepoint
, combining_class
);
174 _hb_glyph_info_set_modified_combining_class (&buffer
->info
[i
], combining_class
);
180 zero_mark_advances (hb_buffer_t
*buffer
,
184 for (unsigned int i
= start
; i
< end
; i
++)
185 if (_hb_glyph_info_get_general_category (&buffer
->info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
187 buffer
->pos
[i
].x_advance
= 0;
188 buffer
->pos
[i
].y_advance
= 0;
193 position_mark (const hb_ot_shape_plan_t
*plan
,
196 hb_glyph_extents_t
&base_extents
,
198 unsigned int combining_class
)
200 hb_glyph_extents_t mark_extents
;
201 if (!font
->get_glyph_extents (buffer
->info
[i
].codepoint
,
205 hb_position_t y_gap
= font
->y_scale
/ 16;
207 hb_glyph_position_t
&pos
= buffer
->pos
[i
];
208 pos
.x_offset
= pos
.y_offset
= 0;
211 /* We dont position LEFT and RIGHT marks. */
214 switch (combining_class
)
216 case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW
:
217 case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE
:
218 if (buffer
->props
.direction
== HB_DIRECTION_LTR
) {
219 pos
.x_offset
+= base_extents
.x_bearing
- mark_extents
.width
/ 2 - mark_extents
.x_bearing
;
221 } else if (buffer
->props
.direction
== HB_DIRECTION_RTL
) {
222 pos
.x_offset
+= base_extents
.x_bearing
+ base_extents
.width
- mark_extents
.width
/ 2 - mark_extents
.x_bearing
;
228 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW
:
229 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE
:
230 case HB_UNICODE_COMBINING_CLASS_BELOW
:
231 case HB_UNICODE_COMBINING_CLASS_ABOVE
:
233 pos
.x_offset
+= base_extents
.x_bearing
+ (base_extents
.width
- mark_extents
.width
) / 2 - mark_extents
.x_bearing
;
236 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT
:
237 case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT
:
238 case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT
:
240 pos
.x_offset
+= base_extents
.x_bearing
- mark_extents
.x_bearing
;
243 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT
:
244 case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT
:
245 case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
:
247 pos
.x_offset
+= base_extents
.x_bearing
+ base_extents
.width
- mark_extents
.width
- mark_extents
.x_bearing
;
252 switch (combining_class
)
254 case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW
:
255 case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT
:
256 case HB_UNICODE_COMBINING_CLASS_BELOW
:
257 case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT
:
258 /* Add gap, fall-through. */
259 base_extents
.height
-= y_gap
;
261 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT
:
262 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW
:
263 pos
.y_offset
= base_extents
.y_bearing
+ base_extents
.height
- mark_extents
.y_bearing
;
264 /* Never shift up "below" marks. */
265 if ((y_gap
> 0) == (pos
.y_offset
> 0))
267 base_extents
.height
-= pos
.y_offset
;
270 base_extents
.height
+= mark_extents
.height
;
273 case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE
:
274 case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT
:
275 case HB_UNICODE_COMBINING_CLASS_ABOVE
:
276 case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
:
277 /* Add gap, fall-through. */
278 base_extents
.y_bearing
+= y_gap
;
279 base_extents
.height
-= y_gap
;
281 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE
:
282 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT
:
283 pos
.y_offset
= base_extents
.y_bearing
- (mark_extents
.y_bearing
+ mark_extents
.height
);
284 /* Don't shift down "above" marks too much. */
285 if ((y_gap
> 0) != (pos
.y_offset
> 0))
287 unsigned int correction
= -pos
.y_offset
/ 2;
288 base_extents
.y_bearing
+= correction
;
289 base_extents
.height
-= correction
;
290 pos
.y_offset
+= correction
;
292 base_extents
.y_bearing
-= mark_extents
.height
;
293 base_extents
.height
+= mark_extents
.height
;
299 position_around_base (const hb_ot_shape_plan_t
*plan
,
305 hb_direction_t horiz_dir
= HB_DIRECTION_INVALID
;
306 hb_glyph_extents_t base_extents
;
307 if (!font
->get_glyph_extents (buffer
->info
[base
].codepoint
,
310 /* If extents don't work, zero marks and go home. */
311 zero_mark_advances (buffer
, base
+ 1, end
);
314 base_extents
.x_bearing
+= buffer
->pos
[base
].x_offset
;
315 base_extents
.y_bearing
+= buffer
->pos
[base
].y_offset
;
317 unsigned int lig_id
= _hb_glyph_info_get_lig_id (&buffer
->info
[base
]);
318 unsigned int num_lig_components
= _hb_glyph_info_get_lig_num_comps (&buffer
->info
[base
]);
320 hb_position_t x_offset
= 0, y_offset
= 0;
321 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
322 x_offset
-= buffer
->pos
[base
].x_advance
;
323 y_offset
-= buffer
->pos
[base
].y_advance
;
326 hb_glyph_extents_t component_extents
= base_extents
;
327 unsigned int last_lig_component
= (unsigned int) -1;
328 unsigned int last_combining_class
= 255;
329 hb_glyph_extents_t cluster_extents
= base_extents
; /* Initialization is just to shut gcc up. */
330 for (unsigned int i
= base
+ 1; i
< end
; i
++)
331 if (_hb_glyph_info_get_modified_combining_class (&buffer
->info
[i
]))
333 if (num_lig_components
> 1) {
334 unsigned int this_lig_id
= _hb_glyph_info_get_lig_id (&buffer
->info
[i
]);
335 unsigned int this_lig_component
= _hb_glyph_info_get_lig_comp (&buffer
->info
[i
]) - 1;
336 /* Conditions for attaching to the last component. */
337 if (!lig_id
|| lig_id
!= this_lig_id
|| this_lig_component
>= num_lig_components
)
338 this_lig_component
= num_lig_components
- 1;
339 if (last_lig_component
!= this_lig_component
)
341 last_lig_component
= this_lig_component
;
342 last_combining_class
= 255;
343 component_extents
= base_extents
;
344 if (unlikely (horiz_dir
== HB_DIRECTION_INVALID
)) {
345 if (HB_DIRECTION_IS_HORIZONTAL (plan
->props
.direction
))
346 horiz_dir
= plan
->props
.direction
;
348 horiz_dir
= hb_script_get_horizontal_direction (plan
->props
.script
);
350 if (horiz_dir
== HB_DIRECTION_LTR
)
351 component_extents
.x_bearing
+= (this_lig_component
* component_extents
.width
) / num_lig_components
;
353 component_extents
.x_bearing
+= ((num_lig_components
- 1 - this_lig_component
) * component_extents
.width
) / num_lig_components
;
354 component_extents
.width
/= num_lig_components
;
358 unsigned int this_combining_class
= _hb_glyph_info_get_modified_combining_class (&buffer
->info
[i
]);
359 if (last_combining_class
!= this_combining_class
)
361 last_combining_class
= this_combining_class
;
362 cluster_extents
= component_extents
;
365 position_mark (plan
, font
, buffer
, cluster_extents
, i
, this_combining_class
);
367 buffer
->pos
[i
].x_advance
= 0;
368 buffer
->pos
[i
].y_advance
= 0;
369 buffer
->pos
[i
].x_offset
+= x_offset
;
370 buffer
->pos
[i
].y_offset
+= y_offset
;
373 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
374 x_offset
-= buffer
->pos
[i
].x_advance
;
375 y_offset
-= buffer
->pos
[i
].y_advance
;
377 x_offset
+= buffer
->pos
[i
].x_advance
;
378 y_offset
+= buffer
->pos
[i
].y_advance
;
384 position_cluster (const hb_ot_shape_plan_t
*plan
,
393 /* Find the base glyph */
394 for (unsigned int i
= start
; i
< end
; i
++)
395 if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer
->info
[i
])))
397 /* Find mark glyphs */
399 for (j
= i
+ 1; j
< end
; j
++)
400 if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer
->info
[j
])))
403 position_around_base (plan
, font
, buffer
, i
, j
);
410 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t
*plan
,
414 unsigned int start
= 0;
415 unsigned int last_cluster
= buffer
->info
[0].cluster
;
416 unsigned int count
= buffer
->len
;
417 for (unsigned int i
= 1; i
< count
; i
++)
418 if (buffer
->info
[i
].cluster
!= last_cluster
) {
419 position_cluster (plan
, font
, buffer
, start
, i
);
421 last_cluster
= buffer
->info
[i
].cluster
;
423 position_cluster (plan
, font
, buffer
, start
, count
);
427 /* Performs old-style TrueType kerning. */
429 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t
*plan
,
433 hb_mask_t kern_mask
= plan
->map
.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer
->props
.direction
) ?
434 HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
435 if (!kern_mask
) return;
437 unsigned int count
= buffer
->len
;
439 OT::hb_apply_context_t
c (1, font
, buffer
);
440 c
.set_lookup_mask (kern_mask
);
441 c
.set_lookup_props (OT::LookupFlag::IgnoreMarks
);
443 hb_glyph_info_t
*info
= buffer
->info
;
444 hb_glyph_position_t
*pos
= buffer
->pos
;
446 for (unsigned int idx
= 0; idx
< count
;)
448 OT::hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (&c
, idx
, 1);
449 if (!skippy_iter
.next ())
455 hb_position_t x_kern
, y_kern
;
456 font
->get_glyph_kerning_for_direction (info
[idx
].codepoint
,
457 info
[skippy_iter
.idx
].codepoint
,
458 buffer
->props
.direction
,
463 hb_position_t kern1
= x_kern
>> 1;
464 hb_position_t kern2
= x_kern
- kern1
;
465 pos
[idx
].x_advance
+= kern1
;
466 pos
[skippy_iter
.idx
].x_advance
+= kern2
;
467 pos
[skippy_iter
.idx
].x_offset
+= kern2
;
472 hb_position_t kern1
= y_kern
>> 1;
473 hb_position_t kern2
= y_kern
- kern1
;
474 pos
[idx
].y_advance
+= kern1
;
475 pos
[skippy_iter
.idx
].y_advance
+= kern2
;
476 pos
[skippy_iter
.idx
].y_offset
+= kern2
;
479 idx
= skippy_iter
.idx
;