Optimize save-transform-constructPath-restore
The 4 operations can be replaced with just one in applying the transform to the points coordinates.
This commit is contained in:
parent
7c5695f5c6
commit
6146e5fee7
@ -13,7 +13,14 @@
|
|||||||
* limitations under the License.
|
* 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) {
|
function addState(parentState, pattern, checkFn, iterateFn, processFn) {
|
||||||
let state = parentState;
|
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 {
|
class NullOptimizer {
|
||||||
constructor(queue) {
|
constructor(queue) {
|
||||||
this.queue = queue;
|
this.queue = queue;
|
||||||
|
|||||||
@ -676,6 +676,57 @@ class Util {
|
|||||||
return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`;
|
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.
|
// Concatenates two transformation matrices together and returns the result.
|
||||||
static transform(m1, m2) {
|
static transform(m1, m2) {
|
||||||
return [
|
return [
|
||||||
@ -695,6 +746,22 @@ class Util {
|
|||||||
return [xt, yt];
|
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) {
|
static applyInverseTransform(p, m) {
|
||||||
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;
|
const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user