Skip to content

Commit 038047e

Browse files
committed
Enhance system font text rendering under WASM
1 parent f225f94 commit 038047e

File tree

1 file changed

+65
-37
lines changed

1 file changed

+65
-37
lines changed

core/platform/wasm/Device-wasm.cpp

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ THE SOFTWARE.
2828
#include "platform/PlatformConfig.h"
2929
#if AX_TARGET_PLATFORM == AX_PLATFORM_WASM
3030

31-
#include "platform/Device.h"
32-
#include "platform/FileUtils.h"
31+
# include "platform/Device.h"
32+
# include "platform/FileUtils.h"
3333

34-
#include <emscripten/emscripten.h>
35-
#include <emscripten/html5.h>
34+
# include <emscripten/emscripten.h>
35+
# include <emscripten/html5.h>
3636

3737
namespace ax
3838
{
@@ -57,76 +57,102 @@ void Device::setAccelerometerInterval(float interval)
5757
// TODO: https://emscripten.org/docs/api_reference/html5.h.html?
5858
}
5959

60-
Data Device::getTextureDataForText(std::string_view text, const FontDefinition& textDefinition, TextAlign align, int &width, int &height, bool& hasPremultipliedAlpha)
60+
Data Device::getTextureDataForText(std::string_view text,
61+
const FontDefinition& textDefinition,
62+
TextAlign align,
63+
int& width,
64+
int& height,
65+
bool& hasPremultipliedAlpha)
6166
{
6267
char color[8];
63-
sprintf(color, "#%02x%02x%02x", textDefinition._fontFillColor.r, textDefinition._fontFillColor.g, textDefinition._fontFillColor.b);
68+
sprintf(color, "#%02x%02x%02x", textDefinition._fontFillColor.r, textDefinition._fontFillColor.g,
69+
textDefinition._fontFillColor.b);
70+
// clang-format off
6471
unsigned char* ptr = (unsigned char*)EM_ASM_PTR({
6572
var lines = UTF8ToString($0).split("\n");
66-
var linesWidth = [];
6773
var fontName = UTF8ToString($1);
6874
var fontSize = $2;
69-
var lineHeight = $2 * 1.2; // Nothing accurate
7075
var color = UTF8ToString($3);
7176
var dimWidth = $4;
7277
var dimHeight = $5;
7378
var align = $6;
7479

80+
// use shared canvas
7581
var canvas = Module.axmolSharedCanvas = Module.axmolSharedCanvas || document.createElement("canvas");
7682
var context = canvas.getContext('2d', { willReadFrequently: true });
7783
context.font = fontSize + "px " + fontName;
84+
// use alphabetic baseline for text rendering
85+
context.textBaseline = "alphabetic";
86+
87+
var linesWidth = [];
88+
var linesAscent = [];
89+
var linesDescent = [];
90+
var totalHeight = 0;
91+
var maxWidth = dimWidth > 0 ? dimWidth : 0;
7892

79-
var canvasWidth = dimWidth;
80-
var canvasHeight = dimHeight;
93+
// compute per line metrics
8194
for (var i = 0; i < lines.length; i++) {
82-
var lineWidth = context.measureText(lines[i]).width;
83-
linesWidth[i] = lineWidth;
84-
if (lineWidth > canvasWidth && dimWidth <= 0) {
85-
canvasWidth = lineWidth;
95+
var metrics = context.measureText(lines[i]);
96+
var lineWidth = metrics.width;
97+
// if browser not support actualBoundingBoxAscent/descent, use fallback values
98+
var ascent = (typeof metrics.actualBoundingBoxAscent === "number") ? metrics.actualBoundingBoxAscent : fontSize * 0.8;
99+
var descent = (typeof metrics.actualBoundingBoxDescent === "number") ? metrics.actualBoundingBoxDescent : fontSize * 0.2;
100+
var lineHeight = ascent + descent;
101+
linesWidth.push(lineWidth);
102+
linesAscent.push(ascent);
103+
linesDescent.push(descent);
104+
if (dimWidth <= 0 && lineWidth > maxWidth) {
105+
maxWidth = lineWidth;
86106
}
87-
};
107+
totalHeight += lineHeight;
108+
}
88109

89-
if (dimHeight <= 0) {
90-
canvasHeight = lineHeight * lines.length;
110+
// if dimensions are specified, use them to limit the height
111+
if (dimHeight > 0) {
112+
totalHeight = dimHeight;
91113
}
92114

93-
canvasWidth = Math.ceil(canvasWidth);
94-
canvasHeight = Math.ceil(canvasHeight);
115+
var canvasWidth = Math.ceil(maxWidth);
116+
var canvasHeight = Math.ceil(totalHeight);
95117

96118
canvas.width = canvasWidth;
97119
canvas.height = canvasHeight;
98120

99121
context.clearRect(0, 0, canvasWidth, canvasHeight);
100122
context.font = fontSize + "px " + fontName;
101123
context.fillStyle = color;
102-
context.textBaseline = "top";
124+
context.textBaseline = "alphabetic";
103125

104-
//Vertical top
126+
// vertical top
105127
var offsetY = 0;
106-
if ((align & 0xf0) == 0x30) {
107-
//Vertical center
108-
offsetY = (canvasHeight - lineHeight * lines.length) / 2;
109-
} else if ((align & 0xf0) == 0x20) {
110-
//Vertical bottom
111-
offsetY = canvasHeight - lineHeight * lines.length;
128+
if ((align & 0xf0) === 0x30) {
129+
// vertical center align
130+
offsetY = (canvasHeight - totalHeight) / 2;
131+
} else if ((align & 0xf0) === 0x20) {
132+
// bottom align
133+
offsetY = canvasHeight - totalHeight;
112134
}
113135

136+
// draw each line of text
114137
for (var i = 0; i < lines.length; i++) {
115-
//Horizonal left
138+
var lineH = linesAscent[i] + linesDescent[i];
139+
// horizontal left
116140
var offsetX = 0;
117-
if ((align & 0x0f) == 0x03) {
118-
//Horizonal center
141+
if ((align & 0x0f) === 0x03) {
119142
offsetX = (canvasWidth - linesWidth[i]) / 2;
120-
} else if ((align & 0x0f) == 0x02) {
121-
//Horizonal right
143+
} else if ((align & 0x0f) === 0x02) {
122144
offsetX = canvasWidth - linesWidth[i];
123145
}
124-
context.fillText(lines[i], offsetX, offsetY + lineHeight * i);
146+
// use align left by default, offsetX remains 0
147+
var baselineY = offsetY + linesAscent[i];
148+
context.fillText(lines[i], offsetX, baselineY);
149+
offsetY += lineH;
125150
}
126151

152+
// get pixel data from the canvas
127153
var data = context.getImageData(0, 0, canvasWidth, canvasHeight).data;
128-
var ptr = _malloc(data.byteLength); // Cocos Data object free it
129-
var buffer= new Uint8Array(Module.HEAPU8.buffer, ptr, data.byteLength);
154+
var ptr = _malloc(data.byteLength);
155+
var buffer = new Uint8Array(Module.HEAPU8.buffer, ptr, data.byteLength);
130156
buffer.set(data);
131157
return ptr;
132158
}, text.data(), textDefinition._fontName.c_str(), textDefinition._fontSize, color, textDefinition._dimensions.width, textDefinition._dimensions.height, align);
@@ -137,6 +163,8 @@ Data Device::getTextureDataForText(std::string_view text, const FontDefinition&
137163
height = EM_ASM_INT({
138164
return Module.axmolSharedCanvas.height;
139165
});
166+
// clang-format on
167+
140168
hasPremultipliedAlpha = false;
141169

142170
Data ret;
@@ -166,6 +194,6 @@ void Device::prepareSelectionFeedbackGenerator() {}
166194

167195
void Device::selectionChanged() {}
168196

169-
}
197+
} // namespace ax
170198

171-
#endif // AX_TARGET_PLATFORM == AX_PLATFORM_WASM
199+
#endif // AX_TARGET_PLATFORM == AX_PLATFORM_WASM

0 commit comments

Comments
 (0)