xbintsc 0.3.25 → 0.3.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +33 -0
  2. package/dist/src/cli/main.js +124 -30
  3. package/dist/src/cli/main.js.map +1 -1
  4. package/dist/src/codegen/generator/calls/access.js +8 -1
  5. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  6. package/dist/src/codegen/generator/state.js +20 -0
  7. package/dist/src/codegen/generator/state.js.map +1 -1
  8. package/dist/src/codegen/generator/tables.d.ts +6 -0
  9. package/dist/src/codegen/generator/tables.js +38 -0
  10. package/dist/src/codegen/generator/tables.js.map +1 -1
  11. package/dist/src/driver/bundler/commonjs.d.ts +52 -0
  12. package/dist/src/driver/bundler/commonjs.js +493 -0
  13. package/dist/src/driver/bundler/commonjs.js.map +1 -0
  14. package/dist/src/driver/bundler/graph.js +14 -0
  15. package/dist/src/driver/bundler/graph.js.map +1 -1
  16. package/dist/src/driver/bundler/merge.js +14 -0
  17. package/dist/src/driver/bundler/merge.js.map +1 -1
  18. package/dist/src/driver/bundler/types.d.ts +8 -0
  19. package/dist/src/driver/compiler.d.ts +8 -1
  20. package/dist/src/driver/compiler.js +73 -5
  21. package/dist/src/driver/compiler.js.map +1 -1
  22. package/dist/src/driver/config.d.ts +53 -0
  23. package/dist/src/driver/config.js +141 -0
  24. package/dist/src/driver/config.js.map +1 -0
  25. package/dist/src/driver/icon.d.ts +62 -0
  26. package/dist/src/driver/icon.js +151 -0
  27. package/dist/src/driver/icon.js.map +1 -0
  28. package/dist/src/driver/index.d.ts +4 -0
  29. package/dist/src/driver/index.js +4 -0
  30. package/dist/src/driver/index.js.map +1 -1
  31. package/dist/src/driver/mac-bundle.d.ts +41 -0
  32. package/dist/src/driver/mac-bundle.js +123 -0
  33. package/dist/src/driver/mac-bundle.js.map +1 -0
  34. package/dist/src/driver/win-icon.d.ts +27 -0
  35. package/dist/src/driver/win-icon.js +80 -0
  36. package/dist/src/driver/win-icon.js.map +1 -0
  37. package/dist/src/parser/statements.js +17 -4
  38. package/dist/src/parser/statements.js.map +1 -1
  39. package/dist/tests/cli/main.test.js +46 -1
  40. package/dist/tests/cli/main.test.js.map +1 -1
  41. package/dist/tests/driver/config.test.d.ts +1 -0
  42. package/dist/tests/driver/config.test.js +124 -0
  43. package/dist/tests/driver/config.test.js.map +1 -0
  44. package/dist/tests/driver/icon.test.d.ts +1 -0
  45. package/dist/tests/driver/icon.test.js +421 -0
  46. package/dist/tests/driver/icon.test.js.map +1 -0
  47. package/dist/tests/driver/modules.test.js +109 -0
  48. package/dist/tests/driver/modules.test.js.map +1 -1
  49. package/dist/tests/e2e/fetch.test.d.ts +12 -0
  50. package/dist/tests/e2e/fetch.test.js +272 -0
  51. package/dist/tests/e2e/fetch.test.js.map +1 -0
  52. package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
  53. package/dist/tests/e2e/gui-dom.test.js +102 -0
  54. package/dist/tests/e2e/gui-dom.test.js.map +1 -0
  55. package/dist/tests/e2e/gui-events.test.d.ts +5 -0
  56. package/dist/tests/e2e/gui-events.test.js +60 -0
  57. package/dist/tests/e2e/gui-events.test.js.map +1 -0
  58. package/dist/tests/e2e/gui-helpers.d.ts +31 -0
  59. package/dist/tests/e2e/gui-helpers.js +74 -0
  60. package/dist/tests/e2e/gui-helpers.js.map +1 -0
  61. package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
  62. package/dist/tests/e2e/gui-layout.test.js +88 -0
  63. package/dist/tests/e2e/gui-layout.test.js.map +1 -0
  64. package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
  65. package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
  66. package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
  67. package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
  68. package/dist/tests/e2e/gui-paint.test.js +111 -0
  69. package/dist/tests/e2e/gui-paint.test.js.map +1 -0
  70. package/dist/tests/e2e/gui-script.test.d.ts +5 -0
  71. package/dist/tests/e2e/gui-script.test.js +78 -0
  72. package/dist/tests/e2e/gui-script.test.js.map +1 -0
  73. package/dist/tests/e2e/gui-style.test.d.ts +5 -0
  74. package/dist/tests/e2e/gui-style.test.js +175 -0
  75. package/dist/tests/e2e/gui-style.test.js.map +1 -0
  76. package/dist/tests/e2e/icon.test.d.ts +7 -0
  77. package/dist/tests/e2e/icon.test.js +80 -0
  78. package/dist/tests/e2e/icon.test.js.map +1 -0
  79. package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
  80. package/dist/tests/e2e/npm-modules.test.js +47 -1
  81. package/dist/tests/e2e/npm-modules.test.js.map +1 -1
  82. package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
  83. package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
  84. package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
  85. package/dist/tests/parser/statements.test.js +11 -0
  86. package/dist/tests/parser/statements.test.js.map +1 -1
  87. package/package.json +1 -1
  88. package/runtime/ext_gui/css.cpp +4 -517
  89. package/runtime/ext_gui/css_internal.h +27 -0
  90. package/runtime/ext_gui/css_match.cpp +195 -0
  91. package/runtime/ext_gui/css_selector.cpp +207 -0
  92. package/runtime/ext_gui/css_sheet.cpp +129 -0
  93. package/runtime/ext_gui/dom.cpp +7 -403
  94. package/runtime/ext_gui/dom_api.cpp +63 -1146
  95. package/runtime/ext_gui/dom_api_document.cpp +96 -0
  96. package/runtime/ext_gui/dom_api_events.cpp +123 -0
  97. package/runtime/ext_gui/dom_api_internal.h +135 -0
  98. package/runtime/ext_gui/dom_api_node.cpp +329 -0
  99. package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
  100. package/runtime/ext_gui/dom_api_proto.cpp +130 -0
  101. package/runtime/ext_gui/dom_api_style.cpp +192 -0
  102. package/runtime/ext_gui/dom_internal.h +39 -0
  103. package/runtime/ext_gui/dom_parse.cpp +348 -0
  104. package/runtime/ext_gui/dom_serialize.cpp +54 -0
  105. package/runtime/ext_gui/gui.cpp +56 -286
  106. package/runtime/ext_gui/gui_events.cpp +294 -0
  107. package/runtime/ext_gui/gui_internal.h +29 -0
  108. package/runtime/ext_gui/layout.cpp +6 -597
  109. package/runtime/ext_gui/layout_flex.cpp +200 -0
  110. package/runtime/ext_gui/layout_flow.cpp +191 -0
  111. package/runtime/ext_gui/layout_flow_internal.h +149 -0
  112. package/runtime/ext_gui/layout_inline.cpp +181 -0
  113. package/runtime/ext_gui/layout_internal.h +20 -0
  114. package/runtime/ext_gui/renderer.cpp +15 -679
  115. package/runtime/ext_gui/renderer_image.cpp +233 -0
  116. package/runtime/ext_gui/renderer_internal.h +112 -0
  117. package/runtime/ext_gui/renderer_shaders.h +108 -0
  118. package/runtime/ext_gui/renderer_text.cpp +342 -0
  119. package/runtime/ext_gui/style.cpp +12 -660
  120. package/runtime/ext_gui/style_internal.h +33 -0
  121. package/runtime/ext_gui/style_print.cpp +113 -0
  122. package/runtime/ext_gui/style_ua.cpp +98 -0
  123. package/runtime/ext_gui/style_values.cpp +468 -0
  124. package/runtime/rt.h +6 -0
  125. package/runtime/rt_internal.h +4 -0
  126. package/runtime/xt_builtins.c +1 -0
  127. package/runtime/xt_containers/access.inc +32 -1
  128. package/runtime/xt_fetch/buffer.inc +64 -0
  129. package/runtime/xt_fetch/headers.inc +312 -0
  130. package/runtime/xt_fetch/request.inc +386 -0
  131. package/runtime/xt_fetch/response.inc +107 -0
  132. package/runtime/xt_fetch/socket.inc +72 -0
  133. package/runtime/xt_fetch/url.inc +108 -0
  134. package/runtime/xt_fetch.c +39 -0
  135. package/runtime/xt_stdlib2/set.inc +1 -1
  136. package/runtime/xt_typed_array.c +614 -0
  137. package/src/cli/main.ts +137 -29
  138. package/src/codegen/generator/calls/access.ts +9 -1
  139. package/src/codegen/generator/state.ts +20 -0
  140. package/src/codegen/generator/tables.ts +40 -0
  141. package/src/driver/bundler/commonjs.ts +553 -0
  142. package/src/driver/bundler/graph.ts +14 -0
  143. package/src/driver/bundler/merge.ts +15 -0
  144. package/src/driver/bundler/types.ts +8 -0
  145. package/src/driver/compiler.ts +83 -5
  146. package/src/driver/config.ts +173 -0
  147. package/src/driver/icon.ts +184 -0
  148. package/src/driver/index.ts +30 -0
  149. package/src/driver/mac-bundle.ts +156 -0
  150. package/src/driver/win-icon.ts +96 -0
  151. package/src/parser/statements.ts +17 -4
  152. package/dist/tests/e2e/gui.test.d.ts +0 -12
  153. package/dist/tests/e2e/gui.test.js +0 -702
  154. package/dist/tests/e2e/gui.test.js.map +0 -1
