1use crate::common::{read_unit, read_variable_sized_unsigned_number, Unit};
2use crate::header::TinyVgHeader;
3use crate::TinyVgParseError;
4use byteorder::ReadBytesExt;
5use std::io::{Cursor, Read};
6
7#[repr(u8)]
8#[derive(Debug)]
9pub enum StyleType {
10 Flat = 0,
12 Linear = 1,
14 Radial = 2
16}
17
18impl StyleType {
19 pub(crate) fn from_u8(value: u8) -> Self {
20 match value {
21 0 => Self::Flat,
22 1 => Self::Linear,
23 2 => Self::Radial,
24 _ => unreachable!("Style::from_u8 must be 0, 1, or 2.")
25 }
26 }
27
28 #[allow(dead_code)]
29 pub(crate) fn from_style(style: &Style) -> Self {
30 match style {
31 Style::FlatColor(..) => StyleType::Flat,
32 Style::LinearGradient(..) => StyleType::Linear,
33 Style::RadialGradient(..) => StyleType::Radial
34 }
35 }
36}
37
38#[derive(Debug)]
39pub struct FlatColored {
40 pub color_index: u64
41}
42impl FlatColored {
43 pub fn read_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<FlatColored, TinyVgParseError> {
44 let color_index = read_variable_sized_unsigned_number(cursor)?;
45
46 Ok(FlatColored {
47 color_index,
48 })
49 }
50
51}
52
53#[derive(Debug)]
54pub struct LinearGradient {
55 pub point_0: Point,
56 pub point_1: Point,
57 pub color_index_0: u64,
58 pub color_index_1: u64,
59}
60
61impl LinearGradient {
62 pub fn read_from_cursor(header: &TinyVgHeader, cursor: &mut Cursor<&[u8]>) -> Result<LinearGradient, TinyVgParseError> {
63 let point_0 = Point::read_point(header, cursor)?;
64 let point_1 = Point::read_point(header, cursor)?;
65
66 let color_index_0 = read_variable_sized_unsigned_number(cursor)?;
67 let color_index_1 = read_variable_sized_unsigned_number(cursor)?;
68
69 Ok(LinearGradient {
70 point_0,
71 point_1,
72 color_index_0,
73 color_index_1,
74 })
75 }
76}
77
78#[derive(Debug)]
79pub struct RadialGradient {
80 pub point_0: Point,
81 pub point_1: Point,
82 pub color_index_0: u64,
83 pub color_index_1: u64,
84}
85
86impl RadialGradient {
87 pub fn read_from_cursor(header: &TinyVgHeader, cursor: &mut Cursor<&[u8]>) -> Result<RadialGradient, TinyVgParseError> {
88 let point_0 = Point::read_point(header, cursor)?;
89 let point_1 = Point::read_point(header, cursor)?;
90
91 let color_index_0 = read_variable_sized_unsigned_number(cursor)?;
92 let color_index_1 = read_variable_sized_unsigned_number(cursor)?;
93
94 Ok(RadialGradient {
95 point_0,
96 point_1,
97 color_index_0,
98 color_index_1,
99 })
100 }
101}
102
103#[derive(Debug)]
104pub enum Style {
105 FlatColor(FlatColored),
106 LinearGradient(LinearGradient),
107 RadialGradient(RadialGradient),
108}
109
110impl Style {
111 fn read_cursor_using_style_type(header: &TinyVgHeader, cursor: &mut Cursor<&[u8]>, style_type: &StyleType) -> Result<Style, TinyVgParseError> {
112 match style_type {
113 StyleType::Flat => Ok(Style::FlatColor(FlatColored::read_from_cursor(cursor)?)),
114 StyleType::Linear => Ok(Style::LinearGradient(LinearGradient::read_from_cursor(header, cursor)?)),
115 StyleType::Radial => Ok(Style::RadialGradient(RadialGradient::read_from_cursor(header, cursor)?))
116 }
117 }
118}
119
120#[repr(u8)]
122#[derive(Debug, PartialEq)]
123pub enum CommandType {
124 EndOfDocument = 0,
126
127 FillPolygon = 1,
129
130 FillRectangles = 2,
132
133 FillPath = 3,
135
136 DrawLines = 4,
138
139 DrawLineLoop = 5,
141
142 DrawLineStrip = 6,
144
145 DrawLinePath = 7,
147
148 OutlineFillPolygon = 8,
150
151 OutlineFillRectangles = 9,
153
154 OutlineFillPath = 10,
156
157 TextHint = 11
159}
160
161impl CommandType {
162 fn from_u8(value: u8) -> Self {
163 match value {
164 0 => Self::EndOfDocument,
165 1 => Self::FillPolygon,
166 2 => Self::FillRectangles,
167 3 => Self::FillPath,
168 4 => Self::DrawLines,
169 5 => Self::DrawLineLoop,
170 6 => Self::DrawLineStrip,
171 7 => Self::DrawLinePath,
172 8 => Self::OutlineFillPolygon,
173 9 => Self::OutlineFillRectangles,
174 10 => Self::OutlineFillPath,
175 11 => Self::TextHint,
176 _ => unreachable!("Style::from_u8 must be in the range 0 to 11.")
177 }
178 }
179}
180
181#[derive(Debug, Copy, Clone,)]
182pub struct Point {
183 pub x: Unit,
184 pub y: Unit,
185}
186
187impl Point {
188 fn read_point(header: &TinyVgHeader, cursor: &mut Cursor<&[u8]>) -> Result<Point, TinyVgParseError> {
189 let x = read_unit(header.scale, cursor, &header.coordinate_range)?;
190 let y = read_unit(header.scale, cursor, &header.coordinate_range)?;
191 let start = Point { x, y };
192 Ok(start)
193 }
194
195 pub fn move_to(&self, point: &Point) -> Self {
196 point.clone()
197 }
198
199 pub fn new(x: Unit, y: Unit) -> Self {
200 Point {
201 x,
202 y
203 }
204 }
205}
206
207#[derive(Debug)]
208pub struct Rectangle {
209 pub x: Unit,
210 pub y: Unit,
211 pub width: Unit,
212 pub height: Unit,
213}
214
215impl Rectangle {
216 fn read_rectangle(header: &TinyVgHeader, cursor: &mut Cursor<&[u8]>) -> Result<Rectangle, TinyVgParseError> {
217 let x = read_unit(header.scale, cursor, &header.coordinate_range)?;
218 let y = read_unit(header.scale, cursor, &header.coordinate_range)?;
219 let width = read_unit(header.scale, cursor, &header.coordinate_range)?;
220 let height = read_unit(header.scale, cursor, &header.coordinate_range)?;
221 Ok(Rectangle { x, y, width, height})
222 }
223}
224
225#[derive(Debug)]
226pub struct Line {
227 pub start: Point,
229 pub end: Point,
231}
232
233impl Line {
234 fn read_line(header: &TinyVgHeader, cursor: &mut Cursor<&[u8]>) -> Result<Line, TinyVgParseError> {
235 let start = Point::read_point(header, cursor)?;
236 let end = Point::read_point(header, cursor)?;
237 Ok(Line{ start, end })
238 }
239}
240
241#[derive(Debug)]
242pub struct FillPolygonData {
243 pub style: Style,
244 pub points: Vec<Point>,
245}
246
247#[derive(Debug)]
248pub struct FillRectanglesData {
249 pub style: Style,
250 pub rectangles: Vec<Rectangle>,
251}
252
253#[derive(Debug)]
254pub struct FillPathData {
255 pub style: Style,
256 pub path: Path,
257}
258
259#[derive(Debug)]
260pub struct DrawLinesData {
261 pub lines: Vec<Line>,
262 pub line_width: Unit,
263 pub line_style: Style,
264}
265
266#[derive(Debug)]
267pub struct DrawLineLoopData {
268 pub line_style: Style,
269 pub line_width: Unit,
270 pub points: Vec<Point>
271}
272
273#[derive(Debug)]
274pub struct DrawLineStripData {
275 pub style: Style,
276 pub line_width: Unit,
277 pub points: Vec<Point>
278}
279
280#[derive(Debug)]
281pub struct DrawLinePathData {
282 pub style: Style,
283 pub line_width: Unit,
284 pub path: Path,
285}
286
287#[derive(Debug)]
288pub struct OutlineFillPolygonData {
289 pub fill_style: Style,
290 pub line_style: Style,
291 pub line_width: Unit,
292 pub points: Vec<Point>,
293}
294
295#[derive(Debug)]
296pub struct OutlineFillRectanglesData {
297 pub fill_style: Style,
298 pub line_style: Style,
299 pub line_width: Unit,
300 pub rectangles: Vec<Rectangle>,
301}
302
303#[derive(Debug)]
304pub struct OutlineFillPathData {
305 pub path: Path,
306 pub fill_style: Style,
307 pub line_style: Style,
308 pub line_width: Unit
309}
310
311#[derive(Debug)]
312pub struct TextHintData {
313 pub center: Point,
315 pub rotation: Unit,
317 pub height: Unit,
320 pub text: String,
321 pub glyph_length: u64,
323 pub glyph_offset: Vec<(Unit, Unit)>,
326}
327
328#[derive(Debug)]
329pub enum DrawCommand {
330 FillPolygon(FillPolygonData),
332
333 FillRectangles(FillRectanglesData),
335
336 FillPath(FillPathData),
338
339 DrawLines(DrawLinesData),
341
342 DrawLineLoop(DrawLineLoopData),
344
345 DrawLineStrip(DrawLineStripData),
347
348 DrawLinePath(DrawLinePathData),
350
351 OutlineFillPolygon(OutlineFillPolygonData),
353
354 OutlineFillRectangles(OutlineFillRectanglesData),
356
357 OutlineFillPath(OutlineFillPathData),
359
360 TextHint(TextHintData)
364}
365
366#[repr(u8)]
367#[derive(Debug, PartialEq)]
368pub(crate) enum PathCommandType {
369 Line = 0,
370 HorizontalLine = 1,
371 VerticalLine = 2,
372 CubicBezier = 3,
373 ArcCircle = 4,
374 ArcEllipse = 5,
375 ClosePath = 6,
376 QuadraticBezier = 7,
377}
378
379impl PathCommandType {
380 fn from_u8(value: u8) -> Self {
381 match value {
382 0 => Self::Line,
383 1 => Self::HorizontalLine,
384 2 => Self::VerticalLine,
385 3 => Self::CubicBezier,
386 4 => Self::ArcCircle,
387 5 => Self::ArcEllipse,
388 6 => Self::ClosePath,
389 7 => Self::QuadraticBezier,
390 _ => unreachable!("PathCommand::from_u8 must be in the range 0 to 7.")
391 }
392 }
393}
394
395#[derive(Debug, Clone)]
396pub struct CubicBezier {
397 pub control_point_0: Point,
398 pub control_point_1: Point,
399 pub point_1: Point,
400}
401
402#[derive(Debug, Clone)]
403pub struct ArcCircle {
404 pub large_arc: bool,
405 pub sweep: bool,
406 pub radius: Unit,
407 pub target: Point,
408}
409
410#[derive(Debug, Clone)]
411pub struct ArcEllipse {
412 pub large_arc: bool,
413 pub sweep: bool,
414 pub radius_x: Unit,
415 pub radius_y: Unit,
416 pub rotation: Unit,
417 pub target: Point,
418}
419
420#[derive(Debug, Clone)]
421pub struct QuadraticBezier {
422 pub control_point: Point,
423 pub point_1: Point,
424}
425
426#[derive(Debug, Clone)]
427pub enum PathCommand {
428 Line(Point, Option<Unit>),
429 HorizontalLine(Unit, Option<Unit>),
430 VerticalLine(Unit, Option<Unit>),
431 CubicBezier(CubicBezier, Option<Unit>),
432 ArcCircle(ArcCircle, Option<Unit>),
433 ArcEllipse(ArcEllipse, Option<Unit>),
434 ClosePath,
435 QuadraticBezier(QuadraticBezier, Option<Unit>),
436}
437
438#[derive(Debug, Clone)]
439pub struct Segment {
440 pub start: Point,
441 pub path_commands: Vec<PathCommand>,
442}
443
444#[derive(Debug)]
445pub struct Path {
446 pub segments: Vec<Segment>,
447}
448
449impl Path {
450 pub fn parse(cursor: &mut Cursor<&[u8]>, header: &TinyVgHeader, segment_count: usize) -> Result<Self, TinyVgParseError> {
451 let mut segment_command_counts: Vec<usize> = Vec::new();
452 for _ in 0..segment_count {
453 let segment_length = read_variable_sized_unsigned_number(cursor)? + 1;
454 segment_command_counts.push(segment_length as usize);
455 }
456
457 let mut segments: Vec<Segment> = Vec::new();
458
459 for i in 0..segment_count {
460 let start = Point::read_point(header, cursor)?;
461
462 let mut segment = Segment {
463 start,
464 path_commands: vec![],
465 };
466
467 let commands_count = segment_command_counts[i];
468
469 for _ in 0..commands_count {
470 let command_tag = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidCommand)?;
471 let path_command_raw = command_tag & 0b00_00_01_11;
472 let path_command = PathCommandType::from_u8(path_command_raw);
473 let has_line_width = (command_tag & 0b00_01_00_00) != 0;
474 let mut line_width: Option<Unit> = None;
475
476 if has_line_width {
477 line_width = Some(read_unit(header.scale, cursor, &header.coordinate_range)?);
479 }
480
481 match path_command {
482 PathCommandType::Line => {
483 let point = Point::read_point(header, cursor)?;
484 segment.path_commands.push(PathCommand::Line(point, line_width));
485 }
486 PathCommandType::HorizontalLine => {
487 let pos_x = read_unit(header.scale, cursor, &header.coordinate_range)?;
488 segment.path_commands.push(PathCommand::HorizontalLine(pos_x, line_width));
489 }
490 PathCommandType::VerticalLine => {
491 let pos_y = read_unit(header.scale, cursor, &header.coordinate_range)?;
492 segment.path_commands.push(PathCommand::VerticalLine(pos_y, line_width));
493 }
494 PathCommandType::CubicBezier => {
495 let control_0 = Point::read_point(header, cursor)?;
496 let control_1 = Point::read_point(header, cursor)?;
497 let point_1 = Point::read_point(header, cursor)?;
498
499 segment.path_commands.push(PathCommand::CubicBezier(
500 CubicBezier {
501 control_point_0: control_0,
502 control_point_1: control_1,
503 point_1,
504 },
505 line_width
506 ));
507 }
508 PathCommandType::ArcCircle => {
509 let large_arc_sweep_padding = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidCommand)?;
510 let large_arc = (large_arc_sweep_padding & 0b00_00_00_01) != 0;
511 let sweep = (large_arc_sweep_padding & 0b00_00_00_10) != 0;
512 let radius = read_unit(header.scale, cursor, &header.coordinate_range)?;
513 let target = Point::read_point(header, cursor)?;
514
515 segment.path_commands.push(PathCommand::ArcCircle(
516 ArcCircle {
517 large_arc,
518 sweep,
519 radius,
520 target
521 },
522 line_width
523 ))
524 }
525 PathCommandType::ArcEllipse => {
526 let large_arc_sweep_padding = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidCommand)?;
527 let large_arc = (large_arc_sweep_padding & 0b00_00_00_01) != 0;
528 let sweep = (large_arc_sweep_padding & 0b00_00_00_10) != 0;
529
530 let radius_x = read_unit(header.scale, cursor, &header.coordinate_range)?;
531 let radius_y = read_unit(header.scale, cursor, &header.coordinate_range)?;
532 let rotation = read_unit(header.scale, cursor, &header.coordinate_range)?;
533 let target = Point::read_point(header, cursor)?;
534
535 let arc_ellipse = ArcEllipse {
536 large_arc,
537 sweep,
538 radius_x,
539 radius_y,
540 rotation,
541 target,
542 };
543 segment.path_commands.push(PathCommand::ArcEllipse(arc_ellipse, line_width));
544 }
545 PathCommandType::ClosePath => {
546 segment.path_commands.push(PathCommand::ClosePath);
547 }
548 PathCommandType::QuadraticBezier => {
549 let control = Point::read_point(header, cursor)?;
550 let point_1 = Point::read_point(header, cursor)?;
551
552 let quadratic_bezier = QuadraticBezier {
553 control_point: control,
554 point_1
555 };
556 segment.path_commands.push(PathCommand::QuadraticBezier(quadratic_bezier, line_width));
557 }
558 }
559 }
560
561 segments.push(segment);
562 }
563
564 Ok(Self {
565 segments,
566 })
567 }
568}
569
570pub(crate) fn parse_draw_commands(cursor: &mut Cursor<&[u8]>, header: &TinyVgHeader) -> Result<Vec<DrawCommand>, TinyVgParseError> {
571 let mut draw_commands: Vec<DrawCommand> = Vec::new();
572
573 loop {
574 let encoded_command = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidCommand)?;
575 let command_index = encoded_command & 0b00_11_11_11;
577 let prim_style_kind = (encoded_command & 0b11_00_00_00) >> 6;
579
580 let command = CommandType::from_u8(command_index);
581
582 if matches!(command, CommandType::EndOfDocument) {
585 break;
586 }
587
588 let style_type = StyleType::from_u8(prim_style_kind);
589
590 match command {
591 CommandType::EndOfDocument => {
592 unreachable!("We should have broken out of the loop above.")
593 }
594 CommandType::FillPolygon => {
595 let point_count = read_variable_sized_unsigned_number(cursor)? + 1;
597 let mut points: Vec<Point> = Vec::with_capacity(point_count as usize);
598
599 let style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
601
602 for _ in 0..point_count {
604 let point = Point::read_point(header, cursor)?;
605 points.push(point);
606 }
607
608 let data = FillPolygonData {
609 style,
610 points,
611 };
612 draw_commands.push(DrawCommand::FillPolygon(data))
613 }
614 CommandType::FillRectangles => {
615 let rectangle_count = read_variable_sized_unsigned_number(cursor)? + 1;
617
618 let style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
620
621 let mut rectangles: Vec<Rectangle> = Vec::with_capacity(rectangle_count as usize);
623 for _ in 0..rectangle_count {
624 let x = read_unit(header.scale, cursor, &header.coordinate_range)?;
626
627 let y = read_unit(header.scale, cursor, &header.coordinate_range)?;
629
630 let width = read_unit(header.scale, cursor, &header.coordinate_range)?;
632
633 let height = read_unit(header.scale, cursor, &header.coordinate_range)?;
635 rectangles.push(Rectangle { x, y, width, height });
636 }
637
638 let data = FillRectanglesData {
639 rectangles,
640 style,
641 };
642 draw_commands.push(DrawCommand::FillRectangles(data))
643 }
644 CommandType::FillPath => {
645 let segment_count = read_variable_sized_unsigned_number(cursor)? + 1;
647
648 let style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
650
651 let path = Path::parse(cursor, header, segment_count as usize)?;
653
654 let data = FillPathData {
655 path,
656 style,
657 };
658 draw_commands.push(DrawCommand::FillPath(data));
659 }
660 CommandType::DrawLines => {
661 let line_count = read_variable_sized_unsigned_number(cursor)? + 1;
663
664 let line_style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
666
667 let line_width = read_unit(header.scale, cursor, &header.coordinate_range)?;
669
670 let mut lines: Vec<Line> = Vec::with_capacity(line_count as usize);
672 for _ in 0..line_count {
673 let line = Line::read_line(header, cursor)?;
674 lines.push(line);
675 }
676
677 let data = DrawLinesData {
678 lines,
679 line_width,
680 line_style,
681 };
682 draw_commands.push(DrawCommand::DrawLines(data));
683 }
684 CommandType::DrawLineLoop => {
685 let point_count = read_variable_sized_unsigned_number(cursor)? + 1;
687
688 let line_style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
690
691 let line_width = read_unit(header.scale, cursor, &header.coordinate_range)?;
693
694 let mut points: Vec<Point> = Vec::with_capacity(point_count as usize);
696 for _ in 0..point_count {
697 let point = Point::read_point(header, cursor)?;
698 points.push(point);
699 }
700
701 let data = DrawLineLoopData {
702 line_style,
703 line_width,
704 points,
705 };
706 draw_commands.push(DrawCommand::DrawLineLoop(data));
707 }
708 CommandType::DrawLineStrip => {
709 let point_count = read_variable_sized_unsigned_number(cursor)? + 1;
711
712 let style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
714
715 let line_width = read_unit(header.scale, cursor, &header.coordinate_range)?;
717
718 let mut points: Vec<Point> = Vec::with_capacity(point_count as usize);
720 for _ in 0..point_count {
721 let point = Point::read_point(header, cursor)?;
722 points.push(point);
723 }
724
725 let data = DrawLineStripData {
726 style,
727 line_width,
728 points
729 };
730 draw_commands.push(DrawCommand::DrawLineStrip(data));
731 }
732 CommandType::DrawLinePath => {
733 let segment_count = read_variable_sized_unsigned_number(cursor)? + 1;
735
736 let style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
738
739 let line_width = read_unit(header.scale, cursor, &header.coordinate_range)?;
741
742 let path = Path::parse(cursor, header, segment_count as usize)?;
744
745 let data = DrawLinePathData {
746 style,
747 line_width,
748 path,
749 };
750 draw_commands.push(DrawCommand::DrawLinePath(data));
751 }
752 CommandType::OutlineFillPolygon => {
753 let point_count_sec_style_kind = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidCommand)?;
754 let point_count = (point_count_sec_style_kind & 0b00_11_11_11) + 1;
756
757 let sec_style_kind = point_count_sec_style_kind & 0b11_00_00_00;
759
760 let fill_style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
762
763 let line_style = Style::read_cursor_using_style_type(header, cursor, &StyleType::from_u8(sec_style_kind))?;
765
766 let line_width = read_unit(header.scale, cursor, &header.coordinate_range)?;
768
769 let mut points: Vec<Point> = Vec::with_capacity(point_count as usize);
771 for _ in 0..point_count {
772 let point = Point::read_point(header, cursor)?;
773 points.push(point);
774 }
775
776 let data = OutlineFillPolygonData {
777 points,
778 line_width,
779 line_style,
780 fill_style,
781 };
782 draw_commands.push(DrawCommand::OutlineFillPolygon(data));
783 }
784 CommandType::OutlineFillRectangles => {
785 let rect_count_sec_style_kind = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidCommand)?;
786 let rect_count = (rect_count_sec_style_kind & 0b00_11_11_11) + 1;
788
789 let sec_style_kind = rect_count_sec_style_kind & 0b11_00_00_00;
791
792 let fill_style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
794
795 let line_style = Style::read_cursor_using_style_type(header, cursor, &StyleType::from_u8(sec_style_kind))?;
797
798 let line_width = read_unit(header.scale, cursor, &header.coordinate_range)?;
800
801 let mut rectangles: Vec<Rectangle> = Vec::with_capacity(rect_count as usize);
803 for _ in 0..rect_count {
804 let rectangle = Rectangle::read_rectangle(header, cursor)?;
805 rectangles.push(rectangle);
806 }
807
808 let data = OutlineFillRectanglesData {
809 fill_style,
810 line_style,
811 line_width,
812 rectangles,
813 };
814 draw_commands.push(DrawCommand::OutlineFillRectangles(data));
815 }
816 CommandType::OutlineFillPath => {
817 let segment_count_and_sec_style_kind = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidCommand)?;
818
819 let segment_count = (segment_count_and_sec_style_kind & 0b00_11_11_11) + 1;
821
822 let sec_style_kind = segment_count_and_sec_style_kind & 0b11_00_00_00;
824 let sec_style_type = StyleType::from_u8(sec_style_kind);
825
826 let fill_style = Style::read_cursor_using_style_type(header, cursor, &style_type)?;
828
829 let line_style = Style::read_cursor_using_style_type(header, cursor, &sec_style_type)?;
831
832 let line_width = read_unit(header.scale, cursor, &header.coordinate_range)?;
834
835 let path = Path::parse(cursor, header, segment_count as usize)?;
837
838 let data = OutlineFillPathData {
839 path,
840 fill_style,
841 line_style,
842 line_width,
843 };
844 draw_commands.push(DrawCommand::OutlineFillPath(data));
845 }
846
847 CommandType::TextHint => {
848 let center = Point::read_point(header, cursor)?;
850
851 let rotation = read_unit(header.scale, cursor, &header.coordinate_range)?;
853
854 let height = read_unit(header.scale, cursor, &header.coordinate_range)?;
857
858 let text_length = read_variable_sized_unsigned_number(cursor)?;
860
861 let mut text_buffer: Vec<u8> = vec![0; text_length as usize];
863 cursor.read_exact(text_buffer.as_mut_slice()).map_err(|_| TinyVgParseError::InvalidCommand)?;
864 let text = String::from_utf8(text_buffer).map_err(|_| TinyVgParseError::InvalidCommand)?;
865
866 let glyph_length = read_variable_sized_unsigned_number(cursor)?;
868
869 let mut glyph_offset: Vec<(Unit, Unit)> = Vec::with_capacity(glyph_length as usize);
872 for _ in 0..glyph_length {
873 let start_offset = read_unit(header.scale, cursor, &header.coordinate_range)?;
874 let end_offset = read_unit(header.scale, cursor, &header.coordinate_range)?;
875 glyph_offset.push((start_offset, end_offset));
876 }
877
878 let data = TextHintData {
879 center,
880 text,
881 rotation,
882 height,
883 glyph_length,
884 glyph_offset
885 };
886 draw_commands.push(DrawCommand::TextHint(data));
887 }
888 }
889
890 }
891
892 Ok(draw_commands)
893}