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.
- package/README.md +33 -0
- package/dist/src/cli/main.js +124 -30
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -1
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/state.js +20 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +6 -0
- package/dist/src/codegen/generator/tables.js +38 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/commonjs.d.ts +52 -0
- package/dist/src/driver/bundler/commonjs.js +493 -0
- package/dist/src/driver/bundler/commonjs.js.map +1 -0
- package/dist/src/driver/bundler/graph.js +14 -0
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +14 -0
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +8 -0
- package/dist/src/driver/compiler.d.ts +8 -1
- package/dist/src/driver/compiler.js +73 -5
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +53 -0
- package/dist/src/driver/config.js +141 -0
- package/dist/src/driver/config.js.map +1 -0
- package/dist/src/driver/icon.d.ts +62 -0
- package/dist/src/driver/icon.js +151 -0
- package/dist/src/driver/icon.js.map +1 -0
- package/dist/src/driver/index.d.ts +4 -0
- package/dist/src/driver/index.js +4 -0
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/mac-bundle.d.ts +41 -0
- package/dist/src/driver/mac-bundle.js +123 -0
- package/dist/src/driver/mac-bundle.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +27 -0
- package/dist/src/driver/win-icon.js +80 -0
- package/dist/src/driver/win-icon.js.map +1 -0
- package/dist/src/parser/statements.js +17 -4
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/tests/cli/main.test.js +46 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/config.test.d.ts +1 -0
- package/dist/tests/driver/config.test.js +124 -0
- package/dist/tests/driver/config.test.js.map +1 -0
- package/dist/tests/driver/icon.test.d.ts +1 -0
- package/dist/tests/driver/icon.test.js +421 -0
- package/dist/tests/driver/icon.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +109 -0
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/e2e/fetch.test.d.ts +12 -0
- package/dist/tests/e2e/fetch.test.js +272 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -0
- package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
- package/dist/tests/e2e/gui-dom.test.js +102 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -0
- package/dist/tests/e2e/gui-events.test.d.ts +5 -0
- package/dist/tests/e2e/gui-events.test.js +60 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +31 -0
- package/dist/tests/e2e/gui-helpers.js +74 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
- package/dist/tests/e2e/gui-layout.test.js +88 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -0
- package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
- package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
- package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
- package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
- package/dist/tests/e2e/gui-paint.test.js +111 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -0
- package/dist/tests/e2e/gui-script.test.d.ts +5 -0
- package/dist/tests/e2e/gui-script.test.js +78 -0
- package/dist/tests/e2e/gui-script.test.js.map +1 -0
- package/dist/tests/e2e/gui-style.test.d.ts +5 -0
- package/dist/tests/e2e/gui-style.test.js +175 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -0
- package/dist/tests/e2e/icon.test.d.ts +7 -0
- package/dist/tests/e2e/icon.test.js +80 -0
- package/dist/tests/e2e/icon.test.js.map +1 -0
- package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
- package/dist/tests/e2e/npm-modules.test.js +47 -1
- package/dist/tests/e2e/npm-modules.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
- package/dist/tests/parser/statements.test.js +11 -0
- package/dist/tests/parser/statements.test.js.map +1 -1
- package/package.json +1 -1
- package/runtime/ext_gui/css.cpp +4 -517
- package/runtime/ext_gui/css_internal.h +27 -0
- package/runtime/ext_gui/css_match.cpp +195 -0
- package/runtime/ext_gui/css_selector.cpp +207 -0
- package/runtime/ext_gui/css_sheet.cpp +129 -0
- package/runtime/ext_gui/dom.cpp +7 -403
- package/runtime/ext_gui/dom_api.cpp +63 -1146
- package/runtime/ext_gui/dom_api_document.cpp +96 -0
- package/runtime/ext_gui/dom_api_events.cpp +123 -0
- package/runtime/ext_gui/dom_api_internal.h +135 -0
- package/runtime/ext_gui/dom_api_node.cpp +329 -0
- package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
- package/runtime/ext_gui/dom_api_proto.cpp +130 -0
- package/runtime/ext_gui/dom_api_style.cpp +192 -0
- package/runtime/ext_gui/dom_internal.h +39 -0
- package/runtime/ext_gui/dom_parse.cpp +348 -0
- package/runtime/ext_gui/dom_serialize.cpp +54 -0
- package/runtime/ext_gui/gui.cpp +56 -286
- package/runtime/ext_gui/gui_events.cpp +294 -0
- package/runtime/ext_gui/gui_internal.h +29 -0
- package/runtime/ext_gui/layout.cpp +6 -597
- package/runtime/ext_gui/layout_flex.cpp +200 -0
- package/runtime/ext_gui/layout_flow.cpp +191 -0
- package/runtime/ext_gui/layout_flow_internal.h +149 -0
- package/runtime/ext_gui/layout_inline.cpp +181 -0
- package/runtime/ext_gui/layout_internal.h +20 -0
- package/runtime/ext_gui/renderer.cpp +15 -679
- package/runtime/ext_gui/renderer_image.cpp +233 -0
- package/runtime/ext_gui/renderer_internal.h +112 -0
- package/runtime/ext_gui/renderer_shaders.h +108 -0
- package/runtime/ext_gui/renderer_text.cpp +342 -0
- package/runtime/ext_gui/style.cpp +12 -660
- package/runtime/ext_gui/style_internal.h +33 -0
- package/runtime/ext_gui/style_print.cpp +113 -0
- package/runtime/ext_gui/style_ua.cpp +98 -0
- package/runtime/ext_gui/style_values.cpp +468 -0
- package/runtime/rt.h +6 -0
- package/runtime/rt_internal.h +4 -0
- package/runtime/xt_builtins.c +1 -0
- package/runtime/xt_containers/access.inc +32 -1
- package/runtime/xt_fetch/buffer.inc +64 -0
- package/runtime/xt_fetch/headers.inc +312 -0
- package/runtime/xt_fetch/request.inc +386 -0
- package/runtime/xt_fetch/response.inc +107 -0
- package/runtime/xt_fetch/socket.inc +72 -0
- package/runtime/xt_fetch/url.inc +108 -0
- package/runtime/xt_fetch.c +39 -0
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_typed_array.c +614 -0
- package/src/cli/main.ts +137 -29
- package/src/codegen/generator/calls/access.ts +9 -1
- package/src/codegen/generator/state.ts +20 -0
- package/src/codegen/generator/tables.ts +40 -0
- package/src/driver/bundler/commonjs.ts +553 -0
- package/src/driver/bundler/graph.ts +14 -0
- package/src/driver/bundler/merge.ts +15 -0
- package/src/driver/bundler/types.ts +8 -0
- package/src/driver/compiler.ts +83 -5
- package/src/driver/config.ts +173 -0
- package/src/driver/icon.ts +184 -0
- package/src/driver/index.ts +30 -0
- package/src/driver/mac-bundle.ts +156 -0
- package/src/driver/win-icon.ts +96 -0
- package/src/parser/statements.ts +17 -4
- package/dist/tests/e2e/gui.test.d.ts +0 -12
- package/dist/tests/e2e/gui.test.js +0 -702
- package/dist/tests/e2e/gui.test.js.map +0 -1
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — CSS declaration application (value parsing and how each
|
|
3
|
+
* property maps onto `XtStyle`).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "style_internal.h"
|
|
7
|
+
|
|
8
|
+
#include <cstdlib>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
namespace xtgui {
|
|
12
|
+
|
|
13
|
+
/* -- small helpers -------------------------------------------------------- */
|
|
14
|
+
|
|
15
|
+
static void setEdge(Edges *edges, const std::string &side, Length value) {
|
|
16
|
+
if (side == "top") edges->top = value;
|
|
17
|
+
else if (side == "right") edges->right = value;
|
|
18
|
+
else if (side == "bottom") edges->bottom = value;
|
|
19
|
+
else if (side == "left") edges->left = value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static bool parseEdgeLengths(const std::string &value, Edges *edges) {
|
|
23
|
+
std::vector<std::string> parts = xt_css_split_whitespace(value);
|
|
24
|
+
if (parts.empty() || parts.size() > 4) return false;
|
|
25
|
+
Length values[4];
|
|
26
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
27
|
+
Length length = xt_css_parse_length(parts[i]);
|
|
28
|
+
if (length.unit == Unit::Invalid) {
|
|
29
|
+
std::string keyword = xt_css_lower(parts[i]);
|
|
30
|
+
if (keyword == "thin") length = {1.0f, Unit::Px};
|
|
31
|
+
else if (keyword == "medium") length = {3.0f, Unit::Px};
|
|
32
|
+
else if (keyword == "thick") length = {5.0f, Unit::Px};
|
|
33
|
+
else return false;
|
|
34
|
+
}
|
|
35
|
+
values[i] = length;
|
|
36
|
+
}
|
|
37
|
+
switch (parts.size()) {
|
|
38
|
+
case 1:
|
|
39
|
+
edges->set(values[0]);
|
|
40
|
+
break;
|
|
41
|
+
case 2:
|
|
42
|
+
edges->top = edges->bottom = values[0];
|
|
43
|
+
edges->right = edges->left = values[1];
|
|
44
|
+
break;
|
|
45
|
+
case 3:
|
|
46
|
+
edges->top = values[0];
|
|
47
|
+
edges->right = edges->left = values[1];
|
|
48
|
+
edges->bottom = values[2];
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
edges->top = values[0];
|
|
52
|
+
edges->right = values[1];
|
|
53
|
+
edges->bottom = values[2];
|
|
54
|
+
edges->left = values[3];
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static bool assignLength(Length *target, const std::string &value) {
|
|
61
|
+
Length length = xt_css_parse_length(value);
|
|
62
|
+
if (length.unit == Unit::Invalid) return false;
|
|
63
|
+
*target = length;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static bool assignColor(Color *target, bool *has, const std::string &value) {
|
|
68
|
+
Color color = xt_css_parse_color(value);
|
|
69
|
+
if (!color.valid) return false;
|
|
70
|
+
*target = color;
|
|
71
|
+
*has = true;
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
float xt_style_resolve_absolute(const Length &length, float base, float em, float root, float vw,
|
|
76
|
+
float vh) {
|
|
77
|
+
switch (length.unit) {
|
|
78
|
+
case Unit::Px:
|
|
79
|
+
case Unit::Number:
|
|
80
|
+
return length.value;
|
|
81
|
+
case Unit::Percent:
|
|
82
|
+
return base * length.value / 100.0f;
|
|
83
|
+
case Unit::Em:
|
|
84
|
+
return em * length.value;
|
|
85
|
+
case Unit::Rem:
|
|
86
|
+
return root * length.value;
|
|
87
|
+
case Unit::Vw:
|
|
88
|
+
return vw * length.value / 100.0f;
|
|
89
|
+
case Unit::Vh:
|
|
90
|
+
return vh * length.value / 100.0f;
|
|
91
|
+
default:
|
|
92
|
+
return 0.0f;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static bool parseEnum(const std::string &value, const char *const *names, int count, int *out) {
|
|
97
|
+
std::string text = xt_css_lower(xt_css_trim(value));
|
|
98
|
+
for (int i = 0; i < count; i++) {
|
|
99
|
+
if (text == names[i]) {
|
|
100
|
+
*out = i;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* -- transitions ---------------------------------------------------------- */
|
|
108
|
+
|
|
109
|
+
static bool parseTimeSeconds(const std::string &text, float *out) {
|
|
110
|
+
std::string token = xt_css_trim(text);
|
|
111
|
+
if (token.empty()) return false;
|
|
112
|
+
const char *begin = token.c_str();
|
|
113
|
+
char *end = nullptr;
|
|
114
|
+
double value = std::strtod(begin, &end);
|
|
115
|
+
if (end == begin) return false;
|
|
116
|
+
std::string unit = xt_css_lower(xt_css_trim(std::string(end)));
|
|
117
|
+
if (unit == "ms") {
|
|
118
|
+
*out = (float)(value / 1000.0);
|
|
119
|
+
} else if (unit.empty() || unit == "s") {
|
|
120
|
+
*out = (float)value;
|
|
121
|
+
} else {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static bool parseTimingFunction(const std::string &text, TimingFunction *out) {
|
|
128
|
+
std::string token = xt_css_lower(xt_css_trim(text));
|
|
129
|
+
if (token == "linear") {
|
|
130
|
+
*out = TimingFunction::Linear;
|
|
131
|
+
} else if (token == "ease") {
|
|
132
|
+
*out = TimingFunction::Ease;
|
|
133
|
+
} else if (token == "ease-in") {
|
|
134
|
+
*out = TimingFunction::EaseIn;
|
|
135
|
+
} else if (token == "ease-out") {
|
|
136
|
+
*out = TimingFunction::EaseOut;
|
|
137
|
+
} else if (token == "ease-in-out") {
|
|
138
|
+
*out = TimingFunction::EaseInOut;
|
|
139
|
+
} else {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static std::vector<std::string> splitCommas(const std::string &text) {
|
|
146
|
+
std::vector<std::string> parts;
|
|
147
|
+
size_t start = 0;
|
|
148
|
+
for (size_t i = 0; i <= text.size(); i++) {
|
|
149
|
+
if (i == text.size() || text[i] == ',') {
|
|
150
|
+
std::string part = xt_css_trim(text.substr(start, i - start));
|
|
151
|
+
if (!part.empty()) parts.push_back(part);
|
|
152
|
+
start = i + 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return parts;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static void parseTransitionShorthand(const std::string &value, std::vector<TransitionSpec> *out) {
|
|
159
|
+
out->clear();
|
|
160
|
+
for (const std::string &group : splitCommas(value)) {
|
|
161
|
+
std::vector<std::string> tokens = xt_css_split_whitespace(group);
|
|
162
|
+
if (tokens.empty()) continue;
|
|
163
|
+
TransitionSpec spec;
|
|
164
|
+
int time_seen = 0;
|
|
165
|
+
for (const std::string &token : tokens) {
|
|
166
|
+
float seconds = 0;
|
|
167
|
+
TimingFunction timing = TimingFunction::Ease;
|
|
168
|
+
if (parseTimeSeconds(token, &seconds)) {
|
|
169
|
+
if (time_seen == 0) {
|
|
170
|
+
spec.duration = seconds;
|
|
171
|
+
} else {
|
|
172
|
+
spec.delay = seconds;
|
|
173
|
+
}
|
|
174
|
+
time_seen++;
|
|
175
|
+
} else if (parseTimingFunction(token, &timing)) {
|
|
176
|
+
spec.timing = timing;
|
|
177
|
+
} else {
|
|
178
|
+
spec.property = xt_css_lower(token);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
out->push_back(spec);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* -- declaration application ---------------------------------------------- */
|
|
186
|
+
|
|
187
|
+
void xt_style_apply_declaration(XtStyle *style, const std::string &property,
|
|
188
|
+
const std::string &rawValue, const ApplyContext &context) {
|
|
189
|
+
std::string value = xt_css_trim(rawValue);
|
|
190
|
+
|
|
191
|
+
if (property == "display") {
|
|
192
|
+
static const char *const names[] = {"none", "block", "inline", "inline-block", "flex", "list-item"};
|
|
193
|
+
int index = 0;
|
|
194
|
+
if (parseEnum(value, names, 6, &index)) style->display = (Display)index;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (property == "position") {
|
|
198
|
+
static const char *const names[] = {"static", "relative", "absolute", "fixed"};
|
|
199
|
+
int index = 0;
|
|
200
|
+
if (parseEnum(value, names, 4, &index)) style->position = (Position)index;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (property == "width") { assignLength(&style->width, value); return; }
|
|
204
|
+
if (property == "height") { assignLength(&style->height, value); return; }
|
|
205
|
+
if (property == "min-width") { assignLength(&style->min_width, value); return; }
|
|
206
|
+
if (property == "min-height") { assignLength(&style->min_height, value); return; }
|
|
207
|
+
if (property == "max-width") { assignLength(&style->max_width, value); return; }
|
|
208
|
+
if (property == "max-height") { assignLength(&style->max_height, value); return; }
|
|
209
|
+
if (property == "top") { assignLength(&style->top, value); return; }
|
|
210
|
+
if (property == "right") { assignLength(&style->right, value); return; }
|
|
211
|
+
if (property == "bottom") { assignLength(&style->bottom, value); return; }
|
|
212
|
+
if (property == "left") { assignLength(&style->left, value); return; }
|
|
213
|
+
|
|
214
|
+
if (property == "margin") { parseEdgeLengths(value, &style->margin); return; }
|
|
215
|
+
if (property == "padding") { parseEdgeLengths(value, &style->padding); return; }
|
|
216
|
+
if (property == "margin-top") { setEdge(&style->margin, "top", xt_css_parse_length(value)); return; }
|
|
217
|
+
if (property == "margin-right") { setEdge(&style->margin, "right", xt_css_parse_length(value)); return; }
|
|
218
|
+
if (property == "margin-bottom") { setEdge(&style->margin, "bottom", xt_css_parse_length(value)); return; }
|
|
219
|
+
if (property == "margin-left") { setEdge(&style->margin, "left", xt_css_parse_length(value)); return; }
|
|
220
|
+
if (property == "padding-top") { setEdge(&style->padding, "top", xt_css_parse_length(value)); return; }
|
|
221
|
+
if (property == "padding-right") { setEdge(&style->padding, "right", xt_css_parse_length(value)); return; }
|
|
222
|
+
if (property == "padding-bottom") { setEdge(&style->padding, "bottom", xt_css_parse_length(value)); return; }
|
|
223
|
+
if (property == "padding-left") { setEdge(&style->padding, "left", xt_css_parse_length(value)); return; }
|
|
224
|
+
|
|
225
|
+
if (property == "border-width") { parseEdgeLengths(value, &style->border_width); return; }
|
|
226
|
+
if (property == "border-top-width") { setEdge(&style->border_width, "top", xt_css_parse_length(value)); return; }
|
|
227
|
+
if (property == "border-right-width") { setEdge(&style->border_width, "right", xt_css_parse_length(value)); return; }
|
|
228
|
+
if (property == "border-bottom-width") { setEdge(&style->border_width, "bottom", xt_css_parse_length(value)); return; }
|
|
229
|
+
if (property == "border-left-width") { setEdge(&style->border_width, "left", xt_css_parse_length(value)); return; }
|
|
230
|
+
if (property == "border-radius") {
|
|
231
|
+
Length length = xt_css_parse_length(value);
|
|
232
|
+
if (length.unit == Unit::Px || length.unit == Unit::Number) style->border_radius = length.value;
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (property == "border-style" || property == "border-top-style" || property == "border-right-style" ||
|
|
236
|
+
property == "border-bottom-style" || property == "border-left-style") {
|
|
237
|
+
static const char *const names[] = {"none", "solid", "dashed", "dotted"};
|
|
238
|
+
int index = 0;
|
|
239
|
+
if (parseEnum(value, names, 4, &index)) style->border_style = (BorderStyle)index;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (property == "border-color" || property == "border-top-color" || property == "border-right-color" ||
|
|
243
|
+
property == "border-bottom-color" || property == "border-left-color") {
|
|
244
|
+
assignColor(&style->border_color, &style->has_border_color, value);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (property == "border" || property == "border-top" || property == "border-right" ||
|
|
248
|
+
property == "border-bottom" || property == "border-left") {
|
|
249
|
+
for (const std::string &token : xt_css_split_whitespace(value)) {
|
|
250
|
+
Length length = xt_css_parse_length(token);
|
|
251
|
+
if (length.unit == Unit::Px || length.unit == Unit::Number) {
|
|
252
|
+
if (property == "border") style->border_width.set(length);
|
|
253
|
+
else setEdge(&style->border_width, property.substr(7), length);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
static const char *const names[] = {"none", "solid", "dashed", "dotted"};
|
|
257
|
+
int index = 0;
|
|
258
|
+
if (parseEnum(token, names, 4, &index)) {
|
|
259
|
+
style->border_style = (BorderStyle)index;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
Color color = xt_css_parse_color(token);
|
|
263
|
+
if (color.valid) {
|
|
264
|
+
style->border_color = color;
|
|
265
|
+
style->has_border_color = true;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (property == "color") {
|
|
272
|
+
Color color = xt_css_parse_color(value);
|
|
273
|
+
if (color.valid) style->color = color;
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (property == "background-color") { assignColor(&style->background, &style->has_background, value); return; }
|
|
277
|
+
if (property == "background") {
|
|
278
|
+
Color color = xt_css_parse_color(value);
|
|
279
|
+
if (color.valid) {
|
|
280
|
+
style->background = color;
|
|
281
|
+
style->has_background = true;
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (property == "font-size") {
|
|
287
|
+
Length length = xt_css_parse_length(value);
|
|
288
|
+
if (length.unit == Unit::Invalid) return;
|
|
289
|
+
/* `em`/`%` resolve against the *parent* font size, never the element's own
|
|
290
|
+
* (possibly UA-set) size. */
|
|
291
|
+
style->font_size = xt_style_resolve_absolute(length, context.parentFontSize, context.parentFontSize,
|
|
292
|
+
context.rootFontSize, context.viewportWidth, context.viewportHeight);
|
|
293
|
+
if (style->font_size <= 0.0f) style->font_size = 16.0f;
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (property == "font-weight") {
|
|
297
|
+
std::string text = xt_css_lower(value);
|
|
298
|
+
if (text == "normal") style->font_weight = 400;
|
|
299
|
+
else if (text == "bold") style->font_weight = 700;
|
|
300
|
+
else if (text == "lighter") style->font_weight = 100;
|
|
301
|
+
else if (text == "bolder") style->font_weight = 700;
|
|
302
|
+
else {
|
|
303
|
+
float number = 0;
|
|
304
|
+
if (xt_css_parse_number(text, &number)) style->font_weight = (int)number;
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (property == "font-family") {
|
|
309
|
+
style->font_family = value;
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (property == "font-style") {
|
|
313
|
+
style->font_style = (xt_css_lower(value) == "italic") ? FontStyle::Italic : FontStyle::Normal;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (property == "line-height") {
|
|
317
|
+
std::string text = xt_css_lower(value);
|
|
318
|
+
if (text == "normal") {
|
|
319
|
+
style->line_height = {};
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
Length length = xt_css_parse_length(text);
|
|
323
|
+
if (length.unit == Unit::Invalid) return;
|
|
324
|
+
/* Relative units are resolved in `finalizeStyle`, once the element's own
|
|
325
|
+
* font size is settled. */
|
|
326
|
+
style->line_height = length;
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (property == "text-align") {
|
|
330
|
+
std::string text = xt_css_lower(value);
|
|
331
|
+
if (text == "left" || text == "start") style->text_align = TextAlign::Start;
|
|
332
|
+
else if (text == "right" || text == "end") style->text_align = TextAlign::End;
|
|
333
|
+
else if (text == "center") style->text_align = TextAlign::Center;
|
|
334
|
+
else if (text == "justify") style->text_align = TextAlign::Justify;
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (property == "white-space") {
|
|
338
|
+
static const char *const names[] = {"normal", "nowrap", "pre", "pre-wrap", "pre-line"};
|
|
339
|
+
int index = 0;
|
|
340
|
+
if (parseEnum(value, names, 5, &index)) style->white_space = (WhiteSpace)index;
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (property == "flex-direction") {
|
|
345
|
+
static const char *const names[] = {"row", "row-reverse", "column", "column-reverse"};
|
|
346
|
+
int index = 0;
|
|
347
|
+
if (parseEnum(value, names, 4, &index)) style->flex_direction = (FlexDirection)index;
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (property == "justify-content") {
|
|
351
|
+
static const char *const names[] = {"flex-start", "flex-end", "center", "space-between",
|
|
352
|
+
"space-around", "space-evenly"};
|
|
353
|
+
int index = 0;
|
|
354
|
+
if (parseEnum(value, names, 6, &index)) style->justify_content = (JustifyContent)index;
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (property == "align-items") {
|
|
358
|
+
static const char *const names[] = {"stretch", "flex-start", "flex-end", "center", "baseline"};
|
|
359
|
+
int index = 0;
|
|
360
|
+
if (parseEnum(value, names, 5, &index)) style->align_items = (AlignItems)index;
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (property == "gap" || property == "row-gap" || property == "column-gap") {
|
|
364
|
+
assignLength(&style->gap, value);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (property == "flex-grow") {
|
|
368
|
+
float number = 0;
|
|
369
|
+
if (xt_css_parse_number(value, &number)) style->flex_grow = number;
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (property == "flex-shrink") {
|
|
373
|
+
float number = 0;
|
|
374
|
+
if (xt_css_parse_number(value, &number)) style->flex_shrink = number;
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (property == "flex-basis") { assignLength(&style->flex_basis, value); return; }
|
|
378
|
+
if (property == "flex") {
|
|
379
|
+
std::string text = xt_css_lower(value);
|
|
380
|
+
if (text == "none") {
|
|
381
|
+
style->flex_grow = 0;
|
|
382
|
+
style->flex_shrink = 0;
|
|
383
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (text == "auto") {
|
|
387
|
+
style->flex_grow = 1;
|
|
388
|
+
style->flex_shrink = 1;
|
|
389
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (text == "initial") {
|
|
393
|
+
style->flex_grow = 0;
|
|
394
|
+
style->flex_shrink = 1;
|
|
395
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
std::vector<std::string> parts = xt_css_split_whitespace(text);
|
|
399
|
+
style->flex_grow = 0;
|
|
400
|
+
style->flex_shrink = 1;
|
|
401
|
+
style->flex_basis = {0.0f, Unit::Auto};
|
|
402
|
+
size_t index = 0;
|
|
403
|
+
float number = 0;
|
|
404
|
+
if (index < parts.size() && xt_css_parse_number(parts[index], &number)) {
|
|
405
|
+
style->flex_grow = number;
|
|
406
|
+
index++;
|
|
407
|
+
if (index < parts.size() && xt_css_parse_number(parts[index], &number)) {
|
|
408
|
+
style->flex_shrink = number;
|
|
409
|
+
index++;
|
|
410
|
+
}
|
|
411
|
+
if (index >= parts.size()) style->flex_basis = {0.0f, Unit::Px};
|
|
412
|
+
}
|
|
413
|
+
if (index < parts.size()) assignLength(&style->flex_basis, parts[index]);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (property == "opacity") {
|
|
418
|
+
float number = 0;
|
|
419
|
+
if (xt_css_parse_number(value, &number)) style->opacity = number < 0 ? 0 : (number > 1 ? 1 : number);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (property == "overflow" || property == "overflow-x" || property == "overflow-y") {
|
|
423
|
+
static const char *const names[] = {"visible", "hidden", "scroll", "auto"};
|
|
424
|
+
int index = 0;
|
|
425
|
+
if (parseEnum(value, names, 4, &index)) style->overflow = (Overflow)index;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (property == "z-index") {
|
|
429
|
+
float number = 0;
|
|
430
|
+
if (xt_css_parse_number(value, &number)) {
|
|
431
|
+
style->z_index = (int)number;
|
|
432
|
+
style->has_z_index = true;
|
|
433
|
+
}
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
if (property == "transition") {
|
|
437
|
+
parseTransitionShorthand(value, &style->transitions);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (property == "transition-property") {
|
|
441
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
442
|
+
style->transitions.resize(parts.size());
|
|
443
|
+
for (size_t i = 0; i < parts.size(); i++) style->transitions[i].property = xt_css_lower(parts[i]);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (property == "transition-duration" || property == "transition-delay") {
|
|
447
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
448
|
+
style->transitions.resize(parts.size());
|
|
449
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
450
|
+
float seconds = 0;
|
|
451
|
+
if (!parseTimeSeconds(parts[i], &seconds)) continue;
|
|
452
|
+
if (property == "transition-duration") style->transitions[i].duration = seconds;
|
|
453
|
+
else style->transitions[i].delay = seconds;
|
|
454
|
+
}
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (property == "transition-timing-function") {
|
|
458
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
459
|
+
style->transitions.resize(parts.size());
|
|
460
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
461
|
+
TimingFunction timing = TimingFunction::Ease;
|
|
462
|
+
if (parseTimingFunction(parts[i], &timing)) style->transitions[i].timing = timing;
|
|
463
|
+
}
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
} // namespace xtgui
|
package/runtime/rt.h
CHANGED
|
@@ -218,6 +218,12 @@ xt_value xt_crypto_create_hash(int32_t argc, xt_value *argv);
|
|
|
218
218
|
/* -- node:child_process --------------------------------------------------- */
|
|
219
219
|
xt_value xt_child_process_spawn_sync(int32_t argc, xt_value *argv);
|
|
220
220
|
|
|
221
|
+
/* -- fetch ---------------------------------------------------------------- */
|
|
222
|
+
/** Implements the global `fetch(input, init)`; returns a settled promise. */
|
|
223
|
+
xt_value xt_fetch(int32_t argc, xt_value *argv);
|
|
224
|
+
/** Construct a `TypeError` with one message argument (used by `fetch`). */
|
|
225
|
+
xt_value xt_type_error_ctor(int32_t argc, xt_value *argv);
|
|
226
|
+
|
|
221
227
|
/* -- promises / async ----------------------------------------------------- */
|
|
222
228
|
xt_value xt_promise_resolve(xt_value value);
|
|
223
229
|
xt_value xt_promise_reject(xt_value value);
|
package/runtime/rt_internal.h
CHANGED
|
@@ -286,4 +286,8 @@ int xt_value_equals(xt_value a, xt_value b);
|
|
|
286
286
|
xt_array *xt_as_array(xt_value value);
|
|
287
287
|
xt_value xt_arg_at(int32_t argc, xt_value *argv, int32_t index);
|
|
288
288
|
|
|
289
|
+
/* Typed arrays (xt_typed_array.c). */
|
|
290
|
+
int xt_typed_array_kind_of(xt_value value);
|
|
291
|
+
double xt_typed_array_coerce(int kind, double value);
|
|
292
|
+
|
|
289
293
|
#endif /* XT_RT_INTERNAL_H */
|
package/runtime/xt_builtins.c
CHANGED
|
@@ -305,6 +305,7 @@ XT_BUILTIN_TRAMPOLINE(xt_builtin_value_setTimeout, xt_set_timeout)
|
|
|
305
305
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_clearTimeout, xt_clear_timeout)
|
|
306
306
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_setInterval, xt_set_interval)
|
|
307
307
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_clearInterval, xt_clear_interval)
|
|
308
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_fetch, xt_fetch)
|
|
308
309
|
|
|
309
310
|
xt_value xt_in(xt_value key, xt_value value) {
|
|
310
311
|
if (XT_IS_OBJECT(value)) return xt_object_has(value, key);
|
|
@@ -163,6 +163,37 @@ xt_value xt_set(xt_value target, xt_value key, xt_value value) {
|
|
|
163
163
|
return xt_array_set(target, key, value);
|
|
164
164
|
}
|
|
165
165
|
if (XT_IS_FUNCTION(target)) return xt_object_set(target, key, value);
|
|
166
|
-
if (XT_IS_OBJECT(target))
|
|
166
|
+
if (XT_IS_OBJECT(target)) {
|
|
167
|
+
/* Writes to a typed-array element are coerced to its element type. */
|
|
168
|
+
int typed = xt_typed_array_kind_of(target);
|
|
169
|
+
if (typed >= 0) {
|
|
170
|
+
if (XT_IS_STRING(key)) {
|
|
171
|
+
xt_string *k = xt_as_string(key);
|
|
172
|
+
if ((k->length == 6 && memcmp(k->data, "length", 6) == 0) ||
|
|
173
|
+
(k->length == 10 && memcmp(k->data, "byteLength", 10) == 0) ||
|
|
174
|
+
(k->length == 10 && memcmp(k->data, "byteOffset", 10) == 0)) {
|
|
175
|
+
xt_throw(xt_string_from_cstr("TypeError: Cannot assign to read only property"));
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
uint32_t index = 0;
|
|
180
|
+
int isIndex = 0;
|
|
181
|
+
if (XT_IS_NUMBER(key)) {
|
|
182
|
+
int32_t numeric = xt_to_int32(key);
|
|
183
|
+
if (numeric >= 0) {
|
|
184
|
+
index = (uint32_t)numeric;
|
|
185
|
+
isIndex = 1;
|
|
186
|
+
}
|
|
187
|
+
} else if (XT_IS_STRING(key)) {
|
|
188
|
+
isIndex = xt_key_is_array_index(xt_as_string(key), &index);
|
|
189
|
+
}
|
|
190
|
+
if (isIndex) {
|
|
191
|
+
double length = xt_to_number(xt_object_get_cstr(target, "length"));
|
|
192
|
+
if (index >= (uint32_t)length) return value; /* out-of-bounds writes are ignored */
|
|
193
|
+
return xt_object_set(target, key, xt_number(xt_typed_array_coerce(typed, xt_to_number(value))));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return xt_object_set(target, key, value);
|
|
197
|
+
}
|
|
167
198
|
return value;
|
|
168
199
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* -- growable byte buffer ------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Fetch needs to accumulate raw response bytes before the headers and body can
|
|
5
|
+
* be parsed. A small growable buffer keeps that logic in one place; it is
|
|
6
|
+
* always NUL-terminated so it can also back a JS string, but the explicit
|
|
7
|
+
* `length` is authoritative because a response body may contain NUL bytes.
|
|
8
|
+
*/
|
|
9
|
+
typedef struct {
|
|
10
|
+
char *data;
|
|
11
|
+
size_t length;
|
|
12
|
+
size_t capacity;
|
|
13
|
+
} xt_fetch_buffer;
|
|
14
|
+
|
|
15
|
+
static void xt_fetch_buffer_init(xt_fetch_buffer *buffer) {
|
|
16
|
+
buffer->data = NULL;
|
|
17
|
+
buffer->length = 0;
|
|
18
|
+
buffer->capacity = 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static void xt_fetch_buffer_free(xt_fetch_buffer *buffer) {
|
|
22
|
+
free(buffer->data);
|
|
23
|
+
buffer->data = NULL;
|
|
24
|
+
buffer->length = 0;
|
|
25
|
+
buffer->capacity = 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static void xt_fetch_buffer_append(xt_fetch_buffer *buffer, const char *data, size_t length) {
|
|
29
|
+
if (length == 0) {
|
|
30
|
+
if (!buffer->data) {
|
|
31
|
+
buffer->capacity = 1;
|
|
32
|
+
buffer->data = (char *)malloc(1);
|
|
33
|
+
if (!buffer->data) abort();
|
|
34
|
+
buffer->data[0] = '\0';
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (buffer->length + length + 1 > buffer->capacity) {
|
|
39
|
+
size_t capacity = buffer->capacity ? buffer->capacity : 256;
|
|
40
|
+
while (capacity < buffer->length + length + 1) capacity *= 2;
|
|
41
|
+
char *grown = (char *)realloc(buffer->data, capacity);
|
|
42
|
+
if (!grown) abort();
|
|
43
|
+
buffer->data = grown;
|
|
44
|
+
buffer->capacity = capacity;
|
|
45
|
+
}
|
|
46
|
+
memcpy(buffer->data + buffer->length, data, length);
|
|
47
|
+
buffer->length += length;
|
|
48
|
+
buffer->data[buffer->length] = '\0';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static void xt_fetch_buffer_append_cstr(xt_fetch_buffer *buffer, const char *text) {
|
|
52
|
+
xt_fetch_buffer_append(buffer, text, strlen(text));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* -- string helpers ------------------------------------------------------- */
|
|
56
|
+
|
|
57
|
+
static void xt_fetch_lowercase(const char *input, char *output, size_t size) {
|
|
58
|
+
size_t i = 0;
|
|
59
|
+
for (; input[i] && i + 1 < size; i++) {
|
|
60
|
+
char c = input[i];
|
|
61
|
+
output[i] = (c >= 'A' && c <= 'Z') ? (char)(c + 32) : c;
|
|
62
|
+
}
|
|
63
|
+
output[i] = '\0';
|
|
64
|
+
}
|