Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added tests/src/core/2d/text/Roboto-Regular-subset.ttf
Binary file not shown.
117 changes: 63 additions & 54 deletions tests/src/core/2d/text/TextUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,19 @@ describe("TextUtils", () => {
let textRendererOverflow: TextRenderer;
let wrap1TextRenderer: TextRenderer;
let wrap2TextRenderer: TextRenderer;
const testFontName = "RobotoSubsetTest";

beforeAll(async function () {
// Load a fixed Roboto subset so that font metrics are deterministic across machines, instead of
// depending on the host "Arial" which is a different font file per OS and rasterizes differently.
// Font: Roboto-Regular v2.137, Apache-2.0, subset to Latin glyphs for these tests.
// See https://github.com/galacean/engine/issues/3043
const fontUrl = new URL("./Roboto-Regular-subset.ttf", import.meta.url).href;
const testFont = new FontFace(testFontName, `url(${fontUrl})`);
await testFont.load();
document.fonts.add(testFont);
await document.fonts.ready;

engine = await WebGLEngine.create({
canvas: document.createElement("canvas")
});
Expand All @@ -46,15 +57,15 @@ describe("TextUtils", () => {
textEntity4 = rootEntity.createChild("text4");

textRendererTruncate = textEntity1.addComponent(TextRenderer);
textRendererTruncate.font = Font.createFromOS(engine, "Arial");
textRendererTruncate.font = Font.createFromOS(engine, testFontName);

textRendererOverflow = textEntity2.addComponent(TextRenderer);
textRendererOverflow.font = Font.createFromOS(engine, "Arial");
textRendererOverflow.font = Font.createFromOS(engine, testFontName);

wrap1TextRenderer = textEntity3.addComponent(TextRenderer);
wrap1TextRenderer.font = Font.createFromOS(engine, "Arial");
wrap1TextRenderer.font = Font.createFromOS(engine, testFontName);
wrap2TextRenderer = textEntity4.addComponent(TextRenderer);
wrap2TextRenderer.font = Font.createFromOS(engine, "Arial");
wrap2TextRenderer.font = Font.createFromOS(engine, testFontName);

engine.run();
});
Expand Down Expand Up @@ -167,7 +178,7 @@ describe("TextUtils", () => {
"步",
"。"
]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererTruncate.text = text2;
result = TextUtils.measureTextWithWrap(
textRendererTruncate,
Expand All @@ -193,10 +204,10 @@ describe("TextUtils", () => {
"at",
"to",
"d",
"a",
"y."
"ay",
"."
]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererTruncate.text = text3;
result = TextUtils.measureTextWithWrap(
textRendererTruncate,
Expand Down Expand Up @@ -226,11 +237,10 @@ describe("TextUtils", () => {
"at",
"to",
"d",
"a",
"y",
"ay",
"。"
]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererTruncate.text = text4;
result = TextUtils.measureTextWithWrap(
textRendererTruncate,
Expand All @@ -239,10 +249,10 @@ describe("TextUtils", () => {
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(23);
expect(result.width).to.be.equal(24);
expect(result.height).to.be.equal(100);
expect(result.lines).to.be.deep.equal([" ", " ", "W", "or", "ld"]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lines).to.be.deep.equal([" ", " ", "W", "or", "ld"]);
expect(result.lineHeight).to.be.closeTo(28, 1);

// Test that measureTextWithWrap works correctly, while set overflow mode to overflow.
textRendererOverflow.overflowMode = OverflowMode.Overflow;
Expand All @@ -261,7 +271,7 @@ describe("TextUtils", () => {
0
);
expect(result.width).to.be.equal(24);
expect(result.height).to.be.equal(567);
expect(result.height).to.be.closeTo(588, 21);
expect(result.lines).to.be.deep.equal([
"趚",
"今",
Expand All @@ -285,7 +295,7 @@ describe("TextUtils", () => {
"步",
"。"
]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererOverflow.text = text2;
result = TextUtils.measureTextWithWrap(
textRendererOverflow,
Expand All @@ -295,7 +305,7 @@ describe("TextUtils", () => {
0
);
expect(result.width).to.be.equal(24);
expect(result.height).to.be.equal(432);
expect(result.height).to.be.closeTo(448, 16);
expect(result.lines).to.be.deep.equal([
"T",
"h",
Expand All @@ -311,10 +321,10 @@ describe("TextUtils", () => {
"at",
"to",
"d",
"a",
"y."
"ay",
"."
]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererOverflow.text = text3;
result = TextUtils.measureTextWithWrap(
textRendererOverflow,
Expand All @@ -324,7 +334,7 @@ describe("TextUtils", () => {
0
);
expect(result.width).to.be.equal(24);
expect(result.height).to.be.equal(567);
expect(result.height).to.be.closeTo(560, 20);
expect(result.lines).to.be.deep.equal([
"阳",
"光",
Expand All @@ -344,11 +354,10 @@ describe("TextUtils", () => {
"at",
"to",
"d",
"a",
"y",
"ay",
"。"
]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererOverflow.text = text4;
result = TextUtils.measureTextWithWrap(
textRendererOverflow,
Expand All @@ -357,10 +366,10 @@ describe("TextUtils", () => {
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(23);
expect(result.height).to.be.equal(135);
expect(result.lines).to.be.deep.equal([" ", " ", "W", "or", "ld"]);
expect(result.lineHeight).to.be.equal(27);
expect(result.width).to.be.equal(24);
expect(result.height).to.be.closeTo(140, 5);
expect(result.lines).to.be.deep.equal([" ", " ", "W", "or", "ld"]);
expect(result.lineHeight).to.be.closeTo(28, 1);

wrap1TextRenderer.enableWrapping = true;
wrap1TextRenderer.width = 5;
Expand Down Expand Up @@ -405,11 +414,11 @@ describe("TextUtils", () => {
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(518);
expect(result.width).to.be.equal(516);
expect(result.height).to.be.equal(100);
expect(result.lines).to.be.deep.equal(["趚今天天气很好,阳光明媚。我 在公园里 漫步。"]);
expect(result.lineWidths).to.be.deep.equal([518]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineWidths).to.be.deep.equal([516]);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererTruncate.text = text2;
result = TextUtils.measureTextWithoutWrap(
textRendererTruncate,
Expand All @@ -421,31 +430,31 @@ describe("TextUtils", () => {
expect(result.height).to.be.equal(100);
expect(result.lines).to.be.deep.equal(["The weather is great today."]);
expect(result.lineWidths).to.be.deep.equal([289]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererTruncate.text = text3;
result = TextUtils.measureTextWithoutWrap(
textRendererTruncate,
textRendererTruncate.height * _pixelsPerUnit,
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(418);
expect(result.width).to.be.equal(421);
expect(result.height).to.be.equal(100);
expect(result.lines).to.be.deep.equal(["阳光明媚,the weather is great today。"]);
expect(result.lineWidths).to.be.deep.equal([418]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineWidths).to.be.deep.equal([421]);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererTruncate.text = text4;
result = TextUtils.measureTextWithoutWrap(
textRendererTruncate,
textRendererTruncate.height * _pixelsPerUnit,
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(111);
expect(result.width).to.be.equal(105);
expect(result.height).to.be.equal(100);
expect(result.lines).to.be.deep.equal([" ", " World"]);
expect(result.lineWidths).to.be.deep.equal([63, 111]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineWidths).to.be.deep.equal([54, 105]);
expect(result.lineHeight).to.be.closeTo(28, 1);

// Test that measureTextWithoutWrap works correctly, while set overflow mode to overflow.
textRendererOverflow.overflowMode = OverflowMode.Overflow;
Expand All @@ -465,7 +474,7 @@ describe("TextUtils", () => {
expect(result.height).to.be.equal(0);
expect(result.lines).to.be.deep.equal([]);
expect(result.lineWidths).to.be.deep.equal([]);
expect(result.lineHeight).to.be.deep.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);

textRendererOverflow.text = undefined;
result = TextUtils.measureTextWithoutWrap(
Expand All @@ -478,7 +487,7 @@ describe("TextUtils", () => {
expect(result.height).to.be.equal(0);
expect(result.lines).to.be.deep.equal([]);
expect(result.lineWidths).to.be.deep.equal([]);
expect(result.lineHeight).to.be.deep.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);

textRendererOverflow.text = text1;
result = TextUtils.measureTextWithoutWrap(
Expand All @@ -487,11 +496,11 @@ describe("TextUtils", () => {
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(518);
expect(result.height).to.be.equal(27);
expect(result.width).to.be.equal(516);
expect(result.height).to.be.closeTo(28, 1);
expect(result.lines).to.be.deep.equal(["趚今天天气很好,阳光明媚。我 在公园里 漫步。"]);
expect(result.lineWidths).to.be.deep.equal([518]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineWidths).to.be.deep.equal([516]);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererOverflow.text = text2;
result = TextUtils.measureTextWithoutWrap(
textRendererOverflow,
Expand All @@ -500,34 +509,34 @@ describe("TextUtils", () => {
0
);
expect(result.width).to.be.equal(289);
expect(result.height).to.be.equal(27);
expect(result.height).to.be.closeTo(28, 1);
expect(result.lines).to.be.deep.equal(["The weather is great today."]);
expect(result.lineWidths).to.be.deep.equal([289]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererOverflow.text = text3;
result = TextUtils.measureTextWithoutWrap(
textRendererOverflow,
textRendererTruncate.height * _pixelsPerUnit,
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(418);
expect(result.height).to.be.equal(27);
expect(result.width).to.be.equal(421);
expect(result.height).to.be.closeTo(28, 1);
expect(result.lines).to.be.deep.equal(["阳光明媚,the weather is great today。"]);
expect(result.lineWidths).to.be.deep.equal([418]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineWidths).to.be.deep.equal([421]);
expect(result.lineHeight).to.be.closeTo(28, 1);
textRendererOverflow.text = text4;
result = TextUtils.measureTextWithoutWrap(
textRendererOverflow,
textRendererTruncate.height * _pixelsPerUnit,
textRendererTruncate.lineSpacing * _pixelsPerUnit,
0
);
expect(result.width).to.be.equal(111);
expect(result.height).to.be.equal(54);
expect(result.width).to.be.equal(105);
expect(result.height).to.be.closeTo(56, 2);
expect(result.lines).to.be.deep.equal([" ", " World"]);
expect(result.lineWidths).to.be.deep.equal([63, 111]);
expect(result.lineHeight).to.be.equal(27);
expect(result.lineWidths).to.be.deep.equal([54, 105]);
expect(result.lineHeight).to.be.closeTo(28, 1);
});

it("getNativeFontHash", () => {
Expand Down
6 changes: 6 additions & 0 deletions tests/src/core/input/InputManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ describe("InputManager", async () => {
target.dispatchEvent(generateKeyboardEvent("keydown", "KeyA"));
target.dispatchEvent(generateKeyboardEvent("keyup", "MetaRight"));
expect(inputManager.isKeyHeldDown(Keys.KeyA)).to.eq(false);

// The events above are queued but never consumed by an `update` in this case. Reset the keyboard
// state so the pending `KeyA` keydown does not leak into later cases (it otherwise stays held down
// on non-mac platforms, where the meta-key cleanup in KeyboardManager does not run).
target.dispatchEvent(new Event("blur"));
engine.update();
});

it("wheel", () => {
Expand Down
Loading