Index: src/gpu/GrAtlasTextBlob.cpp |
diff --git a/src/gpu/GrAtlasTextBlob.cpp b/src/gpu/GrAtlasTextBlob.cpp |
index 0f7368a9245d86a088c4f586ad784f9a771c526a..1cd25e74de33e1c8d2904aca466c933f55950204 100644 |
--- a/src/gpu/GrAtlasTextBlob.cpp |
+++ b/src/gpu/GrAtlasTextBlob.cpp |
@@ -86,6 +86,105 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, |
subRun->glyphAppended(); |
} |
+bool GrAtlasTextBlob::mustRegenerate(SkScalar* outTransX, SkScalar* outTransY, |
+ const SkPaint& paint, |
+ GrColor color, const SkMaskFilter::BlurRec& blurRec, |
+ const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { |
+ // If we have LCD text then our canonical color will be set to transparent, in this case we have |
+ // to regenerate the blob on any color change |
+ // We use the grPaint to get any color filter effects |
+ if (fKey.fCanonicalColor == SK_ColorTRANSPARENT && |
+ fPaintColor != color) { |
+ return true; |
+ } |
+ |
+ if (fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { |
+ return true; |
+ } |
+ |
+ if (fViewMatrix.hasPerspective() && !fViewMatrix.cheapEqualTo(viewMatrix)) { |
+ return true; |
+ } |
+ |
+ // We only cache one masked version |
+ if (fKey.fHasBlur && |
+ (fBlurRec.fSigma != blurRec.fSigma || |
+ fBlurRec.fStyle != blurRec.fStyle || |
+ fBlurRec.fQuality != blurRec.fQuality)) { |
+ return true; |
+ } |
+ |
+ // Similarly, we only cache one version for each style |
+ if (fKey.fStyle != SkPaint::kFill_Style && |
+ (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || |
+ fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || |
+ fStrokeInfo.fJoin != paint.getStrokeJoin())) { |
+ return true; |
+ } |
+ |
+ // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls |
+ // for mixed blobs if this becomes an issue. |
+ if (this->hasBitmap() && this->hasDistanceField()) { |
+ // Identical viewmatrices and we can reuse in all cases |
+ if (fViewMatrix.cheapEqualTo(viewMatrix) && x == fX && y == fY) { |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ if (this->hasBitmap()) { |
+ if (fViewMatrix.getScaleX() != viewMatrix.getScaleX() || |
+ fViewMatrix.getScaleY() != viewMatrix.getScaleY() || |
+ fViewMatrix.getSkewX() != viewMatrix.getSkewX() || |
+ fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { |
+ return true; |
+ } |
+ |
+ // We can update the positions in the cachedtextblobs without regenerating the whole blob, |
+ // but only for integer translations. |
+ // This cool bit of math will determine the necessary translation to apply to the already |
+ // generated vertex coordinates to move them to the correct position |
+ SkScalar transX = viewMatrix.getTranslateX() + |
+ viewMatrix.getScaleX() * (x - fX) + |
+ viewMatrix.getSkewX() * (y - fY) - |
+ fViewMatrix.getTranslateX(); |
+ SkScalar transY = viewMatrix.getTranslateY() + |
+ viewMatrix.getSkewY() * (x - fX) + |
+ viewMatrix.getScaleY() * (y - fY) - |
+ fViewMatrix.getTranslateY(); |
+ if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY) ) { |
+ return true; |
+ } |
+ |
+ (*outTransX) = transX; |
+ (*outTransY) = transY; |
+ } else if (this->hasDistanceField()) { |
+ // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different |
+ // distance field being generated, so we have to regenerate in those cases |
+ SkScalar newMaxScale = viewMatrix.getMaxScale(); |
+ SkScalar oldMaxScale = fViewMatrix.getMaxScale(); |
+ SkScalar scaleAdjust = newMaxScale / oldMaxScale; |
+ if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) { |
+ return true; |
+ } |
+ |
+ (*outTransX) = x - fX; |
+ (*outTransY) = y - fY; |
+ } |
+ |
+ |
+ // If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y |
+ // offsets. Note, we offset the vertex bounds right before flushing |
+ fViewMatrix = viewMatrix; |
+ fX = x; |
+ fY = y; |
+ |
+ // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case |
+ // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate |
+ // the blob anyways at flush time, so no need to regenerate explicitly |
+ return false; |
+} |
+ |
// TODO get this code building again |
#ifdef CACHE_SANITY_CHECK |
void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) { |