Merge pull request #14858 from Snuffleupagus/Type3-Path2D

Use `Path2D`, if available, when rendering Type3-fonts (bug 810214)
This commit is contained in:
Tim van der Meij 2022-05-01 14:29:56 +02:00 committed by GitHub
commit 5ec8c3c191
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 34 deletions

View File

@ -32,6 +32,7 @@ import {
TilingPattern, TilingPattern,
} from "./pattern_helper.js"; } from "./pattern_helper.js";
import { applyMaskImageData } from "../shared/image_utils.js"; import { applyMaskImageData } from "../shared/image_utils.js";
import { isNodeJS } from "../shared/is_node.js";
import { PixelsPerInch } from "./display_utils.js"; import { PixelsPerInch } from "./display_utils.js";
// <canvas> contexts store most of the state we need natively. // <canvas> contexts store most of the state we need natively.
@ -450,24 +451,29 @@ function drawImageAtIntegerCoords(
} }
function compileType3Glyph(imgData) { function compileType3Glyph(imgData) {
const { width, height } = imgData;
if (
!COMPILE_TYPE3_GLYPHS ||
width > MAX_SIZE_TO_COMPILE ||
height > MAX_SIZE_TO_COMPILE
) {
return null;
}
const POINT_TO_PROCESS_LIMIT = 1000; const POINT_TO_PROCESS_LIMIT = 1000;
const POINT_TYPES = new Uint8Array([ const POINT_TYPES = new Uint8Array([
0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0, 0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0,
]); ]);
const width = imgData.width, const width1 = width + 1,
height = imgData.height, points = new Uint8Array(width1 * (height + 1));
width1 = width + 1; let i, j, j0;
let i, ii, j, j0;
const points = new Uint8Array(width1 * (height + 1));
// decodes bit-packed mask data // decodes bit-packed mask data
const lineSize = (width + 7) & ~7, const lineSize = (width + 7) & ~7,
data0 = imgData.data; data = new Uint8Array(lineSize * height);
const data = new Uint8Array(lineSize * height);
let pos = 0; let pos = 0;
for (i = 0, ii = data0.length; i < ii; i++) { for (const elem of imgData.data) {
const elem = data0[i];
let mask = 128; let mask = 128;
while (mask > 0) { while (mask > 0) {
data[pos++] = elem & mask ? 0 : 255; data[pos++] = elem & mask ? 0 : 255;
@ -556,7 +562,13 @@ function compileType3Glyph(imgData) {
// building outlines // building outlines
const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]); const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
const outlines = []; let path, outlines, coords;
if (!isNodeJS) {
path = new Path2D();
} else {
outlines = [];
}
for (i = 0; count && i <= height; i++) { for (i = 0; count && i <= height; i++) {
let p = i * width1; let p = i * width1;
const end = p + width; const end = p + width;
@ -566,7 +578,12 @@ function compileType3Glyph(imgData) {
if (p === end) { if (p === end) {
continue; continue;
} }
const coords = [p % width1, i];
if (path) {
path.moveTo(p % width1, i);
} else {
coords = [p % width1, i];
}
const p0 = p; const p0 = p;
let type = points[p]; let type = points[p];
@ -590,13 +607,20 @@ function compileType3Glyph(imgData) {
points[p] &= (type >> 2) | (type << 2); points[p] &= (type >> 2) | (type << 2);
} }
if (path) {
path.lineTo(p % width1, (p / width1) | 0);
} else {
coords.push(p % width1, (p / width1) | 0); coords.push(p % width1, (p / width1) | 0);
}
if (!points[p]) { if (!points[p]) {
--count; --count;
} }
} while (p0 !== p); } while (p0 !== p);
if (!path) {
outlines.push(coords); outlines.push(coords);
}
--i; --i;
} }
@ -605,15 +629,18 @@ function compileType3Glyph(imgData) {
// the path shall be painted in [0..1]x[0..1] space // the path shall be painted in [0..1]x[0..1] space
c.scale(1 / width, -1 / height); c.scale(1 / width, -1 / height);
c.translate(0, -height); c.translate(0, -height);
if (path) {
c.fill(path);
} else {
c.beginPath(); c.beginPath();
for (let k = 0, kk = outlines.length; k < kk; k++) { for (const o of outlines) {
const o = outlines[k];
c.moveTo(o[0], o[1]); c.moveTo(o[0], o[1]);
for (let l = 2, ll = o.length; l < ll; l += 2) { for (let l = 2, ll = o.length; l < ll; l += 2) {
c.lineTo(o[l], o[l + 1]); c.lineTo(o[l], o[l + 1]);
} }
} }
c.fill(); c.fill();
}
c.beginPath(); c.beginPath();
c.restore(); c.restore();
}; };
@ -2965,29 +2992,23 @@ class CanvasGraphics {
if (!this.contentVisible) { if (!this.contentVisible) {
return; return;
} }
const count = img.count; const count = img.count;
img = this.getObject(img.data, img); img = this.getObject(img.data, img);
img.count = count; img.count = count;
const ctx = this.ctx; const ctx = this.ctx;
const width = img.width,
height = img.height;
const glyph = this.processingType3; const glyph = this.processingType3;
if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) { if (glyph) {
if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) { if (glyph.compiled === undefined) {
glyph.compiled = compileType3Glyph({ data: img.data, width, height }); glyph.compiled = compileType3Glyph(img);
} else {
glyph.compiled = null;
}
} }
if (glyph?.compiled) { if (glyph.compiled) {
glyph.compiled(ctx); glyph.compiled(ctx);
return; return;
} }
}
const mask = this._createMaskCanvas(img); const mask = this._createMaskCanvas(img);
const maskCanvas = mask.canvas; const maskCanvas = mask.canvas;

View File

@ -21,6 +21,7 @@ import {
Util, Util,
warn, warn,
} from "../shared/util.js"; } from "../shared/util.js";
import { isNodeJS } from "../shared/is_node.js";
const PathType = { const PathType = {
FILL: "Fill", FILL: "Fill",
@ -29,7 +30,7 @@ const PathType = {
}; };
function applyBoundingBox(ctx, bbox) { function applyBoundingBox(ctx, bbox) {
if (!bbox || typeof Path2D === "undefined") { if (!bbox || isNodeJS) {
return; return;
} }
const width = bbox[2] - bbox[0]; const width = bbox[2] - bbox[0];

View File

@ -19,6 +19,7 @@
// https://www.electronjs.org/docs/api/process#processversionselectron-readonly // https://www.electronjs.org/docs/api/process#processversionselectron-readonly
// https://www.electronjs.org/docs/api/process#processtype-readonly // https://www.electronjs.org/docs/api/process#processtype-readonly
const isNodeJS = const isNodeJS =
(typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) &&
typeof process === "object" && typeof process === "object" &&
process + "" === "[object process]" && process + "" === "[object process]" &&
!process.versions.nw && !process.versions.nw &&