respect subpixel positioning
git-svn-id: http://skia.googlecode.com/svn/trunk@2165 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
1f221a7021
commit
cb6ccdde51
@ -293,5 +293,31 @@ private:
|
||||
#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
|
||||
#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum SkAxisAlignment {
|
||||
kNone_SkAxisAlignment,
|
||||
kX_SkAxisAlignment,
|
||||
kY_SkAxisAlignment
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the axis (if any) that the baseline for horizontal text will land on
|
||||
* after running through the specified matrix.
|
||||
*
|
||||
* As an example, the identity matrix will return kX_SkAxisAlignment
|
||||
*/
|
||||
static SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
|
||||
SkASSERT(!matrix.hasPerspective());
|
||||
|
||||
if (0 == matrix[SkMatrix::kMSkewY]) {
|
||||
return kX_SkAxisAlignment;
|
||||
}
|
||||
if (0 == matrix[SkMatrix::kMScaleX]) {
|
||||
return kY_SkAxisAlignment;
|
||||
}
|
||||
return kNone_SkAxisAlignment;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1438,24 +1438,6 @@ SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
|
||||
}
|
||||
}
|
||||
|
||||
enum RoundBaseline {
|
||||
kDont_Round_Baseline,
|
||||
kRound_X_Baseline,
|
||||
kRound_Y_Baseline
|
||||
};
|
||||
|
||||
static RoundBaseline computeRoundBaseline(const SkMatrix& mat) {
|
||||
if (mat[1] == 0 && mat[3] == 0) {
|
||||
// we're 0 or 180 degrees, round the y coordinate of the baseline
|
||||
return kRound_Y_Baseline;
|
||||
} else if (mat[0] == 0 && mat[4] == 0) {
|
||||
// we're 90 or 270 degrees, round the x coordinate of the baseline
|
||||
return kRound_X_Baseline;
|
||||
} else {
|
||||
return kDont_Round_Baseline;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkDraw::drawText(const char text[], size_t byteLength,
|
||||
@ -1523,11 +1505,10 @@ void SkDraw::drawText(const char text[], size_t byteLength,
|
||||
SkFixed fxMask = ~0;
|
||||
SkFixed fyMask = ~0;
|
||||
if (paint.isSubpixelText()) {
|
||||
RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
|
||||
if (kRound_Y_Baseline == roundBaseline) {
|
||||
SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*matrix);
|
||||
if (kX_SkAxisAlignment == baseline) {
|
||||
fyMask = 0;
|
||||
// fy = (fy + 0x8000) & ~0xFFFF;
|
||||
} else if (kRound_X_Baseline == roundBaseline) {
|
||||
} else if (kY_SkAxisAlignment == baseline) {
|
||||
fxMask = 0;
|
||||
}
|
||||
}
|
||||
@ -1698,7 +1679,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
||||
|
||||
if (paint.isSubpixelText()) {
|
||||
// maybe we should skip the rounding if linearText is set
|
||||
RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
|
||||
SkAxisAlignment roundBaseline = SkComputeAxisAlignmentForHText(*matrix);
|
||||
|
||||
if (SkPaint::kLeft_Align == paint.getTextAlign()) {
|
||||
while (text < stop) {
|
||||
@ -1710,9 +1691,9 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
||||
SkFixed fxMask = ~0;
|
||||
SkFixed fyMask = ~0;
|
||||
|
||||
if (kRound_Y_Baseline == roundBaseline) {
|
||||
if (kX_SkAxisAlignment == roundBaseline) {
|
||||
fyMask = 0;
|
||||
} else if (kRound_X_Baseline == roundBaseline) {
|
||||
} else if (kY_SkAxisAlignment == roundBaseline) {
|
||||
fxMask = 0;
|
||||
}
|
||||
|
||||
@ -1743,9 +1724,9 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
||||
fx = fixedLoc.fX;
|
||||
fy = fixedLoc.fY;
|
||||
|
||||
if (kRound_Y_Baseline == roundBaseline) {
|
||||
if (kX_SkAxisAlignment == roundBaseline) {
|
||||
fyMask = 0;
|
||||
} else if (kRound_X_Baseline == roundBaseline) {
|
||||
} else if (kY_SkAxisAlignment == roundBaseline) {
|
||||
fxMask = 0;
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,26 @@ static bool isLCDFormat(unsigned format) {
|
||||
return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
|
||||
}
|
||||
|
||||
static CGFloat ScalarToCG(SkScalar scalar) {
|
||||
if (sizeof(CGFloat) == sizeof(float)) {
|
||||
return SkScalarToFloat(scalar);
|
||||
} else {
|
||||
SkASSERT(sizeof(CGFloat) == sizeof(double));
|
||||
return SkScalarToDouble(scalar);
|
||||
}
|
||||
}
|
||||
|
||||
static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
|
||||
float sx = 1, float sy = 1) {
|
||||
return CGAffineTransformMake(ScalarToCG(matrix[SkMatrix::kMScaleX]) * sx,
|
||||
-ScalarToCG(matrix[SkMatrix::kMSkewY]) * sy,
|
||||
-ScalarToCG(matrix[SkMatrix::kMSkewX]) * sx,
|
||||
ScalarToCG(matrix[SkMatrix::kMScaleY]) * sy,
|
||||
ScalarToCG(matrix[SkMatrix::kMTransX]) * sx,
|
||||
ScalarToCG(matrix[SkMatrix::kMTransY]) * sy);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
// Macros
|
||||
//----------------------------------------------------------------------------
|
||||
@ -343,17 +363,11 @@ SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
|
||||
// mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
|
||||
// mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
|
||||
mColorSpaceGray = CGColorSpaceCreateDeviceGray();
|
||||
|
||||
mTransform = CGAffineTransformMake(SkScalarToFloat(skMatrix[SkMatrix::kMScaleX]),
|
||||
-SkScalarToFloat(skMatrix[SkMatrix::kMSkewY]),
|
||||
-SkScalarToFloat(skMatrix[SkMatrix::kMSkewX]),
|
||||
SkScalarToFloat(skMatrix[SkMatrix::kMScaleY]),
|
||||
SkScalarToFloat(skMatrix[SkMatrix::kMTransX]),
|
||||
SkScalarToFloat(skMatrix[SkMatrix::kMTransY]));
|
||||
mTransform = MatrixToCGAffineTransform(skMatrix);
|
||||
|
||||
// since our matrix includes everything, we pass 1 for pointSize
|
||||
mFont = CTFontCreateCopyWithAttributes(ctFont, 1, &mTransform, NULL);
|
||||
mGlyphCount = (uint16_t) numGlyphs;
|
||||
mGlyphCount = SkToU16(numGlyphs);
|
||||
}
|
||||
|
||||
SkScalerContext_Mac::~SkScalerContext_Mac(void)
|
||||
@ -547,11 +561,17 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
|
||||
|
||||
CGContextSetAllowsFontSmoothing(cgContext, doLCD);
|
||||
|
||||
// need to pass the fractional part of our position to cg...
|
||||
bool doSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
|
||||
CGContextSetAllowsFontSubpixelPositioning(cgContext, doSubPosition);
|
||||
CGContextSetShouldSubpixelPositionFonts(cgContext, doSubPosition);
|
||||
|
||||
float subX = 0;
|
||||
float subY = 0;
|
||||
if (doSubPosition) {
|
||||
subX = SkFixedToFloat(glyph.getSubXFixed());
|
||||
subY = SkFixedToFloat(glyph.getSubYFixed());
|
||||
}
|
||||
|
||||
// skia handles quantization itself, so we disable this for cg to get
|
||||
// full fractional data from them.
|
||||
CGContextSetAllowsFontSubpixelQuantization(cgContext, false);
|
||||
@ -563,7 +583,9 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
|
||||
CGContextSetFont( cgContext, cgFont);
|
||||
CGContextSetFontSize( cgContext, 1); // cgFont know's its size
|
||||
CGContextSetTextMatrix( cgContext, mTransform);
|
||||
CGContextShowGlyphsAtPoint( cgContext, -glyph.fLeft, glyph.fTop + glyph.fHeight, &cgGlyph, 1);
|
||||
CGContextShowGlyphsAtPoint( cgContext, -glyph.fLeft + subX,
|
||||
glyph.fTop + glyph.fHeight - subY,
|
||||
&cgGlyph, 1);
|
||||
|
||||
if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
|
||||
// downsample from rgba to rgb565
|
||||
@ -608,15 +630,66 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
|
||||
CFSafeRelease(cgContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Our subpixel resolution is only 2 bits in each direction, so a scale of 4
|
||||
* seems sufficient, and possibly even correct, to allow the hinted outline
|
||||
* to be subpixel positioned.
|
||||
*/
|
||||
#define kScaleForSubPixelPositionHinting 4
|
||||
|
||||
void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
|
||||
CTFontRef font = mFont;
|
||||
float scaleX = 1;
|
||||
float scaleY = 1;
|
||||
|
||||
/*
|
||||
* For subpixel positioning, we want to return an unhinted outline, so it
|
||||
* can be positioned nicely at fractional offsets. However, we special-case
|
||||
* if the baseline of the (horizontal) text is axis-aligned. In those cases
|
||||
* we want to retain hinting in the direction orthogonal to the baseline.
|
||||
* e.g. for horizontal baseline, we want to retain hinting in Y.
|
||||
* The way we remove hinting is to scale the font by some value (4) in that
|
||||
* direction, ask for the path, and then scale the path back down.
|
||||
*/
|
||||
if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
|
||||
SkMatrix m;
|
||||
fRec.getSingleMatrix(&m);
|
||||
|
||||
// start out by assuming that we want no hining in X and Y
|
||||
scaleX = scaleY = kScaleForSubPixelPositionHinting;
|
||||
// now see if we need to restore hinting for axis-aligned baselines
|
||||
switch (SkComputeAxisAlignmentForHText(m)) {
|
||||
case kX_SkAxisAlignment:
|
||||
scaleY = 1; // want hinting in the Y direction
|
||||
break;
|
||||
case kY_SkAxisAlignment:
|
||||
scaleX = 1; // want hinting in the X direction
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
|
||||
// need to release font when we're done
|
||||
font = CTFontCreateCopyWithAttributes(mFont, 1, &xform, NULL);
|
||||
}
|
||||
|
||||
CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
|
||||
CGPathRef cgPath = CTFontCreatePathForGlyph(mFont, cgGlyph, NULL);
|
||||
CGPathRef cgPath = CTFontCreatePathForGlyph(font, cgGlyph, NULL);
|
||||
|
||||
path->reset();
|
||||
if (cgPath != NULL) {
|
||||
CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
|
||||
CFRelease(cgPath);
|
||||
}
|
||||
|
||||
if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
|
||||
SkMatrix m;
|
||||
m.setScale(SkFloatToScalar(1 / scaleX), SkFloatToScalar(1 / scaleY));
|
||||
path->transform(m);
|
||||
// balance the call to CTFontCreateCopyWithAttributes
|
||||
CFRelease(font);
|
||||
}
|
||||
}
|
||||
|
||||
void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
|
||||
|
Loading…
Reference in New Issue
Block a user