Replace use of deprecated CG methods.

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
This commit is contained in:
bungeman 2014-12-10 21:43:27 -08:00 committed by Commit bot
parent 294738268d
commit 3490263287
9 changed files with 255 additions and 217 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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));

View File

@ -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) {