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
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — SVG presentation properties in the document cascade.
|
|
3
|
+
*
|
|
4
|
+
* Inline `<svg>` is serialized and rasterised by NanoSVG, which only sees the
|
|
5
|
+
* markup, not the document's computed styles. The cascade therefore records the
|
|
6
|
+
* SVG presentation properties here and `inline_svg.cpp` writes them back as an
|
|
7
|
+
* inline `style="…"` attribute (so NanoSVG's class/style reader applies them).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "style_internal.h"
|
|
11
|
+
#include "style_values_internal.h"
|
|
12
|
+
|
|
13
|
+
#include <string>
|
|
14
|
+
|
|
15
|
+
namespace xtgui {
|
|
16
|
+
|
|
17
|
+
namespace {
|
|
18
|
+
|
|
19
|
+
bool isSvgPresentationProperty(const std::string &property) {
|
|
20
|
+
static const char *const names[] = {
|
|
21
|
+
"fill", "fill-opacity", "fill-rule", "stroke",
|
|
22
|
+
"stroke-opacity", "stroke-width", "stroke-dasharray", "stroke-dashoffset",
|
|
23
|
+
"stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stop-color",
|
|
24
|
+
"stop-opacity", "paint-order"};
|
|
25
|
+
for (const char *name : names) {
|
|
26
|
+
if (property == name) return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
} // namespace
|
|
32
|
+
|
|
33
|
+
bool xt_style_apply_svg_property(XtStyle *style, const std::string &property,
|
|
34
|
+
const std::string &value) {
|
|
35
|
+
if (!isSvgPresentationProperty(property)) return false;
|
|
36
|
+
style->svg_props[property] = xt_css_trim(value);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — text-oriented CSS declarations.
|
|
3
|
+
*
|
|
4
|
+
* `letter-spacing`, `text-transform`, `writing-mode`, `vertical-align`, the
|
|
5
|
+
* `font` shorthand and the font-feature hints live here so the main declaration
|
|
6
|
+
* dispatcher stays under the repository's per-file line budget.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "style_internal.h"
|
|
10
|
+
#include "style_values_internal.h"
|
|
11
|
+
|
|
12
|
+
#include <cctype>
|
|
13
|
+
#include <cstring>
|
|
14
|
+
#include <string>
|
|
15
|
+
#include <vector>
|
|
16
|
+
|
|
17
|
+
namespace xtgui {
|
|
18
|
+
|
|
19
|
+
namespace {
|
|
20
|
+
|
|
21
|
+
std::string lowerTrim(const std::string &text) { return xt_css_lower(xt_css_trim(text)); }
|
|
22
|
+
|
|
23
|
+
bool isSpace(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f'; }
|
|
24
|
+
|
|
25
|
+
/** Split at whitespace outside `(...)` so `calc(1em + 2px)` stays one token. */
|
|
26
|
+
std::vector<std::string> splitTokens(const std::string &text) {
|
|
27
|
+
std::vector<std::string> parts;
|
|
28
|
+
std::string current;
|
|
29
|
+
int depth = 0;
|
|
30
|
+
for (char c : text) {
|
|
31
|
+
if (c == '(') depth++;
|
|
32
|
+
if (c == ')') depth--;
|
|
33
|
+
if (isSpace(c) && depth == 0) {
|
|
34
|
+
if (!current.empty()) {
|
|
35
|
+
parts.push_back(current);
|
|
36
|
+
current.clear();
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
current.push_back(c);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!current.empty()) parts.push_back(current);
|
|
43
|
+
return parts;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** `normal` is zero; lengths are kept symbolic for `finalizeStyle` (em is the
|
|
47
|
+
* element's own font size, not the parent's). */
|
|
48
|
+
bool parseLetterSpacing(const std::string &value, Length *out) {
|
|
49
|
+
std::string text = lowerTrim(value);
|
|
50
|
+
if (text == "normal") {
|
|
51
|
+
*out = Length{0.0f, Unit::Px};
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
Length length = xt_css_parse_length(text);
|
|
55
|
+
if (length.unit == Unit::Invalid || length.unit == Unit::Auto || length.unit == Unit::None ||
|
|
56
|
+
length.unit == Unit::Percent) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
*out = length;
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
bool parseTextTransform(const std::string &value, TextTransform *out) {
|
|
64
|
+
std::string text = lowerTrim(value);
|
|
65
|
+
if (text == "none") *out = TextTransform::None;
|
|
66
|
+
else if (text == "uppercase") *out = TextTransform::Uppercase;
|
|
67
|
+
else if (text == "lowercase") *out = TextTransform::Lowercase;
|
|
68
|
+
else if (text == "capitalize") *out = TextTransform::Capitalize;
|
|
69
|
+
else return false;
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
bool parseWritingMode(const std::string &value, WritingMode *out) {
|
|
74
|
+
std::string text = lowerTrim(value);
|
|
75
|
+
if (text == "horizontal-tb") *out = WritingMode::HorizontalTB;
|
|
76
|
+
else if (text == "vertical-rl") *out = WritingMode::VerticalRL;
|
|
77
|
+
else if (text == "vertical-lr") *out = WritingMode::VerticalLR;
|
|
78
|
+
else return false;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Only the length form is acted on; the keywords are accepted so a declaration
|
|
83
|
+
* is not dropped (the used files only carry a length). */
|
|
84
|
+
bool parseVerticalAlign(const std::string &value, Length *out) {
|
|
85
|
+
std::string text = lowerTrim(value);
|
|
86
|
+
if (text == "baseline" || text == "top" || text == "middle" || text == "bottom" ||
|
|
87
|
+
text == "text-top" || text == "text-bottom") {
|
|
88
|
+
*out = Length{0.0f, Unit::Px};
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (text == "sub") {
|
|
92
|
+
*out = Length{-0.2f, Unit::Em};
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
if (text == "super") {
|
|
96
|
+
*out = Length{0.4f, Unit::Em};
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
Length length = xt_css_parse_length(text);
|
|
100
|
+
if (length.unit == Unit::Invalid || length.unit == Unit::Auto || length.unit == Unit::None) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
*out = length;
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
bool parseFontVariantNumeric(const std::string &value, bool *out) {
|
|
108
|
+
std::vector<std::string> tokens = splitTokens(lowerTrim(value));
|
|
109
|
+
if (tokens.empty()) return false;
|
|
110
|
+
bool tabular = false;
|
|
111
|
+
for (const std::string &token : tokens) {
|
|
112
|
+
if (token == "tabular-nums" || token == "lining-nums" || token == "oldstyle-nums") tabular = true;
|
|
113
|
+
}
|
|
114
|
+
*out = tabular;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
bool isFontStyleKeyword(const std::string &token) {
|
|
119
|
+
return token == "italic" || token == "oblique";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
bool isFontWeightKeyword(const std::string &token) {
|
|
123
|
+
return token == "bold" || token == "bolder" || token == "lighter" || token == "normal";
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} // namespace
|
|
127
|
+
|
|
128
|
+
std::string xt_apply_text_transform(const std::string &text, TextTransform transform) {
|
|
129
|
+
if (transform == TextTransform::None) return text;
|
|
130
|
+
std::string out = text;
|
|
131
|
+
if (transform == TextTransform::Uppercase || transform == TextTransform::Lowercase) {
|
|
132
|
+
for (char &c : out) {
|
|
133
|
+
unsigned char byte = (unsigned char)c;
|
|
134
|
+
if (byte >= 0x80) continue; // Non-ASCII bytes are left alone.
|
|
135
|
+
c = transform == TextTransform::Uppercase ? (char)std::toupper(byte)
|
|
136
|
+
: (char)std::tolower(byte);
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
/* capitalize: the first ASCII letter of every whitespace-separated word. */
|
|
141
|
+
bool wordStart = true;
|
|
142
|
+
for (char &c : out) {
|
|
143
|
+
unsigned char byte = (unsigned char)c;
|
|
144
|
+
if (byte >= 0x80) {
|
|
145
|
+
wordStart = false;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (std::isspace(byte)) {
|
|
149
|
+
wordStart = true;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (wordStart) c = (char)std::toupper(byte);
|
|
153
|
+
wordStart = false;
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
bool xt_style_apply_text_property(XtStyle *style, const std::string &property,
|
|
159
|
+
const std::string &rawValue, const ApplyContext &context) {
|
|
160
|
+
std::string value = xt_css_trim(rawValue);
|
|
161
|
+
|
|
162
|
+
if (property == "letter-spacing") {
|
|
163
|
+
parseLetterSpacing(value, &style->letter_spacing);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
if (property == "text-transform") {
|
|
167
|
+
parseTextTransform(value, &style->text_transform);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
if (property == "writing-mode") {
|
|
171
|
+
parseWritingMode(value, &style->writing_mode);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
if (property == "vertical-align") {
|
|
175
|
+
parseVerticalAlign(value, &style->vertical_align);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
if (property == "aspect-ratio") {
|
|
179
|
+
std::string text = lowerTrim(value);
|
|
180
|
+
if (text == "auto") {
|
|
181
|
+
style->aspect_ratio = 0.0f;
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
float width = 0;
|
|
185
|
+
float height = 1;
|
|
186
|
+
size_t slash = text.find('/');
|
|
187
|
+
if (slash == std::string::npos) {
|
|
188
|
+
if (!xt_css_parse_number(text, &width) || width <= 0) return true;
|
|
189
|
+
} else if (!xt_css_parse_number(xt_css_trim(text.substr(0, slash)), &width) ||
|
|
190
|
+
!xt_css_parse_number(xt_css_trim(text.substr(slash + 1)), &height) || width <= 0 ||
|
|
191
|
+
height <= 0) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
style->aspect_ratio = width / height;
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
if (property == "font-variant-numeric") {
|
|
198
|
+
parseFontVariantNumeric(value, &style->font_variant_numeric);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
if (property == "text-wrap" || property == "text-rendering") {
|
|
202
|
+
/* Accepted for author compatibility: line breaking is greedy and the text
|
|
203
|
+
* backend has no rendering-quality switch of its own. */
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
if (property != "font") return false;
|
|
207
|
+
|
|
208
|
+
std::string lower = lowerTrim(value);
|
|
209
|
+
if (lower == "inherit") {
|
|
210
|
+
if (const XtStyle *parent = context.parent) {
|
|
211
|
+
style->font_size = parent->font_size;
|
|
212
|
+
style->font_weight = parent->font_weight;
|
|
213
|
+
style->font_family = parent->font_family;
|
|
214
|
+
style->font_style = parent->font_style;
|
|
215
|
+
style->line_height = parent->line_height;
|
|
216
|
+
style->letter_spacing = parent->letter_spacing;
|
|
217
|
+
style->font_variant_numeric = parent->font_variant_numeric;
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
std::vector<std::string> tokens = splitTokens(value);
|
|
223
|
+
if (tokens.empty()) return true;
|
|
224
|
+
|
|
225
|
+
bool italic = false;
|
|
226
|
+
int weight = 400;
|
|
227
|
+
size_t index = 0;
|
|
228
|
+
for (; index < tokens.size(); index++) {
|
|
229
|
+
std::string token = xt_css_lower(tokens[index]);
|
|
230
|
+
if (isFontStyleKeyword(token)) {
|
|
231
|
+
italic = true;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (isFontWeightKeyword(token)) {
|
|
235
|
+
if (token == "bold" || token == "bolder") weight = 700;
|
|
236
|
+
else if (token == "lighter") weight = 100;
|
|
237
|
+
else weight = 400;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
float number = 0;
|
|
241
|
+
if (xt_css_parse_number(token, &number)) {
|
|
242
|
+
weight = (int)number;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
if (index >= tokens.size()) return true;
|
|
248
|
+
|
|
249
|
+
/* `size[/line-height]`; a separate `/` token is tolerated. */
|
|
250
|
+
std::string sizeToken = tokens[index];
|
|
251
|
+
std::string lineToken;
|
|
252
|
+
size_t slash = sizeToken.find('/');
|
|
253
|
+
if (slash != std::string::npos) {
|
|
254
|
+
lineToken = sizeToken.substr(slash + 1);
|
|
255
|
+
sizeToken = sizeToken.substr(0, slash);
|
|
256
|
+
}
|
|
257
|
+
Length size = xt_css_parse_length(sizeToken);
|
|
258
|
+
if (size.unit == Unit::Invalid || size.unit == Unit::Auto || size.unit == Unit::None) return true;
|
|
259
|
+
index++;
|
|
260
|
+
if (lineToken.empty() && index < tokens.size() && tokens[index] == "/") {
|
|
261
|
+
index++;
|
|
262
|
+
if (index < tokens.size()) lineToken = tokens[index++];
|
|
263
|
+
}
|
|
264
|
+
if (index >= tokens.size()) return true;
|
|
265
|
+
|
|
266
|
+
std::string family;
|
|
267
|
+
for (size_t i = index; i < tokens.size(); i++) {
|
|
268
|
+
if (!family.empty()) family += " ";
|
|
269
|
+
family += tokens[i];
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
style->font_style = italic ? FontStyle::Italic : FontStyle::Normal;
|
|
273
|
+
style->font_weight = weight;
|
|
274
|
+
style->font_size = xt_style_resolve_absolute(size, context.parentFontSize,
|
|
275
|
+
context.parentFontSize, context.rootFontSize,
|
|
276
|
+
context.viewportWidth, context.viewportHeight);
|
|
277
|
+
if (style->font_size <= 0.0f) style->font_size = 16.0f;
|
|
278
|
+
if (!lineToken.empty()) {
|
|
279
|
+
std::string text = xt_css_lower(lineToken);
|
|
280
|
+
float number = 0;
|
|
281
|
+
bool hasUnit = false;
|
|
282
|
+
for (const char *suffix : {"px", "%", "em", "rem", "vw", "vh", "pt", "pc", "in", "cm", "mm", "q"}) {
|
|
283
|
+
size_t length = std::strlen(suffix);
|
|
284
|
+
if (text.size() >= length && text.compare(text.size() - length, length, suffix) == 0) {
|
|
285
|
+
hasUnit = true;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (!hasUnit && xt_css_parse_number(text, &number)) {
|
|
290
|
+
style->line_height = {number, Unit::Number};
|
|
291
|
+
} else {
|
|
292
|
+
Length line = xt_css_parse_length(text);
|
|
293
|
+
if (line.unit != Unit::Invalid) style->line_height = line;
|
|
294
|
+
}
|
|
295
|
+
} else {
|
|
296
|
+
style->line_height = Length{};
|
|
297
|
+
}
|
|
298
|
+
style->font_family = family;
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — UI/interaction declarations.
|
|
3
|
+
*
|
|
4
|
+
* `outline` is a real painted property (the focus ring). The rest of this unit
|
|
5
|
+
* accepts the platform hints a browser stylesheet carries (`cursor`,
|
|
6
|
+
* `touch-action`, `user-select`, scrolling hints) so an authored declaration is
|
|
7
|
+
* not silently dropped; only `cursor` maps to an actual SDL cursor, because the
|
|
8
|
+
* engine has no touch gestures, text selection or smooth scrolling yet.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#include "style_internal.h"
|
|
12
|
+
#include "style_values_internal.h"
|
|
13
|
+
|
|
14
|
+
#include <string>
|
|
15
|
+
#include <vector>
|
|
16
|
+
|
|
17
|
+
namespace xtgui {
|
|
18
|
+
|
|
19
|
+
namespace {
|
|
20
|
+
|
|
21
|
+
std::string lowerTrim(const std::string &text) { return xt_css_lower(xt_css_trim(text)); }
|
|
22
|
+
|
|
23
|
+
std::vector<std::string> splitTokens(const std::string &text) {
|
|
24
|
+
std::vector<std::string> parts;
|
|
25
|
+
std::string current;
|
|
26
|
+
int depth = 0;
|
|
27
|
+
for (char c : text) {
|
|
28
|
+
if (c == '(') depth++;
|
|
29
|
+
if (c == ')') depth--;
|
|
30
|
+
if ((c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f') && depth == 0) {
|
|
31
|
+
if (!current.empty()) {
|
|
32
|
+
parts.push_back(current);
|
|
33
|
+
current.clear();
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
current.push_back(c);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (!current.empty()) parts.push_back(current);
|
|
40
|
+
return parts;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
bool parseBorderStyle(const std::string &value, BorderStyle *out) {
|
|
44
|
+
std::string text = lowerTrim(value);
|
|
45
|
+
if (text == "none") *out = BorderStyle::None;
|
|
46
|
+
else if (text == "solid") *out = BorderStyle::Solid;
|
|
47
|
+
else if (text == "dashed") *out = BorderStyle::Dashed;
|
|
48
|
+
else if (text == "dotted") *out = BorderStyle::Dotted;
|
|
49
|
+
else return false;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
bool parseCursor(const std::string &value, CursorShape *out) {
|
|
54
|
+
std::string text = lowerTrim(value);
|
|
55
|
+
if (text == "auto") *out = CursorShape::Auto;
|
|
56
|
+
else if (text == "default") *out = CursorShape::Default;
|
|
57
|
+
else if (text == "pointer" || text == "hand") *out = CursorShape::Pointer;
|
|
58
|
+
else if (text == "text" || text == "vertical-text") *out = CursorShape::Text;
|
|
59
|
+
else if (text == "move") *out = CursorShape::Move;
|
|
60
|
+
else if (text == "wait" || text == "progress") *out = CursorShape::Wait;
|
|
61
|
+
else if (text == "help") *out = CursorShape::Help;
|
|
62
|
+
else if (text == "not-allowed" || text == "no-drop") *out = CursorShape::NotAllowed;
|
|
63
|
+
else if (text == "crosshair") *out = CursorShape::Crosshair;
|
|
64
|
+
else return false;
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void resetOutline(XtStyle *style) {
|
|
69
|
+
style->outline_width = Length{0.0f, Unit::Px};
|
|
70
|
+
style->outline_style = BorderStyle::None;
|
|
71
|
+
style->outline_color = Color();
|
|
72
|
+
style->has_outline_color = false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} // namespace
|
|
76
|
+
|
|
77
|
+
bool xt_style_apply_ui_property(XtStyle *style, const std::string &property,
|
|
78
|
+
const std::string &rawValue) {
|
|
79
|
+
std::string value = xt_css_trim(rawValue);
|
|
80
|
+
|
|
81
|
+
if (property == "outline") {
|
|
82
|
+
resetOutline(style);
|
|
83
|
+
for (const std::string &token : splitTokens(value)) {
|
|
84
|
+
Length length = xt_css_parse_length(token);
|
|
85
|
+
if (length.unit != Unit::Invalid && length.unit != Unit::Auto &&
|
|
86
|
+
length.unit != Unit::None) {
|
|
87
|
+
style->outline_width = length;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (parseBorderStyle(token, &style->outline_style)) continue;
|
|
91
|
+
Color color = xt_css_parse_color(token);
|
|
92
|
+
if (color.valid) {
|
|
93
|
+
style->outline_color = color;
|
|
94
|
+
style->has_outline_color = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
if (property == "outline-width") {
|
|
100
|
+
Length length = xt_css_parse_length(value);
|
|
101
|
+
if (length.unit != Unit::Invalid && length.unit != Unit::Auto &&
|
|
102
|
+
length.unit != Unit::None) {
|
|
103
|
+
style->outline_width = length;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
if (property == "outline-style") {
|
|
108
|
+
parseBorderStyle(value, &style->outline_style);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (property == "outline-color") {
|
|
112
|
+
std::string text = lowerTrim(value);
|
|
113
|
+
if (text == "currentcolor" || text == "inherit") {
|
|
114
|
+
style->has_outline_color = false;
|
|
115
|
+
} else {
|
|
116
|
+
Color color = xt_css_parse_color(value);
|
|
117
|
+
if (color.valid) {
|
|
118
|
+
style->outline_color = color;
|
|
119
|
+
style->has_outline_color = true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (property == "outline-offset") {
|
|
125
|
+
Length length = xt_css_parse_length(value);
|
|
126
|
+
if (length.unit != Unit::Invalid && length.unit != Unit::Auto &&
|
|
127
|
+
length.unit != Unit::None) {
|
|
128
|
+
style->outline_offset = length;
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
if (property == "cursor") {
|
|
133
|
+
parseCursor(value, &style->cursor);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
if (property == "isolation") {
|
|
137
|
+
style->isolation = lowerTrim(value) == "isolate";
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
/* Accepted platform hints with no engine subsystem behind them. */
|
|
141
|
+
if (property == "touch-action" || property == "user-select" ||
|
|
142
|
+
property == "overscroll-behavior" || property == "scroll-behavior" ||
|
|
143
|
+
property == "vector-effect" || property == "-webkit-font-smoothing" ||
|
|
144
|
+
property == "-webkit-tap-highlight-color") {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
} // namespace xtgui
|