@flighthq/bitmaptext 0.2.1-next.841.373388f → 0.3.0-edge.1516.1b4fb2b
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 +23 -34
- package/src/updateBitmapText.test.ts +79 -94
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, setTextureSource } 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({ dimension: '2d', source: image });
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
setTextureSource(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-edge.1516.1b4fb2b",
|
|
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-edge.1516.1b4fb2b",
|
|
40
|
+
"@flighthq/geometry": "0.3.0-edge.1516.1b4fb2b",
|
|
41
|
+
"@flighthq/node": "0.3.0-edge.1516.1b4fb2b",
|
|
42
|
+
"@flighthq/texture": "0.3.0-edge.1516.1b4fb2b",
|
|
43
|
+
"@flighthq/textureatlas": "0.3.0-edge.1516.1b4fb2b",
|
|
44
|
+
"@flighthq/types": "0.3.0-edge.1516.1b4fb2b"
|
|
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, Image } 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,
|
|
@@ -23,7 +21,7 @@ import {
|
|
|
23
21
|
} from './bitmapText';
|
|
24
22
|
import { updateBitmapText } from './updateBitmapText';
|
|
25
23
|
|
|
26
|
-
// A single-page glyph source: A/B are 6x8, a space advances 5, and page 0 is a stub `
|
|
24
|
+
// A single-page glyph source: A/B are 6x8, a space advances 5, and page 0 is a stub `Image`.
|
|
27
25
|
function createTestGlyphSource(): GlyphSource {
|
|
28
26
|
const entries = new Map<number, GlyphEntry>();
|
|
29
27
|
const add = (cp: number, x: number): void => {
|
|
@@ -32,7 +30,7 @@ function createTestGlyphSource(): GlyphSource {
|
|
|
32
30
|
add(0x41, 0); // A
|
|
33
31
|
add(0x42, 6); // B
|
|
34
32
|
entries.set(0x20, { advance: 5, bearingX: 0, bearingY: 0, height: 0, page: 0, width: 0, x: 0, y: 0 }); // space
|
|
35
|
-
const image = {} as
|
|
33
|
+
const image = {} as Image;
|
|
36
34
|
return {
|
|
37
35
|
getGlyphAtlasImage: (page = 0) => (page === 0 ? image : null),
|
|
38
36
|
getGlyphEntry: (cp) => entries.get(cp) ?? null,
|
|
@@ -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,17 +3,17 @@ import {
|
|
|
3
3
|
createGlyphSourceFromGlyphAtlas,
|
|
4
4
|
createStubGlyphRasterizerBackend,
|
|
5
5
|
setGlyphRasterizerBackend,
|
|
6
|
-
} from '@flighthq/glyphatlas';
|
|
7
|
-
import {
|
|
8
|
-
import type {
|
|
6
|
+
} from '@flighthq/glyphatlas/contract';
|
|
7
|
+
import { getTextureSource } from '@flighthq/texture/contract';
|
|
8
|
+
import type { GlyphEntry, GlyphSource, Image } from '@flighthq/types/contract';
|
|
9
9
|
import { describe, expect, it } from 'vitest';
|
|
10
10
|
|
|
11
|
-
import { createBitmapText, getBitmapTextBounds,
|
|
11
|
+
import { createBitmapText, getBitmapTextBounds, getBitmapTextPages } from './bitmapText';
|
|
12
12
|
import { updateBitmapText } from './updateBitmapText';
|
|
13
13
|
|
|
14
14
|
// A deterministic single-page glyph source: every visible glyph is 6x8 with advance 10 and bearingY 8
|
|
15
15
|
// (so line tops sit at y=0), a space advances 5 with no pixels, and the pair (A, B) kerns by -2. All
|
|
16
|
-
// glyphs live on page 0, whose atlas image is a stub `
|
|
16
|
+
// glyphs live on page 0, whose atlas image is a stub `Image`.
|
|
17
17
|
function createTestGlyphSource(): GlyphSource {
|
|
18
18
|
const entries = new Map<number, GlyphEntry>();
|
|
19
19
|
const add = (cp: number, x: number): void => {
|
|
@@ -23,7 +23,7 @@ function createTestGlyphSource(): GlyphSource {
|
|
|
23
23
|
add(0x42, 6); // B
|
|
24
24
|
entries.set(0x20, { advance: 5, bearingX: 0, bearingY: 0, height: 0, page: 0, width: 0, x: 0, y: 0 }); // space
|
|
25
25
|
const kerning = new Map<number, number>([[(0x41 << 16) | 0x42, -2]]);
|
|
26
|
-
const image = {} as
|
|
26
|
+
const image = {} as Image;
|
|
27
27
|
return {
|
|
28
28
|
getGlyphAtlasImage: (page = 0) => (page === 0 ? image : null),
|
|
29
29
|
getGlyphEntry: (cp) => entries.get(cp) ?? null,
|
|
@@ -33,9 +33,9 @@ function createTestGlyphSource(): GlyphSource {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// A two-page glyph source: 'A' lives on page 0, 'B' on page 1, each page a DISTINCT stub image.
|
|
36
|
-
function createTwoPageGlyphSource(): { source: GlyphSource; page0Image:
|
|
37
|
-
const page0Image = {} as
|
|
38
|
-
const page1Image = {} as
|
|
36
|
+
function createTwoPageGlyphSource(): { source: GlyphSource; page0Image: Image; page1Image: Image } {
|
|
37
|
+
const page0Image = {} as Image;
|
|
38
|
+
const page1Image = {} as Image;
|
|
39
39
|
const entries = new Map<number, GlyphEntry>([
|
|
40
40
|
[0x41, { advance: 10, bearingX: 0, bearingY: 8, height: 8, page: 0, width: 6, x: 0, y: 0 }], // A → page 0
|
|
41
41
|
[0x42, { advance: 10, bearingX: 0, bearingY: 8, height: 8, page: 1, width: 6, x: 3, y: 0 }], // B → page 1
|
|
@@ -59,9 +59,9 @@ describe('updateBitmapText', () => {
|
|
|
59
59
|
const atlas = createGlyphAtlas({ fontFamily: 'unavailable', fontSize: 24, height: 256, width: 256 });
|
|
60
60
|
const text = createBitmapText(createGlyphSourceFromGlyphAtlas(atlas), { text: 'Hi' });
|
|
61
61
|
updateBitmapText(text);
|
|
62
|
-
const
|
|
63
|
-
expect(
|
|
64
|
-
expect(
|
|
62
|
+
const pages = getBitmapTextPages(text);
|
|
63
|
+
expect(pages.length).toBeGreaterThan(0);
|
|
64
|
+
expect(pages[0]!.instanceCount).toBe(2);
|
|
65
65
|
} finally {
|
|
66
66
|
setGlyphRasterizerBackend(null);
|
|
67
67
|
}
|
|
@@ -70,63 +70,63 @@ describe('updateBitmapText', () => {
|
|
|
70
70
|
it('places each glyph at its cumulative advance, applying kerning', () => {
|
|
71
71
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB' });
|
|
72
72
|
updateBitmapText(text);
|
|
73
|
-
const
|
|
74
|
-
expect(
|
|
75
|
-
expect(
|
|
76
|
-
expect(
|
|
77
|
-
expect(
|
|
78
|
-
expect(
|
|
73
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
74
|
+
expect(page.instanceCount).toBe(2);
|
|
75
|
+
expect(page.transforms[0]).toBe(0); // A.x
|
|
76
|
+
expect(page.transforms[1]).toBe(0); // A.y
|
|
77
|
+
expect(page.transforms[2]).toBe(8); // B.x = 10 (advance) - 2 (kerning)
|
|
78
|
+
expect(page.transforms[3]).toBe(0); // B.y
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
it('builds one atlas region per distinct glyph and references it by id', () => {
|
|
82
82
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB' });
|
|
83
83
|
updateBitmapText(text);
|
|
84
|
-
const
|
|
85
|
-
expect(
|
|
86
|
-
expect(
|
|
87
|
-
expect(
|
|
88
|
-
expect(
|
|
89
|
-
expect(
|
|
84
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
85
|
+
expect(page.atlas.regions).toHaveLength(2);
|
|
86
|
+
expect(page.ids[0]).toBe(0);
|
|
87
|
+
expect(page.ids[1]).toBe(1);
|
|
88
|
+
expect(page.atlas.regions[0].x).toBe(0); // A rect
|
|
89
|
+
expect(page.atlas.regions[1].x).toBe(6); // B rect
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
it('reuses one region for repeated codepoints', () => {
|
|
93
93
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA' });
|
|
94
94
|
updateBitmapText(text);
|
|
95
|
-
const
|
|
96
|
-
expect(
|
|
97
|
-
expect(
|
|
98
|
-
expect(
|
|
99
|
-
expect(
|
|
95
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
96
|
+
expect(page.instanceCount).toBe(2);
|
|
97
|
+
expect(page.atlas.regions).toHaveLength(1);
|
|
98
|
+
expect(page.ids[0]).toBe(0);
|
|
99
|
+
expect(page.ids[1]).toBe(0);
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
it('starts a new line at the metric line advance on an explicit newline', () => {
|
|
103
103
|
const text = createBitmapText(createTestGlyphSource(), { text: 'A\nB' });
|
|
104
104
|
updateBitmapText(text);
|
|
105
|
-
const
|
|
106
|
-
expect(
|
|
107
|
-
expect(
|
|
108
|
-
expect(
|
|
109
|
-
expect(
|
|
110
|
-
expect(
|
|
105
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
106
|
+
expect(page.instanceCount).toBe(2);
|
|
107
|
+
expect(page.transforms[0]).toBe(0); // line 0 A.x
|
|
108
|
+
expect(page.transforms[1]).toBe(0); // line 0 A.y
|
|
109
|
+
expect(page.transforms[2]).toBe(0); // line 1 B.x
|
|
110
|
+
expect(page.transforms[3]).toBe(10); // line 1 B.y = 1 * (8 + 2 + 0)
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
it('scales the line advance by lineHeight', () => {
|
|
114
114
|
const text = createBitmapText(createTestGlyphSource(), { text: 'A\nB', lineHeight: 2 });
|
|
115
115
|
updateBitmapText(text);
|
|
116
|
-
const
|
|
117
|
-
expect(
|
|
116
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
117
|
+
expect(page.transforms[3]).toBe(20); // 2 * (8 + 2 + 0)
|
|
118
118
|
});
|
|
119
119
|
|
|
120
120
|
it('word-wraps at a word boundary when the width is exceeded', () => {
|
|
121
121
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA AA', wrapWidth: 30 });
|
|
122
122
|
updateBitmapText(text);
|
|
123
|
-
const
|
|
124
|
-
expect(
|
|
123
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
124
|
+
expect(page.instanceCount).toBe(4);
|
|
125
125
|
let firstLine = 0;
|
|
126
126
|
let secondLine = 0;
|
|
127
|
-
for (let i = 0; i <
|
|
128
|
-
if (
|
|
129
|
-
else if (
|
|
127
|
+
for (let i = 0; i < page.instanceCount; i++) {
|
|
128
|
+
if (page.transforms[i * 2 + 1] === 0) firstLine++;
|
|
129
|
+
else if (page.transforms[i * 2 + 1] === 10) secondLine++;
|
|
130
130
|
}
|
|
131
131
|
expect(firstLine).toBe(2);
|
|
132
132
|
expect(secondLine).toBe(2);
|
|
@@ -135,62 +135,62 @@ describe('updateBitmapText', () => {
|
|
|
135
135
|
it('keeps words on one line and honors space advance when no wrap is set', () => {
|
|
136
136
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA AA' });
|
|
137
137
|
updateBitmapText(text);
|
|
138
|
-
const
|
|
139
|
-
expect(
|
|
140
|
-
for (let i = 0; i <
|
|
141
|
-
expect(
|
|
142
|
-
expect(
|
|
138
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
139
|
+
expect(page.instanceCount).toBe(4);
|
|
140
|
+
for (let i = 0; i < page.instanceCount; i++) expect(page.transforms[i * 2 + 1]).toBe(0);
|
|
141
|
+
expect(page.transforms[4]).toBe(25); // third glyph: word1 width 20 + space 5
|
|
142
|
+
expect(page.transforms[6]).toBe(35);
|
|
143
143
|
});
|
|
144
144
|
|
|
145
145
|
it('offsets a line for center alignment', () => {
|
|
146
146
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB', wrapWidth: 100, align: 'center' });
|
|
147
147
|
updateBitmapText(text);
|
|
148
|
-
const
|
|
149
|
-
expect(
|
|
150
|
-
expect(
|
|
148
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
149
|
+
expect(page.transforms[0]).toBe(41); // (100 - 18) / 2
|
|
150
|
+
expect(page.transforms[2]).toBe(49); // 41 + 8
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
it('offsets a line for right alignment', () => {
|
|
154
154
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB', wrapWidth: 100, align: 'right' });
|
|
155
155
|
updateBitmapText(text);
|
|
156
|
-
const
|
|
157
|
-
expect(
|
|
156
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
157
|
+
expect(page.transforms[0]).toBe(82); // 100 - 18
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
it('stretches inter-word gaps for justify on non-final lines', () => {
|
|
161
161
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AA AA AA', wrapWidth: 50, align: 'justify' });
|
|
162
162
|
updateBitmapText(text);
|
|
163
|
-
const
|
|
163
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
164
164
|
// 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(
|
|
165
|
+
expect(page.transforms[4]).toBe(30);
|
|
166
|
+
expect(page.transforms[6]).toBe(40);
|
|
167
167
|
// Line 1 = trailing "AA" (paragraph end) stays left.
|
|
168
168
|
const line1 = [];
|
|
169
|
-
for (let i = 0; i <
|
|
170
|
-
if (
|
|
169
|
+
for (let i = 0; i < page.instanceCount; i++)
|
|
170
|
+
if (page.transforms[i * 2 + 1] === 10) line1.push(page.transforms[i * 2]);
|
|
171
171
|
expect(line1).toEqual([0, 10]);
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
it('omits a missing glyph with no quad and no advance', () => {
|
|
175
175
|
const text = createBitmapText(createTestGlyphSource(), { text: 'A?B' });
|
|
176
176
|
updateBitmapText(text);
|
|
177
|
-
const
|
|
178
|
-
expect(
|
|
179
|
-
expect(
|
|
180
|
-
expect(
|
|
177
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
178
|
+
expect(page.instanceCount).toBe(2);
|
|
179
|
+
expect(page.transforms[0]).toBe(0); // A
|
|
180
|
+
expect(page.transforms[2]).toBe(8); // B placed as if '?' were absent (10 - 2 kerning)
|
|
181
181
|
});
|
|
182
182
|
|
|
183
183
|
it('adds letterSpacing after each glyph advance', () => {
|
|
184
184
|
const text = createBitmapText(createTestGlyphSource(), { text: 'AB', letterSpacing: 1 });
|
|
185
185
|
updateBitmapText(text);
|
|
186
|
-
const
|
|
187
|
-
expect(
|
|
186
|
+
const page = getBitmapTextPages(text)[0]!;
|
|
187
|
+
expect(page.transforms[2]).toBe(9); // 10 + 1 (spacing) - 2 (kerning)
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
-
it('lays out an empty string as an empty
|
|
190
|
+
it('lays out an empty string as an empty page without throwing', () => {
|
|
191
191
|
const text = createBitmapText(createTestGlyphSource(), { text: '' });
|
|
192
192
|
expect(() => updateBitmapText(text)).not.toThrow();
|
|
193
|
-
expect(
|
|
193
|
+
expect(getBitmapTextPages(text)[0]!.instanceCount).toBe(0);
|
|
194
194
|
const bounds = getBitmapTextBounds(text);
|
|
195
195
|
expect(bounds.width).toBe(0);
|
|
196
196
|
expect(bounds.height).toBe(0);
|
|
@@ -206,47 +206,32 @@ describe('updateBitmapText', () => {
|
|
|
206
206
|
expect(bounds.height).toBe(8);
|
|
207
207
|
});
|
|
208
208
|
|
|
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', () => {
|
|
209
|
+
it('produces exactly one page bound to the page-0 image for a single-page source', () => {
|
|
225
210
|
const source = createTestGlyphSource();
|
|
226
211
|
const text = createBitmapText(source, { text: 'AB' });
|
|
227
212
|
updateBitmapText(text);
|
|
228
|
-
const
|
|
229
|
-
expect(
|
|
230
|
-
expect(
|
|
231
|
-
expect(
|
|
213
|
+
const pages = getBitmapTextPages(text);
|
|
214
|
+
expect(pages).toHaveLength(1);
|
|
215
|
+
expect(pages[0].instanceCount).toBe(2);
|
|
216
|
+
expect(getTextureSource(pages[0].atlas.texture!)).toBe(source.getGlyphAtlasImage(0));
|
|
232
217
|
});
|
|
233
218
|
|
|
234
|
-
it('partitions glyphs into one
|
|
219
|
+
it('partitions glyphs into one page per glyph-atlas page, each bound to its own page image', () => {
|
|
235
220
|
const { source, page0Image, page1Image } = createTwoPageGlyphSource();
|
|
236
221
|
const text = createBitmapText(source, { text: 'AB' });
|
|
237
222
|
updateBitmapText(text);
|
|
238
|
-
const
|
|
239
|
-
expect(
|
|
223
|
+
const pages = getBitmapTextPages(text);
|
|
224
|
+
expect(pages).toHaveLength(2);
|
|
240
225
|
|
|
241
226
|
// Page 0 holds 'A' only, sampling page0Image; page 1 holds 'B' only, sampling page1Image.
|
|
242
|
-
const page0 =
|
|
243
|
-
const page1 =
|
|
227
|
+
const page0 = pages[0];
|
|
228
|
+
const page1 = pages[1];
|
|
244
229
|
expect(page0.instanceCount).toBe(1);
|
|
245
230
|
expect(page1.instanceCount).toBe(1);
|
|
246
|
-
expect(page0.atlas
|
|
247
|
-
expect(page1.atlas
|
|
248
|
-
expect(page0.atlas
|
|
249
|
-
expect(page1.atlas
|
|
231
|
+
expect(getTextureSource(page0.atlas.texture!)).toBe(page0Image);
|
|
232
|
+
expect(getTextureSource(page1.atlas.texture!)).toBe(page1Image);
|
|
233
|
+
expect(page0.atlas.regions[0].x).toBe(0); // A's rect on page 0
|
|
234
|
+
expect(page1.atlas.regions[0].x).toBe(3); // B's rect on page 1
|
|
250
235
|
expect(page0.transforms[0]).toBe(0); // A at pen origin
|
|
251
236
|
expect(page1.transforms[0]).toBe(10); // B after A's advance (no kerning)
|
|
252
237
|
});
|