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,211 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — CSS `backdrop-filter`.
|
|
3
|
+
*
|
|
4
|
+
* The backdrop is whatever has already been painted behind the element, which
|
|
5
|
+
* only the renderer can see. Paint therefore resolves the filter list into the
|
|
6
|
+
* two things the compositor needs: a Gaussian sigma and one combined 3x3 colour
|
|
7
|
+
* matrix. The renderer snapshots the scene, applies both in a full-screen
|
|
8
|
+
* shader, and composites the result back inside the element's rounded border
|
|
9
|
+
* box (see `renderer_layer.cpp`).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#include "paint_internal.h"
|
|
13
|
+
|
|
14
|
+
#include <algorithm>
|
|
15
|
+
#include <cmath>
|
|
16
|
+
|
|
17
|
+
namespace xtgui {
|
|
18
|
+
namespace paint_detail {
|
|
19
|
+
|
|
20
|
+
namespace {
|
|
21
|
+
|
|
22
|
+
struct ColorMatrix {
|
|
23
|
+
float m[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
|
24
|
+
float offset[3] = {0, 0, 0};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** `out = left * right` for row-major 3x3 matrices. */
|
|
28
|
+
ColorMatrix multiply(const ColorMatrix &left, const ColorMatrix &right) {
|
|
29
|
+
ColorMatrix result;
|
|
30
|
+
for (int row = 0; row < 3; row++) {
|
|
31
|
+
for (int column = 0; column < 3; column++) {
|
|
32
|
+
float sum = 0.0f;
|
|
33
|
+
for (int k = 0; k < 3; k++) sum += left.m[row * 3 + k] * right.m[k * 3 + column];
|
|
34
|
+
result.m[row * 3 + column] = sum;
|
|
35
|
+
}
|
|
36
|
+
result.offset[row] = left.m[row * 3] * right.offset[0] +
|
|
37
|
+
left.m[row * 3 + 1] * right.offset[1] +
|
|
38
|
+
left.m[row * 3 + 2] * right.offset[2] + left.offset[row];
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
ColorMatrix identity() { return ColorMatrix(); }
|
|
44
|
+
|
|
45
|
+
ColorMatrix brightness(float amount) {
|
|
46
|
+
ColorMatrix matrix;
|
|
47
|
+
matrix.m[0] = matrix.m[4] = matrix.m[8] = amount;
|
|
48
|
+
return matrix;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
ColorMatrix contrast(float amount) {
|
|
52
|
+
ColorMatrix matrix = brightness(amount);
|
|
53
|
+
float shift = 0.5f - 0.5f * amount;
|
|
54
|
+
matrix.offset[0] = matrix.offset[1] = matrix.offset[2] = shift;
|
|
55
|
+
return matrix;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ColorMatrix invert(float amount) {
|
|
59
|
+
ColorMatrix matrix;
|
|
60
|
+
float scale = 1.0f - 2.0f * amount;
|
|
61
|
+
matrix.m[0] = matrix.m[4] = matrix.m[8] = scale;
|
|
62
|
+
matrix.offset[0] = matrix.offset[1] = matrix.offset[2] = amount;
|
|
63
|
+
return matrix;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
ColorMatrix grayscale(float amount) {
|
|
67
|
+
const float lr = 0.2126f, lg = 0.7152f, lb = 0.0722f;
|
|
68
|
+
ColorMatrix matrix;
|
|
69
|
+
matrix.m[0] = 1.0f - amount + amount * lr;
|
|
70
|
+
matrix.m[1] = amount * lg;
|
|
71
|
+
matrix.m[2] = amount * lb;
|
|
72
|
+
matrix.m[3] = amount * lr;
|
|
73
|
+
matrix.m[4] = 1.0f - amount + amount * lg;
|
|
74
|
+
matrix.m[5] = amount * lb;
|
|
75
|
+
matrix.m[6] = amount * lr;
|
|
76
|
+
matrix.m[7] = amount * lg;
|
|
77
|
+
matrix.m[8] = 1.0f - amount + amount * lb;
|
|
78
|
+
return matrix;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ColorMatrix sepia(float amount) {
|
|
82
|
+
const float base[9] = {0.393f, 0.769f, 0.189f, 0.349f, 0.686f,
|
|
83
|
+
0.168f, 0.272f, 0.534f, 0.131f};
|
|
84
|
+
ColorMatrix matrix;
|
|
85
|
+
for (int i = 0; i < 9; i++) matrix.m[i] = (1.0f - amount) * (i % 4 == 0 ? 1.0f : 0.0f) +
|
|
86
|
+
amount * base[i];
|
|
87
|
+
return matrix;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
ColorMatrix saturate(float amount) {
|
|
91
|
+
const float lr = 0.213f, lg = 0.715f, lb = 0.072f;
|
|
92
|
+
ColorMatrix matrix;
|
|
93
|
+
matrix.m[0] = lr + (1.0f - lr) * amount;
|
|
94
|
+
matrix.m[1] = lg - lg * amount;
|
|
95
|
+
matrix.m[2] = lb - lb * amount;
|
|
96
|
+
matrix.m[3] = lr - lr * amount;
|
|
97
|
+
matrix.m[4] = lg + (1.0f - lg) * amount;
|
|
98
|
+
matrix.m[5] = lb - lb * amount;
|
|
99
|
+
matrix.m[6] = lr - lr * amount;
|
|
100
|
+
matrix.m[7] = lg - lg * amount;
|
|
101
|
+
matrix.m[8] = lb + (1.0f - lb) * amount;
|
|
102
|
+
return matrix;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
ColorMatrix hueRotate(float degrees) {
|
|
106
|
+
float radians = degrees * 3.14159265358979323846f / 180.0f;
|
|
107
|
+
float c = std::cos(radians);
|
|
108
|
+
float s = std::sin(radians);
|
|
109
|
+
ColorMatrix matrix;
|
|
110
|
+
matrix.m[0] = 0.213f + c * 0.787f - s * 0.213f;
|
|
111
|
+
matrix.m[1] = 0.715f - c * 0.715f - s * 0.715f;
|
|
112
|
+
matrix.m[2] = 0.072f - c * 0.072f + s * 0.928f;
|
|
113
|
+
matrix.m[3] = 0.213f - c * 0.213f + s * 0.143f;
|
|
114
|
+
matrix.m[4] = 0.715f + c * 0.285f + s * 0.140f;
|
|
115
|
+
matrix.m[5] = 0.072f - c * 0.072f - s * 0.283f;
|
|
116
|
+
matrix.m[6] = 0.213f - c * 0.213f - s * 0.787f;
|
|
117
|
+
matrix.m[7] = 0.715f - c * 0.715f + s * 0.715f;
|
|
118
|
+
matrix.m[8] = 0.072f + c * 0.928f + s * 0.072f;
|
|
119
|
+
return matrix;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Combine the filter list in application order: the first function applies to
|
|
123
|
+
* the backdrop first, so each new matrix multiplies the accumulated one on the
|
|
124
|
+
* left. Drop shadows are a silhouette effect that the colour matrix cannot
|
|
125
|
+
* express; they are ignored rather than misapplied. */
|
|
126
|
+
void compileFilters(const std::vector<FilterOp> &filters, const XtStyle &style,
|
|
127
|
+
float viewportWidth, float viewportHeight, ColorMatrix *matrix, float *blur,
|
|
128
|
+
float *alpha) {
|
|
129
|
+
*matrix = identity();
|
|
130
|
+
*blur = 0.0f;
|
|
131
|
+
*alpha = 1.0f;
|
|
132
|
+
for (const FilterOp &filter : filters) {
|
|
133
|
+
switch (filter.kind) {
|
|
134
|
+
case FilterKind::Blur:
|
|
135
|
+
*blur += resolveLength(filter.blur, 0.0f, style.font_size, viewportWidth, viewportHeight);
|
|
136
|
+
break;
|
|
137
|
+
case FilterKind::Brightness:
|
|
138
|
+
*matrix = multiply(brightness(filter.amount), *matrix);
|
|
139
|
+
break;
|
|
140
|
+
case FilterKind::Contrast:
|
|
141
|
+
*matrix = multiply(contrast(filter.amount), *matrix);
|
|
142
|
+
break;
|
|
143
|
+
case FilterKind::Grayscale:
|
|
144
|
+
*matrix = multiply(grayscale(filter.amount), *matrix);
|
|
145
|
+
break;
|
|
146
|
+
case FilterKind::Sepia:
|
|
147
|
+
*matrix = multiply(sepia(filter.amount), *matrix);
|
|
148
|
+
break;
|
|
149
|
+
case FilterKind::Invert:
|
|
150
|
+
*matrix = multiply(invert(filter.amount), *matrix);
|
|
151
|
+
break;
|
|
152
|
+
case FilterKind::Saturate:
|
|
153
|
+
*matrix = multiply(saturate(filter.amount), *matrix);
|
|
154
|
+
break;
|
|
155
|
+
case FilterKind::HueRotate:
|
|
156
|
+
*matrix = multiply(hueRotate(filter.amount), *matrix);
|
|
157
|
+
break;
|
|
158
|
+
case FilterKind::Opacity:
|
|
159
|
+
*alpha *= filter.amount;
|
|
160
|
+
break;
|
|
161
|
+
case FilterKind::DropShadow:
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
} // namespace
|
|
168
|
+
|
|
169
|
+
bool addBackdropFilter(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
170
|
+
const PaintClip &clip, float viewportWidth, float viewportHeight) {
|
|
171
|
+
if (style.backdrop_filters.empty()) return false;
|
|
172
|
+
ColorMatrix matrix;
|
|
173
|
+
float blur = 0.0f;
|
|
174
|
+
float alpha = 1.0f;
|
|
175
|
+
compileFilters(style.backdrop_filters, style, viewportWidth, viewportHeight, &matrix, &blur,
|
|
176
|
+
&alpha);
|
|
177
|
+
if (blur <= 0.0f && alpha >= 1.0f && matrix.m[0] == 1.0f && matrix.m[1] == 0.0f &&
|
|
178
|
+
matrix.m[2] == 0.0f && matrix.m[3] == 0.0f && matrix.m[4] == 1.0f &&
|
|
179
|
+
matrix.m[5] == 0.0f && matrix.m[6] == 0.0f && matrix.m[7] == 0.0f &&
|
|
180
|
+
matrix.m[8] == 1.0f) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
PaintBackdrop backdrop;
|
|
184
|
+
float x = box.x;
|
|
185
|
+
float y = box.y;
|
|
186
|
+
float width = box.width;
|
|
187
|
+
float height = box.height;
|
|
188
|
+
backdrop.radius = box.border_radius;
|
|
189
|
+
if (box.has_transform) {
|
|
190
|
+
LayoutRect bounds = xt_layout_transform_rect(box.world, x, y, width, height);
|
|
191
|
+
x = bounds.x;
|
|
192
|
+
y = bounds.y;
|
|
193
|
+
width = bounds.width;
|
|
194
|
+
height = bounds.height;
|
|
195
|
+
}
|
|
196
|
+
backdrop.x = x;
|
|
197
|
+
backdrop.y = y;
|
|
198
|
+
backdrop.width = width;
|
|
199
|
+
backdrop.height = height;
|
|
200
|
+
backdrop.blur = blur;
|
|
201
|
+
backdrop.alpha = alpha;
|
|
202
|
+
for (int i = 0; i < 9; i++) backdrop.color[i] = matrix.m[i];
|
|
203
|
+
for (int i = 0; i < 3; i++) backdrop.offset[i] = matrix.offset[i];
|
|
204
|
+
out.backdrops.push_back(backdrop);
|
|
205
|
+
out.ops.push_back(
|
|
206
|
+
PaintOp{PaintKind::Backdrop, (uint32_t)(out.backdrops.size() - 1), clip});
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
} // namespace paint_detail
|
|
211
|
+
} // namespace xtgui
|
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
* xbintsc GUI engine — background layer painting.
|
|
3
3
|
*
|
|
4
4
|
* `background-color` is one rounded rectangle and a `background-image` layer is
|
|
5
|
-
* a gradient or an image.
|
|
6
|
-
* (18 strips, 64 while repeating). A radial gradient is emitted as a single
|
|
5
|
+
* a gradient or an image. Both gradient kinds are emitted as a single
|
|
7
6
|
* `PaintGradient` that the renderer rasterises per pixel
|
|
8
|
-
* (`renderer_gradient.cpp`)
|
|
7
|
+
* (`renderer_gradient.cpp`). Stacking translucent bands instead composites their
|
|
9
8
|
* alpha once per band, which turns a vignette whose stops fade to `transparent`
|
|
10
|
-
* into an opaque disc
|
|
9
|
+
* into an opaque disc, and a run of bands cannot draw a stop narrower than one
|
|
10
|
+
* band: a 1px divider line either falls between two samples or becomes a block.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
#include "paint_internal.h"
|
|
14
14
|
|
|
15
15
|
#include <algorithm>
|
|
16
16
|
#include <cmath>
|
|
17
|
+
#include <cstddef>
|
|
17
18
|
#include <cstdio>
|
|
19
|
+
#include <limits>
|
|
18
20
|
#include <memory>
|
|
19
21
|
#include <string>
|
|
20
22
|
#include <vector>
|
|
@@ -69,23 +71,31 @@ Color gradientColorAt(const std::vector<GradientStop> &stops, bool repeating, fl
|
|
|
69
71
|
namespace {
|
|
70
72
|
|
|
71
73
|
/** Resolve the declaration's percentage/length offsets against the gradient
|
|
72
|
-
* line, then distribute the omitted
|
|
73
|
-
*
|
|
74
|
-
*
|
|
74
|
+
* line, then distribute the omitted ones between their neighbours. The last
|
|
75
|
+
* explicit stop is preserved: for a normal gradient it holds that colour, and
|
|
76
|
+
* for a repeating one it defines the period. */
|
|
75
77
|
std::vector<GradientStop> resolveStops(const BackgroundLayer &layer, float line_length,
|
|
76
78
|
const XtStyle &style, float viewportWidth,
|
|
77
79
|
float viewportHeight) {
|
|
78
80
|
std::vector<GradientStop> stops;
|
|
81
|
+
stops.reserve(layer.stops.size());
|
|
79
82
|
for (const BackgroundGradientStop &stop : layer.stops) {
|
|
80
83
|
GradientStop resolved;
|
|
81
84
|
resolved.color = stop.color;
|
|
82
|
-
resolved
|
|
85
|
+
/* NaN means "this stop has no offset"; a resolved offset may legitimately be
|
|
86
|
+
* negative (`red -10%`, or a `calc()` that lands below the line's start), so
|
|
87
|
+
* it must not double as the "unset" marker — that turned a negative offset
|
|
88
|
+
* into an implicit one and re-spaced the whole ramp. */
|
|
89
|
+
resolved.offset = std::numeric_limits<float>::quiet_NaN();
|
|
83
90
|
if (stop.offset.unit == Unit::Percent) {
|
|
84
91
|
resolved.offset = stop.offset.value / 100.0f;
|
|
85
92
|
} else if (stop.offset.unit != Unit::Auto && stop.offset.unit != Unit::Invalid &&
|
|
86
93
|
stop.offset.unit != Unit::None) {
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
/* A percentage inside `calc()` is relative to the gradient line, exactly
|
|
95
|
+
* like a bare percentage; resolving it against a zero base made
|
|
96
|
+
* `calc(10% - 1px)` come out as `-1px`. */
|
|
97
|
+
float pixels =
|
|
98
|
+
resolveLength(stop.offset, line_length, style.font_size, viewportWidth, viewportHeight);
|
|
89
99
|
resolved.offset = line_length > 0.00001f ? pixels / line_length : 0.0f;
|
|
90
100
|
}
|
|
91
101
|
stops.push_back(resolved);
|
|
@@ -93,24 +103,27 @@ std::vector<GradientStop> resolveStops(const BackgroundLayer &layer, float line_
|
|
|
93
103
|
if (stops.empty()) return stops;
|
|
94
104
|
|
|
95
105
|
/* Explicit offsets are non-decreasing, as in CSS. */
|
|
96
|
-
|
|
106
|
+
bool have_previous = false;
|
|
107
|
+
float previous = 0.0f;
|
|
97
108
|
for (GradientStop &stop : stops) {
|
|
98
|
-
if (stop.offset
|
|
99
|
-
if (stop.offset <
|
|
100
|
-
|
|
109
|
+
if (std::isnan(stop.offset)) continue;
|
|
110
|
+
if (have_previous && stop.offset < previous) stop.offset = previous;
|
|
111
|
+
previous = stop.offset;
|
|
112
|
+
have_previous = true;
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
/* Fill implicit offsets by distributing them between their neighbours. */
|
|
104
116
|
size_t i = 0;
|
|
105
117
|
while (i < stops.size()) {
|
|
106
|
-
if (stops[i].offset
|
|
118
|
+
if (!std::isnan(stops[i].offset)) {
|
|
107
119
|
i++;
|
|
108
120
|
continue;
|
|
109
121
|
}
|
|
110
122
|
size_t j = i;
|
|
111
|
-
while (j < stops.size() && stops[j].offset
|
|
123
|
+
while (j < stops.size() && std::isnan(stops[j].offset)) j++;
|
|
112
124
|
float before = (i == 0) ? 0.0f : stops[i - 1].offset;
|
|
113
125
|
float after = (j >= stops.size()) ? 1.0f : stops[j].offset;
|
|
126
|
+
if (after < before) after = before;
|
|
114
127
|
size_t count = j - i;
|
|
115
128
|
for (size_t k = 0; k < count; k++) {
|
|
116
129
|
float offset = 0.0f;
|
|
@@ -164,35 +177,108 @@ PaintClip boxClip(const PaintClip &clip, const LayoutBox &box) {
|
|
|
164
177
|
return out;
|
|
165
178
|
}
|
|
166
179
|
|
|
180
|
+
/** Stable identity of a rasterised gradient: the ramp plus its geometry. The
|
|
181
|
+
* renderer keys its texture cache by this string, so an unchanged declaration
|
|
182
|
+
* rasterises once. */
|
|
183
|
+
std::string gradientKey(const PaintGradient &gradient) {
|
|
184
|
+
char buffer[192];
|
|
185
|
+
std::string key;
|
|
186
|
+
for (const GradientStop &stop : gradient.stops) {
|
|
187
|
+
std::snprintf(buffer, sizeof(buffer), "%.4f/%.5f,%.5f,%.5f,%.5f;", stop.offset, stop.color.r,
|
|
188
|
+
stop.color.g, stop.color.b, stop.color.a);
|
|
189
|
+
key += buffer;
|
|
190
|
+
}
|
|
191
|
+
std::snprintf(buffer, sizeof(buffer), "%d;%.3f,%.3f,%.3f,%.3f;%.3f,%.3f,%.4f,%.4f,%.3f;%d;%.5f",
|
|
192
|
+
gradient.kind == PaintGradient::Kind::Linear ? 1 : 0, gradient.center_x,
|
|
193
|
+
gradient.center_y, gradient.radius_x, gradient.radius_y, gradient.start_x,
|
|
194
|
+
gradient.start_y, gradient.dir_x, gradient.dir_y, gradient.length,
|
|
195
|
+
gradient.repeating ? 1 : 0, gradient.period);
|
|
196
|
+
key += buffer;
|
|
197
|
+
return key;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** The CSS gradient line of `layer` inside `box`: the box-local point where the
|
|
201
|
+
* ramp starts, the direction increasing offsets run in, and the line's length.
|
|
202
|
+
* CSS angles grow clockwise from "to top" and y grows downwards, hence the
|
|
203
|
+
* negated cosine. The line passes through the box centre and its length is the
|
|
204
|
+
* box's extent projected onto the direction, so `t` spans exactly 0..1 across
|
|
205
|
+
* the box and `%` offsets in `calc()` resolve against it. */
|
|
206
|
+
void linearLine(const LayoutBox &box, float angle, float *start_x, float *start_y, float *dir_x,
|
|
207
|
+
float *dir_y, float *length) {
|
|
208
|
+
const float radians = angle * 3.14159265358979f / 180.0f;
|
|
209
|
+
const float dx = std::sin(radians);
|
|
210
|
+
const float dy = -std::cos(radians);
|
|
211
|
+
const float span = std::fabs(box.width * dx) + std::fabs(box.height * dy);
|
|
212
|
+
*dir_x = dx;
|
|
213
|
+
*dir_y = dy;
|
|
214
|
+
*length = span;
|
|
215
|
+
*start_x = box.width * 0.5f - dx * span * 0.5f;
|
|
216
|
+
*start_y = box.height * 0.5f - dy * span * 0.5f;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Fold the colour half of the filter chain into `stops` and emit the layer as
|
|
220
|
+
* one gradient image. `brightness()` and `opacity()` stay out of the stops: the
|
|
221
|
+
* image tint carries them exactly, and leaving them out keeps the ramp — and
|
|
222
|
+
* therefore the texture cache key — stable while a fade animates. */
|
|
223
|
+
void emitGradient(const LayoutBox &box, const FilterChain &chain, const PaintClip &clip,
|
|
224
|
+
const std::shared_ptr<PaintGradient> &gradient,
|
|
225
|
+
const std::vector<GradientStop> &stops, DisplayList &out) {
|
|
226
|
+
FilterChain stopChain = chain;
|
|
227
|
+
stopChain.opacity = 1.0f;
|
|
228
|
+
for (size_t i = stopChain.ops.size(); i-- > 0;) {
|
|
229
|
+
FilterKind kind = stopChain.ops[i].kind;
|
|
230
|
+
if (kind == FilterKind::Brightness || kind == FilterKind::Opacity) {
|
|
231
|
+
stopChain.ops.erase(stopChain.ops.begin() + (std::ptrdiff_t)i);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
gradient->stops.reserve(stops.size());
|
|
235
|
+
bool visible = false;
|
|
236
|
+
for (const GradientStop &stop : stops) {
|
|
237
|
+
GradientStop resolved = stop;
|
|
238
|
+
resolved.color = filterColor(stopChain, resolved.color);
|
|
239
|
+
visible = visible || resolved.color.a > 0.0f;
|
|
240
|
+
gradient->stops.push_back(resolved);
|
|
241
|
+
}
|
|
242
|
+
if (!visible) return;
|
|
243
|
+
gradient->key = gradientKey(*gradient);
|
|
244
|
+
|
|
245
|
+
/* One quad for the whole layer: the renderer resolves the ramp per pixel, so
|
|
246
|
+
* the layer composites exactly once instead of once per translucent band, and
|
|
247
|
+
* a stop narrower than a band keeps its exact position and width. */
|
|
248
|
+
PaintImage image;
|
|
249
|
+
image.x = box.x;
|
|
250
|
+
image.y = box.y;
|
|
251
|
+
image.width = box.width;
|
|
252
|
+
image.height = box.height;
|
|
253
|
+
image.transform = box.world;
|
|
254
|
+
image.gradient = gradient;
|
|
255
|
+
addImage(out, std::move(image), clip, chain);
|
|
256
|
+
}
|
|
257
|
+
|
|
167
258
|
void paintLinear(const LayoutBox &box, const XtStyle &style, const BackgroundLayer &layer,
|
|
168
259
|
const FilterChain &chain, const PaintClip &clip, float viewportWidth,
|
|
169
260
|
float viewportHeight, DisplayList &out) {
|
|
170
261
|
if (layer.stops.size() < 2 || box.width <= 0.0f || box.height <= 0.0f) return;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
viewportHeight);
|
|
262
|
+
float start_x = 0.0f;
|
|
263
|
+
float start_y = 0.0f;
|
|
264
|
+
float dir_x = 1.0f;
|
|
265
|
+
float dir_y = 0.0f;
|
|
266
|
+
float length = 0.0f;
|
|
267
|
+
linearLine(box, layer.angle, &start_x, &start_y, &dir_x, &dir_y, &length);
|
|
268
|
+
if (length <= 0.00001f) return;
|
|
269
|
+
std::vector<GradientStop> stops =
|
|
270
|
+
resolveStops(layer, length, style, viewportWidth, viewportHeight);
|
|
181
271
|
if (stops.size() < 2) return;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
addRect(out, box.x, box.y + box.height * (float)i / (float)strips, box.width,
|
|
193
|
-
box.height / (float)strips + 0.4f, 0.0f, color, clip, box.world);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
272
|
+
auto gradient = std::make_shared<PaintGradient>();
|
|
273
|
+
gradient->kind = PaintGradient::Kind::Linear;
|
|
274
|
+
gradient->start_x = start_x;
|
|
275
|
+
gradient->start_y = start_y;
|
|
276
|
+
gradient->dir_x = dir_x;
|
|
277
|
+
gradient->dir_y = dir_y;
|
|
278
|
+
gradient->length = length;
|
|
279
|
+
gradient->repeating = layer.repeating;
|
|
280
|
+
gradient->period = stops.back().offset;
|
|
281
|
+
emitGradient(box, chain, clip, gradient, stops, out);
|
|
196
282
|
}
|
|
197
283
|
|
|
198
284
|
/** Radii of a keyword-sized ellipse: it keeps the box's aspect ratio and is
|
|
@@ -283,24 +369,6 @@ void radialRadii(const LayoutBox &box, const BackgroundLayer &layer, const XtSty
|
|
|
283
369
|
*cy = centerY;
|
|
284
370
|
}
|
|
285
371
|
|
|
286
|
-
/** Stable identity of a rasterised gradient: the ramp plus its geometry. The
|
|
287
|
-
* renderer keys its texture cache by this string, so an unchanged declaration
|
|
288
|
-
* rasterises once. */
|
|
289
|
-
std::string gradientKey(const PaintGradient &gradient) {
|
|
290
|
-
char buffer[192];
|
|
291
|
-
std::string key;
|
|
292
|
-
for (const GradientStop &stop : gradient.stops) {
|
|
293
|
-
std::snprintf(buffer, sizeof(buffer), "%.4f/%.5f,%.5f,%.5f,%.5f;", stop.offset, stop.color.r,
|
|
294
|
-
stop.color.g, stop.color.b, stop.color.a);
|
|
295
|
-
key += buffer;
|
|
296
|
-
}
|
|
297
|
-
std::snprintf(buffer, sizeof(buffer), "%.3f,%.3f,%.3f,%.3f;%d;%.5f", gradient.center_x,
|
|
298
|
-
gradient.center_y, gradient.radius_x, gradient.radius_y,
|
|
299
|
-
gradient.repeating ? 1 : 0, gradient.period);
|
|
300
|
-
key += buffer;
|
|
301
|
-
return key;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
372
|
void paintRadial(const LayoutBox &box, const XtStyle &style, const BackgroundLayer &layer,
|
|
305
373
|
const FilterChain &chain, const PaintClip &clip, float viewportWidth,
|
|
306
374
|
float viewportHeight, DisplayList &out) {
|
|
@@ -314,53 +382,63 @@ void paintRadial(const LayoutBox &box, const XtStyle &style, const BackgroundLay
|
|
|
314
382
|
std::vector<GradientStop> stops = resolveStops(layer, std::max(rx, ry), style, viewportWidth,
|
|
315
383
|
viewportHeight);
|
|
316
384
|
if (stops.size() < 2) return;
|
|
317
|
-
/* The colour functions fold into the stops (a per-stop application is exact
|
|
318
|
-
* for the linear ones); `brightness()` and `opacity()` stay out, because the
|
|
319
|
-
* image tint carries them exactly and leaving them out keeps the ramp — and
|
|
320
|
-
* therefore the texture cache key — stable while a fade animates. */
|
|
321
|
-
FilterChain stopChain = chain;
|
|
322
|
-
stopChain.opacity = 1.0f;
|
|
323
|
-
for (size_t i = stopChain.ops.size(); i-- > 0;) {
|
|
324
|
-
FilterKind kind = stopChain.ops[i].kind;
|
|
325
|
-
if (kind == FilterKind::Brightness || kind == FilterKind::Opacity) {
|
|
326
|
-
stopChain.ops.erase(stopChain.ops.begin() + (ptrdiff_t)i);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
385
|
auto gradient = std::make_shared<PaintGradient>();
|
|
330
|
-
gradient->
|
|
331
|
-
bool visible = false;
|
|
332
|
-
for (size_t i = 0; i < stops.size(); i++) {
|
|
333
|
-
GradientStop resolved = stops[i];
|
|
334
|
-
resolved.color = filterColor(stopChain, resolved.color);
|
|
335
|
-
visible = visible || resolved.color.a > 0.0f;
|
|
336
|
-
gradient->stops.push_back(resolved);
|
|
337
|
-
}
|
|
338
|
-
if (!visible) return;
|
|
386
|
+
gradient->kind = PaintGradient::Kind::Radial;
|
|
339
387
|
gradient->center_x = cx - box.x;
|
|
340
388
|
gradient->center_y = cy - box.y;
|
|
341
389
|
gradient->radius_x = rx;
|
|
342
390
|
gradient->radius_y = ry;
|
|
343
391
|
gradient->repeating = layer.repeating;
|
|
344
392
|
gradient->period = stops.back().offset;
|
|
345
|
-
gradient
|
|
346
|
-
|
|
347
|
-
/* One quad for the whole layer: the renderer resolves the ramp per pixel, so
|
|
348
|
-
* the layer composites exactly once instead of once per translucent band. */
|
|
349
|
-
PaintImage image;
|
|
350
|
-
image.x = box.x;
|
|
351
|
-
image.y = box.y;
|
|
352
|
-
image.width = box.width;
|
|
353
|
-
image.height = box.height;
|
|
354
|
-
image.transform = box.world;
|
|
355
|
-
image.gradient = gradient;
|
|
356
|
-
addImage(out, std::move(image), clip, chain);
|
|
393
|
+
emitGradient(box, chain, clip, gradient, stops, out);
|
|
357
394
|
}
|
|
358
395
|
|
|
359
|
-
void paintImage(const LayoutBox &box, const BackgroundLayer &layer, const
|
|
360
|
-
const PaintClip &clip, DisplayList &out
|
|
396
|
+
void paintImage(const LayoutBox &box, const BackgroundLayer &layer, const XtStyle &style,
|
|
397
|
+
size_t index, const FilterChain &chain, const PaintClip &clip, DisplayList &out,
|
|
398
|
+
float viewportWidth, float viewportHeight) {
|
|
361
399
|
if (layer.image_src.empty() || box.width <= 0.0f || box.height <= 0.0f) return;
|
|
362
|
-
|
|
363
|
-
|
|
400
|
+
const BackgroundSize *size =
|
|
401
|
+
index < style.background_sizes.size() ? &style.background_sizes[index] : nullptr;
|
|
402
|
+
if (size != nullptr) {
|
|
403
|
+
bool width_auto = size->width.unit == Unit::Auto || size->width.unit == Unit::Invalid ||
|
|
404
|
+
size->width.unit == Unit::None;
|
|
405
|
+
bool height_auto = size->height.unit == Unit::Auto || size->height.unit == Unit::Invalid ||
|
|
406
|
+
size->height.unit == Unit::None;
|
|
407
|
+
float tile_width =
|
|
408
|
+
width_auto ? box.width
|
|
409
|
+
: resolveLength(size->width, box.width, style.font_size, viewportWidth,
|
|
410
|
+
viewportHeight);
|
|
411
|
+
float tile_height =
|
|
412
|
+
height_auto ? box.height
|
|
413
|
+
: resolveLength(size->height, box.height, style.font_size, viewportWidth,
|
|
414
|
+
viewportHeight);
|
|
415
|
+
if (tile_width > 0.0f && tile_height > 0.0f) {
|
|
416
|
+
/* The default `background-repeat` is `repeat`; the size is per layer. */
|
|
417
|
+
int columns = (int)std::ceil(box.width / tile_width);
|
|
418
|
+
int rows = (int)std::ceil(box.height / tile_height);
|
|
419
|
+
if (columns < 1) columns = 1;
|
|
420
|
+
if (rows < 1) rows = 1;
|
|
421
|
+
const int kMaxTiles = 4096;
|
|
422
|
+
if (columns * rows > kMaxTiles) {
|
|
423
|
+
columns = 1;
|
|
424
|
+
rows = 1;
|
|
425
|
+
}
|
|
426
|
+
for (int row = 0; row < rows; row++) {
|
|
427
|
+
for (int column = 0; column < columns; column++) {
|
|
428
|
+
PaintImage image;
|
|
429
|
+
image.x = box.x + (float)column * tile_width;
|
|
430
|
+
image.y = box.y + (float)row * tile_height;
|
|
431
|
+
image.width = tile_width;
|
|
432
|
+
image.height = tile_height;
|
|
433
|
+
image.src = layer.image_src;
|
|
434
|
+
image.transform = box.world;
|
|
435
|
+
addImage(out, image, clip, chain);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
/* No `background-size`: keep the historical stretch to the box. */
|
|
364
442
|
PaintImage image;
|
|
365
443
|
image.x = box.x;
|
|
366
444
|
image.y = box.y;
|
|
@@ -382,7 +460,7 @@ void paintBackgrounds(DisplayList &out, const LayoutBox &box, const XtStyle &sty
|
|
|
382
460
|
/* The rectangle is already the border box, so the incoming clip is enough;
|
|
383
461
|
* narrowing it to the box again would only change the reported clip (and
|
|
384
462
|
* would clip a filtered/rounded fill differently from before M19). */
|
|
385
|
-
addRectFiltered(out, box.x, box.y, box.width, box.height,
|
|
463
|
+
addRectFiltered(out, box.x, box.y, box.width, box.height, box.border_radius,
|
|
386
464
|
style.background, clip, box.world, chain);
|
|
387
465
|
}
|
|
388
466
|
/* CSS paints the first layer on top, so walk the list backwards. */
|
|
@@ -393,7 +471,7 @@ void paintBackgrounds(DisplayList &out, const LayoutBox &box, const XtStyle &sty
|
|
|
393
471
|
} else if (layer.kind == BackgroundKind::Radial) {
|
|
394
472
|
paintRadial(box, style, layer, chain, layerClip, viewportWidth, viewportHeight, out);
|
|
395
473
|
} else {
|
|
396
|
-
paintImage(box, layer, chain, layerClip, out);
|
|
474
|
+
paintImage(box, layer, style, i, chain, layerClip, out, viewportWidth, viewportHeight);
|
|
397
475
|
}
|
|
398
476
|
}
|
|
399
477
|
}
|
|
@@ -228,6 +228,7 @@ void addRectFiltered(DisplayList &out, float x, float y, float width, float heig
|
|
|
228
228
|
|
|
229
229
|
void addBoxDropShadows(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
230
230
|
const FilterChain &chain, const PaintClip &clip) {
|
|
231
|
+
(void)style; // box.border_radius is the resolved form
|
|
231
232
|
if (chain.shadows.empty()) return;
|
|
232
233
|
for (const FilterChain::Shadow &shadow : chain.shadows) {
|
|
233
234
|
Color color = filterColor(chain, shadow.color);
|
|
@@ -237,7 +238,7 @@ void addBoxDropShadows(DisplayList &out, const LayoutBox &box, const XtStyle &st
|
|
|
237
238
|
Color copy = color;
|
|
238
239
|
if (shadow.blur > 0.0f) copy.a *= kBlurTapWeight;
|
|
239
240
|
addRect(out, box.x + shadow.dx + tap.dx, box.y + shadow.dy + tap.dy, box.width, box.height,
|
|
240
|
-
|
|
241
|
+
box.border_radius, copy, clip, box.world);
|
|
241
242
|
}
|
|
242
243
|
}
|
|
243
244
|
}
|
|
@@ -274,7 +275,9 @@ void addTextRun(DisplayList &out, float x, float baseline, float width, float he
|
|
|
274
275
|
}
|
|
275
276
|
|
|
276
277
|
/* `text-shadow`, bottom-most first: CSS paints later layers under earlier
|
|
277
|
-
* ones, so reverse the declaration list.
|
|
278
|
+
* ones, so reverse the declaration list. A zero-blur layer stays a crisp text
|
|
279
|
+
* run at an offset; a blurred one is a real Gaussian of the glyph coverage,
|
|
280
|
+
* composited as one tinted texture. */
|
|
278
281
|
for (size_t index = style.text_shadow.size(); index-- > 0;) {
|
|
279
282
|
const TextShadow &shadow = style.text_shadow[index];
|
|
280
283
|
float dx = resolveLength(shadow.dx, 0.0f, style.font_size, viewportWidth, viewportHeight);
|
|
@@ -282,11 +285,14 @@ void addTextRun(DisplayList &out, float x, float baseline, float width, float he
|
|
|
282
285
|
float blur =
|
|
283
286
|
resolveLength(shadow.blur, 0.0f, style.font_size, viewportWidth, viewportHeight);
|
|
284
287
|
Color shadowColor = shadow.has_color ? filterColor(chain, shadow.color) : color;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
emit(dx + tap.dx, dy + tap.dy, copy, true);
|
|
288
|
+
if (blur <= 0.0f) {
|
|
289
|
+
emit(dx, dy, shadowColor, true);
|
|
290
|
+
continue;
|
|
289
291
|
}
|
|
292
|
+
std::shared_ptr<const PaintBitmap> mask = textShadowMask(text, font, blur);
|
|
293
|
+
if (mask == nullptr) continue;
|
|
294
|
+
addBitmapImage(out, mask, x + dx + mask->origin_x, baseline + dy + mask->origin_y,
|
|
295
|
+
shadowColor, transform, clip);
|
|
290
296
|
}
|
|
291
297
|
|
|
292
298
|
/* `filter: blur()` spreads the glyphs themselves. */
|
|
@@ -72,10 +72,37 @@ void paintBackgrounds(DisplayList &out, const LayoutBox &box, const XtStyle &sty
|
|
|
72
72
|
const FilterChain &chain, const PaintClip &clip, float viewportWidth,
|
|
73
73
|
float viewportHeight);
|
|
74
74
|
|
|
75
|
+
/** Append the `outline` edge rectangles (after the border, before content). */
|
|
76
|
+
void addOutline(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
77
|
+
const FilterChain &chain, const PaintClip &clip, float viewportWidth,
|
|
78
|
+
float viewportHeight);
|
|
79
|
+
|
|
75
80
|
/** Append the drop-shadow silhouettes of a box (once, before its content). */
|
|
76
81
|
void addBoxDropShadows(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
77
82
|
const FilterChain &chain, const PaintClip &clip);
|
|
78
83
|
|
|
84
|
+
/** Append the `box-shadow` layers of a box. Outer shadows paint behind the
|
|
85
|
+
* background; inset shadows paint above it (call with `inset = true` for the
|
|
86
|
+
* latter). Declaration order is topmost first, so the list is reversed. */
|
|
87
|
+
void addBoxShadows(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
88
|
+
const FilterChain &chain, const PaintClip &clip, bool inset,
|
|
89
|
+
float viewportWidth, float viewportHeight);
|
|
90
|
+
|
|
91
|
+
/** Rasterise (or fetch from the bounded cache) the blurred glyph mask of a
|
|
92
|
+
* `text-shadow` layer. Returns null when the run has no visible glyphs. */
|
|
93
|
+
std::shared_ptr<const PaintBitmap> textShadowMask(const std::string &text, const FontSpec &font,
|
|
94
|
+
float blur);
|
|
95
|
+
|
|
96
|
+
/** Append a bitmap-backed image op (a rasterised shadow) with `color` as its
|
|
97
|
+
* tint. The bitmap now owns its pixels; the renderer uploads it once. */
|
|
98
|
+
void addBitmapImage(DisplayList &out, std::shared_ptr<const PaintBitmap> bitmap, float x, float y,
|
|
99
|
+
const Color &color, const Matrix2D &transform, const PaintClip &clip);
|
|
100
|
+
|
|
101
|
+
/** Resolve and append a `backdrop-filter` op for a box (before its
|
|
102
|
+
* background). Returns false when the filter list has no visible effect. */
|
|
103
|
+
bool addBackdropFilter(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
104
|
+
const PaintClip &clip, float viewportWidth, float viewportHeight);
|
|
105
|
+
|
|
79
106
|
/** Resolve `clip-path` into a device-space triangulated polygon. */
|
|
80
107
|
int addClipPathForBox(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
81
108
|
float viewportWidth, float viewportHeight);
|