2 * Copyright © 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
28 #define hb_old_shaper_face_data_t HB_FaceRec_
29 #define hb_old_shaper_font_data_t HB_Font_
30 #include "hb-shaper-impl-private.hh"
36 #define HB_DEBUG_OLD (HB_DEBUG+0)
41 hb_old_script_from_script (hb_script_t script
)
43 switch ((hb_tag_t
) script
)
46 case HB_SCRIPT_COMMON
: return HB_Script_Common
;
47 case HB_SCRIPT_GREEK
: return HB_Script_Greek
;
48 case HB_SCRIPT_CYRILLIC
: return HB_Script_Cyrillic
;
49 case HB_SCRIPT_ARMENIAN
: return HB_Script_Armenian
;
50 case HB_SCRIPT_HEBREW
: return HB_Script_Hebrew
;
51 case HB_SCRIPT_ARABIC
: return HB_Script_Arabic
;
52 case HB_SCRIPT_SYRIAC
: return HB_Script_Syriac
;
53 case HB_SCRIPT_THAANA
: return HB_Script_Thaana
;
54 case HB_SCRIPT_DEVANAGARI
: return HB_Script_Devanagari
;
55 case HB_SCRIPT_BENGALI
: return HB_Script_Bengali
;
56 case HB_SCRIPT_GURMUKHI
: return HB_Script_Gurmukhi
;
57 case HB_SCRIPT_GUJARATI
: return HB_Script_Gujarati
;
58 case HB_SCRIPT_ORIYA
: return HB_Script_Oriya
;
59 case HB_SCRIPT_TAMIL
: return HB_Script_Tamil
;
60 case HB_SCRIPT_TELUGU
: return HB_Script_Telugu
;
61 case HB_SCRIPT_KANNADA
: return HB_Script_Kannada
;
62 case HB_SCRIPT_MALAYALAM
: return HB_Script_Malayalam
;
63 case HB_SCRIPT_SINHALA
: return HB_Script_Sinhala
;
64 case HB_SCRIPT_THAI
: return HB_Script_Thai
;
65 case HB_SCRIPT_LAO
: return HB_Script_Lao
;
66 case HB_SCRIPT_TIBETAN
: return HB_Script_Tibetan
;
67 case HB_SCRIPT_MYANMAR
: return HB_Script_Myanmar
;
68 case HB_SCRIPT_GEORGIAN
: return HB_Script_Georgian
;
69 case HB_SCRIPT_HANGUL
: return HB_Script_Hangul
;
70 case HB_SCRIPT_OGHAM
: return HB_Script_Ogham
;
71 case HB_SCRIPT_RUNIC
: return HB_Script_Runic
;
72 case HB_SCRIPT_KHMER
: return HB_Script_Khmer
;
73 case HB_SCRIPT_NKO
: return HB_Script_Nko
;
74 case HB_SCRIPT_INHERITED
: return HB_Script_Inherited
;
80 hb_old_convertStringToGlyphIndices (HB_Font old_font
,
81 const HB_UChar16
*string
,
87 hb_font_t
*font
= (hb_font_t
*) old_font
->userData
;
89 for (unsigned int i
= 0; i
< length
; i
++)
93 /* XXX Handle UTF-16. Ugh */
97 u
= hb_unicode_funcs_get_default ()->mirroring (u
);
99 font
->get_glyph (u
, 0, &u
); /* TODO Variation selectors */
103 *numGlyphs
= length
; /* XXX */
109 hb_old_getGlyphAdvances (HB_Font old_font
,
110 const HB_Glyph
*glyphs
,
113 int flags
/*HB_ShaperFlag*/ HB_UNUSED
)
115 hb_font_t
*font
= (hb_font_t
*) old_font
->userData
;
117 for (unsigned int i
= 0; i
< numGlyphs
; i
++)
118 advances
[i
] = font
->get_glyph_h_advance (glyphs
[i
]);
122 hb_old_canRender (HB_Font old_font
,
123 const HB_UChar16
*string
,
126 return true; /* TODO */
130 hb_old_getPointInOutline (HB_Font old_font
,
132 int flags
/*HB_ShaperFlag*/,
138 return HB_Err_Ok
; /* TODO */
142 hb_old_getGlyphMetrics (HB_Font old_font
,
144 HB_GlyphMetrics
*metrics
)
146 hb_font_t
*font
= (hb_font_t
*) old_font
->userData
;
148 hb_glyph_extents_t extents
;
150 font
->get_glyph_extents (glyph
, &extents
);
152 metrics
->x
= extents
.x_bearing
;
153 metrics
->y
= extents
.y_bearing
;
154 metrics
->width
= extents
.width
;
155 metrics
->height
= extents
.height
;
156 metrics
->xOffset
= font
->get_glyph_h_advance (glyph
);
157 metrics
->yOffset
= 0;
161 hb_old_getFontMetric (HB_Font old_font
,
162 HB_FontMetric metric
)
164 hb_font_t
*font
= (hb_font_t
*) old_font
->userData
;
169 return font
->y_scale
; /* XXX We don't have ascent data yet. */
176 static const HB_FontClass hb_old_font_class
= {
177 hb_old_convertStringToGlyphIndices
,
178 hb_old_getGlyphAdvances
,
180 hb_old_getPointInOutline
,
181 hb_old_getGlyphMetrics
,
188 table_func (void *font
, HB_Tag tag
, HB_Byte
*buffer
, HB_UInt
*length
)
190 hb_face_t
*face
= (hb_face_t
*) font
;
191 hb_blob_t
*blob
= face
->reference_table ((hb_tag_t
) tag
);
192 unsigned int capacity
= *length
;
193 *length
= hb_blob_get_length (blob
);
194 memcpy (buffer
, hb_blob_get_data (blob
, NULL
), MIN (capacity
, *length
));
195 hb_blob_destroy (blob
);
204 hb_old_shaper_face_data_t
*
205 _hb_old_shaper_face_data_create (hb_face_t
*face
)
207 return HB_NewFace (face
, table_func
);
211 _hb_old_shaper_face_data_destroy (hb_old_shaper_face_data_t
*data
)
221 hb_old_shaper_font_data_t
*
222 _hb_old_shaper_font_data_create (hb_font_t
*font
)
224 HB_FontRec
*data
= (HB_FontRec
*) calloc (1, sizeof (HB_FontRec
));
225 if (unlikely (!data
)) {
226 DEBUG_MSG (OLD
, font
, "malloc()ing HB_Font failed");
230 data
->klass
= &hb_old_font_class
;
231 data
->x_ppem
= font
->x_ppem
;
232 data
->y_ppem
= font
->y_ppem
;
233 data
->x_scale
= font
->x_scale
; /* XXX */
234 data
->y_scale
= font
->y_scale
; /* XXX */
235 data
->userData
= font
;
241 _hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t
*data
)
248 * shaper shape_plan data
251 struct hb_old_shaper_shape_plan_data_t
{};
253 hb_old_shaper_shape_plan_data_t
*
254 _hb_old_shaper_shape_plan_data_create (hb_shape_plan_t
*shape_plan HB_UNUSED
,
255 const hb_feature_t
*user_features HB_UNUSED
,
256 unsigned int num_user_features HB_UNUSED
)
258 return (hb_old_shaper_shape_plan_data_t
*) HB_SHAPER_DATA_SUCCEEDED
;
262 _hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t
*data HB_UNUSED
)
272 _hb_old_shape (hb_shape_plan_t
*shape_plan HB_UNUSED
,
275 const hb_feature_t
*features
,
276 unsigned int num_features
)
278 hb_face_t
*face
= font
->face
;
279 HB_Face old_face
= HB_SHAPER_DATA_GET (face
);
280 HB_Font old_font
= HB_SHAPER_DATA_GET (font
);
282 bool backward
= HB_DIRECTION_IS_BACKWARD (buffer
->props
.direction
);
286 unsigned int scratch_size
;
287 char *scratch
= (char *) buffer
->get_scratch_buffer (&scratch_size
);
289 #define utf16_index() var1.u32
290 HB_UChar16
*pchars
= (HB_UChar16
*) scratch
;
291 unsigned int chars_len
= 0;
292 for (unsigned int i
= 0; i
< buffer
->len
; i
++) {
293 hb_codepoint_t c
= buffer
->info
[i
].codepoint
;
294 buffer
->info
[i
].utf16_index() = chars_len
;
295 if (likely (c
< 0x10000))
296 pchars
[chars_len
++] = c
;
297 else if (unlikely (c
>= 0x110000))
298 pchars
[chars_len
++] = 0xFFFD;
300 pchars
[chars_len
++] = 0xD800 + ((c
- 0x10000) >> 10);
301 pchars
[chars_len
++] = 0xDC00 + ((c
- 0x10000) & ((1 << 10) - 1));
306 #define ALLOCATE_ARRAY(Type, name, len) \
307 name = (Type *) scratch; \
308 scratch += (len) * sizeof ((name)[0]); \
309 scratch_size -= (len) * sizeof ((name)[0]);
312 HB_ShaperItem item
= {0};
314 ALLOCATE_ARRAY (const HB_UChar16
, item
.string
, chars_len
);
315 ALLOCATE_ARRAY (unsigned short, item
.log_clusters
, chars_len
+ 2);
316 item
.stringLength
= chars_len
;
318 item
.item
.length
= item
.stringLength
;
319 item
.item
.script
= hb_old_script_from_script (buffer
->props
.script
);
320 item
.item
.bidiLevel
= backward
? 1 : 0;
322 item
.font
= old_font
;
323 item
.face
= old_face
;
324 item
.shaperFlags
= 0;
326 item
.glyphIndicesPresent
= false;
328 /* TODO Alignment. */
329 unsigned int num_glyphs
= scratch_size
/ (sizeof (HB_Glyph
) +
330 sizeof (HB_GlyphAttributes
) +
332 sizeof (HB_FixedPoint
) +
335 item
.num_glyphs
= num_glyphs
;
336 ALLOCATE_ARRAY (HB_Glyph
, item
.glyphs
, num_glyphs
);
337 ALLOCATE_ARRAY (HB_GlyphAttributes
, item
.attributes
, num_glyphs
);
338 ALLOCATE_ARRAY (HB_Fixed
, item
.advances
, num_glyphs
);
339 ALLOCATE_ARRAY (HB_FixedPoint
, item
.offsets
, num_glyphs
);
340 /* Apparently in some cases the offsets array will not be fully assigned to.
342 memset (item
.offsets
, 0, num_glyphs
* sizeof (item
.offsets
[0]));
343 uint32_t *vis_clusters
;
344 ALLOCATE_ARRAY (uint32_t, vis_clusters
, num_glyphs
);
346 #undef ALLOCATE_ARRAY
348 if (!HB_ShapeItem (&item
))
350 if (unlikely (item
.num_glyphs
> num_glyphs
))
352 buffer
->ensure (buffer
->allocated
* 2);
353 if (buffer
->in_error
)
359 num_glyphs
= item
.num_glyphs
;
361 /* Ok, we've got everything we need, now compose output buffer,
362 * very, *very*, carefully! */
364 /* Calculate visual-clusters. That's what we ship. */
365 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
366 vis_clusters
[i
] = -1;
367 for (unsigned int i
= 0; i
< buffer
->len
; i
++) {
368 uint32_t *p
= &vis_clusters
[item
.log_clusters
[buffer
->info
[i
].utf16_index()]];
369 *p
= MIN (*p
, buffer
->info
[i
].cluster
);
371 for (unsigned int i
= 1; i
< num_glyphs
; i
++)
372 if (vis_clusters
[i
] == (uint32_t) -1)
373 vis_clusters
[i
] = vis_clusters
[i
- 1];
377 buffer
->ensure (num_glyphs
);
378 if (buffer
->in_error
)
382 buffer
->len
= num_glyphs
;
383 hb_glyph_info_t
*info
= buffer
->info
;
384 for (unsigned int i
= 0; i
< num_glyphs
; i
++)
386 info
[i
].codepoint
= item
.glyphs
[i
];
387 info
[i
].cluster
= vis_clusters
[i
];
389 info
[i
].mask
= item
.advances
[i
];
390 info
[i
].var1
.u32
= item
.offsets
[i
].x
;
391 info
[i
].var2
.u32
= item
.offsets
[i
].y
;
394 buffer
->clear_positions ();
396 for (unsigned int i
= 0; i
< num_glyphs
; ++i
) {
397 hb_glyph_info_t
*info
= &buffer
->info
[i
];
398 hb_glyph_position_t
*pos
= &buffer
->pos
[i
];
401 pos
->x_advance
= info
->mask
;
402 pos
->x_offset
= info
->var1
.u32
;
403 pos
->y_offset
= info
->var2
.u32
;
406 if (HB_DIRECTION_IS_BACKWARD (buffer
->props
.direction
))