Replace use of deprecated CG methods.
authorbungeman <bungeman@google.com>
Thu, 11 Dec 2014 05:43:27 +0000 (21:43 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 11 Dec 2014 05:43:28 +0000 (21:43 -0800)
OSX10.9 and iOS7.0 deprecated CGContextShowGlyphsAtPoint so a new API
should be used. OSX10.7 and iOS4.2 replace CGContextShowGlyphsAtPoint with
CTFontDrawGlyphs. OSX10.5 and iOS2.0 have CGContextShowGlyphsAtPositions
which works similarly to CTFontDrawGlyphs and has not yet been deprecated.
This change allows the use of CTFontDrawGlyphs when it is available,
falling back to CGContextShowGlyphsAtPositions when it isn't.

Review URL: https://codereview.chromium.org/770383002

expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json
expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json
expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Debug/expected-results.json
expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json
expectations/gm/Test-Win8-ShuttleA-HD7770-x86_64-Debug/expected-results.json
src/core/SkScalerContext.cpp
src/ports/SkFontHost_mac.cpp

index 12565b4..d6ce671 100644 (file)
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11789348685223172819
+          13032493291667632017
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15149178935785271539
+          11273349171545726106
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15438356327428870853
+          4366598485015533839
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13789531822458450208
+          1555170927970049036
         ]
       ], 
-      "ignore-failure": false
+      "ignore-failure": false, 
+      "reviewed-by-human": true
     }, 
     "fontscaler_8888.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3435885476716320759
+          17388530483934778471
         ]
       ], 
-      "ignore-failure": false
+      "ignore-failure": false, 
+      "reviewed-by-human": true
     }, 
     "fontscaler_mesa.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          9662049661835088514
+          18234606030589341199
         ]
       ], 
       "ignore-failure": false, 
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6893029029115312480
+          264636000130053487
         ]
       ], 
       "reviewed-by-human": true
index a76f4b6..5f677c5 100644 (file)
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11789348685223172819
+          13032493291667632017
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15149178935785271539
+          11273349171545726106
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15438356327428870853
+          4366598485015533839
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13789531822458450208
+          1555170927970049036
         ]
       ], 
-      "ignore-failure": false
+      "ignore-failure": false, 
+      "reviewed-by-human": true
     }, 
     "fontscaler_8888.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3435885476716320759
+          17388530483934778471
         ]
       ], 
-      "ignore-failure": false
+      "ignore-failure": false, 
+      "reviewed-by-human": true
     }, 
     "fontscaler_mesa.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          9662049661835088514
+          18234606030589341199
         ]
       ], 
       "ignore-failure": false, 
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6893029029115312480
+          264636000130053487
         ]
       ], 
       "reviewed-by-human": true
index 5ab9a4e..748162b 100644 (file)
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          17002895254586432810
+          10504736350687219486
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4959262438000071841
+          14198296579204287815
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1210581495450174193
+          514767491095290848
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13789531822458450208
+          1555170927970049036
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "fontscaler_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4537724508375691923
+          2134692741702715875
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "fontscaler_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2530193206350601725
+          18427423781989508156
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "fontscaler_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          8003986504359203333
+          17167114531887522572
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_b_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4926111011675128636
+          4880012749537220191
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_b_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15937320568943303273
+          3593359414566240039
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_b_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2627991343461002616
+          16689680143909117721
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_f_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1582657629558125819
+          5821692075575780679
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_f_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15937320568943303273
+          3593359414566240039
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_f_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2627991343461002616
+          16689680143909117721
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_n_f_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1582657629558125819
+          5821692075575780679
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_n_f_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15937320568943303273
+          3593359414566240039
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_n_f_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12884571093974353905
+          2435486642285013318
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13543648152054227175
+          9933814546434293170
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13289089982625103849
+          3198612469547093872
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6651118343277262089
+          7001896540887715021
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3905594370593977881
+          4651633999793759361
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          16428423489579456001
+          8700348762160056890
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext2_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          14850136310879358623
+          10189510583005081144
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext2_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2015193952465671122
+          17574422104110667197
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext2_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6192051826260083375
+          247197231749911357
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3886670421682288382
+          6066620589880697533
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12925986002228045213
+          7852579337448825372
         ]
       ], 
       "reviewed-by-human": true
