Merge pull request #14858 from Snuffleupagus/Type3-Path2D
Use `Path2D`, if available, when rendering Type3-fonts (bug 810214)
This commit is contained in:
commit
5ec8c3c191
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
coords.push(p % width1, (p / width1) | 0);
|
if (path) {
|
||||||
|
path.lineTo(p % width1, (p / width1) | 0);
|
||||||
|
} else {
|
||||||
|
coords.push(p % width1, (p / width1) | 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!points[p]) {
|
if (!points[p]) {
|
||||||
--count;
|
--count;
|
||||||
}
|
}
|
||||||
} while (p0 !== p);
|
} while (p0 !== p);
|
||||||
outlines.push(coords);
|
|
||||||
|
if (!path) {
|
||||||
|
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);
|
||||||
c.beginPath();
|
if (path) {
|
||||||
for (let k = 0, kk = outlines.length; k < kk; k++) {
|
c.fill(path);
|
||||||
const o = outlines[k];
|
} else {
|
||||||
c.moveTo(o[0], o[1]);
|
c.beginPath();
|
||||||
for (let l = 2, ll = o.length; l < ll; l += 2) {
|
for (const o of outlines) {
|
||||||
c.lineTo(o[l], o[l + 1]);
|
c.moveTo(o[0], o[1]);
|
||||||
|
for (let l = 2, ll = o.length; l < ll; l += 2) {
|
||||||
|
c.lineTo(o[l], o[l + 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
c.fill();
|
||||||
}
|
}
|
||||||
c.fill();
|
|
||||||
c.beginPath();
|
c.beginPath();
|
||||||
c.restore();
|
c.restore();
|
||||||
};
|
};
|
||||||
@ -2965,28 +2992,22 @@ 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;
|
||||||
|
@ -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];
|
||||||
|
@ -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 &&
|
||||||
|
Loading…
Reference in New Issue
Block a user