1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 22:58:07 +02:00

Merge pull request #19712 from calixteman/optimize_save_construct

Optimize save-transform-constructPath-restore
This commit is contained in:
calixteman 2025-04-01 18:20:59 +02:00 committed by GitHub
commit 25693dc0ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 139 additions and 1 deletions

View file

@ -13,7 +13,14 @@
* limitations under the License.
*/
import { ImageKind, OPS, RenderingIntentFlag, warn } from "../shared/util.js";
import {
DrawOPS,
ImageKind,
OPS,
RenderingIntentFlag,
Util,
warn,
} from "../shared/util.js";
function addState(parentState, pattern, checkFn, iterateFn, processFn) {
let state = parentState;
@ -470,6 +477,70 @@ addState(
}
);
// This replaces (save, transform, constructPath, restore)
// sequences with |constructPath| operation.
addState(
InitialState,
[OPS.save, OPS.transform, OPS.constructPath, OPS.restore],
context => {
const argsArray = context.argsArray;
const iFirstConstructPath = context.iCurr - 1;
const op = argsArray[iFirstConstructPath][0];
// When stroking the transform has to be applied to the line width too.
// So we can only optimize if the transform is an identity.
if (
op !== OPS.stroke &&
op !== OPS.closeStroke &&
op !== OPS.fillStroke &&
op !== OPS.eoFillStroke &&
op !== OPS.closeFillStroke &&
op !== OPS.closeEOFillStroke
) {
return true;
}
const iFirstTransform = context.iCurr - 2;
const transform = argsArray[iFirstTransform];
return (
transform[0] === 1 &&
transform[1] === 0 &&
transform[2] === 0 &&
transform[3] === 1
);
},
() => false,
(context, i) => {
const { fnArray, argsArray } = context;
const curr = context.iCurr;
const iFirstSave = curr - 3;
const iFirstTransform = curr - 2;
const iFirstConstructPath = curr - 1;
const args = argsArray[iFirstConstructPath];
const transform = argsArray[iFirstTransform];
const [, [buffer], minMax] = args;
Util.scaleMinMax(transform, minMax);
for (let k = 0, kk = buffer.length; k < kk; ) {
switch (buffer[k++]) {
case DrawOPS.moveTo:
case DrawOPS.lineTo:
Util.applyTransformInPlace(buffer.subarray(k), transform);
k += 2;
break;
case DrawOPS.curveTo:
Util.applyTransformToBezierInPlace(buffer.subarray(k), transform);
k += 6;
break;
}
}
// Replace queue items.
fnArray.splice(iFirstSave, 4, OPS.constructPath);
argsArray.splice(iFirstSave, 4, args);
return iFirstSave + 1;
}
);
class NullOptimizer {
constructor(queue) {
this.queue = queue;

View file

@ -676,6 +676,57 @@ class Util {
return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`;
}
// Apply a scaling matrix to some min/max values.
// If a scaling factor is negative then min and max must be
// swapped.
static scaleMinMax(transform, minMax) {
let temp;
if (transform[0]) {
if (transform[0] < 0) {
temp = minMax[0];
minMax[0] = minMax[2];
minMax[2] = temp;
}
minMax[0] *= transform[0];
minMax[2] *= transform[0];
if (transform[3] < 0) {
temp = minMax[1];
minMax[1] = minMax[3];
minMax[3] = temp;
}
minMax[1] *= transform[3];
minMax[3] *= transform[3];
} else {
temp = minMax[0];
minMax[0] = minMax[1];
minMax[1] = temp;
temp = minMax[2];
minMax[2] = minMax[3];
minMax[3] = temp;
if (transform[1] < 0) {
temp = minMax[1];
minMax[1] = minMax[3];
minMax[3] = temp;
}
minMax[1] *= transform[1];
minMax[3] *= transform[1];
if (transform[2] < 0) {
temp = minMax[0];
minMax[0] = minMax[2];
minMax[2] = temp;
}
minMax[0] *= transform[2];
minMax[2] *= transform[2];
}
minMax[0] += transform[4];
minMax[1] += transform[5];
minMax[2] += transform[4];
minMax[3] += transform[5];
}
// Concatenates two transformation matrices together and returns the result.
static transform(m1, m2) {
return [
@ -695,6 +746,22 @@ class Util {
return [xt, yt];
}
static applyTransformInPlace(p, m) {
const [p0, p1] = p;
p[0] = p0 * m[0] + p1 * m[2] + m[4];
p[1] = p0 * m[1] + p1 * m[3] + m[5];
}
// For 2d affine transforms
static applyTransformToBezierInPlace(p, [m0, m1, m2, m3, m4, m5]) {
for (let i = 0; i < 6; i += 2) {
const pI = p[i];
const pI1 = p[i + 1];
p[i] = pI * m0 + pI1 * m2 + m4;
p[i + 1] = pI * m1 + pI1 * m3 + m5;
}
}
static applyInverseTransform(p, m) {
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;