index bd7355a..915b1d7 100644 (file)
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          17002895254586432810
+          10504736350687219486
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4959262438000071841
+          14198296579204287815
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1210581495450174193
+          514767491095290848
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13789531822458450208
+          1555170927970049036
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "fontscaler_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4537724508375691923
+          2134692741702715875
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "fontscaler_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2530193206350601725
+          18427423781989508156
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "fontscaler_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          8003986504359203333
+          17167114531887522572
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_b_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          4926111011675128636
+          4880012749537220191
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_b_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15937320568943303273
+          3593359414566240039
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_b_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2627991343461002616
+          16689680143909117721
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_f_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1582657629558125819
+          5821692075575780679
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_f_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15937320568943303273
+          3593359414566240039
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_h_f_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2627991343461002616
+          16689680143909117721
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_n_f_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1582657629558125819
+          5821692075575780679
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_n_f_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15937320568943303273
+          3593359414566240039
         ]
       ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "glyph_pos_n_f_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12884571093974353905
+          2435486642285013318
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13543648152054227175
+          9933814546434293170
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          13289089982625103849
+          3198612469547093872
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6651118343277262089
+          7001896540887715021
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3905594370593977881
+          4651633999793759361
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          16428423489579456001
+          8700348762160056890
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext2_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          14850136310879358623
+          10189510583005081144
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext2_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          2015193952465671122
+          17574422104110667197
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext2_pdf-mac.png": {
       "allowed-digests": [
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          6192051826260083375
+          247197231749911357
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext_8888.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3886670421682288382
+          6066620589880697533
         ]
       ], 
-      "bugs": [
-        1578
-      ], 
-      "reviewed-by-human": false
+      "reviewed-by-human": true
     }, 
     "verttext_gpu.png": {
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          12925986002228045213
+          7852579337448825372
         ]
       ], 
       "reviewed-by-human": true
index 2e7749c..4d337e3 100644 (file)
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3831063373917728128
+          3842687298137299011
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11558777522282590832
+          14073061431532239187
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1729916360334344548
+          2795433082744565454
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          5441129619971163954
+          8485952545707534084
         ]
       ], 
       "reviewed-by-human": true
index d7d1d36..93a8e57 100644 (file)
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3831063373917728128
+          3842687298137299011
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11558777522282590832
+          14073061431532239187
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          1729916360334344548
+          2795433082744565454
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          5441129619971163954
+          8485952545707534084
         ]
       ], 
       "reviewed-by-human": true
index 233ba54..5b9284f 100644 (file)
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          15579862310139097370
+          8420356960539158456
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          3831063373917728128
+          3842687298137299011
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          11361790156959481856
+          9281955663584814698
         ]
       ], 
       "reviewed-by-human": true
       "allowed-digests": [
         [
           "bitmap-64bitMD5", 
-          14699863291227746930
+          4737335735437517136
         ]
       ], 
       "reviewed-by-human": true
index 4d22fbe..cf3c30c 100644 (file)
@@ -735,6 +735,29 @@ void SkScalerContextRec::computeMatrices(PreMatrixScale preMatrixScale, SkVector
         *A_out = A;
     }
 
+    // If the 'total' matrix is singular, set the 'scale' to something finite and zero the matrices.
+    // All underlying ports have issues with zero text size, so use the matricies to zero.
+
+    // Map the vectors [1,1] and [1,-1] (the EM) through the 'total' matrix.
+    // If the length of one of these vectors is less than 1/256 then an EM filling square will
+    // never affect any pixels.
+    SkVector diag[2] = { { A.getScaleX() + A.getSkewX(), A.getScaleY() + A.getSkewY() },
+                         { A.getScaleX() - A.getSkewX(), A.getScaleY() - A.getSkewY() }, };
+    if (diag[0].lengthSqd() <= SK_ScalarNearlyZero * SK_ScalarNearlyZero ||
+        diag[1].lengthSqd() <= SK_ScalarNearlyZero * SK_ScalarNearlyZero)
+    {
+        s->fX = SK_Scalar1;
+        s->fY = SK_Scalar1;
+        sA->setScale(0, 0);
+        if (GsA) {
+            GsA->setScale(0, 0);
+        }
+        if (G_inv) {
+            G_inv->reset();
+        }
+        return;
+    }
+
     // GA is the matrix A with rotation removed.
     SkMatrix GA;
     bool skewedOrFlipped = A.getSkewX() || A.getSkewY() || A.getScaleX() < 0 || A.getScaleY() < 0;
