1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright © 2015 Google, Inc. 3cb93a386Sopenharmony_ci * Copyright © 2019 Adobe Inc. 4cb93a386Sopenharmony_ci * Copyright © 2019 Ebrahim Byagowi 5cb93a386Sopenharmony_ci * 6cb93a386Sopenharmony_ci * This is part of HarfBuzz, a text shaping library. 7cb93a386Sopenharmony_ci * 8cb93a386Sopenharmony_ci * Permission is hereby granted, without written agreement and without 9cb93a386Sopenharmony_ci * license or royalty fees, to use, copy, modify, and distribute this 10cb93a386Sopenharmony_ci * software and its documentation for any purpose, provided that the 11cb93a386Sopenharmony_ci * above copyright notice and the following two paragraphs appear in 12cb93a386Sopenharmony_ci * all copies of this software. 13cb93a386Sopenharmony_ci * 14cb93a386Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15cb93a386Sopenharmony_ci * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16cb93a386Sopenharmony_ci * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17cb93a386Sopenharmony_ci * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18cb93a386Sopenharmony_ci * DAMAGE. 19cb93a386Sopenharmony_ci * 20cb93a386Sopenharmony_ci * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21cb93a386Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22cb93a386Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23cb93a386Sopenharmony_ci * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24cb93a386Sopenharmony_ci * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25cb93a386Sopenharmony_ci * 26cb93a386Sopenharmony_ci * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter 27cb93a386Sopenharmony_ci * Adobe Author(s): Michiharu Ariza 28cb93a386Sopenharmony_ci */ 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#ifndef HB_OT_GLYF_TABLE_HH 31cb93a386Sopenharmony_ci#define HB_OT_GLYF_TABLE_HH 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci#include "hb-open-type.hh" 34cb93a386Sopenharmony_ci#include "hb-ot-head-table.hh" 35cb93a386Sopenharmony_ci#include "hb-ot-hmtx-table.hh" 36cb93a386Sopenharmony_ci#include "hb-ot-var-gvar-table.hh" 37cb93a386Sopenharmony_ci#include "hb-draw.hh" 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_cinamespace OT { 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci/* 43cb93a386Sopenharmony_ci * loca -- Index to Location 44cb93a386Sopenharmony_ci * https://docs.microsoft.com/en-us/typography/opentype/spec/loca 45cb93a386Sopenharmony_ci */ 46cb93a386Sopenharmony_ci#define HB_OT_TAG_loca HB_TAG('l','o','c','a') 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci#ifndef HB_MAX_COMPOSITE_OPERATIONS 49cb93a386Sopenharmony_ci#define HB_MAX_COMPOSITE_OPERATIONS 100000 50cb93a386Sopenharmony_ci#endif 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_cistruct loca 54cb93a386Sopenharmony_ci{ 55cb93a386Sopenharmony_ci friend struct glyf; 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ci static constexpr hb_tag_t tableTag = HB_OT_TAG_loca; 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const 60cb93a386Sopenharmony_ci { 61cb93a386Sopenharmony_ci TRACE_SANITIZE (this); 62cb93a386Sopenharmony_ci return_trace (true); 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci protected: 66cb93a386Sopenharmony_ci UnsizedArrayOf<HBUINT8> 67cb93a386Sopenharmony_ci dataZ; /* Location data. */ 68cb93a386Sopenharmony_ci public: 69cb93a386Sopenharmony_ci DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always 70cb93a386Sopenharmony_ci * check the size externally, allow Null() object of it by 71cb93a386Sopenharmony_ci * defining it _MIN instead. */ 72cb93a386Sopenharmony_ci}; 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci/* 76cb93a386Sopenharmony_ci * glyf -- TrueType Glyph Data 77cb93a386Sopenharmony_ci * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf 78cb93a386Sopenharmony_ci */ 79cb93a386Sopenharmony_ci#define HB_OT_TAG_glyf HB_TAG('g','l','y','f') 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_cistruct glyf 83cb93a386Sopenharmony_ci{ 84cb93a386Sopenharmony_ci static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const 87cb93a386Sopenharmony_ci { 88cb93a386Sopenharmony_ci TRACE_SANITIZE (this); 89cb93a386Sopenharmony_ci /* Runtime checks as eager sanitizing each glyph is costy */ 90cb93a386Sopenharmony_ci return_trace (true); 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci template<typename Iterator, 94cb93a386Sopenharmony_ci hb_requires (hb_is_source_of (Iterator, unsigned int))> 95cb93a386Sopenharmony_ci static bool 96cb93a386Sopenharmony_ci _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets) 97cb93a386Sopenharmony_ci { 98cb93a386Sopenharmony_ci unsigned max_offset = 99cb93a386Sopenharmony_ci + padded_offsets 100cb93a386Sopenharmony_ci | hb_reduce (hb_add, 0) 101cb93a386Sopenharmony_ci ; 102cb93a386Sopenharmony_ci unsigned num_offsets = padded_offsets.len () + 1; 103cb93a386Sopenharmony_ci bool use_short_loca = max_offset < 0x1FFFF; 104cb93a386Sopenharmony_ci unsigned entry_size = use_short_loca ? 2 : 4; 105cb93a386Sopenharmony_ci char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets); 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci if (unlikely (!loca_prime_data)) return false; 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d " 110cb93a386Sopenharmony_ci "max_offset %d size %d", 111cb93a386Sopenharmony_ci entry_size, num_offsets, max_offset, entry_size * num_offsets); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci if (use_short_loca) 114cb93a386Sopenharmony_ci _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); 115cb93a386Sopenharmony_ci else 116cb93a386Sopenharmony_ci _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, 119cb93a386Sopenharmony_ci entry_size * num_offsets, 120cb93a386Sopenharmony_ci HB_MEMORY_MODE_WRITABLE, 121cb93a386Sopenharmony_ci loca_prime_data, 122cb93a386Sopenharmony_ci hb_free); 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) 125cb93a386Sopenharmony_ci && _add_head_and_set_loca_version (plan, use_short_loca); 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci hb_blob_destroy (loca_blob); 128cb93a386Sopenharmony_ci return result; 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci template<typename IteratorIn, typename IteratorOut, 132cb93a386Sopenharmony_ci hb_requires (hb_is_source_of (IteratorIn, unsigned int)), 133cb93a386Sopenharmony_ci hb_requires (hb_is_sink_of (IteratorOut, unsigned))> 134cb93a386Sopenharmony_ci static void 135cb93a386Sopenharmony_ci _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest) 136cb93a386Sopenharmony_ci { 137cb93a386Sopenharmony_ci unsigned int offset = 0; 138cb93a386Sopenharmony_ci dest << 0; 139cb93a386Sopenharmony_ci + it 140cb93a386Sopenharmony_ci | hb_map ([=, &offset] (unsigned int padded_size) 141cb93a386Sopenharmony_ci { 142cb93a386Sopenharmony_ci offset += padded_size; 143cb93a386Sopenharmony_ci DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); 144cb93a386Sopenharmony_ci return offset >> right_shift; 145cb93a386Sopenharmony_ci }) 146cb93a386Sopenharmony_ci | hb_sink (dest) 147cb93a386Sopenharmony_ci ; 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci /* requires source of SubsetGlyph complains the identifier isn't declared */ 151cb93a386Sopenharmony_ci template <typename Iterator> 152cb93a386Sopenharmony_ci bool serialize (hb_serialize_context_t *c, 153cb93a386Sopenharmony_ci Iterator it, 154cb93a386Sopenharmony_ci const hb_subset_plan_t *plan) 155cb93a386Sopenharmony_ci { 156cb93a386Sopenharmony_ci TRACE_SERIALIZE (this); 157cb93a386Sopenharmony_ci unsigned init_len = c->length (); 158cb93a386Sopenharmony_ci for (const auto &_ : it) _.serialize (c, plan); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci /* As a special case when all glyph in the font are empty, add a zero byte 161cb93a386Sopenharmony_ci * to the table, so that OTS doesn’t reject it, and to make the table work 162cb93a386Sopenharmony_ci * on Windows as well. 163cb93a386Sopenharmony_ci * See https://github.com/khaledhosny/ots/issues/52 */ 164cb93a386Sopenharmony_ci if (init_len == c->length ()) 165cb93a386Sopenharmony_ci { 166cb93a386Sopenharmony_ci HBUINT8 empty_byte; 167cb93a386Sopenharmony_ci empty_byte = 0; 168cb93a386Sopenharmony_ci c->copy (empty_byte); 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci return_trace (true); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci /* Byte region(s) per glyph to output 174cb93a386Sopenharmony_ci unpadded, hints removed if so requested 175cb93a386Sopenharmony_ci If we fail to process a glyph we produce an empty (0-length) glyph */ 176cb93a386Sopenharmony_ci bool subset (hb_subset_context_t *c) const 177cb93a386Sopenharmony_ci { 178cb93a386Sopenharmony_ci TRACE_SUBSET (this); 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci glyf *glyf_prime = c->serializer->start_embed <glyf> (); 181cb93a386Sopenharmony_ci if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci hb_vector_t<SubsetGlyph> glyphs; 184cb93a386Sopenharmony_ci _populate_subset_glyphs (c->plan, &glyphs); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan); 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci auto padded_offsets = 189cb93a386Sopenharmony_ci + hb_iter (glyphs) 190cb93a386Sopenharmony_ci | hb_map (&SubsetGlyph::padded_size) 191cb93a386Sopenharmony_ci ; 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_ci if (unlikely (c->serializer->in_error ())) return_trace (false); 194cb93a386Sopenharmony_ci return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, 195cb93a386Sopenharmony_ci padded_offsets))); 196cb93a386Sopenharmony_ci } 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci template <typename SubsetGlyph> 199cb93a386Sopenharmony_ci void 200cb93a386Sopenharmony_ci _populate_subset_glyphs (const hb_subset_plan_t *plan, 201cb93a386Sopenharmony_ci hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const 202cb93a386Sopenharmony_ci { 203cb93a386Sopenharmony_ci OT::glyf::accelerator_t glyf; 204cb93a386Sopenharmony_ci glyf.init (plan->source); 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci + hb_range (plan->num_output_glyphs ()) 207cb93a386Sopenharmony_ci | hb_map ([&] (hb_codepoint_t new_gid) 208cb93a386Sopenharmony_ci { 209cb93a386Sopenharmony_ci SubsetGlyph subset_glyph = {0}; 210cb93a386Sopenharmony_ci subset_glyph.new_gid = new_gid; 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci /* should never fail: all old gids should be mapped */ 213cb93a386Sopenharmony_ci if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) 214cb93a386Sopenharmony_ci return subset_glyph; 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci if (new_gid == 0 && 217cb93a386Sopenharmony_ci !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) 218cb93a386Sopenharmony_ci subset_glyph.source_glyph = Glyph (); 219cb93a386Sopenharmony_ci else 220cb93a386Sopenharmony_ci subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); 221cb93a386Sopenharmony_ci if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) 222cb93a386Sopenharmony_ci subset_glyph.drop_hints_bytes (); 223cb93a386Sopenharmony_ci else 224cb93a386Sopenharmony_ci subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); 225cb93a386Sopenharmony_ci return subset_glyph; 226cb93a386Sopenharmony_ci }) 227cb93a386Sopenharmony_ci | hb_sink (glyphs) 228cb93a386Sopenharmony_ci ; 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci glyf.fini (); 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ci static bool 234cb93a386Sopenharmony_ci _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) 235cb93a386Sopenharmony_ci { 236cb93a386Sopenharmony_ci hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source); 237cb93a386Sopenharmony_ci hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); 238cb93a386Sopenharmony_ci hb_blob_destroy (head_blob); 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci if (unlikely (!head_prime_blob)) 241cb93a386Sopenharmony_ci return false; 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); 244cb93a386Sopenharmony_ci head_prime->indexToLocFormat = use_short_loca ? 0 : 1; 245cb93a386Sopenharmony_ci bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ci hb_blob_destroy (head_prime_blob); 248cb93a386Sopenharmony_ci return success; 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci struct CompositeGlyphChain 252cb93a386Sopenharmony_ci { 253cb93a386Sopenharmony_ci protected: 254cb93a386Sopenharmony_ci enum composite_glyph_flag_t 255cb93a386Sopenharmony_ci { 256cb93a386Sopenharmony_ci ARG_1_AND_2_ARE_WORDS = 0x0001, 257cb93a386Sopenharmony_ci ARGS_ARE_XY_VALUES = 0x0002, 258cb93a386Sopenharmony_ci ROUND_XY_TO_GRID = 0x0004, 259cb93a386Sopenharmony_ci WE_HAVE_A_SCALE = 0x0008, 260cb93a386Sopenharmony_ci MORE_COMPONENTS = 0x0020, 261cb93a386Sopenharmony_ci WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, 262cb93a386Sopenharmony_ci WE_HAVE_A_TWO_BY_TWO = 0x0080, 263cb93a386Sopenharmony_ci WE_HAVE_INSTRUCTIONS = 0x0100, 264cb93a386Sopenharmony_ci USE_MY_METRICS = 0x0200, 265cb93a386Sopenharmony_ci OVERLAP_COMPOUND = 0x0400, 266cb93a386Sopenharmony_ci SCALED_COMPONENT_OFFSET = 0x0800, 267cb93a386Sopenharmony_ci UNSCALED_COMPONENT_OFFSET = 0x1000 268cb93a386Sopenharmony_ci }; 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci public: 271cb93a386Sopenharmony_ci unsigned int get_size () const 272cb93a386Sopenharmony_ci { 273cb93a386Sopenharmony_ci unsigned int size = min_size; 274cb93a386Sopenharmony_ci /* arg1 and 2 are int16 */ 275cb93a386Sopenharmony_ci if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; 276cb93a386Sopenharmony_ci /* arg1 and 2 are int8 */ 277cb93a386Sopenharmony_ci else size += 2; 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci /* One x 16 bit (scale) */ 280cb93a386Sopenharmony_ci if (flags & WE_HAVE_A_SCALE) size += 2; 281cb93a386Sopenharmony_ci /* Two x 16 bit (xscale, yscale) */ 282cb93a386Sopenharmony_ci else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; 283cb93a386Sopenharmony_ci /* Four x 16 bit (xscale, scale01, scale10, yscale) */ 284cb93a386Sopenharmony_ci else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci return size; 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; } 290cb93a386Sopenharmony_ci hb_codepoint_t get_glyph_index () const { return glyphIndex; } 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; } 293cb93a386Sopenharmony_ci void set_overlaps_flag () 294cb93a386Sopenharmony_ci { 295cb93a386Sopenharmony_ci flags = (uint16_t) flags | OVERLAP_COMPOUND; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; } 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci bool has_more () const { return flags & MORE_COMPONENTS; } 301cb93a386Sopenharmony_ci bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } 302cb93a386Sopenharmony_ci bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } 303cb93a386Sopenharmony_ci void get_anchor_points (unsigned int &point1, unsigned int &point2) const 304cb93a386Sopenharmony_ci { 305cb93a386Sopenharmony_ci const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex); 306cb93a386Sopenharmony_ci if (flags & ARG_1_AND_2_ARE_WORDS) 307cb93a386Sopenharmony_ci { 308cb93a386Sopenharmony_ci point1 = ((const HBUINT16 *) p)[0]; 309cb93a386Sopenharmony_ci point2 = ((const HBUINT16 *) p)[1]; 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci else 312cb93a386Sopenharmony_ci { 313cb93a386Sopenharmony_ci point1 = p[0]; 314cb93a386Sopenharmony_ci point2 = p[1]; 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci void transform_points (contour_point_vector_t &points) const 319cb93a386Sopenharmony_ci { 320cb93a386Sopenharmony_ci float matrix[4]; 321cb93a386Sopenharmony_ci contour_point_t trans; 322cb93a386Sopenharmony_ci if (get_transformation (matrix, trans)) 323cb93a386Sopenharmony_ci { 324cb93a386Sopenharmony_ci if (scaled_offsets ()) 325cb93a386Sopenharmony_ci { 326cb93a386Sopenharmony_ci points.translate (trans); 327cb93a386Sopenharmony_ci points.transform (matrix); 328cb93a386Sopenharmony_ci } 329cb93a386Sopenharmony_ci else 330cb93a386Sopenharmony_ci { 331cb93a386Sopenharmony_ci points.transform (matrix); 332cb93a386Sopenharmony_ci points.translate (trans); 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci protected: 338cb93a386Sopenharmony_ci bool scaled_offsets () const 339cb93a386Sopenharmony_ci { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci bool get_transformation (float (&matrix)[4], contour_point_t &trans) const 342cb93a386Sopenharmony_ci { 343cb93a386Sopenharmony_ci matrix[0] = matrix[3] = 1.f; 344cb93a386Sopenharmony_ci matrix[1] = matrix[2] = 0.f; 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci int tx, ty; 347cb93a386Sopenharmony_ci const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex); 348cb93a386Sopenharmony_ci if (flags & ARG_1_AND_2_ARE_WORDS) 349cb93a386Sopenharmony_ci { 350cb93a386Sopenharmony_ci tx = *(const HBINT16 *) p; 351cb93a386Sopenharmony_ci p += HBINT16::static_size; 352cb93a386Sopenharmony_ci ty = *(const HBINT16 *) p; 353cb93a386Sopenharmony_ci p += HBINT16::static_size; 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci else 356cb93a386Sopenharmony_ci { 357cb93a386Sopenharmony_ci tx = *p++; 358cb93a386Sopenharmony_ci ty = *p++; 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci if (is_anchored ()) tx = ty = 0; 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci trans.init ((float) tx, (float) ty); 363cb93a386Sopenharmony_ci 364cb93a386Sopenharmony_ci { 365cb93a386Sopenharmony_ci const F2DOT14 *points = (const F2DOT14 *) p; 366cb93a386Sopenharmony_ci if (flags & WE_HAVE_A_SCALE) 367cb93a386Sopenharmony_ci { 368cb93a386Sopenharmony_ci matrix[0] = matrix[3] = points[0].to_float (); 369cb93a386Sopenharmony_ci return true; 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) 372cb93a386Sopenharmony_ci { 373cb93a386Sopenharmony_ci matrix[0] = points[0].to_float (); 374cb93a386Sopenharmony_ci matrix[3] = points[1].to_float (); 375cb93a386Sopenharmony_ci return true; 376cb93a386Sopenharmony_ci } 377cb93a386Sopenharmony_ci else if (flags & WE_HAVE_A_TWO_BY_TWO) 378cb93a386Sopenharmony_ci { 379cb93a386Sopenharmony_ci matrix[0] = points[0].to_float (); 380cb93a386Sopenharmony_ci matrix[1] = points[1].to_float (); 381cb93a386Sopenharmony_ci matrix[2] = points[2].to_float (); 382cb93a386Sopenharmony_ci matrix[3] = points[3].to_float (); 383cb93a386Sopenharmony_ci return true; 384cb93a386Sopenharmony_ci } 385cb93a386Sopenharmony_ci } 386cb93a386Sopenharmony_ci return tx || ty; 387cb93a386Sopenharmony_ci } 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_ci protected: 390cb93a386Sopenharmony_ci HBUINT16 flags; 391cb93a386Sopenharmony_ci HBGlyphID16 glyphIndex; 392cb93a386Sopenharmony_ci public: 393cb93a386Sopenharmony_ci DEFINE_SIZE_MIN (4); 394cb93a386Sopenharmony_ci }; 395cb93a386Sopenharmony_ci 396cb93a386Sopenharmony_ci struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &> 397cb93a386Sopenharmony_ci { 398cb93a386Sopenharmony_ci typedef const CompositeGlyphChain *__item_t__; 399cb93a386Sopenharmony_ci composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : 400cb93a386Sopenharmony_ci glyph (glyph_), current (nullptr), current_size (0) 401cb93a386Sopenharmony_ci { 402cb93a386Sopenharmony_ci set_next (current_); 403cb93a386Sopenharmony_ci } 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ci composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci const CompositeGlyphChain &__item__ () const { return *current; } 408cb93a386Sopenharmony_ci bool __more__ () const { return current; } 409cb93a386Sopenharmony_ci void __next__ () 410cb93a386Sopenharmony_ci { 411cb93a386Sopenharmony_ci if (!current->has_more ()) { current = nullptr; return; } 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size)); 414cb93a386Sopenharmony_ci } 415cb93a386Sopenharmony_ci bool operator != (const composite_iter_t& o) const 416cb93a386Sopenharmony_ci { return glyph != o.glyph || current != o.current; } 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_ci void set_next (const CompositeGlyphChain *composite) 420cb93a386Sopenharmony_ci { 421cb93a386Sopenharmony_ci if (!glyph.check_range (composite, CompositeGlyphChain::min_size)) 422cb93a386Sopenharmony_ci { 423cb93a386Sopenharmony_ci current = nullptr; 424cb93a386Sopenharmony_ci current_size = 0; 425cb93a386Sopenharmony_ci return; 426cb93a386Sopenharmony_ci } 427cb93a386Sopenharmony_ci unsigned size = composite->get_size (); 428cb93a386Sopenharmony_ci if (!glyph.check_range (composite, size)) 429cb93a386Sopenharmony_ci { 430cb93a386Sopenharmony_ci current = nullptr; 431cb93a386Sopenharmony_ci current_size = 0; 432cb93a386Sopenharmony_ci return; 433cb93a386Sopenharmony_ci } 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ci current = composite; 436cb93a386Sopenharmony_ci current_size = size; 437cb93a386Sopenharmony_ci } 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci private: 440cb93a386Sopenharmony_ci hb_bytes_t glyph; 441cb93a386Sopenharmony_ci __item_t__ current; 442cb93a386Sopenharmony_ci unsigned current_size; 443cb93a386Sopenharmony_ci }; 444cb93a386Sopenharmony_ci 445cb93a386Sopenharmony_ci enum phantom_point_index_t 446cb93a386Sopenharmony_ci { 447cb93a386Sopenharmony_ci PHANTOM_LEFT = 0, 448cb93a386Sopenharmony_ci PHANTOM_RIGHT = 1, 449cb93a386Sopenharmony_ci PHANTOM_TOP = 2, 450cb93a386Sopenharmony_ci PHANTOM_BOTTOM = 3, 451cb93a386Sopenharmony_ci PHANTOM_COUNT = 4 452cb93a386Sopenharmony_ci }; 453cb93a386Sopenharmony_ci 454cb93a386Sopenharmony_ci struct accelerator_t; 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci struct Glyph 457cb93a386Sopenharmony_ci { 458cb93a386Sopenharmony_ci enum simple_glyph_flag_t 459cb93a386Sopenharmony_ci { 460cb93a386Sopenharmony_ci FLAG_ON_CURVE = 0x01, 461cb93a386Sopenharmony_ci FLAG_X_SHORT = 0x02, 462cb93a386Sopenharmony_ci FLAG_Y_SHORT = 0x04, 463cb93a386Sopenharmony_ci FLAG_REPEAT = 0x08, 464cb93a386Sopenharmony_ci FLAG_X_SAME = 0x10, 465cb93a386Sopenharmony_ci FLAG_Y_SAME = 0x20, 466cb93a386Sopenharmony_ci FLAG_OVERLAP_SIMPLE = 0x40, 467cb93a386Sopenharmony_ci FLAG_RESERVED2 = 0x80 468cb93a386Sopenharmony_ci }; 469cb93a386Sopenharmony_ci 470cb93a386Sopenharmony_ci private: 471cb93a386Sopenharmony_ci struct GlyphHeader 472cb93a386Sopenharmony_ci { 473cb93a386Sopenharmony_ci bool has_data () const { return numberOfContours; } 474cb93a386Sopenharmony_ci 475cb93a386Sopenharmony_ci bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, 476cb93a386Sopenharmony_ci hb_codepoint_t gid, hb_glyph_extents_t *extents) const 477cb93a386Sopenharmony_ci { 478cb93a386Sopenharmony_ci /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ 479cb93a386Sopenharmony_ci /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ 480cb93a386Sopenharmony_ci extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid)); 481cb93a386Sopenharmony_ci extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); 482cb93a386Sopenharmony_ci extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); 483cb93a386Sopenharmony_ci extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); 484cb93a386Sopenharmony_ci 485cb93a386Sopenharmony_ci return true; 486cb93a386Sopenharmony_ci } 487cb93a386Sopenharmony_ci 488cb93a386Sopenharmony_ci HBINT16 numberOfContours; 489cb93a386Sopenharmony_ci /* If the number of contours is 490cb93a386Sopenharmony_ci * greater than or equal to zero, 491cb93a386Sopenharmony_ci * this is a simple glyph; if negative, 492cb93a386Sopenharmony_ci * this is a composite glyph. */ 493cb93a386Sopenharmony_ci FWORD xMin; /* Minimum x for coordinate data. */ 494cb93a386Sopenharmony_ci FWORD yMin; /* Minimum y for coordinate data. */ 495cb93a386Sopenharmony_ci FWORD xMax; /* Maximum x for coordinate data. */ 496cb93a386Sopenharmony_ci FWORD yMax; /* Maximum y for coordinate data. */ 497cb93a386Sopenharmony_ci public: 498cb93a386Sopenharmony_ci DEFINE_SIZE_STATIC (10); 499cb93a386Sopenharmony_ci }; 500cb93a386Sopenharmony_ci 501cb93a386Sopenharmony_ci struct SimpleGlyph 502cb93a386Sopenharmony_ci { 503cb93a386Sopenharmony_ci const GlyphHeader &header; 504cb93a386Sopenharmony_ci hb_bytes_t bytes; 505cb93a386Sopenharmony_ci SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : 506cb93a386Sopenharmony_ci header (header_), bytes (bytes_) {} 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci unsigned int instruction_len_offset () const 509cb93a386Sopenharmony_ci { return GlyphHeader::static_size + 2 * header.numberOfContours; } 510cb93a386Sopenharmony_ci 511cb93a386Sopenharmony_ci unsigned int length (unsigned int instruction_len) const 512cb93a386Sopenharmony_ci { return instruction_len_offset () + 2 + instruction_len; } 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci unsigned int instructions_length () const 515cb93a386Sopenharmony_ci { 516cb93a386Sopenharmony_ci unsigned int instruction_length_offset = instruction_len_offset (); 517cb93a386Sopenharmony_ci if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_ci const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset); 520cb93a386Sopenharmony_ci /* Out of bounds of the current glyph */ 521cb93a386Sopenharmony_ci if (unlikely (length (instructionLength) > bytes.length)) return 0; 522cb93a386Sopenharmony_ci return instructionLength; 523cb93a386Sopenharmony_ci } 524cb93a386Sopenharmony_ci 525cb93a386Sopenharmony_ci const Glyph trim_padding () const 526cb93a386Sopenharmony_ci { 527cb93a386Sopenharmony_ci /* based on FontTools _g_l_y_f.py::trim */ 528cb93a386Sopenharmony_ci const uint8_t *glyph = (uint8_t*) bytes.arrayZ; 529cb93a386Sopenharmony_ci const uint8_t *glyph_end = glyph + bytes.length; 530cb93a386Sopenharmony_ci /* simple glyph w/contours, possibly trimmable */ 531cb93a386Sopenharmony_ci glyph += instruction_len_offset (); 532cb93a386Sopenharmony_ci 533cb93a386Sopenharmony_ci if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); 534cb93a386Sopenharmony_ci unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1; 535cb93a386Sopenharmony_ci unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0); 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_ci glyph += 2 + num_instructions; 538cb93a386Sopenharmony_ci 539cb93a386Sopenharmony_ci unsigned int coord_bytes = 0; 540cb93a386Sopenharmony_ci unsigned int coords_with_flags = 0; 541cb93a386Sopenharmony_ci while (glyph < glyph_end) 542cb93a386Sopenharmony_ci { 543cb93a386Sopenharmony_ci uint8_t flag = *glyph; 544cb93a386Sopenharmony_ci glyph++; 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ci unsigned int repeat = 1; 547cb93a386Sopenharmony_ci if (flag & FLAG_REPEAT) 548cb93a386Sopenharmony_ci { 549cb93a386Sopenharmony_ci if (unlikely (glyph >= glyph_end)) return Glyph (); 550cb93a386Sopenharmony_ci repeat = *glyph + 1; 551cb93a386Sopenharmony_ci glyph++; 552cb93a386Sopenharmony_ci } 553cb93a386Sopenharmony_ci 554cb93a386Sopenharmony_ci unsigned int xBytes, yBytes; 555cb93a386Sopenharmony_ci xBytes = yBytes = 0; 556cb93a386Sopenharmony_ci if (flag & FLAG_X_SHORT) xBytes = 1; 557cb93a386Sopenharmony_ci else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; 558cb93a386Sopenharmony_ci 559cb93a386Sopenharmony_ci if (flag & FLAG_Y_SHORT) yBytes = 1; 560cb93a386Sopenharmony_ci else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; 561cb93a386Sopenharmony_ci 562cb93a386Sopenharmony_ci coord_bytes += (xBytes + yBytes) * repeat; 563cb93a386Sopenharmony_ci coords_with_flags += repeat; 564cb93a386Sopenharmony_ci if (coords_with_flags >= num_coordinates) break; 565cb93a386Sopenharmony_ci } 566cb93a386Sopenharmony_ci 567cb93a386Sopenharmony_ci if (unlikely (coords_with_flags != num_coordinates)) return Glyph (); 568cb93a386Sopenharmony_ci return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph))); 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci 571cb93a386Sopenharmony_ci /* zero instruction length */ 572cb93a386Sopenharmony_ci void drop_hints () 573cb93a386Sopenharmony_ci { 574cb93a386Sopenharmony_ci GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header); 575cb93a386Sopenharmony_ci (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0; 576cb93a386Sopenharmony_ci } 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_ci void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const 579cb93a386Sopenharmony_ci { 580cb93a386Sopenharmony_ci unsigned int instructions_len = instructions_length (); 581cb93a386Sopenharmony_ci unsigned int glyph_length = length (instructions_len); 582cb93a386Sopenharmony_ci dest_start = bytes.sub_array (0, glyph_length - instructions_len); 583cb93a386Sopenharmony_ci dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); 584cb93a386Sopenharmony_ci } 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci void set_overlaps_flag () 587cb93a386Sopenharmony_ci { 588cb93a386Sopenharmony_ci if (unlikely (!header.numberOfContours)) return; 589cb93a386Sopenharmony_ci 590cb93a386Sopenharmony_ci unsigned flags_offset = length (instructions_length ()); 591cb93a386Sopenharmony_ci if (unlikely (length (flags_offset + 1) > bytes.length)) return; 592cb93a386Sopenharmony_ci 593cb93a386Sopenharmony_ci HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset); 594cb93a386Sopenharmony_ci first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE; 595cb93a386Sopenharmony_ci } 596cb93a386Sopenharmony_ci 597cb93a386Sopenharmony_ci static bool read_points (const HBUINT8 *&p /* IN/OUT */, 598cb93a386Sopenharmony_ci contour_point_vector_t &points_ /* IN/OUT */, 599cb93a386Sopenharmony_ci const hb_bytes_t &bytes, 600cb93a386Sopenharmony_ci void (* setter) (contour_point_t &_, float v), 601cb93a386Sopenharmony_ci const simple_glyph_flag_t short_flag, 602cb93a386Sopenharmony_ci const simple_glyph_flag_t same_flag) 603cb93a386Sopenharmony_ci { 604cb93a386Sopenharmony_ci float v = 0; 605cb93a386Sopenharmony_ci for (unsigned i = 0; i < points_.length; i++) 606cb93a386Sopenharmony_ci { 607cb93a386Sopenharmony_ci uint8_t flag = points_[i].flag; 608cb93a386Sopenharmony_ci if (flag & short_flag) 609cb93a386Sopenharmony_ci { 610cb93a386Sopenharmony_ci if (unlikely (!bytes.check_range (p))) return false; 611cb93a386Sopenharmony_ci if (flag & same_flag) 612cb93a386Sopenharmony_ci v += *p++; 613cb93a386Sopenharmony_ci else 614cb93a386Sopenharmony_ci v -= *p++; 615cb93a386Sopenharmony_ci } 616cb93a386Sopenharmony_ci else 617cb93a386Sopenharmony_ci { 618cb93a386Sopenharmony_ci if (!(flag & same_flag)) 619cb93a386Sopenharmony_ci { 620cb93a386Sopenharmony_ci if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false; 621cb93a386Sopenharmony_ci v += *(const HBINT16 *) p; 622cb93a386Sopenharmony_ci p += HBINT16::static_size; 623cb93a386Sopenharmony_ci } 624cb93a386Sopenharmony_ci } 625cb93a386Sopenharmony_ci setter (points_[i], v); 626cb93a386Sopenharmony_ci } 627cb93a386Sopenharmony_ci return true; 628cb93a386Sopenharmony_ci } 629cb93a386Sopenharmony_ci 630cb93a386Sopenharmony_ci bool get_contour_points (contour_point_vector_t &points_ /* OUT */, 631cb93a386Sopenharmony_ci bool phantom_only = false) const 632cb93a386Sopenharmony_ci { 633cb93a386Sopenharmony_ci const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header); 634cb93a386Sopenharmony_ci int num_contours = header.numberOfContours; 635cb93a386Sopenharmony_ci if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false; 636cb93a386Sopenharmony_ci unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; 637cb93a386Sopenharmony_ci 638cb93a386Sopenharmony_ci points_.resize (num_points); 639cb93a386Sopenharmony_ci for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); 640cb93a386Sopenharmony_ci if (phantom_only) return true; 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci for (int i = 0; i < num_contours; i++) 643cb93a386Sopenharmony_ci points_[endPtsOfContours[i]].is_end_point = true; 644cb93a386Sopenharmony_ci 645cb93a386Sopenharmony_ci /* Skip instructions */ 646cb93a386Sopenharmony_ci const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1], 647cb93a386Sopenharmony_ci endPtsOfContours[num_contours]); 648cb93a386Sopenharmony_ci 649cb93a386Sopenharmony_ci /* Read flags */ 650cb93a386Sopenharmony_ci for (unsigned int i = 0; i < num_points; i++) 651cb93a386Sopenharmony_ci { 652cb93a386Sopenharmony_ci if (unlikely (!bytes.check_range (p))) return false; 653cb93a386Sopenharmony_ci uint8_t flag = *p++; 654cb93a386Sopenharmony_ci points_[i].flag = flag; 655cb93a386Sopenharmony_ci if (flag & FLAG_REPEAT) 656cb93a386Sopenharmony_ci { 657cb93a386Sopenharmony_ci if (unlikely (!bytes.check_range (p))) return false; 658cb93a386Sopenharmony_ci unsigned int repeat_count = *p++; 659cb93a386Sopenharmony_ci while ((repeat_count-- > 0) && (++i < num_points)) 660cb93a386Sopenharmony_ci points_[i].flag = flag; 661cb93a386Sopenharmony_ci } 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_ci /* Read x & y coordinates */ 665cb93a386Sopenharmony_ci return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; }, 666cb93a386Sopenharmony_ci FLAG_X_SHORT, FLAG_X_SAME) 667cb93a386Sopenharmony_ci && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; }, 668cb93a386Sopenharmony_ci FLAG_Y_SHORT, FLAG_Y_SAME); 669cb93a386Sopenharmony_ci } 670cb93a386Sopenharmony_ci }; 671cb93a386Sopenharmony_ci 672cb93a386Sopenharmony_ci struct CompositeGlyph 673cb93a386Sopenharmony_ci { 674cb93a386Sopenharmony_ci const GlyphHeader &header; 675cb93a386Sopenharmony_ci hb_bytes_t bytes; 676cb93a386Sopenharmony_ci CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : 677cb93a386Sopenharmony_ci header (header_), bytes (bytes_) {} 678cb93a386Sopenharmony_ci 679cb93a386Sopenharmony_ci composite_iter_t get_iterator () const 680cb93a386Sopenharmony_ci { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); } 681cb93a386Sopenharmony_ci 682cb93a386Sopenharmony_ci unsigned int instructions_length (hb_bytes_t bytes) const 683cb93a386Sopenharmony_ci { 684cb93a386Sopenharmony_ci unsigned int start = bytes.length; 685cb93a386Sopenharmony_ci unsigned int end = bytes.length; 686cb93a386Sopenharmony_ci const CompositeGlyphChain *last = nullptr; 687cb93a386Sopenharmony_ci for (auto &item : get_iterator ()) 688cb93a386Sopenharmony_ci last = &item; 689cb93a386Sopenharmony_ci if (unlikely (!last)) return 0; 690cb93a386Sopenharmony_ci 691cb93a386Sopenharmony_ci if (last->has_instructions ()) 692cb93a386Sopenharmony_ci start = (char *) last - &bytes + last->get_size (); 693cb93a386Sopenharmony_ci if (unlikely (start > end)) return 0; 694cb93a386Sopenharmony_ci return end - start; 695cb93a386Sopenharmony_ci } 696cb93a386Sopenharmony_ci 697cb93a386Sopenharmony_ci /* Trimming for composites not implemented. 698cb93a386Sopenharmony_ci * If removing hints it falls out of that. */ 699cb93a386Sopenharmony_ci const Glyph trim_padding () const { return Glyph (bytes); } 700cb93a386Sopenharmony_ci 701cb93a386Sopenharmony_ci void drop_hints () 702cb93a386Sopenharmony_ci { 703cb93a386Sopenharmony_ci for (const auto &_ : get_iterator ()) 704cb93a386Sopenharmony_ci const_cast<CompositeGlyphChain &> (_).drop_instructions_flag (); 705cb93a386Sopenharmony_ci } 706cb93a386Sopenharmony_ci 707cb93a386Sopenharmony_ci /* Chop instructions off the end */ 708cb93a386Sopenharmony_ci void drop_hints_bytes (hb_bytes_t &dest_start) const 709cb93a386Sopenharmony_ci { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } 710cb93a386Sopenharmony_ci 711cb93a386Sopenharmony_ci void set_overlaps_flag () 712cb93a386Sopenharmony_ci { 713cb93a386Sopenharmony_ci const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header)) 714cb93a386Sopenharmony_ci .set_overlaps_flag (); 715cb93a386Sopenharmony_ci } 716cb93a386Sopenharmony_ci }; 717cb93a386Sopenharmony_ci 718cb93a386Sopenharmony_ci enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; 719cb93a386Sopenharmony_ci 720cb93a386Sopenharmony_ci public: 721cb93a386Sopenharmony_ci composite_iter_t get_composite_iterator () const 722cb93a386Sopenharmony_ci { 723cb93a386Sopenharmony_ci if (type != COMPOSITE) return composite_iter_t (); 724cb93a386Sopenharmony_ci return CompositeGlyph (*header, bytes).get_iterator (); 725cb93a386Sopenharmony_ci } 726cb93a386Sopenharmony_ci 727cb93a386Sopenharmony_ci const Glyph trim_padding () const 728cb93a386Sopenharmony_ci { 729cb93a386Sopenharmony_ci switch (type) { 730cb93a386Sopenharmony_ci case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); 731cb93a386Sopenharmony_ci case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); 732cb93a386Sopenharmony_ci default: return bytes; 733cb93a386Sopenharmony_ci } 734cb93a386Sopenharmony_ci } 735cb93a386Sopenharmony_ci 736cb93a386Sopenharmony_ci void drop_hints () 737cb93a386Sopenharmony_ci { 738cb93a386Sopenharmony_ci switch (type) { 739cb93a386Sopenharmony_ci case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; 740cb93a386Sopenharmony_ci case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; 741cb93a386Sopenharmony_ci default: return; 742cb93a386Sopenharmony_ci } 743cb93a386Sopenharmony_ci } 744cb93a386Sopenharmony_ci 745cb93a386Sopenharmony_ci void set_overlaps_flag () 746cb93a386Sopenharmony_ci { 747cb93a386Sopenharmony_ci switch (type) { 748cb93a386Sopenharmony_ci case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; 749cb93a386Sopenharmony_ci case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; 750cb93a386Sopenharmony_ci default: return; 751cb93a386Sopenharmony_ci } 752cb93a386Sopenharmony_ci } 753cb93a386Sopenharmony_ci 754cb93a386Sopenharmony_ci void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const 755cb93a386Sopenharmony_ci { 756cb93a386Sopenharmony_ci switch (type) { 757cb93a386Sopenharmony_ci case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; 758cb93a386Sopenharmony_ci case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; 759cb93a386Sopenharmony_ci default: return; 760cb93a386Sopenharmony_ci } 761cb93a386Sopenharmony_ci } 762cb93a386Sopenharmony_ci 763cb93a386Sopenharmony_ci /* Note: Recursively calls itself. 764cb93a386Sopenharmony_ci * all_points includes phantom points 765cb93a386Sopenharmony_ci */ 766cb93a386Sopenharmony_ci bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, 767cb93a386Sopenharmony_ci contour_point_vector_t &all_points /* OUT */, 768cb93a386Sopenharmony_ci bool phantom_only = false, 769cb93a386Sopenharmony_ci unsigned int depth = 0) const 770cb93a386Sopenharmony_ci { 771cb93a386Sopenharmony_ci if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; 772cb93a386Sopenharmony_ci contour_point_vector_t points; 773cb93a386Sopenharmony_ci 774cb93a386Sopenharmony_ci switch (type) { 775cb93a386Sopenharmony_ci case COMPOSITE: 776cb93a386Sopenharmony_ci { 777cb93a386Sopenharmony_ci /* pseudo component points for each component in composite glyph */ 778cb93a386Sopenharmony_ci unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ()); 779cb93a386Sopenharmony_ci if (unlikely (!points.resize (num_points))) return false; 780cb93a386Sopenharmony_ci for (unsigned i = 0; i < points.length; i++) 781cb93a386Sopenharmony_ci points[i].init (); 782cb93a386Sopenharmony_ci break; 783cb93a386Sopenharmony_ci } 784cb93a386Sopenharmony_ci case SIMPLE: 785cb93a386Sopenharmony_ci if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) 786cb93a386Sopenharmony_ci return false; 787cb93a386Sopenharmony_ci break; 788cb93a386Sopenharmony_ci } 789cb93a386Sopenharmony_ci 790cb93a386Sopenharmony_ci /* Init phantom points */ 791cb93a386Sopenharmony_ci if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; 792cb93a386Sopenharmony_ci hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); 793cb93a386Sopenharmony_ci { 794cb93a386Sopenharmony_ci for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init (); 795cb93a386Sopenharmony_ci int h_delta = (int) header->xMin - glyf_accelerator.hmtx->get_side_bearing (gid); 796cb93a386Sopenharmony_ci int v_orig = (int) header->yMax + glyf_accelerator.vmtx->get_side_bearing (gid); 797cb93a386Sopenharmony_ci unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid); 798cb93a386Sopenharmony_ci unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid); 799cb93a386Sopenharmony_ci phantoms[PHANTOM_LEFT].x = h_delta; 800cb93a386Sopenharmony_ci phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; 801cb93a386Sopenharmony_ci phantoms[PHANTOM_TOP].y = v_orig; 802cb93a386Sopenharmony_ci phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; 803cb93a386Sopenharmony_ci } 804cb93a386Sopenharmony_ci 805cb93a386Sopenharmony_ci#ifndef HB_NO_VAR 806cb93a386Sopenharmony_ci if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()))) 807cb93a386Sopenharmony_ci return false; 808cb93a386Sopenharmony_ci#endif 809cb93a386Sopenharmony_ci 810cb93a386Sopenharmony_ci switch (type) { 811cb93a386Sopenharmony_ci case SIMPLE: 812cb93a386Sopenharmony_ci all_points.extend (points.as_array ()); 813cb93a386Sopenharmony_ci break; 814cb93a386Sopenharmony_ci case COMPOSITE: 815cb93a386Sopenharmony_ci { 816cb93a386Sopenharmony_ci unsigned int comp_index = 0; 817cb93a386Sopenharmony_ci for (auto &item : get_composite_iterator ()) 818cb93a386Sopenharmony_ci { 819cb93a386Sopenharmony_ci contour_point_vector_t comp_points; 820cb93a386Sopenharmony_ci if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ()) 821cb93a386Sopenharmony_ci .get_points (font, glyf_accelerator, comp_points, 822cb93a386Sopenharmony_ci phantom_only, depth + 1) 823cb93a386Sopenharmony_ci || comp_points.length < PHANTOM_COUNT)) 824cb93a386Sopenharmony_ci return false; 825cb93a386Sopenharmony_ci 826cb93a386Sopenharmony_ci /* Copy phantom points from component if USE_MY_METRICS flag set */ 827cb93a386Sopenharmony_ci if (item.is_use_my_metrics ()) 828cb93a386Sopenharmony_ci for (unsigned int i = 0; i < PHANTOM_COUNT; i++) 829cb93a386Sopenharmony_ci phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_ci /* Apply component transformation & translation */ 832cb93a386Sopenharmony_ci item.transform_points (comp_points); 833cb93a386Sopenharmony_ci 834cb93a386Sopenharmony_ci /* Apply translation from gvar */ 835cb93a386Sopenharmony_ci comp_points.translate (points[comp_index]); 836cb93a386Sopenharmony_ci 837cb93a386Sopenharmony_ci if (item.is_anchored ()) 838cb93a386Sopenharmony_ci { 839cb93a386Sopenharmony_ci unsigned int p1, p2; 840cb93a386Sopenharmony_ci item.get_anchor_points (p1, p2); 841cb93a386Sopenharmony_ci if (likely (p1 < all_points.length && p2 < comp_points.length)) 842cb93a386Sopenharmony_ci { 843cb93a386Sopenharmony_ci contour_point_t delta; 844cb93a386Sopenharmony_ci delta.init (all_points[p1].x - comp_points[p2].x, 845cb93a386Sopenharmony_ci all_points[p1].y - comp_points[p2].y); 846cb93a386Sopenharmony_ci 847cb93a386Sopenharmony_ci comp_points.translate (delta); 848cb93a386Sopenharmony_ci } 849cb93a386Sopenharmony_ci } 850cb93a386Sopenharmony_ci 851cb93a386Sopenharmony_ci all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); 852cb93a386Sopenharmony_ci 853cb93a386Sopenharmony_ci comp_index++; 854cb93a386Sopenharmony_ci } 855cb93a386Sopenharmony_ci 856cb93a386Sopenharmony_ci all_points.extend (phantoms); 857cb93a386Sopenharmony_ci } break; 858cb93a386Sopenharmony_ci default: 859cb93a386Sopenharmony_ci all_points.extend (phantoms); 860cb93a386Sopenharmony_ci } 861cb93a386Sopenharmony_ci 862cb93a386Sopenharmony_ci if (depth == 0) /* Apply at top level */ 863cb93a386Sopenharmony_ci { 864cb93a386Sopenharmony_ci /* Undocumented rasterizer behavior: 865cb93a386Sopenharmony_ci * Shift points horizontally by the updated left side bearing 866cb93a386Sopenharmony_ci */ 867cb93a386Sopenharmony_ci contour_point_t delta; 868cb93a386Sopenharmony_ci delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); 869cb93a386Sopenharmony_ci if (delta.x) all_points.translate (delta); 870cb93a386Sopenharmony_ci } 871cb93a386Sopenharmony_ci 872cb93a386Sopenharmony_ci return true; 873cb93a386Sopenharmony_ci } 874cb93a386Sopenharmony_ci 875cb93a386Sopenharmony_ci bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, 876cb93a386Sopenharmony_ci hb_glyph_extents_t *extents) const 877cb93a386Sopenharmony_ci { 878cb93a386Sopenharmony_ci if (type == EMPTY) return true; /* Empty glyph; zero extents. */ 879cb93a386Sopenharmony_ci return header->get_extents (font, glyf_accelerator, gid, extents); 880cb93a386Sopenharmony_ci } 881cb93a386Sopenharmony_ci 882cb93a386Sopenharmony_ci hb_bytes_t get_bytes () const { return bytes; } 883cb93a386Sopenharmony_ci 884cb93a386Sopenharmony_ci Glyph (hb_bytes_t bytes_ = hb_bytes_t (), 885cb93a386Sopenharmony_ci hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_), 886cb93a386Sopenharmony_ci header (bytes.as<GlyphHeader> ()) 887cb93a386Sopenharmony_ci { 888cb93a386Sopenharmony_ci int num_contours = header->numberOfContours; 889cb93a386Sopenharmony_ci if (unlikely (num_contours == 0)) type = EMPTY; 890cb93a386Sopenharmony_ci else if (num_contours > 0) type = SIMPLE; 891cb93a386Sopenharmony_ci else type = COMPOSITE; /* negative numbers */ 892cb93a386Sopenharmony_ci } 893cb93a386Sopenharmony_ci 894cb93a386Sopenharmony_ci protected: 895cb93a386Sopenharmony_ci hb_bytes_t bytes; 896cb93a386Sopenharmony_ci hb_codepoint_t gid; 897cb93a386Sopenharmony_ci const GlyphHeader *header; 898cb93a386Sopenharmony_ci unsigned type; 899cb93a386Sopenharmony_ci }; 900cb93a386Sopenharmony_ci 901cb93a386Sopenharmony_ci struct accelerator_t 902cb93a386Sopenharmony_ci { 903cb93a386Sopenharmony_ci void init (hb_face_t *face_) 904cb93a386Sopenharmony_ci { 905cb93a386Sopenharmony_ci short_offset = false; 906cb93a386Sopenharmony_ci num_glyphs = 0; 907cb93a386Sopenharmony_ci loca_table = nullptr; 908cb93a386Sopenharmony_ci glyf_table = nullptr; 909cb93a386Sopenharmony_ci#ifndef HB_NO_VAR 910cb93a386Sopenharmony_ci gvar = nullptr; 911cb93a386Sopenharmony_ci#endif 912cb93a386Sopenharmony_ci hmtx = nullptr; 913cb93a386Sopenharmony_ci vmtx = nullptr; 914cb93a386Sopenharmony_ci face = face_; 915cb93a386Sopenharmony_ci const OT::head &head = *face->table.head; 916cb93a386Sopenharmony_ci if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) 917cb93a386Sopenharmony_ci /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ 918cb93a386Sopenharmony_ci return; 919cb93a386Sopenharmony_ci short_offset = 0 == head.indexToLocFormat; 920cb93a386Sopenharmony_ci 921cb93a386Sopenharmony_ci loca_table = hb_sanitize_context_t ().reference_table<loca> (face); 922cb93a386Sopenharmony_ci glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); 923cb93a386Sopenharmony_ci#ifndef HB_NO_VAR 924cb93a386Sopenharmony_ci gvar = face->table.gvar; 925cb93a386Sopenharmony_ci#endif 926cb93a386Sopenharmony_ci hmtx = face->table.hmtx; 927cb93a386Sopenharmony_ci vmtx = face->table.vmtx; 928cb93a386Sopenharmony_ci 929cb93a386Sopenharmony_ci num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; 930cb93a386Sopenharmony_ci num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); 931cb93a386Sopenharmony_ci } 932cb93a386Sopenharmony_ci 933cb93a386Sopenharmony_ci void fini () 934cb93a386Sopenharmony_ci { 935cb93a386Sopenharmony_ci loca_table.destroy (); 936cb93a386Sopenharmony_ci glyf_table.destroy (); 937cb93a386Sopenharmony_ci } 938cb93a386Sopenharmony_ci 939cb93a386Sopenharmony_ci protected: 940cb93a386Sopenharmony_ci template<typename T> 941cb93a386Sopenharmony_ci bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const 942cb93a386Sopenharmony_ci { 943cb93a386Sopenharmony_ci if (gid >= num_glyphs) return false; 944cb93a386Sopenharmony_ci 945cb93a386Sopenharmony_ci /* Making this allocfree is not that easy 946cb93a386Sopenharmony_ci https://github.com/harfbuzz/harfbuzz/issues/2095 947cb93a386Sopenharmony_ci mostly because of gvar handling in VF fonts, 948cb93a386Sopenharmony_ci perhaps a separate path for non-VF fonts can be considered */ 949cb93a386Sopenharmony_ci contour_point_vector_t all_points; 950cb93a386Sopenharmony_ci 951cb93a386Sopenharmony_ci bool phantom_only = !consumer.is_consuming_contour_points (); 952cb93a386Sopenharmony_ci if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only))) 953cb93a386Sopenharmony_ci return false; 954cb93a386Sopenharmony_ci 955cb93a386Sopenharmony_ci if (consumer.is_consuming_contour_points ()) 956cb93a386Sopenharmony_ci { 957cb93a386Sopenharmony_ci for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index) 958cb93a386Sopenharmony_ci consumer.consume_point (all_points[point_index]); 959cb93a386Sopenharmony_ci consumer.points_end (); 960cb93a386Sopenharmony_ci } 961cb93a386Sopenharmony_ci 962cb93a386Sopenharmony_ci /* Where to write phantoms, nullptr if not requested */ 963cb93a386Sopenharmony_ci contour_point_t *phantoms = consumer.get_phantoms_sink (); 964cb93a386Sopenharmony_ci if (phantoms) 965cb93a386Sopenharmony_ci for (unsigned i = 0; i < PHANTOM_COUNT; ++i) 966cb93a386Sopenharmony_ci phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i]; 967cb93a386Sopenharmony_ci 968cb93a386Sopenharmony_ci return true; 969cb93a386Sopenharmony_ci } 970cb93a386Sopenharmony_ci 971cb93a386Sopenharmony_ci#ifndef HB_NO_VAR 972cb93a386Sopenharmony_ci struct points_aggregator_t 973cb93a386Sopenharmony_ci { 974cb93a386Sopenharmony_ci hb_font_t *font; 975cb93a386Sopenharmony_ci hb_glyph_extents_t *extents; 976cb93a386Sopenharmony_ci contour_point_t *phantoms; 977cb93a386Sopenharmony_ci 978cb93a386Sopenharmony_ci struct contour_bounds_t 979cb93a386Sopenharmony_ci { 980cb93a386Sopenharmony_ci contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } 981cb93a386Sopenharmony_ci 982cb93a386Sopenharmony_ci void add (const contour_point_t &p) 983cb93a386Sopenharmony_ci { 984cb93a386Sopenharmony_ci min_x = hb_min (min_x, p.x); 985cb93a386Sopenharmony_ci min_y = hb_min (min_y, p.y); 986cb93a386Sopenharmony_ci max_x = hb_max (max_x, p.x); 987cb93a386Sopenharmony_ci max_y = hb_max (max_y, p.y); 988cb93a386Sopenharmony_ci } 989cb93a386Sopenharmony_ci 990cb93a386Sopenharmony_ci bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } 991cb93a386Sopenharmony_ci 992cb93a386Sopenharmony_ci void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) 993cb93a386Sopenharmony_ci { 994cb93a386Sopenharmony_ci if (unlikely (empty ())) 995cb93a386Sopenharmony_ci { 996cb93a386Sopenharmony_ci extents->width = 0; 997cb93a386Sopenharmony_ci extents->x_bearing = 0; 998cb93a386Sopenharmony_ci extents->height = 0; 999cb93a386Sopenharmony_ci extents->y_bearing = 0; 1000cb93a386Sopenharmony_ci return; 1001cb93a386Sopenharmony_ci } 1002cb93a386Sopenharmony_ci extents->x_bearing = font->em_scalef_x (min_x); 1003cb93a386Sopenharmony_ci extents->width = font->em_scalef_x (max_x) - extents->x_bearing; 1004cb93a386Sopenharmony_ci extents->y_bearing = font->em_scalef_y (max_y); 1005cb93a386Sopenharmony_ci extents->height = font->em_scalef_y (min_y) - extents->y_bearing; 1006cb93a386Sopenharmony_ci } 1007cb93a386Sopenharmony_ci 1008cb93a386Sopenharmony_ci protected: 1009cb93a386Sopenharmony_ci float min_x, min_y, max_x, max_y; 1010cb93a386Sopenharmony_ci } bounds; 1011cb93a386Sopenharmony_ci 1012cb93a386Sopenharmony_ci points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_) 1013cb93a386Sopenharmony_ci { 1014cb93a386Sopenharmony_ci font = font_; 1015cb93a386Sopenharmony_ci extents = extents_; 1016cb93a386Sopenharmony_ci phantoms = phantoms_; 1017cb93a386Sopenharmony_ci if (extents) bounds = contour_bounds_t (); 1018cb93a386Sopenharmony_ci } 1019cb93a386Sopenharmony_ci 1020cb93a386Sopenharmony_ci void consume_point (const contour_point_t &point) { bounds.add (point); } 1021cb93a386Sopenharmony_ci void points_end () { bounds.get_extents (font, extents); } 1022cb93a386Sopenharmony_ci 1023cb93a386Sopenharmony_ci bool is_consuming_contour_points () { return extents; } 1024cb93a386Sopenharmony_ci contour_point_t *get_phantoms_sink () { return phantoms; } 1025cb93a386Sopenharmony_ci }; 1026cb93a386Sopenharmony_ci 1027cb93a386Sopenharmony_ci public: 1028cb93a386Sopenharmony_ci unsigned 1029cb93a386Sopenharmony_ci get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const 1030cb93a386Sopenharmony_ci { 1031cb93a386Sopenharmony_ci if (unlikely (gid >= num_glyphs)) return 0; 1032cb93a386Sopenharmony_ci 1033cb93a386Sopenharmony_ci bool success = false; 1034cb93a386Sopenharmony_ci 1035cb93a386Sopenharmony_ci contour_point_t phantoms[PHANTOM_COUNT]; 1036cb93a386Sopenharmony_ci if (likely (font->num_coords == gvar->get_axis_count ())) 1037cb93a386Sopenharmony_ci success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); 1038cb93a386Sopenharmony_ci 1039cb93a386Sopenharmony_ci if (unlikely (!success)) 1040cb93a386Sopenharmony_ci return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid); 1041cb93a386Sopenharmony_ci 1042cb93a386Sopenharmony_ci float result = is_vertical 1043cb93a386Sopenharmony_ci ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y 1044cb93a386Sopenharmony_ci : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x; 1045cb93a386Sopenharmony_ci return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); 1046cb93a386Sopenharmony_ci } 1047cb93a386Sopenharmony_ci 1048cb93a386Sopenharmony_ci int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const 1049cb93a386Sopenharmony_ci { 1050cb93a386Sopenharmony_ci if (unlikely (gid >= num_glyphs)) return 0; 1051cb93a386Sopenharmony_ci 1052cb93a386Sopenharmony_ci hb_glyph_extents_t extents; 1053cb93a386Sopenharmony_ci 1054cb93a386Sopenharmony_ci contour_point_t phantoms[PHANTOM_COUNT]; 1055cb93a386Sopenharmony_ci if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) 1056cb93a386Sopenharmony_ci return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid); 1057cb93a386Sopenharmony_ci 1058cb93a386Sopenharmony_ci return is_vertical 1059cb93a386Sopenharmony_ci ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing 1060cb93a386Sopenharmony_ci : floorf (phantoms[PHANTOM_LEFT].x); 1061cb93a386Sopenharmony_ci } 1062cb93a386Sopenharmony_ci#endif 1063cb93a386Sopenharmony_ci 1064cb93a386Sopenharmony_ci public: 1065cb93a386Sopenharmony_ci bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const 1066cb93a386Sopenharmony_ci { 1067cb93a386Sopenharmony_ci if (unlikely (gid >= num_glyphs)) return false; 1068cb93a386Sopenharmony_ci 1069cb93a386Sopenharmony_ci#ifndef HB_NO_VAR 1070cb93a386Sopenharmony_ci if (font->num_coords && font->num_coords == gvar->get_axis_count ()) 1071cb93a386Sopenharmony_ci return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); 1072cb93a386Sopenharmony_ci#endif 1073cb93a386Sopenharmony_ci return glyph_for_gid (gid).get_extents (font, *this, extents); 1074cb93a386Sopenharmony_ci } 1075cb93a386Sopenharmony_ci 1076cb93a386Sopenharmony_ci const Glyph 1077cb93a386Sopenharmony_ci glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const 1078cb93a386Sopenharmony_ci { 1079cb93a386Sopenharmony_ci if (unlikely (gid >= num_glyphs)) return Glyph (); 1080cb93a386Sopenharmony_ci 1081cb93a386Sopenharmony_ci unsigned int start_offset, end_offset; 1082cb93a386Sopenharmony_ci 1083cb93a386Sopenharmony_ci if (short_offset) 1084cb93a386Sopenharmony_ci { 1085cb93a386Sopenharmony_ci const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; 1086cb93a386Sopenharmony_ci start_offset = 2 * offsets[gid]; 1087cb93a386Sopenharmony_ci end_offset = 2 * offsets[gid + 1]; 1088cb93a386Sopenharmony_ci } 1089cb93a386Sopenharmony_ci else 1090cb93a386Sopenharmony_ci { 1091cb93a386Sopenharmony_ci const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; 1092cb93a386Sopenharmony_ci start_offset = offsets[gid]; 1093cb93a386Sopenharmony_ci end_offset = offsets[gid + 1]; 1094cb93a386Sopenharmony_ci } 1095cb93a386Sopenharmony_ci 1096cb93a386Sopenharmony_ci if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) 1097cb93a386Sopenharmony_ci return Glyph (); 1098cb93a386Sopenharmony_ci 1099cb93a386Sopenharmony_ci Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, 1100cb93a386Sopenharmony_ci end_offset - start_offset), gid); 1101cb93a386Sopenharmony_ci return needs_padding_removal ? glyph.trim_padding () : glyph; 1102cb93a386Sopenharmony_ci } 1103cb93a386Sopenharmony_ci 1104cb93a386Sopenharmony_ci unsigned 1105cb93a386Sopenharmony_ci add_gid_and_children (hb_codepoint_t gid, 1106cb93a386Sopenharmony_ci hb_set_t *gids_to_retain, 1107cb93a386Sopenharmony_ci unsigned depth = 0, 1108cb93a386Sopenharmony_ci unsigned operation_count = 0) const 1109cb93a386Sopenharmony_ci { 1110cb93a386Sopenharmony_ci if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; 1111cb93a386Sopenharmony_ci if (unlikely (operation_count++ > HB_MAX_COMPOSITE_OPERATIONS)) return operation_count; 1112cb93a386Sopenharmony_ci /* Check if is already visited */ 1113cb93a386Sopenharmony_ci if (gids_to_retain->has (gid)) return operation_count; 1114cb93a386Sopenharmony_ci 1115cb93a386Sopenharmony_ci gids_to_retain->add (gid); 1116cb93a386Sopenharmony_ci 1117cb93a386Sopenharmony_ci auto it = glyph_for_gid (gid).get_composite_iterator (); 1118cb93a386Sopenharmony_ci while (it) 1119cb93a386Sopenharmony_ci { 1120cb93a386Sopenharmony_ci auto item = *(it++); 1121cb93a386Sopenharmony_ci operation_count = 1122cb93a386Sopenharmony_ci add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth, operation_count); 1123cb93a386Sopenharmony_ci } 1124cb93a386Sopenharmony_ci 1125cb93a386Sopenharmony_ci return operation_count; 1126cb93a386Sopenharmony_ci } 1127cb93a386Sopenharmony_ci 1128cb93a386Sopenharmony_ci#ifdef HB_EXPERIMENTAL_API 1129cb93a386Sopenharmony_ci struct path_builder_t 1130cb93a386Sopenharmony_ci { 1131cb93a386Sopenharmony_ci hb_font_t *font; 1132cb93a386Sopenharmony_ci draw_helper_t *draw_helper; 1133cb93a386Sopenharmony_ci 1134cb93a386Sopenharmony_ci struct optional_point_t 1135cb93a386Sopenharmony_ci { 1136cb93a386Sopenharmony_ci optional_point_t () { has_data = false; } 1137cb93a386Sopenharmony_ci optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; } 1138cb93a386Sopenharmony_ci 1139cb93a386Sopenharmony_ci bool has_data; 1140cb93a386Sopenharmony_ci float x; 1141cb93a386Sopenharmony_ci float y; 1142cb93a386Sopenharmony_ci 1143cb93a386Sopenharmony_ci optional_point_t lerp (optional_point_t p, float t) 1144cb93a386Sopenharmony_ci { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } 1145cb93a386Sopenharmony_ci } first_oncurve, first_offcurve, last_offcurve; 1146cb93a386Sopenharmony_ci 1147cb93a386Sopenharmony_ci path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_) 1148cb93a386Sopenharmony_ci { 1149cb93a386Sopenharmony_ci font = font_; 1150cb93a386Sopenharmony_ci draw_helper = &draw_helper_; 1151cb93a386Sopenharmony_ci first_oncurve = first_offcurve = last_offcurve = optional_point_t (); 1152cb93a386Sopenharmony_ci } 1153cb93a386Sopenharmony_ci 1154cb93a386Sopenharmony_ci /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 1155cb93a386Sopenharmony_ci See also: 1156cb93a386Sopenharmony_ci * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html 1157cb93a386Sopenharmony_ci * https://stackoverflow.com/a/20772557 */ 1158cb93a386Sopenharmony_ci void consume_point (const contour_point_t &point) 1159cb93a386Sopenharmony_ci { 1160cb93a386Sopenharmony_ci /* Skip empty contours */ 1161cb93a386Sopenharmony_ci if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data)) 1162cb93a386Sopenharmony_ci return; 1163cb93a386Sopenharmony_ci 1164cb93a386Sopenharmony_ci bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE; 1165cb93a386Sopenharmony_ci optional_point_t p (point.x, point.y); 1166cb93a386Sopenharmony_ci if (!first_oncurve.has_data) 1167cb93a386Sopenharmony_ci { 1168cb93a386Sopenharmony_ci if (is_on_curve) 1169cb93a386Sopenharmony_ci { 1170cb93a386Sopenharmony_ci first_oncurve = p; 1171cb93a386Sopenharmony_ci draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); 1172cb93a386Sopenharmony_ci } 1173cb93a386Sopenharmony_ci else 1174cb93a386Sopenharmony_ci { 1175cb93a386Sopenharmony_ci if (first_offcurve.has_data) 1176cb93a386Sopenharmony_ci { 1177cb93a386Sopenharmony_ci optional_point_t mid = first_offcurve.lerp (p, .5f); 1178cb93a386Sopenharmony_ci first_oncurve = mid; 1179cb93a386Sopenharmony_ci last_offcurve = p; 1180cb93a386Sopenharmony_ci draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); 1181cb93a386Sopenharmony_ci } 1182cb93a386Sopenharmony_ci else 1183cb93a386Sopenharmony_ci first_offcurve = p; 1184cb93a386Sopenharmony_ci } 1185cb93a386Sopenharmony_ci } 1186cb93a386Sopenharmony_ci else 1187cb93a386Sopenharmony_ci { 1188cb93a386Sopenharmony_ci if (last_offcurve.has_data) 1189cb93a386Sopenharmony_ci { 1190cb93a386Sopenharmony_ci if (is_on_curve) 1191cb93a386Sopenharmony_ci { 1192cb93a386Sopenharmony_ci draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), 1193cb93a386Sopenharmony_ci font->em_scalef_x (p.x), font->em_scalef_y (p.y)); 1194cb93a386Sopenharmony_ci last_offcurve = optional_point_t (); 1195cb93a386Sopenharmony_ci } 1196cb93a386Sopenharmony_ci else 1197cb93a386Sopenharmony_ci { 1198cb93a386Sopenharmony_ci optional_point_t mid = last_offcurve.lerp (p, .5f); 1199cb93a386Sopenharmony_ci draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), 1200cb93a386Sopenharmony_ci font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); 1201cb93a386Sopenharmony_ci last_offcurve = p; 1202cb93a386Sopenharmony_ci } 1203cb93a386Sopenharmony_ci } 1204cb93a386Sopenharmony_ci else 1205cb93a386Sopenharmony_ci { 1206cb93a386Sopenharmony_ci if (is_on_curve) 1207cb93a386Sopenharmony_ci draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); 1208cb93a386Sopenharmony_ci else 1209cb93a386Sopenharmony_ci last_offcurve = p; 1210cb93a386Sopenharmony_ci } 1211cb93a386Sopenharmony_ci } 1212cb93a386Sopenharmony_ci 1213cb93a386Sopenharmony_ci if (point.is_end_point) 1214cb93a386Sopenharmony_ci { 1215cb93a386Sopenharmony_ci if (first_offcurve.has_data && last_offcurve.has_data) 1216cb93a386Sopenharmony_ci { 1217cb93a386Sopenharmony_ci optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); 1218cb93a386Sopenharmony_ci draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), 1219cb93a386Sopenharmony_ci font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); 1220cb93a386Sopenharmony_ci last_offcurve = optional_point_t (); 1221cb93a386Sopenharmony_ci /* now check the rest */ 1222cb93a386Sopenharmony_ci } 1223cb93a386Sopenharmony_ci 1224cb93a386Sopenharmony_ci if (first_offcurve.has_data && first_oncurve.has_data) 1225cb93a386Sopenharmony_ci draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y), 1226cb93a386Sopenharmony_ci font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); 1227cb93a386Sopenharmony_ci else if (last_offcurve.has_data && first_oncurve.has_data) 1228cb93a386Sopenharmony_ci draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), 1229cb93a386Sopenharmony_ci font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); 1230cb93a386Sopenharmony_ci else if (first_oncurve.has_data) 1231cb93a386Sopenharmony_ci draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); 1232cb93a386Sopenharmony_ci 1233cb93a386Sopenharmony_ci /* Getting ready for the next contour */ 1234cb93a386Sopenharmony_ci first_oncurve = first_offcurve = last_offcurve = optional_point_t (); 1235cb93a386Sopenharmony_ci draw_helper->end_path (); 1236cb93a386Sopenharmony_ci } 1237cb93a386Sopenharmony_ci } 1238cb93a386Sopenharmony_ci void points_end () {} 1239cb93a386Sopenharmony_ci 1240cb93a386Sopenharmony_ci bool is_consuming_contour_points () { return true; } 1241cb93a386Sopenharmony_ci contour_point_t *get_phantoms_sink () { return nullptr; } 1242cb93a386Sopenharmony_ci }; 1243cb93a386Sopenharmony_ci 1244cb93a386Sopenharmony_ci bool 1245cb93a386Sopenharmony_ci get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const 1246cb93a386Sopenharmony_ci { return get_points (font, gid, path_builder_t (font, draw_helper)); } 1247cb93a386Sopenharmony_ci#endif 1248cb93a386Sopenharmony_ci 1249cb93a386Sopenharmony_ci#ifndef HB_NO_VAR 1250cb93a386Sopenharmony_ci const gvar_accelerator_t *gvar; 1251cb93a386Sopenharmony_ci#endif 1252cb93a386Sopenharmony_ci const hmtx_accelerator_t *hmtx; 1253cb93a386Sopenharmony_ci const vmtx_accelerator_t *vmtx; 1254cb93a386Sopenharmony_ci 1255cb93a386Sopenharmony_ci private: 1256cb93a386Sopenharmony_ci bool short_offset; 1257cb93a386Sopenharmony_ci unsigned int num_glyphs; 1258cb93a386Sopenharmony_ci hb_blob_ptr_t<loca> loca_table; 1259cb93a386Sopenharmony_ci hb_blob_ptr_t<glyf> glyf_table; 1260cb93a386Sopenharmony_ci hb_face_t *face; 1261cb93a386Sopenharmony_ci }; 1262cb93a386Sopenharmony_ci 1263cb93a386Sopenharmony_ci struct SubsetGlyph 1264cb93a386Sopenharmony_ci { 1265cb93a386Sopenharmony_ci hb_codepoint_t new_gid; 1266cb93a386Sopenharmony_ci hb_codepoint_t old_gid; 1267cb93a386Sopenharmony_ci Glyph source_glyph; 1268cb93a386Sopenharmony_ci hb_bytes_t dest_start; /* region of source_glyph to copy first */ 1269cb93a386Sopenharmony_ci hb_bytes_t dest_end; /* region of source_glyph to copy second */ 1270cb93a386Sopenharmony_ci 1271cb93a386Sopenharmony_ci bool serialize (hb_serialize_context_t *c, 1272cb93a386Sopenharmony_ci const hb_subset_plan_t *plan) const 1273cb93a386Sopenharmony_ci { 1274cb93a386Sopenharmony_ci TRACE_SERIALIZE (this); 1275cb93a386Sopenharmony_ci 1276cb93a386Sopenharmony_ci hb_bytes_t dest_glyph = dest_start.copy (c); 1277cb93a386Sopenharmony_ci dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); 1278cb93a386Sopenharmony_ci unsigned int pad_length = padding (); 1279cb93a386Sopenharmony_ci DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); 1280cb93a386Sopenharmony_ci 1281cb93a386Sopenharmony_ci HBUINT8 pad; 1282cb93a386Sopenharmony_ci pad = 0; 1283cb93a386Sopenharmony_ci while (pad_length > 0) 1284cb93a386Sopenharmony_ci { 1285cb93a386Sopenharmony_ci c->embed (pad); 1286cb93a386Sopenharmony_ci pad_length--; 1287cb93a386Sopenharmony_ci } 1288cb93a386Sopenharmony_ci 1289cb93a386Sopenharmony_ci if (unlikely (!dest_glyph.length)) return_trace (true); 1290cb93a386Sopenharmony_ci 1291cb93a386Sopenharmony_ci /* update components gids */ 1292cb93a386Sopenharmony_ci for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) 1293cb93a386Sopenharmony_ci { 1294cb93a386Sopenharmony_ci hb_codepoint_t new_gid; 1295cb93a386Sopenharmony_ci if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid)) 1296cb93a386Sopenharmony_ci const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid); 1297cb93a386Sopenharmony_ci } 1298cb93a386Sopenharmony_ci 1299cb93a386Sopenharmony_ci if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) 1300cb93a386Sopenharmony_ci Glyph (dest_glyph).drop_hints (); 1301cb93a386Sopenharmony_ci 1302cb93a386Sopenharmony_ci if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG) 1303cb93a386Sopenharmony_ci Glyph (dest_glyph).set_overlaps_flag (); 1304cb93a386Sopenharmony_ci 1305cb93a386Sopenharmony_ci return_trace (true); 1306cb93a386Sopenharmony_ci } 1307cb93a386Sopenharmony_ci 1308cb93a386Sopenharmony_ci void drop_hints_bytes () 1309cb93a386Sopenharmony_ci { source_glyph.drop_hints_bytes (dest_start, dest_end); } 1310cb93a386Sopenharmony_ci 1311cb93a386Sopenharmony_ci unsigned int length () const { return dest_start.length + dest_end.length; } 1312cb93a386Sopenharmony_ci /* pad to 2 to ensure 2-byte loca will be ok */ 1313cb93a386Sopenharmony_ci unsigned int padding () const { return length () % 2; } 1314cb93a386Sopenharmony_ci unsigned int padded_size () const { return length () + padding (); } 1315cb93a386Sopenharmony_ci }; 1316cb93a386Sopenharmony_ci 1317cb93a386Sopenharmony_ci protected: 1318cb93a386Sopenharmony_ci UnsizedArrayOf<HBUINT8> 1319cb93a386Sopenharmony_ci dataZ; /* Glyphs data. */ 1320cb93a386Sopenharmony_ci public: 1321cb93a386Sopenharmony_ci DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always 1322cb93a386Sopenharmony_ci * check the size externally, allow Null() object of it by 1323cb93a386Sopenharmony_ci * defining it _MIN instead. */ 1324cb93a386Sopenharmony_ci}; 1325cb93a386Sopenharmony_ci 1326cb93a386Sopenharmony_cistruct glyf_accelerator_t : glyf::accelerator_t {}; 1327cb93a386Sopenharmony_ci 1328cb93a386Sopenharmony_ci} /* namespace OT */ 1329cb93a386Sopenharmony_ci 1330cb93a386Sopenharmony_ci 1331cb93a386Sopenharmony_ci#endif /* HB_OT_GLYF_TABLE_HH */ 1332