@@ -1,14 +1,15 @@
1
1
  /*
2
2
  * xbintsc GUI engine — cascade, inheritance and computed style.
3
+ *
4
+ * Property parsing/application lives in `style_values.cpp`, the built-in
5
+ * user-agent rules in `style_ua.cpp` and the diagnostic stringification in
6
+ * `style_print.cpp`.
3
7
  */
4
8
 
5
- #include "style.h"
9
+ #include "style_internal.h"
6
10
 
7
11
  #include <algorithm>
8
12
  #include <climits>
9
- #include <cmath>
10
- #include <cstdio>
11
- #include <cstdlib>
12
13
  #include <unordered_map>
13
14
  #include <vector>
14
15
 
@@ -16,552 +17,6 @@ namespace xtgui {
16
17
 
17
18
  XtStyle xt_style_initial() { return XtStyle(); }
18
19
 
19
- /* -- small helpers -------------------------------------------------------- */
20
-
21
- static void setEdge(Edges *edges, const std::string &side, Length value) {
22
- if (side == "top") edges->top = value;
23
- else if (side == "right") edges->right = value;
24
- else if (side == "bottom") edges->bottom = value;
25
- else if (side == "left") edges->left = value;
26
- }
27
-
28
- static bool parseEdgeLengths(const std::string &value, Edges *edges) {
29
- std::vector<std::string> parts = xt_css_split_whitespace(value);
30
- if (parts.empty() || parts.size() > 4) return false;
31
- Length values[4];
32
- for (size_t i = 0; i < parts.size(); i++) {
33
- Length length = xt_css_parse_length(parts[i]);
34
- if (length.unit == Unit::Invalid) {
35
- std::string keyword = xt_css_lower(parts[i]);
36
- if (keyword == "thin") length = {1.0f, Unit::Px};
37
- else if (keyword == "medium") length = {3.0f, Unit::Px};
38
- else if (keyword == "thick") length = {5.0f, Unit::Px};
39
- else return false;
40
- }
41
- values[i] = length;
42
- }
43
- switch (parts.size()) {
44
- case 1:
45
- edges->set(values[0]);
46
- break;
47
- case 2:
48
- edges->top = edges->bottom = values[0];
49
- edges->right = edges->left = values[1];
50
- break;
51
- case 3:
52
- edges->top = values[0];
53
- edges->right = edges->left = values[1];
54
- edges->bottom = values[2];
55
- break;
56
- default:
57
- edges->top = values[0];
58
- edges->right = values[1];
59
- edges->bottom = values[2];
60
- edges->left = values[3];
61
- break;
62
- }
63
- return true;
64
- }
65
-
66
- static bool assignLength(Length *target, const std::string &value) {
67
- Length length = xt_css_parse_length(value);
68
- if (length.unit == Unit::Invalid) return false;
69
- *target = length;
70
- return true;
71
- }
72
-
73
- static bool assignColor(Color *target, bool *has, const std::string &value) {
74
- Color color = xt_css_parse_color(value);
75
- if (!color.valid) return false;
76
- *target = color;
77
- *has = true;
78
- return true;
79
- }
80
-
81
- static float resolveAbsolute(const Length &length, float base, float em, float root, float vw, float vh) {
82
- switch (length.unit) {
83
- case Unit::Px:
84
- case Unit::Number:
85
- return length.value;
86
- case Unit::Percent:
87
- return base * length.value / 100.0f;
88
- case Unit::Em:
89
- return em * length.value;
90
- case Unit::Rem:
91
- return root * length.value;
92
- case Unit::Vw:
93
- return vw * length.value / 100.0f;
94
- case Unit::Vh:
95
- return vh * length.value / 100.0f;
96
- default:
97
- return 0.0f;
98
- }
99
- }
100
-
101
- /* -- user-agent stylesheet ------------------------------------------------ */
102
-
103
- static bool isBlockTag(const std::string &tag) {
104
- static const std::unordered_map<std::string, bool> tags = {
105
- {"address", true}, {"article", true}, {"aside", true}, {"blockquote", true},
106
- {"dd", true}, {"div", true}, {"dl", true}, {"dt", true},
107
- {"fieldset", true}, {"figcaption", true}, {"figure", true}, {"footer", true},
108
- {"form", true}, {"h1", true}, {"h2", true}, {"h3", true},
109
- {"h4", true}, {"h5", true}, {"h6", true}, {"header", true},
110
- {"hr", true}, {"li", true}, {"main", true}, {"nav", true},
111
- {"ol", true}, {"p", true}, {"pre", true}, {"section", true},
112
- {"table", true}, {"tbody", true}, {"td", true}, {"tfoot", true},
113
- {"th", true}, {"thead", true}, {"tr", true}, {"ul", true},
114
- };
115
- return tags.count(tag) != 0;
116
- }
117
-
118
- static void applyUserAgentStyle(const Node *node, XtStyle *style) {
119
- const std::string &tag = node->tag;
120
- if (tag == "html" || tag == "body") style->display = Display::Block;
121
- if (isBlockTag(tag)) style->display = Display::Block;
122
- if (tag == "head" || tag == "style" || tag == "script" || tag == "title" || tag == "meta" ||
123
- tag == "link" || tag == "base" || tag == "template") {
124
- style->display = Display::None;
125
- }
126
- if (tag == "br") style->display = Display::Block;
127
- if (tag == "button" || tag == "input" || tag == "select" || tag == "textarea") {
128
- style->display = Display::InlineBlock;
129
- }
130
- if (tag == "img") style->display = Display::InlineBlock;
131
- if (tag == "body") style->margin.set({8.0f, Unit::Px});
132
- if (tag == "p") style->margin.top = style->margin.bottom = {16.0f, Unit::Px};
133
- if (tag == "blockquote") {
134
- style->margin.top = style->margin.bottom = {16.0f, Unit::Px};
135
- style->margin.left = style->margin.right = {40.0f, Unit::Px};
136
- }
137
- if (tag == "h1") {
138
- style->font_size = 32.0f;
139
- style->font_weight = 700;
140
- style->margin.top = style->margin.bottom = {21.44f, Unit::Px};
141
- } else if (tag == "h2") {
142
- style->font_size = 24.0f;
143
- style->font_weight = 700;
144
- style->margin.top = style->margin.bottom = {19.92f, Unit::Px};
145
- } else if (tag == "h3") {
146
- style->font_size = 18.72f;
147
- style->font_weight = 700;
148
- style->margin.top = style->margin.bottom = {18.72f, Unit::Px};
149
- } else if (tag == "h4") {
150
- style->font_size = 16.0f;
151
- style->font_weight = 700;
152
- style->margin.top = style->margin.bottom = {21.28f, Unit::Px};
153
- } else if (tag == "h5") {
154
- style->font_size = 13.28f;
155
- style->font_weight = 700;
156
- style->margin.top = style->margin.bottom = {22.18f, Unit::Px};
157
- } else if (tag == "h6") {
158
- style->font_size = 10.72f;
159
- style->font_weight = 700;
160
- style->margin.top = style->margin.bottom = {24.97f, Unit::Px};
161
- }
162
- if (tag == "strong" || tag == "b") style->font_weight = 700;
163
- if (tag == "dt") style->font_weight = 700;
164
- if (tag == "em" || tag == "i") style->font_style = FontStyle::Italic;
165
- if (tag == "small") style->font_size = 13.333f;
166
- if (tag == "a") {
167
- style->color = {0.0f, 0.0f, 0.933f, 1.0f};
168
- }
169
- if (tag == "ul" || tag == "ol") {
170
- style->padding.left = {40.0f, Unit::Px};
171
- style->margin.top = style->margin.bottom = {16.0f, Unit::Px};
172
- }
173
- if (tag == "pre" || tag == "code" || tag == "kbd" || tag == "samp") {
174
- style->font_family = "monospace";
175
- }
176
- if (tag == "pre") style->white_space = WhiteSpace::Pre;
177
- if (tag == "hr") {
178
- style->border_width.top = {1.0f, Unit::Px};
179
- style->border_style = BorderStyle::Solid;
180
- style->border_color = {0.5f, 0.5f, 0.5f, 1.0f};
181
- style->has_border_color = true;
182
- style->margin.top = style->margin.bottom = {8.0f, Unit::Px};
183
- }
184
- }
185
-
186
- /* -- declaration application ---------------------------------------------- */
187
-
188
- static bool parseEnum(const std::string &value, const char *const *names, int count, int *out) {
189
- std::string text = xt_css_lower(xt_css_trim(value));
190
- for (int i = 0; i < count; i++) {
191
- if (text == names[i]) {
192
- *out = i;
193
- return true;
194
- }
195
- }
196
- return false;
197
- }
198
-
199
- /* -- transitions ---------------------------------------------------------- */
200
-
201
- static bool parseTimeSeconds(const std::string &text, float *out) {
202
- std::string token = xt_css_trim(text);
203
- if (token.empty()) return false;
204
- const char *begin = token.c_str();
205
- char *end = nullptr;
206
- double value = std::strtod(begin, &end);
207
- if (end == begin) return false;
208
- std::string unit = xt_css_lower(xt_css_trim(std::string(end)));
209
- if (unit == "ms") {
210
- *out = (float)(value / 1000.0);
211
- } else if (unit.empty() || unit == "s") {
212
- *out = (float)value;
213
- } else {
214
- return false;
215
- }
216
- return true;
217
- }
218
-
219
- static bool parseTimingFunction(const std::string &text, TimingFunction *out) {
220
- std::string token = xt_css_lower(xt_css_trim(text));
221
- if (token == "linear") {
222
- *out = TimingFunction::Linear;
223
- } else if (token == "ease") {
224
- *out = TimingFunction::Ease;
225
- } else if (token == "ease-in") {
226
- *out = TimingFunction::EaseIn;
227
- } else if (token == "ease-out") {
228
- *out = TimingFunction::EaseOut;
229
- } else if (token == "ease-in-out") {
230
- *out = TimingFunction::EaseInOut;
231
- } else {
232
- return false;
233
- }
234
- return true;
235
- }
236
-
237
- static std::vector<std::string> splitCommas(const std::string &text) {
238
- std::vector<std::string> parts;
239
- size_t start = 0;
240
- for (size_t i = 0; i <= text.size(); i++) {
241
- if (i == text.size() || text[i] == ',') {
242
- std::string part = xt_css_trim(text.substr(start, i - start));
243
- if (!part.empty()) parts.push_back(part);
244
- start = i + 1;
245
- }
246
- }
247
- return parts;
248
- }
249
-
250
- static void parseTransitionShorthand(const std::string &value, std::vector<TransitionSpec> *out) {
251
- out->clear();
252
- for (const std::string &group : splitCommas(value)) {
253
- std::vector<std::string> tokens = xt_css_split_whitespace(group);
254
- if (tokens.empty()) continue;
255
- TransitionSpec spec;
256
- int time_seen = 0;
257
- for (const std::string &token : tokens) {
258
- float seconds = 0;
259
- TimingFunction timing = TimingFunction::Ease;
260
- if (parseTimeSeconds(token, &seconds)) {
261
- if (time_seen == 0) {
262
- spec.duration = seconds;
263
- } else {
264
- spec.delay = seconds;
265
- }
266
- time_seen++;
267
- } else if (parseTimingFunction(token, &timing)) {
268
- spec.timing = timing;
269
- } else {
270
- spec.property = xt_css_lower(token);
271
- }
272
- }
273
- out->push_back(spec);
274
- }
275
- }
276
-
277
- struct ApplyContext {
278
- float rootFontSize = 16.0f;
279
- float parentFontSize = 16.0f;
280
- float viewportWidth = 0.0f;
281
- float viewportHeight = 0.0f;
282
- };
283
-
284
- static void applyDeclaration(XtStyle *style, const std::string &property, const std::string &rawValue,
285
- const ApplyContext &context) {
286
- std::string value = xt_css_trim(rawValue);
287
-
288
- if (property == "display") {
289
- static const char *const names[] = {"none", "block", "inline", "inline-block", "flex", "list-item"};
290
- int index = 0;
291
- if (parseEnum(value, names, 6, &index)) style->display = (Display)index;
292
- return;
293
- }
294
- if (property == "position") {
295
- static const char *const names[] = {"static", "relative", "absolute", "fixed"};
296
- int index = 0;
297
- if (parseEnum(value, names, 4, &index)) style->position = (Position)index;
298
- return;
299
- }
300
- if (property == "width") { assignLength(&style->width, value); return; }
301
- if (property == "height") { assignLength(&style->height, value); return; }
302
- if (property == "min-width") { assignLength(&style->min_width, value); return; }
303
- if (property == "min-height") { assignLength(&style->min_height, value); return; }
304
- if (property == "max-width") { assignLength(&style->max_width, value); return; }
305
- if (property == "max-height") { assignLength(&style->max_height, value); return; }
306
- if (property == "top") { assignLength(&style->top, value); return; }
307
- if (property == "right") { assignLength(&style->right, value); return; }
308
- if (property == "bottom") { assignLength(&style->bottom, value); return; }
309
- if (property == "left") { assignLength(&style->left, value); return; }
310
-
311
- if (property == "margin") { parseEdgeLengths(value, &style->margin); return; }
312
- if (property == "padding") { parseEdgeLengths(value, &style->padding); return; }
313
- if (property == "margin-top") { setEdge(&style->margin, "top", xt_css_parse_length(value)); return; }
314
- if (property == "margin-right") { setEdge(&style->margin, "right", xt_css_parse_length(value)); return; }
315
- if (property == "margin-bottom") { setEdge(&style->margin, "bottom", xt_css_parse_length(value)); return; }
316
- if (property == "margin-left") { setEdge(&style->margin, "left", xt_css_parse_length(value)); return; }
317
- if (property == "padding-top") { setEdge(&style->padding, "top", xt_css_parse_length(value)); return; }
318
- if (property == "padding-right") { setEdge(&style->padding, "right", xt_css_parse_length(value)); return; }
319
- if (property == "padding-bottom") { setEdge(&style->padding, "bottom", xt_css_parse_length(value)); return; }
320
- if (property == "padding-left") { setEdge(&style->padding, "left", xt_css_parse_length(value)); return; }
321
-
322
- if (property == "border-width") { parseEdgeLengths(value, &style->border_width); return; }
323
- if (property == "border-top-width") { setEdge(&style->border_width, "top", xt_css_parse_length(value)); return; }
324
- if (property == "border-right-width") { setEdge(&style->border_width, "right", xt_css_parse_length(value)); return; }
325
- if (property == "border-bottom-width") { setEdge(&style->border_width, "bottom", xt_css_parse_length(value)); return; }
326
- if (property == "border-left-width") { setEdge(&style->border_width, "left", xt_css_parse_length(value)); return; }
327
- if (property == "border-radius") {
328
- Length length = xt_css_parse_length(value);
329
- if (length.unit == Unit::Px || length.unit == Unit::Number) style->border_radius = length.value;
330
- return;
331
- }
332
- if (property == "border-style" || property == "border-top-style" || property == "border-right-style" ||
333
- property == "border-bottom-style" || property == "border-left-style") {
334
- static const char *const names[] = {"none", "solid", "dashed", "dotted"};
335
- int index = 0;
336
- if (parseEnum(value, names, 4, &index)) style->border_style = (BorderStyle)index;
337
- return;
338
- }
339
- if (property == "border-color" || property == "border-top-color" || property == "border-right-color" ||
340
- property == "border-bottom-color" || property == "border-left-color") {
341
- assignColor(&style->border_color, &style->has_border_color, value);
342
- return;
343
- }
344
- if (property == "border" || property == "border-top" || property == "border-right" ||
345
- property == "border-bottom" || property == "border-left") {
346
- for (const std::string &token : xt_css_split_whitespace(value)) {
347
- Length length = xt_css_parse_length(token);
348
- if (length.unit == Unit::Px || length.unit == Unit::Number) {
349
- if (property == "border") style->border_width.set(length);
350
- else setEdge(&style->border_width, property.substr(7), length);
351
- continue;
352
- }
353
- static const char *const names[] = {"none", "solid", "dashed", "dotted"};
354
- int index = 0;
355
- if (parseEnum(token, names, 4, &index)) {
356
- style->border_style = (BorderStyle)index;
357
- continue;
358
- }
359
- Color color = xt_css_parse_color(token);
360
- if (color.valid) {
361
- style->border_color = color;
362
- style->has_border_color = true;
363
- }
364
- }
365
- return;
366
- }
367
-
368
- if (property == "color") {
369
- Color color = xt_css_parse_color(value);
370
- if (color.valid) style->color = color;
371
- return;
372
- }
373
- if (property == "background-color") { assignColor(&style->background, &style->has_background, value); return; }
374
- if (property == "background") {
375
- Color color = xt_css_parse_color(value);
376
- if (color.valid) {
377
- style->background = color;
378
- style->has_background = true;
379
- }
380
- return;
381
- }
382
-
383
- if (property == "font-size") {
384
- Length length = xt_css_parse_length(value);
385
- if (length.unit == Unit::Invalid) return;
386
- /* `em`/`%` resolve against the *parent* font size, never the element's own
387
- * (possibly UA-set) size. */
388
- style->font_size = resolveAbsolute(length, context.parentFontSize, context.parentFontSize,
389
- context.rootFontSize, context.viewportWidth, context.viewportHeight);
390
- if (style->font_size <= 0.0f) style->font_size = 16.0f;
391
- return;
392
- }
393
- if (property == "font-weight") {
394
- std::string text = xt_css_lower(value);
395
- if (text == "normal") style->font_weight = 400;
396
- else if (text == "bold") style->font_weight = 700;
397
- else if (text == "lighter") style->font_weight = 100;
398
- else if (text == "bolder") style->font_weight = 700;
399
- else {
400
- float number = 0;
401
- if (xt_css_parse_number(text, &number)) style->font_weight = (int)number;
402
- }
403
- return;
404
- }
405
- if (property == "font-family") {
406
- style->font_family = value;
407
- return;
408
- }
409
- if (property == "font-style") {
410
- style->font_style = (xt_css_lower(value) == "italic") ? FontStyle::Italic : FontStyle::Normal;
411
- return;
412
- }
413
- if (property == "line-height") {
414
- std::string text = xt_css_lower(value);
415
- if (text == "normal") {
416
- style->line_height = {};
417
- return;
418
- }
419
- Length length = xt_css_parse_length(text);
420
- if (length.unit == Unit::Invalid) return;
421
- /* Relative units are resolved in `finalizeStyle`, once the element's own
422
- * font size is settled. */
423
- style->line_height = length;
424
- return;
425
- }
426
- if (property == "text-align") {
427
- std::string text = xt_css_lower(value);
428
- if (text == "left" || text == "start") style->text_align = TextAlign::Start;
429
- else if (text == "right" || text == "end") style->text_align = TextAlign::End;
430
- else if (text == "center") style->text_align = TextAlign::Center;
431
- else if (text == "justify") style->text_align = TextAlign::Justify;
432
- return;
433
- }
434
- if (property == "white-space") {
435
- static const char *const names[] = {"normal", "nowrap", "pre", "pre-wrap", "pre-line"};
436
- int index = 0;
437
- if (parseEnum(value, names, 5, &index)) style->white_space = (WhiteSpace)index;
438
- return;
439
- }
440
-
441
- if (property == "flex-direction") {
442
- static const char *const names[] = {"row", "row-reverse", "column", "column-reverse"};
443
- int index = 0;
444
- if (parseEnum(value, names, 4, &index)) style->flex_direction = (FlexDirection)index;
445
- return;
446
- }
447
- if (property == "justify-content") {
448
- static const char *const names[] = {"flex-start", "flex-end", "center", "space-between",
449
- "space-around", "space-evenly"};
450
- int index = 0;
451
- if (parseEnum(value, names, 6, &index)) style->justify_content = (JustifyContent)index;
452
- return;
453
- }
454
- if (property == "align-items") {
455
- static const char *const names[] = {"stretch", "flex-start", "flex-end", "center", "baseline"};
456
- int index = 0;
457
- if (parseEnum(value, names, 5, &index)) style->align_items = (AlignItems)index;
458
- return;
459
- }
460
- if (property == "gap" || property == "row-gap" || property == "column-gap") {
461
- assignLength(&style->gap, value);
462
- return;
463
- }
464
- if (property == "flex-grow") {
465
- float number = 0;
466
- if (xt_css_parse_number(value, &number)) style->flex_grow = number;
467
- return;
468
- }
469
- if (property == "flex-shrink") {
470
- float number = 0;
471
- if (xt_css_parse_number(value, &number)) style->flex_shrink = number;
472
- return;
473
- }
474
- if (property == "flex-basis") { assignLength(&style->flex_basis, value); return; }
475
- if (property == "flex") {
476
- std::string text = xt_css_lower(value);
477
- if (text == "none") {
478
- style->flex_grow = 0;
479
- style->flex_shrink = 0;
480
- style->flex_basis = {0.0f, Unit::Auto};
481
- return;
482
- }
483
- if (text == "auto") {
484
- style->flex_grow = 1;
485
- style->flex_shrink = 1;
486
- style->flex_basis = {0.0f, Unit::Auto};
487
- return;
488
- }
489
- if (text == "initial") {
490
- style->flex_grow = 0;
491
- style->flex_shrink = 1;
492
- style->flex_basis = {0.0f, Unit::Auto};
493
- return;
494
- }
495
- std::vector<std::string> parts = xt_css_split_whitespace(text);
496
- style->flex_grow = 0;
497
- style->flex_shrink = 1;
498
- style->flex_basis = {0.0f, Unit::Auto};
499
- size_t index = 0;
500
- float number = 0;
501
- if (index < parts.size() && xt_css_parse_number(parts[index], &number)) {
502
- style->flex_grow = number;
503
- index++;
504
- if (index < parts.size() && xt_css_parse_number(parts[index], &number)) {
505
- style->flex_shrink = number;
506
- index++;
507
- }
508
- if (index >= parts.size()) style->flex_basis = {0.0f, Unit::Px};
509
- }
510
- if (index < parts.size()) assignLength(&style->flex_basis, parts[index]);
511
- return;
512
- }
513
-
514
- if (property == "opacity") {
515
- float number = 0;
516
- if (xt_css_parse_number(value, &number)) style->opacity = number < 0 ? 0 : (number > 1 ? 1 : number);
517
- return;
518
- }
519
- if (property == "overflow" || property == "overflow-x" || property == "overflow-y") {
520
- static const char *const names[] = {"visible", "hidden", "scroll", "auto"};
521
- int index = 0;
522
- if (parseEnum(value, names, 4, &index)) style->overflow = (Overflow)index;
523
- return;
524
- }
525
- if (property == "z-index") {
526
- float number = 0;
527
- if (xt_css_parse_number(value, &number)) {
528
- style->z_index = (int)number;
529
- style->has_z_index = true;
530
- }
531
- return;
532
- }
533
- if (property == "transition") {
534
- parseTransitionShorthand(value, &style->transitions);
535
- return;
536
- }
537
- if (property == "transition-property") {
538
- std::vector<std::string> parts = splitCommas(value);
539
- style->transitions.resize(parts.size());
540
- for (size_t i = 0; i < parts.size(); i++) style->transitions[i].property = xt_css_lower(parts[i]);
541
- return;
542
- }
543
- if (property == "transition-duration" || property == "transition-delay") {
544
- std::vector<std::string> parts = splitCommas(value);
545
- style->transitions.resize(parts.size());
546
- for (size_t i = 0; i < parts.size(); i++) {
547
- float seconds = 0;
548
- if (!parseTimeSeconds(parts[i], &seconds)) continue;
549
- if (property == "transition-duration") style->transitions[i].duration = seconds;
550
- else style->transitions[i].delay = seconds;
551
- }
552
- return;
553
- }
554
- if (property == "transition-timing-function") {
555
- std::vector<std::string> parts = splitCommas(value);
556
- style->transitions.resize(parts.size());
557
- for (size_t i = 0; i < parts.size(); i++) {
558
- TimingFunction timing = TimingFunction::Ease;
559
- if (parseTimingFunction(parts[i], &timing)) style->transitions[i].timing = timing;
560
- }
561
- return;
562
- }
563
- }
564
-
565
20
  /* -- cascade -------------------------------------------------------------- */
566
21
 
567
22
  namespace {
@@ -579,16 +34,16 @@ bool candidateBefore(const Candidate &a, const Candidate &b) {
579
34
  return a.order < b.order;
580
35
  }
581
36
 
582
- static void finalizeStyle(XtStyle *style, const ApplyContext &context) {
37
+ void finalizeStyle(XtStyle *style, const ApplyContext &context) {
583
38
  switch (style->line_height.unit) {
584
39
  case Unit::Em:
585
40
  case Unit::Percent:
586
41
  case Unit::Rem:
587
42
  case Unit::Vw:
588
43
  case Unit::Vh:
589
- style->line_height.value = resolveAbsolute(style->line_height, style->font_size, style->font_size,
590
- context.rootFontSize, context.viewportWidth,
591
- context.viewportHeight);
44
+ style->line_height.value = xt_style_resolve_absolute(
45
+ style->line_height, style->font_size, style->font_size, context.rootFontSize,
46
+ context.viewportWidth, context.viewportHeight);
592
47
  style->line_height.unit = Unit::Px;
593
48
  break;
594
49
  default:
@@ -616,7 +71,7 @@ void computeNode(const Node *node, const XtStyle *parent, const StyleSheet &shee
616
71
  } else {
617
72
  style.color = {0.0f, 0.0f, 0.0f, 1.0f};
618
73
  }
619
- applyUserAgentStyle(node, &style);
74
+ xt_style_apply_user_agent(node, &style);
620
75
 
621
76
  ApplyContext nodeContext = context;
622
77
  nodeContext.parentFontSize = (parent != nullptr) ? parent->font_size : context.rootFontSize;
@@ -640,7 +95,8 @@ void computeNode(const Node *node, const XtStyle *parent, const StyleSheet &shee
640
95
  }
641
96
  std::stable_sort(candidates.begin(), candidates.end(), candidateBefore);
642
97
  for (const Candidate &candidate : candidates) {
643
- applyDeclaration(&style, candidate.declaration->property, candidate.declaration->value, nodeContext);
98
+ xt_style_apply_declaration(&style, candidate.declaration->property, candidate.declaration->value,
99
+ nodeContext);
644
100
  }
645
101
  finalizeStyle(&style, nodeContext);
646
102
 
@@ -664,108 +120,4 @@ void xt_style_compute(const Node *root, const StyleSheet &sheet,
664
120
  computeNode(root, nullptr, sheet, out, context, state);
665
121
  }
666
122
 
667
- /* -- diagnostics ---------------------------------------------------------- */
668
-
669
- static std::string formatNumber(float number) {
670
- char buffer[64];
671
- if (number == (float)(long)number) {
672
- snprintf(buffer, sizeof(buffer), "%ld", (long)number);
673
- } else {
674
- snprintf(buffer, sizeof(buffer), "%.4g", number);
675
- }
676
- return buffer;
677
- }
678
-
679
- static std::string formatLength(const Length &length) {
680
- switch (length.unit) {
681
- case Unit::Auto:
682
- return "auto";
683
- case Unit::None:
684
- return "none";
685
- case Unit::Number:
686
- return formatNumber(length.value);
687
- case Unit::Px:
688
- return formatNumber(length.value) + "px";
689
- case Unit::Percent:
690
- return formatNumber(length.value) + "%";
691
- case Unit::Em:
692
- return formatNumber(length.value) + "em";
693
- case Unit::Rem:
694
- return formatNumber(length.value) + "rem";
695
- case Unit::Vw:
696
- return formatNumber(length.value) + "vw";
697
- case Unit::Vh:
698
- return formatNumber(length.value) + "vh";
699
- default:
700
- return "";
701
- }
702
- }
703
-
704
- static std::string formatColor(const Color &color) {
705
- if (color.a >= 1.0f) {
706
- char buffer[64];
707
- snprintf(buffer, sizeof(buffer), "rgb(%ld, %ld, %ld)", (long)(color.r * 255.0f + 0.5f),
708
- (long)(color.g * 255.0f + 0.5f), (long)(color.b * 255.0f + 0.5f));
709
- return buffer;
710
- }
711
- char buffer[96];
712
- snprintf(buffer, sizeof(buffer), "rgba(%ld, %ld, %ld, %.2f)", (long)(color.r * 255.0f + 0.5f),
713
- (long)(color.g * 255.0f + 0.5f), (long)(color.b * 255.0f + 0.5f), color.a);
714
- return buffer;
715
- }
716
-
717
- std::string xt_style_property_to_string(const XtStyle &style, const std::string &rawProperty) {
718
- std::string property = xt_css_lower(xt_css_trim(rawProperty));
719
- static const char *const displayNames[] = {"none", "block", "inline", "inline-block", "flex", "list-item"};
720
- static const char *const positionNames[] = {"static", "relative", "absolute", "fixed"};
721
- static const char *const flexNames[] = {"row", "row-reverse", "column", "column-reverse"};
722
- static const char *const justifyNames[] = {"flex-start", "flex-end", "center", "space-between",
723
- "space-around", "space-evenly"};
724
- static const char *const alignNames[] = {"stretch", "flex-start", "flex-end", "center", "baseline"};
725
- static const char *const alignTextNames[] = {"start", "center", "end", "justify"};
726
-
727
- if (property == "display") return displayNames[(int)style.display];
728
- if (property == "position") return positionNames[(int)style.position];
729
- if (property == "color") return formatColor(style.color);
730
- if (property == "background-color" || property == "background") {
731
- return style.has_background ? formatColor(style.background) : "rgba(0, 0, 0, 0)";
732
- }
733
- if (property == "width") return formatLength(style.width);
734
- if (property == "height") return formatLength(style.height);
735
- if (property == "min-width") return formatLength(style.min_width);
736
- if (property == "min-height") return formatLength(style.min_height);
737
- if (property == "max-width") return formatLength(style.max_width);
738
- if (property == "max-height") return formatLength(style.max_height);
739
- if (property == "top") return formatLength(style.top);
740
- if (property == "right") return formatLength(style.right);
741
- if (property == "bottom") return formatLength(style.bottom);
742
- if (property == "left") return formatLength(style.left);
743
- if (property == "margin-top") return formatLength(style.margin.top);
744
- if (property == "margin-right") return formatLength(style.margin.right);
745
- if (property == "margin-bottom") return formatLength(style.margin.bottom);
746
- if (property == "margin-left") return formatLength(style.margin.left);
747
- if (property == "padding-top") return formatLength(style.padding.top);
748
- if (property == "padding-right") return formatLength(style.padding.right);
749
- if (property == "padding-bottom") return formatLength(style.padding.bottom);
750
- if (property == "padding-left") return formatLength(style.padding.left);
751
- if (property == "font-size") return formatNumber(style.font_size) + "px";
752
- if (property == "font-weight") return formatNumber((float)style.font_weight);
753
- if (property == "font-family") return style.font_family;
754
- if (property == "line-height") {
755
- return style.line_height.unit == Unit::Auto ? "normal" : formatLength(style.line_height);
756
- }
757
- if (property == "text-align") return alignTextNames[(int)style.text_align];
758
- if (property == "flex-direction") return flexNames[(int)style.flex_direction];
759
- if (property == "justify-content") return justifyNames[(int)style.justify_content];
760
- if (property == "align-items") return alignNames[(int)style.align_items];
761
- if (property == "gap") return formatLength(style.gap);
762
- if (property == "flex-grow") return formatNumber(style.flex_grow);
763
- if (property == "flex-shrink") return formatNumber(style.flex_shrink);
764
- if (property == "flex-basis") return formatLength(style.flex_basis);
765
- if (property == "border-radius") return formatNumber(style.border_radius) + "px";
766
- if (property == "opacity") return formatNumber(style.opacity);
767
- if (property == "z-index") return style.has_z_index ? formatNumber((float)style.z_index) : "auto";
768
- return "";
769
- }
770
-
771
123
  } // namespace xtgui