@@ -789,12 +812,18 @@ void SkScalerContextRec::computeMatrices(PreMatrixScale preMatrixScale, SkVector
     }
 
     // The 'remaining' matrix sA is the total matrix A without the scale.
-    if (!skewedOrFlipped && kFull_PreMatrixScale == preMatrixScale) {
+    if (!skewedOrFlipped && (
+            (kFull_PreMatrixScale == preMatrixScale) ||
+            (kVertical_PreMatrixScale == preMatrixScale && A.getScaleX() == A.getScaleY())))
+    {
         // If GA == A and kFull_PreMatrixScale, sA is identity.
+        // If GA == A and kVertical_PreMatrixScale and A.scaleX == A.scaleY, sA is identity.
+        sA->reset();
+    } else if (!skewedOrFlipped && kVertical_PreMatrixScale == preMatrixScale) {
+        // If GA == A and kVertical_PreMatrixScale, sA.scaleY is SK_Scalar1.
         sA->reset();
+        sA->setScaleX(A.getScaleX() / s->fY);
     } 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));
index c19df19..0d4bbb7 100755 (executable)
@@ -25,6 +25,7 @@
 #include "SkFontDescriptor.h"
 #include "SkFloatingPoint.h"
 #include "SkGlyph.h"
+#include "SkLazyFnPtr.h"
 #include "SkMaskGamma.h"
 #include "SkSFNTHeader.h"
 #include "SkOTTable_glyf.h"
@@ -43,7 +44,7 @@
 #include "SkFontMgr.h"
 #include "SkUtils.h"
 
-//#define HACK_COLORGLYPHS
+#include <dlfcn.h>
 
 class SkScalerContext_Mac;
 
@@ -273,7 +274,6 @@ static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
 ///////////////////////////////////////////////////////////////////////////////
 
 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
-#define BITMAP_INFO_GRAY (kCGImageAlphaNone)
 
 /**
  * There does not appear to be a publicly accessable API for determining if lcd
@@ -304,7 +304,14 @@ static bool supports_LCD() {
 
 class Offscreen {
 public:
-    Offscreen();
+    Offscreen()
+        : fRGBSpace(NULL)
+        , fCG(NULL)
+        , fDoAA(false)
+        , fDoLCD(false)
+    {
+        fSize.set(0, 0);
+    }
 
     CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
                       CGGlyph glyphID, size_t* rowBytesPtr,
@@ -328,11 +335,6 @@ private:
     }
 };
 
-Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
-                         fDoAA(false), fDoLCD(false) {
-    fSize.set(0, 0);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) {
@@ -440,8 +442,21 @@ public:
         , fRequestedName(requestedName)
         , fFontRef(fontRef) // caller has already called CFRetain for us
         , fIsLocalStream(isLocalStream)
+        , fHasSbixTable(false)
     {
         SkASSERT(fontRef);
+
+        AutoCFRelease<CFArrayRef> tags(CTFontCopyAvailableTables(fFontRef,kCTFontTableOptionNoOptions));
+        if (tags) {
+            int count = SkToInt(CFArrayGetCount(tags));
+            for (int i = 0; i < count; ++i) {
+                uintptr_t tag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(tags, i));
+                if ('sbix' == tag) {
+                    fHasSbixTable = true;
+                    break;
+                }
+            }
+        }
     }
 
     SkString fRequestedName;
@@ -469,6 +484,7 @@ protected:
 
 private:
     bool fIsLocalStream;
+    bool fHasSbixTable;
 
     typedef SkTypeface INHERITED;
 };
@@ -663,6 +679,7 @@ private:
 
     Offscreen fOffscreen;
     AutoCFRelease<CTFontRef> fCTFont;
+    CGAffineTransform fInvTransform;
 
     /** Vertical variant of fCTFont.
      *
@@ -701,9 +718,14 @@ SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
     SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
     fGlyphCount = SkToU16(numGlyphs);
 
+    // CT on (at least) 10.9 will size color glyphs down from the requested size, but not up.
+    // As a result, it is necessary to know the actual device size and request that.
+    SkVector scale;
     SkMatrix skTransform;
-    fRec.getSingleMatrixWithoutTextSize(&skTransform);
+    fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, &scale, &skTransform,
+                         NULL, NULL, &fFUnitMatrix);
     CGAffineTransform transform = MatrixToCGAffineTransform(skTransform);
+    fInvTransform = CGAffineTransformInvert(transform);
 
     AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
     if (fVertical) {
@@ -722,13 +744,7 @@ SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
 
     // The transform contains everything except the requested text size.
     // Some properties, like 'trak', are based on the text size (before applying the matrix).
-    CGFloat textSize = ScalarToCG(fRec.fTextSize);
-
-    // If a text size of 0 is requested, CoreGraphics will use 12 instead.
-    // If the text size is 0, set it to something tiny.
-    if (textSize < CGFLOAT_MIN) {
-        textSize = CGFLOAT_MIN;
-    }
+    CGFloat textSize = ScalarToCG(scale.y());
 
     fCTFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, &transform, ctFontDesc));
     fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, NULL));
@@ -739,14 +755,39 @@ SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
     }
 
     // The fUnitMatrix includes the text size (and em) as it is used to scale the raw font data.
-    fRec.getSingleMatrix(&fFUnitMatrix);
     SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
     fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
 }
 
+extern "C" {
+
+/** CTFontDrawGlyphs was introduced in 10.7. */
+typedef void (*CTFontDrawGlyphsProc)(CTFontRef, const CGGlyph[], const CGPoint[],
+                                     size_t, CGContextRef);
+
+/** This is an implementation of CTFontDrawGlyphs for 10.6. */
+static void sk_legacy_CTFontDrawGlyphs(CTFontRef, const CGGlyph glyphs[], const CGPoint points[],
+                                       size_t count, CGContextRef cg)
+{
+    CGContextShowGlyphsAtPositions(cg, glyphs, points, count);
+}
+
+}
+
+CTFontDrawGlyphsProc SkChooseCTFontDrawGlyphs() {
+    CTFontDrawGlyphsProc realCTFontDrawGlyphs;
+    *reinterpret_cast<void**>(&realCTFontDrawGlyphs) = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
+    return realCTFontDrawGlyphs ? realCTFontDrawGlyphs : sk_legacy_CTFontDrawGlyphs;
+};
+
+SK_DECLARE_STATIC_LAZY_FN_PTR(CTFontDrawGlyphsProc, gCTFontDrawGlyphs, SkChooseCTFontDrawGlyphs);
+
 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
                              CGGlyph glyphID, size_t* rowBytesPtr,
