Index: src/core/SkScalerContext.cpp |
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp |
index b7409ffe9ecbf1e7aace9bcf86ff16d011d7a4ec..4d22fbec62c154671d62ca69a64a1920da3f5702 100644 |
--- a/src/core/SkScalerContext.cpp |
+++ b/src/core/SkScalerContext.cpp |
@@ -15,6 +15,7 @@ |
#include "SkGlyph.h" |
#include "SkMaskFilter.h" |
#include "SkMaskGamma.h" |
+#include "SkMatrix22.h" |
#include "SkReadBuffer.h" |
#include "SkWriteBuffer.h" |
#include "SkPathEffect.h" |
@@ -722,6 +723,91 @@ void SkScalerContextRec::getSingleMatrixWithoutTextSize(SkMatrix* m) const { |
m->postConcat(deviceMatrix); |
} |
+void SkScalerContextRec::computeMatrices(PreMatrixScale preMatrixScale, SkVector* s, SkMatrix* sA, |
+ SkMatrix* GsA, SkMatrix* G_inv, SkMatrix* A_out) |
+{ |
+ // A is the 'total' matrix. |
+ SkMatrix A; |
+ this->getSingleMatrix(&A); |
+ |
+ // The caller may find the 'total' matrix useful when dealing directly with EM sizes. |
+ if (A_out) { |
+ *A_out = A; |
+ } |
+ |
+ // GA is the matrix A with rotation removed. |
+ SkMatrix GA; |
+ bool skewedOrFlipped = A.getSkewX() || A.getSkewY() || A.getScaleX() < 0 || A.getScaleY() < 0; |
+ if (skewedOrFlipped) { |
+ // h is where A maps the horizontal baseline. |
+ SkPoint h = SkPoint::Make(SK_Scalar1, 0); |
+ A.mapPoints(&h, 1); |
+ |
+ // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0). |
+ SkMatrix G; |
+ SkComputeGivensRotation(h, &G); |
+ |
+ GA = G; |
+ GA.preConcat(A); |
+ |
+ // The 'remainingRotation' is G inverse, which is fairly simple since G is 2x2 rotational. |
+ if (G_inv) { |
+ G_inv->setAll( |
+ G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX), |
+ -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY), |
+ G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2)); |
+ } |
+ } else { |
+ GA = A; |
+ if (G_inv) { |
+ G_inv->reset(); |
+ } |
+ } |
+ |
+ // At this point, given GA, create s. |
+ switch (preMatrixScale) { |
+ case kFull_PreMatrixScale: |
+ s->fX = SkScalarAbs(GA.get(SkMatrix::kMScaleX)); |
+ s->fY = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); |
+ break; |
+ case kVertical_PreMatrixScale: { |
+ SkScalar yScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); |
+ s->fX = yScale; |
+ s->fY = yScale; |
+ break; |
+ } |
+ case kVerticalInteger_PreMatrixScale: { |
+ SkScalar realYScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); |
+ SkScalar intYScale = SkScalarRoundToScalar(realYScale); |
+ if (intYScale == 0) { |
+ intYScale = SK_Scalar1; |
+ } |
+ s->fX = intYScale; |
+ s->fY = intYScale; |
+ break; |
+ } |
+ } |
+ |
+ // The 'remaining' matrix sA is the total matrix A without the scale. |
+ if (!skewedOrFlipped && kFull_PreMatrixScale == preMatrixScale) { |
+ // If GA == A and kFull_PreMatrixScale, sA is identity. |
+ sA->reset(); |
+ } else { |
+ // TODO: If GA == A and kVertical_PreMatrixScale, sA.scaleY is SK_Scalar1. |
+ // TODO: If GA == A and kVertical_PreMatrixScale and A.scaleX == A.scaleY, sA is identity. |
+ // TODO: like kVertical_PreMatrixScale, kVerticalInteger_PreMatrixScale with int scales. |
+ *sA = A; |
+ sA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY)); |
+ } |
+ |
+ // The 'remainingWithoutRotation' matrix GsA is the non-rotational part of A without the scale. |
+ if (GsA) { |
+ *GsA = GA; |
+ // G is rotational so reorders with the scale. |
+ GsA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY)); |
+ } |
+} |
+ |
SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) { |
SkASSERT(!matrix.hasPerspective()); |