aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/utils.gyp2
-rw-r--r--include/core/SkFloatingPoint.h21
-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
6 files changed, 161 insertions, 61 deletions
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
index 070d18a07e..5b3d9ea98c 100644
--- a/gyp/utils.gyp
+++ b/gyp/utils.gyp
@@ -81,6 +81,8 @@
'../src/utils/SkGatherPixelRefsAndRects.h',
'../src/utils/SkInterpolator.cpp',
'../src/utils/SkLayer.cpp',
+ '../src/utils/SkMatrix22.cpp',
+ '../src/utils/SkMatrix22.h',
'../src/utils/SkMatrix44.cpp',
'../src/utils/SkMD5.cpp',
'../src/utils/SkMD5.h',
diff --git a/include/core/SkFloatingPoint.h b/include/core/SkFloatingPoint.h
index 7dfa9d8680..95c28bc18a 100644
--- a/include/core/SkFloatingPoint.h
+++ b/include/core/SkFloatingPoint.h
@@ -14,6 +14,12 @@
#include <math.h>
#include <float.h>
+
+// For _POSIX_VERSION
+#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
+#include <unistd.h>
+#endif
+
#include "SkFloatBits.h"
// C++98 cmath std::pow seems to be the earliest portable way to get float pow.
@@ -24,9 +30,24 @@ static inline float sk_float_pow(float base, float exp) {
}
static inline float sk_float_copysign(float x, float y) {
+// c++11 contains a 'float copysign(float, float)' function in <cmath>.
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ return copysign(x, y);
+
+// Posix has demanded 'float copysignf(float, float)' (from C99) since Issue 6.
+#elif defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L
+ return copysignf(x, y);
+
+// Visual studio prior to 13 only has 'double _copysign(double, double)'.
+#elif defined(_MSC_VER)
+ return _copysign(x, y);
+
+// Otherwise convert to bits and extract sign.
+#else
int32_t xbits = SkFloat2Bits(x);
int32_t ybits = SkFloat2Bits(y);
return SkBits2Float((xbits & 0x7FFFFFFF) | (ybits & 0x80000000));
+#endif
}
#ifdef SK_BUILD_FOR_WINCE
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);