-                             bool generateA8FromLCD) {
+                             bool generateA8FromLCD)
+{
+    CTFontDrawGlyphsProc ctFontDrawGlyphs = gCTFontDrawGlyphs.get();
+
     if (!fRGBSpace) {
         //It doesn't appear to matter what color space is specified.
         //Regular blends and antialiased text are always (s*a + d*(1-a))
@@ -769,6 +810,13 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
         doAA = true;
     }
 
+    // If this font might have color glyphs, disable LCD as there's no way to support it.
+    // CoreText doesn't tell us which format it ended up using, so we can't detect it.
+    // A8 will be ugly too (white on transparent), but TODO: we can detect gray and set to A8.
+    if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
+        doLCD = false;
+    }
+
     size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
     if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
         if (fSize.fWidth < glyph.fWidth) {
@@ -780,24 +828,25 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
 
         rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
         void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
+        const CGImageAlphaInfo alpha = (SkMask::kARGB32_Format == glyph.fMaskFormat)
+                                     ? kCGImageAlphaPremultipliedFirst
+                                     : kCGImageAlphaNoneSkipFirst;
+        const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha;
         fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
-                                        rowBytes, fRGBSpace, BITMAP_INFO_RGB));
+                                        rowBytes, fRGBSpace, bitmapInfo));
 
-        // skia handles quantization itself, so we disable this for cg to get
-        // full fractional data from them.
+        // Skia handles quantization and subpixel positioning,
+        // so disable quantization and enabe subpixel positioning in CG.
         CGContextSetAllowsFontSubpixelQuantization(fCG, false);
         CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
 
-        CGContextSetTextDrawingMode(fCG, kCGTextFill);
-        CGContextSetFont(fCG, context.fCGFont);
-        CGContextSetFontSize(fCG, CTFontGetSize(context.fCTFont));
-        CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
-
         // Because CG always draws from the horizontal baseline,
         // if there is a non-integral translation from the horizontal origin to the vertical origin,
         // then CG cannot draw the glyph in the correct location without subpixel positioning.
-        CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
-        CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical);
+        CGContextSetAllowsFontSubpixelPositioning(fCG, true);
+        CGContextSetShouldSubpixelPositionFonts(fCG, true);
+
+        CGContextSetTextDrawingMode(fCG, kCGTextFill);
 
         // Draw white on black to create mask.
         // TODO: Draw black on white and invert, CG has a special case codepath.
