@effindomv2/fui-as 0.1.37 → 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.
- package/browser/routed-app-conventions.ts +1 -1
- package/browser/src/common-harness.ts +1 -27
- package/browser/src/index.ts +19 -26
- package/browser/src/routed-harness.ts +1 -194
- package/browser/src/shared-browser.ts +6 -0
- package/package.json +23 -13
- package/scripts/build.sh +47 -46
- package/scripts/framework-host-services.ts +1 -1
- package/scripts/generate-host-events.ts +15 -241
- package/scripts/generate-host-services.ts +13 -261
- package/scripts/hostgen/assemblyscript-host-events.ts +165 -0
- package/scripts/hostgen/assemblyscript-host-services.ts +207 -0
- package/scripts/hostgen/common.ts +73 -0
- package/scripts/hostgen/registry.ts +159 -0
- package/src/Fui.ts +65 -5
- package/src/FuiExports.ts +12 -1
- package/src/bindings/ui.ts +157 -8
- package/src/controls/Button.ts +98 -71
- package/src/controls/Checkbox.ts +23 -21
- package/src/controls/ComboBox.ts +1201 -0
- package/src/controls/ContextMenu.ts +279 -165
- package/src/controls/Dialog.ts +91 -17
- package/src/controls/Dropdown.ts +101 -333
- package/src/controls/NavLink.ts +29 -6
- package/src/controls/Popup.ts +10 -5
- package/src/controls/ProgressBar.ts +1 -2
- package/src/controls/RadioButton.ts +34 -13
- package/src/controls/RadioGroup.ts +32 -19
- package/src/controls/Slider.ts +21 -23
- package/src/controls/Switch.ts +34 -17
- package/src/controls/index.ts +2 -1
- package/src/controls/internal/ButtonPresenter.ts +5 -2
- package/src/controls/internal/CheckboxIndicatorPresenter.ts +10 -10
- package/src/controls/internal/DropdownChevronPresenter.ts +3 -3
- package/src/controls/internal/DropdownFieldPresenter.ts +6 -6
- package/src/controls/internal/DropdownOptionRowPresenter.ts +5 -4
- package/src/controls/internal/PressableLabeledControl.ts +4 -7
- package/src/controls/internal/RadioIndicatorPresenter.ts +7 -7
- package/src/controls/internal/SelectablePopupList.ts +463 -0
- package/src/controls/internal/SliderPresenter.ts +5 -5
- package/src/controls/internal/SwitchIndicatorPresenter.ts +63 -17
- package/src/controls/internal/TextInputCore.ts +307 -41
- package/src/controls/internal/TextInputPresenter.ts +2 -2
- package/src/controls/templating.ts +10 -0
- package/src/core/Application.ts +17 -8
- package/src/core/Bitmap.ts +192 -3
- package/src/core/ContextMenuManager.ts +128 -44
- package/src/core/DebugApi.ts +17 -2
- package/src/core/DragGesture.ts +8 -7
- package/src/core/EventRouter.ts +332 -12
- package/src/core/Fetch.ts +15 -7
- package/src/core/FetchFfi.ts +1 -15
- package/src/core/File.ts +75 -34
- package/src/core/FocusAdornerManager.ts +3 -3
- package/src/core/FocusVisibility.ts +7 -0
- package/src/core/FrameScheduler.ts +104 -5
- package/src/core/ImageSampling.ts +43 -0
- package/src/core/Logger.ts +2 -0
- package/src/core/MobileTextSelectionToolbarManager.ts +901 -0
- package/src/core/Node.ts +1039 -97
- package/src/core/Platform.ts +16 -16
- package/src/core/SelectionHandleAdornerManager.ts +697 -0
- package/src/core/Theme.ts +34 -20
- package/src/core/ToolTipManager.ts +3 -3
- package/src/core/Typography.ts +411 -19
- package/src/core/Worker.ts +69 -33
- package/src/core/event_exports.ts +123 -5
- package/src/core/ffi.ts +5 -865
- package/src/core/generated/FetchHostAbi.ts +10 -0
- package/src/core/generated/FrameworkHostServices.ts +1 -1
- package/src/core/generated/HostAbi.ts +220 -0
- package/src/core/generated/UiAbi.ts +356 -0
- package/src/core/generated/UiEnums.ts +186 -0
- package/src/drawing/DrawCallback.ts +17 -1
- package/src/drawing/DrawContext.ts +140 -32
- package/src/nodes/CustomDrawable.ts +8 -1
- package/src/nodes/FlexBox.ts +40 -11
- package/src/nodes/Grid.ts +5 -5
- package/src/nodes/Image.ts +20 -1
- package/src/nodes/RichText.ts +36 -25
- package/src/nodes/ScrollBar.ts +2 -1
- package/src/nodes/ScrollBox.ts +7 -2
- package/src/nodes/ScrollView.ts +17 -6
- package/src/nodes/Svg.ts +18 -1
- package/src/nodes/Text.ts +1 -1
- package/src/nodes/TextCore.ts +115 -20
- package/src/nodes/index.ts +1 -1
- package/src/text/DynamicTextLayout.ts +275 -0
- package/src/text/TextLayout.ts +308 -0
- package/src/worker/Worker.ts +3 -36
- package/src/worker/WorkerJob.ts +5 -9
- package/src/worker/ffi.ts +0 -6
- package/browser/src/common-harness/host-imports.ts +0 -447
- package/browser/src/common-harness/interop.ts +0 -39
- package/browser/src/common-harness/managed-harness-bitmap-host.ts +0 -92
- package/browser/src/common-harness/managed-harness-canvas-host.ts +0 -72
- package/browser/src/common-harness/managed-harness-fetch-host.ts +0 -201
- package/browser/src/common-harness/managed-harness-file-host.ts +0 -1066
- package/browser/src/common-harness/managed-harness-file-payloads.ts +0 -143
- package/browser/src/common-harness/managed-harness-file-types.ts +0 -71
- package/browser/src/common-harness/managed-harness-session.ts +0 -15
- package/browser/src/common-harness/managed-harness.ts +0 -1472
- package/browser/src/common-harness/managed-history.ts +0 -168
- package/browser/src/common-harness/persisted-restore-policy.ts +0 -50
- package/browser/src/common-harness/persisted-ui-state-controller.ts +0 -309
- package/browser/src/common-harness/text-session-bridge.ts +0 -452
- package/browser/src/common-harness/types.ts +0 -206
- package/browser/src/common-harness/ui-chrome.ts +0 -206
- package/browser/src/common-harness/ui-imports.ts +0 -559
- package/browser/src/common-harness/wasm-module-cache.ts +0 -47
- package/browser/src/file-processing-worker.ts +0 -89
- package/browser/src/host-events.ts +0 -118
- package/browser/src/host-services.ts +0 -483
- package/browser/src/persisted-ui-state.ts +0 -206
- package/browser/src/routed-app-conventions.ts +0 -292
- package/browser/src/worker-bootstrap.ts +0 -916
- package/browser/src/worker-manager.ts +0 -234
- package/browser/src/worker-types.ts +0 -68
package/src/core/Theme.ts
CHANGED
|
@@ -55,25 +55,35 @@ export class Spacing {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
export class Fonts {
|
|
58
|
+
readonly bodyStack: FontStack;
|
|
59
|
+
readonly headingStack: FontStack;
|
|
60
|
+
readonly monoStack: FontStack;
|
|
61
|
+
readonly monoBoldStack: FontStack;
|
|
58
62
|
readonly bodyFamily: FontFamily;
|
|
59
63
|
readonly headingFamily: FontFamily;
|
|
60
64
|
readonly monoFamily: FontFamily;
|
|
61
65
|
|
|
62
66
|
constructor(
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
bodyStack: FontStack,
|
|
68
|
+
headingStack: FontStack,
|
|
65
69
|
readonly sizeBody: f32,
|
|
66
70
|
readonly sizeHeading: f32,
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
monoStack: FontStack | null = null,
|
|
72
|
+
monoBoldStack: FontStack | null = null,
|
|
69
73
|
readonly sizeMono: f32 = sizeBody,
|
|
70
74
|
bodyFamily: FontFamily | null = null,
|
|
71
75
|
headingFamily: FontFamily | null = null,
|
|
72
76
|
monoFamily: FontFamily | null = null,
|
|
73
77
|
) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
this.
|
|
78
|
+
const resolvedMonoStack = monoStack !== null ? changetype<FontStack>(monoStack) : bodyStack;
|
|
79
|
+
const resolvedMonoBoldStack = monoBoldStack !== null ? changetype<FontStack>(monoBoldStack) : resolvedMonoStack;
|
|
80
|
+
this.bodyStack = bodyStack;
|
|
81
|
+
this.headingStack = headingStack;
|
|
82
|
+
this.monoStack = resolvedMonoStack;
|
|
83
|
+
this.monoBoldStack = resolvedMonoBoldStack;
|
|
84
|
+
this.bodyFamily = bodyFamily !== null ? changetype<FontFamily>(bodyFamily) : FontFamily.regularBold(bodyStack, headingStack);
|
|
85
|
+
this.headingFamily = headingFamily !== null ? changetype<FontFamily>(headingFamily) : FontFamily.regularBold(headingStack, headingStack);
|
|
86
|
+
this.monoFamily = monoFamily !== null ? changetype<FontFamily>(monoFamily) : FontFamily.regularBold(resolvedMonoStack, resolvedMonoBoldStack);
|
|
77
87
|
}
|
|
78
88
|
}
|
|
79
89
|
|
|
@@ -83,7 +93,6 @@ export class ContextMenuItemTheme {
|
|
|
83
93
|
readonly hoverBackground: u32,
|
|
84
94
|
readonly textColor: u32,
|
|
85
95
|
readonly cornerRadius: f32,
|
|
86
|
-
readonly fontId: u32,
|
|
87
96
|
readonly fontFamily: FontFamily,
|
|
88
97
|
readonly fontSize: f32,
|
|
89
98
|
readonly height: f32,
|
|
@@ -115,7 +124,6 @@ export class ToolTipTheme {
|
|
|
115
124
|
readonly panelShadowColor: u32,
|
|
116
125
|
readonly panelCornerRadius: f32,
|
|
117
126
|
readonly textColor: u32,
|
|
118
|
-
readonly fontId: u32,
|
|
119
127
|
readonly fontFamily: FontFamily,
|
|
120
128
|
readonly fontSize: f32,
|
|
121
129
|
readonly maxWidth: f32,
|
|
@@ -203,20 +211,20 @@ function estimateThemeDark(theme: Theme): bool {
|
|
|
203
211
|
}
|
|
204
212
|
|
|
205
213
|
const DEFAULT_SPACING = new Spacing(4.0, 8.0, 16.0, 24.0, 32.0);
|
|
206
|
-
const DEFAULT_BODY_STACK =
|
|
207
|
-
const DEFAULT_HEADING_STACK =
|
|
208
|
-
const DEFAULT_MONO_STACK =
|
|
209
|
-
const DEFAULT_MONO_BOLD_STACK =
|
|
214
|
+
const DEFAULT_BODY_STACK = FontStack._fromId(1)._fallbackId(3);
|
|
215
|
+
const DEFAULT_HEADING_STACK = FontStack._fromId(2)._fallbackId(3);
|
|
216
|
+
const DEFAULT_MONO_STACK = FontStack._fromId(7)._fallbackId(4)._fallbackId(3);
|
|
217
|
+
const DEFAULT_MONO_BOLD_STACK = FontStack._fromId(8)._fallbackId(4)._fallbackId(3);
|
|
210
218
|
|
|
211
219
|
const DEFAULT_FONTS = new Fonts(
|
|
212
|
-
|
|
213
|
-
|
|
220
|
+
DEFAULT_BODY_STACK,
|
|
221
|
+
DEFAULT_HEADING_STACK,
|
|
214
222
|
16.0,
|
|
215
223
|
24.0,
|
|
216
|
-
|
|
217
|
-
|
|
224
|
+
DEFAULT_MONO_STACK,
|
|
225
|
+
DEFAULT_MONO_BOLD_STACK,
|
|
218
226
|
15.0,
|
|
219
|
-
|
|
227
|
+
FontFamily._fromIds(1, 2, 5, 6),
|
|
220
228
|
FontFamily.regularBoldStacks(DEFAULT_HEADING_STACK, DEFAULT_HEADING_STACK),
|
|
221
229
|
FontFamily.regularBoldStacks(DEFAULT_MONO_STACK, DEFAULT_MONO_BOLD_STACK),
|
|
222
230
|
);
|
|
@@ -289,7 +297,6 @@ export function generateTheme(isDark: bool, accentColor: u32 = DEFAULT_ACCENT_CO
|
|
|
289
297
|
contextMenuItemHover,
|
|
290
298
|
textPrimary,
|
|
291
299
|
isDark ? 10.0 : 9.0,
|
|
292
|
-
DEFAULT_FONTS.body,
|
|
293
300
|
DEFAULT_FONTS.bodyFamily,
|
|
294
301
|
13.0,
|
|
295
302
|
30.0,
|
|
@@ -305,7 +312,6 @@ export function generateTheme(isDark: bool, accentColor: u32 = DEFAULT_ACCENT_CO
|
|
|
305
312
|
toolTipPanelShadowColor,
|
|
306
313
|
isDark ? 12.0 : 10.0,
|
|
307
314
|
textPrimary,
|
|
308
|
-
DEFAULT_FONTS.body,
|
|
309
315
|
DEFAULT_FONTS.bodyFamily,
|
|
310
316
|
13.0,
|
|
311
317
|
280.0,
|
|
@@ -377,3 +383,11 @@ export function handleSystemDarkModeChanged(isDark: bool): Theme {
|
|
|
377
383
|
systemAccentColor = normalizeAccentColor(ffi.fui_get_accent_color());
|
|
378
384
|
return applySystemTheme();
|
|
379
385
|
}
|
|
386
|
+
|
|
387
|
+
export function handleSystemAccentColorChanged(color: u32): Theme {
|
|
388
|
+
systemAccentColor = normalizeAccentColor(color);
|
|
389
|
+
if (themeSource != ThemeSource.System) {
|
|
390
|
+
return activeTheme.value;
|
|
391
|
+
}
|
|
392
|
+
return applySystemTheme();
|
|
393
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as ui from "../bindings/ui";
|
|
2
2
|
import { PopupPresenter } from "../controls/internal/PopupPresenter";
|
|
3
3
|
import { FlexBox, Portal, TextCore } from "../nodes";
|
|
4
|
-
import {
|
|
4
|
+
import { FlexDirection, HandleValue, Unit } from "./ffi";
|
|
5
5
|
import { flushCommit } from "./FrameScheduler";
|
|
6
6
|
import { keyboardFocusVisible } from "./FocusVisibility";
|
|
7
7
|
import { cancelTimer, scheduleTimer } from "./Timers";
|
|
@@ -314,14 +314,14 @@ export class ToolTipManager {
|
|
|
314
314
|
const panelBackground = toolTip.hasPanelColorOverride ? toolTip.panelBackgroundColor : theme.panelBackground;
|
|
315
315
|
const textColor = toolTip.hasTextColorOverride ? toolTip.tooltipTextColor : theme.textColor;
|
|
316
316
|
labelNode.text(toolTip.contentText)
|
|
317
|
-
.font(theme.fontId, theme.fontSize)
|
|
318
317
|
.fontFamily(theme.fontFamily)
|
|
318
|
+
.fontSize(theme.fontSize)
|
|
319
319
|
.textColor(textColor)
|
|
320
320
|
.width(0.0, Unit.Auto)
|
|
321
321
|
.height(0.0, Unit.Auto);
|
|
322
322
|
panelNode.padding(theme.paddingLeft, theme.paddingTop, theme.paddingRight, theme.paddingBottom)
|
|
323
323
|
.cornerRadius(theme.panelCornerRadius)
|
|
324
|
-
.border(1.0, theme.panelBorderColor
|
|
324
|
+
.border(1.0, theme.panelBorderColor)
|
|
325
325
|
.dropShadow(theme.panelShadowColor, 0.0, theme.shadowOffsetY, theme.shadowBlur, theme.shadowSpread)
|
|
326
326
|
.bgColor(panelBackground)
|
|
327
327
|
.width(0.0, Unit.Auto)
|
package/src/core/Typography.ts
CHANGED
|
@@ -18,6 +18,7 @@ const MAX_FONT_SCORE: i32 = 0x7fffffff;
|
|
|
18
18
|
const FIRST_DYNAMIC_FONT_ID: u32 = 1024;
|
|
19
19
|
|
|
20
20
|
let nextDynamicFontId: u32 = FIRST_DYNAMIC_FONT_ID;
|
|
21
|
+
const loadedFontIds: Array<u32> = new Array<u32>();
|
|
21
22
|
|
|
22
23
|
function absI32(value: i32): i32 {
|
|
23
24
|
return value < 0 ? -value : value;
|
|
@@ -29,9 +30,206 @@ function allocateDynamicFontId(): u32 {
|
|
|
29
30
|
return allocated;
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
export class FontFaceLoadedEventArgs {
|
|
34
|
+
readonly font: FontFace;
|
|
35
|
+
readonly fontId: u32;
|
|
36
|
+
|
|
37
|
+
constructor(fontId: u32) {
|
|
38
|
+
this.fontId = fontId;
|
|
39
|
+
this.font = FontFace._fromId(fontId);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class FontsLoadedEventArgs {
|
|
44
|
+
readonly fontIds: Array<u32>;
|
|
45
|
+
|
|
46
|
+
constructor(fontIds: Array<u32>) {
|
|
47
|
+
this.fontIds = fontIds;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class FontStackLoadedEventArgs {
|
|
52
|
+
readonly stack: FontStack;
|
|
53
|
+
readonly fontIds: Array<u32>;
|
|
54
|
+
|
|
55
|
+
constructor(stack: FontStack, fontIds: Array<u32>) {
|
|
56
|
+
this.stack = stack;
|
|
57
|
+
this.fontIds = fontIds;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type FontLoadedHandler<Owner> = (owner: Owner, event: FontFaceLoadedEventArgs) => void;
|
|
62
|
+
export type FontReadyHandler<Owner> = (owner: Owner, event: FontsLoadedEventArgs) => void;
|
|
63
|
+
export type FontStackLoadedHandler<Owner> = (owner: Owner, event: FontStackLoadedEventArgs) => void;
|
|
64
|
+
|
|
65
|
+
abstract class FontLoadedRegistration {
|
|
66
|
+
abstract invoke(fontId: u32): void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
abstract class FontReadyRegistration {
|
|
70
|
+
abstract invoke(): void;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Callback wrappers — AS can't nest function types in generics
|
|
74
|
+
class FontLoadedCallback extends FontLoadedRegistration {
|
|
75
|
+
constructor(
|
|
76
|
+
readonly fontId: u32,
|
|
77
|
+
readonly cb: (event: FontFaceLoadedEventArgs) => void,
|
|
78
|
+
) {
|
|
79
|
+
super();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
invoke(_fontId: u32): void {
|
|
83
|
+
this.cb(new FontFaceLoadedEventArgs(this.fontId));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
class FontReadyCallback extends FontReadyRegistration {
|
|
88
|
+
constructor(
|
|
89
|
+
private readonly fontIds: Array<u32>,
|
|
90
|
+
readonly cb: (event: FontsLoadedEventArgs) => void,
|
|
91
|
+
) {
|
|
92
|
+
super();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
invoke(): void {
|
|
96
|
+
this.cb(new FontsLoadedEventArgs(this.fontIds));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
class FontReadyHandlerRegistration<Owner> extends FontReadyRegistration {
|
|
101
|
+
constructor(
|
|
102
|
+
private readonly fontIds: Array<u32>,
|
|
103
|
+
private readonly owner: Owner,
|
|
104
|
+
private readonly handler: FontReadyHandler<Owner>,
|
|
105
|
+
) {
|
|
106
|
+
super();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
invoke(): void {
|
|
110
|
+
this.handler(this.owner, new FontsLoadedEventArgs(this.fontIds));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
class FontLoadedHandlerRegistration<Owner> extends FontLoadedRegistration {
|
|
115
|
+
constructor(
|
|
116
|
+
private readonly fontId: u32,
|
|
117
|
+
private readonly owner: Owner,
|
|
118
|
+
private readonly handler: FontLoadedHandler<Owner>,
|
|
119
|
+
) {
|
|
120
|
+
super();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
invoke(_fontId: u32): void {
|
|
124
|
+
this.handler(this.owner, new FontFaceLoadedEventArgs(this.fontId));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
class FontStackLoadedCallback extends FontReadyRegistration {
|
|
129
|
+
constructor(
|
|
130
|
+
private readonly stack: FontStack,
|
|
131
|
+
private readonly cb: (event: FontStackLoadedEventArgs) => void,
|
|
132
|
+
) {
|
|
133
|
+
super();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
invoke(): void {
|
|
137
|
+
this.cb(new FontStackLoadedEventArgs(this.stack, this.stack.requiredFontIds()));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
class FontStackLoadedHandlerRegistration<Owner> extends FontReadyRegistration {
|
|
142
|
+
constructor(
|
|
143
|
+
private readonly stack: FontStack,
|
|
144
|
+
private readonly owner: Owner,
|
|
145
|
+
private readonly handler: FontStackLoadedHandler<Owner>,
|
|
146
|
+
) {
|
|
147
|
+
super();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
invoke(): void {
|
|
151
|
+
this.handler(this.owner, new FontStackLoadedEventArgs(this.stack, this.stack.requiredFontIds()));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
class FontLoadBarrierCallback extends FontLoadedRegistration {
|
|
156
|
+
constructor(private readonly barrier: FontLoadBarrier) {
|
|
157
|
+
super();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
invoke(_fontId: u32): void {
|
|
161
|
+
this.barrier.notify();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
class FontLoadBarrier {
|
|
166
|
+
private done: bool = false;
|
|
167
|
+
|
|
168
|
+
constructor(
|
|
169
|
+
private readonly fontIds: Array<u32>,
|
|
170
|
+
private readonly callback: FontReadyRegistration,
|
|
171
|
+
) {}
|
|
172
|
+
|
|
173
|
+
notify(): void {
|
|
174
|
+
if (this.done) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (!areFontIdsLoaded(this.fontIds)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.done = true;
|
|
181
|
+
this.callback.invoke();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function isPreloadedBuiltInFont(fontId: u32): bool {
|
|
186
|
+
return fontId >= 1 && fontId <= 6;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function pushUniqueFontId(fontIds: Array<u32>, fontId: u32): void {
|
|
190
|
+
if (fontId == 0) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
for (let index = 0; index < fontIds.length; ++index) {
|
|
194
|
+
if (unchecked(fontIds[index]) == fontId) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
fontIds.push(fontId);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function markFontLoaded(fontId: u32): void {
|
|
202
|
+
pushUniqueFontId(loadedFontIds, fontId);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function normalizeFontIds(fontIds: Array<u32>): Array<u32> {
|
|
206
|
+
const unique = new Array<u32>();
|
|
207
|
+
for (let index = 0; index < fontIds.length; ++index) {
|
|
208
|
+
pushUniqueFontId(unique, unchecked(fontIds[index]));
|
|
209
|
+
}
|
|
210
|
+
return unique;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function areFontIdsLoaded(fontIds: Array<u32>): bool {
|
|
214
|
+
for (let index = 0; index < fontIds.length; ++index) {
|
|
215
|
+
if (!FontFace.isLoaded(unchecked(fontIds[index]))) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
|
|
32
222
|
export class FontFace {
|
|
223
|
+
private static readonly registrations: Array<FontLoadedRegistration> = new Array();
|
|
224
|
+
private static readonly regFontIds: Array<u32> = new Array();
|
|
225
|
+
|
|
33
226
|
constructor(readonly id: u32) {}
|
|
34
227
|
|
|
228
|
+
/** @internal */
|
|
229
|
+
static _fromId(id: u32): FontFace {
|
|
230
|
+
return new FontFace(id);
|
|
231
|
+
}
|
|
232
|
+
|
|
35
233
|
static load(url: string, id: u32 = allocateDynamicFontId()): FontFace {
|
|
36
234
|
return new FontFace(id).load(url);
|
|
37
235
|
}
|
|
@@ -43,15 +241,113 @@ export class FontFace {
|
|
|
43
241
|
ui.loadFont(this.id, url);
|
|
44
242
|
return this;
|
|
45
243
|
}
|
|
244
|
+
|
|
245
|
+
onLoaded(callback: (event: FontFaceLoadedEventArgs) => void): this {
|
|
246
|
+
if (FontFace.isLoaded(this.id)) {
|
|
247
|
+
callback(new FontFaceLoadedEventArgs(this.id));
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
FontFace.registrations.push(new FontLoadedCallback(this.id, callback));
|
|
251
|
+
FontFace.regFontIds.push(this.id);
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
onLoadedWith<Owner>(owner: Owner, handler: FontLoadedHandler<Owner>): this {
|
|
256
|
+
FontFace.whenLoadedWith<Owner>(this.id, owner, handler);
|
|
257
|
+
return this;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
isLoaded(): bool {
|
|
261
|
+
return FontFace.isLoaded(this.id);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
static isLoaded(fontId: u32): bool {
|
|
265
|
+
if (fontId == 0 || isPreloadedBuiltInFont(fontId)) {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
for (let index = 0; index < loadedFontIds.length; ++index) {
|
|
269
|
+
if (unchecked(loadedFontIds[index]) == fontId) {
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
static whenLoaded(fontId: u32, callback: (event: FontFaceLoadedEventArgs) => void): void {
|
|
277
|
+
if (FontFace.isLoaded(fontId)) {
|
|
278
|
+
callback(new FontFaceLoadedEventArgs(fontId));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
FontFace.registrations.push(new FontLoadedCallback(fontId, callback));
|
|
282
|
+
FontFace.regFontIds.push(fontId);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static whenLoadedWith<Owner>(fontId: u32, owner: Owner, handler: FontLoadedHandler<Owner>): void {
|
|
286
|
+
if (FontFace.isLoaded(fontId)) {
|
|
287
|
+
handler(owner, new FontFaceLoadedEventArgs(fontId));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
FontFace.registrations.push(new FontLoadedHandlerRegistration<Owner>(fontId, owner, handler));
|
|
291
|
+
FontFace.regFontIds.push(fontId);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
static whenFontsLoaded(fontIds: Array<u32>, callback: (event: FontsLoadedEventArgs) => void): void {
|
|
295
|
+
const uniqueFontIds = normalizeFontIds(fontIds);
|
|
296
|
+
FontFace.whenFontsLoadedWithRegistration(uniqueFontIds, new FontReadyCallback(uniqueFontIds, callback));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
static whenFontsLoadedWith<Owner>(fontIds: Array<u32>, owner: Owner, callback: FontReadyHandler<Owner>): void {
|
|
300
|
+
const uniqueFontIds = normalizeFontIds(fontIds);
|
|
301
|
+
FontFace.whenFontsLoadedWithRegistration(uniqueFontIds, new FontReadyHandlerRegistration<Owner>(uniqueFontIds, owner, callback));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static whenFontsLoadedFor<Owner>(fontIds: Array<u32>, owner: Owner, callback: FontReadyHandler<Owner>): void {
|
|
305
|
+
FontFace.whenFontsLoadedWith<Owner>(fontIds, owner, callback);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private static whenFontsLoadedWithRegistration(fontIds: Array<u32>, callback: FontReadyRegistration): void {
|
|
309
|
+
const uniqueFontIds = fontIds;
|
|
310
|
+
if (areFontIdsLoaded(uniqueFontIds)) {
|
|
311
|
+
callback.invoke();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const barrier = new FontLoadBarrier(uniqueFontIds, callback);
|
|
315
|
+
for (let index = 0; index < uniqueFontIds.length; ++index) {
|
|
316
|
+
const fontId = unchecked(uniqueFontIds[index]);
|
|
317
|
+
if (FontFace.isLoaded(fontId)) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
FontFace.registrations.push(new FontLoadBarrierCallback(barrier));
|
|
321
|
+
FontFace.regFontIds.push(fontId);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** @internal */
|
|
326
|
+
static _dispatchFontLoaded(fontId: u32): void {
|
|
327
|
+
markFontLoaded(fontId);
|
|
328
|
+
for (let i = 0; i < FontFace.regFontIds.length; i++) {
|
|
329
|
+
if (unchecked(FontFace.regFontIds[i]) == fontId) {
|
|
330
|
+
unchecked(FontFace.registrations[i]).invoke(fontId);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
46
334
|
}
|
|
47
335
|
|
|
48
336
|
export class FontStack {
|
|
337
|
+
readonly id: u32;
|
|
49
338
|
private readonly fallbackIds: Array<u32> = new Array<u32>();
|
|
50
339
|
|
|
51
|
-
constructor(readonly
|
|
340
|
+
constructor(readonly face: FontFace) {
|
|
341
|
+
this.id = face.id;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** @internal */
|
|
345
|
+
static _fromId(id: u32): FontStack {
|
|
346
|
+
return new FontStack(FontFace._fromId(id));
|
|
347
|
+
}
|
|
52
348
|
|
|
53
349
|
static load(url: string, id: u32 = allocateDynamicFontId()): FontStack {
|
|
54
|
-
return new FontStack(
|
|
350
|
+
return new FontStack(FontFace.load(url, id));
|
|
55
351
|
}
|
|
56
352
|
|
|
57
353
|
load(url: string): this {
|
|
@@ -62,7 +358,8 @@ export class FontStack {
|
|
|
62
358
|
return this;
|
|
63
359
|
}
|
|
64
360
|
|
|
65
|
-
|
|
361
|
+
/** @internal */
|
|
362
|
+
_fallbackId(fontId: u32): this {
|
|
66
363
|
if (fontId == 0 || fontId == this.id) {
|
|
67
364
|
warn(
|
|
68
365
|
"Typography",
|
|
@@ -80,12 +377,16 @@ export class FontStack {
|
|
|
80
377
|
return this;
|
|
81
378
|
}
|
|
82
379
|
|
|
380
|
+
fallback(face: FontFace): this {
|
|
381
|
+
return this._fallbackId(face.id);
|
|
382
|
+
}
|
|
383
|
+
|
|
83
384
|
fallbackFace(face: FontFace): this {
|
|
84
|
-
return this.fallback(face
|
|
385
|
+
return this.fallback(face);
|
|
85
386
|
}
|
|
86
387
|
|
|
87
388
|
fallbackStack(stack: FontStack): this {
|
|
88
|
-
return this.
|
|
389
|
+
return this._fallbackId(stack.id);
|
|
89
390
|
}
|
|
90
391
|
|
|
91
392
|
fallbackLoaded(url: string, fontId: u32 = allocateDynamicFontId()): this {
|
|
@@ -93,40 +394,131 @@ export class FontStack {
|
|
|
93
394
|
warn("Typography", "FontStack.fallbackLoaded() received an empty font URL.");
|
|
94
395
|
}
|
|
95
396
|
ui.loadFont(fontId, url);
|
|
96
|
-
return this.
|
|
397
|
+
return this._fallbackId(fontId);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
requiredFontIds(): Array<u32> {
|
|
401
|
+
const fontIds = new Array<u32>();
|
|
402
|
+
pushUniqueFontId(fontIds, this.id);
|
|
403
|
+
for (let index = 0; index < this.fallbackIds.length; ++index) {
|
|
404
|
+
pushUniqueFontId(fontIds, unchecked(this.fallbackIds[index]));
|
|
405
|
+
}
|
|
406
|
+
return fontIds;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
isLoaded(): bool {
|
|
410
|
+
return areFontIdsLoaded(this.requiredFontIds());
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
onLoaded(callback: (event: FontStackLoadedEventArgs) => void): this {
|
|
414
|
+
FontFace.whenFontsLoadedWithRegistration(this.requiredFontIds(), new FontStackLoadedCallback(this, callback));
|
|
415
|
+
return this;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
onLoadedWith<Owner>(owner: Owner, handler: FontStackLoadedHandler<Owner>): this {
|
|
419
|
+
FontFace.whenFontsLoadedWithRegistration(this.requiredFontIds(), new FontStackLoadedHandlerRegistration<Owner>(this, owner, handler));
|
|
420
|
+
return this;
|
|
97
421
|
}
|
|
98
422
|
}
|
|
99
423
|
|
|
100
424
|
export class FontFamily {
|
|
101
425
|
constructor(
|
|
102
|
-
readonly
|
|
103
|
-
readonly
|
|
104
|
-
readonly
|
|
105
|
-
readonly
|
|
106
|
-
readonly
|
|
107
|
-
readonly
|
|
108
|
-
readonly
|
|
109
|
-
readonly
|
|
426
|
+
readonly regularStack: FontStack,
|
|
427
|
+
readonly boldStack: FontStack | null = null,
|
|
428
|
+
readonly italicStack: FontStack | null = null,
|
|
429
|
+
readonly boldItalicStack: FontStack | null = null,
|
|
430
|
+
readonly mediumStack: FontStack | null = null,
|
|
431
|
+
readonly mediumItalicStack: FontStack | null = null,
|
|
432
|
+
readonly semiboldStack: FontStack | null = null,
|
|
433
|
+
readonly semiboldItalicStack: FontStack | null = null,
|
|
110
434
|
) {}
|
|
111
435
|
|
|
112
|
-
|
|
436
|
+
get regular(): u32 {
|
|
437
|
+
return this.regularStack.id;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
get bold(): u32 {
|
|
441
|
+
return this.boldStack !== null ? changetype<FontStack>(this.boldStack).id : 0;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
get italic(): u32 {
|
|
445
|
+
return this.italicStack !== null ? changetype<FontStack>(this.italicStack).id : 0;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
get boldItalic(): u32 {
|
|
449
|
+
return this.boldItalicStack !== null ? changetype<FontStack>(this.boldItalicStack).id : 0;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
get medium(): u32 {
|
|
453
|
+
return this.mediumStack !== null ? changetype<FontStack>(this.mediumStack).id : 0;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
get mediumItalic(): u32 {
|
|
457
|
+
return this.mediumItalicStack !== null ? changetype<FontStack>(this.mediumItalicStack).id : 0;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
get semibold(): u32 {
|
|
461
|
+
return this.semiboldStack !== null ? changetype<FontStack>(this.semiboldStack).id : 0;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
get semiboldItalic(): u32 {
|
|
465
|
+
return this.semiboldItalicStack !== null ? changetype<FontStack>(this.semiboldItalicStack).id : 0;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** @internal */
|
|
469
|
+
static _fromIds(
|
|
470
|
+
regular: u32,
|
|
471
|
+
bold: u32 = 0,
|
|
472
|
+
italic: u32 = 0,
|
|
473
|
+
boldItalic: u32 = 0,
|
|
474
|
+
medium: u32 = 0,
|
|
475
|
+
mediumItalic: u32 = 0,
|
|
476
|
+
semibold: u32 = 0,
|
|
477
|
+
semiboldItalic: u32 = 0,
|
|
478
|
+
): FontFamily {
|
|
479
|
+
return new FontFamily(
|
|
480
|
+
FontStack._fromId(regular),
|
|
481
|
+
bold != 0 ? FontStack._fromId(bold) : null,
|
|
482
|
+
italic != 0 ? FontStack._fromId(italic) : null,
|
|
483
|
+
boldItalic != 0 ? FontStack._fromId(boldItalic) : null,
|
|
484
|
+
medium != 0 ? FontStack._fromId(medium) : null,
|
|
485
|
+
mediumItalic != 0 ? FontStack._fromId(mediumItalic) : null,
|
|
486
|
+
semibold != 0 ? FontStack._fromId(semibold) : null,
|
|
487
|
+
semiboldItalic != 0 ? FontStack._fromId(semiboldItalic) : null,
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
static withRegular(regular: FontStack): FontFamily {
|
|
113
492
|
return new FontFamily(regular);
|
|
114
493
|
}
|
|
115
494
|
|
|
116
495
|
static withRegularStack(regular: FontStack): FontFamily {
|
|
117
|
-
return new FontFamily(regular
|
|
496
|
+
return new FontFamily(regular);
|
|
118
497
|
}
|
|
119
498
|
|
|
120
499
|
static withRegularFace(regular: FontFace): FontFamily {
|
|
121
|
-
return new FontFamily(regular
|
|
500
|
+
return new FontFamily(new FontStack(regular));
|
|
122
501
|
}
|
|
123
502
|
|
|
124
|
-
static regularBold(regular:
|
|
503
|
+
static regularBold(regular: FontStack, bold: FontStack): FontFamily {
|
|
125
504
|
return new FontFamily(regular, bold);
|
|
126
505
|
}
|
|
127
506
|
|
|
128
507
|
static regularBoldStacks(regular: FontStack, bold: FontStack): FontFamily {
|
|
129
|
-
return new FontFamily(regular
|
|
508
|
+
return new FontFamily(regular, bold);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
requiredFontIds(): Array<u32> {
|
|
512
|
+
const fontIds = new Array<u32>();
|
|
513
|
+
pushUniqueFontId(fontIds, this.regular);
|
|
514
|
+
pushUniqueFontId(fontIds, this.bold);
|
|
515
|
+
pushUniqueFontId(fontIds, this.italic);
|
|
516
|
+
pushUniqueFontId(fontIds, this.boldItalic);
|
|
517
|
+
pushUniqueFontId(fontIds, this.medium);
|
|
518
|
+
pushUniqueFontId(fontIds, this.mediumItalic);
|
|
519
|
+
pushUniqueFontId(fontIds, this.semibold);
|
|
520
|
+
pushUniqueFontId(fontIds, this.semiboldItalic);
|
|
521
|
+
return fontIds;
|
|
130
522
|
}
|
|
131
523
|
|
|
132
524
|
resolve(weight: FontWeight = FontWeight.Regular, style: FontStyle = FontStyle.Normal): u32 {
|