Move 'mustRegenerate' function into GrAtlasTextBlob

BUG=skia:

Review URL: https://codereview.chromium.org/1515543003
This commit is contained in:
joshualitt 2015-12-10 07:44:50 -08:00 committed by Commit bot
parent 067e90e72f
commit fd5f6c1b0d
4 changed files with 105 additions and 104 deletions

View File

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

View File

@ -300,6 +300,10 @@ struct GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> {
}
}
bool mustRegenerate(SkScalar* outTransX, SkScalar* outTransY, const SkPaint& paint,
GrColor color, const SkMaskFilter::BlurRec& blurRec,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
// position + local coord
static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);

View File

@ -188,99 +188,6 @@ bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) {
return false;
}
bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY,
const GrAtlasTextBlob& blob, 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 (blob.fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
blob.fPaintColor != color) {
return true;
}
if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) {
return true;
}
if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(viewMatrix)) {
return true;
}
// We only cache one masked version
if (blob.fKey.fHasBlur &&
(blob.fBlurRec.fSigma != blurRec.fSigma ||
blob.fBlurRec.fStyle != blurRec.fStyle ||
blob.fBlurRec.fQuality != blurRec.fQuality)) {
return true;
}
// Similarly, we only cache one version for each style
if (blob.fKey.fStyle != SkPaint::kFill_Style &&
(blob.fStrokeInfo.fFrameWidth != paint.getStrokeWidth() ||
blob.fStrokeInfo.fMiterLimit != paint.getStrokeMiter() ||
blob.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 (blob.hasBitmap() && blob.hasDistanceField()) {
// Identical viewmatrices and we can reuse in all cases
if (blob.fViewMatrix.cheapEqualTo(viewMatrix) && x == blob.fX && y == blob.fY) {
return false;
}
return true;
}
if (blob.hasBitmap()) {
if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() ||
blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() ||
blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() ||
blob.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 - blob.fX) +
viewMatrix.getSkewX() * (y - blob.fY) -
blob.fViewMatrix.getTranslateX();
SkScalar transY = viewMatrix.getTranslateY() +
viewMatrix.getSkewY() * (x - blob.fX) +
viewMatrix.getScaleY() * (y - blob.fY) -
blob.fViewMatrix.getTranslateY();
if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY) ) {
return true;
}
(*outTransX) = transX;
(*outTransY) = transY;
} else if (blob.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 = blob.fViewMatrix.getMaxScale();
SkScalar scaleAdjust = newMaxScale / oldMaxScale;
if (scaleAdjust < blob.fMaxMinScale || scaleAdjust > blob.fMinMaxScale) {
return true;
}
(*outTransX) = x - blob.fX;
(*outTransY) = y - blob.fY;
}
// 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;
}
inline SkGlyphCache* GrAtlasTextContext::setupCache(GrAtlasTextBlob::Run* run,
const SkPaint& skPaint,
const SkMatrix* viewMatrix,
@ -342,8 +249,8 @@ void GrAtlasTextContext::drawTextBlob(GrDrawContext* dc,
}
if (cacheBlob) {
if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, grPaint.getColor(), blurRec,
viewMatrix, x, y)) {
if (cacheBlob->mustRegenerate(&transX, &transY, skPaint, grPaint.getColor(), blurRec,
viewMatrix, x, y)) {
// We have to remake the blob because changes may invalidate our masks.
// TODO we could probably get away reuse most of the time if the pointer is unique,
// but we'd have to clear the subrun information
@ -353,11 +260,6 @@ void GrAtlasTextContext::drawTextBlob(GrDrawContext* dc,
this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix,
blob, x, y, drawFilter, clip);
} else {
// 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
cacheBlob->fViewMatrix = viewMatrix;
cacheBlob->fX = x;
cacheBlob->fY = y;
fCache->makeMRU(cacheBlob);
#ifdef CACHE_SANITY_CHECK
{

View File

@ -128,10 +128,6 @@ private:
// sets up the descriptor on the blob and returns a detached cache. Client must attach
inline static GrColor ComputeCanonicalColor(const SkPaint&, bool lcd);
inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix* viewMatrix, bool noGamma);
static inline bool MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTransY,
const GrAtlasTextBlob&, const SkPaint&, GrColor,
const SkMaskFilter::BlurRec&,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
void regenerateTextBlob(GrAtlasTextBlob* bmp, const SkPaint& skPaint, GrColor,
const SkMatrix& viewMatrix,
const SkTextBlob* blob, SkScalar x, SkScalar y,