1
// This file was derived from ttf-parser, licenced under Apache-2.0.
2
// https://github.com/RazrFalcon/ttf-parser/blob/439aaaebd50eb8aed66302e3c1b51fae047f85b2/src/tables/cff/charstring.rs
3

            
4
use crate::cff::charstring::{ArgumentsStack, IsEven};
5
use crate::cff::outline::Builder;
6
use crate::cff::{self, CFFError};
7
use crate::outline::OutlineSink;
8

            
9
pub(crate) struct CharStringParser<'a, B>
10
where
11
    B: OutlineSink,
12
{
13
    pub(crate) builder: &'a mut Builder<'a, B>,
14
    pub(crate) x: f32,
15
    pub(crate) y: f32,
16
    // Used to track if a moveto operator has been encountered before other path building operators.
17
    // Adobe Technical Note #5177 - The Type 2 Charstring Format:
18
    // > Every character path and subpath must begin with one of the moveto operators. If the
19
    // > current path is open when a moveto operator is encountered, the path is closed before
20
    // > performing the moveto operation.
21
    pub(crate) has_move_to: bool,
22
    // Used to determine what point a moveto operator is relative to.
23
    // Adobe Technical Note #5177 - The Type 2 Charstring Format:
24
    // > For the initial moveto operators in a charstring, the arguments are relative to the (0, 0)
25
    // > point in the character’s coordinate system; subsequent moveto operators’ arguments are
26
    // > relative to the current point.
27
    pub(crate) is_first_move_to: bool,
28
    /// Used as temporary storage when processing some operators.
29
    ///
30
    /// Needs to be the same size as the argument stack.
31
    pub(crate) temp: [f32; cff::MAX_OPERANDS],
32
}
33

            
34
impl<B: OutlineSink> CharStringParser<'_, B> {
35
    pub fn parse_move_to(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
36
        // dx1 dy1
37

            
38
        if stack.len() != 2 {
39
            return Err(CFFError::InvalidArgumentsStackLength);
40
        }
41

            
42
        if self.is_first_move_to {
43
            self.is_first_move_to = false;
44
        } else {
45
            self.builder.close();
46
        }
47

            
48
        self.has_move_to = true;
49

            
50
        self.x += stack.at(0);
51
        self.y += stack.at(1);
52
        self.builder.move_to(self.x, self.y);
53

            
54
        Ok(())
55
    }
56

            
57
    pub fn parse_horizontal_move_to(
58
        &mut self,
59
        stack: &ArgumentsStack<'_, f32>,
60
    ) -> Result<(), CFFError> {
61
        // dx1
62

            
63
        if stack.len() != 1 {
64
            return Err(CFFError::InvalidArgumentsStackLength);
65
        }
66

            
67
        if self.is_first_move_to {
68
            self.is_first_move_to = false;
69
        } else {
70
            self.builder.close();
71
        }
72

            
73
        self.has_move_to = true;
74

            
75
        self.x += stack.at(0);
76
        self.builder.move_to(self.x, self.y);
77

            
78
        Ok(())
79
    }
80

            
81
    pub fn parse_vertical_move_to(
82
        &mut self,
83
        stack: &ArgumentsStack<'_, f32>,
84
    ) -> Result<(), CFFError> {
85
        // dy1
86

            
87
        if stack.len() != 1 {
88
            return Err(CFFError::InvalidArgumentsStackLength);
89
        }
90

            
91
        if self.is_first_move_to {
92
            self.is_first_move_to = false;
93
        } else {
94
            self.builder.close();
95
        }
96

            
97
        self.has_move_to = true;
98

            
99
        self.y += stack.at(0);
100
        self.builder.move_to(self.x, self.y);
101

            
102
        Ok(())
103
    }
104

            
105
    pub fn parse_line_to(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
106
        // {dxa dya}+
107

            
108
        if !self.has_move_to {
109
            return Err(CFFError::MissingMoveTo);
110
        }
111

            
112
        if stack.len().is_odd() {
113
            return Err(CFFError::InvalidArgumentsStackLength);
114
        }
115

            
116
        let mut i = 0;
117
        while i < stack.len() {
118
            self.x += stack.at(i + 0);
119
            self.y += stack.at(i + 1);
120
            self.builder.line_to(self.x, self.y);
121
            i += 2;
122
        }
123

            
124
        Ok(())
125
    }
126

            
127
    pub fn parse_horizontal_line_to(
128
        &mut self,
129
        stack: &ArgumentsStack<'_, f32>,
130
    ) -> Result<(), CFFError> {
131
        // dx1 {dya dxb}*
132
        //     {dxa dyb}+
133

            
134
        if !self.has_move_to {
135
            return Err(CFFError::MissingMoveTo);
136
        }
137

            
138
        if stack.is_empty() {
139
            return Err(CFFError::InvalidArgumentsStackLength);
140
        }
141

            
142
        let mut i = 0;
143
        while i < stack.len() {
144
            self.x += stack.at(i);
145
            i += 1;
146
            self.builder.line_to(self.x, self.y);
147

            
148
            if i == stack.len() {
149
                break;
150
            }
151

            
152
            self.y += stack.at(i);
153
            i += 1;
154
            self.builder.line_to(self.x, self.y);
155
        }
156

            
157
        Ok(())
158
    }
