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) == 0x0E00u
)
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 hb_glyph_info_t
*info
= buffer
->info
;
171 for (unsigned int i
= 0; i
< count
; i
++)
172 if (_hb_glyph_info_get_general_category (&info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
) {
173 unsigned int combining_class
= _hb_glyph_info_get_modified_combining_class (&info
[i
]);
174 combining_class
= recategorize_combining_class (info
[i
].codepoint
, combining_class
);
175 _hb_glyph_info_set_modified_combining_class (&info
[i
], combining_class
);
181 zero_mark_advances (hb_buffer_t
*buffer
,
185 hb_glyph_info_t
*info
= buffer
->info
;
186 for (unsigned int i
= start
; i
< end
; i
++)
187 if (_hb_glyph_info_get_general_category (&info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
189 buffer
->pos
[i
].x_advance
= 0;
190 buffer
->pos
[i
].y_advance
= 0;
195 position_mark (const hb_ot_shape_plan_t
*plan
,
198 hb_glyph_extents_t
&base_extents
,
200 unsigned int combining_class
)
202 hb_glyph_extents_t mark_extents
;
203 if (!font
->get_glyph_extents (buffer
->info
[i
].codepoint
,
207 hb_position_t y_gap
= font
->y_scale
/ 16;
209 hb_glyph_position_t
&pos
= buffer
->pos
[i
];
210 pos
.x_offset
= pos
.y_offset
= 0;
213 /* We dont position LEFT and RIGHT marks. */
216 switch (combining_class
)
218 case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW
:
219 case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE
:
220 if (buffer
->props
.direction
== HB_DIRECTION_LTR
) {
221 pos
.x_offset
+= base_extents
.x_bearing
- mark_extents
.width
/ 2 - mark_extents
.x_bearing
;
223 } else if (buffer
->props
.direction
== HB_DIRECTION_RTL
) {
224 pos
.x_offset
+= base_extents
.x_bearing
+ base_extents
.width
- mark_extents
.width
/ 2 - mark_extents
.x_bearing
;
230 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW
:
231 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE
:
232 case HB_UNICODE_COMBINING_CLASS_BELOW
:
233 case HB_UNICODE_COMBINING_CLASS_ABOVE
:
235 pos
.x_offset
+= base_extents
.x_bearing
+ (base_extents
.width
- mark_extents
.width
) / 2 - mark_extents
.x_bearing
;
238 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT
:
239 case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT
:
240 case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT
:
242 pos
.x_offset
+= base_extents
.x_bearing
- mark_extents
.x_bearing
;
245 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT
:
246 case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT
:
247 case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
:
249 pos
.x_offset
+= base_extents
.x_bearing
+ base_extents
.width
- mark_extents
.width
- mark_extents
.x_bearing
;
254 switch (combining_class
)
256 case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW
:
257 case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT
:
258 case HB_UNICODE_COMBINING_CLASS_BELOW
:
259 case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT
:
260 /* Add gap, fall-through. */
261 base_extents
.height
-= y_gap
;
263 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT
:
264 case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW
:
265 pos
.y_offset
= base_extents
.y_bearing
+ base_extents
.height
- mark_extents
.y_bearing
;
266 /* Never shift up "below" marks. */
267 if ((y_gap
> 0) == (pos
.y_offset
> 0))
269 base_extents
.height
-= pos
.y_offset
;
272 base_extents
.height
+= mark_extents
.height
;
275 case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE
:
276 case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT
:
277 case HB_UNICODE_COMBINING_CLASS_ABOVE
:
278 case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
:
279 /* Add gap, fall-through. */
280 base_extents
.y_bearing
+= y_gap
;
281 base_extents
.height
-= y_gap
;
283 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE
:
284 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT
:
285 pos
.y_offset
= base_extents
.y_bearing
- (mark_extents
.y_bearing
+ mark_extents
.height
);
286 /* Don't shift down "above" marks too much. */
287 if ((y_gap
> 0) != (pos
.y_offset
> 0))
289 unsigned int correction
= -pos
.y_offset
/ 2;
290 base_extents
.y_bearing
+= correction
;
291 base_extents
.height
-= correction
;
292 pos
.y_offset
+= correction
;
294 base_extents
.y_bearing
-= mark_extents
.height
;
295 base_extents
.height
+= mark_extents
.height
;
301 position_around_base (const hb_ot_shape_plan_t
*plan
,
307 hb_direction_t horiz_dir
= HB_DIRECTION_INVALID
;
308 hb_glyph_extents_t base_extents
;
309 if (!font
->get_glyph_extents (buffer
->info
[base
].codepoint
,
312 /* If extents don't work, zero marks and go home. */
313 zero_mark_advances (buffer
, base
+ 1, end
);
316 base_extents
.x_bearing
+= buffer
->pos
[base
].x_offset
;
317 base_extents
.y_bearing
+= buffer
->pos
[base
].y_offset
;
319 unsigned int lig_id
= _hb_glyph_info_get_lig_id (&buffer
->info
[base
]);
320 unsigned int num_lig_components
= _hb_glyph_info_get_lig_num_comps (&buffer
->info
[base
]);
322 hb_position_t x_offset
= 0, y_offset
= 0;
323 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
324 x_offset
-= buffer
->pos
[base
].x_advance
;
325 y_offset
-= buffer
->pos
[base
].y_advance
;
328 hb_glyph_extents_t component_extents
= base_extents
;
329 unsigned int last_lig_component
= (unsigned int) -1;
330 unsigned int last_combining_class
= 255;
331 hb_glyph_extents_t cluster_extents
= base_extents
; /* Initialization is just to shut gcc up. */
332 hb_glyph_info_t
*info
= buffer
->info
;
333 for (unsigned int i
= base
+ 1; i
< end
; i
++)
334 if (_hb_glyph_info_get_modified_combining_class (&info
[i
]))
336 if (num_lig_components
> 1) {
337 unsigned int this_lig_id
= _hb_glyph_info_get_lig_id (&info
[i
]);
338 unsigned int this_lig_component
= _hb_glyph_info_get_lig_comp (&info
[i
]) - 1;
339 /* Conditions for attaching to the last component. */
340 if (!lig_id
|| lig_id
!= this_lig_id
|| this_lig_component
>= num_lig_components
)
341 this_lig_component
= num_lig_components
- 1;
342 if (last_lig_component
!= this_lig_component
)
344 last_lig_component
= this_lig_component
;
345 last_combining_class
= 255;
346 component_extents
= base_extents
;
347 if (unlikely (horiz_dir
== HB_DIRECTION_INVALID
)) {
348 if (HB_DIRECTION_IS_HORIZONTAL (plan
->props
.direction
))
349 horiz_dir
= plan
->props
.direction
;
351 horiz_dir
= hb_script_get_horizontal_direction (plan
->props
.script
);
353 if (horiz_dir
== HB_DIRECTION_LTR
)
354 component_extents
.x_bearing
+= (this_lig_component
* component_extents
.width
) / num_lig_components
;
356 component_extents
.x_bearing
+= ((num_lig_components
- 1 - this_lig_component
) * component_extents
.width
) / num_lig_components
;
357 component_extents
.width
/= num_lig_components
;
361 unsigned int this_combining_class
= _hb_glyph_info_get_modified_combining_class (&info
[i
]);
362 if (last_combining_class
!= this_combining_class
)
364 last_combining_class
= this_combining_class
;
365 cluster_extents
= component_extents
;
368 position_mark (plan
, font
, buffer
, cluster_extents
, i
, this_combining_class
);
370 buffer
->pos
[i
].x_advance
= 0;
371 buffer
->pos
[i
].y_advance
= 0;
372 buffer
->pos
[i
].x_offset
+= x_offset
;
373 buffer
->pos
[i
].y_offset
+= y_offset
;
376 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
377 x_offset
-= buffer
->pos
[i
].x_advance
;
378 y_offset
-= buffer
->pos
[i
].y_advance
;
380 x_offset
+= buffer
->pos
[i
].x_advance
;
381 y_offset
+= buffer
->pos
[i
].y_advance
;
387 position_cluster (const hb_ot_shape_plan_t
*plan
,
396 /* Find the base glyph */
397 hb_glyph_info_t
*info
= buffer
->info
;
398 for (unsigned int i
= start
; i
< end
; i
++)
399 if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info
[i
])))
401 /* Find mark glyphs */
403 for (j
= i
+ 1; j
< end
; j
++)
404 if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info
[j
])))
407 position_around_base (plan
, font
, buffer
, i
, j
);
414 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t
*plan
,
418 _hb_buffer_assert_gsubgpos_vars (buffer
);
420 unsigned int start
= 0;
421 unsigned int count
= buffer
->len
;
422 hb_glyph_info_t
*info
= buffer
->info
;
423 for (unsigned int i
= 1; i
< count
; i
++)
424 if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info
[i
])))) {
425 position_cluster (plan
, font
, buffer
, start
, i
);
428 position_cluster (plan
, font
, buffer
, start
, count
);
432 /* Performs old-style TrueType kerning. */
434 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t
*plan
,
438 if (!plan
->has_kern
) return;
440 OT::hb_apply_context_t
c (1, font
, buffer
);
441 c
.set_lookup_mask (plan
->kern_mask
);
442 c
.set_lookup_props (OT::LookupFlag::IgnoreMarks
);
443 OT::hb_apply_context_t::skipping_iterator_t
&skippy_iter
= c
.iter_input
;
444 skippy_iter
.init (&c
);
446 unsigned int count
= buffer
->len
;
447 hb_glyph_info_t
*info
= buffer
->info
;
448 hb_glyph_position_t
*pos
= buffer
->pos
;
449 for (unsigned int idx
= 0; idx
< count
;)
451 skippy_iter
.reset (idx
, 1);
452 if (!skippy_iter
.next ())
458 hb_position_t x_kern
, y_kern
;
459 font
->get_glyph_kerning_for_direction (info
[idx
].codepoint
,
460 info
[skippy_iter
.idx
].codepoint
,
461 buffer
->props
.direction
,
466 hb_position_t kern1
= x_kern
>> 1;
467 hb_position_t kern2
= x_kern
- kern1
;
468 pos
[idx
].x_advance
+= kern1
;
469 pos
[skippy_iter
.idx
].x_advance
+= kern2
;
470 pos
[skippy_iter
.idx
].x_offset
+= kern2
;
475 hb_position_t kern1
= y_kern
>> 1;
476 hb_position_t kern2
= y_kern
- kern1
;
477 pos
[idx
].y_advance
+= kern1
;
478 pos
[skippy_iter
.idx
].y_advance
+= kern2
;
479 pos
[skippy_iter
.idx
].y_offset
+= kern2
;
482 idx
= skippy_iter
.idx
;