Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: third_party/ots/src/cff_type2_charstring.cc

Issue 775893002: Updating OTS repo from https://github.com/khaledhosny/ots.git (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updating with 4800 warning fix Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/ots/src/cff_type2_charstring.h ('k') | third_party/ots/src/cmap.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // A parser for the Type 2 Charstring Format.
6 // http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
7
8 #include "cff_type2_charstring.h"
9
10 #include <climits>
11 #include <cstdio>
12 #include <cstring>
13 #include <stack>
14 #include <string>
15 #include <utility>
16
17 #define TABLE_NAME "CFF"
18
19 namespace {
20
21 // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
22 // Note #5177.
23 const int32_t kMaxSubrsCount = 65536;
24 const size_t kMaxCharStringLength = 65535;
25 const size_t kMaxArgumentStack = 48;
26 const size_t kMaxNumberOfStemHints = 96;
27 const size_t kMaxSubrNesting = 10;
28
29 // |dummy_result| should be a huge positive integer so callsubr and callgsubr
30 // will fail with the dummy value.
31 const int32_t dummy_result = INT_MAX;
32
33 bool ExecuteType2CharString(ots::OpenTypeFile *file,
34 size_t call_depth,
35 const ots::CFFIndex& global_subrs_index,
36 const ots::CFFIndex& local_subrs_index,
37 ots::Buffer *cff_table,
38 ots::Buffer *char_string,
39 std::stack<int32_t> *argument_stack,
40 bool *out_found_endchar,
41 bool *out_found_width,
42 size_t *in_out_num_stems);
43
44 #ifdef DUMP_T2CHARSTRING
45 // Converts |op| to a string and returns it.
46 const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) {
47 switch (op) {
48 case ots::kHStem:
49 return "HStem";
50 case ots::kVStem:
51 return "VStem";
52 case ots::kVMoveTo:
53 return "VMoveTo";
54 case ots::kRLineTo:
55 return "RLineTo";
56 case ots::kHLineTo:
57 return "HLineTo";
58 case ots::kVLineTo:
59 return "VLineTo";
60 case ots::kRRCurveTo:
61 return "RRCurveTo";
62 case ots::kCallSubr:
63 return "CallSubr";
64 case ots::kReturn:
65 return "Return";
66 case ots::kEndChar:
67 return "EndChar";
68 case ots::kHStemHm:
69 return "HStemHm";
70 case ots::kHintMask:
71 return "HintMask";
72 case ots::kCntrMask:
73 return "CntrMask";
74 case ots::kRMoveTo:
75 return "RMoveTo";
76 case ots::kHMoveTo:
77 return "HMoveTo";
78 case ots::kVStemHm:
79 return "VStemHm";
80 case ots::kRCurveLine:
81 return "RCurveLine";
82 case ots::kRLineCurve:
83 return "RLineCurve";
84 case ots::kVVCurveTo:
85 return "VVCurveTo";
86 case ots::kHHCurveTo:
87 return "HHCurveTo";
88 case ots::kCallGSubr:
89 return "CallGSubr";
90 case ots::kVHCurveTo:
91 return "VHCurveTo";
92 case ots::kHVCurveTo:
93 return "HVCurveTo";
94 case ots::kDotSection:
95 return "DotSection";
96 case ots::kAnd:
97 return "And";
98 case ots::kOr:
99 return "Or";
100 case ots::kNot:
101 return "Not";
102 case ots::kAbs:
103 return "Abs";
104 case ots::kAdd:
105 return "Add";
106 case ots::kSub:
107 return "Sub";
108 case ots::kDiv:
109 return "Div";
110 case ots::kNeg:
111 return "Neg";
112 case ots::kEq:
113 return "Eq";
114 case ots::kDrop:
115 return "Drop";
116 case ots::kPut:
117 return "Put";
118 case ots::kGet:
119 return "Get";
120 case ots::kIfElse:
121 return "IfElse";
122 case ots::kRandom:
123 return "Random";
124 case ots::kMul:
125 return "Mul";
126 case ots::kSqrt:
127 return "Sqrt";
128 case ots::kDup:
129 return "Dup";
130 case ots::kExch:
131 return "Exch";
132 case ots::kIndex:
133 return "Index";
134 case ots::kRoll:
135 return "Roll";
136 case ots::kHFlex:
137 return "HFlex";
138 case ots::kFlex:
139 return "Flex";
140 case ots::kHFlex1:
141 return "HFlex1";
142 case ots::kFlex1:
143 return "Flex1";
144 }
145
146 return "UNKNOWN";
147 }
148 #endif
149
150 // Read one or more bytes from the |char_string| buffer and stores the number
151 // read on |out_number|. If the number read is an operator (ex 'vstem'), sets
152 // true on |out_is_operator|. Returns true if the function read a number.
153 bool ReadNextNumberFromType2CharString(ots::Buffer *char_string,
154 int32_t *out_number,
155 bool *out_is_operator) {
156 uint8_t v = 0;
157 if (!char_string->ReadU8(&v)) {
158 return OTS_FAILURE();
159 }
160 *out_is_operator = false;
161
162 // The conversion algorithm is described in Adobe Technical Note #5177, page
163 // 13, Table 1.
164 if (v <= 11) {
165 *out_number = v;
166 *out_is_operator = true;
167 } else if (v == 12) {
168 uint16_t result = (v << 8);
169 if (!char_string->ReadU8(&v)) {
170 return OTS_FAILURE();
171 }
172 result += v;
173 *out_number = result;
174 *out_is_operator = true;
175 } else if (v <= 27) {
176 // Special handling for v==19 and v==20 are implemented in
177 // ExecuteType2CharStringOperator().
178 *out_number = v;
179 *out_is_operator = true;
180 } else if (v == 28) {
181 if (!char_string->ReadU8(&v)) {
182 return OTS_FAILURE();
183 }
184 uint16_t result = (v << 8);
185 if (!char_string->ReadU8(&v)) {
186 return OTS_FAILURE();
187 }
188 result += v;
189 *out_number = result;
190 } else if (v <= 31) {
191 *out_number = v;
192 *out_is_operator = true;
193 } else if (v <= 246) {
194 *out_number = static_cast<int32_t>(v) - 139;
195 } else if (v <= 250) {
196 uint8_t w = 0;
197 if (!char_string->ReadU8(&w)) {
198 return OTS_FAILURE();
199 }
200 *out_number = ((static_cast<int32_t>(v) - 247) * 256) +
201 static_cast<int32_t>(w) + 108;
202 } else if (v <= 254) {
203 uint8_t w = 0;
204 if (!char_string->ReadU8(&w)) {
205 return OTS_FAILURE();
206 }
207 *out_number = -((static_cast<int32_t>(v) - 251) * 256) -
208 static_cast<int32_t>(w) - 108;
209 } else if (v == 255) {
210 // TODO(yusukes): We should not skip the 4 bytes. Note that when v is 255,
211 // we should treat the following 4-bytes as a 16.16 fixed-point number
212 // rather than 32bit signed int.
213 if (!char_string->Skip(4)) {
214 return OTS_FAILURE();
215 }
216 *out_number = dummy_result;
217 } else {
218 return OTS_FAILURE();
219 }
220
221 return true;
222 }
223
224 // Executes |op| and updates |argument_stack|. Returns true if the execution
225 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
226 // calls ExecuteType2CharString() function. The arguments other than |op| and
227 // |argument_stack| are passed for that reason.
228 bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
229 int32_t op,
230 size_t call_depth,
231 const ots::CFFIndex& global_subrs_index,
232 const ots::CFFIndex& local_subrs_index,
233 ots::Buffer *cff_table,
234 ots::Buffer *char_string,
235 std::stack<int32_t> *argument_stack,
236 bool *out_found_endchar,
237 bool *in_out_found_width,
238 size_t *in_out_num_stems) {
239 const size_t stack_size = argument_stack->size();
240
241 switch (op) {
242 case ots::kCallSubr:
243 case ots::kCallGSubr: {
244 const ots::CFFIndex& subrs_index =
245 (op == ots::kCallSubr ? local_subrs_index : global_subrs_index);
246
247 if (stack_size < 1) {
248 return OTS_FAILURE();
249 }
250 int32_t subr_number = argument_stack->top();
251 argument_stack->pop();
252 if (subr_number == dummy_result) {
253 // For safety, we allow subr calls only with immediate subr numbers for
254 // now. For example, we allow "123 callgsubr", but does not allow "100 12
255 // add callgsubr". Please note that arithmetic and conditional operators
256 // always push the |dummy_result| in this implementation.
257 return OTS_FAILURE();
258 }
259
260 // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes."
261 int32_t bias = 32768;
262 if (subrs_index.count < 1240) {
263 bias = 107;
264 } else if (subrs_index.count < 33900) {
265 bias = 1131;
266 }
267 subr_number += bias;
268
269 // Sanity checks of |subr_number|.
270 if (subr_number < 0) {
271 return OTS_FAILURE();
272 }
273 if (subr_number >= kMaxSubrsCount) {
274 return OTS_FAILURE();
275 }
276 if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) {
277 return OTS_FAILURE(); // The number is out-of-bounds.
278 }
279
280 // Prepare ots::Buffer where we're going to jump.
281 const size_t length =
282 subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number];
283 if (length > kMaxCharStringLength) {
284 return OTS_FAILURE();
285 }
286 const size_t offset = subrs_index.offsets[subr_number];
287 cff_table->set_offset(offset);
288 if (!cff_table->Skip(length)) {
289 return OTS_FAILURE();
290 }
291 ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
292
293 return ExecuteType2CharString(file,
294 call_depth + 1,
295 global_subrs_index,
296 local_subrs_index,
297 cff_table,
298 &char_string_to_jump,
299 argument_stack,
300 out_found_endchar,
301 in_out_found_width,
302 in_out_num_stems);
303 }
304
305 case ots::kReturn:
306 return true;
307
308 case ots::kEndChar:
309 *out_found_endchar = true;
310 *in_out_found_width = true; // just in case.
311 return true;
312
313 case ots::kHStem:
314 case ots::kVStem:
315 case ots::kHStemHm:
316 case ots::kVStemHm: {
317 bool successful = false;
318 if (stack_size < 2) {
319 return OTS_FAILURE();
320 }
321 if ((stack_size % 2) == 0) {
322 successful = true;
323 } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) {
324 // The -1 is for "width" argument. For details, see Adobe Technical Note
325 // #5177, page 16, note 4.
326 successful = true;
327 }
328 (*in_out_num_stems) += (stack_size / 2);
329 if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
330 return OTS_FAILURE();
331 }
332 while (!argument_stack->empty())
333 argument_stack->pop();
334 *in_out_found_width = true; // always set true since "w" might be 0 byte.
335 return successful ? true : OTS_FAILURE();
336 }
337
338 case ots::kRMoveTo: {
339 bool successful = false;
340 if (stack_size == 2) {
341 successful = true;
342 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) {
343 successful = true;
344 }
345 while (!argument_stack->empty())
346 argument_stack->pop();
347 *in_out_found_width = true;
348 return successful ? true : OTS_FAILURE();
349 }
350
351 case ots::kVMoveTo:
352 case ots::kHMoveTo: {
353 bool successful = false;
354 if (stack_size == 1) {
355 successful = true;
356 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) {
357 successful = true;
358 }
359 while (!argument_stack->empty())
360 argument_stack->pop();
361 *in_out_found_width = true;
362 return successful ? true : OTS_FAILURE();
363 }
364
365 case ots::kHintMask:
366 case ots::kCntrMask: {
367 bool successful = false;
368 if (stack_size == 0) {
369 successful = true;
370 } else if ((!(*in_out_found_width)) && (stack_size == 1)) {
371 // A number for "width" is found.
372 successful = true;
373 } else if ((!(*in_out_found_width)) || // in this case, any sizes are ok.
374 ((stack_size % 2) == 0)) {
375 // The numbers are vstem definition.
376 // See Adobe Technical Note #5177, page 24, hintmask.
377 (*in_out_num_stems) += (stack_size / 2);
378 if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
379 return OTS_FAILURE();
380 }
381 successful = true;
382 }
383 if (!successful) {
384 return OTS_FAILURE();
385 }
386
387 if ((*in_out_num_stems) == 0) {
388 return OTS_FAILURE();
389 }
390 const size_t mask_bytes = (*in_out_num_stems + 7) / 8;
391 if (!char_string->Skip(mask_bytes)) {
392 return OTS_FAILURE();
393 }
394 while (!argument_stack->empty())
395 argument_stack->pop();
396 *in_out_found_width = true;
397 return true;
398 }
399
400 case ots::kRLineTo:
401 if (!(*in_out_found_width)) {
402 // The first stack-clearing operator should be one of hstem, hstemhm,
403 // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or
404 // endchar. For details, see Adobe Technical Note #5177, page 16, note 4.
405 return OTS_FAILURE();
406 }
407 if (stack_size < 2) {
408 return OTS_FAILURE();
409 }
410 if ((stack_size % 2) != 0) {
411 return OTS_FAILURE();
412 }
413 while (!argument_stack->empty())
414 argument_stack->pop();
415 return true;
416
417 case ots::kHLineTo:
418 case ots::kVLineTo:
419 if (!(*in_out_found_width)) {
420 return OTS_FAILURE();
421 }
422 if (stack_size < 1) {
423 return OTS_FAILURE();
424 }
425 while (!argument_stack->empty())
426 argument_stack->pop();
427 return true;
428
429 case ots::kRRCurveTo:
430 if (!(*in_out_found_width)) {
431 return OTS_FAILURE();
432 }
433 if (stack_size < 6) {
434 return OTS_FAILURE();
435 }
436 if ((stack_size % 6) != 0) {
437 return OTS_FAILURE();
438 }
439 while (!argument_stack->empty())
440 argument_stack->pop();
441 return true;
442
443 case ots::kRCurveLine:
444 if (!(*in_out_found_width)) {
445 return OTS_FAILURE();
446 }
447 if (stack_size < 8) {
448 return OTS_FAILURE();
449 }
450 if (((stack_size - 2) % 6) != 0) {
451 return OTS_FAILURE();
452 }
453 while (!argument_stack->empty())
454 argument_stack->pop();
455 return true;
456
457 case ots::kRLineCurve:
458 if (!(*in_out_found_width)) {
459 return OTS_FAILURE();
460 }
461 if (stack_size < 8) {
462 return OTS_FAILURE();
463 }
464 if (((stack_size - 6) % 2) != 0) {
465 return OTS_FAILURE();
466 }
467 while (!argument_stack->empty())
468 argument_stack->pop();
469 return true;
470
471 case ots::kVVCurveTo:
472 if (!(*in_out_found_width)) {
473 return OTS_FAILURE();
474 }
475 if (stack_size < 4) {
476 return OTS_FAILURE();
477 }
478 if (((stack_size % 4) != 0) &&
479 (((stack_size - 1) % 4) != 0)) {
480 return OTS_FAILURE();
481 }
482 while (!argument_stack->empty())
483 argument_stack->pop();
484 return true;
485
486 case ots::kHHCurveTo: {
487 bool successful = false;
488 if (!(*in_out_found_width)) {
489 return OTS_FAILURE();
490 }
491 if (stack_size < 4) {
492 return OTS_FAILURE();
493 }
494 if ((stack_size % 4) == 0) {
495 // {dxa dxb dyb dxc}+
496 successful = true;
497 } else if (((stack_size - 1) % 4) == 0) {
498 // dy1? {dxa dxb dyb dxc}+
499 successful = true;
500 }
501 while (!argument_stack->empty())
502 argument_stack->pop();
503 return successful ? true : OTS_FAILURE();
504 }
505
506 case ots::kVHCurveTo:
507 case ots::kHVCurveTo: {
508 bool successful = false;
509 if (!(*in_out_found_width)) {
510 return OTS_FAILURE();
511 }
512 if (stack_size < 4) {
513 return OTS_FAILURE();
514 }
515 if (((stack_size - 4) % 8) == 0) {
516 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}*
517 successful = true;
518 } else if ((stack_size >= 5) &&
519 ((stack_size - 5) % 8) == 0) {
520 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf
521 successful = true;
522 } else if ((stack_size >= 8) &&
523 ((stack_size - 8) % 8) == 0) {
524 // {dxa dxb dyb dyc dyd dxe dye dxf}+
525 successful = true;
526 } else if ((stack_size >= 9) &&
527 ((stack_size - 9) % 8) == 0) {
528 // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
529 successful = true;
530 }
531 while (!argument_stack->empty())
532 argument_stack->pop();
533 return successful ? true : OTS_FAILURE();
534 }
535
536 case ots::kDotSection:
537 // Deprecated operator but harmless, we probably should drop it some how.
538 if (stack_size != 0) {
539 return OTS_FAILURE();
540 }
541 return true;
542
543 case ots::kAnd:
544 case ots::kOr:
545 case ots::kEq:
546 case ots::kAdd:
547 case ots::kSub:
548 if (stack_size < 2) {
549 return OTS_FAILURE();
550 }
551 argument_stack->pop();
552 argument_stack->pop();
553 argument_stack->push(dummy_result);
554 // TODO(yusukes): Implement this. We should push a real value for all
555 // arithmetic and conditional operations.
556 return true;
557
558 case ots::kNot:
559 case ots::kAbs:
560 case ots::kNeg:
561 if (stack_size < 1) {
562 return OTS_FAILURE();
563 }
564 argument_stack->pop();
565 argument_stack->push(dummy_result);
566 // TODO(yusukes): Implement this. We should push a real value for all
567 // arithmetic and conditional operations.
568 return true;
569
570 case ots::kDiv:
571 // TODO(yusukes): Should detect div-by-zero errors.
572 if (stack_size < 2) {
573 return OTS_FAILURE();
574 }
575 argument_stack->pop();
576 argument_stack->pop();
577 argument_stack->push(dummy_result);
578 // TODO(yusukes): Implement this. We should push a real value for all
579 // arithmetic and conditional operations.
580 return true;
581
582 case ots::kDrop:
583 if (stack_size < 1) {
584 return OTS_FAILURE();
585 }
586 argument_stack->pop();
587 return true;
588
589 case ots::kPut:
590 case ots::kGet:
591 case ots::kIndex:
592 // For now, just call OTS_FAILURE since there is no way to check whether the
593 // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType
594 // fonts I have (except malicious ones!) use the operators.
595 // TODO(yusukes): Implement them in a secure way.
596 return OTS_FAILURE();
597
598 case ots::kRoll:
599 // Likewise, just call OTS_FAILURE for kRoll since there is no way to check
600 // whether |N| is smaller than the current stack depth or not.
601 // TODO(yusukes): Implement them in a secure way.
602 return OTS_FAILURE();
603
604 case ots::kRandom:
605 // For now, we don't handle the 'random' operator since the operator makes
606 // it hard to analyze hinting code statically.
607 return OTS_FAILURE();
608
609 case ots::kIfElse:
610 if (stack_size < 4) {
611 return OTS_FAILURE();
612 }
613 argument_stack->pop();
614 argument_stack->pop();
615 argument_stack->pop();
616 argument_stack->pop();
617 argument_stack->push(dummy_result);
618 // TODO(yusukes): Implement this. We should push a real value for all
619 // arithmetic and conditional operations.
620 return true;
621
622 case ots::kMul:
623 // TODO(yusukes): Should detect overflows.
624 if (stack_size < 2) {
625 return OTS_FAILURE();
626 }
627 argument_stack->pop();
628 argument_stack->pop();
629 argument_stack->push(dummy_result);
630 // TODO(yusukes): Implement this. We should push a real value for all
631 // arithmetic and conditional operations.
632 return true;
633
634 case ots::kSqrt:
635 // TODO(yusukes): Should check if the argument is negative.
636 if (stack_size < 1) {
637 return OTS_FAILURE();
638 }
639 argument_stack->pop();
640 argument_stack->push(dummy_result);
641 // TODO(yusukes): Implement this. We should push a real value for all
642 // arithmetic and conditional operations.
643 return true;
644
645 case ots::kDup:
646 if (stack_size < 1) {
647 return OTS_FAILURE();
648 }
649 argument_stack->pop();
650 argument_stack->push(dummy_result);
651 argument_stack->push(dummy_result);
652 if (argument_stack->size() > kMaxArgumentStack) {
653 return OTS_FAILURE();
654 }
655 // TODO(yusukes): Implement this. We should push a real value for all
656 // arithmetic and conditional operations.
657 return true;
658
659 case ots::kExch:
660 if (stack_size < 2) {
661 return OTS_FAILURE();
662 }
663 argument_stack->pop();
664 argument_stack->pop();
665 argument_stack->push(dummy_result);
666 argument_stack->push(dummy_result);
667 // TODO(yusukes): Implement this. We should push a real value for all
668 // arithmetic and conditional operations.
669 return true;
670
671 case ots::kHFlex:
672 if (!(*in_out_found_width)) {
673 return OTS_FAILURE();
674 }
675 if (stack_size != 7) {
676 return OTS_FAILURE();
677 }
678 while (!argument_stack->empty())
679 argument_stack->pop();
680 return true;
681
682 case ots::kFlex:
683 if (!(*in_out_found_width)) {
684 return OTS_FAILURE();
685 }
686 if (stack_size != 13) {
687 return OTS_FAILURE();
688 }
689 while (!argument_stack->empty())
690 argument_stack->pop();
691 return true;
692
693 case ots::kHFlex1:
694 if (!(*in_out_found_width)) {
695 return OTS_FAILURE();
696 }
697 if (stack_size != 9) {
698 return OTS_FAILURE();
699 }
700 while (!argument_stack->empty())
701 argument_stack->pop();
702 return true;
703
704 case ots::kFlex1:
705 if (!(*in_out_found_width)) {
706 return OTS_FAILURE();
707 }
708 if (stack_size != 11) {
709 return OTS_FAILURE();
710 }
711 while (!argument_stack->empty())
712 argument_stack->pop();
713 return true;
714 }
715
716 return OTS_FAILURE_MSG("Undefined operator: %d (0x%x)", op, op);
717 }
718
719 // Executes |char_string| and updates |argument_stack|.
720 //
721 // call_depth: The current call depth. Initial value is zero.
722 // global_subrs_index: Global subroutines.
723 // local_subrs_index: Local subroutines for the current glyph.
724 // cff_table: A whole CFF table which contains all global and local subroutines.
725 // char_string: A charstring we'll execute. |char_string| can be a main routine
726 // in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
727 // argument_stack: The stack which an operator in |char_string| operates.
728 // out_found_endchar: true is set if |char_string| contains 'endchar'.
729 // in_out_found_width: true is set if |char_string| contains 'width' byte (which
730 // is 0 or 1 byte.)
731 // in_out_num_stems: total number of hstems and vstems processed so far.
732 bool ExecuteType2CharString(ots::OpenTypeFile *file,
733 size_t call_depth,
734 const ots::CFFIndex& global_subrs_index,
735 const ots::CFFIndex& local_subrs_index,
736 ots::Buffer *cff_table,
737 ots::Buffer *char_string,
738 std::stack<int32_t> *argument_stack,
739 bool *out_found_endchar,
740 bool *in_out_found_width,
741 size_t *in_out_num_stems) {
742 if (call_depth > kMaxSubrNesting) {
743 return OTS_FAILURE();
744 }
745 *out_found_endchar = false;
746
747 const size_t length = char_string->length();
748 while (char_string->offset() < length) {
749 int32_t operator_or_operand = 0;
750 bool is_operator = false;
751 if (!ReadNextNumberFromType2CharString(char_string,
752 &operator_or_operand,
753 &is_operator)) {
754 return OTS_FAILURE();
755 }
756
757 #ifdef DUMP_T2CHARSTRING
758 /*
759 You can dump all operators and operands (except mask bytes for hintmask
760 and cntrmask) by the following code:
761 */
762
763 if (!is_operator) {
764 std::fprintf(stderr, "#%d# ", operator_or_operand);
765 } else {
766 std::fprintf(stderr, "#%s#\n",
767 Type2CharStringOperatorToString(
768 ots::Type2CharStringOperator(operator_or_operand))
769 );
770 }
771 #endif
772
773 if (!is_operator) {
774 argument_stack->push(operator_or_operand);
775 if (argument_stack->size() > kMaxArgumentStack) {
776 return OTS_FAILURE();
777 }
778 continue;
779 }
780
781 // An operator is found. Execute it.
782 if (!ExecuteType2CharStringOperator(file,
783 operator_or_operand,
784 call_depth,
785 global_subrs_index,
786 local_subrs_index,
787 cff_table,
788 char_string,
789 argument_stack,
790 out_found_endchar,
791 in_out_found_width,
792 in_out_num_stems)) {
793 return OTS_FAILURE();
794 }
795 if (*out_found_endchar) {
796 return true;
797 }
798 if (operator_or_operand == ots::kReturn) {
799 return true;
800 }
801 }
802
803 // No endchar operator is found.
804 return OTS_FAILURE();
805 }
806
807 // Selects a set of subroutings for |glyph_index| from |cff| and sets it on
808 // |out_local_subrs_to_use|. Returns true on success.
809 bool SelectLocalSubr(const std::map<uint16_t, uint8_t> &fd_select,
810 const std::vector<ots::CFFIndex *> &local_subrs_per_font,
811 const ots::CFFIndex *local_subrs,
812 uint16_t glyph_index, // 0-origin
813 const ots::CFFIndex **out_local_subrs_to_use) {
814 *out_local_subrs_to_use = NULL;
815
816 // First, find local subrs from |local_subrs_per_font|.
817 if ((fd_select.size() > 0) &&
818 (!local_subrs_per_font.empty())) {
819 // Look up FDArray index for the glyph.
820 std::map<uint16_t, uint8_t>::const_iterator iter =
821 fd_select.find(glyph_index);
822 if (iter == fd_select.end()) {
823 return OTS_FAILURE();
824 }
825 const uint8_t fd_index = iter->second;
826 if (fd_index >= local_subrs_per_font.size()) {
827 return OTS_FAILURE();
828 }
829 *out_local_subrs_to_use = local_subrs_per_font.at(fd_index);
830 } else if (local_subrs) {
831 // Second, try to use |local_subrs|. Most Latin fonts don't have FDSelect
832 // entries. If The font has a local subrs index associated with the Top
833 // DICT (not FDArrays), use it.
834 *out_local_subrs_to_use = local_subrs;
835 } else {
836 // Just return NULL.
837 *out_local_subrs_to_use = NULL;
838 }
839
840 return true;
841 }
842
843 } // namespace
844
845 namespace ots {
846
847 bool ValidateType2CharStringIndex(
848 ots::OpenTypeFile *file,
849 const CFFIndex& char_strings_index,
850 const CFFIndex& global_subrs_index,
851 const std::map<uint16_t, uint8_t> &fd_select,
852 const std::vector<CFFIndex *> &local_subrs_per_font,
853 const CFFIndex *local_subrs,
854 Buffer* cff_table) {
855 const uint16_t num_offsets =
856 static_cast<uint16_t>(char_strings_index.offsets.size());
857 if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) {
858 return OTS_FAILURE(); // no charstring.
859 }
860
861 // For each glyph, validate the corresponding charstring.
862 for (uint16_t i = 1; i < num_offsets; ++i) {
863 // Prepare a Buffer object, |char_string|, which contains the charstring
864 // for the |i|-th glyph.
865 const size_t length =
866 char_strings_index.offsets[i] - char_strings_index.offsets[i - 1];
867 if (length > kMaxCharStringLength) {
868 return OTS_FAILURE();
869 }
870 const size_t offset = char_strings_index.offsets[i - 1];
871 cff_table->set_offset(offset);
872 if (!cff_table->Skip(length)) {
873 return OTS_FAILURE();
874 }
875 Buffer char_string(cff_table->buffer() + offset, length);
876
877 // Get a local subrs for the glyph.
878 const uint16_t glyph_index = i - 1; // index in the map is 0-origin.
879 const CFFIndex *local_subrs_to_use = NULL;
880 if (!SelectLocalSubr(fd_select,
881 local_subrs_per_font,
882 local_subrs,
883 glyph_index,
884 &local_subrs_to_use)) {
885 return OTS_FAILURE();
886 }
887 // If |local_subrs_to_use| is still NULL, use an empty one.
888 CFFIndex default_empty_subrs;
889 if (!local_subrs_to_use){
890 local_subrs_to_use = &default_empty_subrs;
891 }
892
893 // Check a charstring for the |i|-th glyph.
894 std::stack<int32_t> argument_stack;
895 bool found_endchar = false;
896 bool found_width = false;
897 size_t num_stems = 0;
898 if (!ExecuteType2CharString(file,
899 0 /* initial call_depth is zero */,
900 global_subrs_index, *local_subrs_to_use,
901 cff_table, &char_string, &argument_stack,
902 &found_endchar, &found_width, &num_stems)) {
903 return OTS_FAILURE();
904 }
905 if (!found_endchar) {
906 return OTS_FAILURE();
907 }
908 }
909 return true;
910 }
911
912 } // namespace ots
913
914 #undef TABLE_NAME
OLDNEW
« no previous file with comments | « third_party/ots/src/cff_type2_charstring.h ('k') | third_party/ots/src/cmap.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698