@effindomv2/fui-as 0.1.36 → 0.1.39

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.
Files changed (119) hide show
  1. package/browser/routed-app-conventions.ts +1 -1
  2. package/browser/src/common-harness.ts +1 -27
  3. package/browser/src/index.ts +19 -26
  4. package/browser/src/routed-harness.ts +1 -194
  5. package/browser/src/shared-browser.ts +6 -0
  6. package/package.json +26 -16
  7. package/scripts/build.sh +51 -47
  8. package/scripts/framework-host-services.ts +1 -1
  9. package/scripts/generate-host-events.ts +15 -241
  10. package/scripts/generate-host-services.ts +13 -261
  11. package/scripts/hostgen/assemblyscript-host-events.ts +165 -0
  12. package/scripts/hostgen/assemblyscript-host-services.ts +207 -0
  13. package/scripts/hostgen/common.ts +73 -0
  14. package/scripts/hostgen/registry.ts +159 -0
  15. package/src/Fui.ts +70 -4
  16. package/src/FuiExports.ts +13 -1
  17. package/src/bindings/ui.ts +165 -8
  18. package/src/controls/Button.ts +98 -71
  19. package/src/controls/Checkbox.ts +23 -21
  20. package/src/controls/ComboBox.ts +1201 -0
  21. package/src/controls/ContextMenu.ts +279 -165
  22. package/src/controls/Dialog.ts +91 -17
  23. package/src/controls/Dropdown.ts +101 -333
  24. package/src/controls/NavLink.ts +29 -6
  25. package/src/controls/Popup.ts +10 -5
  26. package/src/controls/ProgressBar.ts +1 -2
  27. package/src/controls/RadioButton.ts +34 -13
  28. package/src/controls/RadioGroup.ts +32 -19
  29. package/src/controls/Slider.ts +21 -23
  30. package/src/controls/Switch.ts +34 -17
  31. package/src/controls/index.ts +2 -1
  32. package/src/controls/internal/ButtonPresenter.ts +5 -2
  33. package/src/controls/internal/CheckboxIndicatorPresenter.ts +10 -10
  34. package/src/controls/internal/DropdownChevronPresenter.ts +3 -3
  35. package/src/controls/internal/DropdownFieldPresenter.ts +6 -6
  36. package/src/controls/internal/DropdownOptionRowPresenter.ts +5 -4
  37. package/src/controls/internal/PressableLabeledControl.ts +4 -7
  38. package/src/controls/internal/RadioIndicatorPresenter.ts +7 -7
  39. package/src/controls/internal/SelectablePopupList.ts +463 -0
  40. package/src/controls/internal/SliderPresenter.ts +5 -5
  41. package/src/controls/internal/SwitchIndicatorPresenter.ts +63 -17
  42. package/src/controls/internal/TextInputCore.ts +307 -41
  43. package/src/controls/internal/TextInputPresenter.ts +2 -2
  44. package/src/controls/templating.ts +10 -0
  45. package/src/core/Application.ts +19 -9
  46. package/src/core/Bitmap.ts +219 -1
  47. package/src/core/ContextMenuManager.ts +128 -44
  48. package/src/core/DebugApi.ts +17 -2
  49. package/src/core/DragGesture.ts +8 -7
  50. package/src/core/EventRouter.ts +332 -12
  51. package/src/core/Fetch.ts +15 -7
  52. package/src/core/FetchFfi.ts +1 -15
  53. package/src/core/File.ts +75 -34
  54. package/src/core/FocusAdornerManager.ts +3 -3
  55. package/src/core/FocusVisibility.ts +7 -0
  56. package/src/core/FrameScheduler.ts +126 -0
  57. package/src/core/ImageSampling.ts +43 -0
  58. package/src/core/Logger.ts +2 -0
  59. package/src/core/MobileTextSelectionToolbarManager.ts +901 -0
  60. package/src/core/Node.ts +1039 -97
  61. package/src/core/Platform.ts +16 -16
  62. package/src/core/SelectionHandleAdornerManager.ts +697 -0
  63. package/src/core/Theme.ts +34 -20
  64. package/src/core/ToolTipManager.ts +3 -3
  65. package/src/core/Typography.ts +411 -19
  66. package/src/core/Worker.ts +69 -33
  67. package/src/core/event_exports.ts +123 -5
  68. package/src/core/ffi.ts +5 -746
  69. package/src/core/generated/FetchHostAbi.ts +10 -0
  70. package/src/core/generated/FrameworkHostServices.ts +1 -1
  71. package/src/core/generated/HostAbi.ts +220 -0
  72. package/src/core/generated/UiAbi.ts +356 -0
  73. package/src/core/generated/UiEnums.ts +186 -0
  74. package/src/drawing/DrawCallback.ts +34 -0
  75. package/src/drawing/DrawContext.ts +189 -0
  76. package/src/drawing/Paint.ts +34 -0
  77. package/src/drawing/Path.ts +40 -0
  78. package/src/nodes/CustomDrawable.ts +61 -0
  79. package/src/nodes/FlexBox.ts +57 -11
  80. package/src/nodes/Grid.ts +5 -5
  81. package/src/nodes/Image.ts +20 -1
  82. package/src/nodes/RichText.ts +36 -25
  83. package/src/nodes/ScrollBar.ts +2 -1
  84. package/src/nodes/ScrollBox.ts +7 -2
  85. package/src/nodes/ScrollView.ts +17 -6
  86. package/src/nodes/Svg.ts +18 -1
  87. package/src/nodes/Text.ts +1 -1
  88. package/src/nodes/TextCore.ts +115 -20
  89. package/src/nodes/index.ts +3 -1
  90. package/src/text/DynamicTextLayout.ts +275 -0
  91. package/src/text/TextLayout.ts +308 -0
  92. package/src/worker/Worker.ts +3 -36
  93. package/src/worker/WorkerJob.ts +5 -9
  94. package/src/worker/ffi.ts +0 -6
  95. package/browser/src/common-harness/host-imports.ts +0 -447
  96. package/browser/src/common-harness/interop.ts +0 -39
  97. package/browser/src/common-harness/managed-harness-bitmap-host.ts +0 -92
  98. package/browser/src/common-harness/managed-harness-fetch-host.ts +0 -201
  99. package/browser/src/common-harness/managed-harness-file-host.ts +0 -1066
  100. package/browser/src/common-harness/managed-harness-file-payloads.ts +0 -143
  101. package/browser/src/common-harness/managed-harness-file-types.ts +0 -71
  102. package/browser/src/common-harness/managed-harness-session.ts +0 -15
  103. package/browser/src/common-harness/managed-harness.ts +0 -1451
  104. package/browser/src/common-harness/managed-history.ts +0 -168
  105. package/browser/src/common-harness/persisted-restore-policy.ts +0 -50
  106. package/browser/src/common-harness/persisted-ui-state-controller.ts +0 -309
  107. package/browser/src/common-harness/text-session-bridge.ts +0 -452
  108. package/browser/src/common-harness/types.ts +0 -205
  109. package/browser/src/common-harness/ui-chrome.ts +0 -206
  110. package/browser/src/common-harness/ui-imports.ts +0 -553
  111. package/browser/src/common-harness/wasm-module-cache.ts +0 -47
  112. package/browser/src/file-processing-worker.ts +0 -89
  113. package/browser/src/host-events.ts +0 -118
  114. package/browser/src/host-services.ts +0 -483
  115. package/browser/src/persisted-ui-state.ts +0 -206
  116. package/browser/src/routed-app-conventions.ts +0 -292
  117. package/browser/src/worker-bootstrap.ts +0 -916
  118. package/browser/src/worker-manager.ts +0 -234
  119. package/browser/src/worker-types.ts +0 -68
