[canvaskit] Add test to prove we have COLRv1 font support

Pardon the duplicate test file, I have not yet finished
moving the CanvasKit tests to be on Bazel. When I do,
the duplicate (font.spec.js) will go away.

Change-Id: I6ad468f3f322280ffa25429fb8732e7266703e91
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/526297
Reviewed-by: Ben Wagner <bungeman@google.com>
This commit is contained in:
Kevin Lubick 2022-03-31 10:52:50 -04:00
parent 1422409d32
commit dabc752c3f
6 changed files with 124 additions and 14 deletions

View File

@ -13,6 +13,20 @@ CanvasKit._extraInitializations.push(function() {
CanvasKit._free(strPtr);
};
CanvasKit.Canvas.prototype.drawGlyphs = function(glyphs, positions, x, y, font, paint) {
if (!(glyphs.length*2 <= positions.length)) {
throw 'Not enough positions for the array of gyphs';
}
CanvasKit.setCurrentContext(this._context);
const glyphs_ptr = copy1dArray(glyphs, 'HEAPU16');
const positions_ptr = copy1dArray(positions, 'HEAPF32');
this._drawGlyphs(glyphs.length, glyphs_ptr, positions_ptr, x, y, font, paint);
freeArraysThatAreNotMallocedByUsers(positions_ptr, positions);
freeArraysThatAreNotMallocedByUsers(glyphs_ptr, glyphs);
};
// Glyphs should be a Uint16Array of glyph ids, e.g. provided by Font.getGlyphIDs.
// If using a Malloc'd array, be sure to use CanvasKit.MallocGlyphIDs() to get the right type.
// The return value will be a Float32Array that is 4 times as long as the input array. For each

View File

@ -577,20 +577,6 @@ CanvasKit.onRuntimeInitialized = function() {
this._drawDRRect(oPtr, iPtr, paint);
};
CanvasKit.Canvas.prototype.drawGlyphs = function(glyphs, positions, x, y, font, paint) {
if (!(glyphs.length*2 <= positions.length)) {
throw 'Not enough positions for the array of gyphs';
}
CanvasKit.setCurrentContext(this._context);
const glyphs_ptr = copy1dArray(glyphs, 'HEAPU16');
const positions_ptr = copy1dArray(positions, 'HEAPF32');
this._drawGlyphs(glyphs.length, glyphs_ptr, positions_ptr, x, y, font, paint);
freeArraysThatAreNotMallocedByUsers(positions_ptr, positions);
freeArraysThatAreNotMallocedByUsers(glyphs_ptr, glyphs);
};
CanvasKit.Canvas.prototype.drawImage = function(img, x, y, paint) {
CanvasKit.setCurrentContext(this._context);
this._drawImage(img, x, y, paint || null);

View File

@ -19,6 +19,7 @@ filegroup(
"mandrill_512.png",
"mandrill_h1v1.jpg",
"map-shield.json",
"more_samples-glyf_colr_1.ttf",
"red_line.skp",
"test.ttc",
],

View File

@ -18,10 +18,19 @@ describe('Font Behavior', () => {
bungeeFontBuffer = buffer;
});
let colrv1FontBuffer = null;
// This font has glyphs for COLRv1. Also used in gms/colrv1.cpp
const colrv1FontLoaded = fetch('/assets/more_samples-glyf_colr_1.ttf').then(
(response) => response.arrayBuffer()).then(
(buffer) => {
colrv1FontBuffer = buffer;
});
beforeEach(async () => {
await EverythingLoaded;
await notoSerifFontLoaded;
await bungeeFontLoaded;
await colrv1FontLoaded;
container = document.createElement('div');
container.innerHTML = `
<canvas width=600 height=600 id=test></canvas>
@ -413,4 +422,49 @@ describe('Font Behavior', () => {
font.delete();
});
gm('colrv1_gradients', (canvas) => {
// Inspired by gm/colrv1.cpp, specifically the kColorFontsRepoGradients one.
canvas.clear(CanvasKit.WHITE);
const colrFace = CanvasKit.Typeface.MakeFreeTypeFaceFromData(colrv1FontBuffer);
const textPaint = new CanvasKit.Paint();
const annotationFont = new CanvasKit.Font(null, 20);
canvas.drawText('You should see 4 lines of gradient glyphs below',
5, 25, textPaint, annotationFont);
// These glyphIDs show off gradients in the COLRv1 font.
const glyphIDs = [2, 5, 6, 7, 8, 55];
const testFont = new CanvasKit.Font(colrFace);
const sizes = [12, 18, 30, 100];
let y = 30;
for (let i = 0; i < sizes.length; i++) {
const size = sizes[i];
testFont.setSize(size);
const metrics = testFont.getMetrics();
y -= metrics.ascent;
const positions = calculateRun(testFont, glyphIDs)
canvas.drawGlyphs(glyphIDs, positions, 5, y, testFont, textPaint);
y += metrics.descent + metrics.leading;
}
textPaint.delete();
annotationFont.delete();
testFont.delete();
colrFace.delete();
});
function calculateRun(font, glyphIDs) {
const spacing = 5; // put 5 pixels between each glyph
const bounds = font.getGlyphBounds(glyphIDs);
const positions = [0, 0];
let width = 0;
for (let i = 0; i < glyphIDs.length - 1; i++) {
// subtract the right bounds from the left bounds to get glyph width
const glyphWidth = bounds[2 + i*4] - bounds[i*4];
width += glyphWidth + spacing
positions.push(width, 0);
}
return positions;
}
});

View File

@ -18,10 +18,19 @@ describe('Font Behavior', () => {
bungeeFontBuffer = buffer;
});
let colrv1FontBuffer = null;
// This font has glyphs for COLRv1. Also used in gms/colrv1.cpp
const colrv1FontLoaded = fetch('/assets/more_samples-glyf_colr_1.ttf').then(
(response) => response.arrayBuffer()).then(
(buffer) => {
colrv1FontBuffer = buffer;
});
beforeEach(async () => {
await LoadCanvasKit;
await notoSerifFontLoaded;
await bungeeFontLoaded;
await colrv1FontLoaded;
container = document.createElement('div');
container.innerHTML = `
<canvas width=600 height=600 id=test></canvas>
@ -413,4 +422,50 @@ describe('Font Behavior', () => {
font.delete();
});
gm('colrv1_gradients', (canvas) => {
// Inspired by gm/colrv1.cpp, specifically the kColorFontsRepoGradients one.
canvas.clear(CanvasKit.WHITE);
const colrFace = CanvasKit.Typeface.MakeFreeTypeFaceFromData(colrv1FontBuffer);
const textPaint = new CanvasKit.Paint();
const annotationFont = new CanvasKit.Font(null, 20);
canvas.drawText('You should see 4 lines of gradient glyphs below',
5, 25, textPaint, annotationFont);
// These glyphIDs show off gradients in the COLRv1 font.
const glyphIDs = [2, 5, 6, 7, 8, 55];
const testFont = new CanvasKit.Font(colrFace);
const sizes = [12, 18, 30, 100];
let y = 30;
for (let i = 0; i < sizes.length; i++) {
const size = sizes[i];
testFont.setSize(size);
const metrics = testFont.getMetrics();
y -= metrics.ascent;
const positions = calculateRun(testFont, glyphIDs)
canvas.drawGlyphs(glyphIDs, positions, 5, y, testFont, textPaint);
y += metrics.descent + metrics.leading;
}
textPaint.delete();
annotationFont.delete();
testFont.delete();
colrFace.delete();
});
function calculateRun(font, glyphIDs) {
const spacing = 5; // put 5 pixels between each glyph
const bounds = font.getGlyphBounds(glyphIDs);
const positions = [0, 0];
let width = 0;
for (let i = 0; i < glyphIDs.length - 1; i++) {
// subtract the right bounds from the left bounds to get glyph width
const glyphWidth = bounds[2 + i*4] - bounds[i*4];
width += glyphWidth + spacing
positions.push(width, 0);
}
return positions;
}
});