Index: src/core/SkPaint.cpp |
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp |
index 9b6b88386339d24a41d3c2f2bd5a3db4115c0dc5..e781cd45a7893c209336ea49c6beb45c3c831267 100644 |
--- a/src/core/SkPaint.cpp |
+++ b/src/core/SkPaint.cpp |
@@ -30,6 +30,7 @@ |
#include "SkStroke.h" |
#include "SkTextFormatParams.h" |
#include "SkTextToPathIter.h" |
+#include "SkTLazy.h" |
#include "SkTypeface.h" |
#include "SkXfermode.h" |
@@ -425,6 +426,37 @@ SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) { |
/////////////////////////////////////////////////////////////////////////////// |
+static SkScalar mag2(SkScalar x, SkScalar y) { |
+ return x * x + y * y; |
+} |
+ |
+static bool tooBig(const SkMatrix& m, SkScalar ma2max) { |
+ return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max |
+ || |
+ mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max; |
+} |
+ |
+bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM) { |
+ SkASSERT(!ctm.hasPerspective()); |
+ SkASSERT(!textM.hasPerspective()); |
+ |
+ SkMatrix matrix; |
+ matrix.setConcat(ctm, textM); |
+ return tooBig(matrix, MaxCacheSize2()); |
+} |
+ |
+bool SkPaint::tooBigToUseCache(const SkMatrix& ctm) const { |
+ SkMatrix textM; |
+ return TooBigToUseCache(ctm, *this->setTextMatrix(&textM)); |
+} |
+ |
+bool SkPaint::tooBigToUseCache() const { |
+ SkMatrix textM; |
+ return tooBig(*this->setTextMatrix(&textM), MaxCacheSize2()); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
#include "SkGlyphCache.h" |
#include "SkUtils.h" |
@@ -915,33 +947,51 @@ SkDrawCacheProc SkPaint::getDrawCacheProc() const { |
/////////////////////////////////////////////////////////////////////////////// |
-class SkAutoRestorePaintTextSizeAndFrame { |
+#define TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE ( \ |
+SkPaint::kDevKernText_Flag | \ |
+SkPaint::kLinearText_Flag | \ |
+SkPaint::kLCDRenderText_Flag | \ |
+SkPaint::kEmbeddedBitmapText_Flag | \ |
+SkPaint::kAutoHinting_Flag | \ |
+SkPaint::kGenA8FromLCD_Flag ) |
+ |
+SkScalar SkPaint::setupForAsPaths() { |
+ uint32_t flags = this->getFlags(); |
+ // clear the flags we don't care about |
+ flags &= ~TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE; |
+ // set the flags we do care about |
+ flags |= SkPaint::kSubpixelText_Flag; |
+ |
+ this->setFlags(flags); |
+ this->setHinting(SkPaint::kNo_Hinting); |
+ |
+ SkScalar textSize = fTextSize; |
+ this->setTextSize(kCanonicalTextSizeForPaths); |
+ return textSize / kCanonicalTextSizeForPaths; |
+} |
+ |
+class SkCanonicalizePaint { |
public: |
- SkAutoRestorePaintTextSizeAndFrame(const SkPaint* paint) |
- : fPaint((SkPaint*)paint) { |
-#ifdef SK_BUILD_FOR_ANDROID |
- fGenerationID = fPaint->getGenerationID(); |
-#endif |
- fTextSize = paint->getTextSize(); |
- fStyle = paint->getStyle(); |
- fPaint->setStyle(SkPaint::kFill_Style); |
+ SkCanonicalizePaint(const SkPaint& paint) : fPaint(&paint), fScale(0) { |
+ if (paint.isLinearText() || paint.tooBigToUseCache()) { |
+ SkPaint* p = fLazy.set(paint); |
+ fScale = p->setupForAsPaths(); |
+ fPaint = p; |
+ } |
} |
- ~SkAutoRestorePaintTextSizeAndFrame() { |
- fPaint->setStyle(fStyle); |
- fPaint->setTextSize(fTextSize); |
-#ifdef SK_BUILD_FOR_ANDROID |
- fPaint->setGenerationID(fGenerationID); |
-#endif |
- } |
+ const SkPaint& getPaint() const { return *fPaint; } |
+ |
+ /** |
+ * Returns 0 if the paint was unmodified, or the scale factor need to |
+ * the original textSize |
+ */ |
+ SkScalar getScale() const { return fScale; } |
private: |
- SkPaint* fPaint; |
- SkScalar fTextSize; |
- SkPaint::Style fStyle; |
-#ifdef SK_BUILD_FOR_ANDROID |
- uint32_t fGenerationID; |
-#endif |
+ const SkPaint* fPaint; |
+ SkScalar fScale; |
+ SkTLazy<SkPaint> fLazy; |
}; |
static void set_bounds(const SkGlyph& g, SkRect* bounds) { |
@@ -1069,14 +1119,9 @@ SkScalar SkPaint::measureText(const void* textData, size_t length, |
const char* text = (const char*)textData; |
SkASSERT(text != NULL || length == 0); |
- SkScalar scale = 0; |
- SkAutoRestorePaintTextSizeAndFrame restore(this); |
- |
- if (this->isLinearText()) { |
- scale = fTextSize / kCanonicalTextSizeForPaths; |
- // this gets restored by restore |
- ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); |
- } |
+ SkCanonicalizePaint canon(*this); |
+ const SkPaint& paint = canon.getPaint(); |
+ SkScalar scale = canon.getScale(); |
SkMatrix zoomMatrix, *zoomPtr = NULL; |
if (zoom) { |
@@ -1084,7 +1129,7 @@ SkScalar SkPaint::measureText(const void* textData, size_t length, |
zoomPtr = &zoomMatrix; |
} |
- SkAutoGlyphCache autoCache(*this, NULL, zoomPtr); |
+ SkAutoGlyphCache autoCache(paint, NULL, zoomPtr); |
SkGlyphCache* cache = autoCache.getCache(); |
SkScalar width = 0; |
@@ -1092,7 +1137,7 @@ SkScalar SkPaint::measureText(const void* textData, size_t length, |
if (length > 0) { |
int tempCount; |
- width = this->measure_text(cache, text, length, &tempCount, bounds); |
+ width = paint.measure_text(cache, text, length, &tempCount, bounds); |
if (scale) { |
width = SkScalarMul(width, scale); |
if (bounds) { |
@@ -1153,23 +1198,22 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, |
SkASSERT(textD != NULL); |
const char* text = (const char*)textD; |
- SkScalar scale = 0; |
- SkAutoRestorePaintTextSizeAndFrame restore(this); |
+ SkCanonicalizePaint canon(*this); |
+ const SkPaint& paint = canon.getPaint(); |
+ SkScalar scale = canon.getScale(); |
- if (this->isLinearText()) { |
- scale = fTextSize / kCanonicalTextSizeForPaths; |
- maxWidth = SkScalarMulDiv(maxWidth, kCanonicalTextSizeForPaths, fTextSize); |
- // this gets restored by restore |
- ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); |
+ // adjust max in case we changed the textSize in paint |
+ if (scale) { |
+ maxWidth /= scale; |
} |
- SkAutoGlyphCache autoCache(*this, NULL, NULL); |
+ SkAutoGlyphCache autoCache(paint, NULL, NULL); |
SkGlyphCache* cache = autoCache.getCache(); |
- SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false); |
+ SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc(tbd, false); |
const char* stop; |
SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop); |
- const int xyIndex = this->isVerticalText() ? 1 : 0; |
+ const int xyIndex = paint.isVerticalText() ? 1 : 0; |
// use 64bits for our accumulator, to avoid overflowing 16.16 |
Sk48Dot16 max = SkScalarToFixed(maxWidth); |
Sk48Dot16 width = 0; |
@@ -1227,15 +1271,10 @@ static void FontMetricsDescProc(SkTypeface* typeface, const SkDescriptor* desc, |
} |
SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const { |
- SkScalar scale = 0; |
- SkAutoRestorePaintTextSizeAndFrame restore(this); |
- |
- if (this->isLinearText()) { |
- scale = fTextSize / kCanonicalTextSizeForPaths; |
- // this gets restored by restore |
- ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); |
- } |
- |
+ SkCanonicalizePaint canon(*this); |
+ const SkPaint& paint = canon.getPaint(); |
+ SkScalar scale = canon.getScale(); |
+ |
SkMatrix zoomMatrix, *zoomPtr = NULL; |
if (zoom) { |
zoomMatrix.setScale(zoom, zoom); |
@@ -1247,7 +1286,7 @@ SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const { |
metrics = &storage; |
} |
- this->descriptorProc(NULL, zoomPtr, FontMetricsDescProc, metrics, true); |
+ paint.descriptorProc(NULL, zoomPtr, FontMetricsDescProc, metrics, true); |
if (scale) { |
metrics->fTop = SkScalarMul(metrics->fTop, scale); |
@@ -1284,25 +1323,20 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, |
return this->countText(textData, byteLength); |
} |
- SkAutoRestorePaintTextSizeAndFrame restore(this); |
- SkScalar scale = 0; |
- |
- if (this->isLinearText()) { |
- scale = fTextSize / kCanonicalTextSizeForPaths; |
- // this gets restored by restore |
- ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); |
- } |
+ SkCanonicalizePaint canon(*this); |
+ const SkPaint& paint = canon.getPaint(); |
+ SkScalar scale = canon.getScale(); |
- SkAutoGlyphCache autoCache(*this, NULL, NULL); |
+ SkAutoGlyphCache autoCache(paint, NULL, NULL); |
SkGlyphCache* cache = autoCache.getCache(); |
SkMeasureCacheProc glyphCacheProc; |
- glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, |
+ glyphCacheProc = paint.getMeasureCacheProc(kForward_TextBufferDirection, |
NULL != bounds); |
const char* text = (const char*)textData; |
const char* stop = text + byteLength; |
int count = 0; |
- const int xyIndex = this->isVerticalText() ? 1 : 0; |
+ const int xyIndex = paint.isVerticalText() ? 1 : 0; |
if (this->isDevKernText()) { |
// we adjust the widths returned here through auto-kerning |