159

            
160
    pub fn parse_vertical_line_to(
161
        &mut self,
162
        stack: &ArgumentsStack<'_, f32>,
163
    ) -> Result<(), CFFError> {
164
        // dy1 {dxa dyb}*
165
        //     {dya dxb}+
166

            
167
        if !self.has_move_to {
168
            return Err(CFFError::MissingMoveTo);
169
        }
170

            
171
        if stack.is_empty() {
172
            return Err(CFFError::InvalidArgumentsStackLength);
173
        }
174

            
175
        let mut i = 0;
176
        while i < stack.len() {
177
            self.y += stack.at(i);
178
            i += 1;
179
            self.builder.line_to(self.x, self.y);
180

            
181
            if i == stack.len() {
182
                break;
183
            }
184

            
185
            self.x += stack.at(i);
186
            i += 1;
187
            self.builder.line_to(self.x, self.y);
188
        }
189

            
190
        Ok(())
191
    }
192

            
193
    pub fn parse_curve_to(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
194
        // {dxa dya dxb dyb dxc dyc}+
195

            
196
        if !self.has_move_to {
197
            return Err(CFFError::MissingMoveTo);
198
        }
199

            
200
        if stack.len() % 6 != 0 {
201
            return Err(CFFError::InvalidArgumentsStackLength);
202
        }
203

            
204
        let mut i = 0;
205
        while i < stack.len() {
206
            let x1 = self.x + stack.at(i + 0);
207
            let y1 = self.y + stack.at(i + 1);
208
            let x2 = x1 + stack.at(i + 2);
209
            let y2 = y1 + stack.at(i + 3);
210
            self.x = x2 + stack.at(i + 4);
211
            self.y = y2 + stack.at(i + 5);
212

            
213
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
214
            i += 6;
215
        }
216

            
217
        Ok(())
218
    }
219

            
220
    pub fn parse_curve_line(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
221
        // {dxa dya dxb dyb dxc dyc}+ dxd dyd
222

            
223
        if !self.has_move_to {
224
            return Err(CFFError::MissingMoveTo);
225
        }
226

            
227
        if stack.len() < 8 {
228
            return Err(CFFError::InvalidArgumentsStackLength);
229
        }
230

            
231
        if (stack.len() - 2) % 6 != 0 {
232
            return Err(CFFError::InvalidArgumentsStackLength);
233
        }
234

            
235
        let mut i = 0;
236
        while i < stack.len() - 2 {
237
            let x1 = self.x + stack.at(i + 0);
238
            let y1 = self.y + stack.at(i + 1);
239
            let x2 = x1 + stack.at(i + 2);
240
            let y2 = y1 + stack.at(i + 3);
241
            self.x = x2 + stack.at(i + 4);
242
            self.y = y2 + stack.at(i + 5);
243

            
244
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
245
            i += 6;
246
        }
247

            
248
        self.x += stack.at(i + 0);
249
        self.y += stack.at(i + 1);
250
        self.builder.line_to(self.x, self.y);
251

            
252
        Ok(())
253
    }
254

            
255
    pub fn parse_line_curve(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
256
        // {dxa dya}+ dxb dyb dxc dyc dxd dyd
257

            
258
        if !self.has_move_to {
259
            return Err(CFFError::MissingMoveTo);
260
        }
261

            
262
        if stack.len() < 8 {
263
            return Err(CFFError::InvalidArgumentsStackLength);
264
        }
265

            
266
        if (stack.len() - 6).is_odd() {
267
            return Err(CFFError::InvalidArgumentsStackLength);
268
        }
269

            
270
        let mut i = 0;
271
        while i < stack.len() - 6 {
272
            self.x += stack.at(i + 0);
273
            self.y += stack.at(i + 1);
274

            
275
            self.builder.line_to(self.x, self.y);
276
            i += 2;
277
        }
278

            
279
        let x1 = self.x + stack.at(i + 0);
280
        let y1 = self.y + stack.at(i + 1);
281
        let x2 = x1 + stack.at(i + 2);
282
        let y2 = y1 + stack.at(i + 3);
283
        self.x = x2 + stack.at(i + 4);
284
        self.y = y2 + stack.at(i + 5);
285
        self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
286

            
287
        Ok(())
288
    }