@@ -806,6 +855,14 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
         // force our checks below to happen
         fDoAA = !doAA;
         fDoLCD = !doLCD;
+
+        if (sk_legacy_CTFontDrawGlyphs == ctFontDrawGlyphs) {
+            // CTFontDrawGlyphs will apply the font, font size, and font matrix to the CGContext.
+            // Our 'fake' one does not, so set up the CGContext here.
+            CGContextSetFont(fCG, context.fCGFont);
+            CGContextSetFontSize(fCG, CTFontGetSize(context.fCTFont));
+            CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
+        }
     }
 
     if (fDoAA != doAA) {
@@ -831,7 +888,7 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
         subY = SkFixedToFloat(glyph.getSubYFixed());
     }
 
-    // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin.
+    // CoreText and CoreGraphics always draw using the horizontal baseline origin.
     if (context.fVertical) {
         SkPoint offset;
         context.getVerticalOffset(glyphID, &offset);
@@ -839,9 +896,12 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
         subY += offset.fY;
     }
 
-    CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
-                               glyph.fTop + glyph.fHeight - subY,
-                               &glyphID, 1);
+    // CTFontDrawGlyphs and CGContextShowGlyphsAtPositions take 'positions' which are in text space.
+    // The glyph location (in device space) must be mapped into text space, so that CG can convert
+    // it back into device space.
+    CGPoint point = CGPointMake(-glyph.fLeft + subX, glyph.fTop + glyph.fHeight - subY);
+    point = CGPointApplyAffineTransform(point, context.fInvTransform);
+    ctFontDrawGlyphs(context.fCTFont, &glyphID, &point, 1, fCG);
 
     SkASSERT(rowBytesPtr);
     *rowBytesPtr = rowBytes;
@@ -1045,10 +1105,6 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
     glyph->fTop = SkToS16(skIBounds.fTop);
     glyph->fWidth = SkToU16(skIBounds.width());
     glyph->fHeight = SkToU16(skIBounds.height());
-
-#ifdef HACK_COLORGLYPHS
-    glyph->fMaskFormat = SkMask::kARGB32_Format;
-#endif
 }
 
 #include "SkColorPriv.h"
@@ -1140,22 +1196,14 @@ static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowByt
     }
 }
 
-#ifdef HACK_COLORGLYPHS
-// hack to colorize the output for testing kARGB32_Format
-static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
-                                     int x, int y) {
+static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) {
+    U8CPU a = (rgb >> 24) & 0xFF;
     U8CPU r = (rgb >> 16) & 0xFF;
     U8CPU g = (rgb >>  8) & 0xFF;
     U8CPU b = (rgb >>  0) & 0xFF;
-    unsigned a = SkComputeLuminance(r, g, b);
 
-    // compute gradient from x,y
-    r = x * 255 / glyph.fWidth;
-    g = 0;
-    b = (glyph.fHeight - y) * 255 / glyph.fHeight;
-    return SkPreMultiplyARGB(a, r, g, b);    // red
+    return SkPackARGB32(a, r, g, b);
 }
-#endif
 
 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
     return (T*)((char*)ptr + byteOffset);
@@ -1228,20 +1276,18 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
                 dst += dstRB;
             }
         } break;
-#ifdef HACK_COLORGLYPHS
         case SkMask::kARGB32_Format: {
             const int width = glyph.fWidth;
             size_t dstRB = glyph.rowBytes();
             SkPMColor* dst = (SkPMColor*)glyph.fImage;
             for (int y = 0; y < glyph.fHeight; y++) {
                 for (int x = 0; x < width; ++x) {
-                    dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y);
+                    dst[x] = cgpixels_to_pmcolor(cgPixels[x]);
                 }
                 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
                 dst = (SkPMColor*)((char*)dst + dstRB);
             }
         } break;
-#endif
         default:
             SkDEBUGFAIL("unexpected mask format");
             break;
@@ -1828,6 +1874,13 @@ void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
         }
     }
 
+    // CoreText provides no information as to whether a glyph will be color or not.
+    // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis.
+    // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd.
+    if (fHasSbixTable) {
+        rec->fMaskFormat = SkMask::kARGB32_Format;
+    }
+
     // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
     // All other masks can use regular gamma.
     if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {