Correctly render the glyph outline when it has a stroke pattern
It fixes #19360. Each glyph in the test case has a fill and a stroke pattern, so the current transform used to scale the glyph outline must be the same. In setting the stroke color to green, I noticed that the last outline contains some non-closed subpaths, so when generating the glyph outline, every time we 'moveTo', we close the previous subpath.
This commit is contained in:
parent
23dc3ff49f
commit
1ccf6ed976
@ -170,6 +170,11 @@ function lookupCmap(ranges, unicode) {
|
|||||||
|
|
||||||
function compileGlyf(code, cmds, font) {
|
function compileGlyf(code, cmds, font) {
|
||||||
function moveTo(x, y) {
|
function moveTo(x, y) {
|
||||||
|
if (firstPoint) {
|
||||||
|
// Close the current subpath in adding a straight line to the first point.
|
||||||
|
cmds.add("L", firstPoint);
|
||||||
|
}
|
||||||
|
firstPoint = [x, y];
|
||||||
cmds.add("M", [x, y]);
|
cmds.add("M", [x, y]);
|
||||||
}
|
}
|
||||||
function lineTo(x, y) {
|
function lineTo(x, y) {
|
||||||
@ -182,6 +187,7 @@ function compileGlyf(code, cmds, font) {
|
|||||||
let i = 0;
|
let i = 0;
|
||||||
const numberOfContours = getInt16(code, i);
|
const numberOfContours = getInt16(code, i);
|
||||||
let flags;
|
let flags;
|
||||||
|
let firstPoint = null;
|
||||||
let x = 0,
|
let x = 0,
|
||||||
y = 0;
|
y = 0;
|
||||||
i += 10;
|
i += 10;
|
||||||
@ -350,6 +356,11 @@ function compileGlyf(code, cmds, font) {
|
|||||||
|
|
||||||
function compileCharString(charStringCode, cmds, font, glyphId) {
|
function compileCharString(charStringCode, cmds, font, glyphId) {
|
||||||
function moveTo(x, y) {
|
function moveTo(x, y) {
|
||||||
|
if (firstPoint) {
|
||||||
|
// Close the current subpath in adding a straight line to the first point.
|
||||||
|
cmds.add("L", firstPoint);
|
||||||
|
}
|
||||||
|
firstPoint = [x, y];
|
||||||
cmds.add("M", [x, y]);
|
cmds.add("M", [x, y]);
|
||||||
}
|
}
|
||||||
function lineTo(x, y) {
|
function lineTo(x, y) {
|
||||||
@ -363,6 +374,7 @@ function compileCharString(charStringCode, cmds, font, glyphId) {
|
|||||||
let x = 0,
|
let x = 0,
|
||||||
y = 0;
|
y = 0;
|
||||||
let stems = 0;
|
let stems = 0;
|
||||||
|
let firstPoint = null;
|
||||||
|
|
||||||
function parse(code) {
|
function parse(code) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|||||||
@ -2043,12 +2043,13 @@ class CanvasGraphics {
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(x, y);
|
ctx.translate(x, y);
|
||||||
ctx.scale(fontSize, -fontSize);
|
ctx.scale(fontSize, -fontSize);
|
||||||
|
let currentTransform;
|
||||||
if (
|
if (
|
||||||
fillStrokeMode === TextRenderingMode.FILL ||
|
fillStrokeMode === TextRenderingMode.FILL ||
|
||||||
fillStrokeMode === TextRenderingMode.FILL_STROKE
|
fillStrokeMode === TextRenderingMode.FILL_STROKE
|
||||||
) {
|
) {
|
||||||
if (patternFillTransform) {
|
if (patternFillTransform) {
|
||||||
const currentTransform = ctx.getTransform();
|
currentTransform = ctx.getTransform();
|
||||||
ctx.setTransform(...patternFillTransform);
|
ctx.setTransform(...patternFillTransform);
|
||||||
ctx.fill(
|
ctx.fill(
|
||||||
this.#getScaledPath(path, currentTransform, patternFillTransform)
|
this.#getScaledPath(path, currentTransform, patternFillTransform)
|
||||||
@ -2062,8 +2063,22 @@ class CanvasGraphics {
|
|||||||
fillStrokeMode === TextRenderingMode.FILL_STROKE
|
fillStrokeMode === TextRenderingMode.FILL_STROKE
|
||||||
) {
|
) {
|
||||||
if (patternStrokeTransform) {
|
if (patternStrokeTransform) {
|
||||||
const currentTransform = ctx.getTransform();
|
currentTransform ||= ctx.getTransform();
|
||||||
ctx.setTransform(...patternStrokeTransform);
|
ctx.setTransform(...patternStrokeTransform);
|
||||||
|
const { a, b, c, d } = currentTransform;
|
||||||
|
const invPatternTransform = Util.inverseTransform(
|
||||||
|
patternStrokeTransform
|
||||||
|
);
|
||||||
|
const transf = Util.transform(
|
||||||
|
[a, b, c, d, 0, 0],
|
||||||
|
invPatternTransform
|
||||||
|
);
|
||||||
|
const [sx, sy] = Util.singularValueDecompose2dScale(transf);
|
||||||
|
|
||||||
|
// Cancel the pattern scaling of the line width.
|
||||||
|
// If sx and sy are different, unfortunately we can't do anything and
|
||||||
|
// we'll have a rendering bug.
|
||||||
|
ctx.lineWidth *= Math.max(sx, sy) / fontSize;
|
||||||
ctx.stroke(
|
ctx.stroke(
|
||||||
this.#getScaledPath(path, currentTransform, patternStrokeTransform)
|
this.#getScaledPath(path, currentTransform, patternStrokeTransform)
|
||||||
);
|
);
|
||||||
|
|||||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -696,3 +696,4 @@
|
|||||||
!issue18911.pdf
|
!issue18911.pdf
|
||||||
!issue19207.pdf
|
!issue19207.pdf
|
||||||
!issue19239.pdf
|
!issue19239.pdf
|
||||||
|
!issue19360.pdf
|
||||||
|
|||||||
BIN
test/pdfs/issue19360.pdf
Executable file
BIN
test/pdfs/issue19360.pdf
Executable file
Binary file not shown.
@ -11286,5 +11286,12 @@
|
|||||||
"firstPage": 2,
|
"firstPage": 2,
|
||||||
"lastPage": 2,
|
"lastPage": 2,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "issue19360",
|
||||||
|
"file": "pdfs/issue19360.pdf",
|
||||||
|
"md5": "b2de376f7e96fa2b6afc00dac016c40a",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user