2 * Copyright © 2012 Mozilla Foundation.
3 * Copyright © 2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Mozilla Author(s): Jonathan Kew
26 * Google Author(s): Behdad Esfahbod
29 #define HB_SHAPER coretext
30 #include "hb-shaper-impl-private.hh"
32 #include "hb-coretext.h"
35 #ifndef HB_DEBUG_CORETEXT
36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
40 HB_SHAPER_DATA_ENSURE_DECLARE(coretext
, face
)
41 HB_SHAPER_DATA_ENSURE_DECLARE(coretext
, font
)
48 struct hb_coretext_shaper_face_data_t
{
53 release_data (void *info
, const void *data
, size_t size
)
55 assert (hb_blob_get_length ((hb_blob_t
*) info
) == size
&&
56 hb_blob_get_data ((hb_blob_t
*) info
, NULL
) == data
);
58 hb_blob_destroy ((hb_blob_t
*) info
);
61 hb_coretext_shaper_face_data_t
*
62 _hb_coretext_shaper_face_data_create (hb_face_t
*face
)
64 hb_coretext_shaper_face_data_t
*data
= (hb_coretext_shaper_face_data_t
*) calloc (1, sizeof (hb_coretext_shaper_face_data_t
));
68 hb_blob_t
*blob
= hb_face_reference_blob (face
);
69 unsigned int blob_length
;
70 const char *blob_data
= hb_blob_get_data (blob
, &blob_length
);
71 if (unlikely (!blob_length
))
72 DEBUG_MSG (CORETEXT
, face
, "Face has empty blob");
74 CGDataProviderRef provider
= CGDataProviderCreateWithData (blob
, blob_data
, blob_length
, &release_data
);
75 data
->cg_font
= CGFontCreateWithDataProvider (provider
);
76 CGDataProviderRelease (provider
);
78 if (unlikely (!data
->cg_font
)) {
79 DEBUG_MSG (CORETEXT
, face
, "Face CGFontCreateWithDataProvider() failed");
88 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t
*data
)
90 CFRelease (data
->cg_font
);
95 hb_coretext_face_get_cg_font (hb_face_t
*face
)
97 if (unlikely (!hb_coretext_shaper_face_data_ensure (face
))) return NULL
;
98 hb_coretext_shaper_face_data_t
*face_data
= HB_SHAPER_DATA_GET (face
);
99 return face_data
->cg_font
;
107 struct hb_coretext_shaper_font_data_t
{
111 hb_coretext_shaper_font_data_t
*
112 _hb_coretext_shaper_font_data_create (hb_font_t
*font
)
114 if (unlikely (!hb_coretext_shaper_face_data_ensure (font
->face
))) return NULL
;
116 hb_coretext_shaper_font_data_t
*data
= (hb_coretext_shaper_font_data_t
*) calloc (1, sizeof (hb_coretext_shaper_font_data_t
));
117 if (unlikely (!data
))
120 hb_face_t
*face
= font
->face
;
121 hb_coretext_shaper_face_data_t
*face_data
= HB_SHAPER_DATA_GET (face
);
123 data
->ct_font
= CTFontCreateWithGraphicsFont (face_data
->cg_font
, font
->y_scale
, NULL
, NULL
);
124 if (unlikely (!data
->ct_font
)) {
125 DEBUG_MSG (CORETEXT
, font
, "Font CTFontCreateWithGraphicsFont() failed");
134 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t
*data
)
136 CFRelease (data
->ct_font
);
142 * shaper shape_plan data
145 struct hb_coretext_shaper_shape_plan_data_t
{};
147 hb_coretext_shaper_shape_plan_data_t
*
148 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t
*shape_plan HB_UNUSED
,
149 const hb_feature_t
*user_features HB_UNUSED
,
150 unsigned int num_user_features HB_UNUSED
)
152 return (hb_coretext_shaper_shape_plan_data_t
*) HB_SHAPER_DATA_SUCCEEDED
;
156 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t
*data HB_UNUSED
)
161 hb_coretext_font_get_ct_font (hb_font_t
*font
)
163 if (unlikely (!hb_coretext_shaper_font_data_ensure (font
))) return NULL
;
164 hb_coretext_shaper_font_data_t
*font_data
= HB_SHAPER_DATA_GET (font
);
165 return font_data
->ct_font
;
174 _hb_coretext_shape (hb_shape_plan_t
*shape_plan
,
177 const hb_feature_t
*features
,
178 unsigned int num_features
)
180 hb_face_t
*face
= font
->face
;
181 hb_coretext_shaper_face_data_t
*face_data
= HB_SHAPER_DATA_GET (face
);
182 hb_coretext_shaper_font_data_t
*font_data
= HB_SHAPER_DATA_GET (font
);
186 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
190 unsigned int scratch_size
;
191 char *scratch
= (char *) buffer
->get_scratch_buffer (&scratch_size
);
193 #define utf16_index() var1.u32
195 UniChar
*pchars
= (UniChar
*) scratch
;
196 unsigned int chars_len
= 0;
197 for (unsigned int i
= 0; i
< buffer
->len
; i
++) {
198 hb_codepoint_t c
= buffer
->info
[i
].codepoint
;
199 buffer
->info
[i
].utf16_index() = chars_len
;
200 if (likely (c
< 0x10000))
201 pchars
[chars_len
++] = c
;
202 else if (unlikely (c
>= 0x110000))
203 pchars
[chars_len
++] = 0xFFFD;
205 pchars
[chars_len
++] = 0xD800 + ((c
- 0x10000) >> 10);
206 pchars
[chars_len
++] = 0xDC00 + ((c
- 0x10000) & ((1 << 10) - 1));
212 CFStringRef string_ref
= CFStringCreateWithCharactersNoCopy (kCFAllocatorDefault
,
216 CFDictionaryRef attrs
= CFDictionaryCreate (kCFAllocatorDefault
,
217 (const void**) &kCTFontAttributeName
,
218 (const void**) &font_data
->ct_font
,
219 1, /* count of attributes */
220 &kCFTypeDictionaryKeyCallBacks
,
221 &kCFTypeDictionaryValueCallBacks
);
223 /* TODO: support features */
225 CFAttributedStringRef attr_string
= CFAttributedStringCreate (kCFAllocatorDefault
, string_ref
, attrs
);
226 CFRelease (string_ref
);
229 CTLineRef line
= CTLineCreateWithAttributedString (attr_string
);
230 CFRelease (attr_string
);
232 CFArrayRef glyph_runs
= CTLineGetGlyphRuns (line
);
233 unsigned int num_runs
= CFArrayGetCount (glyph_runs
);
238 const CFRange range_all
= CFRangeMake (0, 0);
240 for (unsigned int i
= 0; i
< num_runs
; i
++) {
241 CTRunRef run
= (CTRunRef
) CFArrayGetValueAtIndex (glyph_runs
, i
);
243 unsigned int num_glyphs
= CTRunGetGlyphCount (run
);
247 buffer
->ensure (buffer
->len
+ num_glyphs
);
249 /* Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds,
250 * and so copying data to our own buffer with CTRunGetGlyphs will be
253 unsigned int scratch_size
;
254 char *scratch
= (char *) buffer
->get_scratch_buffer (&scratch_size
);
256 #define ALLOCATE_ARRAY(Type, name, len) \
257 Type *name = (Type *) scratch; \
258 scratch += (len) * sizeof ((name)[0]); \
259 scratch_size -= (len) * sizeof ((name)[0]);
261 const CGGlyph
* glyphs
= CTRunGetGlyphsPtr (run
);
263 ALLOCATE_ARRAY (CGGlyph
, glyph_buf
, num_glyphs
);
264 CTRunGetGlyphs (run
, range_all
, glyph_buf
);
268 const CGPoint
* positions
= CTRunGetPositionsPtr (run
);
270 ALLOCATE_ARRAY (CGPoint
, position_buf
, num_glyphs
);
271 CTRunGetPositions (run
, range_all
, position_buf
);
272 positions
= position_buf
;
275 const CFIndex
* string_indices
= CTRunGetStringIndicesPtr (run
);
276 if (!string_indices
) {
277 ALLOCATE_ARRAY (CFIndex
, index_buf
, num_glyphs
);
278 CTRunGetStringIndices (run
, range_all
, index_buf
);
279 string_indices
= index_buf
;
282 #undef ALLOCATE_ARRAY
284 double run_width
= CTRunGetTypographicBounds (run
, range_all
, NULL
, NULL
, NULL
);
286 for (unsigned int j
= 0; j
< num_glyphs
; j
++) {
287 double advance
= (j
+ 1 < num_glyphs
? positions
[j
+ 1].x
: positions
[0].x
+ run_width
) - positions
[j
].x
;
289 hb_glyph_info_t
*info
= &buffer
->info
[buffer
->len
];
290 hb_glyph_position_t
*pos
= &buffer
->pos
[buffer
->len
];
292 info
->codepoint
= glyphs
[j
];
293 info
->cluster
= string_indices
[j
];
295 /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
296 info
->mask
= advance
;
298 info
->var2
.u32
= positions
[j
].y
;
304 buffer
->clear_positions ();
306 unsigned int count
= buffer
->len
;
307 for (unsigned int i
= 0; i
< count
; ++i
) {
308 hb_glyph_info_t
*info
= &buffer
->info
[i
];
309 hb_glyph_position_t
*pos
= &buffer
->pos
[i
];
312 pos
->x_advance
= info
->mask
;
313 pos
->x_offset
= info
->var1
.u32
;
314 pos
->y_offset
= info
->var2
.u32
;
317 /* Fix up clusters so that we never return out-of-order indices;
318 * if core text has reordered glyphs, we'll merge them to the
319 * beginning of the reordered cluster.
321 * This does *not* mean we'll form the same clusters as Uniscribe
322 * or the native OT backend, only that the cluster indices will be
323 * monotonic in the output buffer. */
324 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
325 unsigned int prev_cluster
= 0;
326 for (unsigned int i
= 0; i
< count
; i
++) {
327 unsigned int curr_cluster
= buffer
->info
[i
].cluster
;
328 if (curr_cluster
< prev_cluster
) {
329 for (unsigned int j
= i
; j
> 0; j
--) {
330 if (buffer
->info
[j
- 1].cluster
> curr_cluster
)
331 buffer
->info
[j
- 1].cluster
= curr_cluster
;
336 prev_cluster
= curr_cluster
;
339 unsigned int prev_cluster
= (unsigned int)-1;
340 for (unsigned int i
= 0; i
< count
; i
++) {
341 unsigned int curr_cluster
= buffer
->info
[i
].cluster
;
342 if (curr_cluster
> prev_cluster
) {
343 for (unsigned int j
= i
; j
> 0; j
--) {
344 if (buffer
->info
[j
- 1].cluster
< curr_cluster
)
345 buffer
->info
[j
- 1].cluster
= curr_cluster
;
350 prev_cluster
= curr_cluster
;