diff options
author | alokp@chromium.org <alokp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-08 22:45:18 +0000 |
---|---|---|
committer | alokp@chromium.org <alokp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-08 22:45:18 +0000 |
commit | 58838bf7106c6f2a0c75af275e7b60bd1faea3d6 (patch) | |
tree | 1fc2954fb35830073ffcee016d50d3d22fe29624 | |
parent | 1389a03f1ac25bf7e80fb88cdbff5e48abd875a1 (diff) | |
download | chromium_src-58838bf7106c6f2a0c75af275e7b60bd1faea3d6.zip chromium_src-58838bf7106c6f2a0c75af275e7b60bd1faea3d6.tar.gz chromium_src-58838bf7106c6f2a0c75af275e7b60bd1faea3d6.tar.bz2 |
Smart layer invalidation for LCD text.
When LCD text needs to be disabled for a layer, we can invalidate just the tiles containing text.
This only works with impl-side painting where it is very cheap to mark tiles that have text.
BUG=181245
Review URL: https://chromiumcodereview.appspot.com/13726013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@192936 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/layers/picture_layer_impl.cc | 5 | ||||
-rw-r--r-- | cc/resources/picture_layer_tiling.cc | 13 | ||||
-rw-r--r-- | cc/resources/picture_layer_tiling.h | 1 | ||||
-rw-r--r-- | cc/resources/picture_layer_tiling_set.cc | 5 | ||||
-rw-r--r-- | cc/resources/picture_layer_tiling_set.h | 1 | ||||
-rw-r--r-- | cc/resources/picture_pile_impl.cc | 2 | ||||
-rw-r--r-- | cc/resources/picture_pile_impl.h | 1 | ||||
-rw-r--r-- | cc/resources/tile.h | 3 | ||||
-rw-r--r-- | skia/ext/analysis_canvas.cc | 19 | ||||
-rw-r--r-- | skia/ext/analysis_canvas.h | 3 | ||||
-rw-r--r-- | skia/ext/analysis_canvas_unittest.cc | 125 |
11 files changed, 172 insertions, 6 deletions
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index a2c951c..728c8f7 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc @@ -854,10 +854,7 @@ void PictureLayerImpl::UpdateLCDTextStatus() { pending_layer->is_using_lcd_text_ = is_using_lcd_text_; pending_layer->pile_ = PicturePileImpl::CreateFromOther(pending_layer->pile_, is_using_lcd_text_); - - // TODO(enne): if we tracked text regions, we could just invalidate those - // directly rather than tossing away every tile. - pending_layer->tilings_->Invalidate(gfx::Rect(bounds())); + pending_layer->tilings_->InvalidateTilesWithText(); } void PictureLayerImpl::ResetRasterScale() { diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc index c3a2ffe..62350fc 100644 --- a/cc/resources/picture_layer_tiling.cc +++ b/cc/resources/picture_layer_tiling.cc @@ -156,6 +156,19 @@ void PictureLayerTiling::Invalidate(const Region& layer_invalidation) { CreateTile(new_tiles[i].first, new_tiles[i].second); } +void PictureLayerTiling::InvalidateTilesWithText() { + std::vector<TileMapKey> new_tiles; + for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { + if (it->second->has_text()) + new_tiles.push_back(it->first); + } + + for (size_t i = 0; i < new_tiles.size(); ++i) { + tiles_.erase(new_tiles[i]); + CreateTile(new_tiles[i].first, new_tiles[i].second); + } +} + void PictureLayerTiling::CreateTilesFromLayerRect(gfx::Rect layer_rect) { gfx::Rect content_rect = gfx::ToEnclosingRect(ScaleRect(layer_rect, contents_scale_)); diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h index 67e757a..5a83e40 100644 --- a/cc/resources/picture_layer_tiling.h +++ b/cc/resources/picture_layer_tiling.h @@ -50,6 +50,7 @@ class CC_EXPORT PictureLayerTiling { gfx::Size layer_bounds() const { return layer_bounds_; } void SetLayerBounds(gfx::Size layer_bounds); void Invalidate(const Region& layer_invalidation); + void InvalidateTilesWithText(); // Add any tiles that intersect with |layer_rect|. If any tiles already // exist, then this leaves them as-is. diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc index b5460b9..1b26e56 100644 --- a/cc/resources/picture_layer_tiling_set.cc +++ b/cc/resources/picture_layer_tiling_set.cc @@ -81,6 +81,11 @@ void PictureLayerTilingSet::Invalidate(const Region& layer_invalidation) { tilings_[i]->Invalidate(layer_invalidation); } +void PictureLayerTilingSet::InvalidateTilesWithText() { + for (size_t i = 0; i < tilings_.size(); ++i) + tilings_[i]->InvalidateTilesWithText(); +} + PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) { tilings_.push_back(PictureLayerTiling::Create(contents_scale)); PictureLayerTiling* appended = tilings_.back(); diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h index c9d32de..f88d1ef1 100644 --- a/cc/resources/picture_layer_tiling_set.h +++ b/cc/resources/picture_layer_tiling_set.h @@ -30,6 +30,7 @@ class CC_EXPORT PictureLayerTilingSet { gfx::Size LayerBounds() const; void Invalidate(const Region& layer_invalidation); + void InvalidateTilesWithText(); PictureLayerTiling* AddTiling(float contents_scale); size_t num_tilings() const { return tilings_.size(); } diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc index 6e71cad..397d64c 100644 --- a/cc/resources/picture_pile_impl.cc +++ b/cc/resources/picture_pile_impl.cc @@ -262,12 +262,14 @@ void PicturePileImpl::AnalyzeInRect(const gfx::Rect& content_rect, analysis->is_transparent = canvas.isTransparent(); analysis->is_solid_color = canvas.getColorIfSolid(&analysis->solid_color); analysis->is_cheap_to_raster = canvas.isCheap(); + analysis->has_text = canvas.hasText(); canvas.consumeLazyPixelRefs(&analysis->lazy_pixel_refs); } PicturePileImpl::Analysis::Analysis() : is_solid_color(false), is_transparent(false), + has_text(false), is_cheap_to_raster(false) { } diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h index 34364bd..9b49ed9 100644 --- a/cc/resources/picture_pile_impl.h +++ b/cc/resources/picture_pile_impl.h @@ -50,6 +50,7 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { bool is_solid_color; bool is_transparent; + bool has_text; bool is_cheap_to_raster; SkColor solid_color; diff --git a/cc/resources/tile.h b/cc/resources/tile.h index d519851..608aef7 100644 --- a/cc/resources/tile.h +++ b/cc/resources/tile.h @@ -55,6 +55,9 @@ class CC_EXPORT Tile : public base::RefCounted<Tile> { } const gfx::Rect& opaque_rect() const { return opaque_rect_; } + bool has_text() const { + return managed_state_.picture_pile_analysis.has_text; + } float contents_scale() const { return contents_scale_; } gfx::Rect content_rect() const { return content_rect_; } diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc index 93580b0..0af76f2 100644 --- a/skia/ext/analysis_canvas.cc +++ b/skia/ext/analysis_canvas.cc @@ -96,8 +96,8 @@ AnalysisDevice::AnalysisDevice(const SkBitmap& bm) , isForcedNotSolid_(false) , isForcedNotTransparent_(false) , isSolidColor_(false) - , isTransparent_(false) { - + , isTransparent_(false) + , hasText_(false) { } AnalysisDevice::~AnalysisDevice() { @@ -118,6 +118,10 @@ bool AnalysisDevice::isTransparent() const { return isTransparent_; } +bool AnalysisDevice::hasText() const { + return hasText_; +} + void AnalysisDevice::setForceNotSolid(bool flag) { isForcedNotSolid_ = flag; if (isForcedNotSolid_) @@ -181,6 +185,7 @@ void AnalysisDevice::clear(SkColor color) { estimatedCost_ += kUnknownExpensiveCost; isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0); + hasText_ = false; if (!isForcedNotSolid_ && SkColorGetA(color) == 255) { isSolidColor_ = true; @@ -246,6 +251,7 @@ void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, !isForcedNotTransparent_ && xferMode == SkXfermode::kClear_Mode) { isTransparent_ = true; + hasText_ = false; } else if (paint.getAlpha() != 0 || xferMode != SkXfermode::kSrc_Mode) { @@ -262,6 +268,7 @@ void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, doesCoverCanvas) { isSolidColor_ = true; color_ = paint.getColor(); + hasText_ = false; } else { isSolidColor_ = false; @@ -346,6 +353,7 @@ void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, } isSolidColor_ = false; isTransparent_ = false; + hasText_ = true; } void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, @@ -361,6 +369,7 @@ void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, } isSolidColor_ = false; isTransparent_ = false; + hasText_ = true; } void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, @@ -374,6 +383,7 @@ void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, } isSolidColor_ = false; isTransparent_ = false; + hasText_ = true; } #ifdef SK_BUILD_FOR_ANDROID @@ -388,6 +398,7 @@ void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, } isSolidColor_ = false; isTransparent_ = false; + hasText_ = true; } #endif @@ -441,6 +452,10 @@ bool AnalysisCanvas::isTransparent() const { return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent(); } +bool AnalysisCanvas::hasText() const { + return (static_cast<AnalysisDevice*>(getDevice()))->hasText(); +} + int AnalysisCanvas::getEstimatedCost() const { return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); } diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h index 3c2daaf..4ebf793 100644 --- a/skia/ext/analysis_canvas.h +++ b/skia/ext/analysis_canvas.h @@ -35,6 +35,7 @@ class SK_API AnalysisCanvas : public SkCanvas { bool isCheap() const; bool getColorIfSolid(SkColor* color) const; bool isTransparent() const; + bool hasText() const; void consumeLazyPixelRefs(LazyPixelRefList* pixelRefs); // Returns the estimated cost of drawing, in arbitrary units. @@ -76,6 +77,7 @@ class SK_API AnalysisDevice : public SkDevice { int getEstimatedCost() const; bool getColorIfSolid(SkColor* color) const; bool isTransparent() const; + bool hasText() const; void consumeLazyPixelRefs(LazyPixelRefList* pixelRefs); void setForceNotSolid(bool flag); @@ -144,6 +146,7 @@ class SK_API AnalysisDevice : public SkDevice { bool isSolidColor_; SkColor color_; bool isTransparent_; + bool hasText_; IdSet existingPixelRefIDs_; LazyPixelRefList lazyPixelRefs_; }; diff --git a/skia/ext/analysis_canvas_unittest.cc b/skia/ext/analysis_canvas_unittest.cc index 46c9645..a8a9d0d 100644 --- a/skia/ext/analysis_canvas_unittest.cc +++ b/skia/ext/analysis_canvas_unittest.cc @@ -454,4 +454,129 @@ TEST(AnalysisCanvasTest, PixelRefsFromPaint) { } } +TEST(AnalysisCanvasTest, HasText) { + int width = 200; + int height = 100; + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kNo_Config, width, height); + + const char* text = "A"; + size_t byteLength = 1; + + SkPoint point = SkPoint::Make(SkIntToScalar(25), SkIntToScalar(25)); + SkPath path; + path.moveTo(point); + path.lineTo(SkIntToScalar(75), SkIntToScalar(75)); + + SkPaint paint; + paint.setColor(SK_ColorGRAY); + paint.setTextSize(SkIntToScalar(10)); + + { + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + // Test after initialization. + EXPECT_FALSE(canvas.hasText()); + // Test drawing anything other than text. + canvas.drawRect(SkRect::MakeWH(width/2, height), paint); + EXPECT_FALSE(canvas.hasText()); + } + { + // Test SkCanvas::drawText. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawText(text, byteLength, point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + } + { + // Test SkCanvas::drawPosText. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawPosText(text, byteLength, &point, paint); + EXPECT_TRUE(canvas.hasText()); + } + { + // Test SkCanvas::drawPosTextH. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawPosTextH(text, byteLength, &point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + } + { + // Test SkCanvas::drawTextOnPathHV. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawTextOnPathHV(text, byteLength, path, point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + } + { + // Test SkCanvas::drawTextOnPath. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawTextOnPath(text, byteLength, path, NULL, paint); + EXPECT_TRUE(canvas.hasText()); + } + { + // Text under opaque rect. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawText(text, byteLength, point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + canvas.drawRect(SkRect::MakeWH(width, height), paint); + EXPECT_FALSE(canvas.hasText()); + } + { + // Text under translucent rect. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawText(text, byteLength, point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + SkPaint translucentPaint; + translucentPaint.setColor(0x88FFFFFF); + canvas.drawRect(SkRect::MakeWH(width, height), translucentPaint); + EXPECT_TRUE(canvas.hasText()); + } + { + // Text under rect in clear mode. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawText(text, byteLength, point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + SkPaint clearModePaint; + clearModePaint.setXfermodeMode(SkXfermode::kClear_Mode); + canvas.drawRect(SkRect::MakeWH(width, height), clearModePaint); + EXPECT_FALSE(canvas.hasText()); + } + { + // Clear. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.drawText(text, byteLength, point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + canvas.clear(SK_ColorGRAY); + EXPECT_FALSE(canvas.hasText()); + } + { + // Text inside clip region. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.clipRect(SkRect::MakeWH(100, 100)); + canvas.drawText(text, byteLength, point.fX, point.fY, paint); + EXPECT_TRUE(canvas.hasText()); + } + { + // Text outside clip region. + skia::AnalysisDevice device(bitmap); + skia::AnalysisCanvas canvas(&device); + canvas.clipRect(SkRect::MakeXYWH(100, 0, 100, 100)); + canvas.drawText(text, byteLength, point.fX, point.fY, paint); + // Analysis device does not do any clipping. + // So even when text is outside the clip region, + // it is marked as having the text. + // TODO(alokp): We may be able to do some trivial rejection. + EXPECT_TRUE(canvas.hasText()); + } +} + } // namespace skia |