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