| 1 | #ifndef OT_GLYF_SUBSETGLYPH_HH |
| 2 | #define OT_GLYF_SUBSETGLYPH_HH |
| 3 | |
| 4 | |
| 5 | #include "../../hb-open-type.hh" |
| 6 | |
| 7 | |
| 8 | namespace OT { |
| 9 | |
| 10 | struct glyf_accelerator_t; |
| 11 | |
| 12 | namespace glyf_impl { |
| 13 | |
| 14 | |
| 15 | struct SubsetGlyph |
| 16 | { |
| 17 | hb_codepoint_t old_gid; |
| 18 | Glyph source_glyph; |
| 19 | hb_bytes_t dest_start; /* region of source_glyph to copy first */ |
| 20 | hb_bytes_t dest_end; /* region of source_glyph to copy second */ |
| 21 | bool allocated; |
| 22 | |
| 23 | bool serialize (hb_serialize_context_t *c, |
| 24 | bool use_short_loca, |
| 25 | const hb_subset_plan_t *plan) const |
| 26 | { |
| 27 | TRACE_SERIALIZE (this); |
| 28 | |
| 29 | hb_bytes_t dest_glyph = dest_start.copy (c); |
| 30 | hb_bytes_t end_copy = dest_end.copy (c); |
| 31 | if (!end_copy.arrayZ || !dest_glyph.arrayZ) { |
| 32 | return false; |
| 33 | } |
| 34 | |
| 35 | dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length); |
| 36 | unsigned int pad_length = use_short_loca ? padding () : 0; |
| 37 | DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u" , dest_glyph.length, dest_glyph.length + pad_length, pad_length); |
| 38 | |
| 39 | HBUINT8 pad; |
| 40 | pad = 0; |
| 41 | while (pad_length > 0) |
| 42 | { |
| 43 | (void) c->embed (pad); |
| 44 | pad_length--; |
| 45 | } |
| 46 | |
| 47 | if (unlikely (!dest_glyph.length)) return_trace (true); |
| 48 | |
| 49 | /* update components gids. */ |
| 50 | for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) |
| 51 | { |
| 52 | hb_codepoint_t new_gid; |
| 53 | if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) |
| 54 | const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid); |
| 55 | } |
| 56 | #ifndef HB_NO_VAR_COMPOSITES |
| 57 | for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ()) |
| 58 | { |
| 59 | hb_codepoint_t new_gid; |
| 60 | if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) |
| 61 | const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid); |
| 62 | } |
| 63 | #endif |
| 64 | |
| 65 | #ifndef HB_NO_BEYOND_64K |
| 66 | auto it = Glyph (dest_glyph).get_composite_iterator (); |
| 67 | if (it) |
| 68 | { |
| 69 | /* lower GID24 to GID16 in components if possible. |
| 70 | * |
| 71 | * TODO: VarComposite. Not as critical, since VarComposite supports |
| 72 | * gid24 from the first version. */ |
| 73 | char *p = it ? (char *) &*it : nullptr; |
| 74 | char *q = p; |
| 75 | const char *end = dest_glyph.arrayZ + dest_glyph.length; |
| 76 | while (it) |
| 77 | { |
| 78 | auto &rec = const_cast<CompositeGlyphRecord &> (*it); |
| 79 | ++it; |
| 80 | |
| 81 | q += rec.get_size (); |
| 82 | |
| 83 | rec.lower_gid_24_to_16 (); |
| 84 | |
| 85 | unsigned size = rec.get_size (); |
| 86 | |
| 87 | memmove (p, &rec, size); |
| 88 | |
| 89 | p += size; |
| 90 | } |
| 91 | memmove (p, q, end - q); |
| 92 | p += end - q; |
| 93 | |
| 94 | /* We want to shorten the glyph, but we can't do that without |
| 95 | * updating the length in the loca table, which is already |
| 96 | * written out :-(. So we just fill the rest of the glyph with |
| 97 | * harmless instructions, since that's what they will be |
| 98 | * interpreted as. |
| 99 | * |
| 100 | * Should move the lowering to _populate_subset_glyphs() to |
| 101 | * fix this issue. */ |
| 102 | |
| 103 | hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p); |
| 104 | p += end - p; |
| 105 | dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ); |
| 106 | |
| 107 | // TODO: Padding; & trim serialized bytes. |
| 108 | // TODO: Update length in loca. Ugh. |
| 109 | } |
| 110 | #endif |
| 111 | |
| 112 | if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) |
| 113 | Glyph (dest_glyph).drop_hints (); |
| 114 | |
| 115 | if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG) |
| 116 | Glyph (dest_glyph).set_overlaps_flag (); |
| 117 | |
| 118 | return_trace (true); |
| 119 | } |
| 120 | |
| 121 | bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, |
| 122 | hb_font_t *font, |
| 123 | const glyf_accelerator_t &glyf) |
| 124 | { |
| 125 | allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); |
| 126 | return allocated; |
| 127 | } |
| 128 | |
| 129 | void free_compiled_bytes () |
| 130 | { |
| 131 | if (likely (allocated)) { |
| 132 | allocated = false; |
| 133 | dest_start.fini (); |
| 134 | dest_end.fini (); |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | void drop_hints_bytes () |
| 139 | { source_glyph.drop_hints_bytes (dest_start, dest_end); } |
| 140 | |
| 141 | unsigned int length () const { return dest_start.length + dest_end.length; } |
| 142 | /* pad to 2 to ensure 2-byte loca will be ok */ |
| 143 | unsigned int padding () const { return length () % 2; } |
| 144 | unsigned int padded_size () const { return length () + padding (); } |
| 145 | }; |
| 146 | |
| 147 | |
| 148 | } /* namespace glyf_impl */ |
| 149 | } /* namespace OT */ |
| 150 | |
| 151 | |
| 152 | #endif /* OT_GLYF_SUBSETGLYPH_HH */ |
| 153 | |