Chromium Code Reviews| Index: src/ports/SkFontHost_mac.cpp |
| =================================================================== |
| --- src/ports/SkFontHost_mac.cpp (revision 9039) |
| +++ src/ports/SkFontHost_mac.cpp (working copy) |
| @@ -124,13 +124,6 @@ |
| return rect.size.width <= 0 || rect.size.height <= 0; |
| } |
| -static void CGRectInset_inline(CGRect* rect, CGFloat dx, CGFloat dy) { |
| - rect->origin.x += dx; |
| - rect->origin.y += dy; |
| - rect->size.width -= dx * 2; |
| - rect->size.height -= dy * 2; |
| -} |
| - |
| static CGFloat CGRectGetMinX_inline(const CGRect& rect) { |
| return rect.origin.x; |
| } |
| @@ -251,10 +244,6 @@ |
| return darwin_version; |
| } |
| -static bool isLeopard() { |
| - return darwinVersion() == 9; |
| -} |
| - |
| static bool isSnowLeopard() { |
| return darwinVersion() == 10; |
| } |
| @@ -300,11 +289,6 @@ |
| ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); |
| } |
| -static SkScalar getFontScale(CGFontRef cgFont) { |
| - int unitsPerEm = CGFontGetUnitsPerEm(cgFont); |
| - return SkScalarInvert(SkIntToScalar(unitsPerEm)); |
| -} |
| - |
| /////////////////////////////////////////////////////////////////////////////// |
| #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) |
| @@ -530,13 +514,7 @@ |
| CTFontDescriptorCreateWithAttributes(cfAttributes)); |
| if (ctFontDesc != NULL) { |
| - if (isLeopard()) { |
| - // CTFontCreateWithFontDescriptor on Leopard ignores the name |
| - AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithName(cfFontName, 1, NULL)); |
| - ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, ctFontDesc); |
| - } else { |
| - ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); |
| - } |
| + ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); |
| } |
| } |
| @@ -648,13 +626,9 @@ |
| return face; |
| } |
| -static void flip(SkMatrix* matrix) { |
| - matrix->setSkewX(-matrix->getSkewX()); |
| - matrix->setSkewY(-matrix->getSkewY()); |
| -} |
| - |
| /////////////////////////////////////////////////////////////////////////////// |
| +/** GlyphRect is in FUnits (em space, y up). */ |
| struct GlyphRect { |
| int16_t fMinX; |
| int16_t fMinY; |
| @@ -665,9 +639,8 @@ |
| class SkScalerContext_Mac : public SkScalerContext { |
| public: |
| SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*); |
| - virtual ~SkScalerContext_Mac(); |
| + virtual ~SkScalerContext_Mac() { }; |
|
caryclark
2013/05/14 20:08:09
can we remove the destructor altogether at this po
bungeman-skia
2013/05/14 22:30:21
Done.
|
| - |
| protected: |
| unsigned generateGlyphCount(void) SK_OVERRIDE; |
| uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; |
| @@ -679,25 +652,60 @@ |
| private: |
| static void CTPathElement(void *info, const CGPathElement *element); |
| + |
| + /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */ |
| + void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const; |
| + |
| + /** Initializes and returns the value of fFBoundingBoxesGlyphOffset. |
| + * |
| + * For use with (and must be called before) generateBBoxes. |
| + */ |
| uint16_t getFBoundingBoxesGlyphOffset(); |
| - void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const; |
| + |
| + /** Initializes fFBoundingBoxes and returns true on success. |
| + * |
| + * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to |
| + * return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is |
| + * less than its maxp::numGlyphs. When this is the case we try to read the bounds from the |
| + * font directly. |
| + * |
| + * This routine initializes fFBoundingBoxes to an array of |
| + * fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits |
| + * (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount). |
| + * |
| + * Returns true if fFBoundingBoxes is properly initialized. The table can only be properly |
| + * initialized for a TrueType font with 'head', 'loca', and 'glyf' tables. |
| + * |
| + * TODO: A future optimization will compute fFBoundingBoxes once per fCTFont. |
| + */ |
| bool generateBBoxes(); |
| - CGAffineTransform fTransform; |
| - SkMatrix fUnitMatrix; // without font size |
| - SkMatrix fVerticalMatrix; // unit rotated |
| - SkMatrix fMatrix; // with font size |
| - SkMatrix fFBoundingBoxesMatrix; // lion-specific fix |
| + /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down). |
| + * |
| + * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs. |
| + * Used on Lion to correct CTFontGetBoundingRectsForGlyphs. |
| + */ |
| + SkMatrix fFUnitMatrix; |
| + |
| Offscreen fOffscreen; |
| AutoCFRelease<CTFontRef> fCTFont; |
| - AutoCFRelease<CTFontRef> fCTVerticalFont; // for vertical advance |
| + |
| + /** Vertical variant of fCTFont. |
| + * |
| + * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise. |
| + * This makes kCTFontDefaultOrientation dangerous, because the metrics from |
| + * kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation. |
| + * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space. |
| + */ |
| + AutoCFRelease<CTFontRef> fCTVerticalFont; |
| + |
| AutoCFRelease<CGFontRef> fCGFont; |
| - GlyphRect* fFBoundingBoxes; |
| + SkAutoTMalloc<GlyphRect> fFBoundingBoxes; |
| uint16_t fFBoundingBoxesGlyphOffset; |
| uint16_t fGlyphCount; |
| bool fGeneratedFBoundingBoxes; |
| - bool fDoSubPosition; |
| - bool fVertical; |
| + const bool fDoSubPosition; |
| + const bool fVertical; |
| friend class Offscreen; |
| @@ -707,39 +715,21 @@ |
| SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, |
| const SkDescriptor* desc) |
| : INHERITED(typeface, desc) |
| - , fFBoundingBoxes(NULL) |
| + , fFBoundingBoxes() |
| , fFBoundingBoxesGlyphOffset(0) |
| , fGeneratedFBoundingBoxes(false) |
| + , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) |
| + , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) |
| + |
| { |
| CTFontRef ctFont = typeface->fFontRef.get(); |
| CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); |
| - |
| - // Get the state we need |
| - fRec.getSingleMatrix(&fMatrix); |
| - fUnitMatrix = fMatrix; |
| - |
| - // extract the font size out of the matrix, but leave the skewing for italic |
| - SkScalar reciprocal = SkScalarInvert(fRec.fTextSize); |
| - fUnitMatrix.preScale(reciprocal, reciprocal); |
| - |
| SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); |
| - |
| - fTransform = MatrixToCGAffineTransform(fMatrix); |
| - |
| - CGAffineTransform transform; |
| - CGFloat unitFontSize; |
| - if (isLeopard()) { |
| - // passing 1 for pointSize to Leopard sets the font size to 1 pt. |
| - // pass the CoreText size explicitly |
| - transform = MatrixToCGAffineTransform(fUnitMatrix); |
| - unitFontSize = SkScalarToFloat(fRec.fTextSize); |
| - } else { |
| - // since our matrix includes everything, we pass 1 for pointSize |
| - transform = fTransform; |
| - unitFontSize = 1; |
| - } |
| - flip(&fUnitMatrix); // flip to fix up bounds later |
| - fVertical = SkToBool(fRec.fFlags & kVertical_Flag); |
| + fGlyphCount = SkToU16(numGlyphs); |
| + |
| + fRec.getSingleMatrix(&fFUnitMatrix); |
| + CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix); |
| + |
| AutoCFRelease<CTFontDescriptorRef> ctFontDesc; |
| if (fVertical) { |
| AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable( |
| @@ -754,29 +744,18 @@ |
| ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); |
| } |
| } |
| - fCTFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform, ctFontDesc); |
| + // Since our matrix includes everything, we pass 1 for size. |
| + fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1.f, &transform, ctFontDesc); |
|
caryclark
2013/05/14 20:08:09
It looks like the rest of Skia mostly uses 1.f ins
bungeman-skia
2013/05/14 22:30:21
Done.
|
| fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); |
| if (fVertical) { |
| CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); |
| transform = CGAffineTransformConcat(rotateLeft, transform); |
| - fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform, NULL); |
| - fVerticalMatrix = fUnitMatrix; |
| - if (isSnowLeopard()) { |
| - SkScalar scale = SkScalarMul(fRec.fTextSize, getFontScale(fCGFont)); |
| - fVerticalMatrix.preScale(scale, scale); |
| - } else { |
| - fVerticalMatrix.preRotate(SkIntToScalar(90)); |
| - } |
| - fVerticalMatrix.postScale(SK_Scalar1, -SK_Scalar1); |
| + fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1.f, &transform, NULL); |
|
caryclark
2013/05/14 20:08:09
and here
bungeman-skia
2013/05/14 22:30:21
Done.
|
| } |
| - fGlyphCount = SkToU16(numGlyphs); |
| - fDoSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag); |
| + SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont))); |
| + fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); |
| } |
| -SkScalerContext_Mac::~SkScalerContext_Mac() { |
| - delete[] fFBoundingBoxes; |
| -} |
| - |
| CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, |
| CGGlyph glyphID, size_t* rowBytesPtr, |
| bool generateA8FromLCD) { |
| @@ -823,11 +802,14 @@ |
| CGContextSetTextDrawingMode(fCG, kCGTextFill); |
| CGContextSetFont(fCG, context.fCGFont); |
| - CGContextSetFontSize(fCG, 1); |
| - CGContextSetTextMatrix(fCG, context.fTransform); |
| + CGContextSetFontSize(fCG, 1.0f /*CTFontGetSize(context.fCTFont)*/); |
| + CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont)); |
| - CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition); |
| - CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition); |
| + // 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); |
| // Draw white on black to create mask. |
| // TODO: Draw black on white and invert, CG has a special case codepath. |
| @@ -860,12 +842,15 @@ |
| subX = SkFixedToFloat(glyph.getSubXFixed()); |
| subY = SkFixedToFloat(glyph.getSubYFixed()); |
| } |
| + |
| + // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin. |
| if (context.fVertical) { |
| - SkIPoint offset; |
| + SkPoint offset; |
| context.getVerticalOffset(glyphID, &offset); |
| subX += offset.fX; |
| subY += offset.fY; |
| } |
| + |
| CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, |
| glyph.fTop + glyph.fHeight - subY, |
| &glyphID, 1); |
| @@ -875,22 +860,22 @@ |
| return image; |
| } |
| -void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const { |
| - CGSize vertOffset; |
| - CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffset, 1); |
| - const SkPoint trans = {CGToScalar(vertOffset.width), |
| - CGToScalar(vertOffset.height)}; |
| - SkPoint floatOffset; |
| - fVerticalMatrix.mapPoints(&floatOffset, &trans, 1); |
| - if (!isSnowLeopard()) { |
| - // SnowLeopard fails to apply the font's matrix to the vertical metrics, |
| - // but Lion and Leopard do. The unit matrix describes the font's matrix at |
| - // point size 1. There may be some way to avoid mapping here by setting up |
| - // fVerticalMatrix differently, but this works for now. |
| - fUnitMatrix.mapPoints(&floatOffset, 1); |
| +void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const { |
| + // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up). |
| + // Lion and Leopard return cgVertOffset in CG units (pixels, y up). |
| + CGSize cgVertOffset; |
| + CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1); |
| + |
| + SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) }; |
| + if (isSnowLeopard()) { |
| + // From FUnits (em space, y up) to SkGlyph units (pixels, y down). |
| + fFUnitMatrix.mapPoints(&skVertOffset, 1); |
| + } else { |
| + // From CG units (pixels, y up) to SkGlyph units (pixels, y down). |
| + skVertOffset.fY = -skVertOffset.fY; |
| } |
| - offset->fX = SkScalarRound(floatOffset.fX); |
| - offset->fY = SkScalarRound(floatOffset.fY); |
| + |
| + *offset = skVertOffset; |
| } |
| uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { |
| @@ -905,20 +890,9 @@ |
| return fFBoundingBoxesGlyphOffset; |
| } |
| -/* |
| - * Lion has a bug in CTFontGetBoundingRectsForGlyphs which returns a bad value |
| - * in theBounds.origin.x for fonts whose numOfLogHorMetrics is less than its |
| - * glyph count. This workaround reads the glyph bounds from the font directly. |
| - * |
| - * The table is computed only if the font is a TrueType font, if the glyph |
| - * value is >= fFBoundingBoxesGlyphOffset. (called only if fFBoundingBoxesGlyphOffset < fGlyphCount). |
| - * |
| - * TODO: A future optimization will compute fFBoundingBoxes once per CGFont, and |
| - * compute fFBoundingBoxesMatrix once per font context. |
| - */ |
| bool SkScalerContext_Mac::generateBBoxes() { |
| if (fGeneratedFBoundingBoxes) { |
| - return NULL != fFBoundingBoxes; |
| + return NULL != fFBoundingBoxes.get(); |
| } |
| fGeneratedFBoundingBoxes = true; |
| @@ -938,7 +912,7 @@ |
| } |
| uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; |
| - fFBoundingBoxes = new GlyphRect[entries]; |
| + fFBoundingBoxes.reset(entries); |
| SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; |
| SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat); |
| @@ -951,10 +925,6 @@ |
| rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); |
| rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); |
| } |
| - fFBoundingBoxesMatrix = fMatrix; |
| - flip(&fFBoundingBoxesMatrix); |
| - SkScalar fontScale = getFontScale(fCGFont); |
| - fFBoundingBoxesMatrix.preScale(fontScale, fontScale); |
| return true; |
| } |
| @@ -985,105 +955,111 @@ |
| } |
| void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { |
| - CGSize advance; |
| - CGRect bounds; |
| - CGGlyph cgGlyph; |
| - |
| - // Get the state we need |
| - cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); |
| - |
| + const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); |
| + glyph->zeroMetrics(); |
| + |
| + // The following block produces cgAdvance in CG units (pixels, y up). |
| + CGSize cgAdvance; |
| if (fVertical) { |
| - if (!isSnowLeopard()) { |
| - // Lion and Leopard respect the vertical font metrics. |
| - CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, |
| - &cgGlyph, &bounds, 1); |
| - } else { |
| - // Snow Leopard and earlier respect the vertical font metrics for |
| - // advances, but not bounds, so use the default box and adjust it below. |
| - CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, |
| - &cgGlyph, &bounds, 1); |
| - } |
| CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, |
| - &cgGlyph, &advance, 1); |
| + &cgGlyph, &cgAdvance, 1); |
| } else { |
| - CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, |
| - &cgGlyph, &bounds, 1); |
| - CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation, |
| - &cgGlyph, &advance, 1); |
| + CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation, |
| + &cgGlyph, &cgAdvance, 1); |
| } |
| + glyph->fAdvanceX = SkFloatToFixed_Check(cgAdvance.width); |
| + glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height); |
| - // BUG? |
| - // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when |
| - // it should be empty. So, if we see a zero-advance, we check if it has an |
| - // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance |
| - // is rare, so we won't incur a big performance cost for this extra check. |
| - if (0 == advance.width && 0 == advance.height) { |
| - AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL)); |
| - if (NULL == path || CGPathIsEmpty(path)) { |
| - bounds = CGRectMake(0, 0, 0, 0); |
| + // The following produces skBounds in SkGlyph units (pixels, y down), |
| + // or returns early if skBounds would be empty. |
| + SkRect skBounds; |
| + |
| + // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and |
| + // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts. |
| + // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get |
| + // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph |
| + // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that |
| + // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries |
| + // to center the glyph along the vertical baseline and also perform some mysterious shift |
| + // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform |
| + // these steps. |
| + // |
| + // It is not known which is correct (or if either is correct). However, we must always draw |
| + // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw. |
| + // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs. |
| + |
| + // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and |
| + // returns horizontal bounds. |
| + |
| + // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to |
| + // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is |
| + // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the |
| + // font directly. |
| + if ((isLion() || isMountainLion()) && |
| + (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes())) |
| + { |
| + const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset]; |
| + if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) { |
| + return; |
| } |
| - } |
| + skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); |
| + // From FUnits (em space, y up) to SkGlyph units (pixels, y down). |
| + fFUnitMatrix.mapRect(&skBounds); |
| - glyph->zeroMetrics(); |
| - glyph->fAdvanceX = SkFloatToFixed_Check(advance.width); |
| - glyph->fAdvanceY = -SkFloatToFixed_Check(advance.height); |
| + } else { |
| + // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up). |
| + CGRect cgBounds; |
| + CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation, |
| + &cgGlyph, &cgBounds, 1); |
| + |
| + // BUG? |
| + // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when |
| + // it should be empty. So, if we see a zero-advance, we check if it has an |
| + // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance |
| + // is rare, so we won't incur a big performance cost for this extra check. |
| + if (0 == cgAdvance.width && 0 == cgAdvance.height) { |
| + AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL)); |
| + if (NULL == path || CGPathIsEmpty(path)) { |
| + return; |
| + } |
| + } |
| - if (CGRectIsEmpty_inline(bounds)) { |
| - return; |
| - } |
| + if (CGRectIsEmpty_inline(cgBounds)) { |
| + return; |
| + } |
| - if (isLeopard() && !fVertical) { |
| - // Leopard does not consider the matrix skew in its bounds. |
| - // Run the bounding rectangle through the skew matrix to determine |
| - // the true bounds. However, this doesn't work if the font is vertical. |
| - // FIXME (Leopard): If the font has synthetic italic (e.g., matrix skew) |
| - // and the font is vertical, the bounds need to be recomputed. |
| - SkRect glyphBounds = SkRect::MakeXYWH( |
| - bounds.origin.x, bounds.origin.y, |
| - bounds.size.width, bounds.size.height); |
| - fUnitMatrix.mapRect(&glyphBounds); |
| - bounds.origin.x = glyphBounds.fLeft; |
| - bounds.origin.y = glyphBounds.fTop; |
| - bounds.size.width = glyphBounds.width(); |
| - bounds.size.height = glyphBounds.height(); |
| + // Convert cgBounds to SkGlyph units (pixels, y down). |
| + skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height, |
| + cgBounds.size.width, cgBounds.size.height); |
| } |
| - // Adjust the bounds |
| - // |
| - // CTFontGetBoundingRectsForGlyphs ignores the font transform, so we need |
| - // to transform the bounding box ourselves. |
| - // |
| - // The bounds are also expanded by 1 pixel, to give CG room for anti-aliasing. |
| - CGRectInset_inline(&bounds, -1, -1); |
| - // Get the metrics |
| - bool lionAdjustedMetrics = false; |
| - if (isLion() || isMountainLion()) { |
| - if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()){ |
| - lionAdjustedMetrics = true; |
| - SkRect adjust; |
| - const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset]; |
| - adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); |
| - fFBoundingBoxesMatrix.mapRect(&adjust); |
| - bounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1; |
| - bounds.origin.y = SkScalarToFloat(adjust.fTop) - 1; |
| - } |
| - // Lion returns fractions in the bounds |
| - glyph->fWidth = SkToU16(sk_float_ceil2int(bounds.size.width)); |
| - glyph->fHeight = SkToU16(sk_float_ceil2int(bounds.size.height)); |
| - } else { |
| - glyph->fWidth = SkToU16(sk_float_round2int(bounds.size.width)); |
| - glyph->fHeight = SkToU16(sk_float_round2int(bounds.size.height)); |
| - } |
| - glyph->fTop = SkToS16(-sk_float_round2int(CGRectGetMaxY_inline(bounds))); |
| - glyph->fLeft = SkToS16(sk_float_round2int(CGRectGetMinX_inline(bounds))); |
| - SkIPoint offset; |
| - if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) { |
| - // SnowLeopard doesn't respect vertical metrics, so compute them manually. |
| - // Also compute them for Lion when the metrics were computed by hand. |
| + if (fVertical) { |
| + // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds. |
| + // Convert these horizontal bounds into vertical bounds. |
| + SkPoint offset; |
| getVerticalOffset(cgGlyph, &offset); |
| - glyph->fLeft += offset.fX; |
| - glyph->fTop += offset.fY; |
| + skBounds.offset(offset); |
| } |
| + |
| + // Currently the bounds are based on being rendered at (0,0). |
| + // The top left must not move, since that is the base from which subpixel positioning is offset. |
| + if (fDoSubPosition) { |
| + skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed()); |
| + skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed()); |
| + } |
| + |
| + SkIRect skIBounds; |
| + skBounds.roundOut(&skIBounds); |
| + // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. |
| + // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset |
| + // is not currently known, as CG dilates the outlines by some percentage. |
| + // Note that if this context is A8 and not back-forming from LCD, there is no need to outset. |
| + skIBounds.outset(1, 1); |
| + glyph->fLeft = SkToS16(skIBounds.fLeft); |
| + glyph->fTop = SkToS16(skIBounds.fTop); |
| + glyph->fWidth = SkToU16(skIBounds.width()); |
| + glyph->fHeight = SkToU16(skIBounds.height()); |
| + |
| #ifdef HACK_COLORGLYPHS |
| glyph->fMaskFormat = SkMask::kARGB32_Format; |
| #endif |
| @@ -1371,17 +1347,17 @@ |
| CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement); |
| } |
| - if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { |
| + if (fDoSubPosition) { |
| SkMatrix m; |
| m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); |
| path->transform(m); |
| // balance the call to CTFontCreateCopyWithAttributes |
| CFSafeRelease(font); |
| } |
| - if (fRec.fFlags & SkScalerContext::kVertical_Flag) { |
| - SkIPoint offset; |
| + if (fVertical) { |
| + SkPoint offset; |
| getVerticalOffset(cgGlyph, &offset); |
| - path->offset(SkIntToScalar(offset.fX), SkIntToScalar(offset.fY)); |
| + path->offset(offset.fX, offset.fY); |
| } |
| } |