mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-22 16:18:08 +02:00
Reduce memory use and improve perfs when computing the bounding box of a bezier curve (bug 1875547)
It isn't really a fix for the mentioned bug but it slightly improve things. In reducing the memory use, the time spent in the GC is reduced either. The algorithm to compute the bounding box is the same as before but it has just been rewritten to be more efficient.
This commit is contained in:
parent
a5d4660a75
commit
7f2428a77e
5 changed files with 139 additions and 103 deletions
|
@ -1386,17 +1386,17 @@ class PartialEvaluator {
|
|||
const y = args[1] + args[3];
|
||||
minMax = [
|
||||
Math.min(args[0], x),
|
||||
Math.max(args[0], x),
|
||||
Math.min(args[1], y),
|
||||
Math.max(args[0], x),
|
||||
Math.max(args[1], y),
|
||||
];
|
||||
break;
|
||||
case OPS.moveTo:
|
||||
case OPS.lineTo:
|
||||
minMax = [args[0], args[0], args[1], args[1]];
|
||||
minMax = [args[0], args[1], args[0], args[1]];
|
||||
break;
|
||||
default:
|
||||
minMax = [Infinity, -Infinity, Infinity, -Infinity];
|
||||
minMax = [Infinity, Infinity, -Infinity, -Infinity];
|
||||
break;
|
||||
}
|
||||
operatorList.addOp(OPS.constructPath, [[fn], args, minMax]);
|
||||
|
@ -1420,15 +1420,15 @@ class PartialEvaluator {
|
|||
const x = args[0] + args[2];
|
||||
const y = args[1] + args[3];
|
||||
minMax[0] = Math.min(minMax[0], args[0], x);
|
||||
minMax[1] = Math.max(minMax[1], args[0], x);
|
||||
minMax[2] = Math.min(minMax[2], args[1], y);
|
||||
minMax[1] = Math.min(minMax[1], args[1], y);
|
||||
minMax[2] = Math.max(minMax[2], args[0], x);
|
||||
minMax[3] = Math.max(minMax[3], args[1], y);
|
||||
break;
|
||||
case OPS.moveTo:
|
||||
case OPS.lineTo:
|
||||
minMax[0] = Math.min(minMax[0], args[0]);
|
||||
minMax[1] = Math.max(minMax[1], args[0]);
|
||||
minMax[2] = Math.min(minMax[2], args[1]);
|
||||
minMax[1] = Math.min(minMax[1], args[1]);
|
||||
minMax[2] = Math.max(minMax[2], args[0]);
|
||||
minMax[3] = Math.max(minMax[3], args[1]);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -529,18 +529,14 @@ class CanvasExtraState {
|
|||
updateScalingPathMinMax(transform, minMax) {
|
||||
Util.scaleMinMax(transform, minMax);
|
||||
this.minX = Math.min(this.minX, minMax[0]);
|
||||
this.maxX = Math.max(this.maxX, minMax[1]);
|
||||
this.minY = Math.min(this.minY, minMax[2]);
|
||||
this.minY = Math.min(this.minY, minMax[1]);
|
||||
this.maxX = Math.max(this.maxX, minMax[2]);
|
||||
this.maxY = Math.max(this.maxY, minMax[3]);
|
||||
}
|
||||
|
||||
updateCurvePathMinMax(transform, x0, y0, x1, y1, x2, y2, x3, y3, minMax) {
|
||||
const box = Util.bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3);
|
||||
const box = Util.bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3, minMax);
|
||||
if (minMax) {
|
||||
minMax[0] = Math.min(minMax[0], box[0], box[2]);
|
||||
minMax[1] = Math.max(minMax[1], box[0], box[2]);
|
||||
minMax[2] = Math.min(minMax[2], box[1], box[3]);
|
||||
minMax[3] = Math.max(minMax[3], box[1], box[3]);
|
||||
return;
|
||||
}
|
||||
this.updateRectMinMax(transform, box);
|
||||
|
|
|
@ -651,52 +651,52 @@ class Util {
|
|||
|
||||
// Apply a scaling matrix to some min/max values.
|
||||
// If a scaling factor is negative then min and max must be
|
||||
// swaped.
|
||||
// swapped.
|
||||
static scaleMinMax(transform, minMax) {
|
||||
let temp;
|
||||
if (transform[0]) {
|
||||
if (transform[0] < 0) {
|
||||
temp = minMax[0];
|
||||
minMax[0] = minMax[1];
|
||||
minMax[1] = temp;
|
||||
minMax[0] = minMax[2];
|
||||
minMax[2] = temp;
|
||||
}
|
||||
minMax[0] *= transform[0];
|
||||
minMax[1] *= transform[0];
|
||||
minMax[2] *= transform[0];
|
||||
|
||||
if (transform[3] < 0) {
|
||||
temp = minMax[2];
|
||||
minMax[2] = minMax[3];
|
||||
temp = minMax[1];
|
||||
minMax[1] = minMax[3];
|
||||
minMax[3] = temp;
|
||||
}
|
||||
minMax[2] *= transform[3];
|
||||
minMax[1] *= transform[3];
|
||||
minMax[3] *= transform[3];
|
||||
} else {
|
||||
temp = minMax[0];
|
||||
minMax[0] = minMax[2];
|
||||
minMax[2] = temp;
|
||||
temp = minMax[1];
|
||||
minMax[1] = minMax[3];
|
||||
minMax[0] = minMax[1];
|
||||
minMax[1] = temp;
|
||||
temp = minMax[2];
|
||||
minMax[2] = minMax[3];
|
||||
minMax[3] = temp;
|
||||
|
||||
if (transform[1] < 0) {
|
||||
temp = minMax[2];
|
||||
minMax[2] = minMax[3];
|
||||
temp = minMax[1];
|
||||
minMax[1] = minMax[3];
|
||||
minMax[3] = temp;
|
||||
}
|
||||
minMax[2] *= transform[1];
|
||||
minMax[1] *= transform[1];
|
||||
minMax[3] *= transform[1];
|
||||
|
||||
if (transform[2] < 0) {
|
||||
temp = minMax[0];
|
||||
minMax[0] = minMax[1];
|
||||
minMax[1] = temp;
|
||||
minMax[0] = minMax[2];
|
||||
minMax[2] = temp;
|
||||
}
|
||||
minMax[0] *= transform[2];
|
||||
minMax[1] *= transform[2];
|
||||
minMax[2] *= transform[2];
|
||||
}
|
||||
minMax[0] += transform[4];
|
||||
minMax[1] += transform[4];
|
||||
minMax[2] += transform[5];
|
||||
minMax[1] += transform[5];
|
||||
minMax[2] += transform[4];
|
||||
minMax[3] += transform[5];
|
||||
}
|
||||
|
||||
|
@ -822,76 +822,116 @@ class Util {
|
|||
return [xLow, yLow, xHigh, yHigh];
|
||||
}
|
||||
|
||||
static #getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, t, minMax) {
|
||||
if (t <= 0 || t >= 1) {
|
||||
return;
|
||||
}
|
||||
const mt = 1 - t;
|
||||
const tt = t * t;
|
||||
const ttt = tt * t;
|
||||
const x = mt * (mt * (mt * x0 + 3 * t * x1) + 3 * tt * x2) + ttt * x3;
|
||||
const y = mt * (mt * (mt * y0 + 3 * t * y1) + 3 * tt * y2) + ttt * y3;
|
||||
minMax[0] = Math.min(minMax[0], x);
|
||||
minMax[1] = Math.min(minMax[1], y);
|
||||
minMax[2] = Math.max(minMax[2], x);
|
||||
minMax[3] = Math.max(minMax[3], y);
|
||||
}
|
||||
|
||||
static #getExtremum(x0, x1, x2, x3, y0, y1, y2, y3, a, b, c, minMax) {
|
||||
if (Math.abs(a) < 1e-12) {
|
||||
if (Math.abs(b) >= 1e-12) {
|
||||
this.#getExtremumOnCurve(
|
||||
x0,
|
||||
x1,
|
||||
x2,
|
||||
x3,
|
||||
y0,
|
||||
y1,
|
||||
y2,
|
||||
y3,
|
||||
-c / b,
|
||||
minMax
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const delta = b ** 2 - 4 * c * a;
|
||||
if (delta < 0) {
|
||||
return;
|
||||
}
|
||||
const sqrtDelta = Math.sqrt(delta);
|
||||
const a2 = 2 * a;
|
||||
this.#getExtremumOnCurve(
|
||||
x0,
|
||||
x1,
|
||||
x2,
|
||||
x3,
|
||||
y0,
|
||||
y1,
|
||||
y2,
|
||||
y3,
|
||||
(-b + sqrtDelta) / a2,
|
||||
minMax
|
||||
);
|
||||
this.#getExtremumOnCurve(
|
||||
x0,
|
||||
x1,
|
||||
x2,
|
||||
x3,
|
||||
y0,
|
||||
y1,
|
||||
y2,
|
||||
y3,
|
||||
(-b - sqrtDelta) / a2,
|
||||
minMax
|
||||
);
|
||||
}
|
||||
|
||||
// From https://github.com/adobe-webplatform/Snap.svg/blob/b365287722a72526000ac4bfcf0ce4cac2faa015/src/path.js#L852
|
||||
static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3) {
|
||||
const tvalues = [],
|
||||
bounds = [[], []];
|
||||
let a, b, c, t, t1, t2, b2ac, sqrtb2ac;
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
if (i === 0) {
|
||||
b = 6 * x0 - 12 * x1 + 6 * x2;
|
||||
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
|
||||
c = 3 * x1 - 3 * x0;
|
||||
} else {
|
||||
b = 6 * y0 - 12 * y1 + 6 * y2;
|
||||
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
|
||||
c = 3 * y1 - 3 * y0;
|
||||
}
|
||||
if (Math.abs(a) < 1e-12) {
|
||||
if (Math.abs(b) < 1e-12) {
|
||||
continue;
|
||||
}
|
||||
t = -c / b;
|
||||
if (0 < t && t < 1) {
|
||||
tvalues.push(t);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
b2ac = b * b - 4 * c * a;
|
||||
sqrtb2ac = Math.sqrt(b2ac);
|
||||
if (b2ac < 0) {
|
||||
continue;
|
||||
}
|
||||
t1 = (-b + sqrtb2ac) / (2 * a);
|
||||
if (0 < t1 && t1 < 1) {
|
||||
tvalues.push(t1);
|
||||
}
|
||||
t2 = (-b - sqrtb2ac) / (2 * a);
|
||||
if (0 < t2 && t2 < 1) {
|
||||
tvalues.push(t2);
|
||||
}
|
||||
static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3, minMax) {
|
||||
if (minMax) {
|
||||
minMax[0] = Math.min(minMax[0], x0, x3);
|
||||
minMax[1] = Math.min(minMax[1], y0, y3);
|
||||
minMax[2] = Math.max(minMax[2], x0, x3);
|
||||
minMax[3] = Math.max(minMax[3], y0, y3);
|
||||
} else {
|
||||
minMax = [
|
||||
Math.min(x0, x3),
|
||||
Math.min(y0, y3),
|
||||
Math.max(x0, x3),
|
||||
Math.max(y0, y3),
|
||||
];
|
||||
}
|
||||
|
||||
let j = tvalues.length,
|
||||
mt;
|
||||
const jlen = j;
|
||||
while (j--) {
|
||||
t = tvalues[j];
|
||||
mt = 1 - t;
|
||||
bounds[0][j] =
|
||||
mt * mt * mt * x0 +
|
||||
3 * mt * mt * t * x1 +
|
||||
3 * mt * t * t * x2 +
|
||||
t * t * t * x3;
|
||||
bounds[1][j] =
|
||||
mt * mt * mt * y0 +
|
||||
3 * mt * mt * t * y1 +
|
||||
3 * mt * t * t * y2 +
|
||||
t * t * t * y3;
|
||||
}
|
||||
|
||||
bounds[0][jlen] = x0;
|
||||
bounds[1][jlen] = y0;
|
||||
bounds[0][jlen + 1] = x3;
|
||||
bounds[1][jlen + 1] = y3;
|
||||
bounds[0].length = bounds[1].length = jlen + 2;
|
||||
|
||||
return [
|
||||
Math.min(...bounds[0]),
|
||||
Math.min(...bounds[1]),
|
||||
Math.max(...bounds[0]),
|
||||
Math.max(...bounds[1]),
|
||||
];
|
||||
this.#getExtremum(
|
||||
x0,
|
||||
x1,
|
||||
x2,
|
||||
x3,
|
||||
y0,
|
||||
y1,
|
||||
y2,
|
||||
y3,
|
||||
3 * (-x0 + 3 * (x1 - x2) + x3),
|
||||
6 * (x0 - 2 * x1 + x2),
|
||||
3 * (x1 - x0),
|
||||
minMax
|
||||
);
|
||||
this.#getExtremum(
|
||||
x0,
|
||||
x1,
|
||||
x2,
|
||||
x3,
|
||||
y0,
|
||||
y1,
|
||||
y2,
|
||||
y3,
|
||||
3 * (-y0 + 3 * (y1 - y2) + y3),
|
||||
6 * (y0 - 2 * y1 + y2),
|
||||
3 * (y1 - y0),
|
||||
minMax
|
||||
);
|
||||
return minMax;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue