diff --git a/src/core/bounding_boxes.js b/src/core/bounding_boxes.js index 26248b070bc9b..7e080b403092c 100644 --- a/src/core/bounding_boxes.js +++ b/src/core/bounding_boxes.js @@ -52,133 +52,70 @@ class BoundingBoxesCalculator { } getTextBoundingBox(glyphs) { - let tx = 0; - let ty = 0; // Save previous x value to take it into account while calculating // width of marked content - const ctm = this.graphicsStateManager.state.ctm; + const textState = this.textStateManager.state; + const { + fontMatrix, textMatrix, textHScale, fontSize, + font, textRise, charSpacing, wordSpacing, + } = textState; + const scaledFontSize = textHScale * fontSize; - const descent = - (this.textStateManager.state.font.descent || 0) * - this.textStateManager.state.fontSize; - const ascent = - (this.textStateManager.state.font.ascent || 1) * - this.textStateManager.state.fontSize; - const rise = - this.textStateManager.state.textRise * - this.textStateManager.state.fontSize; + const descent = (font.descent || 0) * fontSize; + const ascent = (font.ascent || 1) * fontSize; + const rise = textRise * fontSize; let tx0, ty0, shift, height; - if (!this.textStateManager.state.font.vertical) { + if (!font.vertical) { // Left Bottom point of text bbox // Save before text matrix will be changed with going through glyphs - [tx0, ty0] = this.transformPoint( - 0, - descent + rise, - this.textStateManager.state.textMatrix - ); + [tx0, ty0] = this.transformPoint(0, descent + rise, textMatrix); // Calculate transformed height and shift to place // the whole glyph inside the bbox - shift = [ - tx0 - this.textStateManager.state.textMatrix[4], - ty0 - this.textStateManager.state.textMatrix[5], - ]; - height = this.transformPoint( - 0, - ascent - descent, - this.textStateManager.state.textMatrix - ); + shift = [tx0 - textMatrix[4], ty0 - textMatrix[5]]; + height = this.transformPoint(0, ascent - descent, textMatrix); } else { - [tx0, ty0] = this.transformPoint( - -this.textStateManager.state.fontSize / 2, - rise, - this.textStateManager.state.textMatrix - ); - shift = [ - tx0 - this.textStateManager.state.textMatrix[4], - ty0 - this.textStateManager.state.textMatrix[5], - ]; - height = this.transformPoint( - ascent - descent, - 0, - this.textStateManager.state.textMatrix - ); + [tx0, ty0] = this.transformPoint(-scaledFontSize / 2, rise, textMatrix); + shift = [tx0 - textMatrix[4], ty0 - textMatrix[5]]; + height = this.transformPoint(scaledFontSize, 0, textMatrix); } - height[0] -= this.textStateManager.state.textMatrix[4]; - height[1] -= this.textStateManager.state.textMatrix[5]; + height[0] -= textMatrix[4]; + height[1] -= textMatrix[5]; height = Math.hypot(height[0], height[1]); - height *= - this.textStateManager.state.textMatrix[0] * - this.textStateManager.state.textMatrix[3] < - 0 - ? -1 - : 1; + height *= textMatrix[0] * textMatrix[3] < 0 ? -1 : 1; let glyphsSize = []; + let tx = 0, ty = 0; for (let i = 0; i < glyphs.length; i++) { + textState.translateTextMatrix(tx, -ty); + tx = ty = 0; const glyph = glyphs[i]; if (typeof glyph === "number") { - if (this.textStateManager.state.font.vertical) { - ty = - (-glyph / 1000) * - this.textStateManager.state.fontSize * - this.textStateManager.state.textHScale; + if (!font.vertical) { + tx = (-glyph / 1000) * scaledFontSize; } else { - tx = - (-glyph / 1000) * - this.textStateManager.state.fontSize * - this.textStateManager.state.textHScale; + ty = (glyph / 1000) * fontSize; } } else { - let glyphWidth = null; - glyphWidth = - this.textStateManager.state.font.vertical && glyph.vmetric - ? glyph.vmetric[0] - : glyph.width; - if (!this.textStateManager.state.font.vertical) { - const w0 = - glyphWidth * - (this.textStateManager.state.fontMatrix - ? this.textStateManager.state.fontMatrix[0] - : 1 / 1000); - tx = - (w0 * this.textStateManager.state.fontSize + - this.textStateManager.state.charSpacing + - (glyph.isSpace ? this.textStateManager.state.wordSpacing : 0)) * - this.textStateManager.state.textHScale; + const vmetric = glyph.vmetric ?? font.defaultVMetrics; + const glyphWidth = font.vertical && vmetric ? -vmetric[0] : glyph.width; + const [x, y] = [textMatrix[4] + shift[0], textMatrix[5] + shift[1]]; + if (!font.vertical) { + const w0 = glyphWidth * (fontMatrix ? fontMatrix[0] : 1 / 1000); + textState.translateTextMatrix(w0 * scaledFontSize, 0); + tx = (charSpacing + (glyph.isSpace ? wordSpacing : 0)) * textHScale; } else { - const w1 = - glyphWidth * - (this.textStateManager.state.fontMatrix - ? this.textStateManager.state.fontMatrix[0] - : 1 / 1000); - ty = - w1 * this.textStateManager.state.fontSize - - this.textStateManager.state.charSpacing - - (glyph.isSpace ? this.textStateManager.state.wordSpacing : 0); + const w1 = glyphWidth * (fontMatrix ? fontMatrix[0] : 1 / 1000); + textState.translateTextMatrix(0, -w1 * fontSize); + ty = -charSpacing - (glyph.isSpace ? wordSpacing : 0); } - } - const [x, y] = [ - this.textStateManager.state.textMatrix[4] + shift[0], - this.textStateManager.state.textMatrix[5] + shift[1], - ]; - this.textStateManager.state.translateTextMatrix(tx, -ty); - if (typeof glyph !== "number") { - glyphsSize.push([ - x, - y, - this.textStateManager.state.textMatrix[4] + shift[0], - this.textStateManager.state.textMatrix[5] + shift[1], - ]); + glyphsSize.push([x, y, textMatrix[4] + shift[0], textMatrix[5] + shift[1]]); } } // Right Bottom point is in text matrix after going through glyphs - const [tx1, ty1] = [ - this.textStateManager.state.textMatrix[4] + shift[0], - this.textStateManager.state.textMatrix[5] + shift[1], - ]; + const [tx1, ty1] = [textMatrix[4] + shift[0], textMatrix[5] + shift[1]]; // Top point can be calculated from base and height const [tx2, ty2, tx3, ty3] = this.getTopPoints(tx0, ty0, tx1, ty1, height); glyphsSize = glyphsSize.map(glyphSize => [