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
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
#include "canvas.h"
|
|
17
17
|
#include "image.h"
|
|
18
18
|
#include "image_bitmap.h"
|
|
19
|
+
#include "image_api.h"
|
|
19
20
|
#include "webgl.h"
|
|
21
|
+
#include "webgl_feature.h"
|
|
20
22
|
|
|
21
23
|
namespace domapi {
|
|
22
24
|
namespace {
|
|
@@ -121,10 +123,11 @@ bool webgl_read_source(xt_value source, int *width, int *height, std::vector<uin
|
|
|
121
123
|
XtGuiWindow *win = nullptr;
|
|
122
124
|
xtgui::Node *node = resolve_node(source, &win);
|
|
123
125
|
const xtgui::Image *image = nullptr;
|
|
126
|
+
const XtImageApi *images = xt_image_api();
|
|
124
127
|
std::vector<uint8_t> owned;
|
|
125
128
|
if (node != nullptr && node->isElement() && node->isTag("img")) {
|
|
126
129
|
const std::string *src = node->attr("src");
|
|
127
|
-
if (src != nullptr) image =
|
|
130
|
+
if (src != nullptr && images != nullptr) image = images->load(*src, 0, 0);
|
|
128
131
|
} else if (node != nullptr && node->isElement() && node->isTag("video")) {
|
|
129
132
|
xtgui::MediaPlayer *player = xt_gui_media_player(win, node);
|
|
130
133
|
if (player != nullptr) image = player->frame();
|
|
@@ -161,7 +164,7 @@ bool webgl_read_source(xt_value source, int *width, int *height, std::vector<uin
|
|
|
161
164
|
xt_value src = xt_object_get_cstr(source, "src");
|
|
162
165
|
if (XT_IS_STRING(src)) {
|
|
163
166
|
const char *path = xt_string_data(xt_to_string(src));
|
|
164
|
-
if (path != nullptr && path[0] != '\0') image =
|
|
167
|
+
if (path != nullptr && path[0] != '\0' && images != nullptr) image = images->load(path, 0, 0);
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
170
|
if (image == nullptr || image->width <= 0 || image->height <= 0) return false;
|
|
@@ -37,18 +37,72 @@ static bool parseTimeSeconds(const std::string &text, float *out) {
|
|
|
37
37
|
return true;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
static std::vector<std::string> splitCommas(const std::string &text);
|
|
41
|
+
static std::vector<std::string> splitTokens(const std::string &text);
|
|
42
|
+
|
|
43
|
+
/** Parse a CSS timing function. Besides the five keywords this accepts
|
|
44
|
+
* `cubic-bezier(x1, y1, x2, y2)` and `steps(n[, start|end|jump-*])`. */
|
|
40
45
|
static bool parseTimingFunction(const std::string &text, TimingFunction *out) {
|
|
41
46
|
std::string token = xt_css_lower(xt_css_trim(text));
|
|
42
47
|
if (token == "linear") {
|
|
43
|
-
*out = TimingFunction
|
|
48
|
+
*out = TimingFunction();
|
|
49
|
+
out->kind = TimingFunction::Kind::Linear;
|
|
44
50
|
} else if (token == "ease") {
|
|
45
|
-
*out = TimingFunction
|
|
51
|
+
*out = TimingFunction();
|
|
46
52
|
} else if (token == "ease-in") {
|
|
47
|
-
*out = TimingFunction
|
|
53
|
+
*out = TimingFunction();
|
|
54
|
+
out->kind = TimingFunction::Kind::EaseIn;
|
|
48
55
|
} else if (token == "ease-out") {
|
|
49
|
-
*out = TimingFunction
|
|
56
|
+
*out = TimingFunction();
|
|
57
|
+
out->kind = TimingFunction::Kind::EaseOut;
|
|
50
58
|
} else if (token == "ease-in-out") {
|
|
51
|
-
*out = TimingFunction
|
|
59
|
+
*out = TimingFunction();
|
|
60
|
+
out->kind = TimingFunction::Kind::EaseInOut;
|
|
61
|
+
} else if (token == "step-start") {
|
|
62
|
+
*out = TimingFunction();
|
|
63
|
+
out->kind = TimingFunction::Kind::StepsStart;
|
|
64
|
+
out->steps = 1;
|
|
65
|
+
} else if (token == "step-end") {
|
|
66
|
+
*out = TimingFunction();
|
|
67
|
+
out->kind = TimingFunction::Kind::StepsEnd;
|
|
68
|
+
out->steps = 1;
|
|
69
|
+
} else if (token.compare(0, 13, "cubic-bezier(") == 0 && token.back() == ')') {
|
|
70
|
+
std::vector<std::string> args =
|
|
71
|
+
splitCommas(token.substr(13, token.size() - 14));
|
|
72
|
+
if (args.size() != 4) return false;
|
|
73
|
+
float values[4];
|
|
74
|
+
for (int i = 0; i < 4; i++) {
|
|
75
|
+
if (!xt_css_parse_number(args[i], &values[i])) return false;
|
|
76
|
+
}
|
|
77
|
+
TimingFunction fn;
|
|
78
|
+
fn.kind = TimingFunction::Kind::CubicBezier;
|
|
79
|
+
fn.x1 = values[0] < 0.0f ? 0.0f : (values[0] > 1.0f ? 1.0f : values[0]);
|
|
80
|
+
fn.y1 = values[1];
|
|
81
|
+
fn.x2 = values[2] < 0.0f ? 0.0f : (values[2] > 1.0f ? 1.0f : values[2]);
|
|
82
|
+
fn.y2 = values[3];
|
|
83
|
+
*out = fn;
|
|
84
|
+
} else if (token.compare(0, 6, "steps(") == 0 && token.back() == ')') {
|
|
85
|
+
std::string inner = token.substr(6, token.size() - 7);
|
|
86
|
+
for (char &c : inner) {
|
|
87
|
+
if (c == ',') c = ' ';
|
|
88
|
+
}
|
|
89
|
+
std::vector<std::string> args = xt_css_split_whitespace(inner);
|
|
90
|
+
if (args.empty()) return false;
|
|
91
|
+
float count = 0;
|
|
92
|
+
if (!xt_css_parse_number(args[0], &count) || count < 1.0f) return false;
|
|
93
|
+
bool stepStart = false;
|
|
94
|
+
if (args.size() > 1) {
|
|
95
|
+
std::string position = xt_css_lower(args[1]);
|
|
96
|
+
if (position == "start" || position == "jump-start" || position == "jump-both") {
|
|
97
|
+
stepStart = true;
|
|
98
|
+
} else if (position != "end" && position != "jump-end" && position != "jump-none") {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
TimingFunction fn;
|
|
103
|
+
fn.kind = stepStart ? TimingFunction::Kind::StepsStart : TimingFunction::Kind::StepsEnd;
|
|
104
|
+
fn.steps = (int)(count + 0.5f);
|
|
105
|
+
*out = fn;
|
|
52
106
|
} else {
|
|
53
107
|
return false;
|
|
54
108
|
}
|
|
@@ -56,28 +110,21 @@ static bool parseTimingFunction(const std::string &text, TimingFunction *out) {
|
|
|
56
110
|
}
|
|
57
111
|
|
|
58
112
|
static std::vector<std::string> splitCommas(const std::string &text) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (i == text.size() || text[i] == ',') {
|
|
63
|
-
std::string part = xt_css_trim(text.substr(start, i - start));
|
|
64
|
-
if (!part.empty()) parts.push_back(part);
|
|
65
|
-
start = i + 1;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return parts;
|
|
113
|
+
/* Top-level commas only: a timing function or colour function may contain
|
|
114
|
+
* its own comma (`steps(4, end)`, `rgb(1, 2, 3)`). */
|
|
115
|
+
return xt_css_split_commas(text);
|
|
69
116
|
}
|
|
70
117
|
|
|
71
118
|
static void parseTransitionShorthand(const std::string &value, std::vector<TransitionSpec> *out) {
|
|
72
119
|
out->clear();
|
|
73
120
|
for (const std::string &group : splitCommas(value)) {
|
|
74
|
-
std::vector<std::string> tokens =
|
|
121
|
+
std::vector<std::string> tokens = splitTokens(group);
|
|
75
122
|
if (tokens.empty()) continue;
|
|
76
123
|
TransitionSpec spec;
|
|
77
124
|
int time_seen = 0;
|
|
78
125
|
for (const std::string &token : tokens) {
|
|
79
126
|
float seconds = 0;
|
|
80
|
-
TimingFunction timing
|
|
127
|
+
TimingFunction timing;
|
|
81
128
|
if (parseTimeSeconds(token, &seconds)) {
|
|
82
129
|
if (time_seen == 0) {
|
|
83
130
|
spec.duration = seconds;
|
|
@@ -89,6 +136,8 @@ static void parseTransitionShorthand(const std::string &value, std::vector<Trans
|
|
|
89
136
|
spec.timing = timing;
|
|
90
137
|
} else {
|
|
91
138
|
spec.property = xt_css_lower(token);
|
|
139
|
+
/* The shorthand animates its colour component. */
|
|
140
|
+
if (spec.property == "background") spec.property = "background-color";
|
|
92
141
|
}
|
|
93
142
|
}
|
|
94
143
|
out->push_back(spec);
|
|
@@ -99,7 +148,7 @@ static void parseTransitionShorthand(const std::string &value, std::vector<Trans
|
|
|
99
148
|
/* -- filters, shadows and generated content -------------------------------- */
|
|
100
149
|
|
|
101
150
|
/** Split on whitespace outside function parentheses (`rgb(1, 2, 3)` stays one). */
|
|
102
|
-
static std::vector<std::string>
|
|
151
|
+
static std::vector<std::string> splitTokens(const std::string &text) {
|
|
103
152
|
std::vector<std::string> parts;
|
|
104
153
|
std::string current;
|
|
105
154
|
int depth = 0;
|
|
@@ -152,7 +201,7 @@ static bool parseAngleDegrees(const std::string &raw, float *out) {
|
|
|
152
201
|
|
|
153
202
|
static bool parseShadowLengths(const std::string &value, Length *dx, Length *dy, Length *blur,
|
|
154
203
|
Color *color, bool *hasColor) {
|
|
155
|
-
std::vector<std::string> tokens =
|
|
204
|
+
std::vector<std::string> tokens = splitTokens(value);
|
|
156
205
|
Length lengths[3];
|
|
157
206
|
size_t count = 0;
|
|
158
207
|
for (const std::string &token : tokens) {
|
|
@@ -255,11 +304,106 @@ static bool parseTextShadow(const std::string &value, std::vector<TextShadow> *o
|
|
|
255
304
|
return true;
|
|
256
305
|
}
|
|
257
306
|
|
|
307
|
+
/** Parse a comma-separated `box-shadow` list. Offsets are `<dx> <dy>
|
|
308
|
+
* [<blur> [<spread>]]`, and the optional `inset` keyword plus a colour may
|
|
309
|
+
* appear anywhere in the entry, as in CSS. */
|
|
310
|
+
static bool parseBoxShadow(const std::string &value, std::vector<BoxShadow> *out) {
|
|
311
|
+
std::string text = xt_css_trim(value);
|
|
312
|
+
std::string lower = xt_css_lower(text);
|
|
313
|
+
out->clear();
|
|
314
|
+
if (lower == "none" || text.empty()) return true;
|
|
315
|
+
for (const std::string &part : splitCommas(value)) {
|
|
316
|
+
BoxShadow shadow;
|
|
317
|
+
Length lengths[4];
|
|
318
|
+
size_t count = 0;
|
|
319
|
+
for (const std::string &token : splitTokens(part)) {
|
|
320
|
+
std::string tokenLower = xt_css_lower(token);
|
|
321
|
+
if (tokenLower == "inset") {
|
|
322
|
+
shadow.inset = true;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
Length length = xt_css_parse_length(token);
|
|
326
|
+
if (length.unit != Unit::Invalid && length.unit != Unit::Auto &&
|
|
327
|
+
length.unit != Unit::None) {
|
|
328
|
+
if (count < 4) lengths[count++] = length;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
Color color = xt_css_parse_color(token);
|
|
332
|
+
if (color.valid) {
|
|
333
|
+
shadow.color = color;
|
|
334
|
+
shadow.has_color = true;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (count < 2) return false;
|
|
338
|
+
shadow.dx = lengths[0];
|
|
339
|
+
shadow.dy = lengths[1];
|
|
340
|
+
shadow.blur = count > 2 ? lengths[2] : Length{0.0f, Unit::Px};
|
|
341
|
+
shadow.spread = count > 3 ? lengths[3] : Length{0.0f, Unit::Px};
|
|
342
|
+
out->push_back(shadow);
|
|
343
|
+
}
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
static bool parseAnimationShorthand(const std::string &value, std::vector<AnimationSpec> *out) {
|
|
348
|
+
out->clear();
|
|
349
|
+
for (const std::string &group : splitCommas(value)) {
|
|
350
|
+
std::vector<std::string> tokens = splitTokens(group);
|
|
351
|
+
if (tokens.empty()) continue;
|
|
352
|
+
AnimationSpec spec;
|
|
353
|
+
int time_seen = 0;
|
|
354
|
+
for (const std::string &token : tokens) {
|
|
355
|
+
std::string lower = xt_css_lower(token);
|
|
356
|
+
float seconds = 0;
|
|
357
|
+
TimingFunction timing;
|
|
358
|
+
if (parseTimeSeconds(token, &seconds)) {
|
|
359
|
+
if (time_seen == 0) spec.duration = seconds;
|
|
360
|
+
else if (time_seen == 1) spec.delay = seconds;
|
|
361
|
+
time_seen++;
|
|
362
|
+
} else if (parseTimingFunction(token, &timing)) {
|
|
363
|
+
spec.timing = timing;
|
|
364
|
+
} else if (lower == "infinite") {
|
|
365
|
+
spec.iterations = -1.0f;
|
|
366
|
+
} else if (lower == "normal") {
|
|
367
|
+
spec.direction = AnimationDirection::Normal;
|
|
368
|
+
} else if (lower == "reverse") {
|
|
369
|
+
spec.direction = AnimationDirection::Reverse;
|
|
370
|
+
} else if (lower == "alternate") {
|
|
371
|
+
spec.direction = AnimationDirection::Alternate;
|
|
372
|
+
} else if (lower == "alternate-reverse") {
|
|
373
|
+
spec.direction = AnimationDirection::AlternateReverse;
|
|
374
|
+
} else if (lower == "none") {
|
|
375
|
+
spec.fill = AnimationFillMode::None;
|
|
376
|
+
} else if (lower == "forwards") {
|
|
377
|
+
spec.fill = AnimationFillMode::Forwards;
|
|
378
|
+
} else if (lower == "backwards") {
|
|
379
|
+
spec.fill = AnimationFillMode::Backwards;
|
|
380
|
+
} else if (lower == "both") {
|
|
381
|
+
spec.fill = AnimationFillMode::Both;
|
|
382
|
+
} else if (lower == "paused") {
|
|
383
|
+
spec.paused = true;
|
|
384
|
+
} else if (lower == "running") {
|
|
385
|
+
spec.paused = false;
|
|
386
|
+
} else {
|
|
387
|
+
float count = 0;
|
|
388
|
+
if (xt_css_parse_number(token, &count)) spec.iterations = count;
|
|
389
|
+
else spec.name = token;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
out->push_back(spec);
|
|
393
|
+
}
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
|
|
258
397
|
bool xt_style_apply_effect(XtStyle *style, const std::string &property,
|
|
259
398
|
const std::string &value) {
|
|
260
399
|
if (property == "filter") return parseFilterList(value, &style->filters);
|
|
261
400
|
if (property == "backdrop-filter") return parseFilterList(value, &style->backdrop_filters);
|
|
262
401
|
if (property == "text-shadow") return parseTextShadow(value, &style->text_shadow);
|
|
402
|
+
if (property == "box-shadow") return parseBoxShadow(value, &style->box_shadow);
|
|
403
|
+
if (property == "animation") {
|
|
404
|
+
parseAnimationShorthand(value, &style->animations);
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
263
407
|
if (property == "content") {
|
|
264
408
|
std::string text = xt_css_lower(xt_css_trim(value));
|
|
265
409
|
if (text == "none" || text == "normal") {
|
|
@@ -283,7 +427,11 @@ bool xt_style_apply_transition(XtStyle *style, const std::string &property,
|
|
|
283
427
|
if (property == "transition-property") {
|
|
284
428
|
std::vector<std::string> parts = splitCommas(value);
|
|
285
429
|
style->transitions.resize(parts.size());
|
|
286
|
-
for (size_t i = 0; i < parts.size(); i++)
|
|
430
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
431
|
+
style->transitions[i].property = xt_css_lower(parts[i]);
|
|
432
|
+
if (style->transitions[i].property == "background")
|
|
433
|
+
style->transitions[i].property = "background-color";
|
|
434
|
+
}
|
|
287
435
|
return true;
|
|
288
436
|
}
|
|
289
437
|
if (property == "transition-duration" || property == "transition-delay") {
|
|
@@ -301,7 +449,7 @@ bool xt_style_apply_transition(XtStyle *style, const std::string &property,
|
|
|
301
449
|
std::vector<std::string> parts = splitCommas(value);
|
|
302
450
|
style->transitions.resize(parts.size());
|
|
303
451
|
for (size_t i = 0; i < parts.size(); i++) {
|
|
304
|
-
TimingFunction timing
|
|
452
|
+
TimingFunction timing;
|
|
305
453
|
if (parseTimingFunction(parts[i], &timing)) style->transitions[i].timing = timing;
|
|
306
454
|
}
|
|
307
455
|
return true;
|
|
@@ -309,4 +457,80 @@ bool xt_style_apply_transition(XtStyle *style, const std::string &property,
|
|
|
309
457
|
return false;
|
|
310
458
|
}
|
|
311
459
|
|
|
460
|
+
bool xt_style_apply_animation(XtStyle *style, const std::string &property,
|
|
461
|
+
const std::string &value) {
|
|
462
|
+
if (property == "animation-name") {
|
|
463
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
464
|
+
style->animations.resize(parts.size());
|
|
465
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
466
|
+
style->animations[i].name = parts[i];
|
|
467
|
+
}
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
if (property == "animation-duration" || property == "animation-delay") {
|
|
471
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
472
|
+
style->animations.resize(parts.size());
|
|
473
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
474
|
+
float seconds = 0;
|
|
475
|
+
if (!parseTimeSeconds(parts[i], &seconds)) continue;
|
|
476
|
+
if (property == "animation-duration") style->animations[i].duration = seconds;
|
|
477
|
+
else style->animations[i].delay = seconds;
|
|
478
|
+
}
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
if (property == "animation-timing-function") {
|
|
482
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
483
|
+
style->animations.resize(parts.size());
|
|
484
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
485
|
+
TimingFunction timing;
|
|
486
|
+
if (parseTimingFunction(parts[i], &timing)) style->animations[i].timing = timing;
|
|
487
|
+
}
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
if (property == "animation-iteration-count") {
|
|
491
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
492
|
+
style->animations.resize(parts.size());
|
|
493
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
494
|
+
std::string lower = xt_css_lower(parts[i]);
|
|
495
|
+
float count = 0;
|
|
496
|
+
if (lower == "infinite") style->animations[i].iterations = -1.0f;
|
|
497
|
+
else if (xt_css_parse_number(parts[i], &count)) style->animations[i].iterations = count;
|
|
498
|
+
}
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
if (property == "animation-direction") {
|
|
502
|
+
static const char *const names[] = {"normal", "reverse", "alternate", "alternate-reverse"};
|
|
503
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
504
|
+
style->animations.resize(parts.size());
|
|
505
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
506
|
+
std::string lower = xt_css_lower(parts[i]);
|
|
507
|
+
for (int d = 0; d < 4; d++) {
|
|
508
|
+
if (lower == names[d]) style->animations[i].direction = (AnimationDirection)d;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
if (property == "animation-fill-mode") {
|
|
514
|
+
static const char *const names[] = {"none", "forwards", "backwards", "both"};
|
|
515
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
516
|
+
style->animations.resize(parts.size());
|
|
517
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
518
|
+
std::string lower = xt_css_lower(parts[i]);
|
|
519
|
+
for (int f = 0; f < 4; f++) {
|
|
520
|
+
if (lower == names[f]) style->animations[i].fill = (AnimationFillMode)f;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
if (property == "animation-play-state") {
|
|
526
|
+
std::vector<std::string> parts = splitCommas(value);
|
|
527
|
+
style->animations.resize(parts.size());
|
|
528
|
+
for (size_t i = 0; i < parts.size(); i++) {
|
|
529
|
+
style->animations[i].paused = xt_css_lower(parts[i]) == "paused";
|
|
530
|
+
}
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
|
|
312
536
|
} // namespace xtgui
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — `gpu` link feature registration bridge.
|
|
3
|
+
*
|
|
4
|
+
* This tiny C translation unit is compiled and linked *only* when the compiler
|
|
5
|
+
* decides the program may compile GLSL (`getContext("webgl…")`,
|
|
6
|
+
* `mix-blend-mode`, or markup built at run time). Its constructor calls
|
|
7
|
+
* `xt_gpu_feature_register` in `gpu_feature.cpp`, which installs the shader
|
|
8
|
+
* table and references glslang/SPIRV-Cross; those references are what make the
|
|
9
|
+
* linker extract the translator members from `gui.a`.
|
|
10
|
+
*
|
|
11
|
+
* When the feature is inactive this object is absent, so nothing references the
|
|
12
|
+
* translator and the table in `gpu_shader.cpp` stays null.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
extern void xt_gpu_feature_register(void);
|
|
16
|
+
|
|
17
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
18
|
+
/* clang targeting Windows (the toolchain xbintsc uses there) implements this
|
|
19
|
+
* attribute with a `.CRT$XCU` entry, which the MSVC CRT runs before `main`. */
|
|
20
|
+
__attribute__((constructor)) static void xt_gpu_feature_boot(void) {
|
|
21
|
+
xt_gpu_feature_register();
|
|
22
|
+
}
|
|
23
|
+
#elif defined(_MSC_VER)
|
|
24
|
+
void xt_gpu_feature_boot(void);
|
|
25
|
+
#pragma section(".CRT$XCU", read)
|
|
26
|
+
__declspec(allocate(".CRT$XCU")) static void (*const xt_gpu_feature_ctor)(void) = xt_gpu_feature_boot;
|
|
27
|
+
void xt_gpu_feature_boot(void) { xt_gpu_feature_register(); }
|
|
28
|
+
#endif
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — `gpu` link feature implementation.
|
|
3
|
+
*
|
|
4
|
+
* This translation unit is the only place in `gui.a` that references glslang and
|
|
5
|
+
* SPIRV-Cross. It is pulled out of the archive only when `gpu_bridge.c` (the
|
|
6
|
+
* feature's C registration object) is linked, which happens only when the
|
|
7
|
+
* compiler detects that the program may compile shaders. Without it the engine
|
|
8
|
+
* sees a null table (`gpu_shader.cpp`) and no glslang member is extracted.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#include "gpu_shader_api.h"
|
|
12
|
+
#include "webgl_msl.h"
|
|
13
|
+
|
|
14
|
+
namespace {
|
|
15
|
+
|
|
16
|
+
const xtgui::GpuShaderApi kGpuShaderApi = {
|
|
17
|
+
xtgui::unroll_glsl_pragmas,
|
|
18
|
+
xtgui::scan_glsl,
|
|
19
|
+
xtgui::rewrite_glsl,
|
|
20
|
+
xtgui::compile_glsl,
|
|
21
|
+
xtgui::reflect_uniform_block,
|
|
22
|
+
xtgui::reflect_attributes,
|
|
23
|
+
xtgui::cross_compile_msl,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
} // namespace
|
|
27
|
+
|
|
28
|
+
extern "C" void xt_gpu_feature_register(void) {
|
|
29
|
+
xtgui::gpu_shader_install(&kGpuShaderApi);
|
|
30
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — core-side registry for the optional GPU shader table.
|
|
3
|
+
*
|
|
4
|
+
* Kept in `gui.a` and free of any glslang/SPIRV-Cross dependency: the table is
|
|
5
|
+
* installed by the `gpu` feature's bridge when that feature is linked, and stays
|
|
6
|
+
* null otherwise. See `gpu_shader_api.h`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "gpu_shader_api.h"
|
|
10
|
+
|
|
11
|
+
namespace xtgui {
|
|
12
|
+
namespace {
|
|
13
|
+
|
|
14
|
+
const GpuShaderApi *g_api = nullptr;
|
|
15
|
+
|
|
16
|
+
} // namespace
|
|
17
|
+
|
|
18
|
+
void gpu_shader_install(const GpuShaderApi *api) { g_api = api; }
|
|
19
|
+
|
|
20
|
+
const GpuShaderApi *gpu_shader_api() { return g_api; }
|
|
21
|
+
|
|
22
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — optional GPU shader translation table.
|
|
3
|
+
*
|
|
4
|
+
* WebGL shaders and the `mix-blend-mode` compositor both need GLSL→SPIR-V
|
|
5
|
+
* translation (glslang), and on Metal a second SPIR-V→MSL pass (SPIRV-Cross).
|
|
6
|
+
* Those are the largest optional third-party dependencies in the GUI engine, so
|
|
7
|
+
* the engine reaches them through this table instead of linking them directly.
|
|
8
|
+
*
|
|
9
|
+
* The implementation lives in `gpu_feature.cpp` and is only pulled out of
|
|
10
|
+
* `gui.a` when the `gpu` link feature's bridge is linked. Without it the table is
|
|
11
|
+
* null: the blend compositor falls back to ordinary painting and WebGL reports a
|
|
12
|
+
* shader compile log, but a DOM/2D-canvas page still runs.
|
|
13
|
+
*/
|
|
14
|
+
#ifndef XT_GUI_GPU_SHADER_API_H
|
|
15
|
+
#define XT_GUI_GPU_SHADER_API_H
|
|
16
|
+
|
|
17
|
+
#include <string>
|
|
18
|
+
#include <unordered_map>
|
|
19
|
+
#include <vector>
|
|
20
|
+
|
|
21
|
+
#include "webgl_glsl.h"
|
|
22
|
+
|
|
23
|
+
namespace xtgui {
|
|
24
|
+
|
|
25
|
+
/** The GLSL preprocessing/translation/reflection entry points the engine calls
|
|
26
|
+
* on demand. */
|
|
27
|
+
struct GpuShaderApi {
|
|
28
|
+
std::string (*unroll_glsl_pragmas)(const std::string &source);
|
|
29
|
+
void (*scan_glsl)(const std::string &source, bool fragment, GlslShaderInfo *info);
|
|
30
|
+
std::string (*rewrite_glsl)(const std::string &source, bool fragment,
|
|
31
|
+
const GlslLinkLayout &layout, const GlslShaderInfo &info);
|
|
32
|
+
bool (*compile_glsl)(const std::string &source, bool fragment,
|
|
33
|
+
std::vector<uint32_t> *spirv, std::string *log);
|
|
34
|
+
bool (*reflect_uniform_block)(const std::vector<uint32_t> &spirv,
|
|
35
|
+
std::vector<GlslBlockMember> *out);
|
|
36
|
+
bool (*reflect_attributes)(const std::vector<uint32_t> &spirv,
|
|
37
|
+
std::unordered_map<std::string, int> *out);
|
|
38
|
+
bool (*cross_compile_msl)(const std::vector<uint32_t> &spirv, bool fragment,
|
|
39
|
+
std::string *source, std::string *entry, std::string *log);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** Install the table. Called by the `gpu` feature bridge before `main`. */
|
|
43
|
+
void gpu_shader_install(const GpuShaderApi *api);
|
|
44
|
+
|
|
45
|
+
/** The installed table, or null when the `gpu` feature was not linked. */
|
|
46
|
+
const GpuShaderApi *gpu_shader_api();
|
|
47
|
+
|
|
48
|
+
} // namespace xtgui
|
|
49
|
+
|
|
50
|
+
#endif /* XT_GUI_GPU_SHADER_API_H */
|
|
@@ -474,10 +474,34 @@ void xt_style_apply_background(XtStyle *style, const std::string &value) {
|
|
|
474
474
|
std::vector<BackgroundLayer> layers;
|
|
475
475
|
parseLayers(value, &layers, &color, &hasColor, true);
|
|
476
476
|
style->background_layers = std::move(layers);
|
|
477
|
+
style->background_sizes.clear();
|
|
477
478
|
if (hasColor) {
|
|
478
479
|
style->background = color;
|
|
479
480
|
style->has_background = true;
|
|
480
481
|
}
|
|
481
482
|
}
|
|
482
483
|
|
|
484
|
+
bool xt_style_apply_background_size(XtStyle *style, const std::string &value) {
|
|
485
|
+
std::vector<BackgroundSize> sizes;
|
|
486
|
+
for (const std::string &part : splitCommas(value)) {
|
|
487
|
+
std::vector<std::string> tokens = splitTokens(part);
|
|
488
|
+
if (tokens.empty()) continue;
|
|
489
|
+
BackgroundSize size;
|
|
490
|
+
for (size_t i = 0; i < tokens.size() && i < 2; i++) {
|
|
491
|
+
std::string token = xt_css_lower(xt_css_trim(tokens[i]));
|
|
492
|
+
Length length{0.0f, Unit::Auto};
|
|
493
|
+
if (token != "auto" && token != "cover" && token != "contain") {
|
|
494
|
+
Length parsed = xt_css_parse_length(token);
|
|
495
|
+
if (parsed.unit != Unit::Invalid && parsed.unit != Unit::None) length = parsed;
|
|
496
|
+
}
|
|
497
|
+
if (i == 0) size.width = length;
|
|
498
|
+
else size.height = length;
|
|
499
|
+
}
|
|
500
|
+
if (tokens.size() == 1) size.height = Length{0.0f, Unit::Auto};
|
|
501
|
+
sizes.push_back(size);
|
|
502
|
+
}
|
|
503
|
+
style->background_sizes = std::move(sizes);
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
|
|
483
507
|
} // namespace xtgui
|
|
@@ -223,6 +223,29 @@ bool xt_style_apply_grid_property(XtStyle *style, const std::string &property,
|
|
|
223
223
|
parseGridLine(value, &style->grid_row_start, &style->grid_row_end);
|
|
224
224
|
return true;
|
|
225
225
|
}
|
|
226
|
+
if (property == "grid-area") {
|
|
227
|
+
std::vector<std::string> parts;
|
|
228
|
+
std::string current;
|
|
229
|
+
int depth = 0;
|
|
230
|
+
for (char c : value) {
|
|
231
|
+
if (c == '(') depth++;
|
|
232
|
+
if (c == ')') depth--;
|
|
233
|
+
if (c == '/' && depth == 0) {
|
|
234
|
+
parts.push_back(xt_css_trim(current));
|
|
235
|
+
current.clear();
|
|
236
|
+
} else {
|
|
237
|
+
current.push_back(c);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
parts.push_back(xt_css_trim(current));
|
|
241
|
+
style->grid_row_start = style->grid_column_start = 0;
|
|
242
|
+
style->grid_row_end = style->grid_column_end = 0;
|
|
243
|
+
if (parts.size() >= 1) parseGridLineNumber(parts[0], &style->grid_row_start);
|
|
244
|
+
if (parts.size() >= 2) parseGridLineNumber(parts[1], &style->grid_column_start);
|
|
245
|
+
if (parts.size() >= 3) parseGridLineNumber(parts[2], &style->grid_row_end);
|
|
246
|
+
if (parts.size() >= 4) parseGridLineNumber(parts[3], &style->grid_column_end);
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
226
249
|
|
|
227
250
|
return false;
|
|
228
251
|
}
|
package/runtime/ext_gui/gui.cpp
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
#include "gui_internal.h"
|
|
17
17
|
|
|
18
|
-
#include "
|
|
18
|
+
#include "image_api.h"
|
|
19
19
|
#include "paint.h"
|
|
20
20
|
|
|
21
21
|
#include <stdio.h>
|
|
@@ -36,40 +36,9 @@ int g_window_count = 0;
|
|
|
36
36
|
* `createWindow`), so the next `createWindow` adopts it. */
|
|
37
37
|
int g_implicit_window = 0;
|
|
38
38
|
|
|
39
|
-
/*
|
|
40
|
-
* `
|
|
41
|
-
*
|
|
42
|
-
* are plain: `xt_app_icon_size == 0` means "no icon". */
|
|
43
|
-
extern "C" {
|
|
44
|
-
extern const unsigned char xt_app_icon_data[];
|
|
45
|
-
extern const unsigned long long xt_app_icon_size;
|
|
46
|
-
extern const char xt_app_icon_format[];
|
|
47
|
-
extern const unsigned int xt_app_icon_width;
|
|
48
|
-
extern const unsigned int xt_app_icon_height;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Set the window / taskbar / Dock icon from the embedded PNG, if any. Decoding
|
|
53
|
-
* goes through the same stb_image path as `<img>`, so the icon needs no extra
|
|
54
|
-
* dependency. Failures are silent: an icon is cosmetic and must never stop the
|
|
55
|
-
* program from starting.
|
|
56
|
-
*/
|
|
57
|
-
void xt_gui_apply_icon(SDL_Window *window) {
|
|
58
|
-
if (window == NULL) return;
|
|
59
|
-
size_t size = (size_t)xt_app_icon_size;
|
|
60
|
-
if (size == 0) return;
|
|
61
|
-
if (strcmp(xt_app_icon_format, "png") != 0) return;
|
|
62
|
-
|
|
63
|
-
xtgui::Image image;
|
|
64
|
-
if (!xtgui::xt_image_decode(xt_app_icon_data, size, &image)) return;
|
|
65
|
-
if (image.width <= 0 || image.height <= 0) return;
|
|
66
|
-
|
|
67
|
-
SDL_Surface *surface = SDL_CreateSurfaceFrom(
|
|
68
|
-
image.width, image.height, SDL_PIXELFORMAT_RGBA32, image.pixels.data(), image.width * 4);
|
|
69
|
-
if (surface == NULL) return;
|
|
70
|
-
SDL_SetWindowIcon(window, surface);
|
|
71
|
-
SDL_DestroySurface(surface);
|
|
72
|
-
}
|
|
39
|
+
/* The application icon is decoded and applied by the optional `images` feature
|
|
40
|
+
* (`XtImageApi::apply_icon`), which is forced on when an icon is configured.
|
|
41
|
+
* Keeping it there lets a text-only program drop SDL's surface/blit code. */
|
|
73
42
|
|
|
74
43
|
/* -- garbage collector roots ---------------------------------------------- */
|
|
75
44
|
|
|
@@ -247,7 +216,7 @@ static XtGuiWindow *create_window_record(const char *title, int width, int heigh
|
|
|
247
216
|
SDL_DestroyWindow(window);
|
|
248
217
|
return NULL;
|
|
249
218
|
}
|
|
250
|
-
|
|
219
|
+
if (const XtImageApi *images = xt_image_api()) images->apply_icon(window);
|
|
251
220
|
|
|
252
221
|
int index = g_window_count++;
|
|
253
222
|
XtGuiWindow *record = &g_windows[index];
|
|
@@ -470,7 +439,7 @@ extern "C" xt_value xt_gui_run(int32_t argc, xt_value *argv) {
|
|
|
470
439
|
}
|
|
471
440
|
/* Drop the decoded-image caches (including parsed SVG documents) now that
|
|
472
441
|
* the GPU textures that referenced them are gone. */
|
|
473
|
-
|
|
442
|
+
if (const XtImageApi *images = xt_image_api()) images->shutdown();
|
|
474
443
|
g_window_count = 0;
|
|
475
444
|
return XT_UNDEFINED;
|
|
476
445
|
}
|