2 * Copyright © 2018 Adobe Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Adobe Author(s): Michiharu Ariza
27 #ifndef HB_OT_CFF2_TABLE_HH
28 #define HB_OT_CFF2_TABLE_HH
30 #include "hb-ot-cff-common.hh"
31 #include "hb-subset-cff-common.hh"
33 #include "hb-paint.hh"
38 * CFF2 -- Compact Font Format (CFF) Version 2
39 * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
41 #define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
43 typedef CFFIndex
<HBUINT32
> CFF2Index
;
45 typedef CFF2Index CFF2CharStrings
;
46 typedef Subrs
<HBUINT32
> CFF2Subrs
;
48 typedef FDSelect3_4
<HBUINT32
, HBUINT16
> FDSelect4
;
49 typedef FDSelect3_4_Range
<HBUINT32
, HBUINT16
> FDSelect4_Range
;
53 bool serialize (hb_serialize_context_t
*c
, const CFF2FDSelect
&src
, unsigned int num_glyphs
)
55 TRACE_SERIALIZE (this);
56 unsigned int size
= src
.get_size (num_glyphs
);
57 CFF2FDSelect
*dest
= c
->allocate_size
<CFF2FDSelect
> (size
);
58 if (unlikely (!dest
)) return_trace (false);
59 hb_memcpy (dest
, &src
, size
);
63 unsigned int get_size (unsigned int num_glyphs
) const
67 case 0: return format
.static_size
+ u
.format0
.get_size (num_glyphs
);
68 case 3: return format
.static_size
+ u
.format3
.get_size ();
69 case 4: return format
.static_size
+ u
.format4
.get_size ();
74 hb_codepoint_t
get_fd (hb_codepoint_t glyph
) const
76 if (this == &Null (CFF2FDSelect
))
81 case 0: return u
.format0
.get_fd (glyph
);
82 case 3: return u
.format3
.get_fd (glyph
);
83 case 4: return u
.format4
.get_fd (glyph
);
88 bool sanitize (hb_sanitize_context_t
*c
, unsigned int fdcount
) const
90 TRACE_SANITIZE (this);
91 if (unlikely (!c
->check_struct (this)))
97 case 0: return_trace (u
.format0
.sanitize (c
, fdcount
));
98 case 3: return_trace (u
.format3
.sanitize (c
, fdcount
));
99 case 4: return_trace (u
.format4
.sanitize (c
, fdcount
));
100 default:return_trace (false);
114 struct CFF2VariationStore
116 bool sanitize (hb_sanitize_context_t
*c
) const
118 TRACE_SANITIZE (this);
119 return_trace (c
->check_struct (this) &&
121 c
->check_range (&varStore
, size
) &&
122 varStore
.sanitize (c
));
125 bool serialize (hb_serialize_context_t
*c
, const CFF2VariationStore
*varStore
)
127 TRACE_SERIALIZE (this);
128 unsigned int size_
= varStore
->get_size ();
129 CFF2VariationStore
*dest
= c
->allocate_size
<CFF2VariationStore
> (size_
);
130 if (unlikely (!dest
)) return_trace (false);
131 hb_memcpy (dest
, varStore
, size_
);
135 unsigned int get_size () const { return HBUINT16::static_size
+ size
; }
138 VariationStore varStore
;
140 DEFINE_SIZE_MIN (2 + VariationStore::min_size
);
143 struct cff2_top_dict_values_t
: top_dict_values_t
<>
147 top_dict_values_t
<>::init ();
151 void fini () { top_dict_values_t
<>::fini (); }
153 unsigned int vstoreOffset
;
154 unsigned int FDSelectOffset
;
157 struct cff2_top_dict_opset_t
: top_dict_opset_t
<>
159 static void process_op (op_code_t op
, num_interp_env_t
& env
, cff2_top_dict_values_t
& dictval
)
162 case OpCode_FontMatrix
:
166 dictval
.add_op (op
, env
.str_ref
);
172 dictval
.vstoreOffset
= env
.argStack
.pop_uint ();
175 case OpCode_FDSelect
:
176 dictval
.FDSelectOffset
= env
.argStack
.pop_uint ();
181 SUPER::process_op (op
, env
, dictval
);
182 /* Record this operand below if stack is empty, otherwise done */
183 if (!env
.argStack
.is_empty ()) return;
186 if (unlikely (env
.in_error ())) return;
188 dictval
.add_op (op
, env
.str_ref
);
191 typedef top_dict_opset_t
<> SUPER
;
194 struct cff2_font_dict_values_t
: dict_values_t
<op_str_t
>
198 dict_values_t
<op_str_t
>::init ();
199 privateDictInfo
.init ();
201 void fini () { dict_values_t
<op_str_t
>::fini (); }
203 table_info_t privateDictInfo
;
206 struct cff2_font_dict_opset_t
: dict_opset_t
208 static void process_op (op_code_t op
, num_interp_env_t
& env
, cff2_font_dict_values_t
& dictval
)
212 dictval
.privateDictInfo
.offset
= env
.argStack
.pop_uint ();
213 dictval
.privateDictInfo
.size
= env
.argStack
.pop_uint ();
218 SUPER::process_op (op
, env
);
219 if (!env
.argStack
.is_empty ())
223 if (unlikely (env
.in_error ())) return;
225 dictval
.add_op (op
, env
.str_ref
);
229 typedef dict_opset_t SUPER
;
232 template <typename VAL
>
233 struct cff2_private_dict_values_base_t
: dict_values_t
<VAL
>
237 dict_values_t
<VAL
>::init ();
239 localSubrs
= &Null (CFF2Subrs
);
242 void fini () { dict_values_t
<VAL
>::fini (); }
244 unsigned int subrsOffset
;
245 const CFF2Subrs
*localSubrs
;
249 typedef cff2_private_dict_values_base_t
<op_str_t
> cff2_private_dict_values_subset_t
;
250 typedef cff2_private_dict_values_base_t
<num_dict_val_t
> cff2_private_dict_values_t
;
252 struct cff2_priv_dict_interp_env_t
: num_interp_env_t
254 cff2_priv_dict_interp_env_t (const hb_ubytes_t
&str
) :
255 num_interp_env_t (str
) {}
257 void process_vsindex ()
259 if (likely (!seen_vsindex
))
261 set_ivs (argStack
.pop_uint ());
266 unsigned int get_ivs () const { return ivs
; }
267 void set_ivs (unsigned int ivs_
) { ivs
= ivs_
; }
270 unsigned int ivs
= 0;
271 bool seen_vsindex
= false;
274 struct cff2_private_dict_opset_t
: dict_opset_t
276 static void process_op (op_code_t op
, cff2_priv_dict_interp_env_t
& env
, cff2_private_dict_values_t
& dictval
)
284 case OpCode_BlueScale
:
285 case OpCode_BlueShift
:
286 case OpCode_BlueFuzz
:
287 case OpCode_ExpansionFactor
:
288 case OpCode_LanguageGroup
:
289 case OpCode_BlueValues
:
290 case OpCode_OtherBlues
:
291 case OpCode_FamilyBlues
:
292 case OpCode_FamilyOtherBlues
:
293 case OpCode_StemSnapH
:
294 case OpCode_StemSnapV
:
298 dictval
.subrsOffset
= env
.argStack
.pop_uint ();
301 case OpCode_vsindexdict
:
302 env
.process_vsindex ();
303 dictval
.ivs
= env
.get_ivs ();
306 case OpCode_blenddict
:
310 dict_opset_t::process_op (op
, env
);
311 if (!env
.argStack
.is_empty ()) return;
315 if (unlikely (env
.in_error ())) return;
317 dictval
.add_op (op
, env
.str_ref
, val
);
321 struct cff2_private_dict_opset_subset_t
: dict_opset_t
323 static void process_op (op_code_t op
, cff2_priv_dict_interp_env_t
& env
, cff2_private_dict_values_subset_t
& dictval
)
326 case OpCode_BlueValues
:
327 case OpCode_OtherBlues
:
328 case OpCode_FamilyBlues
:
329 case OpCode_FamilyOtherBlues
:
332 case OpCode_BlueScale
:
333 case OpCode_BlueShift
:
334 case OpCode_BlueFuzz
:
335 case OpCode_StemSnapH
:
336 case OpCode_StemSnapV
:
337 case OpCode_LanguageGroup
:
338 case OpCode_ExpansionFactor
:
342 case OpCode_blenddict
:
347 dictval
.subrsOffset
= env
.argStack
.pop_uint ();
352 SUPER::process_op (op
, env
);
353 if (!env
.argStack
.is_empty ()) return;
357 if (unlikely (env
.in_error ())) return;
359 dictval
.add_op (op
, env
.str_ref
);
363 typedef dict_opset_t SUPER
;
366 typedef dict_interpreter_t
<cff2_top_dict_opset_t
, cff2_top_dict_values_t
> cff2_top_dict_interpreter_t
;
367 typedef dict_interpreter_t
<cff2_font_dict_opset_t
, cff2_font_dict_values_t
> cff2_font_dict_interpreter_t
;
369 struct CFF2FDArray
: FDArray
<HBUINT32
>
371 /* FDArray::serialize does not compile without this partial specialization */
372 template <typename ITER
, typename OP_SERIALIZER
>
373 bool serialize (hb_serialize_context_t
*c
, ITER it
, OP_SERIALIZER
& opszr
)
374 { return FDArray
<HBUINT32
>::serialize
<cff2_font_dict_values_t
, table_info_t
> (c
, it
, opszr
); }
377 } /* namespace CFF */
385 static constexpr hb_tag_t tableTag
= HB_OT_TAG_CFF2
;
387 bool sanitize (hb_sanitize_context_t
*c
) const
389 TRACE_SANITIZE (this);
390 return_trace (c
->check_struct (this) &&
392 likely (version
.major
== 2));
395 template <typename PRIVOPSET
, typename PRIVDICTVAL
>
396 struct accelerator_templ_t
398 static constexpr hb_tag_t tableTag
= cff2::tableTag
;
400 accelerator_templ_t (hb_face_t
*face
)
406 privateDicts
.init ();
408 this->blob
= sc
.reference_table
<cff2
> (face
);
410 /* setup for run-time santization */
411 sc
.init (this->blob
);
412 sc
.start_processing ();
414 const OT::cff2
*cff2
= this->blob
->template as
<OT::cff2
> ();
416 if (cff2
== &Null (OT::cff2
))
419 { /* parse top dict */
420 hb_ubytes_t topDictStr
= (cff2
+ cff2
->topDict
).as_ubytes (cff2
->topDictSize
);
421 if (unlikely (!topDictStr
.sanitize (&sc
))) goto fail
;
423 num_interp_env_t
env (topDictStr
);
424 cff2_top_dict_interpreter_t
top_interp (env
);
426 if (unlikely (!top_interp
.interpret (topDict
))) goto fail
;
429 globalSubrs
= &StructAtOffset
<CFF2Subrs
> (cff2
, cff2
->topDict
+ cff2
->topDictSize
);
430 varStore
= &StructAtOffsetOrNull
<CFF2VariationStore
> (cff2
, topDict
.vstoreOffset
);
431 charStrings
= &StructAtOffsetOrNull
<CFF2CharStrings
> (cff2
, topDict
.charStringsOffset
);
432 fdArray
= &StructAtOffsetOrNull
<CFF2FDArray
> (cff2
, topDict
.FDArrayOffset
);
433 fdSelect
= &StructAtOffsetOrNull
<CFF2FDSelect
> (cff2
, topDict
.FDSelectOffset
);
435 if (((varStore
!= &Null (CFF2VariationStore
)) && unlikely (!varStore
->sanitize (&sc
))) ||
436 (charStrings
== &Null (CFF2CharStrings
)) || unlikely (!charStrings
->sanitize (&sc
)) ||
437 (globalSubrs
== &Null (CFF2Subrs
)) || unlikely (!globalSubrs
->sanitize (&sc
)) ||
438 (fdArray
== &Null (CFF2FDArray
)) || unlikely (!fdArray
->sanitize (&sc
)) ||
440 (((fdSelect
!= &Null (CFF2FDSelect
)) && unlikely (!fdSelect
->sanitize (&sc
, fdArray
->count
)))))
443 num_glyphs
= charStrings
->count
;
444 if (num_glyphs
!= sc
.get_num_glyphs ())
447 fdCount
= fdArray
->count
;
448 if (!privateDicts
.resize (fdCount
))
451 /* parse font dicts and gather private dicts */
452 for (unsigned int i
= 0; i
< fdCount
; i
++)
454 const hb_ubytes_t fontDictStr
= (*fdArray
)[i
];
455 if (unlikely (!fontDictStr
.sanitize (&sc
))) goto fail
;
457 cff2_font_dict_values_t
*font
;
458 num_interp_env_t
env (fontDictStr
);
459 cff2_font_dict_interpreter_t
font_interp (env
);
460 font
= fontDicts
.push ();
461 if (unlikely (font
== &Crap (cff2_font_dict_values_t
))) goto fail
;
463 if (unlikely (!font_interp
.interpret (*font
))) goto fail
;
465 const hb_ubytes_t privDictStr
= StructAtOffsetOrNull
<UnsizedByteStr
> (cff2
, font
->privateDictInfo
.offset
).as_ubytes (font
->privateDictInfo
.size
);
466 if (unlikely (!privDictStr
.sanitize (&sc
))) goto fail
;
468 cff2_priv_dict_interp_env_t
env2 (privDictStr
);
469 dict_interpreter_t
<PRIVOPSET
, PRIVDICTVAL
, cff2_priv_dict_interp_env_t
> priv_interp (env2
);
470 privateDicts
[i
].init ();
471 if (unlikely (!priv_interp
.interpret (privateDicts
[i
]))) goto fail
;
473 privateDicts
[i
].localSubrs
= &StructAtOffsetOrNull
<CFF2Subrs
> (&privDictStr
[0], privateDicts
[i
].subrsOffset
);
474 if (privateDicts
[i
].localSubrs
!= &Null (CFF2Subrs
) &&
475 unlikely (!privateDicts
[i
].localSubrs
->sanitize (&sc
)))
485 ~accelerator_templ_t () { _fini (); }
488 sc
.end_processing ();
491 privateDicts
.fini ();
492 hb_blob_destroy (blob
);
496 hb_vector_t
<uint16_t> *create_glyph_to_sid_map () const
501 hb_blob_t
*get_blob () const { return blob
; }
503 bool is_valid () const { return blob
; }
506 hb_sanitize_context_t sc
;
509 hb_blob_t
*blob
= nullptr;
510 cff2_top_dict_values_t topDict
;
511 const CFF2Subrs
*globalSubrs
= nullptr;
512 const CFF2VariationStore
*varStore
= nullptr;
513 const CFF2CharStrings
*charStrings
= nullptr;
514 const CFF2FDArray
*fdArray
= nullptr;
515 const CFF2FDSelect
*fdSelect
= nullptr;
516 unsigned int fdCount
= 0;
518 hb_vector_t
<cff2_font_dict_values_t
> fontDicts
;
519 hb_vector_t
<PRIVDICTVAL
> privateDicts
;
521 unsigned int num_glyphs
= 0;
524 struct accelerator_t
: accelerator_templ_t
<cff2_private_dict_opset_t
, cff2_private_dict_values_t
>
526 accelerator_t (hb_face_t
*face
) : accelerator_templ_t (face
) {}
528 HB_INTERNAL
bool get_extents (hb_font_t
*font
,
529 hb_codepoint_t glyph
,
530 hb_glyph_extents_t
*extents
) const;
531 HB_INTERNAL
bool paint_glyph (hb_font_t
*font
, hb_codepoint_t glyph
, hb_paint_funcs_t
*funcs
, void *data
, hb_color_t foreground
) const;
532 HB_INTERNAL
bool get_path (hb_font_t
*font
, hb_codepoint_t glyph
, hb_draw_session_t
&draw_session
) const;
535 struct accelerator_subset_t
: accelerator_templ_t
<cff2_private_dict_opset_subset_t
, cff2_private_dict_values_subset_t
>
537 accelerator_subset_t (hb_face_t
*face
) : SUPER (face
) {}
538 ~accelerator_subset_t ()
541 cff_subset_accelerator_t::destroy (cff_accelerator
);
544 HB_INTERNAL
bool subset (hb_subset_context_t
*c
) const;
545 HB_INTERNAL
bool serialize (hb_serialize_context_t
*c
,
546 struct cff2_subset_plan
&plan
,
547 hb_array_t
<int> normalized_coords
) const;
549 mutable CFF::cff_subset_accelerator_t
* cff_accelerator
= nullptr;
551 typedef accelerator_templ_t
<cff2_private_dict_opset_subset_t
, cff2_private_dict_values_subset_t
> SUPER
;
555 FixedVersion
<HBUINT8
> version
; /* Version of CFF2 table. set to 0x0200u */
556 NNOffsetTo
<TopDict
, HBUINT8
> topDict
; /* headerSize = Offset to Top DICT. */
557 HBUINT16 topDictSize
; /* Top DICT size */
560 DEFINE_SIZE_STATIC (5);
563 struct cff2_accelerator_t
: cff2::accelerator_t
{
564 cff2_accelerator_t (hb_face_t
*face
) : cff2::accelerator_t (face
) {}
567 struct cff2_subset_accelerator_t
: cff2::accelerator_subset_t
{
568 cff2_subset_accelerator_t (hb_face_t
*face
) : cff2::accelerator_subset_t (face
) {}
573 #endif /* HB_OT_CFF2_TABLE_HH */