aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-15 15:52:07 +0000
committerGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-15 15:52:07 +0000
commitd3fbd34099a530b5415c95b1f2f8149ac417b9b3 (patch)
tree378e0b3e153d4a3f252c6f766d575e54c9f704c7 /src
parent73cb15351f33459e0c861a96135c634dec77ef9d (diff)
Fix size of rotated text with FreeType.
This generalizes and shares the solution found for a similar issue with GDI. The issue is that the text size is applied early, and the rest of the transformation late. This allows us to isolate and independently control the text size from the rest of the transformation. R=reed@google.com Review URL: https://codereview.chromium.org/213153006 git-svn-id: http://skia.googlecode.com/svn/trunk@14201 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r--src/ports/SkFontHost_FreeType.cpp104
-rwxr-xr-xsrc/ports/SkFontHost_win.cpp30
-rw-r--r--src/utils/SkMatrix22.cpp39
-rw-r--r--src/utils/SkMatrix22.h26
4 files changed, 138 insertions, 61 deletions
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index 97caab4b6b..e1d62c027e 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -18,6 +18,7 @@
#include "SkGlyph.h"
#include "SkMask.h"
#include "SkMaskGamma.h"
+#include "SkMatrix22.h"
#include "SkOTUtils.h"
#include "SkOnce.h"
#include "SkScalerContext.h"
@@ -43,6 +44,8 @@
#include FT_LCD_FILTER_H
#endif
+// Defined in FreeType 2.3.8 and later.
+// This is a silly build time check, we would need a runtime check if we really cared.
#ifdef FT_ADVANCES_H
#include FT_ADVANCES_H
#endif
@@ -693,9 +696,6 @@ SkAdvancedTypefaceMetrics* SkTypeface_FreeType::onGetAdvancedTypefaceMetrics(
///////////////////////////////////////////////////////////////////////////
-#define BLACK_LUMINANCE_LIMIT 0x40
-#define WHITE_LUMINANCE_LIMIT 0xA0
-
static bool bothZero(SkScalar a, SkScalar b) {
return 0 == a && 0 == b;
}
@@ -849,46 +849,34 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
}
fFace = fFaceRec->fFace;
- // compute our factors from the record
-
- SkMatrix m;
-
- fRec.getSingleMatrix(&m);
-
-#ifdef DUMP_STRIKE_CREATION
- SkString keyString;
- SkFontHost::GetDescriptorKeyString(desc, &keyString);
- printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize),
- SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX),
- SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]),
- SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]),
- fRec.getHinting(), fRec.fMaskFormat, keyString.c_str());
-#endif
-
- // now compute our scale factors
- SkScalar sx = m.getScaleX();
- SkScalar sy = m.getScaleY();
+ // A is the total matrix.
+ SkMatrix A;
+ fRec.getSingleMatrix(&A);
+ SkScalar sx = A.getScaleX();
+ SkScalar sy = A.getScaleY();
fMatrix22Scalar.reset();
- if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) {
+//#define SK_IGNORE_FREETYPE_ROTATION_FIX
+#ifdef SK_IGNORE_FREETYPE_ROTATION_FIX
+ if (A.getSkewX() || A.getSkewY() || sx < 0 || sy < 0) {
// sort of give up on hinting
- sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX()));
- sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy));
+ sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(A.getSkewX()));
+ sy = SkMaxScalar(SkScalarAbs(A.getSkewY()), SkScalarAbs(sy));
sx = sy = SkScalarAve(sx, sy);
SkScalar inv = SkScalarInvert(sx);
// flip the skew elements to go from our Y-down system to FreeType's
- fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv));
- fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv));
- fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv));
- fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv));
-
- fMatrix22Scalar.setScaleX(SkScalarMul(m.getScaleX(), inv));
- fMatrix22Scalar.setSkewX(-SkScalarMul(m.getSkewX(), inv));
- fMatrix22Scalar.setSkewY(-SkScalarMul(m.getSkewY(), inv));
- fMatrix22Scalar.setScaleY(SkScalarMul(m.getScaleY(), inv));
+ fMatrix22.xx = SkScalarToFixed(SkScalarMul(A.getScaleX(), inv));
+ fMatrix22.xy = -SkScalarToFixed(SkScalarMul(A.getSkewX(), inv));
+ fMatrix22.yx = -SkScalarToFixed(SkScalarMul(A.getSkewY(), inv));
+ fMatrix22.yy = SkScalarToFixed(SkScalarMul(A.getScaleY(), inv));
+
+ fMatrix22Scalar.setScaleX(SkScalarMul(A.getScaleX(), inv));
+ fMatrix22Scalar.setSkewX(-SkScalarMul(A.getSkewX(), inv));
+ fMatrix22Scalar.setSkewY(-SkScalarMul(A.getSkewY(), inv));
+ fMatrix22Scalar.setScaleY(SkScalarMul(A.getScaleY(), inv));
} else {
fMatrix22.xx = fMatrix22.yy = SK_Fixed1;
fMatrix22.xy = fMatrix22.yx = 0;
@@ -896,6 +884,54 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
fScale.set(sx, sy);
fScaleX = SkScalarToFixed(sx);
fScaleY = SkScalarToFixed(sy);
+#else
+ // In GDI, the hinter is aware of the current transformation
+ // (the transform is in some sense applied before/with the hinting).
+ // The bytecode can then test if it is rotated or stretched and decide
+ // to apply instructions or not.
+ //
+ // FreeType, however, always does the transformation strictly after hinting.
+ // It just sets 'rotated' and 'stretched' to false and only applies the
+ // size before hinting.
+ //
+ // Also, FreeType respects the head::flags::IntegerScaling flag,
+ // (although this is patched out on most major distros)
+ // so it is critical to get the size correct on the request.
+ //
+ // This also gets us the actual closest size on bitmap fonts as well.
+ if (A.getSkewX() || A.getSkewY() || sx < 0 || sy < 0) {
+ // 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 is the matrix A with rotation removed.
+ SkMatrix GA(G);
+ GA.preConcat(A);
+
+ sx = SkScalarAbs(GA.get(SkMatrix::kMScaleX));
+ sy = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
+
+ // sA is the total matrix A without the text scale.
+ SkMatrix sA(A);
+ sA.preScale(SkScalarInvert(sx), SkScalarInvert(sy)); //remove text size
+
+ fMatrix22Scalar.setScaleX(sA.getScaleX());
+ fMatrix22Scalar.setSkewX(-sA.getSkewX());
+ fMatrix22Scalar.setSkewY(-sA.getSkewY());
+ fMatrix22Scalar.setScaleY(sA.getScaleY());
+ }
+ fScale.set(sx, sy);
+ fScaleX = SkScalarToFixed(sx);
+ fScaleY = SkScalarToFixed(sy);
+ fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX());
+ fMatrix22.xy = SkScalarToFixed(fMatrix22Scalar.getSkewX());
+ fMatrix22.yx = SkScalarToFixed(fMatrix22Scalar.getSkewY());
+ fMatrix22.yy = SkScalarToFixed(fMatrix22Scalar.getScaleY());
+#endif
fLCDIsVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index 8ed3b666aa..47a29c0024 100755
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -16,6 +16,7 @@
#include "SkGlyph.h"
#include "SkHRESULT.h"
#include "SkMaskGamma.h"
+#include "SkMatrix22.h"
#include "SkOTTable_maxp.h"
#include "SkOTTable_name.h"
#include "SkOTUtils.h"
@@ -636,34 +637,9 @@ SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
fRec.getSingleMatrix(&A);
A.mapPoints(&h, 1);
- // Find the Given's matrix [[c, -s],[s, c]] which rotates the baseline vector h
- // (where the baseline is mapped to) to the positive horizontal axis.
- const SkScalar& a = h.fX;
- const SkScalar& b = h.fY;
- SkScalar c, s;
- if (0 == b) {
- c = SkDoubleToScalar(_copysign(SK_Scalar1, a));
- s = 0;
- } else if (0 == a) {
- c = 0;
- s = SkDoubleToScalar(-_copysign(SK_Scalar1, b));
- } else if (SkScalarAbs(b) > SkScalarAbs(a)) {
- SkScalar t = a / b;
- SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), b));
- s = -1 / u;
- c = -s * t;
- } else {
- SkScalar t = b / a;
- SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), a));
- c = 1 / u;
- s = -c * t;
- }
-
- // G is the Given's Matrix for A (rotational matrix such that GA[0][1] == 0).
+ // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
SkMatrix G;
- G.setAll(c, -s, 0,
- s, c, 0,
- 0, 0, SkScalarToPersp(SK_Scalar1));
+ SkComputeGivensRotation(h, &G);
// GA is the matrix A with rotation removed.
SkMatrix GA(G);
diff --git a/src/utils/SkMatrix22.cpp b/src/utils/SkMatrix22.cpp
new file mode 100644
index 0000000000..107e123a68
--- /dev/null
+++ b/src/utils/SkMatrix22.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMatrix.h"
+#include "SkPoint.h"
+#include "SkScalar.h"
+
+void SkComputeGivensRotation(const SkVector& h, SkMatrix* G) {
+ const SkScalar& a = h.fX;
+ const SkScalar& b = h.fY;
+ SkScalar c, s;
+ if (0 == b) {
+ c = SkScalarCopySign(SK_Scalar1, a);
+ s = 0;
+ //r = SkScalarAbs(a);
+ } else if (0 == a) {
+ c = 0;
+ s = -SkScalarCopySign(SK_Scalar1, b);
+ //r = SkScalarAbs(b);
+ } else if (SkScalarAbs(b) > SkScalarAbs(a)) {
+ SkScalar t = a / b;
+ SkScalar u = SkScalarCopySign(SkScalarSqrt(SK_Scalar1 + t*t), b);
+ s = -SK_Scalar1 / u;
+ c = -s * t;
+ //r = b * u;
+ } else {
+ SkScalar t = b / a;
+ SkScalar u = SkScalarCopySign(SkScalarSqrt(SK_Scalar1 + t*t), a);
+ c = SK_Scalar1 / u;
+ s = -c * t;
+ //r = a * u;
+ }
+
+ G->setSinCos(s, c);
+}
diff --git a/src/utils/SkMatrix22.h b/src/utils/SkMatrix22.h
new file mode 100644
index 0000000000..d0f4ed3155
--- /dev/null
+++ b/src/utils/SkMatrix22.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPoint.h"
+
+class SkMatrix;
+
+/** Find the Givens matrix G, which is the rotational matrix
+ * that rotates the vector h to the positive hoizontal axis.
+ * G * h = [hypot(h), 0]
+ *
+ * This is equivalent to
+ *
+ * SkScalar r = h.length();
+ * SkScalar r_inv = r ? SkScalarInvert(r) : 0;
+ * h.scale(r_inv);
+ * G->setSinCos(-h.fY, h.fX);
+ *
+ * but has better numerical stability by using (partial) hypot,
+ * and saves a multiply by not computing r.
+ */
+void SkComputeGivensRotation(const SkVector& h, SkMatrix* G);