Compare commits

...

6 Commits

Author SHA1 Message Date
Jonas Jenwald
a45f961a1c
Merge pull request #19751 from Snuffleupagus/applyTransform-in-place
Change `Util.applyTransform` to use the point-argument as an in/out parameter
2025-04-02 20:47:21 +02:00
calixteman
b7437376f1
Merge pull request #19732 from calixteman/rm_useless_beginpath
Remove few useless beginPaths
2025-04-02 13:46:05 +02:00
Jonas Jenwald
4262603b06 Re-name the Util.applyTransformToBezierInPlace method
Given that all `Util.apply...` methods are now using in/out parameters, we can slightly shorten the name of this one.
2025-04-01 23:03:50 +02:00
Jonas Jenwald
c852e877d8 Change Util.applyInverseTransform to use the point-argument as an in/out parameter
This will help reduce the total number of Array allocations, which cannot hurt.
2025-04-01 23:03:44 +02:00
Jonas Jenwald
fa643bb22f Change Util.applyTransform to use the point-argument as an in/out parameter
This will help reduce the total number of Array allocations, which cannot hurt, and also allows us to remove the `Util.applyTransformInPlace` method.
2025-04-01 23:03:36 +02:00
Calixte Denizet
a35443ff45 Remove few useless beginPaths.
The ctx current path is no more changed since we use some Path2D when we want to fill/stroke them.
It makes calling ctx.beginPath useless.
2025-04-01 16:02:38 +02:00
5 changed files with 52 additions and 42 deletions

View File

@ -1320,8 +1320,10 @@ class Annotation {
const transform = getTransformMatrix(rect, bbox, matrix); const transform = getTransformMatrix(rect, bbox, matrix);
transform[4] -= rect[0]; transform[4] -= rect[0];
transform[5] -= rect[1]; transform[5] -= rect[1];
coords = Util.applyTransform(coords, transform); const p = coords.slice();
return Util.applyTransform(coords, matrix); Util.applyTransform(p, transform);
Util.applyTransform(p, matrix);
return p;
} }
/** /**

View File

@ -524,11 +524,11 @@ addState(
switch (buffer[k++]) { switch (buffer[k++]) {
case DrawOPS.moveTo: case DrawOPS.moveTo:
case DrawOPS.lineTo: case DrawOPS.lineTo:
Util.applyTransformInPlace(buffer.subarray(k), transform); Util.applyTransform(buffer.subarray(k), transform);
k += 2; k += 2;
break; break;
case DrawOPS.curveTo: case DrawOPS.curveTo:
Util.applyTransformToBezierInPlace(buffer.subarray(k), transform); Util.applyTransformToBezier(buffer.subarray(k), transform);
k += 6; k += 6;
break; break;
} }

View File

@ -340,10 +340,14 @@ class CanvasExtraState {
} }
updateRectMinMax(transform, rect) { updateRectMinMax(transform, rect) {
const p1 = Util.applyTransform(rect, transform); const p1 = [rect[0], rect[1]];
const p2 = Util.applyTransform(rect.slice(2), transform); Util.applyTransform(p1, transform);
const p3 = Util.applyTransform([rect[0], rect[3]], transform); const p2 = [rect[2], rect[3]];
const p4 = Util.applyTransform([rect[2], rect[1]], transform); Util.applyTransform(p2, transform);
const p3 = [rect[0], rect[3]];
Util.applyTransform(p3, transform);
const p4 = [rect[2], rect[1]];
Util.applyTransform(p4, transform);
this.minX = Math.min(this.minX, p1[0], p2[0], p3[0], p4[0]); this.minX = Math.min(this.minX, p1[0], p2[0], p3[0], p4[0]);
this.minY = Math.min(this.minY, p1[1], p2[1], p3[1], p4[1]); this.minY = Math.min(this.minY, p1[1], p2[1], p3[1], p4[1]);
@ -1605,7 +1609,6 @@ class CanvasGraphics {
const paths = this.pendingTextPaths; const paths = this.pendingTextPaths;
const ctx = this.ctx; const ctx = this.ctx;
if (paths === undefined) { if (paths === undefined) {
ctx.beginPath();
return; return;
} }
@ -1622,7 +1625,6 @@ class CanvasGraphics {
} }
ctx.clip(newPath); ctx.clip(newPath);
ctx.beginPath();
delete this.pendingTextPaths; delete this.pendingTextPaths;
} }
@ -2111,8 +2113,9 @@ class CanvasGraphics {
this.restore(); this.restore();
} }
const transformed = Util.applyTransform([glyph.width, 0], fontMatrix); const p = [glyph.width, 0];
width = transformed[0] * fontSize + spacing; Util.applyTransform(p, fontMatrix);
width = p[0] * fontSize + spacing;
ctx.translate(width, 0); ctx.translate(width, 0);
current.x += width * textHScale; current.x += width * textHScale;
@ -2127,8 +2130,9 @@ class CanvasGraphics {
} }
setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) { setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) {
this.ctx.rect(llx, lly, urx - llx, ury - lly); const clip = new Path2D();
this.ctx.clip(); clip.rect(llx, lly, urx - llx, ury - lly);
this.ctx.clip(clip);
this.endPath(); this.endPath();
} }
@ -2271,11 +2275,11 @@ class CanvasGraphics {
this.baseTransform = getCurrentTransform(this.ctx); this.baseTransform = getCurrentTransform(this.ctx);
if (bbox) { if (bbox) {
const width = bbox[2] - bbox[0];
const height = bbox[3] - bbox[1];
this.ctx.rect(bbox[0], bbox[1], width, height);
this.current.updateRectMinMax(getCurrentTransform(this.ctx), bbox); this.current.updateRectMinMax(getCurrentTransform(this.ctx), bbox);
this.clip(); const [x0, y0, x1, y1] = bbox;
const clip = new Path2D();
clip.rect(x0, y0, x1 - x0, y1 - y0);
this.ctx.clip(clip);
this.endPath(); this.endPath();
} }
} }
@ -2503,9 +2507,9 @@ class CanvasGraphics {
// Consume a potential path before clipping. // Consume a potential path before clipping.
this.endPath(); this.endPath();
this.ctx.rect(rect[0], rect[1], width, height); const clip = new Path2D();
this.ctx.clip(); clip.rect(rect[0], rect[1], width, height);
this.ctx.beginPath(); this.ctx.clip(clip);
} }
} }
@ -2588,8 +2592,9 @@ class CanvasGraphics {
positions[i + 1], positions[i + 1],
]); ]);
const [x, y] = Util.applyTransform([0, 0], trans); // Here we want to apply the transform at the origin,
ctx.drawImage(mask.canvas, x, y); // hence no additional computation is necessary.
ctx.drawImage(mask.canvas, trans[4], trans[5]);
} }
ctx.restore(); ctx.restore();
this.compose(); this.compose();
@ -2902,7 +2907,6 @@ class CanvasGraphics {
this.pendingClip = null; this.pendingClip = null;
} }
this.current.startNewPathAndClipBox(this.current.clipBox); this.current.startNewPathAndClipBox(this.current.clipBox);
ctx.beginPath();
} }
getSinglePixelWidth() { getSinglePixelWidth() {

View File

@ -257,7 +257,9 @@ class PageViewport {
* @see {@link convertToViewportRectangle} * @see {@link convertToViewportRectangle}
*/ */
convertToViewportPoint(x, y) { convertToViewportPoint(x, y) {
return Util.applyTransform([x, y], this.transform); const p = [x, y];
Util.applyTransform(p, this.transform);
return p;
} }
/** /**
@ -268,8 +270,10 @@ class PageViewport {
* @see {@link convertToViewportPoint} * @see {@link convertToViewportPoint}
*/ */
convertToViewportRectangle(rect) { convertToViewportRectangle(rect) {
const topLeft = Util.applyTransform([rect[0], rect[1]], this.transform); const topLeft = [rect[0], rect[1]];
const bottomRight = Util.applyTransform([rect[2], rect[3]], this.transform); Util.applyTransform(topLeft, this.transform);
const bottomRight = [rect[2], rect[3]];
Util.applyTransform(bottomRight, this.transform);
return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]]; return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]];
} }
@ -283,7 +287,9 @@ class PageViewport {
* @see {@link convertToViewportPoint} * @see {@link convertToViewportPoint}
*/ */
convertToPdfPoint(x, y) { convertToPdfPoint(x, y) {
return Util.applyInverseTransform([x, y], this.transform); const p = [x, y];
Util.applyInverseTransform(p, this.transform);
return p;
} }
} }

