diff --git a/src/core/annotation.js b/src/core/annotation.js index 5dfbb3400..a506ccf1c 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -4325,10 +4325,13 @@ class PolylineAnnotation extends MarkupAnnotation { // we get similar rendering/highlighting behaviour as in Adobe Reader. const bbox = [Infinity, Infinity, -Infinity, -Infinity]; for (let i = 0, ii = vertices.length; i < ii; i += 2) { - bbox[0] = Math.min(bbox[0], vertices[i] - borderAdjust); - bbox[1] = Math.min(bbox[1], vertices[i + 1] - borderAdjust); - bbox[2] = Math.max(bbox[2], vertices[i] + borderAdjust); - bbox[3] = Math.max(bbox[3], vertices[i + 1] + borderAdjust); + Util.rectBoundingBox( + vertices[i] - borderAdjust, + vertices[i + 1] - borderAdjust, + vertices[i] + borderAdjust, + vertices[i + 1] + borderAdjust, + bbox + ); } if (!Util.intersect(this.rectangle, bbox)) { this.rectangle = bbox; @@ -4422,10 +4425,13 @@ class InkAnnotation extends MarkupAnnotation { const bbox = [Infinity, Infinity, -Infinity, -Infinity]; for (const inkList of this.data.inkLists) { for (let i = 0, ii = inkList.length; i < ii; i += 2) { - bbox[0] = Math.min(bbox[0], inkList[i] - borderAdjust); - bbox[1] = Math.min(bbox[1], inkList[i + 1] - borderAdjust); - bbox[2] = Math.max(bbox[2], inkList[i] + borderAdjust); - bbox[3] = Math.max(bbox[3], inkList[i + 1] + borderAdjust); + Util.rectBoundingBox( + inkList[i] - borderAdjust, + inkList[i + 1] - borderAdjust, + inkList[i] + borderAdjust, + inkList[i + 1] + borderAdjust, + bbox + ); } } if (!Util.intersect(this.rectangle, bbox)) { diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 4eea49380..9f7ad6347 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -1421,30 +1421,21 @@ class PartialEvaluator { DrawOPS.closePath ); } - minMax[0] = Math.min(minMax[0], x, xw); - minMax[1] = Math.min(minMax[1], y, yh); - minMax[2] = Math.max(minMax[2], x, xw); - minMax[3] = Math.max(minMax[3], y, yh); + Util.rectBoundingBox(x, y, xw, yh, minMax); break; } case OPS.moveTo: { const x = (state.currentPointX = args[0]); const y = (state.currentPointY = args[1]); pathBuffer.push(DrawOPS.moveTo, x, y); - 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); + Util.pointBoundingBox(x, y, minMax); break; } case OPS.lineTo: { const x = (state.currentPointX = args[0]); const y = (state.currentPointY = args[1]); pathBuffer.push(DrawOPS.lineTo, x, y); - 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); + Util.pointBoundingBox(x, y, minMax); break; } case OPS.curveTo: { @@ -4812,7 +4803,8 @@ class TranslatedFont { // Override the fontBBox when it's undefined/empty, or when it's at least // (approximately) one order of magnitude smaller than the charBBox // (fixes issue14999_reduced.pdf). - this.#computeCharBBox(charBBox); + this._bbox ??= [Infinity, Infinity, -Infinity, -Infinity]; + Util.rectBoundingBox(...charBBox, this._bbox); } let i = 0, @@ -4881,21 +4873,13 @@ class TranslatedFont { case OPS.constructPath: const minMax = operatorList.argsArray[i][2]; // Override the fontBBox when it's undefined/empty (fixes 19624.pdf). - this.#computeCharBBox(minMax); + this._bbox ??= [Infinity, Infinity, -Infinity, -Infinity]; + Util.rectBoundingBox(...minMax, this._bbox); break; } i++; } } - - #computeCharBBox(bbox) { - this._bbox ||= [Infinity, Infinity, -Infinity, -Infinity]; - - this._bbox[0] = Math.min(this._bbox[0], bbox[0]); - this._bbox[1] = Math.min(this._bbox[1], bbox[1]); - this._bbox[2] = Math.max(this._bbox[2], bbox[2]); - this._bbox[3] = Math.max(this._bbox[3], bbox[3]); - } } class StateManager { diff --git a/src/display/editor/drawers/freedraw.js b/src/display/editor/drawers/freedraw.js index 30f73d90c..c3bd3dd5f 100644 --- a/src/display/editor/drawers/freedraw.js +++ b/src/display/editor/drawers/freedraw.js @@ -559,36 +559,30 @@ class FreeDrawOutline extends Outline { const outline = this.#outline; let lastX = outline[4]; let lastY = outline[5]; - let minX = lastX; - let minY = lastY; - let maxX = lastX; - let maxY = lastY; + const minMax = [lastX, lastY, lastX, lastY]; let lastPointX = lastX; let lastPointY = lastY; const ltrCallback = isLTR ? Math.max : Math.min; for (let i = 6, ii = outline.length; i < ii; i += 6) { + const x = outline[i + 4], + y = outline[i + 5]; + if (isNaN(outline[i])) { - minX = Math.min(minX, outline[i + 4]); - minY = Math.min(minY, outline[i + 5]); - maxX = Math.max(maxX, outline[i + 4]); - maxY = Math.max(maxY, outline[i + 5]); - if (lastPointY < outline[i + 5]) { - lastPointX = outline[i + 4]; - lastPointY = outline[i + 5]; - } else if (lastPointY === outline[i + 5]) { - lastPointX = ltrCallback(lastPointX, outline[i + 4]); + Util.pointBoundingBox(x, y, minMax); + + if (lastPointY < y) { + lastPointX = x; + lastPointY = y; + } else if (lastPointY === y) { + lastPointX = ltrCallback(lastPointX, x); } } else { - const bbox = Util.bezierBoundingBox( - lastX, - lastY, - ...outline.slice(i, i + 6) - ); - minX = Math.min(minX, bbox[0]); - minY = Math.min(minY, bbox[1]); - maxX = Math.max(maxX, bbox[2]); - maxY = Math.max(maxY, bbox[3]); + const bbox = [Infinity, Infinity, -Infinity, -Infinity]; + Util.bezierBoundingBox(lastX, lastY, ...outline.slice(i, i + 6), bbox); + + Util.rectBoundingBox(...bbox, minMax); + if (lastPointY < bbox[3]) { lastPointX = bbox[2]; lastPointY = bbox[3]; @@ -596,15 +590,15 @@ class FreeDrawOutline extends Outline { lastPointX = ltrCallback(lastPointX, bbox[2]); } } - lastX = outline[i + 4]; - lastY = outline[i + 5]; + lastX = x; + lastY = y; } const bbox = this.#bbox; - bbox[0] = minX - this.#innerMargin; - bbox[1] = minY - this.#innerMargin; - bbox[2] = maxX - minX + 2 * this.#innerMargin; - bbox[3] = maxY - minY + 2 * this.#innerMargin; + bbox[0] = minMax[0] - this.#innerMargin; + bbox[1] = minMax[1] - this.#innerMargin; + bbox[2] = minMax[2] - minMax[0] + 2 * this.#innerMargin; + bbox[3] = minMax[3] - minMax[1] + 2 * this.#innerMargin; this.lastPoint = [lastPointX, lastPointY]; } diff --git a/src/display/editor/drawers/highlight.js b/src/display/editor/drawers/highlight.js index a6389284a..ff0cf469a 100644 --- a/src/display/editor/drawers/highlight.js +++ b/src/display/editor/drawers/highlight.js @@ -15,6 +15,7 @@ import { FreeDrawOutline, FreeDrawOutliner } from "./freedraw.js"; import { Outline } from "./outline.js"; +import { Util } from "../../../shared/util.js"; class HighlightOutliner { #box; @@ -38,10 +39,7 @@ class HighlightOutliner { * the last point of the boxes. */ constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) { - let minX = Infinity; - let maxX = -Infinity; - let minY = Infinity; - let maxY = -Infinity; + const minMax = [Infinity, Infinity, -Infinity, -Infinity]; // We round the coordinates to slightly reduce the number of edges in the // final outlines. @@ -58,16 +56,13 @@ class HighlightOutliner { const right = [x2, y1, y2, false]; this.#verticalEdges.push(left, right); - minX = Math.min(minX, x1); - maxX = Math.max(maxX, x2); - minY = Math.min(minY, y1); - maxY = Math.max(maxY, y2); + Util.rectBoundingBox(x1, y1, x2, y2, minMax); } - const bboxWidth = maxX - minX + 2 * innerMargin; - const bboxHeight = maxY - minY + 2 * innerMargin; - const shiftedMinX = minX - innerMargin; - const shiftedMinY = minY - innerMargin; + const bboxWidth = minMax[2] - minMax[0] + 2 * innerMargin; + const bboxHeight = minMax[3] - minMax[1] + 2 * innerMargin; + const shiftedMinX = minMax[0] - innerMargin; + const shiftedMinY = minMax[1] - innerMargin; const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2); const lastPoint = [lastEdge[0], lastEdge[2]]; diff --git a/src/display/editor/drawers/inkdraw.js b/src/display/editor/drawers/inkdraw.js index 0be1c7bde..fa4df96e3 100644 --- a/src/display/editor/drawers/inkdraw.js +++ b/src/display/editor/drawers/inkdraw.js @@ -597,11 +597,7 @@ class InkDrawOutline extends Outline { if (line.length <= 12) { // We've only one or two points => no bezier curve. for (let i = 4, ii = line.length; i < ii; i += 6) { - const [x, y] = line.subarray(i, i + 2); - bbox[0] = Math.min(bbox[0], x); - bbox[1] = Math.min(bbox[1], y); - bbox[2] = Math.max(bbox[2], x); - bbox[3] = Math.max(bbox[3], y); + Util.pointBoundingBox(line[i], line[i + 1], bbox); } continue; } diff --git a/src/shared/util.js b/src/shared/util.js index b36a7383a..cfbd9995d 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -798,6 +798,20 @@ class Util { return [xLow, yLow, xHigh, yHigh]; } + static pointBoundingBox(x, y, minMax) { + 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 rectBoundingBox(x0, y0, x1, y1, minMax) { + minMax[0] = Math.min(minMax[0], x0, x1); + minMax[1] = Math.min(minMax[1], y0, y1); + minMax[2] = Math.max(minMax[2], x0, x1); + minMax[3] = Math.max(minMax[3], y0, y1); + } + static #getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, t, minMax) { if (t <= 0 || t >= 1) { return; @@ -866,19 +880,11 @@ class Util { // From https://github.com/adobe-webplatform/Snap.svg/blob/b365287722a72526000ac4bfcf0ce4cac2faa015/src/path.js#L852 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), - ]; - } + 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); + this.#getExtremum( x0, x1, @@ -907,7 +913,6 @@ class Util { 3 * (y1 - y0), minMax ); - return minMax; } } diff --git a/web/autolinker.js b/web/autolinker.js index fe28235c2..957e4de8e 100644 --- a/web/autolinker.js +++ b/web/autolinker.js @@ -59,11 +59,7 @@ function calculateLinkPosition(range, pdfPageView) { quadPoints[i + 2] = quadPoints[i + 6] = normalized[2]; quadPoints[i + 5] = quadPoints[i + 7] = normalized[1]; - rect[0] = Math.min(rect[0], normalized[0]); - rect[1] = Math.min(rect[1], normalized[1]); - rect[2] = Math.max(rect[2], normalized[2]); - rect[3] = Math.max(rect[3], normalized[3]); - + Util.rectBoundingBox(...normalized, rect); i += 8; } return { quadPoints, rect };