289

            
290
    pub fn parse_hh_curve_to(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
291
        // dy1? {dxa dxb dyb dxc}+
292

            
293
        if !self.has_move_to {
294
            return Err(CFFError::MissingMoveTo);
295
        }
296

            
297
        let mut i = 0;
298

            
299
        // The odd argument count indicates an Y position.
300
        if stack.len().is_odd() {
301
            self.y += stack.at(0);
302
            i += 1;
303
        }
304

            
305
        if (stack.len() - i) % 4 != 0 {
306
            return Err(CFFError::InvalidArgumentsStackLength);
307
        }
308

            
309
        while i < stack.len() {
310
            let x1 = self.x + stack.at(i + 0);
311
            let y1 = self.y;
312
            let x2 = x1 + stack.at(i + 1);
313
            let y2 = y1 + stack.at(i + 2);
314
            self.x = x2 + stack.at(i + 3);
315
            self.y = y2;
316

            
317
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
318
            i += 4;
319
        }
320

            
321
        Ok(())
322
    }
323

            
324
    pub fn parse_vv_curve_to(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
325
        // dx1? {dya dxb dyb dyc}+
326

            
327
        if !self.has_move_to {
328
            return Err(CFFError::MissingMoveTo);
329
        }
330

            
331
        let mut i = 0;
332

            
333
        // The odd argument count indicates an X position.
334
        if stack.len().is_odd() {
335
            self.x += stack.at(0);
336
            i += 1;
337
        }
338

            
339
        if (stack.len() - i) % 4 != 0 {
340
            return Err(CFFError::InvalidArgumentsStackLength);
341
        }
342

            
343
        while i < stack.len() {
344
            let x1 = self.x;
345
            let y1 = self.y + stack.at(i + 0);
346
            let x2 = x1 + stack.at(i + 1);
347
            let y2 = y1 + stack.at(i + 2);
348
            self.x = x2;
349
            self.y = y2 + stack.at(i + 3);
350

            
351
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
352
            i += 4;
353
        }
354

            
355
        Ok(())
356
    }
357

            
358
    pub fn parse_hv_curve_to(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
359
        // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
360
        //                 {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
361

            
362
        if !self.has_move_to {
363
            return Err(CFFError::MissingMoveTo);
364
        }
365

            
366
        if stack.len() < 4 {
367
            return Err(CFFError::InvalidArgumentsStackLength);
368
        }
369

            
370
        let mut stack = stack.clone_into(self.temp.as_mut_slice());
371
        stack.reverse();
372
        while !stack.is_empty() {
373
            if stack.len() < 4 {
374
                return Err(CFFError::InvalidArgumentsStackLength);
375
            }
376

            
377
            let x1 = self.x + stack.pop();
378
            let y1 = self.y;
379
            let x2 = x1 + stack.pop();
380
            let y2 = y1 + stack.pop();
381
            self.y = y2 + stack.pop();
382
            self.x = x2 + if stack.len() == 1 { stack.pop() } else { 0.0 };
383
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
384
            if stack.is_empty() {
385
                break;
386
            }
387

            
388
            if stack.len() < 4 {
389
                return Err(CFFError::InvalidArgumentsStackLength);
390
            }
391

            
392
            let x1 = self.x;
393
            let y1 = self.y + stack.pop();
394
            let x2 = x1 + stack.pop();
395
            let y2 = y1 + stack.pop();
396
            self.x = x2 + stack.pop();
397
            self.y = y2 + if stack.len() == 1 { stack.pop() } else { 0.0 };
398
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
399
        }
400

            
401
        debug_assert!(stack.is_empty());
402
        Ok(())
403
    }
404

            
405
    pub fn parse_vh_curve_to(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
406
        // dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf?
407
        //                 {dya dxb dyb dxc dxd dxe dye dyf}+ dxf?
408

            
409
        if !self.has_move_to {
410
            return Err(CFFError::MissingMoveTo);
411
        }
412

            
413
        if stack.len() < 4 {
414
            return Err(CFFError::InvalidArgumentsStackLength);
415
        }
416

            
417
        let mut stack = stack.clone_into(self.temp.as_mut_slice());
418
        stack.reverse();
419
        while !stack.is_empty() {
420
            if stack.len() < 4 {
421
                return Err(CFFError::InvalidArgumentsStackLength);
422
            }
423

            
424
            let x1 = self.x;
425
            let y1 = self.y + stack.pop();
426
            let x2 = x1 + stack.pop();
427
            let y2 = y1 + stack.pop();
428
            self.x = x2 + stack.pop();
429
            self.y = y2 + if stack.len() == 1 { stack.pop() } else { 0.0 };
430
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
431
            if stack.is_empty() {
432
                break;
433
            }
434

            
435
            if stack.len() < 4 {
436
                return Err(CFFError::InvalidArgumentsStackLength);
437
            }
438

            
439
            let x1 = self.x + stack.pop();
440
            let y1 = self.y;
441
            let x2 = x1 + stack.pop();
442
            let y2 = y1 + stack.pop();
443
            self.y = y2 + stack.pop();
444
            self.x = x2 + if stack.len() == 1 { stack.pop() } else { 0.0 };
445
            self.builder.curve_to(x1, y1, x2, y2, self.x, self.y);
446
        }
447

            
448
        debug_assert!(stack.is_empty());
449
        Ok(())
450
    }
451

            
452
    pub fn parse_flex(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
453
        // dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd
454

            
455
        if !self.has_move_to {
456
            return Err(CFFError::MissingMoveTo);
457
        }
458

            
459
        if stack.len() != 13 {
460
            return Err(CFFError::InvalidArgumentsStackLength);
461
        }
462

            
463
        let dx1 = self.x + stack.at(0);
464
        let dy1 = self.y + stack.at(1);
465
        let dx2 = dx1 + stack.at(2);
466
        let dy2 = dy1 + stack.at(3);
467
        let dx3 = dx2 + stack.at(4);
468
        let dy3 = dy2 + stack.at(5);
469
        let dx4 = dx3 + stack.at(6);
470
        let dy4 = dy3 + stack.at(7);
471
        let dx5 = dx4 + stack.at(8);
472
        let dy5 = dy4 + stack.at(9);
473
        self.x = dx5 + stack.at(10);
474
        self.y = dy5 + stack.at(11);
475
        self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
476
        self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
477

            
478
        Ok(())
479
    }
480

            
481
    pub fn parse_flex1(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
482
        // dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6
483

            
484
        if !self.has_move_to {
485
            return Err(CFFError::MissingMoveTo);
486
        }
487

            
488
        if stack.len() != 11 {
489
            return Err(CFFError::InvalidArgumentsStackLength);
490
        }
491

            
492
        let dx1 = self.x + stack.at(0);
493
        let dy1 = self.y + stack.at(1);
494
        let dx2 = dx1 + stack.at(2);
495
        let dy2 = dy1 + stack.at(3);
496
        let dx3 = dx2 + stack.at(4);
497
        let dy3 = dy2 + stack.at(5);
498
        let dx4 = dx3 + stack.at(6);
499
        let dy4 = dy3 + stack.at(7);
500
        let dx5 = dx4 + stack.at(8);
501
        let dy5 = dy4 + stack.at(9);
502

            
503
        if (dx5 - self.x).abs() > (dy5 - self.y).abs() {
504
            self.x = dx5 + stack.at(10);
505
        } else {
506
            self.y = dy5 + stack.at(10);
507
        }
508

            
509
        self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
510
        self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
511

            
512
        Ok(())
513
    }
514

            
515
    pub fn parse_hflex(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
516
        // dx1 dx2 dy2 dx3 dx4 dx5 dx6
517

            
518
        if !self.has_move_to {
519
            return Err(CFFError::MissingMoveTo);
520
        }
521

            
522
        if stack.len() != 7 {
523
            return Err(CFFError::InvalidArgumentsStackLength);
524
        }
525

            
526
        let dx1 = self.x + stack.at(0);
527
        let dy1 = self.y;
528
        let dx2 = dx1 + stack.at(1);
529
        let dy2 = dy1 + stack.at(2);
530
        let dx3 = dx2 + stack.at(3);
531
        let dy3 = dy2;
532
        let dx4 = dx3 + stack.at(4);
533
        let dy4 = dy2;
534
        let dx5 = dx4 + stack.at(5);
535
        let dy5 = self.y;
536
        self.x = dx5 + stack.at(6);
537
        self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
538
        self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
539

            
540
        Ok(())
541
    }
542

            
543
    pub fn parse_hflex1(&mut self, stack: &ArgumentsStack<'_, f32>) -> Result<(), CFFError> {
544
        // dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6
545

            
546
        if !self.has_move_to {
547
            return Err(CFFError::MissingMoveTo);
548
        }
549

            
550
        if stack.len() != 9 {
551
            return Err(CFFError::InvalidArgumentsStackLength);
552
        }
553

            
554
        let dx1 = self.x + stack.at(0);
555
        let dy1 = self.y + stack.at(1);
556
        let dx2 = dx1 + stack.at(2);
557
        let dy2 = dy1 + stack.at(3);
558
        let dx3 = dx2 + stack.at(4);
559
        let dy3 = dy2;
560
        let dx4 = dx3 + stack.at(5);
561
        let dy4 = dy2;
562
        let dx5 = dx4 + stack.at(6);
563
        let dy5 = dy4 + stack.at(7);
564
        self.x = dx5 + stack.at(8);
565
        self.builder.curve_to(dx1, dy1, dx2, dy2, dx3, dy3);
566
        self.builder.curve_to(dx4, dy4, dx5, dy5, self.x, self.y);
567

            
568
        Ok(())
569
    }
570
}