home
readme
diff
tree
note
docs
0commit aa8ce6c35f8208ce6c30d19014935d7e5a91f04b
1Author: Mason Wright <mason@lakefox.net>
2Date: Sat Oct 18 20:48:36 2025 -0600
3
4 Added all CSS types
5
6diff --git a/.swp b/.swp
7deleted file mode 100644
8index ced872d..0000000
9Binary files a/.swp and /dev/null differ
10diff --git a/docs/content/features/.supported-css-selectors.md.swp b/docs/content/features/.supported-css-selectors.md.swp
11deleted file mode 100644
12index b3fbabf..0000000
13Binary files a/docs/content/features/.supported-css-selectors.md.swp and /dev/null differ
14diff --git a/docs/manpage/grim.3 b/docs/manpage/grim.3
15new file mode 100644
16index 0000000..c942cc3
17--- /dev/null
18+++ b/docs/manpage/grim.3
19@@ -0,0 +1,110 @@
20+'\" t
21+.\" Copyright 2025 Mason Wright (mason@lakefox.net)
22+.\"
23+.\" SPDX-License-Identifier: Linux-man-pages-copyleft
24+.\"
25+.\" Modified Wed Oct 15 16:19 2025, Mason Wright
26+.\"
27+.TH grim 3 2025-10-15 "Linux man-pages 6.03"
28+.SH NAME
29+grim \- render HTML and CSS documents to a output source
30+.SH LIBRARY
31+Grim
32+.SH SYNOPSIS
33+.nf
34+.B #include <grim.h>
35+.PP
36+.BI "int abs(int " j );
37+.BI "long labs(long " j );
38+.BI "long long llabs(long long " j );
39+.PP
40+.B #include <inttypes.h>
41+.PP
42+.BI "intmax_t imaxabs(intmax_t " j );
43+.fi
44+.PP
45+.RS -3
46+Feature Test Macro Requirements for glibc (see
47+.BR feature_test_macros (7)):
48+.RE
49+.PP
50+.BR llabs ():
51+.nf
52+ _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L
53+.fi
54+.SH DESCRIPTION
55+The
56+.BR grim
57+library takes HTML and CSS as a file, string, or virtual document then computes the styles and position for the page.
58+The output is draw to a canvas, this canvas can share memory with any output. Most commonly this will be to the compositor
59+of the system OS.
60+
61+Grim also includes DOM api's from the programming language "JavaScript". This provides a common interface to interact with the
62+document allowing dynamic updates and user events.
63+
64+.SH TABLE
65+.TS
66+tab(@) ;
67+l l l.
68+Header 1@Header 2@Header 3
69+Row 1 A@Row 1 B@Row 1 C
70+Row 2 A@Row 2 B@Row 2 C
71+.TE
72+
73+.SH RETURN VALUE
74+Returns the absolute value of the integer argument, of the appropriate
75+integer type for the function.
76+.SH ATTRIBUTES
77+For an explanation of the terms used in this section, see
78+.BR attributes (7).
79+.ad l
80+.nh
81+.TS
82+allbox;
83+lbx lb lb
84+l l l.
85+Interface Attribute Value
86+T{
87+.BR abs (),
88+.BR labs (),
89+.BR llabs (),
90+.BR imaxabs ()
91+T} Thread safety MT-Safe
92+.TE
93+.hy
94+.ad
95+.sp 1
96+.SH STANDARDS
97+POSIX.1-2001, POSIX.1-2008, C99, SVr4, 4.3BSD.
98+.SH NOTES
99+Trying to take the absolute value of the most negative integer
100+is not defined.
101+.PP
102+The
103+.BR llabs ()
104+function is included since glibc 2.0.
105+The
106+.BR imaxabs ()
107+function is included since glibc 2.1.1.
108+.PP
109+For
110+.BR llabs ()
111+to be declared, it may be necessary to define
112+\fB_ISOC99_SOURCE\fP or \fB_ISOC9X_SOURCE\fP (depending on the
113+version of glibc) before including any standard headers.
114+.PP
115+By default,
116+GCC handles
117+.BR abs (),
118+.BR labs (),
119+and (since GCC 3.0)
120+.BR llabs ()
121+and
122+.BR imaxabs ()
123+as built-in functions.
124+.SH SEE ALSO
125+.BR cabs (3),
126+.BR ceil (3),
127+.BR fabs (3),
128+.BR floor (3),
129+.BR rint (3)
130diff --git a/docs/manpage/grim.html b/docs/manpage/grim.html
131new file mode 100644
132index 0000000..e69de29
133diff --git a/include/grim.h b/include/grim.h
134index fe50ffb..64ee1c7 100755
135--- a/include/grim.h
136+++ b/include/grim.h
137@@ -149,12 +149,14 @@ enum class UnitType {
138 // Operator
139 EQ, LT, GT, LE, GE, ADD, SUB, MULT, DIV,
140 // Color
141- HEX, RGB, RGBA, HSL, HSLA, HWB, COLOR,
142+ HEX, RGB, RGBA, HSL, HSLA, COLOR,
143 // Logic
144 AND, OR, NOT, ONLY, COMMA,
145 // Length
146 PX, EM, PERCENT, CM, CAP, CH, EX, IC, LH, RCAP, RCH, REM, REX, RIC, RLH, VH,
147 VW, VMAX, VMIN, VB, VI, CQW, CQH, CQI, CQB, CQMIN, CQMAX, MM, Q, IN, PC, PT,
148+ // Diminsion
149+ KHZ, HZ, SECOND, MS, FRACTION,
150 // Angle
151 DEG, RAD, GRAD, TURN,
152 // Non-unit numbers
153@@ -167,8 +169,48 @@ enum class UnitType {
154 CONTENT_DISTRIBUTION, BETWEEN, AROUND, EVENLY, STRETCH,
155 // Content-position
156 CONTENT_POSITION, CENTER, START, FLEX_START, FLEX_END,
157+ // Display Box
158+ DISPLAY_BOX, CONTENTS, NONE,
159+ // Display Inside
160+ DISPLAY_INSIDE, FLOW, FLOW_ROOT, TABLE, FLEX, GRID, RUBY,
161+ // Display Internal
162+ DISPLAY_INTERNAL, TABLE_ROW_GROUP, TABLE_HEADER_GROUP, TABLE_FOOTER_GROUP, TABLE_COLUMN_GROUP,
163+ TABLE_ROW, TABLE_CELL, TABLE_COLUMN, TABLE_CAPTION, RUBY_BASE, RUBY_TEXT, RUBY_BASE_CONTAINER,
164+ RUBY_TEXT_CONTAINER,
165+ // Display Legacy
166+ DISPLAY_LEGACY, INLINE_BLOCK, INLINE_TABLE, INLINE_GRID, INLINE_FLEX,
167+ // Display List Item
168+ DISPLAY_LISTITEM, LISTITEM,
169+ // Display Outside
170+ DISPLAY_OUTSIDE, BLOCK, INLINE, RUN_IN,
171+ // Easing Functions
172+ EASING_FUNCTION, LINEAR_EASING_FUNCTION, LINEAR, EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUBIC_BEZIER_FUNCTION,
173+ STEP_START, STEP_END, STEPS_FUNCTION, JUMP_START, JUMP_END, JUMP_NONE, JUMP_BOTH,
174 // Function
175- CALC, MIN,
176+ CALC, MIN, BLUR, BRIGHTNESS, CONTRAST, DROP_SHADOW, GRAYSCALE, HUE_ROTATE, INVERT, OPACITY, SEPIA, SATURATE,
177+ // Position
178+ POSITION, TOP, LEFT, BOTTOM, RIGHT, INLINE_START, INLINE_END, BLOCK_START, BLOCK_END, SELF_START, SELF_END, FLEX_START, FLEX_END,
179+ // Shape
180+ SHAPE, RADIAL_SHAPE, CIRCLE, ELLIPSE,
181+ // Generic Family
182+ GENERIC_FAMILY, SERIF, SANS_SERIF, MONOSPACE, CURSIVE, FANTASY, SYSTEM_UI, UI_SERIF, UI_SANS_SERIF, UI_MONOSPACE,
183+ UI_ROUNDED, MATH, FANGSONG,
184+ // Hue Interpolation
185+ HUE_INTERPOLATION, SHORTER_HUE, LONGER_HUE, INCREASING_HUE, DECREASING_HUE,
186+ HUE,
187+ // Line Style
188+ LINE_STYLE, HIDDEN, DOTTED, DASHED, SOLID, DOUBLE, GROOVE, RIDGE, INSET, OUTSET,
189+ // Image
190+ IMAGE, URL, IMAGE_SET, CROSS_FADE, ELEMENT, GRADIENT,
191+ // Overflow Position
192+ OVERFLOW_POSITION, SAFE, UNSAFE,
193+ // Overflow
194+ OVERFLOW, VISIBLE, CLIP, SCROLL, AUTO,
195+ // Transform Functions
196+ MATRIX, MATRIX3D, PERSPECTIVE, ROTATE, ROTATE3D, ROTATEX, ROTATEY, ROTATEZ, SCALE, SCALE3D, SCALEX, SCALEY, SCALEZ, TRANSLATE, TRANSLATE3D, TRANSLATEX, TRANSLATEY, TRANSLATEZ,
197+ SKEW, SKEWX, SKEWY,
198+ // URL
199+ URL,
200 // Keyword
201 PRINT, SCREEN, TOKEN, FUNC, OPERATOR, GROUP, END,
202 // Property
203diff --git a/src/parser.cc b/src/parser.cc
204index 5a1429b..f29c1c2 100755
205--- a/src/parser.cc
206+++ b/src/parser.cc
207@@ -355,6 +355,174 @@ void typeCheck(std::string key, std::string value, Unit* property, std::vector<U
208 }
209 */
210
211+static const std::unordered_map<std::string_view, unsigned int> kColors {
212+ {"black", 0x000000},
213+ {"silver", 0xc0c0c0},
214+ {"gray", 0x808080},
215+ {"white", 0xffffff},
216+ {"maroon", 0x800000},
217+ {"red", 0xff0000},
218+ {"purple", 0x800080},
219+ {"fuchsia", 0xff00ff},
220+ {"green", 0x008000},
221+ {"lime", 0x00ff00},
222+ {"olive", 0x808000},
223+ {"yellow", 0xffff00},
224+ {"navy", 0x000080},
225+ {"blue", 0x0000ff},
226+ {"teal", 0x008080},
227+ {"aqua", 0x00ffff},
228+ {"aliceblue", 0xf0f8ff},
229+ {"antiquewhite", 0xfaebd7},
230+ {"aqua", 0x00ffff},
231+ {"aquamarine", 0x7fffd4},
232+ {"azure", 0xf0ffff},
233+ {"beige", 0xf5f5dc},
234+ {"bisque", 0xffe4c4},
235+ {"black", 0x000000},
236+ {"blanchedalmond", 0xffebcd},
237+ {"blue", 0x0000ff},
238+ {"blueviolet", 0x8a2be2},
239+ {"brown", 0xa52a2a},
240+ {"burlywood", 0xdeb887},
241+ {"cadetblue", 0x5f9ea0},
242+ {"chartreuse", 0x7fff00},
243+ {"chocolate", 0xd2691e},
244+ {"coral", 0xff7f50},
245+ {"cornflowerblue", 0x6495ed},
246+ {"cornsilk", 0xfff8dc},
247+ {"crimson", 0xdc143c},
248+ {"cyan", 0x00ffff},
249+ {"darkblue", 0x00008b},
250+ {"darkcyan", 0x008b8b},
251+ {"darkgoldenrod", 0xb8860b},
252+ {"darkgray", 0xa9a9a9},
253+ {"darkgreen", 0x006400},
254+ {"darkgrey", 0xa9a9a9},
255+ {"darkkhaki", 0xbdb76b},
256+ {"darkmagenta", 0x8b008b},
257+ {"darkolivegreen", 0x556b2f},
258+ {"darkorange", 0xff8c00},
259+ {"darkorchid", 0x9932cc},
260+ {"darkred", 0x8b0000},
261+ {"darksalmon", 0xe9967a},
262+ {"darkseagreen", 0x8fbc8f},
263+ {"darkslateblue", 0x483d8b},
264+ {"darkslategray", 0x2f4f4f},
265+ {"darkslategrey", 0x2f4f4f},
266+ {"darkturquoise", 0x00ced1},
267+ {"darkviolet", 0x9400d3},
268+ {"deeppink", 0xff1493},
269+ {"deepskyblue", 0x00bfff},
270+ {"dimgray", 0x696969},
271+ {"dimgrey", 0x696969},
272+ {"dodgerblue", 0x1e90ff},
273+ {"firebrick", 0xb22222},
274+ {"floralwhite", 0xfffaf0},
275+ {"forestgreen", 0x228b22},
276+ {"fuchsia", 0xff00ff},
277+ {"gainsboro", 0xdcdcdc},
278+ {"ghostwhite", 0xf8f8ff},
279+ {"gold", 0xffd700},
280+ {"goldenrod", 0xdaa520},
281+ {"gray", 0x808080},
282+ {"green", 0x008000},
283+ {"greenyellow", 0xadff2f},
284+ {"grey", 0x808080},
285+ {"honeydew", 0xf0fff0},
286+ {"hotpink", 0xff69b4},
287+ {"indianred", 0xcd5c5c},
288+ {"indigo", 0x4b0082},
289+ {"ivory", 0xfffff0},
290+ {"khaki", 0xf0e68c},
291+ {"lavender", 0xe6e6fa},
292+ {"lavenderblush", 0xfff0f5},
293+ {"lawngreen", 0x7cfc00},
294+ {"lemonchiffon", 0xfffacd},
295+ {"lightblue", 0xadd8e6},
296+ {"lightcoral", 0xf08080},
297+ {"lightcyan", 0xe0ffff},
298+ {"lightgoldenrodyellow", 0xfafad2},
299+ {"lightgray", 0xd3d3d3},
300+ {"lightgreen", 0x90ee90},
301+ {"lightgrey", 0xd3d3d3},
302+ {"lightpink", 0xffb6c1},
303+ {"lightsalmon", 0xffa07a},
304+ {"lightseagreen", 0x20b2aa},
305+ {"lightskyblue", 0x87cefa},
306+ {"lightslategray", 0x778899},
307+ {"lightslategrey", 0x778899},
308+ {"lightsteelblue", 0xb0c4de},
309+ {"lightyellow", 0xffffe0},
310+ {"lime", 0x00ff00},
311+ {"limegreen", 0x32cd32},
312+ {"linen", 0xfaf0e6},
313+ {"magenta", 0xff00ff},
314+ {"maroon", 0x800000},
315+ {"mediumaquamarine", 0x66cdaa},
316+ {"mediumblue", 0x0000cd},
317+ {"mediumorchid", 0xba55d3},
318+ {"mediumpurple", 0x9370db},
319+ {"mediumseagreen", 0x3cb371},
320+ {"mediumslateblue", 0x7b68ee},
321+ {"mediumspringgreen", 0x00fa9a},
322+ {"mediumturquoise", 0x48d1cc},
323+ {"mediumvioletred", 0xc71585},
324+ {"midnightblue", 0x191970},
325+ {"mintcream", 0xf5fffa},
326+ {"mistyrose", 0xffe4e1},
327+ {"moccasin", 0xffe4b5},
328+ {"navajowhite", 0xffdead},
329+ {"navy", 0x000080},
330+ {"oldlace", 0xfdf5e6},
331+ {"olive", 0x808000},
332+ {"olivedrab", 0x6b8e23},
333+ {"orange", 0xffa500},
334+ {"orangered", 0xff4500},
335+ {"orchid", 0xda70d6},
336+ {"palegoldenrod", 0xeee8aa},
337+ {"palegreen", 0x98fb98},
338+ {"paleturquoise", 0xafeeee},
339+ {"palevioletred", 0xdb7093},
340+ {"papayawhip", 0xffefd5},
341+ {"peachpuff", 0xffdab9},
342+ {"peru", 0xcd853f},
343+ {"pink", 0xffc0cb},
344+ {"plum", 0xdda0dd},
345+ {"powderblue", 0xb0e0e6},
346+ {"purple", 0x800080},
347+ {"rebeccapurple", 0x663399},
348+ {"red", 0xff0000},
349+ {"rosybrown", 0xbc8f8f},
350+ {"royalblue", 0x4169e1},
351+ {"saddlebrown", 0x8b4513},
352+ {"salmon", 0xfa8072},
353+ {"sandybrown", 0xf4a460},
354+ {"seagreen", 0x2e8b57},
355+ {"seashell", 0xfff5ee},
356+ {"sienna", 0xa0522d},
357+ {"silver", 0xc0c0c0},
358+ {"skyblue", 0x87ceeb},
359+ {"slateblue", 0x6a5acd},
360+ {"slategray", 0x708090},
361+ {"slategrey", 0x708090},
362+ {"snow", 0xfffafa},
363+ {"springgreen", 0x00ff7f},
364+ {"steelblue", 0x4682b4},
365+ {"tan", 0xd2b48c},
366+ {"teal", 0x008080},
367+ {"thistle", 0xd8bfd8},
368+ {"tomato", 0xff6347},
369+ {"transparent", 0x00000000.},
370+ {"turquoise", 0x40e0d0},
371+ {"violet", 0xee82ee},
372+ {"wheat", 0xf5deb3},
373+ {"white", 0xffffff},
374+ {"whitesmoke", 0xf5f5f5},
375+ {"yellow", 0xffff00},
376+ {"yellowgreen", 0x9acd32},
377+};
378+
379 struct SuffixParse {
380 std::string_view suffix;
381 UnitType type;
382@@ -381,7 +549,17 @@ static constexpr SuffixParse table[] = {
383 {"cqb", UnitType::CQB, 3},
384 {"deg", UnitType::DEG, 3},
385 {"rad", UnitType::RAD, 3},
386+ {"khz", UnitType::KHZ, 3},
387+ {"kHz", UnitType::KHZ, 3},
388+ {"Khz", UnitType::KHZ, 3},
389+ {"KHz", UnitType::KHZ, 3},
390+ {"KHZ", UnitType::KHZ, 3},
391 {"px", UnitType::PX, 2},
392+ {"hz", UnitType::HZ, 2},
393+ {"Hz", UnitType::HZ, 2},
394+ {"HZ", UnitType::HZ, 2},
395+ {"hZ", UnitType::HZ, 2},
396+ {"ms", UnitType::MS, 2},
397 {"em", UnitType::EM, 2},
398 {"cm", UnitType::CM, 2},
399 {"ch", UnitType::CH, 2},
400@@ -396,8 +574,10 @@ static constexpr SuffixParse table[] = {
401 {"in", UnitType::IN, 2},
402 {"pc", UnitType::PC, 2},
403 {"pt", UnitType::PT, 2},
404+ {"fr", UnitType::FRACTION,2},
405 {"%", UnitType::PERCENT,1},
406 {"q", UnitType::Q, 1},
407+ {"s", UnitType::SECOND,1},
408 };
409
410 static const std::unordered_map<std::string_view, std::pair<UnitType, UnitType>> kMatch{
411@@ -431,6 +611,154 @@ static const std::unordered_map<std::string_view, std::pair<UnitType, UnitType>>
412 {"end",{UnitType::CONTENT_POSITION, UnitType::END}},
413 {"flex-start",{UnitType::CONTENT_POSITION, UnitType::FLEX_START}},
414 {"flex-end",{UnitType::CONTENT_POSITION, UnitType::FLEX_END}},
415+ {"contents",{UnitType::DISPLAY_BOX, UnitType::CONTENTS}},
416+ {"none",{UnitType::DISPLAY_BOX, UnitType::NONE}},
417+ {"flow",{UnitType::DISPLAY_INSIDE, UnitType::FLOW}},
418+ {"flow-root",{UnitType::DISPLAY_INSIDE, UnitType::FLOW_ROOT}},
419+ {"table",{UnitType::DISPLAY_INSIDE, UnitType::TABLE}},
420+ {"flex",{UnitType::DISPLAY_INSIDE, UnitType::FLEX}},
421+ {"grid",{UnitType::DISPLAY_INSIDE, UnitType::GRID}},
422+ {"ruby",{UnitType::DISPLAY_INSIDE, UnitType::RUBY}},
423+ {"table-row-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_ROW_GROUP}},
424+ {"table-header-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_HEADER_GROUP}},
425+ {"table-footer-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_FOOTER_GROUP}},
426+ {"table-column-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_COLUMN_GROUP}},
427+ {"table-row",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_ROW}},
428+ {"table-cell",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_CELL}},
429+ {"table-column",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_COLUMN}},
430+ {"table-caption",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_CAPTION}},
431+ {"ruby-base",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_BASE}},
432+ {"ruby-text",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_TEXT}},
433+ {"ruby-base-container",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_BASE_CONTAINER}},
434+ {"ruby-text-container",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_TEXT_CONTAINER}},
435+ {"inline-block",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_BLOCK}},
436+ {"inline-table",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_TABLE}},
437+ {"inline-flex",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_FLEX}},
438+ {"inline-grid",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_GRID}},
439+ {"list-item",{UnitType::DISPLAY_LISTITEM, UnitType::LISTITEM}},
440+ {"block",{UnitType::DISPLAY_OUTSIDE, UnitType::BLOCK}},
441+ {"inline",{UnitType::DISPLAY_OUTSIDE, UnitType::INLINE}},
442+ {"run-in",{UnitType::DISPLAY_OUTSIDE, UnitType::RUN_IN}},
443+ {"linear",{UnitType::EASING_FUNCTION, UnitType::LINEAR}},
444+ {"ease",{UnitType::EASING_FUNCTION, UnitType::EASE}},
445+ {"ease-in",{UnitType::EASING_FUNCTION, UnitType::EASE_IN}},
446+ {"ease-out",{UnitType::EASING_FUNCTION, UnitType::EASE_OUT}},
447+ {"ease-in-out",{UnitType::EASING_FUNCTION, UnitType::EASE_IN_OUT}},
448+ {"step-start",{UnitType::EASING_FUNCTION, UnitType::STEP_START}},
449+ {"step-end",{UnitType::EASING_FUNCTION, UnitType::STEP_END}},
450+ {"jump-start",{UnitType::EASING_FUNCTION, UnitType::JUMP_START}},
451+ {"jump-end",{UnitType::EASING_FUNCTION, UnitType::JUMP_END}},
452+ {"jump-none",{UnitType::EASING_FUNCTION, UnitType::JUMP_NONE}},
453+ {"jump-both",{UnitType::EASING_FUNCTION, UnitType::JUMP_BOTH}},
454+ {"serif",{UnitType::GENERIC_FAMILY, UnitType::SERIF}},
455+ {"sans-serif",{UnitType::GENERIC_FAMILY, UnitType::SANS_SERIF}},
456+ {"monospace",{UnitType::GENERIC_FAMILY, UnitType::MONOSPACE}},
457+ {"cursive",{UnitType::GENERIC_FAMILY, UnitType::CURSIVE}},
458+ {"fantasy",{UnitType::GENERIC_FAMILY, UnitType::FANTASY}},
459+ {"system-ui",{UnitType::GENERIC_FAMILY, UnitType::SYSTEM_UI}},
460+ {"ui-serif",{UnitType::GENERIC_FAMILY, UnitType::UI_SERIF}},
461+ {"ui-sans-serif",{UnitType::GENERIC_FAMILY, UnitType::UI_SANS_SERIF}},
462+ {"ui-monospace",{UnitType::GENERIC_FAMILY, UnitType::UI_MONOSPACE}},
463+ {"ui-rounded",{UnitType::GENERIC_FAMILY, UnitType::UI_ROUNDED}},
464+ {"math",{UnitType::GENERIC_FAMILY, UnitType::MATH}},
465+ {"fangsong",{UnitType::GENERIC_FAMILY, UnitType::FANGSONG}},
466+ {"top",{UnitType::POSITION, UnitType::TOP}},
467+ {"left",{UnitType::POSITION, UnitType::LEFT}},
468+ {"bottom",{UnitType::POSITION, UnitType::BOTTOM}},
469+ {"right",{UnitType::POSITION, UnitType::RIGHT}},
470+ {"center",{UnitType::POSITION, UnitType::CENTER}},
471+ {"inline-start",{UnitType::POSITION, UnitType::INLINE_START}},
472+ {"inline-end",{UnitType::POSITION, UnitType::INLINE_END}},
473+ {"block-start",{UnitType::POSITION, UnitType::BLOCK_START}},
474+ {"block-end",{UnitType::POSITION, UnitType::BLOCK_END}},
475+ {"self-start",{UnitType::POSITION, UnitType::SELF_START}},
476+ {"self-end",{UnitType::POSITION, UnitType::SELF_END}},
477+ {"flex-start",{UnitType::POSITION, UnitType::FLEX_START}},
478+ {"flex-end",{UnitType::POSITION, UnitType::FLEX_END}},
479+ {"circle",{UnitType::SHAPE, UnitType::CIRCLE}},
480+ {"ellipse",{UnitType::SHAPE, UnitType::ELLIPSE}},
481+ {"shorter hue",{UnitType::HUE_INTERPOLATION, UnitType::SHORTER_HUE}},
482+ {"longer hue",{UnitType::HUE_INTERPOLATION, UnitType::LONGER_HUE}},
483+ {"increasing hue",{UnitType::HUE_INTERPOLATION, UnitType::INCREASING_HUE}},
484+ {"decreasing hue",{UnitType::HUE_INTERPOLATION, UnitType::DECREASING_HUE}},
485+ {"hidden",{UnitType::LINE_STYLE, UnitType::HIDDEN}},
486+ {"dotted",{UnitType::LINE_STYLE, UnitType::DOTTED}},
487+ {"dashed",{UnitType::LINE_STYLE, UnitType::DASHED}},
488+ {"solid",{UnitType::LINE_STYLE, UnitType::SOLID}},
489+ {"double",{UnitType::LINE_STYLE, UnitType::DOUBLE}},
490+ {"groove",{UnitType::LINE_STYLE, UnitType::GROOVE}},
491+ {"ridge",{UnitType::LINE_STYLE, UnitType::RIDGE}},
492+ {"inset",{UnitType::LINE_STYLE, UnitType::INSET}},
493+ {"outset",{UnitType::LINE_STYLE, UnitType::OUTSET}},
494+ {"baseline",{UnitType::BASELINE, UnitType::FIRST}},
495+ {"first baseline",{UnitType::BASELINE, UnitType::FIRST}},
496+ {"last baseline",{UnitType::BASELINE, UnitType::LAST}},
497+ {"safe",{UnitType::OVERFLOW_POSITION, UnitType::SAFE}},
498+ {"unsafe",{UnitType::OVERFLOW_POSITION, UnitType::UNSAFE}},
499+ {"visible",{UnitType::OVERFLOW, UnitType::VISIBLE}},
500+ {"clip",{UnitType::OVERFLOW, UnitType::CLIP}},
501+ {"scroll",{UnitType::OVERFLOW, UnitType::SCROLL}},
502+ {"auto",{UnitType::OVERFLOW, UnitType::AUTO}},
503+};
504+
505+/*
506+ Note to self:
507+ make a kMap object that will map values that have conflicts like none
508+ In another function use the key to find the type
509+
510+ overflow: hidden
511+
512+ what to do about strings
513+*/
514+
515+static const std::unordered_map<std::string_view, UnitType> kFunc{
516+ {"calc", UnitType::CALC},
517+ {"min", UnitType::MIN},
518+ {"rgb", UnitType::RGB},
519+ {"rgba", UnitType::RGBA},
520+ {"hsl", UnitType::HSL},
521+ {"linear", UnitType::LINEAR_EASING_FUNCTION},
522+ {"cubic-bezier", UnitType::CUBIC_BEZIER_FUNCTION},
523+ {"steps", UnitType::STEPS_FUNCTION},
524+ {"blur", UnitType::BLUR},
525+ {"brightness", UnitType::BRIGHTNESS},
526+ {"contrast", UnitType::CONTRAST},
527+ {"drop-shadow", UnitType::DROP_SHADOW},
528+ {"grayscale", UnitType::GRAYSCALE},
529+ {"hue-rotate", UnitType::HUE_ROTATE},
530+ {"invert", UnitType::INVERT},
531+ {"opacity", UnitType::OPACITY},
532+ {"sepia", UnitType::SEPIA},
533+ {"saturate", UnitType::SATURATE},
534+ {"image", UnitType::IMAGE},
535+ {"image-set", UnitType::IMAGE_SET},
536+ {"cross-fade", UnitType::CROSS_FADE},
537+ {"element", UnitType::ELEMENT},
538+ {"gradient", UnitType::GRADIENT},
539+ {"matrix", UnitType::MATRIX},
540+ {"matrix3d", UnitType::MATRIX3D},
541+ {"perspective", UnitType::PERSPECTIVE},
542+ {"rotate", UnitType::ROTATE},
543+ {"rotate3d", UnitType::ROTATE3D},
544+ {"rotateX", UnitType::ROTATEX},
545+ {"rotateY", UnitType::ROTATEY},
546+ {"rotateZ", UnitType::ROTATEZ},
547+ {"scale", UnitType::SCALE},
548+ {"scale3d", UnitType::SCALE3D},
549+ {"scaleX", UnitType::SCALEX},
550+ {"scaleY", UnitType::SCALEY},
551+ {"scaleZ", UnitType::SCALEZ},
552+ {"translate", UnitType::TRANSLATE},
553+ {"translate3d", UnitType::TRANSLATE3D},
554+ {"translateX", UnitType::TRANSLATEX},
555+ {"translateY", UnitType::TRANSLATEY},
556+ {"translateZ", UnitType::TRANSLATEZ},
557+ {"skew", UnitType::SKEW},
558+ {"skewX", UnitType::SKEWX},
559+ {"skewY", UnitType::SKEWY},
560+ {"url", UnitType::URL},
561+
562+ {"", UnitType::GROUP}
563 };
564
565 static const std::unordered_map<std::string_view, float> kAbsSize{
566@@ -470,6 +798,9 @@ std::vector<Unit> getUnit(std::string value) {
567 buffer.push_back(v);
568 continue;
569 } else if (v == ')') {
570+ /*
571+ Function handling
572+ */
573 // We are at the end of the parentheseses and we need to pass it for more parsing
574 std::string name;
575 bool nameset = false;
576@@ -488,22 +819,11 @@ std::vector<Unit> getUnit(std::string value) {
577
578 Unit unit;
579
580- if (name == "calc") {
581- unit.type = UnitType::CALC;
582- } else if (name == "min") {
583- unit.type = UnitType::MIN;
584- } else if (name == "rgb") {
585- unit.type = UnitType::RGB;
586- } else if (name == "rgba") {
587- unit.type = UnitType::RGBA;
588- } else if (name == "hsl") {
589- unit.type = UnitType::HSL;
590- } else if (name == "hwb") {
591- unit.type = UnitType::HWB;
592- } else if (name == "") {
593- unit.type = UnitType::GROUP;
594+ if (auto it = kFunc.find(name); it != kFunc.end()) {
595+ unit.type = it->second;
596 }
597
598+ // The value of the function is the child count
599 unit.value.INT = children.size();
600
601 units.push_back(unit);
602@@ -520,9 +840,19 @@ std::vector<Unit> getUnit(std::string value) {
603
604 bool found = false;
605 if (auto it = kMatch.find(buffer); it != kMatch.end()) {
606+ /*
607+ Keyword Matching
608+ */
609 unit.type = it->second.first;
610 unit.value.ENUM = it->second.second;
611 found = true;
612+ } else if (auto it = kColor.find(buffer); it != kColor.end()) {
613+ /*
614+ Color Matching
615+ */
616+ unit.type = UnitType::HEX;
617+ unit.value.ENUM = it->second;
618+ found = true;
619 } else {
620 for (const auto& [suffix, type, trim] : table) {
621 if (buffer.ends_with(suffix)) {
622@@ -536,19 +866,19 @@ std::vector<Unit> getUnit(std::string value) {
623
624 if (!found) {
625 if (buffer.starts_with("#")) {
626+ /*
627+ # Prefix for HEX codes
628+ */
629 unit.type = UnitType::HEX;
630 unit.value.UINT = std::stoul(buffer.substr(1), nullptr, 16);
631 found = true;
632 } else if (auto it = kAbsSize.find(buffer); it != kAbsSize.end()) {
633+ /*
634+ Absolute size matching
635+ */
636 unit.type = UnitType::EM;
637 unit.value.FLOAT = it->second;
638 found = true;
639- } else if (buffer.ends_with("baseline")) {
640- unit.type = UnitType::BASELINE;
641- if (buffer.starts_with("first")) unit.value.ENUM = UnitType::FIRST;
642- else if (buffer.starts_with("last")) unit.value.ENUM = UnitType::LAST;
643- else unit.value.ENUM = UnitType::FIRST;
644- found = true;
645 } else {
646 // Maybe its a number?
647 try {
648diff --git a/src/parser.cc.bak b/src/parser.cc.bak
649deleted file mode 100755
650index 2578022..0000000
651--- a/src/parser.cc.bak
652+++ /dev/null
653@@ -1,804 +0,0 @@
654-#include "grim.h"
655-#include <iostream>
656-#include <fstream>
657-#include <sstream>
658-#include <unordered_map>
659-#include <cctype>
660-#include <algorithm>
661-#include <cmath>
662-#include <string_view>
663-
664-std::unordered_map<std::string, std::string> parseAttributes(std::string_view token) {
665- std::unordered_map<std::string, std::string> attrs;
666-
667- bool inQuote = false;
668- bool escaped = false;
669- char quoteType = '"';
670-
671- std::string word;
672- for (unsigned short i = 0; i < token.length(); i++) {
673- char current = token[i];
674- if ((current == '"' || current == '\'') && !escaped) {
675- if (inQuote && current == quoteType) {
676- inQuote = false;
677- } else if (!inQuote) {
678- inQuote = true;
679- quoteType = current;
680- }
681- }
682-
683- if (current == '\\') { //'
684- escaped = true;
685- continue;
686- }
687-
688- if ((!std::isspace(current) || inQuote) && i != token.length()-1) {
689- word += current;
690- } else {
691- if (i == token.length()-1) {
692- word += current;
693- }
694-
695- std::string name = "";
696- std::string value = "";
697- bool setValue = false;
698-
699- for (auto c : word) {
700- if (c == '=') {
701- setValue = true;
702- continue;
703- }
704-
705- if (setValue) {
706- value += c;
707- } else {
708- name += c;
709- }
710- }
711-
712- word = "";
713-
714- std::string trimmedName = "";
715- for (auto c : name) {
716- if (!std::isspace(c)) {
717- trimmedName += c;
718- }
719- }
720-
721- if (attrs.size() == 0) {
722- value = '"'+trimmedName+'"';
723- trimmedName = "tagName";
724- }
725-
726- std::string trimmedValue = "";
727- int sliceStart = 0;
728- int sliceEnd = value.length();
729-
730- if (value.length() >= 2) {
731- for (unsigned short t = 0; t < value.length(); t++) {
732- if (!std::isspace(value[t])) {
733- sliceStart = t;
734- break;
735- }
736- }
737-
738- for (int t = value.length()-1; t >= 0; t--) {
739- // Trim the trailing / on self closing elements if there isn't a space inbetween
740- if (!std::isspace(value[t]) && value[t] != '/') {
741- sliceEnd = t;
742- break;
743- }
744- }
745-
746- // Add and subtract 1 from each side to remove quotes
747- for (unsigned short t = sliceStart+1; t < sliceEnd; t++) {
748- trimmedValue += value[t];
749- }
750- }
751-
752- attrs[trimmedName] = trimmedValue;
753- }
754- }
755-
756- return attrs;
757-}
758-
759-std::unique_ptr<Node> parseHTML(std::istream& inputStream) {
760- std::unique_ptr<Node> root = std::make_unique<Node>();
761- root->setTagName("root");
762-
763- Node* currentNode = root.get();
764-
765- bool inTag = false;
766- bool escaped = false;
767- bool inQuote = false;
768- bool inComment = false;
769- bool waitToClose = false;
770- char quoteType = '"';
771-
772- std::string token;
773-
774- char current;
775- while (inputStream.get(current)) {
776- // Finds the --> and removes it then resets inComment
777- if (inComment) {
778- // added the peek to prevent hitting on every -
779- if (current == '-' && inputStream.peek() == '-') {
780- char a,b;
781- // load the next two
782- if (inputStream.get(a) && inputStream.get(b)) {
783- // We know a == -
784- if (b == '>') {
785- // Close the comment
786- inComment = false;
787- }
788- }
789-
790- if (!inComment) {
791- // we don't put anything back and that puts us where we need to be
792- continue;
793- } else {
794- // Not the end
795- inputStream.putback(b);
796- inputStream.putback(a);
797- }
798- }
799- continue;
800- }
801-
802- std::string tagName = currentNode->getTagName();
803- if (!waitToClose && (
804- tagName == "style" ||
805- tagName == "script" ||
806- tagName == "textarea"
807- ) && current == '<' && inputStream.peek() == '/' ) {
808- // If its the starting of a closing tag and we are inside of a special tag
809- // we need to see if the upcoming closing tag is the correct closing tag
810- // if it is then we put the read ahead back and waitToClose. This will let normal parsing
811- // continue
812- const size_t readTo = tagName.length()+2;
813- std::string buffer(readTo, '\0');
814-
815- inputStream.read(&buffer[0], readTo);
816-
817- if (buffer == "/"+tagName+">") {
818- waitToClose = true;
819- } else {
820- token += current;
821- }
822-
823- for (int i = readTo-1; i>= 0; i--) {
824- inputStream.putback(buffer[i]);
825- }
826- if (!waitToClose) {
827- continue;
828- }
829- } else if (!waitToClose && (
830- tagName == "style" ||
831- tagName == "script" ||
832- tagName == "textarea"
833- )) {
834- token += current;
835- continue;
836- }
837-
838- if (inTag) {
839- if ((current == '"' || current == '\'') && !escaped) {
840- if (inQuote && current == quoteType) {
841- inQuote = false;
842- } else if (!inQuote) {
843- inQuote = true;
844- quoteType = current;
845- }
846- }
847-
848- if (current == '>' && !inQuote && !escaped) {
849- inTag = false;
850- waitToClose = false;
851- // Even if the next tag is next still add a text tag as we can just check if its empty and remove it
852- // this check would still have to be done either way so we aren't wasting anything
853- if (token.length() > 0) {
854- bool empty = true;
855- bool closingTag = false;
856- for (size_t i = 0; i < token.length(); i++) {
857- auto c = token[i];
858- if (std::isspace(c)) {
859- continue;
860- } else if (c == '/') {
861- closingTag = true;
862- } else {
863- empty = false;
864- break;
865- }
866- }
867-
868- bool selfClosing = false;
869- int selfClosingPosition = token.length()-1;
870- if (!closingTag) {
871- for (int i = token.length()-1; i >= 0; i--) {
872- auto c = token[i];
873- if (std::isspace(c)) {
874- continue;
875- } else if (c == '/') {
876- selfClosingPosition = i;
877- selfClosing = true;
878- break;
879- } else {
880- break;
881- }
882- }
883- }
884-
885- if (!empty) {
886- if (selfClosing) {
887- //Create element and don't jump inside
888- // Use node instead of currentNode because we do not need to jump into the created element
889- auto attrs = parseAttributes(token.substr(0, selfClosingPosition));
890- auto node = currentNode->createElement(attrs["tagName"]);
891- for (auto const& pair : attrs) {
892- // All attributes are stored as strings so we can just throw them in
893- node->setAttribute(pair.first, pair.second);
894- }
895- } else if (closingTag) {
896- // Checksum and tree move
897- std::string tagName = "";
898- for (auto t : token) {
899- if (!std::isspace(t) && t != '/') {
900- tagName += t;
901- } else if (t == '/') {
902- // For closing tags we just want the name
903- continue;
904- } else if (tagName.length() > 0) {
905- break;
906- }
907- }
908- if (currentNode->getTagName() == tagName) {
909- currentNode = currentNode->parent;
910- } else {
911- std::cerr << "malformed html: closing tag (</" << tagName << ">) found for <" << currentNode->getTagName() << ">" << std::endl;
912- }
913- } else {
914- // Create a element and jump inside
915- auto attrs = parseAttributes(token);
916- // Don't add elements like <!DOCTYPE>
917- if (attrs["tagName"][0] != '!') {
918- currentNode = currentNode->createElement(attrs["tagName"]);
919- for (auto const& pair : attrs) {
920- // All attributes are stored as strings so we can just throw them in
921- currentNode->setAttribute(pair.first, pair.second);
922- }
923- }
924- }
925- }
926- }
927-
928- token = "";
929- continue;
930- }
931- } else if (!escaped && current == '<') {
932- // if the next charector is a !
933- if (inputStream.peek() == '!') {
934- char a,b,c;
935- // load the next three charecters (includes !)
936- if (inputStream.get(a) && inputStream.get(b) && inputStream.get(c)) {
937- // We know a == !
938- if (b == '-' && c == '-') {
939- inComment = true;
940- }
941- }
942-
943- if (inComment) {
944- continue;
945- } else {
946- // Not a comment add all back
947- inputStream.putback(c);
948- inputStream.putback(b);
949- inputStream.putback(a);
950- }
951- }
952- inTag = true;
953-
954- // Heres where you actually make the text node and above the real nodes
955- // can also prob make the vector of tokens a single variable
956- // it really just needs to be a data string bc we know the type based on inTag
957-
958-
959- bool hasText = false;
960- for (auto t : token) {
961- if (!std::isspace(t)) {
962- hasText = true;
963- break;
964- }
965- }
966-
967- // TODO: Add a vector that stores inner text and when elements start to close out pop them but add all to their innerText
968- // | Will need something simular for innerHTML
969- if (hasText) {
970- auto node = currentNode->createElement("text");
971- node->setAttribute("innerText", token);
972- }
973-
974-
975- token = "";
976- continue;
977- }
978-
979- escaped = false;
980-
981- if (current == '\\') { //'
982- escaped = true;
983- continue;
984- }
985-
986- token += current;
987- }
988-
989- return root;
990-}
991-
992-
993-void typeCheck(std::string key, std::string value, Unit* property, std::vector<UnitType> allowedTypes) {
994- for (size_t i = 0; i < property->children.size(); i++) {
995- bool allowed = false;
996- for (size_t j = 0; j < allowedTypes.size(); j++) {
997- if (property->children[i].type == allowedTypes[j]) {
998- allowed = true;
999- break;
1000- }
1001- }
1002-
1003- if (!allowed) {
1004- std::cerr << "Invalid value of property: " << key << " Value: " << value << std::endl;
1005- std::exit(10);
1006- }
1007- }
1008-}
1009-
1010-struct SuffixParse {
1011- std::string_view suffix;
1012- UnitType type;
1013- int trim; // chars to strip from the right
1014-};
1015-
1016-static constexpr SuffixParse table[] = {
1017- {"cqmin", UnitType::CQMIN, 5},
1018- {"cqmax", UnitType::CQMAX, 5},
1019- {"rcap", UnitType::RCAP, 4},
1020- {"vmax", UnitType::VMAX, 4},
1021- {"vmin", UnitType::VMIN, 4},
1022- {"cap", UnitType::CAP, 3},
1023- {"rch", UnitType::RCH, 3},
1024- {"rem", UnitType::REM, 3},
1025- {"rex", UnitType::REX, 3},
1026- {"ric", UnitType::RIC, 3},
1027- {"rlh", UnitType::RLH, 3},
1028- {"cqw", UnitType::CQW, 3},
1029- {"cqh", UnitType::CQH, 3},
1030- {"cqi", UnitType::CQI, 3},
1031- {"cqb", UnitType::CQB, 3},
1032- {"px", UnitType::PX, 2},
1033- {"em", UnitType::EM, 2},
1034- {"cm", UnitType::CM, 2},
1035- {"ch", UnitType::CH, 2},
1036- {"ex", UnitType::EX, 2},
1037- {"ic", UnitType::IC, 2},
1038- {"lh", UnitType::LH, 2},
1039- {"vh", UnitType::VH, 2},
1040- {"vw", UnitType::VW, 2},
1041- {"vb", UnitType::VB, 2},
1042- {"vi", UnitType::VI, 2},
1043- {"mm", UnitType::MM, 2},
1044- {"in", UnitType::IN, 2},
1045- {"pc", UnitType::PC, 2},
1046- {"pt", UnitType::PT, 2},
1047- {"%", UnitType::PERCENT,1},
1048- {"q", UnitType::Q, 1},
1049-};
1050-
1051-std::vector<Unit> getUnit(std::string value) {
1052- std::vector<Unit> units;
1053- std::vector<Unit> children;
1054-
1055-
1056- std::string buffer = "";
1057- std::string parenthesesesBuffer = "";
1058- bool inParentheses = false;
1059- bool inQuotes = false;
1060- // Needs to not be empty but can't be a quote
1061- char quoteType = 'a';
1062- bool escaped = false;
1063-
1064- for (size_t i = 0; i < value.length(); i++) {
1065- char v = value[i];
1066- if (v == '\\' && !escaped) escaped = true;
1067-
1068- if (inParentheses) {
1069- parenthesesesBuffer.push_back(v);
1070- }
1071-
1072- // The way this is setup to parse func() calls is like so
1073- // | calc(1px, 2px);
1074- // | -> value of 1px, 2px get's put into getUnit()
1075- // | once those are pulled into children
1076- // | the buffer only contains calc
1077- // | add the children to the parsed keyword
1078-
1079-
1080- if (v == '(' && !inParentheses && !inQuotes) inParentheses = true;
1081- else if (v == ')' && inParentheses && !inQuotes) {
1082- children = getUnit(parenthesesesBuffer);
1083- inParentheses = false;
1084- parenthesesesBuffer.clear();
1085- } else if ((v == '"' || v == '\'') && !inParentheses) {
1086- if (inQuotes && v == quoteType) {
1087- inQuotes = false;
1088- } else if (!inQuotes) {
1089- quoteType = v;
1090- inQuotes = true;
1091- }
1092-
1093- } else if ((!inQuotes && !inParentheses && (v == ',' || std::isspace(v))) || i >= value.length()-1) {
1094- if (buffer.length() == 0) continue;
1095- if (v != ',' && !std::isspace(v)) buffer.push_back(v);
1096-
1097- Unit unit;
1098-
1099- // Split by spaces into parts
1100-
1101- bool found = false;
1102-
1103- for (const auto& [suffix, type, trim] : table) {
1104- if (buffer.ends_with(suffix)) {
1105- unit.value.FLOAT = std::stof(std::string(buffer.substr(0, buffer.size() - trim)));
1106- unit.type = type;
1107- found = true;
1108- break;
1109- }
1110- }
1111-
1112- if (!found) {
1113- if (buffer.starts_with("#")) {
1114- unit.type = UnitType::HEX;
1115- unit.value.UINT = std::stoul(buffer.substr(1), nullptr, 16);
1116- found = true;
1117- } else if (buffer == "xx-small" || buffer == "x-small" || buffer == "small" || buffer == "medium" ||
1118- buffer == "large" || buffer == "x-large" || buffer == "xx-large" || buffer == "xxx-large" ) {
1119- // <absolute-size> read as a EM
1120- unit.type = UnitType::EM;
1121-
1122- if (buffer == "xx-small") unit.value.FLOAT = 0.6;
1123- else if (buffer == "x-small") unit.value.FLOAT = 0.75;
1124- else if (buffer == "small") unit.value.FLOAT = 0.89;
1125- else if (buffer == "medium") unit.value.FLOAT = 1;
1126- else if (buffer == "large") unit.value.FLOAT = 1.2;
1127- else if (buffer == "x-large") unit.value.FLOAT = 1.5;
1128- else if (buffer == "xx-large") unit.value.FLOAT = 2;
1129- else if (buffer == "xxx-large") unit.value.FLOAT = 3;
1130- found = true;
1131- } else if (buffer.ends_with("baseline")) {
1132- unit.type = UnitType::BASELINE;
1133- std::cout << buffer << std::endl;
1134- if (buffer.starts_with("first")) unit.value.ENUM = UnitType::FIRST;
1135- else if (buffer.starts_with("last")) unit.value.ENUM = UnitType::LAST;
1136- else unit.value.ENUM = UnitType::FIRST;
1137- found = true;
1138- } else if (buffer.ends_with("-box")) {
1139- unit.type = UnitType::BOX_EDGE;
1140-
1141- if (buffer.starts_with("content")) unit.value.ENUM = UnitType::CONTENT;
1142- else if (buffer.starts_with("padding")) unit.value.ENUM = UnitType::PADDING;
1143- else if (buffer.starts_with("border")) unit.value.ENUM = UnitType::BORDER;
1144- else if (buffer.starts_with("margin")) unit.value.ENUM = UnitType::MARGIN;
1145- else if (buffer.starts_with("fill")) unit.value.ENUM = UnitType::FILL;
1146- else if (buffer.starts_with("stroke")) unit.value.ENUM = UnitType::STROKE;
1147- else if (buffer.starts_with("view")) unit.value.ENUM = UnitType::VIEW;
1148- found = true;
1149- }
1150- }
1151-
1152- if (found) {
1153- // Only process if its found
1154-
1155- if (children.size() > 0) {
1156- unit.children = children;
1157- children.clear();
1158- }
1159-
1160- units.push_back(unit);
1161-
1162- buffer.clear();
1163- }
1164- } else {
1165- buffer.push_back(v);
1166- }
1167-
1168- escaped = false;
1169- if (v == '\\') escaped = true;
1170-
1171- }
1172-
1173- return units;
1174-}
1175-
1176-void StyleHandler::parseStream(std::istream& inputStream) {
1177- // nowhitespace: value(can have whitespace); = property
1178- // a selector name is anything before a { up to a ; or a }
1179- Sheet* root = &window->CSS.root;
1180-
1181- Sheet* current = root;
1182- // how to handle @import
1183-
1184- std::string buffer;
1185-
1186- bool incomment = false;
1187-
1188- char ch;
1189- while (inputStream.get(ch)) {
1190- if (ch == '*' && inputStream.peek() == '/') {
1191- incomment = false;
1192- // Skip ahead to the next letter so we don't caputure the trailing /
1193- inputStream.get(ch);
1194- continue;
1195- }
1196- if (ch == '/' && inputStream.peek() == '*') {
1197- incomment = true;
1198- }
1199-
1200- if (incomment) {
1201- continue;
1202- }
1203-
1204- if (ch == '{') {
1205- for (size_t i = buffer.length()-1; i >= 0; i--) {
1206- if (std::isspace(buffer[i])) {
1207- buffer.pop_back();
1208- } else {
1209- break;
1210- }
1211- }
1212-
1213- // Parse the selector into its parts
1214- std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
1215-
1216- if (current->selector.size() > 0) {
1217- // To be able to handle a subsutution with a parent that has h1, h2
1218- // we need to rebuild the selector so we can add new copies
1219- std::vector<std::vector<std::string>> subd;
1220-
1221- // Look for any & if its a style and replace it with the parsed parent selector
1222- for (size_t i = 0; i < parts.size(); i++) {
1223- bool hasAmp = false;
1224- for (size_t e = 0; e < parts[i].size(); e++) {
1225- if (parts[i][e] == "&") {
1226- hasAmp = true;
1227- break;
1228- }
1229- }
1230-
1231- if (hasAmp) {
1232- // If it contains a amp then we need replace the amp with each parent selector
1233- // Inject each part of the parent
1234- // Parent [[h1],[h2]]
1235- // Child: [[& .class, &, &]]
1236- // Result: [[h1 .class, h1, h1]]
1237- // [[h2 .class, h2, h2]]
1238- for (size_t e = 0; e < current->selector.size(); e++) {
1239- std::vector<std::string> temp;
1240- for (size_t f = 0; f < parts[i].size(); f++) {
1241- if (parts[i][f] == "&") {
1242- for (auto p : current->selector[e]) {
1243- temp.push_back(p);
1244- }
1245- } else {
1246- temp.push_back(parts[i][f]);
1247- }
1248- }
1249- subd.push_back(temp);
1250- }
1251- } else {
1252- // If theres nothing to replace just add to back
1253- subd.push_back(parts[i]);
1254- }
1255- }
1256-
1257- parts = subd;
1258- }
1259-
1260- // Find who the parent is
1261- Sheet newSheet;
1262- newSheet.parent = current;
1263- newSheet.selector = parts;
1264- current->children.push_back(newSheet);
1265-
1266- current = ¤t->children.back();
1267-
1268- // here we need to take the selector (buffer)
1269- // and find out what type it is. Also need to manage the nesting
1270- if (parts[0][0][0] == '@') {
1271- if (parts[0][0] == "@container") {
1272- current->type = SheetType::CONTAINER;
1273- bool hasName = false;
1274- if (parts[0].size() >= 3) {
1275- // @container not (width < 400px)
1276- if (parts[0][2] != "not") {
1277- // @container (width > 400px) or|and (height > 400px)
1278- if (parts[0].size() >= 5) {
1279- if (parts[0][5] != "and" || parts[0][5] != "or") {
1280- current->name = parts[0][2];
1281- hasName = true;
1282- }
1283- }
1284- }
1285- }
1286- // If a name is present then remove the name and tag from the selector
1287- // else just remove the @container
1288- if (hasName) {
1289- current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 3, current->selector[0].end());
1290- } else {
1291- current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 1, current->selector[0].end());
1292- }
1293- } else if (parts[0][0] == "@counter-style") {
1294- current->name = parts[0][2];
1295- current->type = SheetType::COUNTER;
1296- } else if (parts[0][0] == "@font-face") {
1297- current->type = SheetType::FONTFACE;
1298- } else if (parts[0][0] == "@font-feature") {
1299- current->type = SheetType::FONTFEATURE;
1300- } else if (parts[0][0] == "@swash") {
1301- current->type = SheetType::SWASH;
1302- } else if (parts[0][0] == "@annotation") {
1303- current->type = SheetType::ANNOTATION;
1304- } else if (parts[0][0] == "@ornaments") {
1305- current->type = SheetType::ORNAMENTS;
1306- } else if (parts[0][0] == "@stylistic") {
1307- current->type = SheetType::STYLISTIC;
1308- } else if (parts[0][0] == "@styleset") {
1309- current->type = SheetType::STYLESET;
1310- } else if (parts[0][0] == "@character-varient") {
1311- current->type = SheetType::CHARACTERVARIANT;
1312- } else if (parts[0][0] == "@font-palette-values") {
1313- current->type = SheetType::FONTPALETTEVALUES;
1314- current->name = parts[0][2];
1315- } else if (parts[0][0] == "@keyframes") {
1316- current->type = SheetType::KEYFRAMES;
1317- current->name = parts[0][2];
1318- } else if (parts[0][0] == "@layer") {
1319- current->type = SheetType::LAYER;
1320- } else if (parts[0][0] == "@media") {
1321- current->type = SheetType::MEDIA;
1322- } else if (parts[0][0] == "@property") {
1323- current->type = SheetType::PROPERTY;
1324- current->name = parts[0][2];
1325- } else if (parts[0][0] == "@starting-style") {
1326- current->type = SheetType::STARTINGSTYLE;
1327- }
1328- } else {
1329- current->type = SheetType::STYLE;
1330- }
1331-
1332-
1333- buffer.clear();
1334- } else if (ch == '}') {
1335- // Calculate the basemap (more info in grim.h)
1336- std::vector<std::string> targetParts = current->selector[current->selector.size()-1];
1337- for (auto p : targetParts) {
1338- if (current->parent->basemap.find(p) != current->parent->basemap.end()) {
1339- current->parent->basemap[p].push_back(window->CSS.index);
1340- } else {
1341- std::vector<size_t> bm = {window->CSS.index};
1342- current->parent->basemap[p] = bm;
1343- }
1344- }
1345-
1346- window->CSS.index++;
1347-
1348- if (current->parent != nullptr) {
1349- current = current->parent;
1350- }
1351-
1352- buffer.clear();
1353- } else if (ch == ';') {
1354- if (buffer[0] == '@') {
1355- // Single line at-rule
1356- Sheet inlineRule;
1357- std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
1358- inlineRule.selector = parts;
1359-
1360- if (parts[0][0] == "@import") {
1361- inlineRule.path = parts[0][2];
1362-
1363- if (parts[0].size() > 3) {
1364- // See if the last word ends in )
1365- // if not then its the name of the layer
1366- if (parts[0].back().back() != ')') {
1367- inlineRule.name = parts[0].back();
1368- }
1369- }
1370-
1371- } else if (parts[0][0] == "@layer") {
1372- // ISSUE: need to add speficity
1373-
1374- }
1375-
1376- current->children.push_back(inlineRule);
1377-
1378- } else {
1379- // end of a style property
1380- std::string key;
1381- std::string value;
1382- bool keyFound = false;
1383- bool firstValue = false;
1384- for (size_t i = 0; i < buffer.length(); i++) {
1385- char c = buffer[i];
1386- if (!keyFound && c == ':') {
1387- keyFound = true;
1388- } else if (!std::isspace(c) && !keyFound) {
1389- key += c;
1390- } else if (!firstValue && keyFound && !std::isspace(c)) {
1391- firstValue = true;
1392- value += c;
1393- } else if (keyFound && firstValue && !(std::isspace(c) && i < buffer.length()-1 && std::isspace(buffer[i+1]))) {
1394- // if the key is found and the charactor isn't a ':'
1395- // also (if c is a space and the next c will be a space)
1396- // this is to auto trim duplicate spaces from the value
1397- value += c;
1398- }
1399- }
1400-
1401- if (key.length() > 2 && key[0] == '-' && key[1] == '-') {
1402- current->variables[key] = value;
1403- } else {
1404- current->properties[key] = value;
1405- }
1406- }
1407- buffer.clear();
1408- } else {
1409- buffer.push_back(ch);
1410- }
1411- }
1412-}
1413-
1414-std::unordered_map<std::string, std::string> parseCSSInline(std::string inlineStyles) {
1415- std::unordered_map<std::string, std::string> props;
1416-
1417- std::string buffer;
1418-
1419- for (size_t i = 0; i < inlineStyles.length(); i++) {
1420- char ch = inlineStyles[i];
1421-
1422- if (ch == ';' || i >= inlineStyles.length()-1) {
1423- // If this is a ';' then it will be removed in the last else if statement
1424- buffer.push_back(ch);
1425- std::string key;
1426- std::string value;
1427- bool keyFound = false;
1428- for (size_t i = 0; i < buffer.length(); i++) {
1429- char c = buffer[i];
1430- if (!keyFound && c == ':') {
1431- keyFound = true;
1432- } else if (!std::isspace(c) && !keyFound) {
1433- key += c;
1434- } else if (keyFound &&
1435- !(std::isspace(c) && i < buffer.length()-1 && std::isspace(buffer[i+1])) &&
1436- c != ';'
1437- ) {
1438- // if the key is found and the charactor isn't a ':'
1439- // also (if c is a space and the next c will be a space)
1440- // this is to auto trim duplicate spaces from the value
1441- value += c;
1442-
1443- }
1444- }
1445-
1446- props[key] = value;
1447-
1448- buffer.clear();
1449- } else {
1450- buffer.push_back(ch);
1451- }
1452- }
1453-
1454- return props;
1455-}
1456-
1457-
1458diff --git a/tests/.css_unit.cc.swp b/tests/.css_unit.cc.swp
1459deleted file mode 100644
1460index 9fda70f..0000000
1461Binary files a/tests/.css_unit.cc.swp and /dev/null differ
1462diff --git a/tests/css_unit.cc b/tests/css_unit.cc
1463index ca96159..9457dc9 100644
1464--- a/tests/css_unit.cc
1465+++ b/tests/css_unit.cc
1466@@ -718,7 +718,171 @@ TEST_CASE("getUnit can parse color values") {
1467 REQUIRE(t[0].type == UnitType::CONTENT_DISTRIBUTION);
1468 REQUIRE(t[0].value.ENUM == UnitType::STRETCH);
1469 }
1470-
1471+ SECTION("content-position center") {
1472+ std::vector<Unit> t = getUnit("center");
1473+ REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1474+ REQUIRE(t[0].value.ENUM == UnitType::CENTER);
1475+ }
1476+ SECTION("content-position start") {
1477+ std::vector<Unit> t = getUnit("start");
1478+ REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1479+ REQUIRE(t[0].value.ENUM == UnitType::START);
1480+ }
1481+ SECTION("content-position end") {
1482+ std::vector<Unit> t = getUnit("end");
1483+ REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1484+ REQUIRE(t[0].value.ENUM == UnitType::END);
1485+ }
1486+ SECTION("content-position flex-start") {
1487+ std::vector<Unit> t = getUnit("flex-start");
1488+ REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1489+ REQUIRE(t[0].value.ENUM == UnitType::FLEX_START);
1490+ }
1491+ SECTION("content-position flex-end") {
1492+ std::vector<Unit> t = getUnit("flex-end");
1493+ REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1494+ REQUIRE(t[0].value.ENUM == UnitType::FLEX_END);
1495+ }
1496+ SECTION("display-box contents") {
1497+ std::vector<Unit> t = getUnit("contents");
1498+ REQUIRE(t[0].type == UnitType::DISPLAY_BOX);
1499+ REQUIRE(t[0].value.ENUM == UnitType::CONTENTS);
1500+ }
1501+ SECTION("display-box none") {
1502+ std::vector<Unit> t = getUnit("none");
1503+ REQUIRE(t[0].type == UnitType::DISPLAY_BOX);
1504+ REQUIRE(t[0].value.ENUM == UnitType::NONE);
1505+ }
1506+ SECTION("display-inside flow") {
1507+ std::vector<Unit> t = getUnit("flow");
1508+ REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1509+ REQUIRE(t[0].value.ENUM == UnitType::FLOW);
1510+ }
1511+ SECTION("display-inside flow-root") {
1512+ std::vector<Unit> t = getUnit("flow-root");
1513+ REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1514+ REQUIRE(t[0].value.ENUM == UnitType::FLOW_ROOT);
1515+ }
1516+ SECTION("display-inside table") {
1517+ std::vector<Unit> t = getUnit("table");
1518+ REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1519+ REQUIRE(t[0].value.ENUM == UnitType::TABLE);
1520+ }
1521+ SECTION("display-inside flex") {
1522+ std::vector<Unit> t = getUnit("flex");
1523+ REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1524+ REQUIRE(t[0].value.ENUM == UnitType::FLEX);
1525+ }
1526+ SECTION("display-inside grid") {
1527+ std::vector<Unit> t = getUnit("grid");
1528+ REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1529+ REQUIRE(t[0].value.ENUM == UnitType::GRID);
1530+ }
1531+ SECTION("display-inside ruby") {
1532+ std::vector<Unit> t = getUnit("ruby");
1533+ REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1534+ REQUIRE(t[0].value.ENUM == UnitType::RUBY);
1535+ }
1536+ SECTION("display-internal table-row-group") {
1537+ std::vector<Unit> t = getUnit("table-row-group");
1538+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1539+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_ROW_GROUP);
1540+ }
1541+ SECTION("display-internal table-header-group") {
1542+ std::vector<Unit> t = getUnit("table-header-group");
1543+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1544+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_HEADER_GROUP);
1545+ }
1546+ SECTION("display-internal table-footer-group") {
1547+ std::vector<Unit> t = getUnit("table-footer-group");
1548+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1549+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_FOOTER_GROUP);
1550+ }
1551+ SECTION("display-internal table-column-group") {
1552+ std::vector<Unit> t = getUnit("table-column-group");
1553+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1554+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_COLUMN_GROUP);
1555+ }
1556+ SECTION("display-internal table-row") {
1557+ std::vector<Unit> t = getUnit("table-row");
1558+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1559+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_ROW);
1560+ }
1561+ SECTION("display-internal table-cell") {
1562+ std::vector<Unit> t = getUnit("table-cell");
1563+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1564+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_CELL);
1565+ }
1566+ SECTION("display-internal table-column") {
1567+ std::vector<Unit> t = getUnit("table-column");
1568+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1569+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_COLUMN);
1570+ }
1571+ SECTION("display-internal table-caption") {
1572+ std::vector<Unit> t = getUnit("table-caption");
1573+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1574+ REQUIRE(t[0].value.ENUM == UnitType::TABLE_CAPTION);
1575+ }
1576+ SECTION("display-internal ruby-base") {
1577+ std::vector<Unit> t = getUnit("ruby-base");
1578+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1579+ REQUIRE(t[0].value.ENUM == UnitType::RUBY_BASE);
1580+ }
1581+ SECTION("display-internal ruby-text") {
1582+ std::vector<Unit> t = getUnit("ruby-text");
1583+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1584+ REQUIRE(t[0].value.ENUM == UnitType::RUBY_TEXT);
1585+ }
1586+ SECTION("display-internal ruby-base-container") {
1587+ std::vector<Unit> t = getUnit("ruby-base-container");
1588+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1589+ REQUIRE(t[0].value.ENUM == UnitType::RUBY_BASE_CONTAINER);
1590+ }
1591+ SECTION("display-internal ruby-text-container") {
1592+ std::vector<Unit> t = getUnit("ruby-text-container");
1593+ REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1594+ REQUIRE(t[0].value.ENUM == UnitType::RUBY_TEXT_CONTAINER);
1595+ }
1596+ SECTION("display-legacy inline-block") {
1597+ std::vector<Unit> t = getUnit("inline-block");
1598+ REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1599+ REQUIRE(t[0].value.ENUM == UnitType::INLINE_BLOCK);
1600+ }
1601+ SECTION("display-legacy inline-table") {
1602+ std::vector<Unit> t = getUnit("inline-table");
1603+ REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1604+ REQUIRE(t[0].value.ENUM == UnitType::INLINE_TABLE);
1605+ }
1606+ SECTION("display-legacy inline-flex") {
1607+ std::vector<Unit> t = getUnit("inline-flex");
1608+ REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1609+ REQUIRE(t[0].value.ENUM == UnitType::INLINE_FLEX);
1610+ }
1611+ SECTION("display-legacy inline-grid") {
1612+ std::vector<Unit> t = getUnit("inline-grid");
1613+ REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1614+ REQUIRE(t[0].value.ENUM == UnitType::INLINE_GRID);
1615+ }
1616+ SECTION("display-listitem list-item") {
1617+ std::vector<Unit> t = getUnit("list-item");
1618+ REQUIRE(t[0].type == UnitType::DISPLAY_LISTITEM);
1619+ REQUIRE(t[0].value.ENUM == UnitType::LISTITEM);
1620+ }
1621+ SECTION("display-outside block") {
1622+ std::vector<Unit> t = getUnit("block");
1623+ REQUIRE(t[0].type == UnitType::DISPLAY_OUTSIDE);
1624+ REQUIRE(t[0].value.ENUM == UnitType::BLOCK);
1625+ }
1626+ SECTION("display-outside inline") {
1627+ std::vector<Unit> t = getUnit("inline");
1628+ REQUIRE(t[0].type == UnitType::DISPLAY_OUTSIDE);
1629+ REQUIRE(t[0].value.ENUM == UnitType::INLINE);
1630+ }
1631+ SECTION("display-outside run-in") {
1632+ std::vector<Unit> t = getUnit("run-in");
1633+ REQUIRE(t[0].type == UnitType::DISPLAY_OUTSIDE);
1634+ REQUIRE(t[0].value.ENUM == UnitType::RUN_IN);
1635+ }
1636 }
1637
1638 /*