Skip to content

Commit

Permalink
Enforce line width to be at least 1px after applied transform
Browse files Browse the repository at this point in the history
 * use currentTransform instead of inverse to compute getSinglePixelWidth
 * get scale values from SVD to compute getSinglePixelWidth
 * slighty improve singularValueDecompose2dScale in case of diag/anti-diag matrices (should be pretty common)
  • Loading branch information
calixteman committed Jan 4, 2021
1 parent ed3758f commit 212e652
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 19 deletions.
15 changes: 5 additions & 10 deletions src/display/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ const MIN_FONT_SIZE = 16;
const MAX_FONT_SIZE = 100;
const MAX_GROUP_SIZE = 4096;

// Heuristic value used when enforcing minimum line widths.
const MIN_WIDTH_FACTOR = 0.65;
// Enforce line to have a minimal width of 1px when transform is applied
const MIN_WIDTH_FACTOR = 1.000001;

const COMPILE_TYPE3_GLYPHS = true;
const MAX_SIZE_TO_COMPILE = 1000;
Expand Down Expand Up @@ -2624,14 +2624,9 @@ const CanvasGraphics = (function CanvasGraphicsClosure() {
},
getSinglePixelWidth(scale) {
if (this._cachedGetSinglePixelWidth === null) {
const inverse = this.ctx.mozCurrentTransformInverse;
// max of the current horizontal and vertical scale
this._cachedGetSinglePixelWidth = Math.sqrt(
Math.max(
inverse[0] * inverse[0] + inverse[1] * inverse[1],
inverse[2] * inverse[2] + inverse[3] * inverse[3]
)
);
const transform = this.ctx.mozCurrentTransform;
this._cachedGetSinglePixelWidth =
1 / Math.min(...Util.singularValueDecompose2dScale(transform));
}
return this._cachedGetSinglePixelWidth;
},
Expand Down
26 changes: 17 additions & 9 deletions src/shared/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -710,19 +710,27 @@ class Util {
// The SVD can be represented with formula A = USV. We are interested in the
// matrix S here because it represents the scale values.
static singularValueDecompose2dScale(m) {
const transpose = [m[0], m[2], m[1], m[3]];
if (Math.abs(m[1]) <= Number.EPSILON && Math.abs(m[2]) <= Number.EPSILON) {
// Diagonal matrix
return [Math.abs(m[0]) || 1, Math.abs(m[3]) || 1];
}

if (Math.abs(m[0]) <= Number.EPSILON && Math.abs(m[3]) <= Number.EPSILON) {
// Anti-diagonal matrix: scale composed with rotation of +/- 90°
return [Math.abs(m[2]) || 1, Math.abs(m[1]) || 1];
}

// Multiply matrix m with its transpose.
const a = m[0] * transpose[0] + m[1] * transpose[2];
const b = m[0] * transpose[1] + m[1] * transpose[3];
const c = m[2] * transpose[0] + m[3] * transpose[2];
const d = m[2] * transpose[1] + m[3] * transpose[3];
const a = m[0] * m[0] + m[1] * m[1];
const b = m[0] * m[2] + m[1] * m[3];
const c = m[2] * m[0] + m[3] * m[1];
const d = m[2] * m[2] + m[3] * m[3];

// Solve the second degree polynomial to get roots.
const first = (a + d) / 2;
const second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
const sx = first + second || 1;
const sy = first - second || 1;
const sum_a_d = a + d;
const second = Math.sqrt(sum_a_d * sum_a_d - 4 * (a * d - c * b));
const sx = (sum_a_d + second) / 2 || 1;
const sy = (sum_a_d - second) / 2 || 1;

// Scale values are the square roots of the eigenvalues.
return [Math.sqrt(sx), Math.sqrt(sy)];
Expand Down

0 comments on commit 212e652

Please sign in to comment.