/src/harfbuzz/src/hb-cff-interp-dict-common.hh
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2018 Adobe Inc. |
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 | | #ifndef HB_CFF_INTERP_DICT_COMMON_HH |
27 | | #define HB_CFF_INTERP_DICT_COMMON_HH |
28 | | |
29 | | #include "hb-cff-interp-common.hh" |
30 | | |
31 | | namespace CFF { |
32 | | |
33 | | using namespace OT; |
34 | | |
35 | | /* an opstr and the parsed out dict value(s) */ |
36 | | struct dict_val_t : op_str_t |
37 | | { |
38 | 3.41M | void init () { single_val.set_int (0); } |
39 | 0 | void fini () {} |
40 | | |
41 | | number_t single_val; |
42 | | }; |
43 | | |
44 | | typedef dict_val_t num_dict_val_t; |
45 | | |
46 | | template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {}; |
47 | | |
48 | | template <typename OPSTR=op_str_t> |
49 | | struct top_dict_values_t : dict_values_t<OPSTR> |
50 | | { |
51 | | void init () |
52 | 1.19M | { |
53 | 1.19M | dict_values_t<OPSTR>::init (); |
54 | 1.19M | charStringsOffset = 0; |
55 | 1.19M | FDArrayOffset = 0; |
56 | 1.19M | } CFF::top_dict_values_t<CFF::cff1_top_dict_val_t>::init() Line | Count | Source | 52 | 607k | { | 53 | 607k | dict_values_t<OPSTR>::init (); | 54 | 607k | charStringsOffset = 0; | 55 | 607k | FDArrayOffset = 0; | 56 | 607k | } |
CFF::top_dict_values_t<CFF::op_str_t>::init() Line | Count | Source | 52 | 586k | { | 53 | 586k | dict_values_t<OPSTR>::init (); | 54 | 586k | charStringsOffset = 0; | 55 | 586k | FDArrayOffset = 0; | 56 | 586k | } |
|
57 | 2.20M | void fini () { dict_values_t<OPSTR>::fini (); }CFF::top_dict_values_t<CFF::cff1_top_dict_val_t>::fini() Line | Count | Source | 57 | 1.12M | void fini () { dict_values_t<OPSTR>::fini (); } |
CFF::top_dict_values_t<CFF::op_str_t>::fini() Line | Count | Source | 57 | 1.07M | void fini () { dict_values_t<OPSTR>::fini (); } |
|
58 | | |
59 | | unsigned int charStringsOffset; |
60 | | unsigned int FDArrayOffset; |
61 | | }; |
62 | | |
63 | | struct dict_opset_t : opset_t<number_t> |
64 | | { |
65 | | static void process_op (op_code_t op, interp_env_t<number_t>& env) |
66 | 4.39M | { |
67 | 4.39M | switch (op) { |
68 | 189k | case OpCode_longintdict: /* 5-byte integer */ |
69 | 189k | env.argStack.push_longint_from_substr (env.str_ref); |
70 | 189k | break; |
71 | | |
72 | 55.3k | case OpCode_BCD: /* real number */ |
73 | 55.3k | env.argStack.push_real (parse_bcd (env.str_ref)); |
74 | 55.3k | break; |
75 | | |
76 | 4.15M | default: |
77 | 4.15M | opset_t<number_t>::process_op (op, env); |
78 | 4.15M | break; |
79 | 4.39M | } |
80 | 4.39M | } |
81 | | |
82 | | /* Turns CFF's BCD format into strtod understandable string */ |
83 | | static double parse_bcd (byte_str_ref_t& str_ref) |
84 | 55.3k | { |
85 | 55.3k | if (unlikely (str_ref.in_error ())) return .0; |
86 | | |
87 | 55.3k | enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; |
88 | | |
89 | 55.3k | char buf[32]; |
90 | 55.3k | unsigned char byte = 0; |
91 | 450k | for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count) |
92 | 450k | { |
93 | 450k | unsigned nibble; |
94 | 450k | if (!(i & 1)) |
95 | 235k | { |
96 | 235k | if (unlikely (!str_ref.avail ())) break; |
97 | | |
98 | 235k | byte = str_ref[0]; |
99 | 235k | str_ref.inc (); |
100 | 235k | nibble = byte >> 4; |
101 | 235k | } |
102 | 215k | else |
103 | 215k | nibble = byte & 0x0F; |
104 | | |
105 | 450k | if (unlikely (nibble == RESERVED)) break; |
106 | 450k | else if (nibble == END) |
107 | 54.9k | { |
108 | 54.9k | const char *p = buf; |
109 | 54.9k | double pv; |
110 | 54.9k | if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */))) |
111 | 438 | break; |
112 | 54.5k | return pv; |
113 | 54.9k | } |
114 | 395k | else |
115 | 395k | { |
116 | 395k | buf[count] = "0123456789.EE?-?"[nibble]; |
117 | 395k | if (nibble == EXP_NEG) |
118 | 1.75k | { |
119 | 1.75k | ++count; |
120 | 1.75k | if (unlikely (count == ARRAY_LENGTH (buf))) break; |
121 | 1.73k | buf[count] = '-'; |
122 | 1.73k | } |
123 | 395k | } |
124 | 450k | } |
125 | | |
126 | 794 | str_ref.set_error (); |
127 | 794 | return .0; |
128 | 55.3k | } |
129 | | |
130 | | static bool is_hint_op (op_code_t op) |
131 | 0 | { |
132 | 0 | switch (op) |
133 | 0 | { |
134 | 0 | case OpCode_BlueValues: |
135 | 0 | case OpCode_OtherBlues: |
136 | 0 | case OpCode_FamilyBlues: |
137 | 0 | case OpCode_FamilyOtherBlues: |
138 | 0 | case OpCode_StemSnapH: |
139 | 0 | case OpCode_StemSnapV: |
140 | 0 | case OpCode_StdHW: |
141 | 0 | case OpCode_StdVW: |
142 | 0 | case OpCode_BlueScale: |
143 | 0 | case OpCode_BlueShift: |
144 | 0 | case OpCode_BlueFuzz: |
145 | 0 | case OpCode_ForceBold: |
146 | 0 | case OpCode_LanguageGroup: |
147 | 0 | case OpCode_ExpansionFactor: |
148 | 0 | return true; |
149 | 0 | default: |
150 | 0 | return false; |
151 | 0 | } |
152 | 0 | } |
153 | | }; |
154 | | |
155 | | template <typename VAL=op_str_t> |
156 | | struct top_dict_opset_t : dict_opset_t |
157 | | { |
158 | | static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval) |
159 | 762k | { |
160 | 762k | switch (op) { |
161 | 49.8k | case OpCode_CharStrings: |
162 | 49.8k | dictval.charStringsOffset = env.argStack.pop_uint (); |
163 | 49.8k | env.clear_args (); |
164 | 49.8k | break; |
165 | 23.7k | case OpCode_FDArray: |
166 | 23.7k | dictval.FDArrayOffset = env.argStack.pop_uint (); |
167 | 23.7k | env.clear_args (); |
168 | 23.7k | break; |
169 | 13.9k | case OpCode_FontMatrix: |
170 | 13.9k | env.clear_args (); |
171 | 13.9k | break; |
172 | 674k | default: |
173 | 674k | dict_opset_t::process_op (op, env); |
174 | 674k | break; |
175 | 762k | } |
176 | 762k | } CFF::top_dict_opset_t<CFF::cff1_top_dict_val_t>::process_op(unsigned int, CFF::interp_env_t<CFF::number_t>&, CFF::top_dict_values_t<CFF::cff1_top_dict_val_t>&) Line | Count | Source | 159 | 610k | { | 160 | 610k | switch (op) { | 161 | 29.3k | case OpCode_CharStrings: | 162 | 29.3k | dictval.charStringsOffset = env.argStack.pop_uint (); | 163 | 29.3k | env.clear_args (); | 164 | 29.3k | break; | 165 | 3.81k | case OpCode_FDArray: | 166 | 3.81k | dictval.FDArrayOffset = env.argStack.pop_uint (); | 167 | 3.81k | env.clear_args (); | 168 | 3.81k | break; | 169 | 13.9k | case OpCode_FontMatrix: | 170 | 13.9k | env.clear_args (); | 171 | 13.9k | break; | 172 | 563k | default: | 173 | 563k | dict_opset_t::process_op (op, env); | 174 | 563k | break; | 175 | 610k | } | 176 | 610k | } |
CFF::top_dict_opset_t<CFF::op_str_t>::process_op(unsigned int, CFF::interp_env_t<CFF::number_t>&, CFF::top_dict_values_t<CFF::op_str_t>&) Line | Count | Source | 159 | 151k | { | 160 | 151k | switch (op) { | 161 | 20.5k | case OpCode_CharStrings: | 162 | 20.5k | dictval.charStringsOffset = env.argStack.pop_uint (); | 163 | 20.5k | env.clear_args (); | 164 | 20.5k | break; | 165 | 19.9k | case OpCode_FDArray: | 166 | 19.9k | dictval.FDArrayOffset = env.argStack.pop_uint (); | 167 | 19.9k | env.clear_args (); | 168 | 19.9k | break; | 169 | 0 | case OpCode_FontMatrix: | 170 | 0 | env.clear_args (); | 171 | 0 | break; | 172 | 111k | default: | 173 | 111k | dict_opset_t::process_op (op, env); | 174 | 111k | break; | 175 | 151k | } | 176 | 151k | } |
|
177 | | }; |
178 | | |
179 | | template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t> |
180 | | struct dict_interpreter_t : interpreter_t<ENV> |
181 | | { |
182 | 1.52M | dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {}CFF::dict_interpreter_t<CFF::cff1_top_dict_opset_t, CFF::cff1_top_dict_values_t, CFF::cff1_top_dict_interp_env_t>::dict_interpreter_t(CFF::cff1_top_dict_interp_env_t&) Line | Count | Source | 182 | 32.6k | dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} |
CFF::dict_interpreter_t<CFF::cff1_font_dict_opset_t, CFF::cff1_font_dict_values_t, CFF::interp_env_t<CFF::number_t> >::dict_interpreter_t(CFF::interp_env_t<CFF::number_t>&) Line | Count | Source | 182 | 462k | dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} |
CFF::dict_interpreter_t<CFF::cff1_private_dict_opset_t, CFF::cff1_private_dict_values_base_t<CFF::dict_val_t>, CFF::interp_env_t<CFF::number_t> >::dict_interpreter_t(CFF::interp_env_t<CFF::number_t>&) Line | Count | Source | 182 | 485k | dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} |
CFF::dict_interpreter_t<CFF::cff2_top_dict_opset_t, CFF::cff2_top_dict_values_t, CFF::interp_env_t<CFF::number_t> >::dict_interpreter_t(CFF::interp_env_t<CFF::number_t>&) Line | Count | Source | 182 | 20.5k | dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} |
CFF::dict_interpreter_t<CFF::cff2_font_dict_opset_t, CFF::cff2_font_dict_values_t, CFF::interp_env_t<CFF::number_t> >::dict_interpreter_t(CFF::interp_env_t<CFF::number_t>&) Line | Count | Source | 182 | 262k | dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} |
CFF::dict_interpreter_t<CFF::cff2_private_dict_opset_t, CFF::cff2_private_dict_values_base_t<CFF::dict_val_t>, CFF::cff2_priv_dict_interp_env_t>::dict_interpreter_t(CFF::cff2_priv_dict_interp_env_t&) Line | Count | Source | 182 | 261k | dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} |
|
183 | | |
184 | | bool interpret (PARAM& param) |
185 | 1.52M | { |
186 | 1.52M | param.init (); |
187 | 7.42M | while (SUPER::env.str_ref.avail ()) |
188 | 5.90M | { |
189 | 5.90M | OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); |
190 | 5.90M | if (unlikely (SUPER::env.in_error ())) |
191 | 6.13k | return false; |
192 | 5.90M | } |
193 | | |
194 | 1.51M | return true; |
195 | 1.52M | } CFF::dict_interpreter_t<CFF::cff1_top_dict_opset_t, CFF::cff1_top_dict_values_t, CFF::cff1_top_dict_interp_env_t>::interpret(CFF::cff1_top_dict_values_t&) Line | Count | Source | 185 | 32.6k | { | 186 | 32.6k | param.init (); | 187 | 914k | while (SUPER::env.str_ref.avail ()) | 188 | 885k | { | 189 | 885k | OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); | 190 | 885k | if (unlikely (SUPER::env.in_error ())) | 191 | 3.16k | return false; | 192 | 885k | } | 193 | | | 194 | 29.4k | return true; | 195 | 32.6k | } |
CFF::dict_interpreter_t<CFF::cff1_font_dict_opset_t, CFF::cff1_font_dict_values_t, CFF::interp_env_t<CFF::number_t> >::interpret(CFF::cff1_font_dict_values_t&) Line | Count | Source | 185 | 462k | { | 186 | 462k | param.init (); | 187 | 1.40M | while (SUPER::env.str_ref.avail ()) | 188 | 943k | { | 189 | 943k | OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); | 190 | 943k | if (unlikely (SUPER::env.in_error ())) | 191 | 284 | return false; | 192 | 943k | } | 193 | | | 194 | 462k | return true; | 195 | 462k | } |
CFF::dict_interpreter_t<CFF::cff1_private_dict_opset_t, CFF::cff1_private_dict_values_base_t<CFF::dict_val_t>, CFF::interp_env_t<CFF::number_t> >::interpret(CFF::cff1_private_dict_values_base_t<CFF::dict_val_t>&) Line | Count | Source | 185 | 485k | { | 186 | 485k | param.init (); | 187 | 3.13M | while (SUPER::env.str_ref.avail ()) | 188 | 2.65M | { | 189 | 2.65M | OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); | 190 | 2.65M | if (unlikely (SUPER::env.in_error ())) | 191 | 693 | return false; | 192 | 2.65M | } | 193 | | | 194 | 484k | return true; | 195 | 485k | } |
CFF::dict_interpreter_t<CFF::cff2_top_dict_opset_t, CFF::cff2_top_dict_values_t, CFF::interp_env_t<CFF::number_t> >::interpret(CFF::cff2_top_dict_values_t&) Line | Count | Source | 185 | 20.5k | { | 186 | 20.5k | param.init (); | 187 | 188k | while (SUPER::env.str_ref.avail ()) | 188 | 169k | { | 189 | 169k | OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); | 190 | 169k | if (unlikely (SUPER::env.in_error ())) | 191 | 1.04k | return false; | 192 | 169k | } | 193 | | | 194 | 19.5k | return true; | 195 | 20.5k | } |
CFF::dict_interpreter_t<CFF::cff2_font_dict_opset_t, CFF::cff2_font_dict_values_t, CFF::interp_env_t<CFF::number_t> >::interpret(CFF::cff2_font_dict_values_t&) Line | Count | Source | 185 | 262k | { | 186 | 262k | param.init (); | 187 | 762k | while (SUPER::env.str_ref.avail ()) | 188 | 500k | { | 189 | 500k | OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); | 190 | 500k | if (unlikely (SUPER::env.in_error ())) | 191 | 554 | return false; | 192 | 500k | } | 193 | | | 194 | 261k | return true; | 195 | 262k | } |
CFF::dict_interpreter_t<CFF::cff2_private_dict_opset_t, CFF::cff2_private_dict_values_base_t<CFF::dict_val_t>, CFF::cff2_priv_dict_interp_env_t>::interpret(CFF::cff2_private_dict_values_base_t<CFF::dict_val_t>&) Line | Count | Source | 185 | 261k | { | 186 | 261k | param.init (); | 187 | 1.01M | while (SUPER::env.str_ref.avail ()) | 188 | 753k | { | 189 | 753k | OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); | 190 | 753k | if (unlikely (SUPER::env.in_error ())) | 191 | 386 | return false; | 192 | 753k | } | 193 | | | 194 | 261k | return true; | 195 | 261k | } |
|
196 | | |
197 | | private: |
198 | | typedef interpreter_t<ENV> SUPER; |
199 | | }; |
200 | | |
201 | | } /* namespace CFF */ |
202 | | |
203 | | #endif /* HB_CFF_INTERP_DICT_COMMON_HH */ |