Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright © 2009 Red Hat, Inc. |
michael@0 | 3 | * Copyright © 2009 Keith Stribley |
michael@0 | 4 | * |
michael@0 | 5 | * This is part of HarfBuzz, a text shaping library. |
michael@0 | 6 | * |
michael@0 | 7 | * Permission is hereby granted, without written agreement and without |
michael@0 | 8 | * license or royalty fees, to use, copy, modify, and distribute this |
michael@0 | 9 | * software and its documentation for any purpose, provided that the |
michael@0 | 10 | * above copyright notice and the following two paragraphs appear in |
michael@0 | 11 | * all copies of this software. |
michael@0 | 12 | * |
michael@0 | 13 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
michael@0 | 14 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
michael@0 | 15 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
michael@0 | 16 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
michael@0 | 17 | * DAMAGE. |
michael@0 | 18 | * |
michael@0 | 19 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
michael@0 | 20 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
michael@0 | 21 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
michael@0 | 22 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
michael@0 | 23 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
michael@0 | 24 | * |
michael@0 | 25 | * Red Hat Author(s): Behdad Esfahbod |
michael@0 | 26 | */ |
michael@0 | 27 | |
michael@0 | 28 | #include "hb-private.hh" |
michael@0 | 29 | |
michael@0 | 30 | #include "hb-ft.h" |
michael@0 | 31 | |
michael@0 | 32 | #include "hb-font-private.hh" |
michael@0 | 33 | |
michael@0 | 34 | #include FT_ADVANCES_H |
michael@0 | 35 | #include FT_TRUETYPE_TABLES_H |
michael@0 | 36 | |
michael@0 | 37 | |
michael@0 | 38 | |
michael@0 | 39 | #ifndef HB_DEBUG_FT |
michael@0 | 40 | #define HB_DEBUG_FT (HB_DEBUG+0) |
michael@0 | 41 | #endif |
michael@0 | 42 | |
michael@0 | 43 | |
michael@0 | 44 | /* TODO: |
michael@0 | 45 | * |
michael@0 | 46 | * In general, this file does a fine job of what it's supposed to do. |
michael@0 | 47 | * There are, however, things that need more work: |
michael@0 | 48 | * |
michael@0 | 49 | * - We don't handle any load_flags. That definitely has API implications. :( |
michael@0 | 50 | * I believe hb_ft_font_create() should take load_flags input. |
michael@0 | 51 | * In particular, FT_Get_Advance() without the NO_HINTING flag seems to be |
michael@0 | 52 | * buggy. |
michael@0 | 53 | * |
michael@0 | 54 | * - We don't handle / allow for emboldening / obliqueing. |
michael@0 | 55 | * |
michael@0 | 56 | * - In the future, we should add constructors to create fonts in font space? |
michael@0 | 57 | * |
michael@0 | 58 | * - FT_Load_Glyph() is exteremely costly. Do something about it? |
michael@0 | 59 | */ |
michael@0 | 60 | |
michael@0 | 61 | |
michael@0 | 62 | static hb_bool_t |
michael@0 | 63 | hb_ft_get_glyph (hb_font_t *font HB_UNUSED, |
michael@0 | 64 | void *font_data, |
michael@0 | 65 | hb_codepoint_t unicode, |
michael@0 | 66 | hb_codepoint_t variation_selector, |
michael@0 | 67 | hb_codepoint_t *glyph, |
michael@0 | 68 | void *user_data HB_UNUSED) |
michael@0 | 69 | |
michael@0 | 70 | { |
michael@0 | 71 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 72 | |
michael@0 | 73 | #ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX |
michael@0 | 74 | if (unlikely (variation_selector)) { |
michael@0 | 75 | *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector); |
michael@0 | 76 | return *glyph != 0; |
michael@0 | 77 | } |
michael@0 | 78 | #endif |
michael@0 | 79 | |
michael@0 | 80 | *glyph = FT_Get_Char_Index (ft_face, unicode); |
michael@0 | 81 | return *glyph != 0; |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | static hb_position_t |
michael@0 | 85 | hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED, |
michael@0 | 86 | void *font_data, |
michael@0 | 87 | hb_codepoint_t glyph, |
michael@0 | 88 | void *user_data HB_UNUSED) |
michael@0 | 89 | { |
michael@0 | 90 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 91 | int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; |
michael@0 | 92 | FT_Fixed v; |
michael@0 | 93 | |
michael@0 | 94 | if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) |
michael@0 | 95 | return 0; |
michael@0 | 96 | |
michael@0 | 97 | return (v + (1<<9)) >> 10; |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | static hb_position_t |
michael@0 | 101 | hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED, |
michael@0 | 102 | void *font_data, |
michael@0 | 103 | hb_codepoint_t glyph, |
michael@0 | 104 | void *user_data HB_UNUSED) |
michael@0 | 105 | { |
michael@0 | 106 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 107 | int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT; |
michael@0 | 108 | FT_Fixed v; |
michael@0 | 109 | |
michael@0 | 110 | if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) |
michael@0 | 111 | return 0; |
michael@0 | 112 | |
michael@0 | 113 | /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates |
michael@0 | 114 | * have a Y growing upward. Hence the extra negation. */ |
michael@0 | 115 | return (-v + (1<<9)) >> 10; |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | static hb_bool_t |
michael@0 | 119 | hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED, |
michael@0 | 120 | void *font_data HB_UNUSED, |
michael@0 | 121 | hb_codepoint_t glyph HB_UNUSED, |
michael@0 | 122 | hb_position_t *x HB_UNUSED, |
michael@0 | 123 | hb_position_t *y HB_UNUSED, |
michael@0 | 124 | void *user_data HB_UNUSED) |
michael@0 | 125 | { |
michael@0 | 126 | /* We always work in the horizontal coordinates. */ |
michael@0 | 127 | return true; |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | static hb_bool_t |
michael@0 | 131 | hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED, |
michael@0 | 132 | void *font_data, |
michael@0 | 133 | hb_codepoint_t glyph, |
michael@0 | 134 | hb_position_t *x, |
michael@0 | 135 | hb_position_t *y, |
michael@0 | 136 | void *user_data HB_UNUSED) |
michael@0 | 137 | { |
michael@0 | 138 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 139 | int load_flags = FT_LOAD_DEFAULT; |
michael@0 | 140 | |
michael@0 | 141 | if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) |
michael@0 | 142 | return false; |
michael@0 | 143 | |
michael@0 | 144 | /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates |
michael@0 | 145 | * have a Y growing upward. Hence the extra negation. */ |
michael@0 | 146 | *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; |
michael@0 | 147 | *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); |
michael@0 | 148 | |
michael@0 | 149 | return true; |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | static hb_position_t |
michael@0 | 153 | hb_ft_get_glyph_h_kerning (hb_font_t *font, |
michael@0 | 154 | void *font_data, |
michael@0 | 155 | hb_codepoint_t left_glyph, |
michael@0 | 156 | hb_codepoint_t right_glyph, |
michael@0 | 157 | void *user_data HB_UNUSED) |
michael@0 | 158 | { |
michael@0 | 159 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 160 | FT_Vector kerningv; |
michael@0 | 161 | |
michael@0 | 162 | FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; |
michael@0 | 163 | if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv)) |
michael@0 | 164 | return 0; |
michael@0 | 165 | |
michael@0 | 166 | return kerningv.x; |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | static hb_position_t |
michael@0 | 170 | hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, |
michael@0 | 171 | void *font_data HB_UNUSED, |
michael@0 | 172 | hb_codepoint_t top_glyph HB_UNUSED, |
michael@0 | 173 | hb_codepoint_t bottom_glyph HB_UNUSED, |
michael@0 | 174 | void *user_data HB_UNUSED) |
michael@0 | 175 | { |
michael@0 | 176 | /* FreeType API doesn't support vertical kerning */ |
michael@0 | 177 | return 0; |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | static hb_bool_t |
michael@0 | 181 | hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, |
michael@0 | 182 | void *font_data, |
michael@0 | 183 | hb_codepoint_t glyph, |
michael@0 | 184 | hb_glyph_extents_t *extents, |
michael@0 | 185 | void *user_data HB_UNUSED) |
michael@0 | 186 | { |
michael@0 | 187 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 188 | int load_flags = FT_LOAD_DEFAULT; |
michael@0 | 189 | |
michael@0 | 190 | if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) |
michael@0 | 191 | return false; |
michael@0 | 192 | |
michael@0 | 193 | extents->x_bearing = ft_face->glyph->metrics.horiBearingX; |
michael@0 | 194 | extents->y_bearing = ft_face->glyph->metrics.horiBearingY; |
michael@0 | 195 | extents->width = ft_face->glyph->metrics.width; |
michael@0 | 196 | extents->height = -ft_face->glyph->metrics.height; |
michael@0 | 197 | return true; |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | static hb_bool_t |
michael@0 | 201 | hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, |
michael@0 | 202 | void *font_data, |
michael@0 | 203 | hb_codepoint_t glyph, |
michael@0 | 204 | unsigned int point_index, |
michael@0 | 205 | hb_position_t *x, |
michael@0 | 206 | hb_position_t *y, |
michael@0 | 207 | void *user_data HB_UNUSED) |
michael@0 | 208 | { |
michael@0 | 209 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 210 | int load_flags = FT_LOAD_DEFAULT; |
michael@0 | 211 | |
michael@0 | 212 | if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) |
michael@0 | 213 | return false; |
michael@0 | 214 | |
michael@0 | 215 | if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) |
michael@0 | 216 | return false; |
michael@0 | 217 | |
michael@0 | 218 | if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) |
michael@0 | 219 | return false; |
michael@0 | 220 | |
michael@0 | 221 | *x = ft_face->glyph->outline.points[point_index].x; |
michael@0 | 222 | *y = ft_face->glyph->outline.points[point_index].y; |
michael@0 | 223 | |
michael@0 | 224 | return true; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | static hb_bool_t |
michael@0 | 228 | hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, |
michael@0 | 229 | void *font_data, |
michael@0 | 230 | hb_codepoint_t glyph, |
michael@0 | 231 | char *name, unsigned int size, |
michael@0 | 232 | void *user_data HB_UNUSED) |
michael@0 | 233 | { |
michael@0 | 234 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 235 | |
michael@0 | 236 | hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); |
michael@0 | 237 | if (ret && (size && !*name)) |
michael@0 | 238 | ret = false; |
michael@0 | 239 | |
michael@0 | 240 | return ret; |
michael@0 | 241 | } |
michael@0 | 242 | |
michael@0 | 243 | static hb_bool_t |
michael@0 | 244 | hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, |
michael@0 | 245 | void *font_data, |
michael@0 | 246 | const char *name, int len, /* -1 means nul-terminated */ |
michael@0 | 247 | hb_codepoint_t *glyph, |
michael@0 | 248 | void *user_data HB_UNUSED) |
michael@0 | 249 | { |
michael@0 | 250 | FT_Face ft_face = (FT_Face) font_data; |
michael@0 | 251 | |
michael@0 | 252 | if (len < 0) |
michael@0 | 253 | *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); |
michael@0 | 254 | else { |
michael@0 | 255 | /* Make a nul-terminated version. */ |
michael@0 | 256 | char buf[128]; |
michael@0 | 257 | len = MIN (len, (int) sizeof (buf) - 1); |
michael@0 | 258 | strncpy (buf, name, len); |
michael@0 | 259 | buf[len] = '\0'; |
michael@0 | 260 | *glyph = FT_Get_Name_Index (ft_face, buf); |
michael@0 | 261 | } |
michael@0 | 262 | |
michael@0 | 263 | if (*glyph == 0) |
michael@0 | 264 | { |
michael@0 | 265 | /* Check whether the given name was actually the name of glyph 0. */ |
michael@0 | 266 | char buf[128]; |
michael@0 | 267 | if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) && |
michael@0 | 268 | len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len)) |
michael@0 | 269 | return true; |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | return *glyph != 0; |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | |
michael@0 | 276 | static hb_font_funcs_t * |
michael@0 | 277 | _hb_ft_get_font_funcs (void) |
michael@0 | 278 | { |
michael@0 | 279 | static const hb_font_funcs_t ft_ffuncs = { |
michael@0 | 280 | HB_OBJECT_HEADER_STATIC, |
michael@0 | 281 | |
michael@0 | 282 | true, /* immutable */ |
michael@0 | 283 | |
michael@0 | 284 | { |
michael@0 | 285 | #define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name, |
michael@0 | 286 | HB_FONT_FUNCS_IMPLEMENT_CALLBACKS |
michael@0 | 287 | #undef HB_FONT_FUNC_IMPLEMENT |
michael@0 | 288 | } |
michael@0 | 289 | }; |
michael@0 | 290 | |
michael@0 | 291 | return const_cast<hb_font_funcs_t *> (&ft_ffuncs); |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | |
michael@0 | 295 | static hb_blob_t * |
michael@0 | 296 | reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) |
michael@0 | 297 | { |
michael@0 | 298 | FT_Face ft_face = (FT_Face) user_data; |
michael@0 | 299 | FT_Byte *buffer; |
michael@0 | 300 | FT_ULong length = 0; |
michael@0 | 301 | FT_Error error; |
michael@0 | 302 | |
michael@0 | 303 | /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ |
michael@0 | 304 | |
michael@0 | 305 | error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); |
michael@0 | 306 | if (error) |
michael@0 | 307 | return NULL; |
michael@0 | 308 | |
michael@0 | 309 | buffer = (FT_Byte *) malloc (length); |
michael@0 | 310 | if (buffer == NULL) |
michael@0 | 311 | return NULL; |
michael@0 | 312 | |
michael@0 | 313 | error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); |
michael@0 | 314 | if (error) |
michael@0 | 315 | return NULL; |
michael@0 | 316 | |
michael@0 | 317 | return hb_blob_create ((const char *) buffer, length, |
michael@0 | 318 | HB_MEMORY_MODE_WRITABLE, |
michael@0 | 319 | buffer, free); |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | /** |
michael@0 | 323 | * hb_ft_face_create: |
michael@0 | 324 | * @ft_face: (destroy destroy) (scope notified): |
michael@0 | 325 | * @destroy: |
michael@0 | 326 | * |
michael@0 | 327 | * |
michael@0 | 328 | * |
michael@0 | 329 | * Return value: (transfer full): |
michael@0 | 330 | * Since: 1.0 |
michael@0 | 331 | **/ |
michael@0 | 332 | hb_face_t * |
michael@0 | 333 | hb_ft_face_create (FT_Face ft_face, |
michael@0 | 334 | hb_destroy_func_t destroy) |
michael@0 | 335 | { |
michael@0 | 336 | hb_face_t *face; |
michael@0 | 337 | |
michael@0 | 338 | if (ft_face->stream->read == NULL) { |
michael@0 | 339 | hb_blob_t *blob; |
michael@0 | 340 | |
michael@0 | 341 | blob = hb_blob_create ((const char *) ft_face->stream->base, |
michael@0 | 342 | (unsigned int) ft_face->stream->size, |
michael@0 | 343 | /* TODO: We assume that it's mmap()'ed, but FreeType code |
michael@0 | 344 | * suggests that there are cases we reach here but font is |
michael@0 | 345 | * not mmapped. For example, when mmap() fails. No idea |
michael@0 | 346 | * how to deal with it better here. */ |
michael@0 | 347 | HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, |
michael@0 | 348 | ft_face, destroy); |
michael@0 | 349 | face = hb_face_create (blob, ft_face->face_index); |
michael@0 | 350 | hb_blob_destroy (blob); |
michael@0 | 351 | } else { |
michael@0 | 352 | face = hb_face_create_for_tables (reference_table, ft_face, destroy); |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | hb_face_set_index (face, ft_face->face_index); |
michael@0 | 356 | hb_face_set_upem (face, ft_face->units_per_EM); |
michael@0 | 357 | |
michael@0 | 358 | return face; |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | static void |
michael@0 | 362 | hb_ft_face_finalize (FT_Face ft_face) |
michael@0 | 363 | { |
michael@0 | 364 | hb_face_destroy ((hb_face_t *) ft_face->generic.data); |
michael@0 | 365 | } |
michael@0 | 366 | |
michael@0 | 367 | /** |
michael@0 | 368 | * hb_ft_face_create_cached: |
michael@0 | 369 | * @ft_face: |
michael@0 | 370 | * |
michael@0 | 371 | * |
michael@0 | 372 | * |
michael@0 | 373 | * Return value: (transfer full): |
michael@0 | 374 | * Since: 1.0 |
michael@0 | 375 | **/ |
michael@0 | 376 | hb_face_t * |
michael@0 | 377 | hb_ft_face_create_cached (FT_Face ft_face) |
michael@0 | 378 | { |
michael@0 | 379 | if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize)) |
michael@0 | 380 | { |
michael@0 | 381 | if (ft_face->generic.finalizer) |
michael@0 | 382 | ft_face->generic.finalizer (ft_face); |
michael@0 | 383 | |
michael@0 | 384 | ft_face->generic.data = hb_ft_face_create (ft_face, NULL); |
michael@0 | 385 | ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize; |
michael@0 | 386 | } |
michael@0 | 387 | |
michael@0 | 388 | return hb_face_reference ((hb_face_t *) ft_face->generic.data); |
michael@0 | 389 | } |
michael@0 | 390 | |
michael@0 | 391 | static void |
michael@0 | 392 | _do_nothing (void) |
michael@0 | 393 | { |
michael@0 | 394 | } |
michael@0 | 395 | |
michael@0 | 396 | |
michael@0 | 397 | /** |
michael@0 | 398 | * hb_ft_font_create: |
michael@0 | 399 | * @ft_face: (destroy destroy) (scope notified): |
michael@0 | 400 | * @destroy: |
michael@0 | 401 | * |
michael@0 | 402 | * |
michael@0 | 403 | * |
michael@0 | 404 | * Return value: (transfer full): |
michael@0 | 405 | * Since: 1.0 |
michael@0 | 406 | **/ |
michael@0 | 407 | hb_font_t * |
michael@0 | 408 | hb_ft_font_create (FT_Face ft_face, |
michael@0 | 409 | hb_destroy_func_t destroy) |
michael@0 | 410 | { |
michael@0 | 411 | hb_font_t *font; |
michael@0 | 412 | hb_face_t *face; |
michael@0 | 413 | |
michael@0 | 414 | face = hb_ft_face_create (ft_face, destroy); |
michael@0 | 415 | font = hb_font_create (face); |
michael@0 | 416 | hb_face_destroy (face); |
michael@0 | 417 | hb_font_set_funcs (font, |
michael@0 | 418 | _hb_ft_get_font_funcs (), |
michael@0 | 419 | ft_face, (hb_destroy_func_t) _do_nothing); |
michael@0 | 420 | hb_font_set_scale (font, |
michael@0 | 421 | (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16), |
michael@0 | 422 | (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16)); |
michael@0 | 423 | hb_font_set_ppem (font, |
michael@0 | 424 | ft_face->size->metrics.x_ppem, |
michael@0 | 425 | ft_face->size->metrics.y_ppem); |
michael@0 | 426 | |
michael@0 | 427 | return font; |
michael@0 | 428 | } |
michael@0 | 429 | |
michael@0 | 430 | |
michael@0 | 431 | /* Thread-safe, lock-free, FT_Library */ |
michael@0 | 432 | |
michael@0 | 433 | static FT_Library ft_library; |
michael@0 | 434 | |
michael@0 | 435 | static inline |
michael@0 | 436 | void free_ft_library (void) |
michael@0 | 437 | { |
michael@0 | 438 | FT_Done_FreeType (ft_library); |
michael@0 | 439 | } |
michael@0 | 440 | |
michael@0 | 441 | static FT_Library |
michael@0 | 442 | get_ft_library (void) |
michael@0 | 443 | { |
michael@0 | 444 | retry: |
michael@0 | 445 | FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); |
michael@0 | 446 | |
michael@0 | 447 | if (unlikely (!library)) |
michael@0 | 448 | { |
michael@0 | 449 | /* Not found; allocate one. */ |
michael@0 | 450 | if (FT_Init_FreeType (&library)) |
michael@0 | 451 | return NULL; |
michael@0 | 452 | |
michael@0 | 453 | if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) { |
michael@0 | 454 | FT_Done_FreeType (library); |
michael@0 | 455 | goto retry; |
michael@0 | 456 | } |
michael@0 | 457 | |
michael@0 | 458 | #ifdef HAVE_ATEXIT |
michael@0 | 459 | atexit (free_ft_library); /* First person registers atexit() callback. */ |
michael@0 | 460 | #endif |
michael@0 | 461 | } |
michael@0 | 462 | |
michael@0 | 463 | return library; |
michael@0 | 464 | } |
michael@0 | 465 | |
michael@0 | 466 | static void |
michael@0 | 467 | _release_blob (FT_Face ft_face) |
michael@0 | 468 | { |
michael@0 | 469 | hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); |
michael@0 | 470 | } |
michael@0 | 471 | |
michael@0 | 472 | void |
michael@0 | 473 | hb_ft_font_set_funcs (hb_font_t *font) |
michael@0 | 474 | { |
michael@0 | 475 | hb_blob_t *blob = hb_face_reference_blob (font->face); |
michael@0 | 476 | unsigned int blob_length; |
michael@0 | 477 | const char *blob_data = hb_blob_get_data (blob, &blob_length); |
michael@0 | 478 | if (unlikely (!blob_length)) |
michael@0 | 479 | DEBUG_MSG (FT, font, "Font face has empty blob"); |
michael@0 | 480 | |
michael@0 | 481 | FT_Face ft_face = NULL; |
michael@0 | 482 | FT_Error err = FT_New_Memory_Face (get_ft_library (), |
michael@0 | 483 | (const FT_Byte *) blob_data, |
michael@0 | 484 | blob_length, |
michael@0 | 485 | hb_face_get_index (font->face), |
michael@0 | 486 | &ft_face); |
michael@0 | 487 | |
michael@0 | 488 | if (unlikely (err)) { |
michael@0 | 489 | hb_blob_destroy (blob); |
michael@0 | 490 | DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed"); |
michael@0 | 491 | return; |
michael@0 | 492 | } |
michael@0 | 493 | |
michael@0 | 494 | FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); |
michael@0 | 495 | |
michael@0 | 496 | assert (font->y_scale >= 0); |
michael@0 | 497 | FT_Set_Char_Size (ft_face, |
michael@0 | 498 | font->x_scale, font->y_scale, |
michael@0 | 499 | 0, 0); |
michael@0 | 500 | #if 0 |
michael@0 | 501 | font->x_ppem * 72 * 64 / font->x_scale, |
michael@0 | 502 | font->y_ppem * 72 * 64 / font->y_scale); |
michael@0 | 503 | #endif |
michael@0 | 504 | |
michael@0 | 505 | ft_face->generic.data = blob; |
michael@0 | 506 | ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; |
michael@0 | 507 | |
michael@0 | 508 | hb_font_set_funcs (font, |
michael@0 | 509 | _hb_ft_get_font_funcs (), |
michael@0 | 510 | ft_face, |
michael@0 | 511 | (hb_destroy_func_t) FT_Done_Face); |
michael@0 | 512 | } |
michael@0 | 513 | |
michael@0 | 514 | FT_Face |
michael@0 | 515 | hb_ft_font_get_face (hb_font_t *font) |
michael@0 | 516 | { |
michael@0 | 517 | if (font->destroy == (hb_destroy_func_t) FT_Done_Face || |
michael@0 | 518 | font->destroy == (hb_destroy_func_t) _do_nothing) |
michael@0 | 519 | return (FT_Face) font->user_data; |
michael@0 | 520 | |
michael@0 | 521 | return NULL; |
michael@0 | 522 | } |