Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 37 additions & 100 deletions src/core/bounding_boxes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => [
Expand Down
Loading