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 base_extents
.height
+= mark_extents
.height
;
267 case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE
:
268 case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT
:
269 case HB_UNICODE_COMBINING_CLASS_ABOVE
:
270 case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT
:
271 /* Add gap, fall-through. */
272 base_extents
.y_bearing
+= y_gap
;
273 base_extents
.height
-= y_gap
;
275 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE
:
276 case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT
:
277 pos
.y_offset
+= base_extents
.y_bearing
- (mark_extents
.y_bearing
+ mark_extents
.height
);
278 base_extents
.y_bearing
-= mark_extents
.height
;
279 base_extents
.height
+= mark_extents
.height
;
285 position_around_base (const hb_ot_shape_plan_t
*plan
,
291 hb_direction_t horiz_dir
= HB_DIRECTION_INVALID
;
292 hb_glyph_extents_t base_extents
;
293 if (!font
->get_glyph_extents (buffer
->info
[base
].codepoint
,
296 /* If extents don't work, zero marks and go home. */
297 zero_mark_advances (buffer
, base
+ 1, end
);
300 base_extents
.x_bearing
+= buffer
->pos
[base
].x_offset
;
301 base_extents
.y_bearing
+= buffer
->pos
[base
].y_offset
;
303 unsigned int lig_id
= get_lig_id (buffer
->info
[base
]);
304 unsigned int num_lig_components
= get_lig_num_comps (buffer
->info
[base
]);
306 hb_position_t x_offset
= 0, y_offset
= 0;
307 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
308 x_offset
-= buffer
->pos
[base
].x_advance
;
309 y_offset
-= buffer
->pos
[base
].y_advance
;
312 hb_glyph_extents_t component_extents
= base_extents
;
313 unsigned int last_lig_component
= (unsigned int) -1;
314 unsigned int last_combining_class
= 255;
315 hb_glyph_extents_t cluster_extents
= base_extents
; /* Initialization is just to shut gcc up. */
316 for (unsigned int i
= base
+ 1; i
< end
; i
++)
317 if (_hb_glyph_info_get_modified_combining_class (&buffer
->info
[i
]))
319 if (num_lig_components
> 1) {
320 unsigned int this_lig_id
= get_lig_id (buffer
->info
[i
]);
321 unsigned int this_lig_component
= get_lig_comp (buffer
->info
[i
]) - 1;
322 /* Conditions for attaching to the last component. */
323 if (!lig_id
|| lig_id
!= this_lig_id
|| this_lig_component
>= num_lig_components
)
324 this_lig_component
= num_lig_components
- 1;
325 if (last_lig_component
!= this_lig_component
)
327 last_lig_component
= this_lig_component
;
328 last_combining_class
= 255;
329 component_extents
= base_extents
;
330 if (unlikely (horiz_dir
== HB_DIRECTION_INVALID
)) {
331 if (HB_DIRECTION_IS_HORIZONTAL (plan
->props
.direction
))
332 horiz_dir
= plan
->props
.direction
;
334 horiz_dir
= hb_script_get_horizontal_direction (plan
->props
.script
);
336 if (horiz_dir
== HB_DIRECTION_LTR
)
337 component_extents
.x_bearing
+= (this_lig_component
* component_extents
.width
) / num_lig_components
;
339 component_extents
.x_bearing
+= ((num_lig_components
- 1 - this_lig_component
) * component_extents
.width
) / num_lig_components
;
340 component_extents
.width
/= num_lig_components
;
344 unsigned int this_combining_class
= _hb_glyph_info_get_modified_combining_class (&buffer
->info
[i
]);
345 if (last_combining_class
!= this_combining_class
)
347 last_combining_class
= this_combining_class
;
348 cluster_extents
= component_extents
;
351 position_mark (plan
, font
, buffer
, cluster_extents
, i
, this_combining_class
);
353 buffer
->pos
[i
].x_advance
= 0;
354 buffer
->pos
[i
].y_advance
= 0;
355 buffer
->pos
[i
].x_offset
+= x_offset
;
356 buffer
->pos
[i
].y_offset
+= y_offset
;
359 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
360 x_offset
-= buffer
->pos
[i
].x_advance
;
361 y_offset
-= buffer
->pos
[i
].y_advance
;
363 x_offset
+= buffer
->pos
[i
].x_advance
;
364 y_offset
+= buffer
->pos
[i
].y_advance
;
370 position_cluster (const hb_ot_shape_plan_t
*plan
,
379 /* Find the base glyph */
380 for (unsigned int i
= start
; i
< end
; i
++)
381 if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer
->info
[i
])))
383 /* Find mark glyphs */
385 for (j
= i
+ 1; j
< end
; j
++)
386 if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer
->info
[j
])))
389 position_around_base (plan
, font
, buffer
, i
, j
);
396 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t
*plan
,
400 unsigned int start
= 0;
401 unsigned int last_cluster
= buffer
->info
[0].cluster
;
402 unsigned int count
= buffer
->len
;
403 for (unsigned int i
= 1; i
< count
; i
++)
404 if (buffer
->info
[i
].cluster
!= last_cluster
) {
405 position_cluster (plan
, font
, buffer
, start
, i
);
407 last_cluster
= buffer
->info
[i
].cluster
;
409 position_cluster (plan
, font
, buffer
, start
, count
);
413 /* Performs old-style TrueType kerning. */
415 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t
*plan
,
419 unsigned int count
= buffer
->len
;
420 hb_mask_t kern_mask
= plan
->map
.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer
->props
.direction
) ?
421 HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
423 OT::hb_apply_context_t
c (1, font
, buffer
, kern_mask
, true/*auto_zwj*/);
424 c
.set_lookup_props (OT::LookupFlag::IgnoreMarks
);
426 for (buffer
->idx
= 0; buffer
->idx
< count
;)
428 OT::hb_apply_context_t::skipping_forward_iterator_t
skippy_iter (&c
, buffer
->idx
, 1);
429 if (!skippy_iter
.next ())
435 hb_position_t x_kern
, y_kern
, kern1
, kern2
;
436 font
->get_glyph_kerning_for_direction (buffer
->info
[buffer
->idx
].codepoint
,
437 buffer
->info
[skippy_iter
.idx
].codepoint
,
438 buffer
->props
.direction
,
442 kern2
= x_kern
- kern1
;
443 buffer
->pos
[buffer
->idx
].x_advance
+= kern1
;
444 buffer
->pos
[skippy_iter
.idx
].x_advance
+= kern2
;
445 buffer
->pos
[skippy_iter
.idx
].x_offset
+= kern2
;
448 kern2
= y_kern
- kern1
;
449 buffer
->pos
[buffer
->idx
].y_advance
+= kern1
;
450 buffer
->pos
[skippy_iter
.idx
].y_advance
+= kern2
;
451 buffer
->pos
[skippy_iter
.idx
].y_offset
+= kern2
;
453 buffer
->idx
= skippy_iter
.idx
;