blob: ff6d7ed1c3744795d41dc29d04496d00b2511dc9 [file] [log] [blame]
Michiharu Ariza5561b812018-08-06 10:04:53 -07001/*
2 * Copyright © 2018 Adobe Systems Incorporated.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Adobe Author(s): Michiharu Ariza
25 */
26
Michiharu Ariza1d1afdd2018-08-29 13:36:39 -070027#ifndef HB_SUBSET_CFF_COMMON_HH
28#define HB_SUBSET_CFF_COMMON_HH
Michiharu Ariza5561b812018-08-06 10:04:53 -070029
Michiharu Ariza8af96902018-08-29 13:26:17 -070030#include "hb.hh"
Michiharu Ariza5561b812018-08-06 10:04:53 -070031
32#include "hb-subset-plan.hh"
Michiharu Ariza8af96902018-08-29 13:26:17 -070033#include "hb-cff-interp-cs-common.hh"
Michiharu Ariza633ce882018-08-15 12:00:19 -070034
35namespace CFF {
36
Michiharu Arizaa11420b2018-08-29 12:14:30 -070037/* Used for writing a temporary charstring */
38struct ByteStrBuff : hb_vector_t<char, 1>
39{
40 inline bool encode_byte (unsigned char b)
41 {
42 return (push ((const char)b) != &Crap(char));
43 }
44
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070045 inline bool encode_int (int v)
46 {
47 if ((-1131 <= v) && (v <= 1131))
48 {
49 if ((-107 <= v) && (v <= 107))
50 return encode_byte (v + 139);
51 else if (v > 0)
52 {
53 v -= 108;
54 return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF);
55 }
56 else
57 {
58 v = -v - 108;
59 return encode_byte ((v >> 8) + OpCode_TwoByteNegInt0) && encode_byte (v & 0xFF);
60 }
61 }
62 assert ((v & ~0xFFFF) == 0);
63 return encode_byte (OpCode_shortint) &&
64 encode_byte ((v >> 8) & 0xFF) &&
65 encode_byte (v & 0xFF);
66 }
67
Michiharu Arizaa11420b2018-08-29 12:14:30 -070068 inline bool encode_num (const Number& n)
69 {
70 if (n.in_int_range ())
71 {
Michiharu Arizaf2d299b2018-09-04 10:25:21 -070072 return encode_int (n.to_int ());
Michiharu Arizaa11420b2018-08-29 12:14:30 -070073 }
74 else
75 {
76 int32_t v = n.to_fixed ();
77 return encode_byte (OpCode_fixedcs) &&
78 encode_byte ((v >> 24) & 0xFF) &&
79 encode_byte ((v >> 16) & 0xFF) &&
80 encode_byte ((v >> 8) & 0xFF) &&
81 encode_byte (v & 0xFF);
82 }
83 }
84
85 inline bool encode_op (OpCode op)
86 {
87 if (Is_OpCode_ESC (op))
88 return encode_byte (OpCode_escape) &&
89 encode_byte (Unmake_OpCode_ESC (op));
90 else
91 return encode_byte (op);
92 }
93};
94
95struct ByteStrBuffArray : hb_vector_t<ByteStrBuff, 1>
96{
97 inline void fini (void)
98 {
99 for (unsigned int i = 0; i < len; i++)
100 hb_vector_t<ByteStrBuff, 1>::operator[] (i).fini ();
101 hb_vector_t<ByteStrBuff, 1>::fini ();
102 }
103};
104
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700105struct CFFSubTableOffsets {
106 inline CFFSubTableOffsets (void)
107 : privateDictsOffset (0)
108
109 {
110 topDictInfo.init ();
111 FDSelectInfo.init ();
112 FDArrayInfo.init ();
113 charStringsInfo.init ();
114 globalSubrsInfo.init ();
115 localSubrsInfos.init ();
116 }
117
118 inline ~CFFSubTableOffsets (void)
119 {
120 localSubrsInfos.fini ();
121 }
122
123 TableInfo topDictInfo;
124 TableInfo FDSelectInfo;
125 TableInfo FDArrayInfo;
126 TableInfo charStringsInfo;
127 unsigned int privateDictsOffset;
128 TableInfo globalSubrsInfo;
129 hb_vector_t<TableInfo> localSubrsInfos;
130};
131
132struct CFFTopDict_OpSerializer : OpSerializer
133{
134 inline bool serialize (hb_serialize_context_t *c,
135 const OpStr &opstr,
136 const CFFSubTableOffsets &offsets) const
137 {
138 TRACE_SERIALIZE (this);
139
140 switch (opstr.op)
141 {
142 case OpCode_CharStrings:
143 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
144
145 case OpCode_FDArray:
146 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
147
148 case OpCode_FDSelect:
149 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
150
151 default:
152 return_trace (copy_opstr (c, opstr));
153 }
154 return_trace (true);
155 }
156
157 inline unsigned int calculate_serialized_size (const OpStr &opstr) const
158 {
159 switch (opstr.op)
160 {
161 case OpCode_CharStrings:
162 case OpCode_FDArray:
163 case OpCode_FDSelect:
164 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
165
166 default:
167 return opstr.str.len;
168 }
169 }
170};
171
172struct CFFFontDict_OpSerializer : OpSerializer
173{
174 inline bool serialize (hb_serialize_context_t *c,
175 const OpStr &opstr,
176 const TableInfo &privateDictInfo) const
177 {
178 TRACE_SERIALIZE (this);
179
180 if (opstr.op == OpCode_Private)
181 {
182 /* serialize the private dict size as a 2-byte integer */
183 if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size)))
184 return_trace (false);
185
186 /* serialize the private dict offset as a 4-byte integer */
187 if (unlikely (!UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
188 return_trace (false);
189
190 /* serialize the opcode */
191 HBUINT8 *p = c->allocate_size<HBUINT8> (1);
192 if (unlikely (p == nullptr)) return_trace (false);
193 p->set (OpCode_Private);
194
195 return_trace (true);
196 }
197 else
198 {
199 HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
200 if (unlikely (d == nullptr)) return_trace (false);
201 memcpy (d, &opstr.str.str[0], opstr.str.len);
202 }
203 return_trace (true);
204 }
205
206 inline unsigned int calculate_serialized_size (const OpStr &opstr) const
207 {
208 if (opstr.op == OpCode_Private)
209 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
210 else
211 return opstr.str.len;
212 }
213};
214
215struct CFFPrivateDict_OpSerializer : OpSerializer
216{
217 inline CFFPrivateDict_OpSerializer (bool drop_hints_=false, bool flatten_subrs_=false)
218 : drop_hints (drop_hints_), flatten_subrs (flatten_subrs_) {}
219
220 inline bool serialize (hb_serialize_context_t *c,
221 const OpStr &opstr,
222 const unsigned int subrsOffset) const
223 {
224 TRACE_SERIALIZE (this);
225
Michiharu Arizafcf17782018-08-31 16:28:47 -0700226 if (drop_hints && DictOpSet<>::is_hint_op (opstr.op))
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700227 return true;
228 if (opstr.op == OpCode_Subrs)
229 {
230 if (flatten_subrs)
231 return_trace (true);
232 else
233 return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
234 }
235 else
236 return_trace (copy_opstr (c, opstr));
237 }
238
239 inline unsigned int calculate_serialized_size (const OpStr &opstr) const
240 {
Michiharu Arizafcf17782018-08-31 16:28:47 -0700241 if (drop_hints && DictOpSet<>::is_hint_op (opstr.op))
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700242 return 0;
243 if (opstr.op == OpCode_Subrs)
244 {
245 if (flatten_subrs)
246 return 0;
247 else
248 return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
249 }
250 else
251 return opstr.str.len;
252 }
253
254 protected:
255 const bool drop_hints;
256 const bool flatten_subrs;
257};
258
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700259struct FlattenParam
260{
261 ByteStrBuff &flatStr;
262 bool drop_hints;
263};
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700264
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700265template <typename ACC, typename ENV, typename OPSET>
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700266struct SubrFlattener
267{
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700268 inline SubrFlattener (const ACC &acc_,
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700269 const hb_vector_t<hb_codepoint_t> &glyphs_,
270 bool drop_hints_)
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700271 : acc (acc_),
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700272 glyphs (glyphs_),
273 drop_hints (drop_hints_)
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700274 {}
275
276 inline bool flatten (ByteStrBuffArray &flat_charstrings)
277 {
278 if (!flat_charstrings.resize (glyphs.len))
279 return false;
280 for (unsigned int i = 0; i < glyphs.len; i++)
281 flat_charstrings[i].init ();
282 for (unsigned int i = 0; i < glyphs.len; i++)
283 {
284 hb_codepoint_t glyph = glyphs[i];
285 const ByteStr str = (*acc.charStrings)[glyph];
286 unsigned int fd = acc.fdSelect->get_fd (glyph);
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700287 CSInterpreter<ENV, OPSET, FlattenParam> interp;
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700288 interp.env.init (str, acc, fd);
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700289 FlattenParam param = { flat_charstrings[i], drop_hints };
290 if (unlikely (!interp.interpret (param)))
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700291 return false;
292 }
293 return true;
294 }
295
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700296 const ACC &acc;
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700297 const hb_vector_t<hb_codepoint_t> &glyphs;
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700298 bool drop_hints;
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700299};
300
Michiharu Ariza633ce882018-08-15 12:00:19 -0700301struct SubrRefMaps
302{
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700303 inline void init (void)
Michiharu Ariza633ce882018-08-15 12:00:19 -0700304 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700305 valid = false;
306 global_map = nullptr;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700307 local_maps.init ();
308 }
309
310 inline void init (unsigned int fd_count)
311 {
312 valid = true;
313 global_map = hb_set_create ();
314 if (global_map == hb_set_get_empty ())
315 valid = false;
316 if (!local_maps.resize (fd_count))
317 valid = false;
318
319 for (unsigned int i = 0; i < local_maps.len; i++)
320 {
321 local_maps[i] = hb_set_create ();
322 if (local_maps[i] == hb_set_get_empty ())
323 valid = false;
324 }
325 }
326
327 inline void fini (void)
328 {
329 hb_set_destroy (global_map);
330 for (unsigned int i = 0; i < local_maps.len; i++)
331 hb_set_destroy (local_maps[i]);
332 local_maps.fini ();
333 }
334
335 bool is_valid (void) const { return valid; }
336 bool valid;
337 hb_set_t *global_map;
338 hb_vector_t<hb_set_t *> local_maps;
339};
340
341struct SubrRefMapPair
342{
343 inline void init (void) {}
344
345 hb_set_t *global_map;
346 hb_set_t *local_map;
347};
348
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700349template <typename ACC, typename ENV, typename OPSET>
Michiharu Ariza633ce882018-08-15 12:00:19 -0700350struct SubrSubsetter
351{
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700352 inline SubrSubsetter (const ACC &acc_, const hb_vector_t<hb_codepoint_t> &glyphs_)
Michiharu Ariza633ce882018-08-15 12:00:19 -0700353 : acc (acc_),
354 glyphs (glyphs_)
355 {}
356
357 bool collect_refs (SubrRefMaps& refmaps /*OUT*/)
358 {
359 refmaps.init (acc.fdCount);
360 if (unlikely (!refmaps.valid)) return false;
361 for (unsigned int i = 0; i < glyphs.len; i++)
362 {
363 hb_codepoint_t glyph = glyphs[i];
364 const ByteStr str = (*acc.charStrings)[glyph];
365 unsigned int fd = acc.fdSelect->get_fd (glyph);
366 SubrRefMapPair pair = { refmaps.global_map, refmaps.local_maps[fd] };
367 CSInterpreter<ENV, OPSET, SubrRefMapPair> interp;
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700368 interp.env.init (str, acc, fd);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700369 if (unlikely (!interp.interpret (pair)))
370 return false;
371 }
372 return true;
373 }
374
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700375 const ACC &acc;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700376 const hb_vector_t<hb_codepoint_t> &glyphs;
377};
378
379}; /* namespace CFF */
Michiharu Ariza5561b812018-08-06 10:04:53 -0700380
381HB_INTERNAL bool
382hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
383 unsigned int fdCount,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700384 const CFF::FDSelect &src, /* IN */
Michiharu Ariza5561b812018-08-06 10:04:53 -0700385 unsigned int &subset_fd_count /* OUT */,
386 unsigned int &subst_fdselect_size /* OUT */,
387 unsigned int &subst_fdselect_format /* OUT */,
388 hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */,
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700389 CFF::FDMap &fdmap /* OUT */);
Michiharu Ariza5561b812018-08-06 10:04:53 -0700390
391HB_INTERNAL bool
392hb_serialize_cff_fdselect (hb_serialize_context_t *c,
393 const hb_vector_t<hb_codepoint_t> &glyphs,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700394 const CFF::FDSelect &src,
Michiharu Ariza5561b812018-08-06 10:04:53 -0700395 unsigned int fd_count,
396 unsigned int fdselect_format,
397 unsigned int size,
398 const hb_vector_t<hb_codepoint_t> &first_glyphs,
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700399 const CFF::FDMap &fdmap);
Michiharu Ariza5561b812018-08-06 10:04:53 -0700400
Michiharu Ariza1d1afdd2018-08-29 13:36:39 -0700401#endif /* HB_SUBSET_CFF_COMMON_HH */