@@ -1,553 +0,0 @@
1
- import type { BridgeRuntime, WasmHandleLike } from '@effindomv2/runtime';
2
-
3
- import { addUiPointer, toBigIntHandle, type AppHandleLike } from './interop';
4
-
5
- export interface PendingGradient {
6
- startX: number;
7
- startY: number;
8
- endX: number;
9
- endY: number;
10
- stopCount: number;
11
- offsets: number[];
12
- colors: number[];
13
- }
14
-
15
- export interface UiImportDeps {
16
- getRuntime(): BridgeRuntime;
17
- readAppUtf8(ptr: number, len: number): string;
18
- readAppFloats(ptr: number, count: number): Float32Array;
19
- readAppBytes(ptr: number, len: number): Uint8Array;
20
- withUiUtf8(text: string, callback: (ptr: WasmHandleLike | number, len: number) => void): void;
21
- withUiGridData(
22
- values: Float32Array,
23
- types: Uint8Array,
24
- callback: (valuesPtr: WasmHandleLike | number, typesPtr: WasmHandleLike | number) => void,
25
- ): void;
26
- withUiGradientData(
27
- offsets: Float32Array,
28
- colors: Uint32Array,
29
- callback: (offsetsPtr: WasmHandleLike | number, colorsPtr: WasmHandleLike | number) => void,
30
- ): void;
31
- zeroPointer(): WasmHandleLike | number;
32
- normalizePointer(ptr: WasmHandleLike | number): WasmHandleLike | number;
33
- getCurrentMemory(): WebAssembly.Memory;
34
- setLatestRootHandle(rootHandle: string | null): void;
35
- updateState(): void;
36
- queueHarnessFrame(): void;
37
- syncUiHostCapabilities(): void;
38
- resetUiState(): void;
39
- pendingGradients: Map<string, PendingGradient>;
40
- }
41
-
42
- export function createUiImportModule(deps: UiImportDeps) {
43
- return {
44
- ui_reset(): void {
45
- const runtime = deps.getRuntime();
46
- runtime.ui._ui_reset();
47
- deps.syncUiHostCapabilities();
48
- deps.resetUiState();
49
- },
50
- ui_create_node(type: number): bigint {
51
- return toBigIntHandle(deps.getRuntime().ui._ui_create_node(type));
52
- },
53
- ui_set_node_id(handle: AppHandleLike, ptr: number, len: number): void {
54
- const runtime = deps.getRuntime();
55
- const text = deps.readAppUtf8(ptr, len);
56
- deps.withUiUtf8(text, (uiPtr, uiLen) => {
57
- runtime.ui._ui_set_node_id(toBigIntHandle(handle), uiPtr, uiLen);
58
- });
59
- },
60
- ui_delete_node(handle: AppHandleLike): void {
61
- deps.getRuntime().ui._ui_delete_node(toBigIntHandle(handle));
62
- },
63
- ui_set_semantic_role(handle: AppHandleLike, role: number): void {
64
- deps.getRuntime().ui._ui_set_semantic_role(toBigIntHandle(handle), role);
65
- },
66
- ui_set_semantic_label(handle: AppHandleLike, ptr: number, len: number): void {
67
- const runtime = deps.getRuntime();
68
- const text = deps.readAppUtf8(ptr, len);
69
- deps.withUiUtf8(text, (uiPtr, uiLen) => {
70
- runtime.ui._ui_set_semantic_label(toBigIntHandle(handle), uiPtr, uiLen);
71
- });
72
- },
73
- ui_set_semantic_checked(handle: AppHandleLike, checkedState: number): void {
74
- deps.getRuntime().ui._ui_set_semantic_checked(toBigIntHandle(handle), checkedState);
75
- },
76
- ui_set_semantic_selected(handle: AppHandleLike, hasSelected: number, selected: number): void {
77
- deps.getRuntime().ui._ui_set_semantic_selected(toBigIntHandle(handle), hasSelected, selected);
78
- },
79
- ui_set_semantic_expanded(handle: AppHandleLike, hasExpanded: number, expanded: number): void {
80
- deps.getRuntime().ui._ui_set_semantic_expanded(toBigIntHandle(handle), hasExpanded, expanded);
81
- },
82
- ui_set_semantic_disabled(handle: AppHandleLike, hasDisabled: number, disabled: number): void {
83
- deps.getRuntime().ui._ui_set_semantic_disabled(toBigIntHandle(handle), hasDisabled, disabled);
84
- },
85
- ui_set_semantic_value_range(
86
- handle: AppHandleLike,
87
- hasValueRange: number,
88
- valueNow: number,
89
- valueMin: number,
90
- valueMax: number,
91
- ): void {
92
- deps.getRuntime().ui._ui_set_semantic_value_range(toBigIntHandle(handle), hasValueRange, valueNow, valueMin, valueMax);
93
- },
94
- ui_set_semantic_orientation(handle: AppHandleLike, orientation: number): void {
95
- deps.getRuntime().ui._ui_set_semantic_orientation(toBigIntHandle(handle), orientation);
96
- },
97
- ui_request_semantic_announcement(handle: AppHandleLike): void {
98
- deps.getRuntime().ui._ui_request_semantic_announcement(toBigIntHandle(handle));
99
- },
100
- ui_push_semantic_scope(handle: AppHandleLike): number {
101
- return deps.getRuntime().ui._ui_push_semantic_scope(toBigIntHandle(handle));
102
- },
103
- ui_remove_semantic_scope(token: number): void {
104
- deps.getRuntime().ui._ui_remove_semantic_scope(token);
105
- },
106
- ui_node_add_child(parent: AppHandleLike, child: AppHandleLike): void {
107
- deps.getRuntime().ui._ui_node_add_child(toBigIntHandle(parent), toBigIntHandle(child));
108
- },
109
- ui_node_remove_child(parent: AppHandleLike, child: AppHandleLike): void {
110
- deps.getRuntime().ui._ui_node_remove_child(toBigIntHandle(parent), toBigIntHandle(child));
111
- },
112
- ui_set_is_portal(handle: AppHandleLike, flag: number): void {
113
- deps.getRuntime().ui._ui_set_is_portal(toBigIntHandle(handle), flag);
114
- },
115
- ui_set_is_shared_size_scope(handle: AppHandleLike, flag: number): void {
116
- deps.getRuntime().ui._ui_set_is_shared_size_scope(toBigIntHandle(handle), flag);
117
- },
118
- ui_set_root(handle: AppHandleLike): void {
119
- const runtime = deps.getRuntime();
120
- const rootHandle = toBigIntHandle(handle);
121
- deps.setLatestRootHandle(rootHandle.toString());
122
- runtime.ui._ui_set_root(rootHandle);
123
- deps.updateState();
124
- },
125
- ui_set_width(handle: AppHandleLike, value: number, unit: number): void {
126
- deps.getRuntime().ui._ui_set_width(toBigIntHandle(handle), value, unit);
127
- },
128
- ui_set_height(handle: AppHandleLike, value: number, unit: number): void {
129
- deps.getRuntime().ui._ui_set_height(toBigIntHandle(handle), value, unit);
130
- },
131
- ui_set_fill_width(handle: AppHandleLike, fill: number): void {
132
- deps.getRuntime().ui._ui_set_fill_width(toBigIntHandle(handle), fill);
133
- },
134
- ui_set_fill_height(handle: AppHandleLike, fill: number): void {
135
- deps.getRuntime().ui._ui_set_fill_height(toBigIntHandle(handle), fill);
136
- },
137
- ui_set_fill_width_percent(handle: AppHandleLike, percent: number): void {
138
- deps.getRuntime().ui._ui_set_fill_width_percent(toBigIntHandle(handle), percent);
139
- },
140
- ui_set_fill_height_percent(handle: AppHandleLike, percent: number): void {
141
- deps.getRuntime().ui._ui_set_fill_height_percent(toBigIntHandle(handle), percent);
142
- },
143
- ui_set_min_width(handle: AppHandleLike, value: number, unit: number): void {
144
- deps.getRuntime().ui._ui_set_min_width(toBigIntHandle(handle), value, unit);
145
- },
146
- ui_set_max_width(handle: AppHandleLike, value: number, unit: number): void {
147
- deps.getRuntime().ui._ui_set_max_width(toBigIntHandle(handle), value, unit);
148
- },
149
- ui_set_min_height(handle: AppHandleLike, value: number, unit: number): void {
150
- deps.getRuntime().ui._ui_set_min_height(toBigIntHandle(handle), value, unit);
151
- },
152
- ui_set_max_height(handle: AppHandleLike, value: number, unit: number): void {
153
- deps.getRuntime().ui._ui_set_max_height(toBigIntHandle(handle), value, unit);
154
- },
155
- ui_set_flex_direction(handle: AppHandleLike, direction: number): void {
156
- deps.getRuntime().ui._ui_set_flex_direction(toBigIntHandle(handle), direction);
157
- },
158
- ui_set_flex_basis(handle: AppHandleLike, basis: number): void {
159
- deps.getRuntime().ui._ui_set_flex_basis(toBigIntHandle(handle), basis);
160
- },
161
- ui_set_justify_content(handle: AppHandleLike, justify: number): void {
162
- deps.getRuntime().ui._ui_set_justify_content(toBigIntHandle(handle), justify);
163
- },
164
- ui_set_align_items(handle: AppHandleLike, align: number): void {
165
- deps.getRuntime().ui._ui_set_align_items(toBigIntHandle(handle), align);
166
- },
167
- ui_set_align_self(handle: AppHandleLike, align: number): void {
168
- deps.getRuntime().ui._ui_set_align_self(toBigIntHandle(handle), align);
169
- },
170
- ui_set_padding(handle: AppHandleLike, left: number, top: number, right: number, bottom: number): void {
171
- deps.getRuntime().ui._ui_set_padding(toBigIntHandle(handle), left, top, right, bottom);
172
- },
173
- ui_set_margin(handle: AppHandleLike, left: number, top: number, right: number, bottom: number): void {
174
- deps.getRuntime().ui._ui_set_margin(toBigIntHandle(handle), left, top, right, bottom);
175
- },
176
- ui_set_position_type(handle: AppHandleLike, positionType: number): void {
177
- deps.getRuntime().ui._ui_set_position_type(toBigIntHandle(handle), positionType);
178
- },
179
- ui_set_position(handle: AppHandleLike, left: number, top: number, right: number, bottom: number): void {
180
- deps.getRuntime().ui._ui_set_position(toBigIntHandle(handle), left, top, right, bottom);
181
- },
182
- ui_grid_set_columns(handle: AppHandleLike, count: number, valuesPtr: number, typesPtr: number): void {
183
- const runtime = deps.getRuntime();
184
- deps.withUiGridData(deps.readAppFloats(valuesPtr, count), deps.readAppBytes(typesPtr, count), (uiValuesPtr, uiTypesPtr) => {
185
- runtime.ui._ui_grid_set_columns(toBigIntHandle(handle), count, uiValuesPtr, uiTypesPtr);
186
- });
187
- },
188
- ui_grid_set_rows(handle: AppHandleLike, count: number, valuesPtr: number, typesPtr: number): void {
189
- const runtime = deps.getRuntime();
190
- deps.withUiGridData(deps.readAppFloats(valuesPtr, count), deps.readAppBytes(typesPtr, count), (uiValuesPtr, uiTypesPtr) => {
191
- runtime.ui._ui_grid_set_rows(toBigIntHandle(handle), count, uiValuesPtr, uiTypesPtr);
192
- });
193
- },
194
- ui_grid_set_column_shared_size_group(handle: AppHandleLike, index: number, ptr: number, len: number): void {
195
- const runtime = deps.getRuntime();
196
- const text = deps.readAppUtf8(ptr, len);
197
- deps.withUiUtf8(text, (uiPtr, uiLen) => {
198
- runtime.ui._ui_grid_set_column_shared_size_group(toBigIntHandle(handle), index, uiPtr, uiLen);
199
- });
200
- },
201
- ui_grid_set_row_shared_size_group(handle: AppHandleLike, index: number, ptr: number, len: number): void {
202
- const runtime = deps.getRuntime();
203
- const text = deps.readAppUtf8(ptr, len);
204
- deps.withUiUtf8(text, (uiPtr, uiLen) => {
205
- runtime.ui._ui_grid_set_row_shared_size_group(toBigIntHandle(handle), index, uiPtr, uiLen);
206
- });
207
- },
208
- ui_node_set_grid_placement(handle: AppHandleLike, row: number, col: number, rowSpan: number, colSpan: number): void {
209
- deps.getRuntime().ui._ui_node_set_grid_placement(toBigIntHandle(handle), row, col, rowSpan, colSpan);
210
- },
211
- ui_set_bg_color(handle: AppHandleLike, color: number): void {
212
- deps.getRuntime().ui._ui_set_bg_color(toBigIntHandle(handle), color);
213
- },
214
- ui_set_box_style(
215
- handle: AppHandleLike,
216
- bgColor: number,
217
- topLeftRadius: number,
218
- topRightRadius: number,
219
- bottomRightRadius: number,
220
- bottomLeftRadius: number,
221
- borderWidth: number,
222
- borderColor: number,
223
- borderStyle: number,
224
- borderDashOn: number,
225
- borderDashOff: number,
226
- ): void {
227
- deps.getRuntime().ui._ui_set_box_style(
228
- toBigIntHandle(handle),
229
- bgColor,
230
- topLeftRadius,
231
- topRightRadius,
232
- bottomRightRadius,
233
- bottomLeftRadius,
234
- borderWidth,
235
- borderColor,
236
- borderStyle,
237
- borderDashOn,
238
- borderDashOff,
239
- );
240
- },
241
- ui_set_layer_effect(handle: AppHandleLike, opacity: number, blurSigma: number, blendMode: number): void {
242
- deps.getRuntime().ui._ui_set_layer_effect(toBigIntHandle(handle), opacity, blurSigma, blendMode);
243
- },
244
- ui_set_drop_shadow(
245
- handle: AppHandleLike,
246
- color: number,
247
- offsetX: number,
248
- offsetY: number,
249
- blurSigma: number,
250
- spread: number,
251
- ): void {
252
- deps.getRuntime().ui._ui_set_drop_shadow(toBigIntHandle(handle), color, offsetX, offsetY, blurSigma, spread);
253
- },
254
- ui_set_background_blur(handle: AppHandleLike, blurSigma: number): void {
255
- deps.getRuntime().ui._ui_set_background_blur(toBigIntHandle(handle), blurSigma);
256
- },
257
- ui_set_image(handle: AppHandleLike, textureId: number, objectFit: number): void {
258
- deps.getRuntime().ui._ui_set_image(toBigIntHandle(handle), textureId, objectFit);
259
- },
260
- ui_set_image_nine(
261
- handle: AppHandleLike,
262
- textureId: number,
263
- insetLeft: number,
264
- insetTop: number,
265
- insetRight: number,
266
- insetBottom: number,
267
- ): void {
268
- deps.getRuntime().ui._ui_set_image_nine(
269
- toBigIntHandle(handle),
270
- textureId,
271
- insetLeft,
272
- insetTop,
273
- insetRight,
274
- insetBottom,
275
- );
276
- },
277
- ui_set_svg(handle: AppHandleLike, svgId: number, tintColor: number): void {
278
- deps.getRuntime().ui._ui_set_svg(toBigIntHandle(handle), svgId, tintColor);
279
- },
280
- ui_set_linear_gradient(
281
- handle: AppHandleLike,
282
- startX: number,
283
- startY: number,
284
- endX: number,
285
- endY: number,
286
- stopCount: number,
287
- ): void {
288
- deps.pendingGradients.set(toBigIntHandle(handle).toString(), {
289
- startX,
290
- startY,
291
- endX,
292
- endY,
293
- stopCount,
294
- offsets: [],
295
- colors: [],
296
- });
297
- },
298
- ui_push_linear_gradient_stop(handle: AppHandleLike, offset: number, color: number): void {
299
- const runtime = deps.getRuntime();
300
- const key = toBigIntHandle(handle).toString();
301
- const pending = deps.pendingGradients.get(key);
302
- if (pending === undefined) {
303
- throw new Error('Gradient stop received before gradient header.');
304
- }
305
- pending.offsets.push(offset);
306
- pending.colors.push(color >>> 0);
307
- if (pending.offsets.length !== pending.stopCount) {
308
- return;
309
- }
310
- deps.pendingGradients.delete(key);
311
- deps.withUiGradientData(
312
- Float32Array.from(pending.offsets),
313
- Uint32Array.from(pending.colors),
314
- (uiOffsetsPtr, uiColorsPtr) => {
315
- runtime.ui._ui_set_linear_gradient(
316
- toBigIntHandle(handle),
317
- pending.startX,
318
- pending.startY,
319
- pending.endX,
320
- pending.endY,
321
- pending.stopCount,
322
- uiOffsetsPtr,
323
- uiColorsPtr,
324
- );
325
- },
326
- );
327
- },
328
- ui_set_clip_to_bounds(handle: AppHandleLike, clip: number): void {
329
- deps.getRuntime().ui._ui_set_clip_to_bounds(toBigIntHandle(handle), clip);
330
- },
331
- ui_set_visibility(handle: AppHandleLike, visibility: number): void {
332
- deps.getRuntime().ui._ui_set_visibility(toBigIntHandle(handle), visibility);
333
- },
334
- ui_set_interactive(handle: AppHandleLike, flag: number): void {
335
- deps.getRuntime().ui._ui_set_interactive(toBigIntHandle(handle), flag);
336
- },
337
- ui_set_scroll_proxy_target(handle: AppHandleLike, scrollHandle: AppHandleLike): void {
338
- deps.getRuntime().ui._ui_set_scroll_proxy_target(toBigIntHandle(handle), toBigIntHandle(scrollHandle));
339
- },
340
- ui_set_scroll_enabled(handle: AppHandleLike, enabledX: number, enabledY: number): void {
341
- deps.getRuntime().ui._ui_set_scroll_enabled(toBigIntHandle(handle), enabledX, enabledY);
342
- },
343
- ui_set_show_scrollbars(handle: AppHandleLike, showScrollbars: number): void {
344
- deps.getRuntime().ui._ui_set_show_scrollbars(toBigIntHandle(handle), showScrollbars);
345
- },
346
- ui_set_scroll_friction(handle: AppHandleLike, friction: number): void {
347
- deps.getRuntime().ui._ui_set_scroll_friction(toBigIntHandle(handle), friction);
348
- },
349
- ui_set_scroll_content_size(handle: AppHandleLike, contentWidth: number, contentHeight: number): void {
350
- deps.getRuntime().ui._ui_set_scroll_content_size(toBigIntHandle(handle), contentWidth, contentHeight);
351
- },
352
- ui_set_focusable(handle: AppHandleLike, flag: number, tabIndex: number): void {
353
- deps.getRuntime().ui._ui_set_focusable(toBigIntHandle(handle), flag, tabIndex);
354
- },
355
- ui_request_focus(handle: AppHandleLike): void {
356
- deps.getRuntime().ui._ui_request_focus(toBigIntHandle(handle));
357
- },
358
- ui_set_font(handle: AppHandleLike, fontId: number, size: number): void {
359
- const runtime = deps.getRuntime();
360
- void runtime.ensureFont(fontId).catch((error: unknown) => {
361
- const message = error instanceof Error ? error.message : String(error);
362
- console.error(`[fui_host] font ${String(fontId)} failed to load on demand: ${message}`);
363
- });
364
- runtime.ui._ui_set_font(toBigIntHandle(handle), fontId, size);
365
- },
366
- ui_set_line_height(handle: AppHandleLike, lineHeight: number): void {
367
- deps.getRuntime().ui._ui_set_line_height(toBigIntHandle(handle), lineHeight);
368
- },
369
- ui_register_font_fallback(fontId: number, fallbackFontId: number): void {
370
- deps.getRuntime().registerFontFallback(fontId, fallbackFontId);
371
- },
372
- ui_set_text_color(handle: AppHandleLike, color: number): void {
373
- deps.getRuntime().ui._ui_set_text_color(toBigIntHandle(handle), color);
374
- },
375
- ui_set_text_align(handle: AppHandleLike, align: number): void {
376
- deps.getRuntime().ui._ui_set_text_align(toBigIntHandle(handle), align);
377
- },
378
- ui_set_text_vertical_align(handle: AppHandleLike, align: number): void {
379
- deps.getRuntime().ui._ui_set_text_vertical_align(toBigIntHandle(handle), align);
380
- },
381
- ui_set_text_limits(handle: AppHandleLike, maxChars: number, maxLines: number): void {
382
- deps.getRuntime().ui._ui_set_text_limits(toBigIntHandle(handle), maxChars, maxLines);
383
- },
384
- ui_set_text_wrapping(handle: AppHandleLike, wrap: number): void {
385
- deps.getRuntime().ui._ui_set_text_wrapping(toBigIntHandle(handle), wrap);
386
- },
387
- ui_set_text_overflow(handle: AppHandleLike, overflow: number): void {
388
- deps.getRuntime().ui._ui_set_text_overflow(toBigIntHandle(handle), overflow);
389
- },
390
- ui_set_text_overflow_fade(handle: AppHandleLike, horizontal: number, vertical: number): void {
391
- deps.getRuntime().ui._ui_set_text_overflow_fade(toBigIntHandle(handle), horizontal, vertical);
392
- },
393
- ui_set_text_obscured(handle: AppHandleLike, obscured: number): void {
394
- deps.getRuntime().ui._ui_set_text_obscured(toBigIntHandle(handle), obscured);
395
- },
396
- ui_set_editable(handle: AppHandleLike, editable: number): void {
397
- deps.getRuntime().ui._ui_set_editable(toBigIntHandle(handle), editable);
398
- },
399
- ui_set_caret_color(handle: AppHandleLike, color: number): void {
400
- deps.getRuntime().ui._ui_set_caret_color(toBigIntHandle(handle), color);
401
- },
402
- ui_set_selectable(handle: AppHandleLike, selectable: number, selectionColor: number): void {
403
- deps.getRuntime().ui._ui_set_selectable(toBigIntHandle(handle), selectable, selectionColor);
404
- },
405
- ui_set_selection_area(handle: AppHandleLike, isArea: number): void {
406
- deps.getRuntime().ui._ui_set_selection_area(toBigIntHandle(handle), isArea);
407
- },
408
- ui_set_selection_area_barrier(handle: AppHandleLike, isBarrier: number): void {
409
- deps.getRuntime().ui._ui_set_selection_area_barrier(toBigIntHandle(handle), isBarrier);
410
- },
411
- ui_clear_selection(handle: AppHandleLike): void {
412
- deps.getRuntime().ui._ui_clear_selection(toBigIntHandle(handle));
413
- },
414
- ui_retarget_selection(fromHandle: AppHandleLike, toHandle: AppHandleLike): void {
415
- deps.getRuntime().ui._ui_retarget_selection(toBigIntHandle(fromHandle), toBigIntHandle(toHandle));
416
- },
417
- ui_is_point_in_selection(x: number, y: number): number {
418
- return deps.getRuntime().ui._ui_is_point_in_selection(x, y);
419
- },
420
- ui_set_text_selection_range(handle: AppHandleLike, selectionStart: number, selectionEnd: number): void {
421
- deps.getRuntime().ui._ui_set_text_selection_range(toBigIntHandle(handle), selectionStart, selectionEnd);
422
- },
423
- ui_clear_current_selection(): void {
424
- deps.getRuntime().ui._ui_clear_current_selection();
425
- },
426
- ui_copy_current_selection(): void {
427
- deps.getRuntime().ui._ui_copy_current_selection();
428
- },
429
- ui_can_undo_text_edit(handle: AppHandleLike): number {
430
- return deps.getRuntime().ui._ui_can_undo_text_edit(toBigIntHandle(handle));
431
- },
432
- ui_can_redo_text_edit(handle: AppHandleLike): number {
433
- return deps.getRuntime().ui._ui_can_redo_text_edit(toBigIntHandle(handle));
434
- },
435
- ui_has_text_selection(handle: AppHandleLike): number {
436
- return deps.getRuntime().ui._ui_has_text_selection(toBigIntHandle(handle));
437
- },
438
- ui_undo_text_edit(handle: AppHandleLike): void {
439
- deps.getRuntime().ui._ui_undo_text_edit(toBigIntHandle(handle));
440
- },
441
- ui_redo_text_edit(handle: AppHandleLike): void {
442
- deps.getRuntime().ui._ui_redo_text_edit(toBigIntHandle(handle));
443
- },
444
- ui_copy_text_selection(handle: AppHandleLike): void {
445
- deps.getRuntime().ui._ui_copy_text_selection(toBigIntHandle(handle));
446
- },
447
- ui_cut_text_selection(handle: AppHandleLike): void {
448
- deps.getRuntime().ui._ui_cut_text_selection(toBigIntHandle(handle));
449
- },
450
- ui_replace_text_range(handle: AppHandleLike, start: number, end: number, ptr: number, len: number, caret: number): void {
451
- deps.getRuntime().ui._ui_replace_text_range(toBigIntHandle(handle), start, end, ptr, len, caret);
452
- },
453
- ui_paste_text(handle: AppHandleLike): void {
454
- deps.getRuntime().ui._ui_paste_text(toBigIntHandle(handle));
455
- },
456
- ui_select_all_text(handle: AppHandleLike): void {
457
- deps.getRuntime().ui._ui_select_all_text(toBigIntHandle(handle));
458
- },
459
- ui_set_scroll_offset(handle: AppHandleLike, x: number, y: number): void {
460
- deps.getRuntime().ui._ui_set_scroll_offset(toBigIntHandle(handle), x, y);
461
- },
462
- ui_clear_momentum_scroll(): void {
463
- deps.getRuntime().ui._ui_clear_momentum_scroll();
464
- },
465
- ui_get_bounds(
466
- handle: AppHandleLike,
467
- outX: number,
468
- outY: number,
469
- outWidth: number,
470
- outHeight: number,
471
- ): number {
472
- const runtime = deps.getRuntime();
473
- const appMemory = deps.getCurrentMemory();
474
- const boundsPtr = runtime.ui._malloc(16);
475
- const boundsOffset = Number(boundsPtr);
476
- runtime.ui.refreshHeapViews?.();
477
- try {
478
- const found = runtime.ui._ui_get_bounds(
479
- toBigIntHandle(handle),
480
- deps.normalizePointer(boundsPtr),
481
- addUiPointer(runtime, boundsPtr, 4),
482
- addUiPointer(runtime, boundsPtr, 8),
483
- addUiPointer(runtime, boundsPtr, 12),
484
- );
485
- if (found === 0) {
486
- return 0;
487
- }
488
-
489
- runtime.ui.refreshHeapViews?.();
490
- const uiView = new DataView(runtime.ui.HEAPU8.buffer);
491
- const appView = new DataView(appMemory.buffer);
492
- appView.setFloat32(outX, uiView.getFloat32(boundsOffset, true), true);
493
- appView.setFloat32(outY, uiView.getFloat32(boundsOffset + 4, true), true);
494
- appView.setFloat32(outWidth, uiView.getFloat32(boundsOffset + 8, true), true);
495
- appView.setFloat32(outHeight, uiView.getFloat32(boundsOffset + 12, true), true);
496
- return 1;
497
- } finally {
498
- runtime.ui._free(boundsPtr);
499
- }
500
- },
501
- ui_set_text(handle: AppHandleLike, ptr: number, len: number): void {
502
- const runtime = deps.getRuntime();
503
- const text = deps.readAppUtf8(ptr, len);
504
- deps.withUiUtf8(text, (uiPtr, uiLen) => {
505
- runtime.ui._ui_set_text(toBigIntHandle(handle), uiPtr, uiLen);
506
- });
507
- },
508
- ui_set_text_style_runs(handle: AppHandleLike, runCount: number, runsWordsPtr: AppHandleLike): void {
509
- const runtime = deps.getRuntime();
510
- const clampedRunCount = Math.max(0, runCount | 0);
511
- if (clampedRunCount === 0) {
512
- runtime.ui._ui_set_text_style_runs(toBigIntHandle(handle), 0, deps.zeroPointer());
513
- return;
514
- }
515
- const byteLength = clampedRunCount * 7 * 4;
516
- const appPtr = Number(runsWordsPtr);
517
- const appBytes = new Uint8Array(deps.getCurrentMemory().buffer, appPtr, byteLength);
518
- const runs = new Uint32Array(appBytes.buffer, appBytes.byteOffset, clampedRunCount * 7);
519
- const requestedFonts = new Set<number>();
520
- for (let index = 0; index < clampedRunCount; index += 1) {
521
- const fontId = runs[(index * 7) + 2] ?? 0;
522
- if (fontId !== 0) {
523
- requestedFonts.add(fontId);
524
- }
525
- }
526
- for (const fontId of requestedFonts) {
527
- void runtime.ensureFont(fontId).catch((error: unknown) => {
528
- const message = error instanceof Error ? error.message : String(error);
529
- console.error(`[fui_host] rich text font ${String(fontId)} failed to load on demand: ${message}`);
530
- });
531
- }
532
- const uiPtr = runtime.ui._malloc(byteLength);
533
- try {
534
- runtime.ui.HEAPU8.set(appBytes, Number(uiPtr));
535
- runtime.ui._ui_set_text_style_runs(
536
- toBigIntHandle(handle),
537
- clampedRunCount,
538
- deps.normalizePointer(uiPtr),
539
- );
540
- } finally {
541
- runtime.ui._free(uiPtr);
542
- }
543
- },
544
- ui_commit_frame(): void {
545
- const runtime = deps.getRuntime();
546
- runtime.commitFrame();
547
- deps.queueHarnessFrame();
548
- },
549
- ui_resize_window(width: number, height: number): void {
550
- deps.getRuntime().ui._ui_resize_window(width, height);
551
- },
552
- };
553
- }
@@ -1,47 +0,0 @@
1
- import { getHostServiceImportNames, type HostServicesDefinition } from '../host-services';
2
-
3
- export class WasmModuleCache {
4
- private readonly wasmByteCache = new Map<string, Promise<ArrayBuffer>>();
5
- private readonly wasmModuleCache = new Map<string, Promise<WebAssembly.Module>>();
6
-
7
- async fetchWasmBytes(wasmPath: string): Promise<ArrayBuffer> {
8
- const cached = this.wasmByteCache.get(wasmPath);
9
- if (cached !== undefined) {
10
- return cached;
11
- }
12
- const fetchPromise = fetch(wasmPath, { cache: 'no-store' }).then(async (response) => {
13
- if (!response.ok) {
14
- throw new Error(`Failed to load wasm app: ${wasmPath}`);
15
- }
16
- return response.arrayBuffer();
17
- });
18
- this.wasmByteCache.set(wasmPath, fetchPromise);
19
- return fetchPromise;
20
- }
21
-
22
- async loadWasmModule(wasmPath: string): Promise<WebAssembly.Module> {
23
- const cached = this.wasmModuleCache.get(wasmPath);
24
- if (cached !== undefined) {
25
- return cached;
26
- }
27
- const compilePromise = this.fetchWasmBytes(wasmPath).then((bytes) => WebAssembly.compile(bytes));
28
- this.wasmModuleCache.set(wasmPath, compilePromise);
29
- return compilePromise;
30
- }
31
- }
32
-
33
- export function validateAppImports(wasmModule: WebAssembly.Module, hostServices: HostServicesDefinition | undefined): void {
34
- const allowedHostServiceImports = getHostServiceImportNames(hostServices);
35
- for (const imported of WebAssembly.Module.imports(wasmModule)) {
36
- if (imported.kind !== 'function') {
37
- throw new Error(`App import ${imported.module}.${imported.name} is not allowed.`);
38
- }
39
- if (imported.module === 'effindom_v2_ui' || imported.module === 'fui_host' || imported.module === 'env') {
40
- continue;
41
- }
42
- if (imported.module === 'fui_host_service' && allowedHostServiceImports.has(imported.name)) {
43
- continue;
44
- }
45
- throw new Error(`App import ${imported.module}.${imported.name} is not allowed.`);
46
- }
47
- }
@@ -1,89 +0,0 @@
1
- /// <reference lib="webworker" />
2
-
3
- interface FileProcessingWorkerStartMessage {
4
- readonly type: "start";
5
- readonly file: File;
6
- readonly chunkSize: number;
7
- }
8
-
9
- interface FileProcessingWorkerNextMessage {
10
- readonly type: "next";
11
- }
12
-
13
- interface FileProcessingWorkerCancelMessage {
14
- readonly type: "cancel";
15
- }
16
-
17
- type FileProcessingWorkerInboundMessage =
18
- | FileProcessingWorkerStartMessage
19
- | FileProcessingWorkerNextMessage
20
- | FileProcessingWorkerCancelMessage;
21
-
22
- interface FileProcessingWorkerChunkMessage {
23
- readonly type: "chunk";
24
- readonly offsetBytes: number;
25
- readonly bytes: ArrayBuffer;
26
- readonly copiedBytes: number;
27
- readonly totalBytes: number;
28
- }
29
-
30
- interface FileProcessingWorkerErrorMessage {
31
- readonly type: "error";
32
- readonly message: string;
33
- }
34
-
35
- let activeFile: File | null = null;
36
- let activeChunkSize = 0;
37
- let activeOffsetBytes = 0;
38
- const workerScope = self as DedicatedWorkerGlobalScope;
39
-
40
- function describeError(error: unknown): string {
41
- return error instanceof Error ? error.message : String(error);
42
- }
43
-
44
- function postNextChunk(): void {
45
- const file = activeFile;
46
- if (file === null) {
47
- return;
48
- }
49
- try {
50
- const offsetBytes = activeOffsetBytes;
51
- const nextOffset = Math.min(file.size, activeOffsetBytes + activeChunkSize);
52
- const reader = new FileReaderSync();
53
- const bytes = reader.readAsArrayBuffer(file.slice(activeOffsetBytes, nextOffset));
54
- activeOffsetBytes = nextOffset;
55
- const message: FileProcessingWorkerChunkMessage = {
56
- type: "chunk",
57
- offsetBytes,
58
- bytes,
59
- copiedBytes: activeOffsetBytes,
60
- totalBytes: file.size,
61
- };
62
- workerScope.postMessage(message, [bytes]);
63
- } catch (error: unknown) {
64
- const failure: FileProcessingWorkerErrorMessage = {
65
- type: "error",
66
- message: describeError(error),
67
- };
68
- workerScope.postMessage(failure);
69
- }
70
- }
71
-
72
- workerScope.onmessage = (event: MessageEvent<FileProcessingWorkerInboundMessage>) => {
73
- const message = event.data;
74
- if (message.type === "cancel") {
75
- activeFile = null;
76
- activeOffsetBytes = 0;
77
- return;
78
- }
79
- if (message.type === "start") {
80
- activeFile = message.file;
81
- activeChunkSize = Math.max(1, Math.floor(message.chunkSize));
82
- activeOffsetBytes = 0;
83
- postNextChunk();
84
- return;
85
- }
86
- if (activeFile !== null) {
87
- postNextChunk();
88
- }
89
- };