xbintsc 0.5.45 → 0.5.52
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/AGENTS.md +1 -1
- package/README.md +5 -4
- package/README.zh-CN.md +4 -3
- package/dist/src/cli/extensions.d.ts +24 -0
- package/dist/src/cli/extensions.js +62 -0
- package/dist/src/cli/extensions.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/help.js +3 -1
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hints.js +8 -3
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +21 -28
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +3 -1
- package/dist/src/diagnostics/diagnostic.js +2 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/driver/build-key.d.ts +2 -0
- package/dist/src/driver/build-key.js +1 -0
- package/dist/src/driver/build-key.js.map +1 -1
- package/dist/src/driver/compiler.js +61 -8
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +4 -0
- package/dist/src/driver/config.js +2 -0
- package/dist/src/driver/config.js.map +1 -1
- package/dist/src/driver/link-features.d.ts +37 -0
- package/dist/src/driver/link-features.js +123 -0
- package/dist/src/driver/link-features.js.map +1 -0
- package/dist/src/driver/options.d.ts +10 -0
- package/dist/src/driver/runtime-objects.d.ts +5 -0
- package/dist/src/driver/runtime-objects.js +20 -1
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/usage.d.ts +23 -0
- package/dist/src/driver/usage.js +353 -0
- package/dist/src/driver/usage.js.map +1 -0
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/catalog.js +1 -2
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/features.d.ts +34 -0
- package/dist/src/extensions/gui/features.js +165 -0
- package/dist/src/extensions/gui/features.js.map +1 -0
- package/dist/src/extensions/gui/index.js +10 -4
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/link-feature.d.ts +70 -0
- package/dist/src/extensions/link-feature.js +18 -0
- package/dist/src/extensions/link-feature.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +24 -4
- package/dist/src/extensions/registry.js +26 -3
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/tests/cli/hints.test.js +5 -7
- package/dist/tests/cli/hints.test.js.map +1 -1
- package/dist/tests/driver/link-features.test.js +105 -0
- package/dist/tests/driver/link-features.test.js.map +1 -0
- package/dist/tests/driver/usage.test.d.ts +1 -0
- package/dist/tests/driver/usage.test.js +88 -0
- package/dist/tests/driver/usage.test.js.map +1 -0
- package/dist/tests/e2e/gui-audio.test.js +4 -4
- package/dist/tests/e2e/gui-audio.test.js.map +1 -1
- package/dist/tests/e2e/gui-css-coverage.test.d.ts +9 -0
- package/dist/tests/e2e/gui-css-coverage.test.js +333 -0
- package/dist/tests/e2e/gui-css-coverage.test.js.map +1 -0
- package/dist/tests/e2e/gui-css-features.test.d.ts +6 -0
- package/dist/tests/e2e/gui-css-features.test.js +270 -0
- package/dist/tests/e2e/gui-css-features.test.js.map +1 -0
- package/dist/tests/e2e/gui-effects.test.js +92 -11
- package/dist/tests/e2e/gui-effects.test.js.map +1 -1
- package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
- package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
- package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
- package/dist/tests/e2e/gui-font-face.test.d.ts +10 -0
- package/dist/tests/e2e/gui-font-face.test.js +142 -0
- package/dist/tests/e2e/gui-font-face.test.js.map +1 -0
- package/dist/tests/e2e/gui-fonts.test.d.ts +10 -0
- package/dist/tests/e2e/gui-fonts.test.js +150 -0
- package/dist/tests/e2e/gui-fonts.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +10 -1
- package/dist/tests/e2e/gui-helpers.js +6 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +7 -3
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
- package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media.test.js +9 -9
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-paint.test.js +5 -2
- package/dist/tests/e2e/gui-paint.test.js.map +1 -1
- package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
- package/dist/tests/e2e/gui-shaping.test.js +47 -0
- package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
- package/dist/tests/e2e/gui-track-sizing.test.d.ts +6 -0
- package/dist/tests/e2e/gui-track-sizing.test.js +173 -0
- package/dist/tests/e2e/gui-track-sizing.test.js.map +1 -0
- package/dist/tests/e2e/gui-transform.test.js +3 -2
- package/dist/tests/e2e/gui-transform.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
- package/dist/tests/extensions/gui-features.test.d.ts +1 -0
- package/dist/tests/extensions/gui-features.test.js +175 -0
- package/dist/tests/extensions/gui-features.test.js.map +1 -0
- package/doc/ai/cli.md +5 -1
- package/doc/ai/extensions.md +56 -26
- package/doc/ai/troubleshooting.md +10 -7
- package/doc/ai/zh-CN/cli.md +5 -1
- package/doc/ai/zh-CN/extensions.md +48 -22
- package/doc/ai/zh-CN/troubleshooting.md +6 -5
- package/doc/gui/animation.md +39 -9
- package/doc/gui/api.md +2 -1
- package/doc/gui/build.md +137 -19
- package/doc/gui/canvas.md +1 -1
- package/doc/gui/dom.md +20 -4
- package/doc/gui/known-issues.md +63 -26
- package/doc/gui/layout.md +31 -8
- package/doc/gui/media.md +13 -7
- package/doc/gui/rendering.md +114 -39
- package/doc/gui/runtime.md +5 -0
- package/doc/gui/webgl.md +24 -6
- package/doc/gui.md +110 -47
- package/doc/implemented/cli.md +2 -0
- package/doc/implemented/extensions.md +9 -3
- package/doc/npm-package.md +4 -4
- package/doc/xbintsc.config.schema.json +10 -0
- package/doc/zh-CN/gui/animation.md +33 -10
- package/doc/zh-CN/gui/api.md +2 -1
- package/doc/zh-CN/gui/build.md +110 -16
- package/doc/zh-CN/gui/canvas.md +1 -1
- package/doc/zh-CN/gui/dom.md +16 -3
- package/doc/zh-CN/gui/known-issues.md +45 -15
- package/doc/zh-CN/gui/layout.md +23 -6
- package/doc/zh-CN/gui/media.md +11 -6
- package/doc/zh-CN/gui/rendering.md +84 -26
- package/doc/zh-CN/gui/runtime.md +3 -0
- package/doc/zh-CN/gui/webgl.md +3 -3
- package/doc/zh-CN/gui.md +92 -41
- package/doc/zh-CN/implemented/cli.md +2 -0
- package/doc/zh-CN/implemented/extensions.md +9 -3
- package/doc/zh-CN/npm-package.md +4 -3
- package/package.json +7 -7
- package/runtime/ext_gui/animation_values.cpp +425 -0
- package/runtime/ext_gui/animation_values.h +64 -0
- package/runtime/ext_gui/browser.cpp +22 -15
- package/runtime/ext_gui/browser_loop.cpp +13 -1
- package/runtime/ext_gui/canvas.h +1 -1
- package/runtime/ext_gui/canvas_raster.cpp +1 -1
- package/runtime/ext_gui/canvas_text.cpp +1 -1
- package/runtime/ext_gui/css.cpp +172 -21
- package/runtime/ext_gui/css.h +75 -4
- package/runtime/ext_gui/css_match.cpp +4 -0
- package/runtime/ext_gui/css_sheet.cpp +218 -2
- package/runtime/ext_gui/document.cpp +42 -192
- package/runtime/ext_gui/document.h +25 -12
- package/runtime/ext_gui/document_animation.cpp +428 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
- package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
- package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
- package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
- package/runtime/ext_gui/dom_api_style.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
- package/runtime/ext_gui/effect_values.cpp +245 -21
- package/runtime/ext_gui/gpu_bridge.c +28 -0
- package/runtime/ext_gui/gpu_feature.cpp +30 -0
- package/runtime/ext_gui/gpu_shader.cpp +22 -0
- package/runtime/ext_gui/gpu_shader_api.h +50 -0
- package/runtime/ext_gui/gradient_values.cpp +24 -0
- package/runtime/ext_gui/grid_values.cpp +23 -0
- package/runtime/ext_gui/gui.cpp +6 -37
- package/runtime/ext_gui/gui_canvas.cpp +14 -6
- package/runtime/ext_gui/gui_cursor.cpp +50 -0
- package/runtime/ext_gui/gui_engine.h +1 -18
- package/runtime/ext_gui/gui_events.cpp +19 -6
- package/runtime/ext_gui/gui_internal.h +3 -0
- package/runtime/ext_gui/gui_webgl.cpp +25 -10
- package/runtime/ext_gui/image_api.cpp +18 -0
- package/runtime/ext_gui/image_api.h +43 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
- package/runtime/ext_gui/image_bridge.c +22 -0
- package/runtime/ext_gui/image_feature.cpp +107 -0
- package/runtime/ext_gui/inline_svg.cpp +95 -8
- package/runtime/ext_gui/inline_svg.h +5 -1
- package/runtime/ext_gui/layout.cpp +15 -9
- package/runtime/ext_gui/layout.h +8 -2
- package/runtime/ext_gui/layout_flex.cpp +134 -29
- package/runtime/ext_gui/layout_flow.cpp +58 -7
- package/runtime/ext_gui/layout_flow_internal.h +39 -4
- package/runtime/ext_gui/layout_grid.cpp +31 -0
- package/runtime/ext_gui/layout_inline.cpp +26 -2
- package/runtime/ext_gui/layout_vertical.cpp +196 -0
- package/runtime/ext_gui/media.cpp +4 -2
- package/runtime/ext_gui/media.h +3 -3
- package/runtime/ext_gui/media_api.h +7 -6
- package/runtime/ext_gui/paint.cpp +67 -9
- package/runtime/ext_gui/paint.h +61 -8
- package/runtime/ext_gui/paint_backdrop.cpp +211 -0
- package/runtime/ext_gui/paint_background.cpp +175 -97
- package/runtime/ext_gui/paint_effects.cpp +12 -6
- package/runtime/ext_gui/paint_internal.h +27 -0
- package/runtime/ext_gui/paint_outline.cpp +44 -0
- package/runtime/ext_gui/paint_shadow.cpp +368 -0
- package/runtime/ext_gui/renderer.cpp +15 -7
- package/runtime/ext_gui/renderer.h +11 -2
- package/runtime/ext_gui/renderer_backdrop.cpp +374 -0
- package/runtime/ext_gui/renderer_bitmap.cpp +82 -0
- package/runtime/ext_gui/renderer_gradient.cpp +51 -17
- package/runtime/ext_gui/renderer_image.cpp +19 -7
- package/runtime/ext_gui/renderer_internal.h +21 -0
- package/runtime/ext_gui/renderer_layer.cpp +37 -6
- package/runtime/ext_gui/renderer_text.cpp +2 -1
- package/runtime/ext_gui/stb_truetype.h +5077 -0
- package/runtime/ext_gui/style.cpp +62 -8
- package/runtime/ext_gui/style.h +111 -4
- package/runtime/ext_gui/style_cascade.cpp +83 -0
- package/runtime/ext_gui/style_internal.h +13 -1
- package/runtime/ext_gui/style_length.cpp +92 -0
- package/runtime/ext_gui/style_print.cpp +83 -2
- package/runtime/ext_gui/style_svg.cpp +40 -0
- package/runtime/ext_gui/style_text.cpp +302 -0
- package/runtime/ext_gui/style_ui.cpp +150 -0
- package/runtime/ext_gui/style_values.cpp +76 -62
- package/runtime/ext_gui/style_values_internal.h +23 -0
- package/runtime/ext_gui/text.cpp +27 -499
- package/runtime/ext_gui/text.h +18 -9
- package/runtime/ext_gui/text_api.h +45 -0
- package/runtime/ext_gui/text_bridge.c +23 -0
- package/runtime/ext_gui/text_cache.cpp +12 -3
- package/runtime/ext_gui/text_font_db.cpp +427 -0
- package/runtime/ext_gui/text_font_paths.cpp +250 -0
- package/runtime/ext_gui/text_font_paths.h +39 -0
- package/runtime/ext_gui/text_font_sfnt.cpp +396 -0
- package/runtime/ext_gui/text_font_sfnt.h +44 -0
- package/runtime/ext_gui/text_fonts.cpp +348 -0
- package/runtime/ext_gui/text_fonts.h +78 -0
- package/runtime/ext_gui/text_fonts_internal.h +77 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
- package/runtime/ext_gui/text_hb.cpp +438 -0
- package/runtime/ext_gui/text_stb.cpp +369 -0
- package/runtime/ext_gui/transform.cpp +107 -9
- package/runtime/ext_gui/transform.h +5 -0
- package/runtime/ext_gui/webgl_api.cpp +19 -0
- package/runtime/ext_gui/webgl_api.h +53 -0
- package/runtime/ext_gui/webgl_bridge.c +25 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
- package/runtime/ext_gui/webgl_feature.cpp +82 -0
- package/runtime/ext_gui/webgl_feature.h +28 -0
- package/runtime/ext_gui/webgl_msl.cpp +41 -0
- package/runtime/ext_gui/webgl_msl.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +40 -32
- package/runtime/ext_gui/window.cpp +7 -7
- package/runtime/ext_media/decode_audio.cpp +1 -1
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +7 -7
- package/scripts/build-gui.ts +97 -98
- package/scripts/check-file-length.ts +1 -0
- package/scripts/gui-build-options.ts +122 -0
- package/src/cli/extensions.ts +72 -0
- package/src/cli/help.ts +3 -1
- package/src/cli/hints.ts +9 -3
- package/src/cli/main.ts +21 -27
- package/src/diagnostics/diagnostic.ts +2 -0
- package/src/driver/build-key.ts +3 -0
- package/src/driver/compiler.ts +63 -8
- package/src/driver/config.ts +6 -0
- package/src/driver/link-features.ts +163 -0
- package/src/driver/options.ts +10 -0
- package/src/driver/runtime-objects.ts +26 -1
- package/src/driver/usage.ts +376 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/catalog.ts +1 -2
- package/src/extensions/gui/features.ts +166 -0
- package/src/extensions/gui/index.ts +10 -4
- package/src/extensions/link-feature.ts +72 -0
- package/src/extensions/registry.ts +45 -4
- package/src/index.ts +3 -2
- package/dist/src/extensions/media/index.d.ts +0 -28
- package/dist/src/extensions/media/index.js +0 -59
- package/dist/src/extensions/media/index.js.map +0 -1
- package/dist/tests/extensions/media.test.js +0 -63
- package/dist/tests/extensions/media.test.js.map +0 -1
- package/src/extensions/media/index.ts +0 -65
- /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
|
@@ -136,6 +136,18 @@ static bool substituteVariables(const std::string &value,
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
void finalizeStyle(XtStyle *style, const ApplyContext &context) {
|
|
139
|
+
/* `letter-spacing` is resolved against the element's own font size. */
|
|
140
|
+
if (style->letter_spacing.unit != Unit::Px && style->letter_spacing.unit != Unit::Number) {
|
|
141
|
+
style->letter_spacing.value = xt_style_resolve_absolute(
|
|
142
|
+
style->letter_spacing, style->font_size, style->font_size, context.rootFontSize,
|
|
143
|
+
context.viewportWidth, context.viewportHeight);
|
|
144
|
+
style->letter_spacing.unit = Unit::Px;
|
|
145
|
+
}
|
|
146
|
+
/* `outline-color` defaults to the element's `color`. */
|
|
147
|
+
if (style->outline_style != BorderStyle::None && !style->has_outline_color) {
|
|
148
|
+
style->outline_color = style->color;
|
|
149
|
+
style->has_outline_color = true;
|
|
150
|
+
}
|
|
139
151
|
switch (style->line_height.unit) {
|
|
140
152
|
case Unit::Em:
|
|
141
153
|
case Unit::Percent:
|
|
@@ -145,6 +157,7 @@ void finalizeStyle(XtStyle *style, const ApplyContext &context) {
|
|
|
145
157
|
case Unit::Clamp:
|
|
146
158
|
case Unit::Min:
|
|
147
159
|
case Unit::Max:
|
|
160
|
+
case Unit::Calc:
|
|
148
161
|
style->line_height.value = xt_style_resolve_absolute(
|
|
149
162
|
style->line_height, style->font_size, style->font_size, context.rootFontSize,
|
|
150
163
|
context.viewportWidth, context.viewportHeight);
|
|
@@ -172,6 +185,11 @@ void inheritFrom(XtStyle *style, const XtStyle *parent) {
|
|
|
172
185
|
style->text_align = parent->text_align;
|
|
173
186
|
style->white_space = parent->white_space;
|
|
174
187
|
style->text_shadow = parent->text_shadow;
|
|
188
|
+
style->text_transform = parent->text_transform;
|
|
189
|
+
style->letter_spacing = parent->letter_spacing;
|
|
190
|
+
style->font_variant_numeric = parent->font_variant_numeric;
|
|
191
|
+
style->writing_mode = parent->writing_mode;
|
|
192
|
+
style->cursor = parent->cursor;
|
|
175
193
|
}
|
|
176
194
|
|
|
177
195
|
void applyCandidates(XtStyle *style, std::vector<Candidate> *candidates,
|
|
@@ -187,15 +205,43 @@ void applyCandidates(XtStyle *style, std::vector<Candidate> *candidates,
|
|
|
187
205
|
style->variables[candidate.declaration->property] = candidate.declaration->value;
|
|
188
206
|
}
|
|
189
207
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
std::string
|
|
193
|
-
if (value.find("var(") != std::string::npos) {
|
|
208
|
+
auto resolvedValue = [&](const Candidate &candidate, std::string *out) {
|
|
209
|
+
*out = candidate.declaration->value;
|
|
210
|
+
if (out->find("var(") != std::string::npos) {
|
|
194
211
|
std::string resolved;
|
|
195
|
-
if (!substituteVariables(
|
|
196
|
-
|
|
212
|
+
if (!substituteVariables(*out, style->variables, 0, &resolved)) return false;
|
|
213
|
+
*out = resolved;
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
};
|
|
217
|
+
/* `color` is computed before the other declarations: `currentColor` in them
|
|
218
|
+
* refers to this element's final colour regardless of source order. */
|
|
219
|
+
for (const Candidate &candidate : *candidates) {
|
|
220
|
+
if (isCustomProperty(candidate.declaration->property) ||
|
|
221
|
+
candidate.declaration->property != "color") {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
std::string value;
|
|
225
|
+
if (!resolvedValue(candidate, &value)) continue;
|
|
226
|
+
if (value == "inherit") {
|
|
227
|
+
xt_style_apply_inherit(style, nodeContext.parent, "color");
|
|
228
|
+
continue;
|
|
197
229
|
}
|
|
198
|
-
xt_style_apply_declaration(style,
|
|
230
|
+
xt_style_apply_declaration(style, "color", value, nodeContext);
|
|
231
|
+
}
|
|
232
|
+
for (const Candidate &candidate : *candidates) {
|
|
233
|
+
const std::string &property = candidate.declaration->property;
|
|
234
|
+
if (isCustomProperty(property) || property == "color") continue;
|
|
235
|
+
std::string value;
|
|
236
|
+
if (!resolvedValue(candidate, &value)) continue;
|
|
237
|
+
if (value == "inherit") {
|
|
238
|
+
xt_style_apply_inherit(style, nodeContext.parent, property);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (xt_css_lower(value).find("current") != std::string::npos) {
|
|
242
|
+
value = xt_style_replace_current_color(value, style->color);
|
|
243
|
+
}
|
|
244
|
+
xt_style_apply_declaration(style, property, value, nodeContext);
|
|
199
245
|
}
|
|
200
246
|
}
|
|
201
247
|
|
|
@@ -348,6 +394,7 @@ struct ComputeScratch {
|
|
|
348
394
|
* `style="transition: …"`), so the document knows whether it needs the
|
|
349
395
|
* transition snapshot path at all. */
|
|
350
396
|
bool has_transitions = false;
|
|
397
|
+
bool has_animations = false;
|
|
351
398
|
};
|
|
352
399
|
|
|
353
400
|
void pushCandidates(std::vector<Candidate> *candidates, ComputeScratch *scratch,
|
|
@@ -377,6 +424,7 @@ void computePseudo(const Node *origin, PseudoElement side, const XtStyle &origin
|
|
|
377
424
|
|
|
378
425
|
ApplyContext nodeContext = context;
|
|
379
426
|
nodeContext.parentFontSize = originStyle.font_size;
|
|
427
|
+
nodeContext.parent = &originStyle;
|
|
380
428
|
|
|
381
429
|
std::string pseudoName = side == PseudoElement::Before ? "before" : "after";
|
|
382
430
|
std::vector<Candidate> &candidates = scratch->candidates;
|
|
@@ -402,6 +450,7 @@ void computePseudo(const Node *origin, PseudoElement side, const XtStyle &origin
|
|
|
402
450
|
applyCandidates(&style, &candidates, nodeContext);
|
|
403
451
|
finalizeStyle(&style, nodeContext);
|
|
404
452
|
if (!style.transitions.empty()) scratch->has_transitions = true;
|
|
453
|
+
if (!style.animations.empty()) scratch->has_animations = true;
|
|
405
454
|
|
|
406
455
|
bool generated = false;
|
|
407
456
|
std::string text;
|
|
@@ -428,6 +477,7 @@ void computeNode(const Node *node, const XtStyle *parent, const StyleSheet &shee
|
|
|
428
477
|
|
|
429
478
|
ApplyContext nodeContext = context;
|
|
430
479
|
nodeContext.parentFontSize = (parent != nullptr) ? parent->font_size : context.rootFontSize;
|
|
480
|
+
nodeContext.parent = parent;
|
|
431
481
|
|
|
432
482
|
std::vector<Candidate> &candidates = scratch->candidates;
|
|
433
483
|
candidates.clear();
|
|
@@ -455,6 +505,7 @@ void computeNode(const Node *node, const XtStyle *parent, const StyleSheet &shee
|
|
|
455
505
|
applyCandidates(&style, &candidates, nodeContext);
|
|
456
506
|
finalizeStyle(&style, nodeContext);
|
|
457
507
|
if (!style.transitions.empty()) scratch->has_transitions = true;
|
|
508
|
+
if (!style.animations.empty()) scratch->has_animations = true;
|
|
458
509
|
|
|
459
510
|
/* `emplace` keeps the address of an existing entry stable, which is what
|
|
460
511
|
* `box->style` pointers rely on. */
|
|
@@ -479,7 +530,7 @@ void computeNode(const Node *node, const XtStyle *parent, const StyleSheet &shee
|
|
|
479
530
|
void xt_style_compute(const Node *root, const StyleSheet &sheet,
|
|
480
531
|
std::unordered_map<const Node *, XtStyle> &out, float viewportWidth,
|
|
481
532
|
float viewportHeight, const MatchState &state, PseudoNodeSet *pseudos,
|
|
482
|
-
bool *hasTransitions) {
|
|
533
|
+
bool *hasTransitions, bool *hasAnimations) {
|
|
483
534
|
out.clear();
|
|
484
535
|
bool wantsPseudo = pseudos != nullptr && sheet.has_pseudo_elements;
|
|
485
536
|
if (wantsPseudo && root != nullptr) {
|
|
@@ -512,6 +563,9 @@ void xt_style_compute(const Node *root, const StyleSheet &sheet,
|
|
|
512
563
|
if (hasTransitions != nullptr) {
|
|
513
564
|
*hasTransitions = *hasTransitions || scratch.has_transitions;
|
|
514
565
|
}
|
|
566
|
+
if (hasAnimations != nullptr) {
|
|
567
|
+
*hasAnimations = *hasAnimations || scratch.has_animations;
|
|
568
|
+
}
|
|
515
569
|
}
|
|
516
570
|
|
|
517
571
|
} // namespace xtgui
|
package/runtime/ext_gui/style.h
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#ifndef XT_GUI_STYLE_H
|
|
11
11
|
#define XT_GUI_STYLE_H
|
|
12
12
|
|
|
13
|
+
#include <map>
|
|
13
14
|
#include <memory>
|
|
14
15
|
#include <string>
|
|
15
16
|
#include <unordered_map>
|
|
@@ -36,7 +37,64 @@ enum class WhiteSpace { Normal, NoWrap, Pre, PreWrap, PreLine };
|
|
|
36
37
|
enum class Overflow { Visible, Hidden, Scroll, Auto };
|
|
37
38
|
enum class BorderStyle { None, Solid, Dashed, Dotted };
|
|
38
39
|
enum class FontStyle { Normal, Italic };
|
|
39
|
-
|
|
40
|
+
|
|
41
|
+
/** CSS `text-transform`; only plain ASCII case mapping is applied. */
|
|
42
|
+
enum class TextTransform { None, Uppercase, Lowercase, Capitalize };
|
|
43
|
+
|
|
44
|
+
/** CSS `writing-mode`. Only text-level vertical layout is implemented. */
|
|
45
|
+
enum class WritingMode { HorizontalTB, VerticalRL, VerticalLR };
|
|
46
|
+
|
|
47
|
+
/** CSS `cursor` values the engine maps to an SDL system cursor. */
|
|
48
|
+
enum class CursorShape { Auto, Default, Pointer, Text, Move, Wait, Help, NotAllowed, Crosshair };
|
|
49
|
+
|
|
50
|
+
/** Apply a computed `text-transform` to a text node's UTF-8 contents. */
|
|
51
|
+
std::string xt_apply_text_transform(const std::string &text, TextTransform transform);
|
|
52
|
+
|
|
53
|
+
/** Resolve a `border-radius` against a border box (percent uses min(w, h)). */
|
|
54
|
+
float xt_style_border_radius_px(const Length &radius, float width, float height, float em,
|
|
55
|
+
float root, float vw, float vh);
|
|
56
|
+
|
|
57
|
+
/** One `background-size` entry for an image layer. */
|
|
58
|
+
struct BackgroundSize {
|
|
59
|
+
Length width{0.0f, Unit::Auto};
|
|
60
|
+
Length height{0.0f, Unit::Auto};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** A CSS timing function. `Ease`/`Linear`/… are the keywords; `CubicBezier` and
|
|
64
|
+
* the two `Steps` kinds carry their parameters. */
|
|
65
|
+
struct TimingFunction {
|
|
66
|
+
enum class Kind {
|
|
67
|
+
Linear,
|
|
68
|
+
Ease,
|
|
69
|
+
EaseIn,
|
|
70
|
+
EaseOut,
|
|
71
|
+
EaseInOut,
|
|
72
|
+
CubicBezier,
|
|
73
|
+
StepsStart,
|
|
74
|
+
StepsEnd
|
|
75
|
+
};
|
|
76
|
+
Kind kind = Kind::Ease;
|
|
77
|
+
float x1 = 0.25f;
|
|
78
|
+
float y1 = 0.1f;
|
|
79
|
+
float x2 = 0.25f;
|
|
80
|
+
float y2 = 1.0f;
|
|
81
|
+
int steps = 1;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
enum class AnimationDirection { Normal, Reverse, Alternate, AlternateReverse };
|
|
85
|
+
enum class AnimationFillMode { None, Forwards, Backwards, Both };
|
|
86
|
+
|
|
87
|
+
/** One `animation` entry: a `@keyframes` name plus how it runs. */
|
|
88
|
+
struct AnimationSpec {
|
|
89
|
+
std::string name = "none";
|
|
90
|
+
float duration = 0.0f; // seconds
|
|
91
|
+
float delay = 0.0f; // seconds
|
|
92
|
+
float iterations = 1.0f; // `infinite` is stored as -1
|
|
93
|
+
TimingFunction timing;
|
|
94
|
+
AnimationDirection direction = AnimationDirection::Normal;
|
|
95
|
+
AnimationFillMode fill = AnimationFillMode::None;
|
|
96
|
+
bool paused = false;
|
|
97
|
+
};
|
|
40
98
|
|
|
41
99
|
/** CSS `mix-blend-mode`. The order matches the composite shader's `u_mode`
|
|
42
100
|
* enum and the keyword table in `style_values.cpp`. */
|
|
@@ -64,7 +122,7 @@ struct TransitionSpec {
|
|
|
64
122
|
std::string property = "all";
|
|
65
123
|
float duration = 0.0f; // seconds
|
|
66
124
|
float delay = 0.0f; // seconds
|
|
67
|
-
TimingFunction timing
|
|
125
|
+
TimingFunction timing;
|
|
68
126
|
};
|
|
69
127
|
|
|
70
128
|
/** One track of a `grid-template-columns` / `grid-template-rows` list.
|
|
@@ -161,6 +219,17 @@ struct TextShadow {
|
|
|
161
219
|
bool has_color = false;
|
|
162
220
|
};
|
|
163
221
|
|
|
222
|
+
/** One `box-shadow` entry (`inset` keyword, spread included). */
|
|
223
|
+
struct BoxShadow {
|
|
224
|
+
Length dx;
|
|
225
|
+
Length dy;
|
|
226
|
+
Length blur;
|
|
227
|
+
Length spread;
|
|
228
|
+
Color color; // `has_color == false` means currentColor
|
|
229
|
+
bool has_color = false;
|
|
230
|
+
bool inset = false;
|
|
231
|
+
};
|
|
232
|
+
|
|
164
233
|
struct Edges {
|
|
165
234
|
Length top;
|
|
166
235
|
Length right;
|
|
@@ -178,12 +247,20 @@ struct XtStyle {
|
|
|
178
247
|
std::unordered_map<std::string, std::string> variables;
|
|
179
248
|
Position position = Position::Static;
|
|
180
249
|
Edges margin;
|
|
250
|
+
/** Which margins were explicitly declared `auto` (the `Edges` default unit is
|
|
251
|
+
* Auto, so the raw value cannot distinguish "unset" from "auto"). */
|
|
252
|
+
bool margin_left_auto = false;
|
|
253
|
+
bool margin_right_auto = false;
|
|
254
|
+
bool margin_top_auto = false;
|
|
255
|
+
bool margin_bottom_auto = false;
|
|
181
256
|
Edges padding;
|
|
182
257
|
Edges border_width;
|
|
183
258
|
BorderStyle border_style = BorderStyle::None;
|
|
184
259
|
Color border_color;
|
|
185
260
|
bool has_border_color = false;
|
|
186
|
-
|
|
261
|
+
/** `border-radius` stays symbolic so a `50%` radius can resolve against the
|
|
262
|
+
* box in layout (the engine has one radius, so percentages use min(w, h)). */
|
|
263
|
+
Length border_radius{0.0f, Unit::Px};
|
|
187
264
|
|
|
188
265
|
Length width;
|
|
189
266
|
Length height;
|
|
@@ -203,6 +280,8 @@ struct XtStyle {
|
|
|
203
280
|
bool has_background = false;
|
|
204
281
|
/** `background-image` layers, in declaration order (first = topmost). */
|
|
205
282
|
std::vector<BackgroundLayer> background_layers;
|
|
283
|
+
/** Per-layer `background-size`; empty keeps the historical stretch. */
|
|
284
|
+
std::vector<BackgroundSize> background_sizes;
|
|
206
285
|
/** `clip-path`; `Type::None` leaves the box unclipped. */
|
|
207
286
|
ClipPathSpec clip_path;
|
|
208
287
|
/** `filter` / `backdrop-filter` function lists (not inherited). */
|
|
@@ -210,6 +289,8 @@ struct XtStyle {
|
|
|
210
289
|
std::vector<FilterOp> backdrop_filters;
|
|
211
290
|
/** `text-shadow` entries (inherited, as in CSS). */
|
|
212
291
|
std::vector<TextShadow> text_shadow;
|
|
292
|
+
/** `box-shadow` entries (not inherited); declaration order = topmost first. */
|
|
293
|
+
std::vector<BoxShadow> box_shadow;
|
|
213
294
|
/** Generated `content` of a `::before`/`::after` box. The cascade resolves
|
|
214
295
|
* `attr()` and string escapes before layout; `has_content` distinguishes
|
|
215
296
|
* `content: ""` from no generated box. */
|
|
@@ -224,6 +305,14 @@ struct XtStyle {
|
|
|
224
305
|
|
|
225
306
|
TextAlign text_align = TextAlign::Start; // inherited
|
|
226
307
|
WhiteSpace white_space = WhiteSpace::Normal; // inherited
|
|
308
|
+
TextTransform text_transform = TextTransform::None; // inherited
|
|
309
|
+
/** Resolved to pixels in the cascade (em is the element's own font size). */
|
|
310
|
+
Length letter_spacing{0.0f, Unit::Px}; // inherited
|
|
311
|
+
bool font_variant_numeric = false; // inherited; accepted, no OpenType features
|
|
312
|
+
WritingMode writing_mode = WritingMode::HorizontalTB; // inherited
|
|
313
|
+
Length vertical_align; // not inherited; atomic inline boxes only
|
|
314
|
+
/** `aspect-ratio` as width / height, or 0 when unset. */
|
|
315
|
+
float aspect_ratio = 0.0f;
|
|
227
316
|
|
|
228
317
|
FlexDirection flex_direction = FlexDirection::Row;
|
|
229
318
|
FlexWrap flex_wrap = FlexWrap::NoWrap;
|
|
@@ -251,6 +340,21 @@ struct XtStyle {
|
|
|
251
340
|
Length flex_basis;
|
|
252
341
|
|
|
253
342
|
float opacity = 1.0f;
|
|
343
|
+
/** `display: inline-flex` / `inline-grid`: a flex/grid container that is
|
|
344
|
+
* still inline-level (laid out atomically by its line box). */
|
|
345
|
+
bool inline_level = false;
|
|
346
|
+
/** `isolation`: parsed for compatibility; group isolation is not modelled. */
|
|
347
|
+
bool isolation = false;
|
|
348
|
+
CursorShape cursor = CursorShape::Auto;
|
|
349
|
+
/** `outline` (painted outside the border box). */
|
|
350
|
+
Length outline_width;
|
|
351
|
+
BorderStyle outline_style = BorderStyle::None;
|
|
352
|
+
Color outline_color;
|
|
353
|
+
bool has_outline_color = false;
|
|
354
|
+
Length outline_offset;
|
|
355
|
+
/** Computed SVG presentation properties (`fill`, `stroke`, …) injected into
|
|
356
|
+
* serialized inline `<svg>` markup. Only populated on SVG elements. */
|
|
357
|
+
std::map<std::string, std::string> svg_props;
|
|
254
358
|
/** `mix-blend-mode` (not inherited: it creates a compositing group). */
|
|
255
359
|
MixBlendMode mix_blend_mode = MixBlendMode::Normal;
|
|
256
360
|
Overflow overflow = Overflow::Visible;
|
|
@@ -268,6 +372,8 @@ struct XtStyle {
|
|
|
268
372
|
|
|
269
373
|
/** `transition` specs; not inherited. Applied by `XtDocument`. */
|
|
270
374
|
std::vector<TransitionSpec> transitions;
|
|
375
|
+
/** `animation` specs; not inherited. Applied by `XtDocument`. */
|
|
376
|
+
std::vector<AnimationSpec> animations;
|
|
271
377
|
};
|
|
272
378
|
|
|
273
379
|
/** Initial (non-inherited) style; inherited fields are overridden from the parent. */
|
|
@@ -297,7 +403,8 @@ class PseudoNodeSet {
|
|
|
297
403
|
void xt_style_compute(const Node *root, const StyleSheet &sheet,
|
|
298
404
|
std::unordered_map<const Node *, XtStyle> &out, float viewportWidth,
|
|
299
405
|
float viewportHeight, const MatchState &state = MatchState(),
|
|
300
|
-
PseudoNodeSet *pseudos = nullptr, bool *hasTransitions = nullptr
|
|
406
|
+
PseudoNodeSet *pseudos = nullptr, bool *hasTransitions = nullptr,
|
|
407
|
+
bool *hasAnimations = nullptr);
|
|
301
408
|
|
|
302
409
|
/** Format a computed property for diagnostics/tests (`computedStyle(sel, prop)`). */
|
|
303
410
|
std::string xt_style_property_to_string(const XtStyle &style, const std::string &property);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — cascade value helpers.
|
|
3
|
+
*
|
|
4
|
+
* CSS-wide `inherit` for the shorthands that appear in real stylesheets, and
|
|
5
|
+
* `currentColor` substitution. They live apart from `style.cpp` so the cascade
|
|
6
|
+
* core stays under the repository's per-file line budget.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "style_internal.h"
|
|
10
|
+
|
|
11
|
+
#include <cctype>
|
|
12
|
+
#include <cstdio>
|
|
13
|
+
#include <string>
|
|
14
|
+
|
|
15
|
+
namespace xtgui {
|
|
16
|
+
|
|
17
|
+
void xt_style_apply_inherit(XtStyle *style, const XtStyle *parent, const std::string &property) {
|
|
18
|
+
if (parent == nullptr) return;
|
|
19
|
+
if (property == "color") {
|
|
20
|
+
style->color = parent->color;
|
|
21
|
+
} else if (property == "clip-path") {
|
|
22
|
+
style->clip_path = parent->clip_path;
|
|
23
|
+
} else if (property == "font") {
|
|
24
|
+
style->font_size = parent->font_size;
|
|
25
|
+
style->font_weight = parent->font_weight;
|
|
26
|
+
style->font_family = parent->font_family;
|
|
27
|
+
style->font_style = parent->font_style;
|
|
28
|
+
style->line_height = parent->line_height;
|
|
29
|
+
style->letter_spacing = parent->letter_spacing;
|
|
30
|
+
style->font_variant_numeric = parent->font_variant_numeric;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
std::string xt_style_replace_current_color(const std::string &value, const Color &color) {
|
|
35
|
+
std::string out;
|
|
36
|
+
char quote = 0;
|
|
37
|
+
auto matches = [&value](size_t at) {
|
|
38
|
+
if (at + 12 > value.size()) return false;
|
|
39
|
+
for (size_t i = 0; i < 12; i++) {
|
|
40
|
+
char c = value[at + i];
|
|
41
|
+
if (c >= 'A' && c <= 'Z') c = (char)(c - 'A' + 'a');
|
|
42
|
+
if (c != "currentcolor"[i]) return false;
|
|
43
|
+
}
|
|
44
|
+
if (at > 0) {
|
|
45
|
+
char before = value[at - 1];
|
|
46
|
+
if (std::isalnum((unsigned char)before) || before == '-' || before == '_') return false;
|
|
47
|
+
}
|
|
48
|
+
if (at + 12 < value.size()) {
|
|
49
|
+
char after = value[at + 12];
|
|
50
|
+
if (std::isalnum((unsigned char)after) || after == '-' || after == '_') return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
};
|
|
54
|
+
for (size_t i = 0; i < value.size();) {
|
|
55
|
+
char c = value[i];
|
|
56
|
+
if (quote != 0) {
|
|
57
|
+
out.push_back(c);
|
|
58
|
+
if (c == quote) quote = 0;
|
|
59
|
+
i++;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (c == '"' || c == '\'') {
|
|
63
|
+
quote = c;
|
|
64
|
+
out.push_back(c);
|
|
65
|
+
i++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (matches(i)) {
|
|
69
|
+
char buffer[96];
|
|
70
|
+
std::snprintf(buffer, sizeof(buffer), "rgba(%ld, %ld, %ld, %.3f)",
|
|
71
|
+
(long)(color.r * 255.0f + 0.5f), (long)(color.g * 255.0f + 0.5f),
|
|
72
|
+
(long)(color.b * 255.0f + 0.5f), (double)color.a);
|
|
73
|
+
out += buffer;
|
|
74
|
+
i += 12;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
out.push_back(c);
|
|
78
|
+
i++;
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
} // namespace xtgui
|
|
@@ -15,16 +15,28 @@ struct ApplyContext {
|
|
|
15
15
|
float parentFontSize = 16.0f;
|
|
16
16
|
float viewportWidth = 0.0f;
|
|
17
17
|
float viewportHeight = 0.0f;
|
|
18
|
+
/** Parent computed style; needed by `inherit` and the `font` shorthand. */
|
|
19
|
+
const XtStyle *parent = nullptr;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
/** Resolve a length to pixels given the current font/viewport context. */
|
|
21
23
|
float xt_style_resolve_absolute(const Length &length, float base, float em, float root, float vw,
|
|
22
24
|
float vh);
|
|
23
25
|
|
|
26
|
+
/** CSS-wide `inherit` for the shorthands the engine handles. */
|
|
27
|
+
void xt_style_apply_inherit(XtStyle *style, const XtStyle *parent, const std::string &property);
|
|
28
|
+
|
|
29
|
+
/** Replace `currentcolor` outside quoted strings with `color`'s rgba spelling. */
|
|
30
|
+
std::string xt_style_replace_current_color(const std::string &value, const Color &color);
|
|
31
|
+
|
|
24
32
|
/** Apply the built-in user-agent rules for one element. */
|
|
25
33
|
void xt_style_apply_user_agent(const Node *node, XtStyle *style);
|
|
26
34
|
|
|
27
|
-
/**
|
|
35
|
+
/** Resolve a `border-radius` against a border box (percent uses min(w, h)). */
|
|
36
|
+
float xt_style_border_radius_px(const Length &radius, float width, float height, float em,
|
|
37
|
+
float root, float vw, float vh);
|
|
38
|
+
|
|
39
|
+
/** Apply a parsed declaration to a computed style. */
|
|
28
40
|
void xt_style_apply_declaration(XtStyle *style, const std::string &property,
|
|
29
41
|
const std::string &rawValue, const ApplyContext &context);
|
|
30
42
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — resolution of computed CSS lengths.
|
|
3
|
+
*
|
|
4
|
+
* `Length` keeps a symbolic expression (`calc()`, `min()`/`max()`/`clamp()`,
|
|
5
|
+
* percentages and relative units) until layout knows the containing block, the
|
|
6
|
+
* element's font size and the viewport. This unit is that one entry point; it
|
|
7
|
+
* lives apart from declaration parsing to keep `style_values.cpp` focused.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "style_internal.h"
|
|
11
|
+
|
|
12
|
+
namespace xtgui {
|
|
13
|
+
|
|
14
|
+
float xt_style_resolve_absolute(const Length &length, float base, float em, float root, float vw,
|
|
15
|
+
float vh) {
|
|
16
|
+
switch (length.unit) {
|
|
17
|
+
case Unit::Clamp: {
|
|
18
|
+
if (length.args.size() < 3) return 0.0f;
|
|
19
|
+
float low = xt_style_resolve_absolute(length.args[0], base, em, root, vw, vh);
|
|
20
|
+
float value = xt_style_resolve_absolute(length.args[1], base, em, root, vw, vh);
|
|
21
|
+
float high = xt_style_resolve_absolute(length.args[2], base, em, root, vw, vh);
|
|
22
|
+
return value < low ? low : (value > high ? high : value);
|
|
23
|
+
}
|
|
24
|
+
case Unit::Min: {
|
|
25
|
+
float best = 0.0f;
|
|
26
|
+
bool first = true;
|
|
27
|
+
for (const Length &arg : length.args) {
|
|
28
|
+
float value = xt_style_resolve_absolute(arg, base, em, root, vw, vh);
|
|
29
|
+
if (first || value < best) best = value;
|
|
30
|
+
first = false;
|
|
31
|
+
}
|
|
32
|
+
return best;
|
|
33
|
+
}
|
|
34
|
+
case Unit::Max: {
|
|
35
|
+
float best = 0.0f;
|
|
36
|
+
bool first = true;
|
|
37
|
+
for (const Length &arg : length.args) {
|
|
38
|
+
float value = xt_style_resolve_absolute(arg, base, em, root, vw, vh);
|
|
39
|
+
if (first || value > best) best = value;
|
|
40
|
+
first = false;
|
|
41
|
+
}
|
|
42
|
+
return best;
|
|
43
|
+
}
|
|
44
|
+
case Unit::Calc: {
|
|
45
|
+
if (length.args.size() < 2) return 0.0f;
|
|
46
|
+
float left = xt_style_resolve_absolute(length.args[0], base, em, root, vw, vh);
|
|
47
|
+
float right = xt_style_resolve_absolute(length.args[1], base, em, root, vw, vh);
|
|
48
|
+
switch (length.op) {
|
|
49
|
+
case '+':
|
|
50
|
+
return left + right;
|
|
51
|
+
case '-':
|
|
52
|
+
return left - right;
|
|
53
|
+
case '*':
|
|
54
|
+
return left * right;
|
|
55
|
+
case '/':
|
|
56
|
+
/* Division by zero makes the whole `calc()` invalid in CSS; the
|
|
57
|
+
* declaration is dropped, which here means "no value contributed". */
|
|
58
|
+
return right == 0.0f ? 0.0f : left / right;
|
|
59
|
+
default:
|
|
60
|
+
return left;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
case Unit::Px:
|
|
64
|
+
case Unit::Number:
|
|
65
|
+
return length.value;
|
|
66
|
+
case Unit::Percent:
|
|
67
|
+
return base * length.value / 100.0f;
|
|
68
|
+
case Unit::Em:
|
|
69
|
+
return em * length.value;
|
|
70
|
+
case Unit::Rem:
|
|
71
|
+
return root * length.value;
|
|
72
|
+
case Unit::Vw:
|
|
73
|
+
return vw * length.value / 100.0f;
|
|
74
|
+
case Unit::Vh:
|
|
75
|
+
return vh * length.value / 100.0f;
|
|
76
|
+
default:
|
|
77
|
+
return 0.0f;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
float xt_style_border_radius_px(const Length &radius, float width, float height, float em,
|
|
82
|
+
float root, float vw, float vh) {
|
|
83
|
+
float base = width < height ? width : height;
|
|
84
|
+
if (base < 0.0f) base = 0.0f;
|
|
85
|
+
float value = xt_style_resolve_absolute(radius, base, em, root, vw, vh);
|
|
86
|
+
if (value < 0.0f) value = 0.0f;
|
|
87
|
+
float half = (width < height ? width : height) / 2.0f;
|
|
88
|
+
if (half < 0.0f) half = 0.0f;
|
|
89
|
+
return value > half ? half : value;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
} // namespace xtgui
|
|
@@ -18,6 +18,21 @@ static std::string formatNumber(float number) {
|
|
|
18
18
|
return buffer;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
static std::string formatCalcBody(const Length &length);
|
|
22
|
+
static std::string formatLength(const Length &length);
|
|
23
|
+
|
|
24
|
+
/** A nested `calc()` operand is parenthesised instead of spelling `calc(calc(…))`,
|
|
25
|
+
* except where operator precedence already groups it the same way. */
|
|
26
|
+
static std::string formatCalcOperand(const Length &length, char parent_op) {
|
|
27
|
+
if (length.unit == Unit::Calc) {
|
|
28
|
+
int parent_precedence = (parent_op == '*' || parent_op == '/') ? 2 : 1;
|
|
29
|
+
int own_precedence = (length.op == '*' || length.op == '/') ? 2 : 1;
|
|
30
|
+
if (own_precedence > parent_precedence) return formatCalcBody(length);
|
|
31
|
+
return "(" + formatCalcBody(length) + ")";
|
|
32
|
+
}
|
|
33
|
+
return formatLength(length);
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
static std::string formatLength(const Length &length) {
|
|
22
37
|
switch (length.unit) {
|
|
23
38
|
case Unit::Auto:
|
|
@@ -50,11 +65,24 @@ static std::string formatLength(const Length &length) {
|
|
|
50
65
|
text += ")";
|
|
51
66
|
return text;
|
|
52
67
|
}
|
|
68
|
+
case Unit::Calc:
|
|
69
|
+
return "calc(" + formatCalcBody(length) + ")";
|
|
53
70
|
default:
|
|
54
71
|
return "";
|
|
55
72
|
}
|
|
56
73
|
}
|
|
57
74
|
|
|
75
|
+
static std::string formatCalcBody(const Length &length) {
|
|
76
|
+
if (length.args.size() < 2) return "";
|
|
77
|
+
char op = length.op != 0 ? length.op : '?';
|
|
78
|
+
std::string text = formatCalcOperand(length.args[0], op);
|
|
79
|
+
text += " ";
|
|
80
|
+
text.push_back(op);
|
|
81
|
+
text += " ";
|
|
82
|
+
text += formatCalcOperand(length.args[1], op);
|
|
83
|
+
return text;
|
|
84
|
+
}
|
|
85
|
+
|
|
58
86
|
static std::string formatColor(const Color &color) {
|
|
59
87
|
if (color.a >= 1.0f) {
|
|
60
88
|
char buffer[64];
|
|
@@ -123,6 +151,22 @@ static std::string formatFilterList(const std::vector<FilterOp> &filters) {
|
|
|
123
151
|
return out;
|
|
124
152
|
}
|
|
125
153
|
|
|
154
|
+
static std::string formatBoxShadows(const std::vector<BoxShadow> &shadows) {
|
|
155
|
+
if (shadows.empty()) return "none";
|
|
156
|
+
std::string out;
|
|
157
|
+
for (const BoxShadow &shadow : shadows) {
|
|
158
|
+
if (!out.empty()) out += ", ";
|
|
159
|
+
if (shadow.inset) out += "inset ";
|
|
160
|
+
out += formatLength(shadow.dx) + " " + formatLength(shadow.dy);
|
|
161
|
+
bool zeroBlur = shadow.blur.unit == Unit::Px && shadow.blur.value == 0.0f;
|
|
162
|
+
bool zeroSpread = shadow.spread.unit == Unit::Px && shadow.spread.value == 0.0f;
|
|
163
|
+
if (!zeroBlur || !zeroSpread) out += " " + formatLength(shadow.blur);
|
|
164
|
+
if (!zeroSpread) out += " " + formatLength(shadow.spread);
|
|
165
|
+
if (shadow.has_color) out += " " + formatColor(shadow.color);
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
126
170
|
static std::string formatTextShadows(const std::vector<TextShadow> &shadows) {
|
|
127
171
|
if (shadows.empty()) return "none";
|
|
128
172
|
std::string out;
|
|
@@ -189,8 +233,16 @@ std::string xt_style_property_to_string(const XtStyle &style, const std::string
|
|
|
189
233
|
static const char *const floatNames[] = {"none", "left", "right"};
|
|
190
234
|
static const char *const clearNames[] = {"none", "left", "right", "both"};
|
|
191
235
|
static const char *const alignTextNames[] = {"start", "center", "end", "justify"};
|
|
236
|
+
static const char *const textTransformNames[] = {"none", "uppercase", "lowercase", "capitalize"};
|
|
237
|
+
static const char *const writingModeNames[] = {"horizontal-tb", "vertical-rl", "vertical-lr"};
|
|
238
|
+
static const char *const cursorNames[] = {"auto", "default", "pointer", "text", "move",
|
|
239
|
+
"wait", "help", "not-allowed", "crosshair"};
|
|
240
|
+
static const char *const borderStyleNames[] = {"none", "solid", "dashed", "dotted"};
|
|
192
241
|
|
|
193
|
-
if (property == "display")
|
|
242
|
+
if (property == "display") {
|
|
243
|
+
if (style.inline_level) return style.display == Display::Grid ? "inline-grid" : "inline-flex";
|
|
244
|
+
return displayNames[(int)style.display];
|
|
245
|
+
}
|
|
194
246
|
if (property == "position") return positionNames[(int)style.position];
|
|
195
247
|
if (property == "color") return formatColor(style.color);
|
|
196
248
|
if (property == "background-color" || property == "background") {
|
|
@@ -221,6 +273,34 @@ std::string xt_style_property_to_string(const XtStyle &style, const std::string
|
|
|
221
273
|
return style.line_height.unit == Unit::Auto ? "normal" : formatLength(style.line_height);
|
|
222
274
|
}
|
|
223
275
|
if (property == "text-align") return alignTextNames[(int)style.text_align];
|
|
276
|
+
if (property == "text-transform") return textTransformNames[(int)style.text_transform];
|
|
277
|
+
if (property == "letter-spacing") return formatLength(style.letter_spacing);
|
|
278
|
+
if (property == "writing-mode") return writingModeNames[(int)style.writing_mode];
|
|
279
|
+
if (property == "vertical-align") return formatLength(style.vertical_align);
|
|
280
|
+
if (property == "font-variant-numeric") return style.font_variant_numeric ? "tabular-nums" : "normal";
|
|
281
|
+
if (property == "cursor") return cursorNames[(int)style.cursor];
|
|
282
|
+
if (property == "aspect-ratio") return style.aspect_ratio > 0 ? formatNumber(style.aspect_ratio) : "auto";
|
|
283
|
+
if (property == "grid-area") {
|
|
284
|
+
return formatNumber((float)style.grid_row_start) + " / " +
|
|
285
|
+
formatNumber((float)style.grid_column_start) + " / " +
|
|
286
|
+
formatNumber((float)style.grid_row_end) + " / " +
|
|
287
|
+
formatNumber((float)style.grid_column_end);
|
|
288
|
+
}
|
|
289
|
+
if (property == "outline-width") return formatLength(style.outline_width);
|
|
290
|
+
if (property == "outline-style") return borderStyleNames[(int)style.outline_style];
|
|
291
|
+
if (property == "outline-color") {
|
|
292
|
+
return style.has_outline_color ? formatColor(style.outline_color) : "currentcolor";
|
|
293
|
+
}
|
|
294
|
+
if (property == "outline-offset") return formatLength(style.outline_offset);
|
|
295
|
+
if (property == "background-size") {
|
|
296
|
+
if (style.background_sizes.empty()) return "auto";
|
|
297
|
+
std::string out;
|
|
298
|
+
for (const BackgroundSize &size : style.background_sizes) {
|
|
299
|
+
if (!out.empty()) out += ", ";
|
|
300
|
+
out += formatLength(size.width) + " " + formatLength(size.height);
|
|
301
|
+
}
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
224
304
|
if (property == "flex-direction") return flexNames[(int)style.flex_direction];
|
|
225
305
|
if (property == "flex-wrap") return wrapNames[(int)style.flex_wrap];
|
|
226
306
|
if (property == "justify-content") return justifyNames[(int)style.justify_content];
|
|
@@ -234,7 +314,7 @@ std::string xt_style_property_to_string(const XtStyle &style, const std::string
|
|
|
234
314
|
if (property == "flex-grow") return formatNumber(style.flex_grow);
|
|
235
315
|
if (property == "flex-shrink") return formatNumber(style.flex_shrink);
|
|
236
316
|
if (property == "flex-basis") return formatLength(style.flex_basis);
|
|
237
|
-
if (property == "border-radius") return
|
|
317
|
+
if (property == "border-radius") return formatLength(style.border_radius);
|
|
238
318
|
if (property == "opacity") return formatNumber(style.opacity);
|
|
239
319
|
if (property == "mix-blend-mode") {
|
|
240
320
|
static const char *const names[] = {
|
|
@@ -250,6 +330,7 @@ std::string xt_style_property_to_string(const XtStyle &style, const std::string
|
|
|
250
330
|
if (property == "filter") return formatFilterList(style.filters);
|
|
251
331
|
if (property == "backdrop-filter") return formatFilterList(style.backdrop_filters);
|
|
252
332
|
if (property == "text-shadow") return formatTextShadows(style.text_shadow);
|
|
333
|
+
if (property == "box-shadow") return formatBoxShadows(style.box_shadow);
|
|
253
334
|
if (property == "background-image") {
|
|
254
335
|
if (style.background_layers.empty()) return "none";
|
|
255
336
|
std::string out;
|