View File

@ -742,19 +742,13 @@ class Util {
// For 2d affine transforms // For 2d affine transforms
static applyTransform(p, m) { static applyTransform(p, m) {
const xt = p[0] * m[0] + p[1] * m[2] + m[4];
const yt = p[0] * m[1] + p[1] * m[3] + m[5];
return [xt, yt];
}
static applyTransformInPlace(p, m) {
const [p0, p1] = p; const [p0, p1] = p;
p[0] = p0 * m[0] + p1 * m[2] + m[4]; p[0] = p0 * m[0] + p1 * m[2] + m[4];
p[1] = p0 * m[1] + p1 * m[3] + m[5]; p[1] = p0 * m[1] + p1 * m[3] + m[5];
} }
// For 2d affine transforms // For 2d affine transforms
static applyTransformToBezierInPlace(p, [m0, m1, m2, m3, m4, m5]) { static applyTransformToBezier(p, [m0, m1, m2, m3, m4, m5]) {
for (let i = 0; i < 6; i += 2) { for (let i = 0; i < 6; i += 2) {
const pI = p[i]; const pI = p[i];
const pI1 = p[i + 1]; const pI1 = p[i + 1];
@ -764,19 +758,23 @@ class Util {
} }
static applyInverseTransform(p, m) { static applyInverseTransform(p, m) {
const [p0, p1] = p;
const d = m[0] * m[3] - m[1] * m[2]; const d = m[0] * m[3] - m[1] * m[2];
const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; p[0] = (p0 * m[3] - p1 * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; p[1] = (-p0 * m[1] + p1 * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
return [xt, yt];
} }
// Applies the transform to the rectangle and finds the minimum axially // Applies the transform to the rectangle and finds the minimum axially
// aligned bounding box. // aligned bounding box.
static getAxialAlignedBoundingBox(r, m) { static getAxialAlignedBoundingBox(r, m) {
const p1 = this.applyTransform(r, m); const p1 = [r[0], r[1]];
const p2 = this.applyTransform(r.slice(2, 4), m); Util.applyTransform(p1, m);
const p3 = this.applyTransform([r[0], r[3]], m); const p2 = [r[2], r[3]];
const p4 = this.applyTransform([r[2], r[1]], m); Util.applyTransform(p2, m);
const p3 = [r[0], r[3]];
Util.applyTransform(p3, m);
const p4 = [r[2], r[1]];
Util.applyTransform(p4, m);
return [ return [
Math.min(p1[0], p2[0], p3[0], p4[0]), Math.min(p1[0], p2[0], p3[0], p4[0]),
Math.min(p1[1], p2[1], p3[1], p4[1]), Math.min(p1[1], p2[1], p3[1], p4[1]),