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
|
@@ -15,6 +15,10 @@ void Layouter::flattenInline(LayoutBox *box, float contentWidth,
|
|
|
15
15
|
std::vector<InlineItem> &out) const {
|
|
16
16
|
const XtStyle &style = *box->style;
|
|
17
17
|
if (box->is_text) {
|
|
18
|
+
if (style.writing_mode != WritingMode::HorizontalTB) {
|
|
19
|
+
flattenVerticalText(box, out);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
18
22
|
float height = lineHeightOf(style);
|
|
19
23
|
float ascent = ascentOf(style);
|
|
20
24
|
const std::string &text = box->text;
|
|
@@ -45,7 +49,8 @@ void Layouter::flattenInline(LayoutBox *box, float contentWidth,
|
|
|
45
49
|
}
|
|
46
50
|
return;
|
|
47
51
|
}
|
|
48
|
-
if (box->display == Display::InlineBlock
|
|
52
|
+
if (box->display == Display::InlineBlock || style.inline_level ||
|
|
53
|
+
style.writing_mode != WritingMode::HorizontalTB) {
|
|
49
54
|
float available = contentWidth;
|
|
50
55
|
float intrinsic = preferredContentWidth(box, available);
|
|
51
56
|
setContainingBlock(box, containingBlockAncestor(box));
|
|
@@ -56,6 +61,13 @@ void Layouter::flattenInline(LayoutBox *box, float contentWidth,
|
|
|
56
61
|
item.atomic = true;
|
|
57
62
|
item.width = box->margin_left + box->width + box->margin_right;
|
|
58
63
|
item.height = box->margin_top + box->height + box->margin_bottom;
|
|
64
|
+
float shift = 0.0f;
|
|
65
|
+
if (!isAuto(style.vertical_align)) {
|
|
66
|
+
shift = px(style.vertical_align, available, style.font_size, 0.0f);
|
|
67
|
+
}
|
|
68
|
+
/* A positive `vertical-align` raises the atomic box above the baseline;
|
|
69
|
+
* the line box keeps its own ascent so the shift is purely visual. */
|
|
70
|
+
item.shift = shift;
|
|
59
71
|
item.ascent = item.height;
|
|
60
72
|
out.push_back(std::move(item));
|
|
61
73
|
return;
|
|
@@ -68,6 +80,13 @@ void Layouter::flattenInline(LayoutBox *box, float contentWidth,
|
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
void Layouter::computeInlineGeometry(LayoutBox *box) const {
|
|
83
|
+
/* An atomic inline box already has geometry from its own formatting context;
|
|
84
|
+
* replacing it with the union of its descendants would shrink an inline-grid
|
|
85
|
+
* to its text (and an inline-block to its content). */
|
|
86
|
+
if (!box->is_text && box->style != nullptr &&
|
|
87
|
+
(box->display == Display::InlineBlock || box->style->inline_level)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
71
90
|
if (box->is_text) {
|
|
72
91
|
if (box->fragments.empty()) return;
|
|
73
92
|
float minx = kHuge, miny = kHuge, maxx = -kHuge, maxy = -kHuge;
|
|
@@ -119,6 +138,11 @@ float Layouter::layoutInlineRun(LayoutBox *container, const std::vector<LayoutBo
|
|
|
119
138
|
if (items.empty()) return 0;
|
|
120
139
|
|
|
121
140
|
const XtStyle &containerStyle = *container->style;
|
|
141
|
+
if (containerStyle.writing_mode != WritingMode::HorizontalTB) {
|
|
142
|
+
float height = layoutVerticalRun(container, items, contentWidth, y);
|
|
143
|
+
for (LayoutBox *box : run) computeInlineGeometry(box);
|
|
144
|
+
return height;
|
|
145
|
+
}
|
|
122
146
|
float cursorY = y;
|
|
123
147
|
std::vector<InlineItem *> line;
|
|
124
148
|
float lineWidth = 0;
|
|
@@ -159,7 +183,7 @@ float Layouter::layoutInlineRun(LayoutBox *container, const std::vector<LayoutBo
|
|
|
159
183
|
* `layoutBlock`, so it must not be moved back onto the line. */
|
|
160
184
|
if (!isAbsoluteChild(item->box)) {
|
|
161
185
|
float dx = x + item->box->margin_left - item->box->x;
|
|
162
|
-
float dy = cursorY + item->box->margin_top - item->box->y;
|
|
186
|
+
float dy = cursorY + item->box->margin_top - item->box->y - item->shift;
|
|
163
187
|
translate(item->box, dx, dy);
|
|
164
188
|
/* `position: relative` on an inline-block shifts it after line
|
|
165
189
|
* placement, so the line box keeps the space it reserved. */
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — vertical writing mode (`writing-mode: vertical-rl|-lr`).
|
|
3
|
+
*
|
|
4
|
+
* This is a focused text layout: characters are placed one per column step,
|
|
5
|
+
* CJK glyphs upright and other scripts rotated 90° at paint time. It covers the
|
|
6
|
+
* decorative vertical labels a page uses; mixed block/inline content in a
|
|
7
|
+
* vertical container still falls back to horizontal layout (documented).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "layout_flow_internal.h"
|
|
11
|
+
|
|
12
|
+
namespace xtgui {
|
|
13
|
+
namespace layout_flow_detail {
|
|
14
|
+
|
|
15
|
+
namespace {
|
|
16
|
+
|
|
17
|
+
/** Decode one UTF-8 codepoint at `index`, advancing it. */
|
|
18
|
+
uint32_t nextCodePoint(const std::string &text, size_t *index) {
|
|
19
|
+
unsigned char first = (unsigned char)text[*index];
|
|
20
|
+
uint32_t value = first;
|
|
21
|
+
size_t length = 1;
|
|
22
|
+
if ((first & 0x80u) == 0) {
|
|
23
|
+
value = first;
|
|
24
|
+
} else if ((first & 0xe0u) == 0xc0u) {
|
|
25
|
+
value = first & 0x1fu;
|
|
26
|
+
length = 2;
|
|
27
|
+
} else if ((first & 0xf0u) == 0xe0u) {
|
|
28
|
+
value = first & 0x0fu;
|
|
29
|
+
length = 3;
|
|
30
|
+
} else {
|
|
31
|
+
value = first & 0x07u;
|
|
32
|
+
length = 4;
|
|
33
|
+
}
|
|
34
|
+
for (size_t i = 1; i < length && *index + i < text.size(); i++) {
|
|
35
|
+
value = (value << 6) | ((unsigned char)text[*index + i] & 0x3fu);
|
|
36
|
+
}
|
|
37
|
+
*index += length;
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** CJK, kana, Hangul and fullwidth forms are kept upright in vertical text. */
|
|
42
|
+
bool isUprightCodePoint(uint32_t value) {
|
|
43
|
+
if (value >= 0x1100 && value <= 0x11ff) return true;
|
|
44
|
+
if (value >= 0x2e80 && value <= 0xa4cf) return true;
|
|
45
|
+
if (value >= 0xac00 && value <= 0xd7af) return true;
|
|
46
|
+
if (value >= 0xf900 && value <= 0xfaff) return true;
|
|
47
|
+
if (value >= 0xfe30 && value <= 0xfe4f) return true;
|
|
48
|
+
if (value >= 0xff00 && value <= 0xffef) return true;
|
|
49
|
+
if (value >= 0x20000) return true;
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The column's top-left x for the first column (right edge for `vertical-rl`). */
|
|
54
|
+
float firstColumnX(const LayoutBox *container, const XtStyle &style, float contentWidth,
|
|
55
|
+
float columnWidth) {
|
|
56
|
+
if (style.writing_mode == WritingMode::VerticalLR) return container->content_x;
|
|
57
|
+
float x = container->content_x + contentWidth - columnWidth;
|
|
58
|
+
if (x < container->content_x) x = container->content_x;
|
|
59
|
+
return x;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
} // namespace
|
|
63
|
+
|
|
64
|
+
void Layouter::flattenVerticalText(LayoutBox *box, std::vector<InlineItem> &out) const {
|
|
65
|
+
const XtStyle &style = *box->style;
|
|
66
|
+
const float columnWidth = lineHeightOf(style);
|
|
67
|
+
const std::string &text = box->text;
|
|
68
|
+
size_t index = 0;
|
|
69
|
+
while (index < text.size()) {
|
|
70
|
+
size_t start = index;
|
|
71
|
+
uint32_t code = nextCodePoint(text, &index);
|
|
72
|
+
if (code == '\n') {
|
|
73
|
+
InlineItem br;
|
|
74
|
+
br.box = box;
|
|
75
|
+
br.style = &style;
|
|
76
|
+
br.force_break = true;
|
|
77
|
+
br.vertical = true;
|
|
78
|
+
out.push_back(std::move(br));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
InlineItem item;
|
|
82
|
+
item.box = box;
|
|
83
|
+
item.style = &style;
|
|
84
|
+
item.text = text.substr(start, index - start);
|
|
85
|
+
item.is_space = code == ' ' || code == '\t';
|
|
86
|
+
item.vertical = true;
|
|
87
|
+
item.upright = isUprightCodePoint(code);
|
|
88
|
+
item.width = columnWidth;
|
|
89
|
+
item.height = textWidth(item.text, style);
|
|
90
|
+
item.ascent = item.height;
|
|
91
|
+
out.push_back(std::move(item));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
float Layouter::layoutVerticalRun(LayoutBox *container, const std::vector<InlineItem> &items,
|
|
96
|
+
float contentWidth, float y) const {
|
|
97
|
+
const XtStyle &style = *container->style;
|
|
98
|
+
const float columnWidth = lineHeightOf(style);
|
|
99
|
+
const bool rightToLeft = style.writing_mode != WritingMode::VerticalLR;
|
|
100
|
+
float limit = -1.0f;
|
|
101
|
+
if (!isAuto(style.height)) limit = px(style.height, container->content_height, style.font_size, -1.0f);
|
|
102
|
+
|
|
103
|
+
float columnX = firstColumnX(container, style, contentWidth, columnWidth);
|
|
104
|
+
float cursorY = y;
|
|
105
|
+
float startY = y;
|
|
106
|
+
float minX = columnX;
|
|
107
|
+
float maxX = columnX + columnWidth;
|
|
108
|
+
float maxY = y;
|
|
109
|
+
bool atColumnStart = true;
|
|
110
|
+
|
|
111
|
+
auto newColumn = [&]() {
|
|
112
|
+
columnX += rightToLeft ? -columnWidth : columnWidth;
|
|
113
|
+
cursorY = startY;
|
|
114
|
+
atColumnStart = true;
|
|
115
|
+
if (columnX < minX) minX = columnX;
|
|
116
|
+
if (columnX + columnWidth > maxX) maxX = columnX + columnWidth;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
for (const InlineItem &item : items) {
|
|
120
|
+
if (item.force_break) {
|
|
121
|
+
newColumn();
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (item.is_space && atColumnStart) continue;
|
|
125
|
+
if (limit >= 0.0f && !atColumnStart && cursorY + item.height > startY + limit) newColumn();
|
|
126
|
+
item.box->fragments.push_back(
|
|
127
|
+
{columnX, cursorY, columnWidth, item.height, item.text, true, item.upright});
|
|
128
|
+
cursorY += item.height;
|
|
129
|
+
atColumnStart = false;
|
|
130
|
+
if (cursorY > maxY) maxY = cursorY;
|
|
131
|
+
if (item.width > 0.0f) {
|
|
132
|
+
float right = columnX + columnWidth;
|
|
133
|
+
if (right > maxX) maxX = right;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
(void)minX;
|
|
137
|
+
(void)maxX;
|
|
138
|
+
return maxY - startY;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
float Layouter::layoutVerticalTextBox(LayoutBox *box, float x, float y, float width) const {
|
|
142
|
+
const XtStyle &style = *box->style;
|
|
143
|
+
const float columnWidth = lineHeightOf(style);
|
|
144
|
+
const bool rightToLeft = style.writing_mode != WritingMode::VerticalLR;
|
|
145
|
+
float limit = -1.0f;
|
|
146
|
+
if (!isAuto(style.height)) limit = px(style.height, -1.0f, style.font_size, -1.0f);
|
|
147
|
+
|
|
148
|
+
float columnX = rightToLeft ? x + width - columnWidth : x;
|
|
149
|
+
if (rightToLeft && columnX < x) columnX = x;
|
|
150
|
+
float cursorY = y;
|
|
151
|
+
float startY = y;
|
|
152
|
+
float minX = columnX;
|
|
153
|
+
float maxX = columnX + columnWidth;
|
|
154
|
+
float maxY = y;
|
|
155
|
+
bool atColumnStart = true;
|
|
156
|
+
|
|
157
|
+
size_t index = 0;
|
|
158
|
+
const std::string &text = box->text;
|
|
159
|
+
while (index < text.size()) {
|
|
160
|
+
size_t start = index;
|
|
161
|
+
uint32_t code = nextCodePoint(text, &index);
|
|
162
|
+
if (code == '\n') {
|
|
163
|
+
columnX += rightToLeft ? -columnWidth : columnWidth;
|
|
164
|
+
cursorY = startY;
|
|
165
|
+
atColumnStart = true;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
std::string glyph = text.substr(start, index - start);
|
|
169
|
+
float advance = textWidth(glyph, style);
|
|
170
|
+
if (limit >= 0.0f && !atColumnStart && cursorY + advance > startY + limit) {
|
|
171
|
+
columnX += rightToLeft ? -columnWidth : columnWidth;
|
|
172
|
+
cursorY = startY;
|
|
173
|
+
atColumnStart = true;
|
|
174
|
+
}
|
|
175
|
+
if (code == ' ' && atColumnStart) continue;
|
|
176
|
+
box->fragments.push_back(
|
|
177
|
+
{columnX, cursorY, columnWidth, advance, glyph, true, isUprightCodePoint(code)});
|
|
178
|
+
cursorY += advance;
|
|
179
|
+
atColumnStart = false;
|
|
180
|
+
if (cursorY > maxY) maxY = cursorY;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
box->x = minX;
|
|
184
|
+
box->y = startY;
|
|
185
|
+
box->width = maxX - minX;
|
|
186
|
+
box->height = maxY - startY;
|
|
187
|
+
box->content_x = box->x;
|
|
188
|
+
box->content_y = box->y;
|
|
189
|
+
box->content_width = box->width;
|
|
190
|
+
box->content_height = box->height;
|
|
191
|
+
box->baseline = box->height;
|
|
192
|
+
return box->height;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
} // namespace layout_flow_detail
|
|
196
|
+
} // namespace xtgui
|
|
@@ -33,7 +33,9 @@ namespace xtgui {
|
|
|
33
33
|
std::unique_ptr<MediaPlayer> MediaPlayer::open(const std::string& path, std::string* error,
|
|
34
34
|
std::unique_ptr<AudioSink> audio) {
|
|
35
35
|
if (g_api == nullptr || g_api->open == nullptr) {
|
|
36
|
-
if (error)
|
|
36
|
+
if (error) {
|
|
37
|
+
*error = "media support was not linked; rebuild with '--feature media' (or make the media use visible to the compiler)";
|
|
38
|
+
}
|
|
37
39
|
return nullptr;
|
|
38
40
|
}
|
|
39
41
|
char message[kErrorSize] = {0};
|
|
@@ -59,7 +61,7 @@ bool xt_media_decode_audio(const uint8_t* data, size_t size, DecodedAudio* out,
|
|
|
59
61
|
std::string* error) {
|
|
60
62
|
if (g_api == nullptr || g_api->decode_audio == nullptr) {
|
|
61
63
|
if (error) {
|
|
62
|
-
*error = "cannot decode this audio format;
|
|
64
|
+
*error = "cannot decode this audio format; rebuild with '--feature media' (the FFmpeg backend was not linked)";
|
|
63
65
|
}
|
|
64
66
|
return false;
|
|
65
67
|
}
|
package/runtime/ext_gui/media.h
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* The engine owns the DOM integration (one `MediaPlayer` per element, owned by
|
|
8
8
|
* the window) and the renderer uploads decoded frames as GPU textures. The
|
|
9
9
|
* decoder itself is optional: `MediaPlayer::open` dispatches through the table
|
|
10
|
-
* the `media`
|
|
11
|
-
*
|
|
10
|
+
* the `media` link feature installs at startup (see `media_api.h`). A program
|
|
11
|
+
* that does not use media therefore links without FFmpeg and reports an `error`
|
|
12
12
|
* event when a media element is opened.
|
|
13
13
|
*
|
|
14
14
|
* A `MediaPlayer` owns one demux/decode pipeline for a single source file. It
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* engine already runs a frame loop, so there is no separate media thread and no
|
|
26
26
|
* interaction with the garbage collector.
|
|
27
27
|
*
|
|
28
|
-
* The FFmpeg headers stay inside the media
|
|
28
|
+
* The FFmpeg headers stay inside the media feature's `media.cpp`; this header
|
|
29
29
|
* only exposes value types so the rest of the engine (and `gui_engine.h`) can
|
|
30
30
|
* hold a player without pulling in libav*.
|
|
31
31
|
*/
|
|
@@ -6,16 +6,17 @@
|
|
|
6
6
|
*
|
|
7
7
|
* The engine knows how to model `<video>`/`<audio>` elements and how to draw
|
|
8
8
|
* their frames, but it deliberately contains no decoder: FFmpeg lives in the
|
|
9
|
-
*
|
|
9
|
+
* optional `media` link feature (`runtime/ext_media/`, linked as
|
|
10
10
|
* `media.a`, or `media.lib` with the MSVC ABI on Windows). Keeping the boundary C-only means the backend can be a prebuilt
|
|
11
11
|
* C++ archive that is compiled independently of the engine.
|
|
12
12
|
*
|
|
13
13
|
* Registration is push-based: the backend's bridge translation unit is linked
|
|
14
|
-
*
|
|
14
|
+
* only when the compiler selects the feature (it is the feature's
|
|
15
|
+
* `runtimeSources()` entry), and a
|
|
15
16
|
* constructor calls `xt_media_install` with its function table. The GUI's
|
|
16
|
-
* dispatch layer (`media.cpp`) starts with a null table, so a program
|
|
17
|
-
*
|
|
18
|
-
* not
|
|
17
|
+
* dispatch layer (`media.cpp`) starts with a null table, so a program that does
|
|
18
|
+
* not use media still links and simply reports that media support was
|
|
19
|
+
* not linked.
|
|
19
20
|
*
|
|
20
21
|
* `audio_sink` is an opaque `xtgui::AudioSink*` owned by the caller until the
|
|
21
22
|
* open call; the backend takes ownership whether the open succeeds or not.
|
|
@@ -72,7 +73,7 @@ void xt_media_install(const XtMediaApi *api);
|
|
|
72
73
|
|
|
73
74
|
/** Decoder backend entry points, implemented by `runtime/ext_media/media.cpp`
|
|
74
75
|
* (inside `media.a`/`media.lib`). The bridge references them, which is what makes the
|
|
75
|
-
* linker extract the archive member when the media
|
|
76
|
+
* linker extract the archive member when the `media` feature is selected. */
|
|
76
77
|
XtMediaPlayerHandle xt_media_backend_open(const char *path, char *error,
|
|
77
78
|
size_t error_size, void *audio_sink);
|
|
78
79
|
XtMediaPlayerHandle xt_media_backend_by_id(uint64_t id);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#include "paint.h"
|
|
10
10
|
|
|
11
11
|
#include <algorithm>
|
|
12
|
+
#include <cmath>
|
|
12
13
|
#include <cstddef>
|
|
13
14
|
#include <cstdio>
|
|
14
15
|
#include <utility>
|
|
@@ -46,6 +47,7 @@ FontSpec specOf(const XtStyle &style) {
|
|
|
46
47
|
spec.pixel_size = style.font_size;
|
|
47
48
|
spec.weight = style.font_weight;
|
|
48
49
|
spec.italic = style.font_style == FontStyle::Italic;
|
|
50
|
+
spec.letter_spacing = style.letter_spacing.unit == Unit::Px ? style.letter_spacing.value : 0.0f;
|
|
49
51
|
return spec;
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -145,11 +147,34 @@ void addTextRuns(const LayoutBox *box, const XtStyle &style, DisplayList &out,
|
|
|
145
147
|
xt_text_metrics(spec, &ascent, nullptr, nullptr);
|
|
146
148
|
if (ascent <= 0.0f) ascent = style.font_size * 0.8f;
|
|
147
149
|
Color base = paint_detail::filterColor(chain, style.color);
|
|
150
|
+
constexpr float kQuarterTurn = 1.57079632679f;
|
|
148
151
|
for (const TextFragment &fragment : box->fragments) {
|
|
149
152
|
if (fragment.text.empty()) continue;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
if (!fragment.vertical) {
|
|
154
|
+
paint_detail::addTextRun(out, fragment.x, fragment.y + ascent, fragment.width,
|
|
155
|
+
fragment.height, fragment.text, spec, base, box->world, clip, style,
|
|
156
|
+
chain, viewportWidth, viewportHeight);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (fragment.upright) {
|
|
160
|
+
/* CJK-style upright glyph centred in its column cell. */
|
|
161
|
+
float glyphWidth = fragment.height;
|
|
162
|
+
float x = fragment.x + (fragment.width - glyphWidth) / 2.0f;
|
|
163
|
+
float baseline = fragment.y + (fragment.height - style.font_size) / 2.0f + ascent;
|
|
164
|
+
paint_detail::addTextRun(out, x, baseline, glyphWidth, fragment.width, fragment.text, spec,
|
|
165
|
+
base, box->world, clip, style, chain, viewportWidth, viewportHeight);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
/* Rotate the horizontal run 90° clockwise about its column's top edge. */
|
|
169
|
+
float pivotX = fragment.x + ascent;
|
|
170
|
+
float pivotY = fragment.y;
|
|
171
|
+
Matrix2D turn = Matrix2D::translate(pivotX, pivotY)
|
|
172
|
+
.multiply(Matrix2D::rotate(kQuarterTurn))
|
|
173
|
+
.multiply(Matrix2D::translate(-pivotX, -pivotY));
|
|
174
|
+
Matrix2D transform = box->world.multiply(turn);
|
|
175
|
+
paint_detail::addTextRun(out, pivotX, pivotY + ascent, fragment.height, fragment.width,
|
|
176
|
+
fragment.text, spec, base, transform, clip, style, chain,
|
|
177
|
+
viewportWidth, viewportHeight);
|
|
153
178
|
}
|
|
154
179
|
}
|
|
155
180
|
|
|
@@ -191,6 +216,13 @@ void paintBoxInner(const LayoutBox *box, DisplayList &out, const PaintClip &clip
|
|
|
191
216
|
/* Drop shadows sit behind the box's own background but above earlier
|
|
192
217
|
* siblings. */
|
|
193
218
|
paint_detail::addBoxDropShadows(out, *box, *style, chain, own);
|
|
219
|
+
/* A backdrop filter samples everything painted before this box, so it is
|
|
220
|
+
* emitted before any of the box's own shapes. */
|
|
221
|
+
paint_detail::addBackdropFilter(out, *box, *style, own, viewportWidth, viewportHeight);
|
|
222
|
+
/* CSS `box-shadow` outsets paint behind the background too; inset ones
|
|
223
|
+
* paint above it. */
|
|
224
|
+
paint_detail::addBoxShadows(out, *box, *style, chain, own, false, viewportWidth,
|
|
225
|
+
viewportHeight);
|
|
194
226
|
paint_detail::paintBackgrounds(out, *box, *style, chain, own, viewportWidth,
|
|
195
227
|
viewportHeight);
|
|
196
228
|
const Matrix2D &matrix = box->world;
|
|
@@ -210,6 +242,9 @@ void paintBoxInner(const LayoutBox *box, DisplayList &out, const PaintClip &clip
|
|
|
210
242
|
paint_detail::addRectFiltered(out, box->x + box->width - right, box->y + top, right,
|
|
211
243
|
inner_height, 0.0f, bc, own, matrix, chain);
|
|
212
244
|
}
|
|
245
|
+
paint_detail::addBoxShadows(out, *box, *style, chain, own, true, viewportWidth,
|
|
246
|
+
viewportHeight);
|
|
247
|
+
paint_detail::addOutline(out, *box, *style, chain, own, viewportWidth, viewportHeight);
|
|
213
248
|
if (box->is_canvas && box->canvas_id != 0 && box->content_width > 0.0f &&
|
|
214
249
|
box->content_height > 0.0f) {
|
|
215
250
|
PaintImage image;
|
|
@@ -361,6 +396,15 @@ std::string DisplayList::dump() const {
|
|
|
361
396
|
text += prefix + "end-layer\n";
|
|
362
397
|
continue;
|
|
363
398
|
}
|
|
399
|
+
if (op.kind == PaintKind::Backdrop) {
|
|
400
|
+
const PaintBackdrop &backdrop = backdrops[op.index];
|
|
401
|
+
std::snprintf(buffer, sizeof(buffer),
|
|
402
|
+
"backdrop x=%.1f y=%.1f w=%.1f h=%.1f r=%.1f blur=%.1f", backdrop.x,
|
|
403
|
+
backdrop.y, backdrop.width, backdrop.height, backdrop.radius,
|
|
404
|
+
backdrop.blur);
|
|
405
|
+
text += prefix + buffer + "\n";
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
364
408
|
std::string suffix;
|
|
365
409
|
if (op.kind == PaintKind::Rect) {
|
|
366
410
|
suffix = transformSuffix(rects[op.index].transform);
|
|
@@ -382,12 +426,22 @@ std::string DisplayList::dump() const {
|
|
|
382
426
|
suffix = transformSuffix(image.transform);
|
|
383
427
|
if (image.gradient != nullptr) {
|
|
384
428
|
const PaintGradient &gradient = *image.gradient;
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
429
|
+
const bool linear = gradient.kind == PaintGradient::Kind::Linear;
|
|
430
|
+
const char *kind = linear ? (gradient.repeating ? "repeating-linear" : "linear")
|
|
431
|
+
: (gradient.repeating ? "repeating-radial" : "radial");
|
|
432
|
+
if (linear) {
|
|
433
|
+
std::snprintf(buffer, sizeof(buffer),
|
|
434
|
+
"image x=%.1f y=%.1f w=%.1f h=%.1f gradient=%s start=%.1f,%.1f "
|
|
435
|
+
"dir=%.4f,%.4f length=%.1f stops=",
|
|
436
|
+
image.x, image.y, image.width, image.height, kind, gradient.start_x,
|
|
437
|
+
gradient.start_y, gradient.dir_x, gradient.dir_y, gradient.length);
|
|
438
|
+
} else {
|
|
439
|
+
std::snprintf(buffer, sizeof(buffer),
|
|
440
|
+
"image x=%.1f y=%.1f w=%.1f h=%.1f gradient=%s center=%.1f,%.1f "
|
|
441
|
+
"radius=%.1f,%.1f stops=",
|
|
442
|
+
image.x, image.y, image.width, image.height, kind, gradient.center_x,
|
|
443
|
+
gradient.center_y, gradient.radius_x, gradient.radius_y);
|
|
444
|
+
}
|
|
391
445
|
text += prefix + buffer;
|
|
392
446
|
for (size_t stop = 0; stop < gradient.stops.size(); stop++) {
|
|
393
447
|
std::snprintf(buffer, sizeof(buffer), "%s%s@%.4f", stop == 0 ? "" : ",",
|
|
@@ -395,6 +449,10 @@ std::string DisplayList::dump() const {
|
|
|
395
449
|
gradient.stops[stop].offset);
|
|
396
450
|
text += buffer;
|
|
397
451
|
}
|
|
452
|
+
} else if (image.bitmap != nullptr) {
|
|
453
|
+
std::snprintf(buffer, sizeof(buffer),
|
|
454
|
+
"image x=%.1f y=%.1f w=%.1f h=%.1f bitmap=%s", image.x, image.y,
|
|
455
|
+
image.width, image.height, image.bitmap->key.c_str());
|
|
398
456
|
} else if (image.media_id != 0) {
|
|
399
457
|
std::snprintf(buffer, sizeof(buffer), "image x=%.1f y=%.1f w=%.1f h=%.1f media=%llu",
|
|
400
458
|
image.x, image.y, image.width, image.height,
|
package/runtime/ext_gui/paint.h
CHANGED
|
@@ -32,22 +32,35 @@ struct GradientStop {
|
|
|
32
32
|
Color color;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
/** A
|
|
35
|
+
/** A `background-image` gradient layer resolved by the paint pass: the renderer
|
|
36
36
|
* rasterises it into one RGBA texture and draws that as a single image quad.
|
|
37
37
|
*
|
|
38
38
|
* Nesting translucent bands instead composites every band's alpha once per band
|
|
39
39
|
* — each band covers the whole interior — so a vignette whose stops fade to
|
|
40
40
|
* `transparent` turns into an opaque disc that hides the scene behind it.
|
|
41
|
-
* Resolving the ramp per pixel composites it exactly once
|
|
41
|
+
* Resolving the ramp per pixel composites it exactly once, and it is the only
|
|
42
|
+
* way to draw a stop narrower than a band: a walk of solid rectangles either
|
|
43
|
+
* swallows a 1px divider line (it falls between two samples) or widens it into
|
|
44
|
+
* a block the width of a band. */
|
|
42
45
|
struct PaintGradient {
|
|
46
|
+
enum class Kind { Radial, Linear };
|
|
47
|
+
Kind kind = Kind::Radial;
|
|
43
48
|
std::vector<GradientStop> stops;
|
|
49
|
+
/* radial: the ending shape, box-local logical pixels. */
|
|
44
50
|
/** Centre in box-local logical pixels; the drawn quad spans the whole box. */
|
|
45
51
|
float center_x = 0.0f;
|
|
46
52
|
float center_y = 0.0f;
|
|
47
53
|
float radius_x = 0.0f;
|
|
48
54
|
float radius_y = 0.0f;
|
|
49
|
-
|
|
50
|
-
* (
|
|
55
|
+
/* linear: `t` grows along the gradient line from `start_*` in the direction
|
|
56
|
+
* `(dir_x, dir_y)` over `length`; both box-local logical pixels. */
|
|
57
|
+
float start_x = 0.0f;
|
|
58
|
+
float start_y = 0.0f;
|
|
59
|
+
float dir_x = 1.0f;
|
|
60
|
+
float dir_y = 0.0f;
|
|
61
|
+
float length = 0.0f;
|
|
62
|
+
/** `repeating-*`: the stop pattern restarts every `period` (the last stop's
|
|
63
|
+
* offset) instead of clamping at the last stop. */
|
|
51
64
|
bool repeating = false;
|
|
52
65
|
float period = 1.0f;
|
|
53
66
|
/** Identity of the ramp (stops and geometry) for the renderer's texture cache. */
|
|
@@ -81,6 +94,22 @@ struct PaintText {
|
|
|
81
94
|
bool shadow = false;
|
|
82
95
|
};
|
|
83
96
|
|
|
97
|
+
/** A CPU-rasterised RGBA bitmap carried by a display-list image op. Shadows are
|
|
98
|
+
* painted as one pre-blurred texture rather than a stack of offset copies: a
|
|
99
|
+
* separable Gaussian on the mask is the CSS blur, and the shader only has to
|
|
100
|
+
* composite one quad. `scale` is bitmap pixels per logical pixel. */
|
|
101
|
+
struct PaintBitmap {
|
|
102
|
+
int width = 0;
|
|
103
|
+
int height = 0;
|
|
104
|
+
float scale = 1.0f;
|
|
105
|
+
/** Logical offset of the bitmap's top-left from the shape's origin (a text
|
|
106
|
+
* run's start/baseline, or a box's top-left). */
|
|
107
|
+
float origin_x = 0.0f;
|
|
108
|
+
float origin_y = 0.0f;
|
|
109
|
+
std::string key;
|
|
110
|
+
std::vector<unsigned char> pixels;
|
|
111
|
+
};
|
|
112
|
+
|
|
84
113
|
/** An image to draw, scaled into the given rectangle (viewport-relative).
|
|
85
114
|
* A non-zero `media_id` names a live `<video>` frame owned by the media
|
|
86
115
|
* subsystem; a non-zero `canvas_id` names a live `<canvas>` bitmap owned by the
|
|
@@ -101,9 +130,13 @@ struct PaintImage {
|
|
|
101
130
|
/** Modulating colour for the image shader (white normally; a filter's
|
|
102
131
|
* multiplicative effect may tint it). */
|
|
103
132
|
Color tint{1.0f, 1.0f, 1.0f, 1.0f};
|
|
104
|
-
/** A
|
|
105
|
-
*
|
|
106
|
-
|
|
133
|
+
/** A CPU-rasterised shadow mask (white RGB, coverage in alpha) drawn with
|
|
134
|
+
* `tint` as its colour. */
|
|
135
|
+
std::shared_ptr<const PaintBitmap> bitmap;
|
|
136
|
+
/** A `background-image` gradient (linear or radial): the renderer rasterises
|
|
137
|
+
* it into the quad instead of loading `src`/`svg`. Its stops already carry the
|
|
138
|
+
* colour functions of the filter chain; `tint` still carries
|
|
139
|
+
* brightness/opacity. */
|
|
107
140
|
std::shared_ptr<const PaintGradient> gradient;
|
|
108
141
|
};
|
|
109
142
|
|
|
@@ -136,7 +169,7 @@ struct PaintClip {
|
|
|
136
169
|
int paths[2] = {-1, -1};
|
|
137
170
|
};
|
|
138
171
|
|
|
139
|
-
enum class PaintKind { Rect, Text, Image, LayerBegin, LayerEnd };
|
|
172
|
+
enum class PaintKind { Rect, Text, Image, LayerBegin, LayerEnd, Backdrop };
|
|
140
173
|
|
|
141
174
|
/** One `mix-blend-mode` compositing group. The ops between its `LayerBegin`
|
|
142
175
|
* and `LayerEnd` markers are rendered to an offscreen texture and composited
|
|
@@ -145,6 +178,23 @@ struct PaintLayer {
|
|
|
145
178
|
MixBlendMode blend = MixBlendMode::Normal;
|
|
146
179
|
};
|
|
147
180
|
|
|
181
|
+
/** One `backdrop-filter` application: the renderer snapshots the scene painted
|
|
182
|
+
* so far, applies the Gaussian blur / colour matrix to it, and composites the
|
|
183
|
+
* result back only inside the element's rounded border box. */
|
|
184
|
+
struct PaintBackdrop {
|
|
185
|
+
float x = 0;
|
|
186
|
+
float y = 0;
|
|
187
|
+
float width = 0;
|
|
188
|
+
float height = 0;
|
|
189
|
+
float radius = 0;
|
|
190
|
+
/** Standard deviation of the Gaussian in logical pixels (0 = no blur). */
|
|
191
|
+
float blur = 0;
|
|
192
|
+
/** Combined colour filter, row-major 3x3 plus a per-channel offset. */
|
|
193
|
+
float color[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
|
194
|
+
float offset[3] = {0, 0, 0};
|
|
195
|
+
float alpha = 1;
|
|
196
|
+
};
|
|
197
|
+
|
|
148
198
|
/** One entry in painter order: which kind of shape, its index in the matching
|
|
149
199
|
* payload vector, and the clip in effect. */
|
|
150
200
|
struct PaintOp {
|
|
@@ -164,6 +214,8 @@ struct DisplayList {
|
|
|
164
214
|
std::vector<ClipPathGeometry> clip_paths;
|
|
165
215
|
/** `mix-blend-mode` groups referenced by `LayerBegin` ops. */
|
|
166
216
|
std::vector<PaintLayer> layers;
|
|
217
|
+
/** `backdrop-filter` regions referenced by `Backdrop` ops. */
|
|
218
|
+
std::vector<PaintBackdrop> backdrops;
|
|
167
219
|
|
|
168
220
|
void clear() {
|
|
169
221
|
rects.clear();
|
|
@@ -172,6 +224,7 @@ struct DisplayList {
|
|
|
172
224
|
ops.clear();
|
|
173
225
|
clip_paths.clear();
|
|
174
226
|
layers.clear();
|
|
227
|
+
backdrops.clear();
|
|
175
228
|
}
|
|
176
229
|
bool empty() const { return rects.empty() && texts.empty() && images.empty(); }
|
|
177
230
|
/** Human-readable dump, one shape per line, in painter order (diagnostics/tests). */
|