summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh
blob: 8099d3c1269fe6ca89c003db2b6b556c39dcec60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#ifndef OT_GLYF_SUBSETGLYPH_HH
#define OT_GLYF_SUBSETGLYPH_HH


#include "../../hb-open-type.hh"


namespace OT {

struct glyf_accelerator_t;

namespace glyf_impl {


struct SubsetGlyph
{
  hb_codepoint_t old_gid;
  Glyph source_glyph;
  hb_bytes_t dest_start;  /* region of source_glyph to copy first */
  hb_bytes_t dest_end;    /* region of source_glyph to copy second */
  bool allocated;

  bool serialize (hb_serialize_context_t *c,
		  bool use_short_loca,
		  const hb_subset_plan_t *plan) const
  {
    TRACE_SERIALIZE (this);

    hb_bytes_t dest_glyph = dest_start.copy (c);
    hb_bytes_t end_copy = dest_end.copy (c);
    if (!end_copy.arrayZ || !dest_glyph.arrayZ) {
      return false;
    }

    dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length);
    unsigned int pad_length = use_short_loca ? padding () : 0;
    DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);

    HBUINT8 pad;
    pad = 0;
    while (pad_length > 0)
    {
      (void) c->embed (pad);
      pad_length--;
    }

    if (unlikely (!dest_glyph.length)) return_trace (true);

    /* update components gids. */
    for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
    {
      hb_codepoint_t new_gid;
      if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
	const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
    }
#ifndef HB_NO_VAR_COMPOSITES
    for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
    {
      hb_codepoint_t new_gid;
      if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
	const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
    }
#endif

#ifndef HB_NO_BEYOND_64K
    auto it = Glyph (dest_glyph).get_composite_iterator ();
    if (it)
    {
      /* lower GID24 to GID16 in components if possible.
       *
       * TODO: VarComposite. Not as critical, since VarComposite supports
       * gid24 from the first version. */
      char *p = it ? (char *) &*it : nullptr;
      char *q = p;
      const char *end = dest_glyph.arrayZ + dest_glyph.length;
      while (it)
      {
	auto &rec = const_cast<CompositeGlyphRecord &> (*it);
	++it;

	q += rec.get_size ();

	rec.lower_gid_24_to_16 ();

	unsigned size = rec.get_size ();

	memmove (p, &rec, size);

	p += size;
      }
      memmove (p, q, end - q);
      p += end - q;

      /* We want to shorten the glyph, but we can't do that without
       * updating the length in the loca table, which is already
       * written out :-(.  So we just fill the rest of the glyph with
       * harmless instructions, since that's what they will be
       * interpreted as.
       *
       * Should move the lowering to _populate_subset_glyphs() to
       * fix this issue. */

      hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p);
      p += end - p;
      dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ);

      // TODO: Padding; & trim serialized bytes.
      // TODO: Update length in loca. Ugh.
    }
#endif

    if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
      Glyph (dest_glyph).drop_hints ();

    if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
      Glyph (dest_glyph).set_overlaps_flag ();

    return_trace (true);
  }

  bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
                                  hb_font_t *font,
                                  const glyf_accelerator_t &glyf)
  {
    allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end);
    return allocated;
  }

  void free_compiled_bytes ()
  {
    if (likely (allocated)) {
      allocated = false;
      dest_start.fini ();
      dest_end.fini ();
    }
  }

  void drop_hints_bytes ()
  { source_glyph.drop_hints_bytes (dest_start, dest_end); }

  unsigned int      length () const { return dest_start.length + dest_end.length; }
  /* pad to 2 to ensure 2-byte loca will be ok */
  unsigned int     padding () const { return length () % 2; }
  unsigned int padded_size () const { return length () + padding (); }
};


} /* namespace glyf_impl */
} /* namespace OT */


#endif /* OT_GLYF_SUBSETGLYPH_HH */