/src/serenity/Userland/Libraries/LibWeb/SVG/AttributeParser.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org> |
3 | | * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org> |
4 | | * Copyright (c) 2024, Tim Ledbetter <timledbetter@gmail.com> |
5 | | * |
6 | | * SPDX-License-Identifier: BSD-2-Clause |
7 | | */ |
8 | | |
9 | | #pragma once |
10 | | |
11 | | #include <AK/GenericLexer.h> |
12 | | #include <AK/Variant.h> |
13 | | #include <AK/Vector.h> |
14 | | #include <LibGfx/Point.h> |
15 | | |
16 | | namespace Web::SVG { |
17 | | |
18 | | enum class PathInstructionType { |
19 | | Move, |
20 | | ClosePath, |
21 | | Line, |
22 | | HorizontalLine, |
23 | | VerticalLine, |
24 | | Curve, |
25 | | SmoothCurve, |
26 | | QuadraticBezierCurve, |
27 | | SmoothQuadraticBezierCurve, |
28 | | EllipticalArc, |
29 | | Invalid, |
30 | | }; |
31 | | |
32 | | struct PathInstruction { |
33 | | PathInstructionType type; |
34 | | bool absolute; |
35 | | Vector<float> data; |
36 | | }; |
37 | | |
38 | | struct Transform { |
39 | | struct Translate { |
40 | | float x; |
41 | | float y; |
42 | | }; |
43 | | struct Scale { |
44 | | float x; |
45 | | float y; |
46 | | }; |
47 | | struct Rotate { |
48 | | float a; |
49 | | float x; |
50 | | float y; |
51 | | }; |
52 | | struct SkewX { |
53 | | float a; |
54 | | }; |
55 | | struct SkewY { |
56 | | float a; |
57 | | }; |
58 | | struct Matrix { |
59 | | float a; |
60 | | float b; |
61 | | float c; |
62 | | float d; |
63 | | float e; |
64 | | float f; |
65 | | }; |
66 | | |
67 | | using Operation = Variant<Translate, Scale, Rotate, SkewX, SkewY, Matrix>; |
68 | | Operation operation; |
69 | | }; |
70 | | |
71 | | struct PreserveAspectRatio { |
72 | | enum class Align { |
73 | | None, |
74 | | xMinYMin, |
75 | | xMidYMin, |
76 | | xMaxYMin, |
77 | | xMinYMid, |
78 | | xMidYMid, |
79 | | xMaxYMid, |
80 | | xMinYMax, |
81 | | xMidYMax, |
82 | | xMaxYMax |
83 | | }; |
84 | | enum class MeetOrSlice { |
85 | | Meet, |
86 | | Slice |
87 | | }; |
88 | | Align align { Align::xMidYMid }; |
89 | | MeetOrSlice meet_or_slice { MeetOrSlice::Meet }; |
90 | | }; |
91 | | |
92 | | enum class SVGUnits { |
93 | | ObjectBoundingBox, |
94 | | UserSpaceOnUse |
95 | | }; |
96 | | |
97 | | using GradientUnits = SVGUnits; |
98 | | using MaskUnits = SVGUnits; |
99 | | using MaskContentUnits = SVGUnits; |
100 | | using ClipPathUnits = SVGUnits; |
101 | | |
102 | | enum class SpreadMethod { |
103 | | Pad, |
104 | | Repeat, |
105 | | Reflect |
106 | | }; |
107 | | |
108 | | class NumberPercentage { |
109 | | public: |
110 | | NumberPercentage(float value, bool is_percentage) |
111 | 0 | : m_value(is_percentage ? value / 100 : value) |
112 | 0 | , m_is_percentage(is_percentage) |
113 | 0 | { |
114 | 0 | } |
115 | | |
116 | | static NumberPercentage create_percentage(float value) |
117 | 0 | { |
118 | 0 | return NumberPercentage(value, true); |
119 | 0 | } |
120 | | |
121 | | static NumberPercentage create_number(float value) |
122 | 0 | { |
123 | 0 | return NumberPercentage(value, false); |
124 | 0 | } |
125 | | |
126 | | float resolve_relative_to(float length) const; |
127 | | |
128 | 0 | float value() const { return m_value; } |
129 | | |
130 | | private: |
131 | | float m_value; |
132 | | bool m_is_percentage { false }; |
133 | | }; |
134 | | |
135 | | enum class FillRule { |
136 | | Nonzero, |
137 | | Evenodd |
138 | | }; |
139 | | |
140 | | using ClipRule = FillRule; |
141 | | |
142 | | enum class TextAnchor { |
143 | | Start, |
144 | | Middle, |
145 | | End |
146 | | }; |
147 | | |
148 | | class AttributeParser final { |
149 | | public: |
150 | 0 | ~AttributeParser() = default; |
151 | | |
152 | | static Optional<float> parse_coordinate(StringView input); |
153 | | static Optional<float> parse_length(StringView input); |
154 | | static Optional<NumberPercentage> parse_number_percentage(StringView input); |
155 | | static Optional<float> parse_positive_length(StringView input); |
156 | | static Vector<Gfx::FloatPoint> parse_points(StringView input); |
157 | | static Vector<PathInstruction> parse_path_data(StringView input); |
158 | | static Optional<Vector<Transform>> parse_transform(StringView input); |
159 | | static Optional<PreserveAspectRatio> parse_preserve_aspect_ratio(StringView input); |
160 | | static Optional<SVGUnits> parse_units(StringView input); |
161 | | static Optional<SpreadMethod> parse_spread_method(StringView input); |
162 | | |
163 | | private: |
164 | | AttributeParser(StringView source); |
165 | | |
166 | | ErrorOr<void> parse_drawto(); |
167 | | ErrorOr<void> parse_moveto(); |
168 | | void parse_closepath(); |
169 | | ErrorOr<void> parse_lineto(); |
170 | | ErrorOr<void> parse_horizontal_lineto(); |
171 | | ErrorOr<void> parse_vertical_lineto(); |
172 | | ErrorOr<void> parse_curveto(); |
173 | | ErrorOr<void> parse_smooth_curveto(); |
174 | | ErrorOr<void> parse_quadratic_bezier_curveto(); |
175 | | ErrorOr<void> parse_smooth_quadratic_bezier_curveto(); |
176 | | ErrorOr<void> parse_elliptical_arc(); |
177 | | |
178 | | Optional<Vector<Transform>> parse_transform(); |
179 | | |
180 | | ErrorOr<float> parse_length(); |
181 | | ErrorOr<float> parse_coordinate(); |
182 | | ErrorOr<Vector<float>> parse_coordinate_pair(); |
183 | | ErrorOr<Vector<float>> parse_coordinate_sequence(); |
184 | | ErrorOr<Vector<Vector<float>>> parse_coordinate_pair_sequence(); |
185 | | ErrorOr<Vector<float>> parse_coordinate_pair_double(); |
186 | | ErrorOr<Vector<float>> parse_coordinate_pair_triplet(); |
187 | | ErrorOr<Vector<float>> parse_elliptical_arc_argument(); |
188 | | void parse_whitespace(bool must_match_once = false); |
189 | | void parse_comma_whitespace(); |
190 | | ErrorOr<float> parse_number(); |
191 | | ErrorOr<float> parse_nonnegative_number(); |
192 | | ErrorOr<float> parse_flag(); |
193 | | // -1 if negative, +1 otherwise |
194 | | int parse_sign(); |
195 | | |
196 | | bool match_whitespace() const; |
197 | | bool match_comma_whitespace() const; |
198 | | bool match_coordinate() const; |
199 | | bool match_length() const; |
200 | | bool match_number() const; |
201 | 0 | bool match(char c) const { return !done() && ch() == c; } |
202 | | |
203 | 0 | bool done() const { return m_lexer.is_eof(); } |
204 | 0 | char ch(size_t offset = 0) const { return m_lexer.peek(offset); } |
205 | 0 | char consume() { return m_lexer.consume(); } |
206 | | |
207 | | GenericLexer m_lexer; |
208 | | Vector<PathInstruction> m_instructions; |
209 | | }; |
210 | | |
211 | | } |