1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 /* 31 * Copyright © 2011,2014 Google, Inc. 32 * 33 * This is part of HarfBuzz, a text shaping library. 34 * 35 * Permission is hereby granted, without written agreement and without 36 * license or royalty fees, to use, copy, modify, and distribute this 37 * software and its documentation for any purpose, provided that the 38 * above copyright notice and the following two paragraphs appear in 39 * all copies of this software. 40 * 41 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 42 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 43 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 44 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 45 * DAMAGE. 46 * 47 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 48 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 49 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 50 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 51 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 52 * 53 * Google Author(s): Behdad Esfahbod, Roozbeh Pournader 54 */ 55 56 #include "hb-private.hh" 57 58 #include "hb-ot.h" 59 60 #include "hb-font-private.hh" 61 62 #include "hb-ot-cmap-table.hh" 63 #include "hb-ot-glyf-table.hh" 64 #include "hb-ot-head-table.hh" 65 #include "hb-ot-hhea-table.hh" 66 #include "hb-ot-hmtx-table.hh" 67 68 69 struct hb_ot_face_metrics_accelerator_t 70 { 71 unsigned int num_metrics; 72 unsigned int num_advances; 73 unsigned int default_advance; 74 const OT::_mtx *table; 75 hb_blob_t *blob; 76 77 inline void init (hb_face_t *face, 78 hb_tag_t _hea_tag, hb_tag_t _mtx_tag, 79 unsigned int default_advance_) 80 { 81 this->default_advance = default_advance_; 82 this->num_metrics = face->get_num_glyphs (); 83 84 hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag)); 85 const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob); 86 this->num_advances = _hea->numberOfLongMetrics; 87 hb_blob_destroy (_hea_blob); 88 89 this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag)); 90 if (unlikely (!this->num_advances || 91 2 * (this->num_advances + this->num_metrics) > hb_blob_get_length (this->blob))) 92 { 93 this->num_metrics = this->num_advances = 0; 94 hb_blob_destroy (this->blob); 95 this->blob = hb_blob_get_empty (); 96 } 97 this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob); 98 } 99 100 inline void fini (void) 101 { 102 hb_blob_destroy (this->blob); 103 } 104 105 inline unsigned int get_advance (hb_codepoint_t glyph) const 106 { 107 if (unlikely (glyph >= this->num_metrics)) 108 { 109 /* If this->num_metrics is zero, it means we don't have the metrics table 110 * for this direction: return default advance. Otherwise, it means that the 111 * glyph index is out of bound: return zero. */ 112 if (this->num_metrics) 113 return 0; 114 else 115 return this->default_advance; 116 } 117 118 if (glyph >= this->num_advances) 119 glyph = this->num_advances - 1; 120 121 return this->table->longMetric[glyph].advance; 122 } 123 }; 124 125 struct hb_ot_face_glyf_accelerator_t 126 { 127 bool short_offset; 128 unsigned int num_glyphs; 129 const OT::loca *loca; 130 const OT::glyf *glyf; 131 hb_blob_t *loca_blob; 132 hb_blob_t *glyf_blob; 133 unsigned int glyf_len; 134 135 inline void init (hb_face_t *face) 136 { 137 hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head)); 138 const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob); 139 if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0) 140 { 141 /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ 142 hb_blob_destroy (head_blob); 143 return; 144 } 145 this->short_offset = 0 == head->indexToLocFormat; 146 hb_blob_destroy (head_blob); 147 148 this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca)); 149 this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob); 150 this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf)); 151 this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob); 152 153 this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1; 154 this->glyf_len = hb_blob_get_length (this->glyf_blob); 155 } 156 157 inline void fini (void) 158 { 159 hb_blob_destroy (this->loca_blob); 160 hb_blob_destroy (this->glyf_blob); 161 } 162 163 inline bool get_extents (hb_codepoint_t glyph, 164 hb_glyph_extents_t *extents) const 165 { 166 if (unlikely (glyph >= this->num_glyphs)) 167 return false; 168 169 unsigned int start_offset, end_offset; 170 if (this->short_offset) 171 { 172 start_offset = 2 * this->loca->u.shortsZ[glyph]; 173 end_offset = 2 * this->loca->u.shortsZ[glyph + 1]; 174 } 175 else 176 { 177 start_offset = this->loca->u.longsZ[glyph]; 178 end_offset = this->loca->u.longsZ[glyph + 1]; 179 } 180 181 if (start_offset > end_offset || end_offset > this->glyf_len) 182 return false; 183 184 if (end_offset - start_offset < OT::glyfGlyphHeader::static_size) 185 return true; /* Empty glyph; zero extents. */ 186 187 const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset); 188 189 extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); 190 extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); 191 extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; 192 extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; 193 194 return true; 195 } 196 }; 197 198 struct hb_ot_face_cmap_accelerator_t 199 { 200 const OT::CmapSubtable *table; 201 const OT::CmapSubtable *uvs_table; 202 hb_blob_t *blob; 203 204 inline void init (hb_face_t *face) 205 { 206 this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap)); 207 const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob); 208 const OT::CmapSubtable *subtable = NULL; 209 const OT::CmapSubtable *subtable_uvs = NULL; 210 211 /* 32-bit subtables. */ 212 if (!subtable) subtable = cmap->find_subtable (3, 10); 213 if (!subtable) subtable = cmap->find_subtable (0, 6); 214 if (!subtable) subtable = cmap->find_subtable (0, 4); 215 /* 16-bit subtables. */ 216 if (!subtable) subtable = cmap->find_subtable (3, 1); 217 if (!subtable) subtable = cmap->find_subtable (0, 3); 218 if (!subtable) subtable = cmap->find_subtable (0, 2); 219 if (!subtable) subtable = cmap->find_subtable (0, 1); 220 if (!subtable) subtable = cmap->find_subtable (0, 0); 221 if (!subtable) subtable = cmap->find_subtable (3, 0); 222 /* Meh. */ 223 if (!subtable) subtable = &OT::Null(OT::CmapSubtable); 224 225 /* UVS subtable. */ 226 if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5); 227 /* Meh. */ 228 if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable); 229 230 this->table = subtable; 231 this->uvs_table = subtable_uvs; 232 } 233 234 inline void fini (void) 235 { 236 hb_blob_destroy (this->blob); 237 } 238 239 inline bool get_glyph (hb_codepoint_t unicode, 240 hb_codepoint_t variation_selector, 241 hb_codepoint_t *glyph) const 242 { 243 if (unlikely (variation_selector)) 244 { 245 switch (this->uvs_table->get_glyph_variant (unicode, 246 variation_selector, 247 glyph)) 248 { 249 case OT::GLYPH_VARIANT_NOT_FOUND: return false; 250 case OT::GLYPH_VARIANT_FOUND: return true; 251 case OT::GLYPH_VARIANT_USE_DEFAULT: break; 252 } 253 } 254 255 return this->table->get_glyph (unicode, glyph); 256 } 257 }; 258 259 260 struct hb_ot_font_t 261 { 262 hb_ot_face_cmap_accelerator_t cmap; 263 hb_ot_face_metrics_accelerator_t h_metrics; 264 hb_ot_face_metrics_accelerator_t v_metrics; 265 hb_ot_face_glyf_accelerator_t glyf; 266 }; 267 268 269 static hb_ot_font_t * 270 _hb_ot_font_create (hb_face_t *face) 271 { 272 hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); 273 274 if (unlikely (!ot_font)) 275 return NULL; 276 277 unsigned int upem = face->get_upem (); 278 279 ot_font->cmap.init (face); 280 ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1); 281 ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */ 282 ot_font->glyf.init (face); 283 284 return ot_font; 285 } 286 287 static void 288 _hb_ot_font_destroy (hb_ot_font_t *ot_font) 289 { 290 ot_font->cmap.fini (); 291 ot_font->h_metrics.fini (); 292 ot_font->v_metrics.fini (); 293 ot_font->glyf.fini (); 294 295 free (ot_font); 296 } 297 298 299 static hb_bool_t 300 hb_ot_get_glyph (hb_font_t *font HB_UNUSED, 301 void *font_data, 302 hb_codepoint_t unicode, 303 hb_codepoint_t variation_selector, 304 hb_codepoint_t *glyph, 305 void *user_data HB_UNUSED) 306 307 { 308 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 309 return ot_font->cmap.get_glyph (unicode, variation_selector, glyph); 310 } 311 312 static hb_position_t 313 hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED, 314 void *font_data, 315 hb_codepoint_t glyph, 316 void *user_data HB_UNUSED) 317 { 318 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 319 return font->em_scale_x (ot_font->h_metrics.get_advance (glyph)); 320 } 321 322 static hb_position_t 323 hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED, 324 void *font_data, 325 hb_codepoint_t glyph, 326 void *user_data HB_UNUSED) 327 { 328 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 329 return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph)); 330 } 331 332 static hb_bool_t 333 hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED, 334 void *font_data HB_UNUSED, 335 hb_codepoint_t glyph HB_UNUSED, 336 hb_position_t *x HB_UNUSED, 337 hb_position_t *y HB_UNUSED, 338 void *user_data HB_UNUSED) 339 { 340 /* We always work in the horizontal coordinates. */ 341 return true; 342 } 343 344 static hb_bool_t 345 hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED, 346 void *font_data, 347 hb_codepoint_t glyph, 348 hb_position_t *x, 349 hb_position_t *y, 350 void *user_data HB_UNUSED) 351 { 352 /* TODO */ 353 return false; 354 } 355 356 static hb_position_t 357 hb_ot_get_glyph_h_kerning (hb_font_t *font, 358 void *font_data, 359 hb_codepoint_t left_glyph, 360 hb_codepoint_t right_glyph, 361 void *user_data HB_UNUSED) 362 { 363 /* TODO */ 364 return 0; 365 } 366 367 static hb_position_t 368 hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, 369 void *font_data HB_UNUSED, 370 hb_codepoint_t top_glyph HB_UNUSED, 371 hb_codepoint_t bottom_glyph HB_UNUSED, 372 void *user_data HB_UNUSED) 373 { 374 /* OpenType doesn't have vertical-kerning other than GPOS. */ 375 return 0; 376 } 377 378 static hb_bool_t 379 hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED, 380 void *font_data, 381 hb_codepoint_t glyph, 382 hb_glyph_extents_t *extents, 383 void *user_data HB_UNUSED) 384 { 385 const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; 386 bool ret = ot_font->glyf.get_extents (glyph, extents); 387 extents->x_bearing = font->em_scale_x (extents->x_bearing); 388 extents->y_bearing = font->em_scale_y (extents->y_bearing); 389 extents->width = font->em_scale_x (extents->width); 390 extents->height = font->em_scale_y (extents->height); 391 return ret; 392 } 393 394 static hb_bool_t 395 hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED, 396 void *font_data, 397 hb_codepoint_t glyph, 398 unsigned int point_index, 399 hb_position_t *x, 400 hb_position_t *y, 401 void *user_data HB_UNUSED) 402 { 403 /* TODO */ 404 return false; 405 } 406 407 static hb_bool_t 408 hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, 409 void *font_data, 410 hb_codepoint_t glyph, 411 char *name, unsigned int size, 412 void *user_data HB_UNUSED) 413 { 414 /* TODO */ 415 return false; 416 } 417 418 static hb_bool_t 419 hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, 420 void *font_data, 421 const char *name, int len, /* -1 means nul-terminated */ 422 hb_codepoint_t *glyph, 423 void *user_data HB_UNUSED) 424 { 425 /* TODO */ 426 return false; 427 } 428 429 430 static hb_font_funcs_t * 431 _hb_ot_get_font_funcs (void) 432 { 433 static const hb_font_funcs_t ot_ffuncs = { 434 HB_OBJECT_HEADER_STATIC, 435 436 true, /* immutable */ 437 438 { 439 #define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name, 440 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS 441 #undef HB_FONT_FUNC_IMPLEMENT 442 } 443 }; 444 445 return const_cast<hb_font_funcs_t *> (&ot_ffuncs); 446 } 447 448 449 /** 450 * Since: 0.9.28 451 **/ 452 void 453 hb_ot_font_set_funcs (hb_font_t *font) 454 { 455 hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); 456 if (unlikely (!ot_font)) 457 return; 458 459 hb_font_set_funcs (font, 460 _hb_ot_get_font_funcs (), 461 ot_font, 462 (hb_destroy_func_t) _hb_ot_font_destroy); 463 }