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:
commit
25693dc0ee
2 changed files with 139 additions and 1 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue