diff --git a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json index 12565b4728..d6ce67132c 100644 --- a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json +++ b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json @@ -6147,7 +6147,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 11789348685223172819 + 13032493291667632017 ] ], "reviewed-by-human": true @@ -6156,7 +6156,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 15149178935785271539 + 11273349171545726106 ] ], "reviewed-by-human": true @@ -6165,7 +6165,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 15438356327428870853 + 4366598485015533839 ] ], "reviewed-by-human": true @@ -9457,10 +9457,11 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 13789531822458450208 + 1555170927970049036 ] ], - "ignore-failure": false + "ignore-failure": false, + "reviewed-by-human": true }, "fontscaler_8888.png": { "allowed-digests": [ @@ -9475,10 +9476,11 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 3435885476716320759 + 17388530483934778471 ] ], - "ignore-failure": false + "ignore-failure": false, + "reviewed-by-human": true }, "fontscaler_mesa.png": { "allowed-digests": [ @@ -16271,7 +16273,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 9662049661835088514 + 18234606030589341199 ] ], "ignore-failure": false, @@ -16281,7 +16283,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 6893029029115312480 + 264636000130053487 ] ], "reviewed-by-human": true diff --git a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json index a76f4b6555..5f677c57f3 100644 --- a/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json +++ b/expectations/gm/Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json @@ -5247,7 +5247,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 11789348685223172819 + 13032493291667632017 ] ], "reviewed-by-human": true @@ -5256,7 +5256,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 15149178935785271539 + 11273349171545726106 ] ], "reviewed-by-human": true @@ -5265,7 +5265,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 15438356327428870853 + 4366598485015533839 ] ], "reviewed-by-human": true @@ -8234,10 +8234,11 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 13789531822458450208 + 1555170927970049036 ] ], - "ignore-failure": false + "ignore-failure": false, + "reviewed-by-human": true }, "fontscaler_8888.png": { "allowed-digests": [ @@ -8252,10 +8253,11 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 3435885476716320759 + 17388530483934778471 ] ], - "ignore-failure": false + "ignore-failure": false, + "reviewed-by-human": true }, "fontscaler_mesa.png": { "allowed-digests": [ @@ -14364,7 +14366,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 9662049661835088514 + 18234606030589341199 ] ], "ignore-failure": false, @@ -14374,7 +14376,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 6893029029115312480 + 264636000130053487 ] ], "reviewed-by-human": true diff --git a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json index 5ab9a4ef06..748162bb4d 100644 --- a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json +++ b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug/expected-results.json @@ -5743,7 +5743,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 17002895254586432810 + 10504736350687219486 ] ], "reviewed-by-human": true @@ -5752,7 +5752,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 4959262438000071841 + 14198296579204287815 ] ], "reviewed-by-human": true @@ -5761,7 +5761,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 1210581495450174193 + 514767491095290848 ] ], "reviewed-by-human": true @@ -8985,37 +8985,28 @@ "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": [ @@ -9948,28 +9939,28 @@ "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": [ @@ -9984,28 +9975,28 @@ "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": [ @@ -10092,28 +10083,28 @@ "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": [ @@ -14146,7 +14137,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 12884571093974353905 + 2435486642285013318 ] ], "reviewed-by-human": true @@ -14155,7 +14146,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 13543648152054227175 + 9933814546434293170 ] ], "reviewed-by-human": true @@ -14164,7 +14155,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 13289089982625103849 + 3198612469547093872 ] ], "reviewed-by-human": true @@ -15356,7 +15347,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 6651118343277262089 + 7001896540887715021 ] ], "reviewed-by-human": true @@ -15365,7 +15356,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 3905594370593977881 + 4651633999793759361 ] ], "reviewed-by-human": true @@ -17917,37 +17908,28 @@ "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": [ @@ -17977,31 +17959,25 @@ "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 diff --git a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json index bd7355a0a7..915b1d7dc3 100644 --- a/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json +++ b/expectations/gm/Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release/expected-results.json @@ -5873,7 +5873,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 17002895254586432810 + 10504736350687219486 ] ], "reviewed-by-human": true @@ -5882,7 +5882,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 4959262438000071841 + 14198296579204287815 ] ], "reviewed-by-human": true @@ -5891,7 +5891,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 1210581495450174193 + 514767491095290848 ] ], "reviewed-by-human": true @@ -9494,37 +9494,28 @@ "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": [ @@ -10495,28 +10486,28 @@ "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": [ @@ -10541,28 +10532,28 @@ "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": [ @@ -10679,28 +10670,28 @@ "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": [ @@ -15196,7 +15187,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 12884571093974353905 + 2435486642285013318 ] ], "reviewed-by-human": true @@ -15205,7 +15196,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 13543648152054227175 + 9933814546434293170 ] ], "reviewed-by-human": true @@ -15214,7 +15205,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 13289089982625103849 + 3198612469547093872 ] ], "reviewed-by-human": true @@ -16527,7 +16518,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 6651118343277262089 + 7001896540887715021 ] ], "reviewed-by-human": true @@ -16536,7 +16527,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 3905594370593977881 + 4651633999793759361 ] ], "reviewed-by-human": true @@ -19348,37 +19339,28 @@ "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": [ @@ -19418,31 +19400,25 @@ "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 diff --git a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Debug/expected-results.json b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Debug/expected-results.json index 2e7749cf43..4d337e3e4c 100644 --- a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Debug/expected-results.json +++ b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Debug/expected-results.json @@ -18366,7 +18366,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 3831063373917728128 + 3842687298137299011 ] ], "reviewed-by-human": true @@ -18375,7 +18375,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 11558777522282590832 + 14073061431532239187 ] ], "reviewed-by-human": true @@ -18384,7 +18384,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 1729916360334344548 + 2795433082744565454 ] ], "reviewed-by-human": true @@ -18393,7 +18393,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 5441129619971163954 + 8485952545707534084 ] ], "reviewed-by-human": true diff --git a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json index d7d1d36c75..93a8e57152 100644 --- a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json +++ b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json @@ -18366,7 +18366,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 3831063373917728128 + 3842687298137299011 ] ], "reviewed-by-human": true @@ -18375,7 +18375,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 11558777522282590832 + 14073061431532239187 ] ], "reviewed-by-human": true @@ -18384,7 +18384,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 1729916360334344548 + 2795433082744565454 ] ], "reviewed-by-human": true @@ -18393,7 +18393,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 5441129619971163954 + 8485952545707534084 ] ], "reviewed-by-human": true diff --git a/expectations/gm/Test-Win8-ShuttleA-HD7770-x86_64-Debug/expected-results.json b/expectations/gm/Test-Win8-ShuttleA-HD7770-x86_64-Debug/expected-results.json index 233ba543f8..5b9284f6ea 100644 --- a/expectations/gm/Test-Win8-ShuttleA-HD7770-x86_64-Debug/expected-results.json +++ b/expectations/gm/Test-Win8-ShuttleA-HD7770-x86_64-Debug/expected-results.json @@ -5140,7 +5140,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 15579862310139097370 + 8420356960539158456 ] ], "reviewed-by-human": true @@ -12325,7 +12325,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 3831063373917728128 + 3842687298137299011 ] ], "reviewed-by-human": true @@ -12334,7 +12334,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 11361790156959481856 + 9281955663584814698 ] ], "reviewed-by-human": true @@ -14152,7 +14152,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 14699863291227746930 + 4737335735437517136 ] ], "reviewed-by-human": true diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index 4d22fbec62..cf3c30cfff 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -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)); diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index c19df196b3..0d4bbb73d9 100755 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -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 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 tags(CTFontCopyAvailableTables(fFontRef,kCTFontTableOptionNoOptions)); + if (tags) { + int count = SkToInt(CFArrayGetCount(tags)); + for (int i = 0; i < count; ++i) { + uintptr_t tag = reinterpret_cast(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 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 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(&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 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) {