@flighthq/bitmaptext 0.2.1-next.841.373388f → 0.3.0-next.1032.e2b99fc
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/dist/bitmapText.d.ts +2 -3
- package/dist/bitmapText.d.ts.map +1 -1
- package/dist/bitmapText.js +31 -33
- package/dist/bitmapText.js.map +1 -1
- package/dist/contract.d.ts +3 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +3 -0
- package/dist/contract.js.map +1 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/updateBitmapText.d.ts +1 -1
- package/dist/updateBitmapText.d.ts.map +1 -1
- package/dist/updateBitmapText.js +63 -65
- package/dist/updateBitmapText.js.map +1 -1
- package/package.json +11 -9
- package/src/bitmapText.test.ts +21 -32
- package/src/updateBitmapText.test.ts +73 -89
package/dist/bitmapText.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import type { BitmapText, BitmapTextAlign, BitmapTextData, BitmapTextOptions, BitmapTextRuntime, GlyphSource,
|
|
1
|
+
import type { BitmapText, BitmapTextAlign, BitmapTextData, BitmapTextOptions, BitmapTextPage, BitmapTextRuntime, GlyphSource, Rectangle } from '@flighthq/types/contract';
|
|
2
2
|
export declare function computeBitmapTextLocalBoundsRectangle(out: Rectangle, source: Readonly<BitmapText>): void;
|
|
3
3
|
export declare function createBitmapText(glyphSource: GlyphSource | null, options?: Readonly<BitmapTextOptions>): BitmapText;
|
|
4
4
|
export declare function createBitmapTextData(data?: Readonly<Partial<BitmapTextData>>): BitmapTextData;
|
|
5
5
|
export declare function createBitmapTextRuntime(): BitmapTextRuntime;
|
|
6
6
|
export declare function getBitmapTextBounds(source: Readonly<BitmapText>): Rectangle;
|
|
7
|
-
export declare function
|
|
7
|
+
export declare function getBitmapTextPages(source: Readonly<BitmapText>): readonly BitmapTextPage[];
|
|
8
8
|
export declare function reserveBitmapText(target: BitmapText, glyphCapacity: number): void;
|
|
9
9
|
export declare function setBitmapTextAlign(target: BitmapText, align: BitmapTextAlign): void;
|
|
10
|
-
export declare function setBitmapTextColor(target: BitmapText, color: number): void;
|
|
11
10
|
export declare function setBitmapTextGlyphSource(target: BitmapText, glyphSource: GlyphSource | null): void;
|
|
12
11
|
export declare function setBitmapTextLetterSpacing(target: BitmapText, letterSpacing: number): void;
|
|
13
12
|
export declare function setBitmapTextLineHeight(target: BitmapText, lineHeight: number): void;
|
package/dist/bitmapText.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitmapText.d.ts","sourceRoot":"","sources":["../src/bitmapText.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bitmapText.d.ts","sourceRoot":"","sources":["../src/bitmapText.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,WAAW,EAGX,SAAS,EACV,MAAM,0BAA0B,CAAC;AASlC,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAWxG;AASD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,UAAU,CAanH;AAED,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,GAAG,cAAc,CAS7F;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAK3D;AAID,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,CAI3E;AAID,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,cAAc,EAAE,CAE1F;AAKD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,CAMjF;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAEnF;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAElG;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,CAE1F;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAEpF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAExE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEzF"}
|
package/dist/bitmapText.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { copyRectangle, createRectangle } from '@flighthq/geometry';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const BITMAP_TEXT_DEFAULT_COLOR = 0xffffffff;
|
|
1
|
+
import { copyRectangle, createRectangle, reserveFloat32Array, reserveUint16Array } from '@flighthq/geometry/contract';
|
|
2
|
+
import { createNode2D, createNode2DRuntime, getNode2DRuntime } from '@flighthq/scene2d/contract';
|
|
3
|
+
import { createTextureAtlas } from '@flighthq/textureatlas/contract';
|
|
4
|
+
import { BitmapTextKind } from '@flighthq/types/contract';
|
|
5
|
+
// Two floats (x, y) per glyph quad — the vector2 (translation-only) transform stride the BitmapText
|
|
6
|
+
// renderer reads. Kept internal so callers never hand-write i*2.
|
|
7
|
+
const BITMAP_TEXT_TRANSFORM_STRIDE = 2;
|
|
9
8
|
// Writes the laid-out text extent (cached by `updateBitmapText`) into `out`, or a zero rectangle when
|
|
10
9
|
// the text has not been laid out yet. Alias-safe: `out` may be the cached rectangle.
|
|
11
10
|
export function computeBitmapTextLocalBoundsRectangle(out, source) {
|
|
@@ -21,27 +20,25 @@ export function computeBitmapTextLocalBoundsRectangle(out, source) {
|
|
|
21
20
|
copyRectangle(out, bounds);
|
|
22
21
|
}
|
|
23
22
|
// Allocates a BitmapText display node bound to `glyphSource` for both layout AND pixels. The
|
|
24
|
-
// `GlyphSource` seam
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// `text`, which
|
|
23
|
+
// `GlyphSource` seam pairs its glyph geometry (rects, advances, kerning, metrics) with the backing atlas
|
|
24
|
+
// image(s) those rects sample (`getGlyphAtlasImage(page)`), so no separate image is supplied. The node
|
|
25
|
+
// owns one `BitmapTextPage` per glyph-atlas page — a single-page source yields exactly one (page 0),
|
|
26
|
+
// created eagerly here — and draws them itself through the registered BitmapText renderer. Call
|
|
27
|
+
// `updateBitmapText` to lay out the current `text`, which binds each page's atlas image and grows the set
|
|
28
|
+
// for a multi-page source.
|
|
29
29
|
export function createBitmapText(glyphSource, options) {
|
|
30
30
|
const bitmapText = createNode2D(BitmapTextKind, undefined, createBitmapTextData, createBitmapTextRuntime);
|
|
31
31
|
const data = bitmapText.data;
|
|
32
32
|
data.glyphSource = glyphSource;
|
|
33
33
|
if (options !== undefined)
|
|
34
34
|
applyBitmapTextOptions(data, options);
|
|
35
|
-
const quadBatch = createQuadBatch({ data: { atlas: createTextureAtlas() } });
|
|
36
35
|
const runtime = getNode2DRuntime(bitmapText);
|
|
37
|
-
runtime.
|
|
38
|
-
addNodeChild(bitmapText, quadBatch);
|
|
36
|
+
runtime.pages.push(createBitmapTextPage());
|
|
39
37
|
return bitmapText;
|
|
40
38
|
}
|
|
41
39
|
export function createBitmapTextData(data) {
|
|
42
40
|
return {
|
|
43
41
|
align: data?.align ?? 'left',
|
|
44
|
-
color: data?.color ?? BITMAP_TEXT_DEFAULT_COLOR,
|
|
45
42
|
glyphSource: data?.glyphSource ?? null,
|
|
46
43
|
letterSpacing: data?.letterSpacing ?? 0,
|
|
47
44
|
lineHeight: data?.lineHeight ?? 1,
|
|
@@ -52,7 +49,7 @@ export function createBitmapTextData(data) {
|
|
|
52
49
|
export function createBitmapTextRuntime() {
|
|
53
50
|
const runtime = createNode2DRuntime(defaultMethods);
|
|
54
51
|
runtime.localBoundsRectangle = null;
|
|
55
|
-
runtime.
|
|
52
|
+
runtime.pages = [];
|
|
56
53
|
return runtime;
|
|
57
54
|
}
|
|
58
55
|
// Allocates a fresh Rectangle holding the laid-out text extent. Use
|
|
@@ -62,26 +59,25 @@ export function getBitmapTextBounds(source) {
|
|
|
62
59
|
computeBitmapTextLocalBoundsRectangle(out, source);
|
|
63
60
|
return out;
|
|
64
61
|
}
|
|
65
|
-
// The
|
|
66
|
-
//
|
|
67
|
-
export function
|
|
68
|
-
return getNode2DRuntime(source).
|
|
62
|
+
// The glyph-quad pages the node draws — one per glyph-atlas page in page order. A single-page source
|
|
63
|
+
// yields exactly one; the array is never empty after construction.
|
|
64
|
+
export function getBitmapTextPages(source) {
|
|
65
|
+
return getNode2DRuntime(source).pages;
|
|
69
66
|
}
|
|
70
|
-
// Grows each
|
|
71
|
-
//
|
|
72
|
-
//
|
|
67
|
+
// Grows each page's quad arrays to hold at least `glyphCapacity` glyph quads without reallocating during
|
|
68
|
+
// layout. Optional — `updateBitmapText` auto-grows — but avoids incremental reallocation for large
|
|
69
|
+
// strings. Reserving every page over-allocates for multi-page text but never under-sizes.
|
|
73
70
|
export function reserveBitmapText(target, glyphCapacity) {
|
|
74
71
|
const runtime = getNode2DRuntime(target);
|
|
75
|
-
for (const
|
|
76
|
-
|
|
72
|
+
for (const page of runtime.pages) {
|
|
73
|
+
page.ids = reserveUint16Array(page.ids, glyphCapacity);
|
|
74
|
+
page.transforms = reserveFloat32Array(page.transforms, glyphCapacity * BITMAP_TEXT_TRANSFORM_STRIDE);
|
|
75
|
+
}
|
|
77
76
|
}
|
|
78
|
-
// The setters below mutate node data only; call `updateBitmapText` afterward to re-lay-out the
|
|
77
|
+
// The setters below mutate node data only; call `updateBitmapText` afterward to re-lay-out the pages.
|
|
79
78
|
export function setBitmapTextAlign(target, align) {
|
|
80
79
|
target.data.align = align;
|
|
81
80
|
}
|
|
82
|
-
export function setBitmapTextColor(target, color) {
|
|
83
|
-
target.data.color = color;
|
|
84
|
-
}
|
|
85
81
|
export function setBitmapTextGlyphSource(target, glyphSource) {
|
|
86
82
|
target.data.glyphSource = glyphSource;
|
|
87
83
|
}
|
|
@@ -100,8 +96,6 @@ export function setBitmapTextWrapWidth(target, wrapWidth) {
|
|
|
100
96
|
function applyBitmapTextOptions(data, options) {
|
|
101
97
|
if (options.align !== undefined)
|
|
102
98
|
data.align = options.align;
|
|
103
|
-
if (options.color !== undefined)
|
|
104
|
-
data.color = options.color;
|
|
105
99
|
if (options.letterSpacing !== undefined)
|
|
106
100
|
data.letterSpacing = options.letterSpacing;
|
|
107
101
|
if (options.lineHeight !== undefined)
|
|
@@ -116,6 +110,10 @@ function copyLocalBoundsRectangle(out, source) {
|
|
|
116
110
|
if (runtime.localBoundsRectangle !== null)
|
|
117
111
|
copyRectangle(out, runtime.localBoundsRectangle);
|
|
118
112
|
}
|
|
113
|
+
// Allocates an empty page bound to a fresh atlas. Its image and regions are set by `updateBitmapText`.
|
|
114
|
+
function createBitmapTextPage() {
|
|
115
|
+
return { atlas: createTextureAtlas(), ids: new Uint16Array(), instanceCount: 0, transforms: new Float32Array() };
|
|
116
|
+
}
|
|
119
117
|
const defaultMethods = {
|
|
120
118
|
computeLocalBoundsRectangle: copyLocalBoundsRectangle,
|
|
121
119
|
};
|
package/dist/bitmapText.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitmapText.js","sourceRoot":"","sources":["../src/bitmapText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"bitmapText.js","sourceRoot":"","sources":["../src/bitmapText.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC"}
|
package/dist/contract.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export * from './updateBitmapText';
|
|
1
|
+
export { computeBitmapTextLocalBoundsRectangle, createBitmapText, getBitmapTextBounds, getBitmapTextPages, reserveBitmapText, setBitmapTextAlign, setBitmapTextGlyphSource, setBitmapTextLetterSpacing, setBitmapTextLineHeight, setBitmapTextText, setBitmapTextWrapWidth, updateBitmapText, } from './contract';
|
|
3
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qCAAqC,EACrC,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export * from './updateBitmapText';
|
|
1
|
+
export { computeBitmapTextLocalBoundsRectangle, createBitmapText, getBitmapTextBounds, getBitmapTextPages, reserveBitmapText, setBitmapTextAlign, setBitmapTextGlyphSource, setBitmapTextLetterSpacing, setBitmapTextLineHeight, setBitmapTextText, setBitmapTextWrapWidth, updateBitmapText, } from './contract';
|
|
3
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qCAAqC,EACrC,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateBitmapText.d.ts","sourceRoot":"","sources":["../src/updateBitmapText.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"updateBitmapText.d.ts","sourceRoot":"","sources":["../src/updateBitmapText.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,UAAU,EAOX,MAAM,0BAA0B,CAAC;AAgBlC,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CA2E7D"}
|
package/dist/updateBitmapText.js
CHANGED
|
@@ -1,35 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
import { addTextureAtlasRegion, createTextureAtlas } from '@flighthq/textureatlas';
|
|
8
|
-
// White (`0xRRGGBBAA` all-ones) leaves the backing batch material-free — the untinted path.
|
|
9
|
-
const BITMAP_TEXT_DEFAULT_COLOR = 0xffffffff;
|
|
1
|
+
import { createRectangle, reserveFloat32Array, reserveUint16Array } from '@flighthq/geometry/contract';
|
|
2
|
+
import { invalidateNodeLocalBounds } from '@flighthq/node/contract';
|
|
3
|
+
import { getNode2DRuntime } from '@flighthq/scene2d/contract';
|
|
4
|
+
import { createTexture, setTextureImage } from '@flighthq/texture/contract';
|
|
5
|
+
import { addTextureAtlasRegion, createTextureAtlas } from '@flighthq/textureatlas/contract';
|
|
6
|
+
const BITMAP_TEXT_TRANSFORM_STRIDE = 2;
|
|
10
7
|
const CARRIAGE_RETURN = 0x0d;
|
|
11
8
|
const SPACE = 0x20;
|
|
12
|
-
// Lays out `bitmapText`'s current string and rewrites its
|
|
13
|
-
// glyph, partitioned by the glyph's atlas page into one
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
9
|
+
// Lays out `bitmapText`'s current string and rewrites its `BitmapTextPage` quads: one quad per visible
|
|
10
|
+
// glyph, partitioned by the glyph's atlas page into one page's quads, positioned by the glyph source's
|
|
11
|
+
// advances and kerning, broken on explicit newlines and (when `wrapWidth` is set) at word boundaries,
|
|
12
|
+
// stacked by the metric line advance, and aligned per line. Each page's atlas Texture is bound from
|
|
13
|
+
// `getGlyphAtlasImage(page)` and its regions rebuilt from that page's encountered glyph rects each call,
|
|
14
|
+
// so a dynamic glyph source whose rects shift between layouts stays correct. A single-page source produces
|
|
15
|
+
// exactly one page (page 0). A page whose `getGlyphAtlasImage` returns null cannot be sampled, so its
|
|
16
|
+
// glyphs are skipped. Missing glyphs (`getGlyphEntry` → null) are omitted entirely — no quad and no
|
|
17
|
+
// advance. Bounds span every drawn glyph across all pages. Tint is the node's own color-adjustment stack,
|
|
18
|
+
// not touched here.
|
|
22
19
|
export function updateBitmapText(bitmapText) {
|
|
23
20
|
const data = bitmapText.data;
|
|
24
21
|
const runtime = getNode2DRuntime(bitmapText);
|
|
25
22
|
const bounds = ensureBoundsRectangle(runtime);
|
|
26
|
-
// Clear
|
|
27
|
-
//
|
|
28
|
-
for (const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
quadBatch.data.atlas.regions.length = 0;
|
|
32
|
-
applyBitmapTextColor(quadBatch, data.color);
|
|
23
|
+
// Clear every existing page; pages with glyphs this layout are refilled below, pages that fall silent
|
|
24
|
+
// stay as empty pages drawing nothing.
|
|
25
|
+
for (const page of runtime.pages) {
|
|
26
|
+
page.instanceCount = 0;
|
|
27
|
+
page.atlas.regions.length = 0;
|
|
33
28
|
}
|
|
34
29
|
const glyphSource = data.glyphSource;
|
|
35
30
|
if (glyphSource === null || data.text.length === 0) {
|
|
@@ -65,18 +60,18 @@ export function updateBitmapText(bitmapText) {
|
|
|
65
60
|
const word = line.words[wi];
|
|
66
61
|
for (const glyph of word.glyphs) {
|
|
67
62
|
const entry = glyph.entry;
|
|
68
|
-
const
|
|
69
|
-
if (
|
|
63
|
+
const context = ensureBitmapTextPage(runtime, glyphSource, pages, entry.page);
|
|
64
|
+
if (context === null)
|
|
70
65
|
continue;
|
|
71
66
|
const quadX = penX + glyph.penWithinWord + entry.bearingX;
|
|
72
67
|
const quadY = baselineY - entry.bearingY;
|
|
73
|
-
let regionId =
|
|
68
|
+
let regionId = context.regionByCodepoint.get(glyph.codepoint);
|
|
74
69
|
if (regionId === undefined) {
|
|
75
|
-
addTextureAtlasRegion(page.atlas, entry.x, entry.y, entry.width, entry.height);
|
|
76
|
-
regionId = page.atlas.regions.length - 1;
|
|
77
|
-
|
|
70
|
+
addTextureAtlasRegion(context.page.atlas, entry.x, entry.y, entry.width, entry.height);
|
|
71
|
+
regionId = context.page.atlas.regions.length - 1;
|
|
72
|
+
context.regionByCodepoint.set(glyph.codepoint, regionId);
|
|
78
73
|
}
|
|
79
|
-
|
|
74
|
+
appendBitmapTextPageQuad(context.page, regionId, quadX, quadY);
|
|
80
75
|
if (quadX < minX)
|
|
81
76
|
minX = quadX;
|
|
82
77
|
if (quadY < minY)
|
|
@@ -100,22 +95,21 @@ export function updateBitmapText(bitmapText) {
|
|
|
100
95
|
}
|
|
101
96
|
invalidateNodeLocalBounds(bitmapText);
|
|
102
97
|
}
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
// Appends one glyph quad (region id + vector2 pen position) to `page`, auto-growing its arrays. The
|
|
99
|
+
// page-local twin of `appendQuadBatchInstance`, over plain owned arrays rather than a QuadBatch node.
|
|
100
|
+
function appendBitmapTextPageQuad(page, id, x, y) {
|
|
101
|
+
const index = page.instanceCount;
|
|
102
|
+
const capacity = Math.min(page.ids.length, (page.transforms.length / BITMAP_TEXT_TRANSFORM_STRIDE) | 0);
|
|
103
|
+
if (index >= capacity) {
|
|
104
|
+
const next = Math.max(index + 1, capacity * 2, 8);
|
|
105
|
+
page.ids = reserveUint16Array(page.ids, next);
|
|
106
|
+
page.transforms = reserveFloat32Array(page.transforms, next * BITMAP_TEXT_TRANSFORM_STRIDE);
|
|
111
107
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
});
|
|
118
|
-
setNode2DColorAdjustments(quadBatch, [createColorTransformAdjustment(colorTransform)]);
|
|
108
|
+
page.ids[index] = id;
|
|
109
|
+
const o = index * BITMAP_TEXT_TRANSFORM_STRIDE;
|
|
110
|
+
page.transforms[o] = x;
|
|
111
|
+
page.transforms[o + 1] = y;
|
|
112
|
+
page.instanceCount = index + 1;
|
|
119
113
|
}
|
|
120
114
|
// Measures one paragraph (a newline-free run) into words separated by whitespace gaps. Intra-word
|
|
121
115
|
// kerning and letter spacing are baked into each glyph's `penWithinWord` and the word width; kerning
|
|
@@ -161,30 +155,34 @@ function buildBitmapTextWords(glyphSource, paragraph, letterSpacing) {
|
|
|
161
155
|
flush();
|
|
162
156
|
return tokens;
|
|
163
157
|
}
|
|
164
|
-
// Ensures a
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
// their own image; the common single-page source touches only page 0 (created by `createBitmapText`).
|
|
169
|
-
function ensureBitmapTextPageBatch(bitmapText, runtime, glyphSource, color, pages, page) {
|
|
158
|
+
// Ensures a `BitmapTextPage` exists for glyph-atlas `page` (page-indexed in `runtime.pages`, growing fresh
|
|
159
|
+
// pages as needed) and binds it to that page's atlas image, returning the per-layout page context (page +
|
|
160
|
+
// region cache). Returns null when the page has no atlas image to sample — its glyphs are then skipped.
|
|
161
|
+
function ensureBitmapTextPage(runtime, glyphSource, pages, page) {
|
|
170
162
|
const cached = pages.get(page);
|
|
171
163
|
if (cached !== undefined)
|
|
172
164
|
return cached;
|
|
173
165
|
const image = glyphSource.getGlyphAtlasImage(page);
|
|
174
166
|
if (image === null)
|
|
175
167
|
return null;
|
|
176
|
-
while (runtime.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
168
|
+
while (runtime.pages.length <= page) {
|
|
169
|
+
runtime.pages.push({
|
|
170
|
+
atlas: createTextureAtlas(),
|
|
171
|
+
ids: new Uint16Array(),
|
|
172
|
+
instanceCount: 0,
|
|
173
|
+
transforms: new Float32Array(),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const pageData = runtime.pages[page];
|
|
177
|
+
if (pageData.atlas.texture === null) {
|
|
178
|
+
pageData.atlas.texture = createTexture({ storage: { dimension: '2d', image } });
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
setTextureImage(pageData.atlas.texture, image);
|
|
181
182
|
}
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const pageBatch = { atlas, quadBatch, regionByCodepoint: new Map() };
|
|
186
|
-
pages.set(page, pageBatch);
|
|
187
|
-
return pageBatch;
|
|
183
|
+
const context = { page: pageData, regionByCodepoint: new Map() };
|
|
184
|
+
pages.set(page, context);
|
|
185
|
+
return context;
|
|
188
186
|
}
|
|
189
187
|
function ensureBoundsRectangle(runtime) {
|
|
190
188
|
if (runtime.localBoundsRectangle === null)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateBitmapText.js","sourceRoot":"","sources":["../src/updateBitmapText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"updateBitmapText.js","sourceRoot":"","sources":["../src/updateBitmapText.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/bitmaptext",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-next.1032.e2b99fc",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/flighthq/flight.git",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
".": {
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./contract": {
|
|
18
|
+
"types": "./dist/contract.d.ts",
|
|
19
|
+
"default": "./dist/contract.js"
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
22
|
"files": [
|
|
@@ -32,14 +36,12 @@
|
|
|
32
36
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
33
37
|
},
|
|
34
38
|
"dependencies": {
|
|
35
|
-
"@flighthq/
|
|
36
|
-
"@flighthq/
|
|
37
|
-
"@flighthq/
|
|
38
|
-
"@flighthq/
|
|
39
|
-
"@flighthq/
|
|
40
|
-
"@flighthq/
|
|
41
|
-
"@flighthq/textureatlas": "0.2.1-next.841.373388f",
|
|
42
|
-
"@flighthq/types": "0.2.1-next.841.373388f"
|
|
39
|
+
"@flighthq/scene2d": "0.3.0-next.1032.e2b99fc",
|
|
40
|
+
"@flighthq/geometry": "0.3.0-next.1032.e2b99fc",
|
|
41
|
+
"@flighthq/node": "0.3.0-next.1032.e2b99fc",
|
|
42
|
+
"@flighthq/texture": "0.3.0-next.1032.e2b99fc",
|
|
43
|
+
"@flighthq/textureatlas": "0.3.0-next.1032.e2b99fc",
|
|
44
|
+
"@flighthq/types": "0.3.0-next.1032.e2b99fc"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"@flighthq/glyphatlas": "*",
|
package/src/bitmapText.test.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { createRectangle } from '@flighthq/geometry';
|
|
2
|
-
import { getNode2DRuntime } from '@flighthq/scene2d';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import { BitmapTextKind } from '@flighthq/types';
|
|
1
|
+
import { createRectangle } from '@flighthq/geometry/contract';
|
|
2
|
+
import { getNode2DRuntime } from '@flighthq/scene2d/contract';
|
|
3
|
+
import type { BitmapTextRuntime, GlyphEntry, GlyphSource, ImageResource } from '@flighthq/types/contract';
|
|
4
|
+
import { BitmapTextKind } from '@flighthq/types/contract';
|
|
6
5
|
import { describe, expect, it } from 'vitest';
|
|
7
6
|
|
|
8
7
|
import {
|
|
@@ -11,10 +10,9 @@ import {
|
|
|
11
10
|
createBitmapTextData,
|
|
12
11
|
createBitmapTextRuntime,
|
|
13
12
|
getBitmapTextBounds,
|
|
14
|
-
|
|
13
|
+
getBitmapTextPages,
|
|
15
14
|
reserveBitmapText,
|
|
16
15
|
setBitmapTextAlign,
|
|
17
|
-
setBitmapTextColor,
|
|
18
16
|
setBitmapTextGlyphSource,
|
|
19
17
|
setBitmapTextLetterSpacing,
|
|
20
18
|
setBitmapTextLineHeight,
|
|
@@ -73,25 +71,23 @@ describe('computeBitmapTextLocalBoundsRectangle', () => {
|
|
|
73
71
|
});
|
|
74
72
|
|
|
75
73
|
describe('createBitmapText', () => {
|
|
76
|
-
it('creates a BitmapText
|
|
74
|
+
it('creates a BitmapText leaf owning one page and no child nodes', () => {
|
|
77
75
|
const text = createBitmapText(createTestGlyphSource());
|
|
78
76
|
expect(text.kind).toBe(BitmapTextKind);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
expect(
|
|
77
|
+
expect(getBitmapTextPages(text)).toHaveLength(1);
|
|
78
|
+
const children = getNode2DRuntime(text).children;
|
|
79
|
+
expect(children == null || children.length === 0).toBe(true);
|
|
82
80
|
});
|
|
83
81
|
|
|
84
82
|
it('applies construction options to node data', () => {
|
|
85
83
|
const text = createBitmapText(createTestGlyphSource(), {
|
|
86
84
|
align: 'center',
|
|
87
|
-
color: 0xff0000ff,
|
|
88
85
|
letterSpacing: 2,
|
|
89
86
|
lineHeight: 1.5,
|
|
90
87
|
text: 'Hi',
|
|
91
88
|
wrapWidth: 120,
|
|
92
89
|
});
|
|
93
90
|
expect(text.data.align).toBe('center');
|
|
94
|
-
expect(text.data.color).toBe(0xff0000ff);
|
|
95
91
|
expect(text.data.letterSpacing).toBe(2);
|
|
96
92
|
expect(text.data.lineHeight).toBe(1.5);
|
|
97
93
|
expect(text.data.text).toBe('Hi');
|
|
@@ -106,10 +102,9 @@ describe('createBitmapText', () => {
|
|
|
106
102
|
});
|
|
107
103
|
|
|
108
104
|
describe('createBitmapTextData', () => {
|
|
109
|
-
it('defaults to left-aligned
|
|
105
|
+
it('defaults to left-aligned empty unwrapped text', () => {
|
|
110
106
|
const data = createBitmapTextData();
|
|
111
107
|
expect(data.align).toBe('left');
|
|
112
|
-
expect(data.color).toBe(0xffffffff);
|
|
113
108
|
expect(data.glyphSource).toBeNull();
|
|
114
109
|
expect(data.letterSpacing).toBe(0);
|
|
115
110
|
expect(data.lineHeight).toBe(1);
|
|
@@ -126,10 +121,10 @@ describe('createBitmapTextData', () => {
|
|
|
126
121
|
});
|
|
127
122
|
|
|
128
123
|
describe('createBitmapTextRuntime', () => {
|
|
129
|
-
it('starts with null bounds and no
|
|
124
|
+
it('starts with null bounds and no pages', () => {
|
|
130
125
|
const runtime = createBitmapTextRuntime();
|
|
131
126
|
expect(runtime.localBoundsRectangle).toBeNull();
|
|
132
|
-
expect(runtime.
|
|
127
|
+
expect(runtime.pages).toEqual([]);
|
|
133
128
|
});
|
|
134
129
|
});
|
|
135
130
|
|
|
@@ -145,20 +140,22 @@ describe('getBitmapTextBounds', () => {
|
|
|
145
140
|
});
|
|
146
141
|
});
|
|
147
142
|
|
|
148
|
-
describe('
|
|
149
|
-
it('returns the
|
|
143
|
+
describe('getBitmapTextPages', () => {
|
|
144
|
+
it('returns the owned pages in page order', () => {
|
|
150
145
|
const text = createBitmapText(createTestGlyphSource());
|
|
151
|
-
const
|
|
152
|
-
expect(
|
|
153
|
-
expect(
|
|
146
|
+
const pages = getBitmapTextPages(text);
|
|
147
|
+
expect(pages).toHaveLength(1);
|
|
148
|
+
expect(pages[0].instanceCount).toBe(0);
|
|
154
149
|
});
|
|
155
150
|
});
|
|
156
151
|
|
|
157
152
|
describe('reserveBitmapText', () => {
|
|
158
|
-
it('grows
|
|
153
|
+
it('grows each page quad-array capacity', () => {
|
|
159
154
|
const text = createBitmapText(createTestGlyphSource());
|
|
160
155
|
reserveBitmapText(text, 64);
|
|
161
|
-
|
|
156
|
+
const page = getBitmapTextPages(text)[0];
|
|
157
|
+
expect(page.ids.length).toBeGreaterThanOrEqual(64);
|
|
158
|
+
expect(page.transforms.length).toBeGreaterThanOrEqual(128);
|
|
162
159
|
});
|
|
163
160
|
});
|
|
164
161
|
|
|
@@ -170,14 +167,6 @@ describe('setBitmapTextAlign', () => {
|
|
|
170
167
|
});
|
|
171
168
|
});
|
|
172
169
|
|
|
173
|
-
describe('setBitmapTextColor', () => {
|
|
174
|
-
it('mutates the color field', () => {
|
|
175
|
-
const text = createBitmapText(createTestGlyphSource());
|
|
176
|
-
setBitmapTextColor(text, 0x00ff00ff);
|
|
177
|
-
expect(text.data.color).toBe(0x00ff00ff);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
170
|
describe('setBitmapTextGlyphSource', () => {
|
|
182
171
|
it('rebinds the glyph source', () => {
|
|
183
172
|
const text = createBitmapText(createTestGlyphSource());
|
|
@@ -3,12 +3,11 @@ import {
|
|
|
3
3
|
createGlyphSourceFromGlyphAtlas,
|
|
4
4
|
createStubGlyphRasterizerBackend,
|
|
5
5
|
setGlyphRasterizerBackend,
|
|
6
|
-
} from '@flighthq/glyphatlas';
|
|
7
|
-
import {
|
|
8
|
-
import type { ColorTransformAdjustment, GlyphEntry, GlyphSource, ImageResource } from '@flighthq/types';
|
|
6
|
+
} from '@flighthq/glyphatlas/contract';
|
|
7
|
+
import type { GlyphEntry, GlyphSource, ImageResource } from '@flighthq/types/contract';
|
|
9
8
|
import { describe, expect, it } from 'vitest';
|
|
10
9
|
|
|
11
|
-
import { createBitmapText, getBitmapTextBounds,
|
|
10
|
+
import { createBitmapText, getBitmapTextBounds, getBitmapTextPages } from './bitmapText';
|
|
12
11
|
import { updateBitmapText } from './updateBitmapText';
|
|
13
12
|
|
|
14
13
|
// A deterministic single-page glyph source: every visible glyph is 6x8 with advance 10 and bearingY 8
|
|
@@ -59,9 +58,9 @@ describe('updateBitmapText', () => {
|
|
|
59
58
|
const atlas = createGlyphAtlas({ fontFamily: 'unavailable', fontSize: 24, height: 256, width: 256 });
|
|
60
59
|
const text = createBitmapText(createGlyphSourceFromGlyphAtlas(atlas), { text: 'Hi' });
|
|
61
60
|
updateBitmapText(text);
|
|
62
|
-
const
|
|
63
|
-
expect(
|
|
64
|
-
expect(
|
|
61
|
+
const pages = getBitmapTextPages(text);
|
|
62
|
+
expect(pages.length).toBeGreaterThan(0);
|
|
63
|
+
expect(pages[0]!.instanceCount).toBe(2);
|
|
65
64
|
} finally {
|
|
66
65
|
setGlyphRasterizerBackend(null);
|
|
67
66
|
}
|
|
@@ -70,63 +69,63 @@ describe('updateBitmapText', () => {
|
|
|
70
69
|
it('places each glyph at its cumulative advance, applying kerning', () => {
|
|
71
70
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB' });
|
|
72
71
|
updateBitmapText(text);
|
|
73
|
-
const
|
|
74
|
-
expect(
|
|
75
|
-
expect(
|
|
76
|
-
expect(
|
|
77
|
-
expect(
|
|
78
|
-
expect(
|
|
72
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
73
|
+
expect(page.instanceCount).toBe(2);
|
|
74
|
+
expect(page.transforms[0]).toBe(0); // A.x
|
|
75
|
+
expect(page.transforms[1]).toBe(0); // A.y
|
|
76
|
+
expect(page.transforms[2]).toBe(8); // B.x = 10 (advance) - 2 (kerning)
|
|
77
|
+
expect(page.transforms[3]).toBe(0); // B.y
|
|
79
78
|
});
|
|
80
79
|
|
|
81
80
|
it('builds one atlas region per distinct glyph and references it by id', () => {
|
|
82
81
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB' });
|
|
83
82
|
updateBitmapText(text);
|
|
84
|
-
const
|
|
85
|
-
expect(
|
|
86
|
-
expect(
|
|
87
|
-
expect(
|
|
88
|
-
expect(
|
|
89
|
-
expect(
|
|
83
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
84
|
+
expect(page.atlas.regions).toHaveLength(2);
|
|
85
|
+
expect(page.ids[0]).toBe(0);
|
|
86
|
+
expect(page.ids[1]).toBe(1);
|
|
87
|
+
expect(page.atlas.regions[0].x).toBe(0); // A rect
|
|
88
|
+
expect(page.atlas.regions[1].x).toBe(6); // B rect
|
|
90
89
|
});
|
|
91
90
|
|
|
92
91
|
it('reuses one region for repeated codepoints', () => {
|
|
93
92
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA' });
|
|
94
93
|
updateBitmapText(text);
|
|
95
|
-
const
|
|
96
|
-
expect(
|
|
97
|
-
expect(
|
|
98
|
-
expect(
|
|
99
|
-
expect(
|
|
94
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
95
|
+
expect(page.instanceCount).toBe(2);
|
|
96
|
+
expect(page.atlas.regions).toHaveLength(1);
|
|
97
|
+
expect(page.ids[0]).toBe(0);
|
|
98
|
+
expect(page.ids[1]).toBe(0);
|
|
100
99
|
});
|
|
101
100
|
|
|
102
101
|
it('starts a new line at the metric line advance on an explicit newline', () => {
|
|
103
102
|
const text = createBitmapText(createTestGlyphSource(), { text: 'A\nB' });
|
|
104
103
|
updateBitmapText(text);
|
|
105
|
-
const
|
|
106
|
-
expect(
|
|
107
|
-
expect(
|
|
108
|
-
expect(
|
|
109
|
-
expect(
|
|
110
|
-
expect(
|
|
104
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
105
|
+
expect(page.instanceCount).toBe(2);
|
|
106
|
+
expect(page.transforms[0]).toBe(0); // line 0 A.x
|
|
107
|
+
expect(page.transforms[1]).toBe(0); // line 0 A.y
|
|
108
|
+
expect(page.transforms[2]).toBe(0); // line 1 B.x
|
|
109
|
+
expect(page.transforms[3]).toBe(10); // line 1 B.y = 1 * (8 + 2 + 0)
|
|
111
110
|
});
|
|
112
111
|
|
|
113
112
|
it('scales the line advance by lineHeight', () => {
|
|
114
113
|
const text = createBitmapText(createTestGlyphSource(), { text: 'A\nB', lineHeight: 2 });
|
|
115
114
|
updateBitmapText(text);
|
|
116
|
-
const
|
|
117
|
-
expect(
|
|
115
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
116
|
+
expect(page.transforms[3]).toBe(20); // 2 * (8 + 2 + 0)
|
|
118
117
|
});
|
|
119
118
|
|
|
120
119
|
it('word-wraps at a word boundary when the width is exceeded', () => {
|
|
121
120
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA AA', wrapWidth: 30 });
|
|
122
121
|
updateBitmapText(text);
|
|
123
|
-
const
|
|
124
|
-
expect(
|
|
122
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
123
|
+
expect(page.instanceCount).toBe(4);
|
|
125
124
|
let firstLine = 0;
|
|
126
125
|
let secondLine = 0;
|
|
127
|
-
for (let i = 0; i <
|
|
128
|
-
if (
|
|
129
|
-
else if (
|
|
126
|
+
for (let i = 0; i < page.instanceCount; i++) {
|
|
127
|
+
if (page.transforms[i * 2 + 1] === 0) firstLine++;
|
|
128
|
+
else if (page.transforms[i * 2 + 1] === 10) secondLine++;
|
|
130
129
|
}
|
|
131
130
|
expect(firstLine).toBe(2);
|
|
132
131
|
expect(secondLine).toBe(2);
|
|
@@ -135,62 +134,62 @@ describe('updateBitmapText', () => {
|
|
|
135
134
|
it('keeps words on one line and honors space advance when no wrap is set', () => {
|
|
136
135
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA AA' });
|
|
137
136
|
updateBitmapText(text);
|
|
138
|
-
const
|
|
139
|
-
expect(
|
|
140
|
-
for (let i = 0; i <
|
|
141
|
-
expect(
|
|
142
|
-
expect(
|
|
137
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
138
|
+
expect(page.instanceCount).toBe(4);
|
|
139
|
+
for (let i = 0; i < page.instanceCount; i++) expect(page.transforms[i * 2 + 1]).toBe(0);
|
|
140
|
+
expect(page.transforms[4]).toBe(25); // third glyph: word1 width 20 + space 5
|
|
141
|
+
expect(page.transforms[6]).toBe(35);
|
|
143
142
|
});
|
|
144
143
|
|
|
145
144
|
it('offsets a line for center alignment', () => {
|
|
146
145
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB', wrapWidth: 100, align: 'center' });
|
|
147
146
|
updateBitmapText(text);
|
|
148
|
-
const
|
|
149
|
-
expect(
|
|
150
|
-
expect(
|
|
147
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
148
|
+
expect(page.transforms[0]).toBe(41); // (100 - 18) / 2
|
|
149
|
+
expect(page.transforms[2]).toBe(49); // 41 + 8
|
|
151
150
|
});
|
|
152
151
|
|
|
153
152
|
it('offsets a line for right alignment', () => {
|
|
154
153
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB', wrapWidth: 100, align: 'right' });
|
|
155
154
|
updateBitmapText(text);
|
|
156
|
-
const
|
|
157
|
-
expect(
|
|
155
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
156
|
+
expect(page.transforms[0]).toBe(82); // 100 - 18
|
|
158
157
|
});
|
|
159
158
|
|
|
160
159
|
it('stretches inter-word gaps for justify on non-final lines', () => {
|
|
161
160
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA AA AA', wrapWidth: 50, align: 'justify' });
|
|
162
161
|
updateBitmapText(text);
|
|
163
|
-
const
|
|
162
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
164
163
|
// Line 0 = "AA AA" justified to 50: gap 5 grows by (50 - 45) / 1 = 5, so word 2 starts at 30.
|
|
165
|
-
expect(
|
|
166
|
-
expect(
|
|
164
|
+
expect(page.transforms[4]).toBe(30);
|
|
165
|
+
expect(page.transforms[6]).toBe(40);
|
|
167
166
|
// Line 1 = trailing "AA" (paragraph end) stays left.
|
|
168
167
|
const line1 = [];
|
|
169
|
-
for (let i = 0; i <
|
|
170
|
-
if (
|
|
168
|
+
for (let i = 0; i < page.instanceCount; i++)
|
|
169
|
+
if (page.transforms[i * 2 + 1] === 10) line1.push(page.transforms[i * 2]);
|
|
171
170
|
expect(line1).toEqual([0, 10]);
|
|
172
171
|
});
|
|
173
172
|
|
|
174
173
|
it('omits a missing glyph with no quad and no advance', () => {
|
|
175
174
|
const text = createBitmapText(createTestGlyphSource(), { text: 'A?B' });
|
|
176
175
|
updateBitmapText(text);
|
|
177
|
-
const
|
|
178
|
-
expect(
|
|
179
|
-
expect(
|
|
180
|
-
expect(
|
|
176
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
177
|
+
expect(page.instanceCount).toBe(2);
|
|
178
|
+
expect(page.transforms[0]).toBe(0); // A
|
|
179
|
+
expect(page.transforms[2]).toBe(8); // B placed as if '?' were absent (10 - 2 kerning)
|
|
181
180
|
});
|
|
182
181
|
|
|
183
182
|
it('adds letterSpacing after each glyph advance', () => {
|
|
184
183
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB', letterSpacing: 1 });
|
|
185
184
|
updateBitmapText(text);
|
|
186
|
-
const
|
|
187
|
-
expect(
|
|
185
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
186
|
+
expect(page.transforms[2]).toBe(9); // 10 + 1 (spacing) - 2 (kerning)
|
|
188
187
|
});
|
|
189
188
|
|
|
190
|
-
it('lays out an empty string as an empty
|
|
189
|
+
it('lays out an empty string as an empty page without throwing', () => {
|
|
191
190
|
const text = createBitmapText(createTestGlyphSource(), { text: '' });
|
|
192
191
|
expect(() => updateBitmapText(text)).not.toThrow();
|
|
193
|
-
expect(
|
|
192
|
+
expect(getBitmapTextPages(text)[0]!.instanceCount).toBe(0);
|
|
194
193
|
const bounds = getBitmapTextBounds(text);
|
|
195
194
|
expect(bounds.width).toBe(0);
|
|
196
195
|
expect(bounds.height).toBe(0);
|
|
@@ -206,47 +205,32 @@ describe('updateBitmapText', () => {
|
|
|
206
205
|
expect(bounds.height).toBe(8);
|
|
207
206
|
});
|
|
208
207
|
|
|
209
|
-
it('
|
|
210
|
-
const text = createBitmapText(createTestGlyphSource(), { text: 'AB' });
|
|
211
|
-
updateBitmapText(text);
|
|
212
|
-
expect(getNode2DColorAdjustments(getBitmapTextQuadBatches(text)[0]!)).toBeNull();
|
|
213
|
-
setBitmapTextColor(text, 0xff0000ff);
|
|
214
|
-
updateBitmapText(text);
|
|
215
|
-
// One color-transform adjustment on the batch's runtime slot — a single whole-batch tint, not per-glyph.
|
|
216
|
-
const adjustments = getNode2DColorAdjustments(getBitmapTextQuadBatches(text)[0]!);
|
|
217
|
-
expect(adjustments).not.toBeNull();
|
|
218
|
-
expect(adjustments!).toHaveLength(1);
|
|
219
|
-
const colorTransform = (adjustments![0] as ColorTransformAdjustment).colorTransform;
|
|
220
|
-
expect(colorTransform.redMultiplier).toBe(1);
|
|
221
|
-
expect(colorTransform.greenMultiplier).toBe(0);
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it('produces exactly one batch bound to the page-0 image for a single-page source', () => {
|
|
208
|
+
it('produces exactly one page bound to the page-0 image for a single-page source', () => {
|
|
225
209
|
const source = createTestGlyphSource();
|
|
226
210
|
const text = createBitmapText(source, { text: 'AB' });
|
|
227
211
|
updateBitmapText(text);
|
|
228
|
-
const
|
|
229
|
-
expect(
|
|
230
|
-
expect(
|
|
231
|
-
expect(
|
|
212
|
+
const pages = getBitmapTextPages(text);
|
|
213
|
+
expect(pages).toHaveLength(1);
|
|
214
|
+
expect(pages[0].instanceCount).toBe(2);
|
|
215
|
+
expect(pages[0].atlas.texture?.storage.image).toBe(source.getGlyphAtlasImage(0));
|
|
232
216
|
});
|
|
233
217
|
|
|
234
|
-
it('partitions glyphs into one
|
|
218
|
+
it('partitions glyphs into one page per glyph-atlas page, each bound to its own page image', () => {
|
|
235
219
|
const { source, page0Image, page1Image } = createTwoPageGlyphSource();
|
|
236
220
|
const text = createBitmapText(source, { text: 'AB' });
|
|
237
221
|
updateBitmapText(text);
|
|
238
|
-
const
|
|
239
|
-
expect(
|
|
222
|
+
const pages = getBitmapTextPages(text);
|
|
223
|
+
expect(pages).toHaveLength(2);
|
|
240
224
|
|
|
241
225
|
// Page 0 holds 'A' only, sampling page0Image; page 1 holds 'B' only, sampling page1Image.
|
|
242
|
-
const page0 =
|
|
243
|
-
const page1 =
|
|
226
|
+
const page0 = pages[0];
|
|
227
|
+
const page1 = pages[1];
|
|
244
228
|
expect(page0.instanceCount).toBe(1);
|
|
245
229
|
expect(page1.instanceCount).toBe(1);
|
|
246
|
-
expect(page0.atlas
|
|
247
|
-
expect(page1.atlas
|
|
248
|
-
expect(page0.atlas
|
|
249
|
-
expect(page1.atlas
|
|
230
|
+
expect(page0.atlas.texture?.storage.image).toBe(page0Image);
|
|
231
|
+
expect(page1.atlas.texture?.storage.image).toBe(page1Image);
|
|
232
|
+
expect(page0.atlas.regions[0].x).toBe(0); // A's rect on page 0
|
|
233
|
+
expect(page1.atlas.regions[0].x).toBe(3); // B's rect on page 1
|
|
250
234
|
expect(page0.transforms[0]).toBe(0); // A at pen origin
|
|
251
235
|
expect(page1.transforms[0]).toBe(10); // B after A's advance (no kerning)
|
|
252
236
|
});
|