xbintsc 0.3.69 → 0.3.81
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/README.md +57 -4
- package/README.zh-CN.md +51 -2
- package/dist/src/driver/compiler.js +6 -1
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/extensions/gui/index.js +10 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/tests/e2e/gui-advanced.test.d.ts +6 -0
- package/dist/tests/e2e/gui-advanced.test.js +261 -0
- package/dist/tests/e2e/gui-advanced.test.js.map +1 -0
- package/dist/tests/e2e/gui-canvas.test.d.ts +9 -0
- package/dist/tests/e2e/gui-canvas.test.js +233 -0
- package/dist/tests/e2e/gui-canvas.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-svg.test.d.ts +21 -0
- package/dist/tests/e2e/gui-example-svg.test.js +105 -0
- package/dist/tests/e2e/gui-example-svg.test.js.map +1 -0
- package/dist/tests/e2e/gui-example.test.d.ts +1 -1
- package/dist/tests/e2e/gui-example.test.js +2 -2
- package/dist/tests/e2e/gui-helpers.d.ts +3 -0
- package/dist/tests/e2e/gui-helpers.js +5 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +73 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.d.ts +8 -0
- package/dist/tests/e2e/gui-media.test.js +119 -0
- package/dist/tests/e2e/gui-media.test.js.map +1 -0
- package/dist/tests/e2e/gui-paint.test.js +40 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -1
- package/dist/tests/e2e/gui-transform.test.d.ts +7 -0
- package/dist/tests/e2e/gui-transform.test.js +198 -0
- package/dist/tests/e2e/gui-transform.test.js.map +1 -0
- package/doc/ai/cli.md +5 -0
- package/doc/ai/extensions.md +20 -3
- package/doc/ai/zh-CN/extensions.md +14 -3
- package/doc/gui/animation.md +97 -0
- package/doc/gui/api.md +92 -0
- package/doc/gui/build.md +91 -0
- package/doc/gui/canvas.md +98 -0
- package/doc/gui/dom.md +128 -0
- package/doc/gui/input.md +25 -0
- package/doc/gui/known-issues.md +78 -0
- package/doc/gui/layout.md +108 -0
- package/doc/gui/media.md +87 -0
- package/doc/gui/rendering.md +113 -0
- package/doc/gui/runtime.md +88 -0
- package/doc/gui-scripts.md +7 -3
- package/doc/gui.md +109 -612
- package/doc/implemented.md +1 -0
- package/doc/zh-CN/gui/animation.md +93 -0
- package/doc/zh-CN/gui/api.md +88 -0
- package/doc/zh-CN/gui/build.md +84 -0
- package/doc/zh-CN/gui/canvas.md +80 -0
- package/doc/zh-CN/gui/dom.md +119 -0
- package/doc/zh-CN/gui/input.md +23 -0
- package/doc/zh-CN/gui/known-issues.md +60 -0
- package/doc/zh-CN/gui/layout.md +91 -0
- package/doc/zh-CN/gui/media.md +71 -0
- package/doc/zh-CN/gui/rendering.md +92 -0
- package/doc/zh-CN/gui/runtime.md +76 -0
- package/doc/zh-CN/gui-scripts.md +6 -2
- package/doc/zh-CN/gui.md +89 -532
- package/doc/zh-CN/implemented.md +1 -0
- package/llms.txt +15 -2
- package/package.json +1 -1
- package/runtime/ext_gui/canvas.cpp +580 -0
- package/runtime/ext_gui/canvas.h +170 -0
- package/runtime/ext_gui/canvas_internal.h +59 -0
- package/runtime/ext_gui/canvas_raster.cpp +254 -0
- package/runtime/ext_gui/document.cpp +45 -4
- package/runtime/ext_gui/document.h +15 -1
- package/runtime/ext_gui/dom_api.cpp +3 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +548 -0
- package/runtime/ext_gui/dom_api_internal.h +73 -0
- package/runtime/ext_gui/dom_api_media.cpp +274 -0
- package/runtime/ext_gui/dom_api_node.cpp +6 -4
- package/runtime/ext_gui/dom_api_proto.cpp +80 -0
- package/runtime/ext_gui/gui.cpp +6 -0
- package/runtime/ext_gui/gui_canvas.cpp +95 -0
- package/runtime/ext_gui/gui_engine.h +49 -0
- package/runtime/ext_gui/gui_events.cpp +21 -5
- package/runtime/ext_gui/gui_media.cpp +193 -0
- package/runtime/ext_gui/image.cpp +31 -12
- package/runtime/ext_gui/image.h +20 -7
- package/runtime/ext_gui/layout.cpp +130 -6
- package/runtime/ext_gui/layout.h +54 -1
- package/runtime/ext_gui/layout_flex.cpp +263 -99
- package/runtime/ext_gui/layout_flow.cpp +85 -9
- package/runtime/ext_gui/layout_flow_internal.h +84 -5
- package/runtime/ext_gui/layout_inline.cpp +54 -37
- package/runtime/ext_gui/media.cpp +514 -0
- package/runtime/ext_gui/media.h +104 -0
- package/runtime/ext_gui/nanosvg.h +3278 -0
- package/runtime/ext_gui/nanosvgrast.h +1472 -0
- package/runtime/ext_gui/paint.cpp +156 -38
- package/runtime/ext_gui/paint.h +42 -6
- package/runtime/ext_gui/renderer.cpp +117 -12
- package/runtime/ext_gui/renderer.h +49 -9
- package/runtime/ext_gui/renderer_image.cpp +205 -78
- package/runtime/ext_gui/renderer_internal.h +12 -9
- package/runtime/ext_gui/renderer_text.cpp +46 -39
- package/runtime/ext_gui/style.h +21 -0
- package/runtime/ext_gui/style_print.cpp +17 -0
- package/runtime/ext_gui/style_ua.cpp +7 -0
- package/runtime/ext_gui/style_values.cpp +83 -1
- package/runtime/ext_gui/svg.cpp +182 -0
- package/runtime/ext_gui/svg.h +46 -0
- package/runtime/ext_gui/text.cpp +156 -25
- package/runtime/ext_gui/text.h +11 -2
- package/runtime/ext_gui/transform.cpp +412 -0
- package/runtime/ext_gui/transform.h +112 -0
- package/runtime/ext_gui/window.cpp +10 -5
- package/scripts/build-gui.ts +148 -6
- package/scripts/check-file-length.ts +5 -1
- package/scripts/install-gui-deps.sh +28 -0
- package/src/driver/compiler.ts +6 -1
- package/src/extensions/gui/index.ts +10 -2
|
@@ -25,6 +25,14 @@ namespace layout_flow_detail {
|
|
|
25
25
|
|
|
26
26
|
constexpr float kHuge = 1e18f;
|
|
27
27
|
|
|
28
|
+
/** Collapse two adjoining vertical margins (CSS margin collapsing): the larger
|
|
29
|
+
* positive margin wins, a negative margin is subtracted. */
|
|
30
|
+
inline float collapseMargins(float a, float b) {
|
|
31
|
+
float positive = std::max(0.0f, std::max(a, b));
|
|
32
|
+
float negative = std::min(0.0f, std::min(a, b));
|
|
33
|
+
return positive + negative;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
struct InlineItem {
|
|
29
37
|
LayoutBox *box = nullptr;
|
|
30
38
|
const XtStyle *style = nullptr;
|
|
@@ -37,6 +45,63 @@ struct InlineItem {
|
|
|
37
45
|
bool force_break = false; // explicit newline (white-space: pre)
|
|
38
46
|
};
|
|
39
47
|
|
|
48
|
+
/** One float taking part in the current block's formatting context. Floats are
|
|
49
|
+
* out of flow: they do not advance the block cursor, but inline lines shrink to
|
|
50
|
+
* the gap they leave. */
|
|
51
|
+
struct ActiveFloat {
|
|
52
|
+
bool left = true;
|
|
53
|
+
float x = 0;
|
|
54
|
+
float width = 0;
|
|
55
|
+
float top = 0;
|
|
56
|
+
float height = 0;
|
|
57
|
+
float bottom() const { return top + height; }
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** The floats in effect while laying out a block's inline content. */
|
|
61
|
+
struct FloatContext {
|
|
62
|
+
std::vector<ActiveFloat> floats;
|
|
63
|
+
void prune(float y) {
|
|
64
|
+
for (auto it = floats.begin(); it != floats.end();) {
|
|
65
|
+
if (it->bottom() <= y) it = floats.erase(it);
|
|
66
|
+
else ++it;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
float leftEdge(float x, float y, float bottom) const {
|
|
70
|
+
for (const ActiveFloat &f : floats) {
|
|
71
|
+
if (!f.left || f.bottom() <= y || f.top >= bottom) continue;
|
|
72
|
+
if (f.x + f.width > x) x = f.x + f.width;
|
|
73
|
+
}
|
|
74
|
+
return x;
|
|
75
|
+
}
|
|
76
|
+
float rightEdge(float x, float y, float bottom) const {
|
|
77
|
+
for (const ActiveFloat &f : floats) {
|
|
78
|
+
if (f.left || f.bottom() <= y || f.top >= bottom) continue;
|
|
79
|
+
if (f.x < x) x = f.x;
|
|
80
|
+
}
|
|
81
|
+
return x;
|
|
82
|
+
}
|
|
83
|
+
float maxBottom() const {
|
|
84
|
+
float bottom = 0;
|
|
85
|
+
for (const ActiveFloat &f : floats)
|
|
86
|
+
if (f.bottom() > bottom) bottom = f.bottom();
|
|
87
|
+
return bottom;
|
|
88
|
+
}
|
|
89
|
+
bool clears(bool left, bool right, float y) const {
|
|
90
|
+
for (const ActiveFloat &f : floats) {
|
|
91
|
+
if (f.bottom() <= y) continue;
|
|
92
|
+
if ((left && f.left) || (right && !f.left)) return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
float clearY(bool left, bool right, float y) const {
|
|
97
|
+
for (const ActiveFloat &f : floats) {
|
|
98
|
+
if (f.bottom() <= y) continue;
|
|
99
|
+
if ((left && f.left) || (right && !f.left)) y = std::max(y, f.bottom());
|
|
100
|
+
}
|
|
101
|
+
return y;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
40
105
|
inline float toPx(const Length &length, float base, float em, float root, float vw, float vh,
|
|
41
106
|
float fallback) {
|
|
42
107
|
switch (length.unit) {
|
|
@@ -128,9 +193,10 @@ struct Layouter {
|
|
|
128
193
|
|
|
129
194
|
void resolveEdges(LayoutBox *box, float containingWidth) const;
|
|
130
195
|
|
|
131
|
-
/** Lay out `box` at (x, y) and return its
|
|
132
|
-
*
|
|
133
|
-
*
|
|
196
|
+
/** Lay out `box` at (x, y) and return its border-box height. The caller owns
|
|
197
|
+
* the vertical margins (it collapses them and advances the flow). `inFlow` is
|
|
198
|
+
* false for an absolutely positioned child: it is still laid out, but the
|
|
199
|
+
* caller ignores the returned height (it is out of flow). */
|
|
134
200
|
float layoutBlock(LayoutBox *box, float x, float y, float availableWidth, float availableHeight,
|
|
135
201
|
float forcedContentWidth = -1, float forcedContentHeight = -1,
|
|
136
202
|
bool inFlow = true) const;
|
|
@@ -168,12 +234,25 @@ struct Layouter {
|
|
|
168
234
|
|
|
169
235
|
void computeInlineGeometry(LayoutBox *box) const;
|
|
170
236
|
|
|
171
|
-
/** Lay out an inline formatting context; returns its consumed height.
|
|
237
|
+
/** Lay out an inline formatting context; returns its consumed height. When
|
|
238
|
+
* `floats` is non-null, each line shrinks to the gap left by the floats that
|
|
239
|
+
* overlap it. */
|
|
172
240
|
float layoutInlineRun(LayoutBox *container, const std::vector<LayoutBox *> &run,
|
|
173
|
-
float contentWidth, float y) const;
|
|
241
|
+
float contentWidth, float y, const FloatContext *floats = nullptr) const;
|
|
174
242
|
|
|
175
243
|
float layoutFlex(LayoutBox *container, float contentWidth, float definiteHeight) const;
|
|
176
244
|
|
|
245
|
+
/** Flex row main-axis layout, wrapping items into lines when `flex-wrap`
|
|
246
|
+
* allows it. Returns the used cross size. */
|
|
247
|
+
float layoutFlexRow(LayoutBox *container, const std::vector<LayoutBox *> &items,
|
|
248
|
+
float contentWidth, float definiteHeight, float mainGap,
|
|
249
|
+
float crossGap) const;
|
|
250
|
+
|
|
251
|
+
/** Flex column main-axis layout (wrapping needs a definite height). */
|
|
252
|
+
float layoutFlexColumn(LayoutBox *container, const std::vector<LayoutBox *> &items,
|
|
253
|
+
float contentWidth, float definiteHeight, float mainGap,
|
|
254
|
+
float crossGap) const;
|
|
255
|
+
|
|
177
256
|
static float sumOf(const std::vector<float> &values);
|
|
178
257
|
|
|
179
258
|
static void applyJustify(JustifyContent justify, float freeSpace, size_t count, float *offset,
|
|
@@ -113,56 +113,47 @@ void Layouter::computeInlineGeometry(LayoutBox *box) const {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
float Layouter::layoutInlineRun(LayoutBox *container, const std::vector<LayoutBox *> &run,
|
|
116
|
-
float contentWidth, float y) const {
|
|
116
|
+
float contentWidth, float y, const FloatContext *floats) const {
|
|
117
117
|
std::vector<InlineItem> items;
|
|
118
118
|
for (LayoutBox *box : run) flattenInline(box, contentWidth, items);
|
|
119
119
|
if (items.empty()) return 0;
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
const XtStyle &containerStyle = *container->style;
|
|
122
|
+
float cursorY = y;
|
|
122
123
|
std::vector<InlineItem *> line;
|
|
123
124
|
float lineWidth = 0;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
float lineAscent = 0;
|
|
126
|
+
float lineDescent = 0;
|
|
127
|
+
|
|
128
|
+
/* Horizontal band left free by the floats overlapping [top, top + height). */
|
|
129
|
+
auto band = [&](float top, float height, float *x0, float *x1) {
|
|
130
|
+
*x0 = container->content_x;
|
|
131
|
+
*x1 = container->content_x + contentWidth;
|
|
132
|
+
if (floats != nullptr && height > 0) {
|
|
133
|
+
*x0 = floats->leftEdge(*x0, top, top + height);
|
|
134
|
+
*x1 = floats->rightEdge(*x1, top, top + height);
|
|
128
135
|
}
|
|
129
|
-
if (
|
|
130
|
-
line.clear();
|
|
131
|
-
lineWidth = 0;
|
|
136
|
+
if (*x1 < *x0) *x1 = *x0;
|
|
132
137
|
};
|
|
133
|
-
for (InlineItem &item : items) {
|
|
134
|
-
if (item.force_break) {
|
|
135
|
-
pushLine();
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (item.is_space && line.empty()) continue; // no leading space on a line
|
|
139
|
-
if (lineWidth + item.width > contentWidth && !line.empty()) pushLine();
|
|
140
|
-
if (item.is_space && line.empty()) continue;
|
|
141
|
-
line.push_back(&item);
|
|
142
|
-
lineWidth += item.width;
|
|
143
|
-
}
|
|
144
|
-
pushLine();
|
|
145
138
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
float width = 0;
|
|
151
|
-
float ascent = 0;
|
|
152
|
-
float descent = 0;
|
|
153
|
-
for (InlineItem *item : current) {
|
|
154
|
-
width += item->width;
|
|
155
|
-
ascent = std::max(ascent, item->ascent);
|
|
156
|
-
descent = std::max(descent, item->height - item->ascent);
|
|
139
|
+
auto finalize = [&]() {
|
|
140
|
+
while (!line.empty() && line.back()->is_space) {
|
|
141
|
+
lineWidth -= line.back()->width;
|
|
142
|
+
line.pop_back();
|
|
157
143
|
}
|
|
158
|
-
|
|
159
|
-
float
|
|
144
|
+
if (line.empty()) return;
|
|
145
|
+
float height = lineAscent + lineDescent;
|
|
146
|
+
float x0 = 0;
|
|
147
|
+
float x1 = 0;
|
|
148
|
+
band(cursorY, height, &x0, &x1);
|
|
149
|
+
float available = x1 - x0;
|
|
150
|
+
float x = x0;
|
|
160
151
|
if (containerStyle.text_align == TextAlign::Center) {
|
|
161
|
-
x += (
|
|
152
|
+
x += (available - lineWidth) / 2.0f;
|
|
162
153
|
} else if (containerStyle.text_align == TextAlign::End) {
|
|
163
|
-
x +=
|
|
154
|
+
x += available - lineWidth;
|
|
164
155
|
}
|
|
165
|
-
for (InlineItem *item :
|
|
156
|
+
for (InlineItem *item : line) {
|
|
166
157
|
if (item->atomic) {
|
|
167
158
|
/* An out-of-flow item was already placed against its containing block by
|
|
168
159
|
* `layoutBlock`, so it must not be moved back onto the line. */
|
|
@@ -180,7 +171,33 @@ float Layouter::layoutInlineRun(LayoutBox *container, const std::vector<LayoutBo
|
|
|
180
171
|
x += item->width;
|
|
181
172
|
}
|
|
182
173
|
cursorY += height;
|
|
174
|
+
line.clear();
|
|
175
|
+
lineWidth = 0;
|
|
176
|
+
lineAscent = 0;
|
|
177
|
+
lineDescent = 0;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
for (InlineItem &item : items) {
|
|
181
|
+
if (item.force_break) {
|
|
182
|
+
finalize();
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (item.is_space && line.empty()) continue; // no leading space on a line
|
|
186
|
+
/* Break against the band the line would occupy, then place it. */
|
|
187
|
+
float pendingHeight = std::max(lineAscent + lineDescent, item.height);
|
|
188
|
+
float x0 = 0;
|
|
189
|
+
float x1 = 0;
|
|
190
|
+
band(cursorY, pendingHeight, &x0, &x1);
|
|
191
|
+
float available = x1 - x0;
|
|
192
|
+
if (lineWidth + item.width > available && !line.empty()) finalize();
|
|
193
|
+
if (item.is_space && line.empty()) continue;
|
|
194
|
+
line.push_back(&item);
|
|
195
|
+
lineWidth += item.width;
|
|
196
|
+
lineAscent = std::max(lineAscent, item.ascent);
|
|
197
|
+
lineDescent = std::max(lineDescent, item.height - item.ascent);
|
|
183
198
|
}
|
|
199
|
+
finalize();
|
|
200
|
+
|
|
184
201
|
for (LayoutBox *box : run) computeInlineGeometry(box);
|
|
185
202
|
return cursorY - y;
|
|
186
203
|
}
|