diff options
-rw-r--r-- | cc/base/util.h | 8 | ||||
-rw-r--r-- | cc/resources/picture.cc | 189 | ||||
-rw-r--r-- | cc/resources/picture.h | 59 | ||||
-rw-r--r-- | cc/resources/picture_pile_impl.cc | 86 | ||||
-rw-r--r-- | cc/resources/picture_pile_impl.h | 30 | ||||
-rw-r--r-- | cc/resources/picture_pile_impl_unittest.cc | 729 | ||||
-rw-r--r-- | cc/resources/picture_unittest.cc | 309 | ||||
-rw-r--r-- | cc/resources/tile_manager.cc | 14 | ||||
-rw-r--r-- | cc/test/fake_content_layer_client.cc | 11 | ||||
-rw-r--r-- | cc/test/fake_content_layer_client.h | 7 | ||||
-rw-r--r-- | cc/test/fake_picture_pile_impl.cc | 7 | ||||
-rw-r--r-- | cc/test/fake_picture_pile_impl.h | 9 |
12 files changed, 1399 insertions, 59 deletions
diff --git a/cc/base/util.h b/cc/base/util.h index b5a58c7..2bf2723 100644 --- a/cc/base/util.h +++ b/cc/base/util.h @@ -8,7 +8,13 @@ namespace cc { template <typename T> T RoundUp(T n, T mul) { - return ((n + mul - 1) / mul) * mul; + return (n > 0) ? ((n + mul - 1) / mul) * mul + : (n / mul) * mul; +} + +template <typename T> T RoundDown(T n, T mul) { + return (n > 0) ? (n / mul) * mul + : ((n - mul + 1) / mul) * mul; } } // namespace cc diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc index da898ff..e0c6630d 100644 --- a/cc/resources/picture.cc +++ b/cc/resources/picture.cc @@ -4,8 +4,13 @@ #include "cc/resources/picture.h" +#include <algorithm> +#include <limits> +#include <set> + #include "base/base64.h" #include "base/debug/trace_event.h" +#include "cc/base/util.h" #include "cc/debug/rendering_stats.h" #include "cc/layers/content_layer_client.h" #include "skia/ext/analysis_canvas.h" @@ -21,8 +26,10 @@ namespace { // URI label for a lazily decoded SkPixelRef. const char kLabelLazyDecoded[] = "lazy"; + // Version ID; to be used in serialization. const int kPictureVersion = 1; + // Minimum size of a decoded stream that we need. // 4 bytes for version, 4 * 4 for each of the 2 rects. const unsigned int kMinPictureSizeBytes = 36; @@ -101,10 +108,12 @@ Picture::Picture(const std::string& encoded_string, bool* success) { Picture::Picture(const skia::RefPtr<SkPicture>& picture, gfx::Rect layer_rect, - gfx::Rect opaque_rect) : + gfx::Rect opaque_rect, + const PixelRefMap& pixel_refs) : layer_rect_(layer_rect), opaque_rect_(opaque_rect), - picture_(picture) { + picture_(picture), + pixel_refs_(pixel_refs) { } Picture::~Picture() { @@ -130,7 +139,8 @@ void Picture::CloneForDrawing(int num_threads) { scoped_refptr<Picture> clone = make_scoped_refptr( new Picture(skia::AdoptRef(new SkPicture(clones[i])), layer_rect_, - opaque_rect_)); + opaque_rect_, + pixel_refs_)); clones_.push_back(clone); } } @@ -182,6 +192,15 @@ void Picture::Record(ContentLayerClient* painter, picture_->endRecording(); opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); + + cell_size_ = gfx::Size( + tile_grid_info.fTileInterval.width() + + 2 * tile_grid_info.fMargin.width(), + tile_grid_info.fTileInterval.height() + + 2 * tile_grid_info.fMargin.height()); + DCHECK_GT(cell_size_.width(), 0); + DCHECK_GT(cell_size_.height(), 0); + GatherAllPixelRefs(); } void Picture::Raster( @@ -207,32 +226,34 @@ void Picture::Raster( canvas->restore(); } -void Picture::GatherPixelRefs(gfx::Rect layer_rect, - std::list<skia::LazyPixelRef*>& pixel_ref_list) { +void Picture::GatherPixelRefsFromSkia( + gfx::Rect query_rect, + PixelRefs* pixel_refs) { DCHECK(picture_); - SkData* pixel_refs = SkPictureUtils::GatherPixelRefs( - picture_.get(), SkRect::MakeXYWH(layer_rect.x(), - layer_rect.y(), - layer_rect.width(), - layer_rect.height())); - if (!pixel_refs) + SkData* pixel_ref_data = SkPictureUtils::GatherPixelRefs( + picture_.get(), + SkRect::MakeXYWH(query_rect.x() - layer_rect_.x(), + query_rect.y() - layer_rect_.y(), + query_rect.width(), + query_rect.height())); + if (!pixel_ref_data) return; - void* data = const_cast<void*>(pixel_refs->data()); + void* data = const_cast<void*>(pixel_ref_data->data()); if (!data) { - pixel_refs->unref(); + pixel_ref_data->unref(); return; } SkPixelRef** refs = reinterpret_cast<SkPixelRef**>(data); - for (size_t i = 0; i < pixel_refs->size() / sizeof(*refs); ++i) { + for (size_t i = 0; i < pixel_ref_data->size() / sizeof(*refs); ++i) { if (*refs && (*refs)->getURI() && !strncmp( (*refs)->getURI(), kLabelLazyDecoded, 4)) { - pixel_ref_list.push_back(static_cast<skia::LazyPixelRef*>(*refs)); + pixel_refs->push_back(static_cast<skia::LazyPixelRef*>(*refs)); } refs++; } - pixel_refs->unref(); + pixel_ref_data->unref(); } void Picture::AsBase64String(std::string* output) const { @@ -262,4 +283,140 @@ void Picture::AsBase64String(std::string* output) const { output); } +void Picture::GatherAllPixelRefs() { + int min_x = std::numeric_limits<int>::max(); + int min_y = std::numeric_limits<int>::max(); + int max_x = 0; + int max_y = 0; + + // Capture pixel refs for this picture in a grid + // with cell_size_ sized cells. + for (int y = layer_rect_.y(); + y < layer_rect_.bottom(); + y += cell_size_.height()) { + for (int x = layer_rect_.x(); + x < layer_rect_.right(); + x += cell_size_.width()) { + gfx::Rect rect(gfx::Point(x, y), cell_size_); + rect.Intersect(layer_rect_); + + PixelRefs pixel_refs; + GatherPixelRefsFromSkia(rect, &pixel_refs); + + // Only capture non-empty cells. + if (!pixel_refs.empty()) { + pixel_refs_[PixelRefMapKey(x, y)].swap(pixel_refs); + min_x = std::min(min_x, x); + min_y = std::min(min_y, y); + max_x = std::max(max_x, x); + max_y = std::max(max_y, y); + } + } + } + + min_pixel_cell_ = gfx::Point(min_x, min_y); + max_pixel_cell_ = gfx::Point(max_x, max_y); +} + +base::LazyInstance<Picture::PixelRefs> + Picture::PixelRefIterator::empty_pixel_refs_; + +Picture::PixelRefIterator::PixelRefIterator() + : picture_(NULL), + current_pixel_refs_(empty_pixel_refs_.Pointer()), + current_index_(0), + min_point_(-1, -1), + max_point_(-1, -1), + current_x_(0), + current_y_(0) { +} + +Picture::PixelRefIterator::PixelRefIterator( + gfx::Rect query_rect, + const Picture* picture) + : picture_(picture), + current_pixel_refs_(empty_pixel_refs_.Pointer()), + current_index_(0) { + gfx::Rect layer_rect = picture->layer_rect_; + gfx::Size cell_size = picture->cell_size_; + + // Early out if the query rect doesn't intersect this picture + if (!query_rect.Intersects(layer_rect)) { + min_point_ = gfx::Point(0, 0); + max_point_ = gfx::Point(0, 0); + current_x_ = 1; + current_y_ = 1; + return; + } + + // We have to find a cell_size aligned point that + // corresponds to query_rect. First, subtract the layer origin, + // then ensure the point is a multiple of cell_size, + // and finally, add the layer origin back. + min_point_ = gfx::Point( + RoundDown(query_rect.x() - layer_rect.x(), cell_size.width()) + + layer_rect.x(), + RoundDown(query_rect.y() - layer_rect.y(), cell_size.height()) + + layer_rect.y()); + max_point_ = gfx::Point( + RoundDown(query_rect.right() - layer_rect.x() - 1, cell_size.width()) + + layer_rect.x(), + RoundDown(query_rect.bottom() - layer_rect.y() - 1, cell_size.height()) + + layer_rect.y()); + + // Limit the points to known pixel ref boundaries. + min_point_ = gfx::Point( + std::max(min_point_.x(), picture->min_pixel_cell_.x()), + std::max(min_point_.y(), picture->min_pixel_cell_.y())); + max_point_ = gfx::Point( + std::min(max_point_.x(), picture->max_pixel_cell_.x()), + std::min(max_point_.y(), picture->max_pixel_cell_.y())); + + // Make the current x be cell_size.width() less than min point, so that + // the first increment will point at min_point_. + current_x_ = min_point_.x() - cell_size.width(); + current_y_ = min_point_.y(); + if (current_y_ <= max_point_.y()) + ++(*this); +} + +Picture::PixelRefIterator::~PixelRefIterator() { +} + +Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() { + ++current_index_; + // If we're not at the end of the list, then we have the next item. + if (current_index_ < current_pixel_refs_->size()) + return *this; + + DCHECK(current_y_ <= max_point_.y()); + while (true) { + gfx::Size cell_size = picture_->cell_size_; + + // Advance the current grid cell. + current_x_ += cell_size.width(); + if (current_x_ > max_point_.x()) { + current_y_ += cell_size.height(); + current_x_ = min_point_.x(); + if (current_y_ > max_point_.y()) { + current_pixel_refs_ = empty_pixel_refs_.Pointer(); + current_index_ = 0; + break; + } + } + + // If there are no pixel refs at this grid cell, keep incrementing. + PixelRefMapKey key(current_x_, current_y_); + PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key); + if (iter == picture_->pixel_refs_.end()) + continue; + + // We found a non-empty list: store it and get the first pixel ref. + current_pixel_refs_ = &iter->second; + current_index_ = 0; + break; + } + return *this; +} + } // namespace cc diff --git a/cc/resources/picture.h b/cc/resources/picture.h index a56156b..86e256d 100644 --- a/cc/resources/picture.h +++ b/cc/resources/picture.h @@ -5,13 +5,17 @@ #ifndef CC_RESOURCES_PICTURE_H_ #define CC_RESOURCES_PICTURE_H_ -#include <list> #include <string> +#include <utility> #include <vector> #include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/lazy_instance.h" +#include "base/logging.h" #include "base/memory/ref_counted.h" #include "cc/base/cc_export.h" +#include "cc/base/hash_pair.h" #include "skia/ext/lazy_pixel_ref.h" #include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkPixelRef.h" @@ -30,6 +34,10 @@ struct RenderingStats; class CC_EXPORT Picture : public base::RefCountedThreadSafe<Picture> { public: + typedef std::pair<int, int> PixelRefMapKey; + typedef std::vector<skia::LazyPixelRef*> PixelRefs; + typedef base::hash_map<PixelRefMapKey, PixelRefs> PixelRefMap; + static scoped_refptr<Picture> Create(gfx::Rect layer_rect); static scoped_refptr<Picture> CreateFromBase64String( const std::string& encoded_string); @@ -58,12 +66,41 @@ class CC_EXPORT Picture float contents_scale, bool enable_lcd_text); - void GatherPixelRefs( - gfx::Rect layer_rect, - std::list<skia::LazyPixelRef*>& pixel_ref_list); - void AsBase64String(std::string* output) const; + class CC_EXPORT PixelRefIterator { + public: + PixelRefIterator(); + PixelRefIterator(gfx::Rect layer_rect, const Picture* picture); + ~PixelRefIterator(); + + skia::LazyPixelRef* operator->() const { + DCHECK_LT(current_index_, current_pixel_refs_->size()); + return (*current_pixel_refs_)[current_index_]; + } + + skia::LazyPixelRef* operator*() const { + DCHECK_LT(current_index_, current_pixel_refs_->size()); + return (*current_pixel_refs_)[current_index_]; + } + + PixelRefIterator& operator++(); + operator bool() const { + return current_index_ < current_pixel_refs_->size(); + } + + private: + static base::LazyInstance<PixelRefs> empty_pixel_refs_; + const Picture* picture_; + const PixelRefs* current_pixel_refs_; + unsigned current_index_; + + gfx::Point min_point_; + gfx::Point max_point_; + int current_x_; + int current_y_; + }; + private: explicit Picture(gfx::Rect layer_rect); Picture(const std::string& encoded_string, bool* success); @@ -71,9 +108,13 @@ class CC_EXPORT Picture // ownership to this picture. Picture(const skia::RefPtr<SkPicture>&, gfx::Rect layer_rect, - gfx::Rect opaque_rect); + gfx::Rect opaque_rect, + const PixelRefMap& pixel_refs); ~Picture(); + void GatherPixelRefsFromSkia(gfx::Rect query_rect, PixelRefs* pixel_refs); + void GatherAllPixelRefs(); + gfx::Rect layer_rect_; gfx::Rect opaque_rect_; skia::RefPtr<SkPicture> picture_; @@ -81,7 +122,13 @@ class CC_EXPORT Picture typedef std::vector<scoped_refptr<Picture> > PictureVector; PictureVector clones_; + PixelRefMap pixel_refs_; + gfx::Point min_pixel_cell_; + gfx::Point max_pixel_cell_; + gfx::Size cell_size_; + friend class base::RefCountedThreadSafe<Picture>; + friend class PixelRefIterator; DISALLOW_COPY_AND_ASSIGN(Picture); }; diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc index dd30ede..6559f24 100644 --- a/cc/resources/picture_pile_impl.cc +++ b/cc/resources/picture_pile_impl.cc @@ -198,31 +198,6 @@ int64 PicturePileImpl::Raster( return total_pixels_rasterized; } -void PicturePileImpl::GatherPixelRefs( - gfx::Rect content_rect, - float contents_scale, - std::list<skia::LazyPixelRef*>& pixel_refs) { - std::list<skia::LazyPixelRef*> result; - - gfx::Rect layer_rect = gfx::ToEnclosingRect( - gfx::ScaleRect(content_rect, 1.f / contents_scale)); - - for (TilingData::Iterator tile_iter(&tiling_, layer_rect); - tile_iter; ++tile_iter) { - PictureListMap::iterator map_iter = - picture_list_map_.find(tile_iter.index()); - if (map_iter == picture_list_map_.end()) - continue; - - PictureList& pic_list = map_iter->second; - for (PictureList::const_iterator i = pic_list.begin(); - i != pic_list.end(); ++i) { - (*i)->GatherPixelRefs(layer_rect, result); - pixel_refs.splice(pixel_refs.end(), result); - } - } -} - skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture"); @@ -277,4 +252,65 @@ PicturePileImpl::Analysis::Analysis() PicturePileImpl::Analysis::~Analysis() { } +PicturePileImpl::PixelRefIterator::PixelRefIterator( + gfx::Rect content_rect, + float contents_scale, + const PicturePileImpl* picture_pile) + : picture_pile_(picture_pile), + layer_rect_(gfx::ToEnclosingRect( + gfx::ScaleRect(content_rect, 1.f / contents_scale))), + tile_iterator_(&picture_pile_->tiling_, layer_rect_), + picture_list_(NULL) { + // Early out if there isn't a single tile. + if (!tile_iterator_) + return; + + if (AdvanceToTileWithPictures()) + AdvanceToPictureWithPixelRefs(); +} + +PicturePileImpl::PixelRefIterator::~PixelRefIterator() { +} + +PicturePileImpl::PixelRefIterator& + PicturePileImpl::PixelRefIterator::operator++() { + ++pixel_ref_iterator_; + if (pixel_ref_iterator_) + return *this; + + ++picture_list_iterator_; + AdvanceToPictureWithPixelRefs(); + return *this; +} + +bool PicturePileImpl::PixelRefIterator::AdvanceToTileWithPictures() { + for (; tile_iterator_; ++tile_iterator_) { + PictureListMap::const_iterator map_iterator = + picture_pile_->picture_list_map_.find(tile_iterator_.index()); + if (map_iterator != picture_pile_->picture_list_map_.end()) { + picture_list_ = &map_iterator->second; + picture_list_iterator_ = picture_list_->begin(); + return true; + } + } + + return false; +} + +void PicturePileImpl::PixelRefIterator::AdvanceToPictureWithPixelRefs() { + DCHECK(tile_iterator_); + do { + for (; + picture_list_iterator_ != picture_list_->end(); + ++picture_list_iterator_) { + pixel_ref_iterator_ = Picture::PixelRefIterator( + layer_rect_, + *picture_list_iterator_); + if (pixel_ref_iterator_) + return; + } + ++tile_iterator_; + } while (AdvanceToTileWithPictures()); +} + } // namespace cc diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h index 352772d..d151bf3 100644 --- a/cc/resources/picture_pile_impl.h +++ b/cc/resources/picture_pile_impl.h @@ -37,11 +37,6 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { gfx::Rect canvas_rect, float contents_scale); - void GatherPixelRefs( - gfx::Rect content_rect, - float contents_scale, - std::list<skia::LazyPixelRef*>& pixel_refs); - skia::RefPtr<SkPicture> GetFlattenedPicture(); struct CC_EXPORT Analysis { @@ -61,8 +56,33 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase { float contents_scale, Analysis* analysis); + class CC_EXPORT PixelRefIterator { + public: + PixelRefIterator(gfx::Rect content_rect, + float contents_scale, + const PicturePileImpl* picture_pile); + ~PixelRefIterator(); + + skia::LazyPixelRef* operator->() const { return *pixel_ref_iterator_; } + skia::LazyPixelRef* operator*() const { return *pixel_ref_iterator_; } + PixelRefIterator& operator++(); + operator bool() const { return pixel_ref_iterator_; } + + private: + bool AdvanceToTileWithPictures(); + void AdvanceToPictureWithPixelRefs(); + + const PicturePileImpl* picture_pile_; + gfx::Rect layer_rect_; + TilingData::Iterator tile_iterator_; + Picture::PixelRefIterator pixel_ref_iterator_; + const PictureList* picture_list_; + PictureList::const_iterator picture_list_iterator_; + }; + protected: friend class PicturePile; + friend class PixelRefIterator; explicit PicturePileImpl(bool enable_lcd_text); PicturePileImpl(const PicturePileBase* other, bool enable_lcd_text); diff --git a/cc/resources/picture_pile_impl_unittest.cc b/cc/resources/picture_pile_impl_unittest.cc index 13a24fd..1f622c3 100644 --- a/cc/resources/picture_pile_impl_unittest.cc +++ b/cc/resources/picture_pile_impl_unittest.cc @@ -2,13 +2,72 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/memory/scoped_ptr.h" #include "cc/test/fake_picture_pile_impl.h" +#include "skia/ext/lazy_pixel_ref.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkPixelRef.h" +#include "third_party/skia/include/core/SkShader.h" #include "ui/gfx/rect.h" namespace cc { namespace { +class TestPixelRef : public SkPixelRef { + public: + // Pure virtual implementation. + TestPixelRef(int width, int height) + : pixels_(new char[4 * width * height]) {} + virtual SkFlattenable::Factory getFactory() OVERRIDE { return NULL; } + virtual void* onLockPixels(SkColorTable** color_table) OVERRIDE { + return pixels_.get(); + } + virtual void onUnlockPixels() OVERRIDE {} + virtual SkPixelRef* deepCopy( + SkBitmap::Config config, + const SkIRect* subset) OVERRIDE { + this->ref(); + return this; + } + private: + scoped_ptr<char[]> pixels_; +}; + +class TestLazyPixelRef : public skia::LazyPixelRef { + public: + // Pure virtual implementation. + TestLazyPixelRef(int width, int height) + : pixels_(new char[4 * width * height]) {} + virtual SkFlattenable::Factory getFactory() OVERRIDE { return NULL; } + virtual void* onLockPixels(SkColorTable** color_table) OVERRIDE { + return pixels_.get(); + } + virtual void onUnlockPixels() OVERRIDE {} + virtual bool PrepareToDecode(const PrepareParams& params) OVERRIDE { + return true; + } + virtual SkPixelRef* deepCopy( + SkBitmap::Config config, + const SkIRect* subset) OVERRIDE { + this->ref(); + return this; + } + virtual void Decode() OVERRIDE {} + private: + scoped_ptr<char[]> pixels_; +}; + +void CreateBitmap(gfx::Size size, const char* uri, SkBitmap* bitmap) { + SkAutoTUnref<TestLazyPixelRef> lazy_pixel_ref; + lazy_pixel_ref.reset(new TestLazyPixelRef(size.width(), size.height())); + lazy_pixel_ref->setURI(uri); + + bitmap->setConfig(SkBitmap::kARGB_8888_Config, + size.width(), + size.height()); + bitmap->setPixelRef(lazy_pixel_ref); +} + void RerecordPile(scoped_refptr<FakePicturePileImpl> pile) { for (int y = 0; y < pile->num_tiles_y(); ++y) { for (int x = 0; x < pile->num_tiles_x(); ++x) { @@ -134,6 +193,676 @@ TEST(PicturePileImplTest, AnalyzeIsSolidScaled) { EXPECT_EQ(analysis.solid_color, solid_color); } +TEST(PicturePileImplTest, PixelRefIteratorEmpty) { + gfx::Size tile_size(128, 128); + gfx::Size layer_bounds(256, 256); + + // Create a filled pile with no recording. + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + // Tile sized iterators. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 2.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 64, 64), + 0.5, + pile); + EXPECT_FALSE(iterator); + } + // Shifted tile sized iterators. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(140, 140, 128, 128), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(280, 280, 256, 256), + 2.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(70, 70, 64, 64), + 0.5, + pile); + EXPECT_FALSE(iterator); + } + // Layer sized iterators. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 2.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 0.5, + pile); + EXPECT_FALSE(iterator); + } +} + +TEST(PicturePileImplTest, PixelRefIteratorNoLazyRefs) { + gfx::Size tile_size(128, 128); + gfx::Size layer_bounds(256, 256); + + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + SkPaint simple_paint; + simple_paint.setColor(SkColorSetARGB(255, 12, 23, 34)); + + SkBitmap non_lazy_bitmap; + CreateBitmap(gfx::Size(128, 128), "notlazy", &non_lazy_bitmap); + + pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 256, 256), simple_paint); + pile->add_draw_rect_with_paint(gfx::Rect(128, 128, 512, 512), simple_paint); + pile->add_draw_rect_with_paint(gfx::Rect(512, 0, 256, 256), simple_paint); + pile->add_draw_rect_with_paint(gfx::Rect(0, 512, 256, 256), simple_paint); + pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(128, 0)); + pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(0, 128)); + pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(150, 150)); + + RerecordPile(pile); + + // Tile sized iterators. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 2.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 64, 64), + 0.5, + pile); + EXPECT_FALSE(iterator); + } + // Shifted tile sized iterators. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(140, 140, 128, 128), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(280, 280, 256, 256), + 2.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(70, 70, 64, 64), + 0.5, + pile); + EXPECT_FALSE(iterator); + } + // Layer sized iterators. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 2.0, + pile); + EXPECT_FALSE(iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 0.5, + pile); + EXPECT_FALSE(iterator); + } +} + +TEST(PicturePileImplTest, PixelRefIteratorLazyRefs) { + gfx::Size tile_size(128, 128); + gfx::Size layer_bounds(256, 256); + + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + SkBitmap lazy_bitmap[2][2]; + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][0]); + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][0]); + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][1]); + + // Lazy pixel refs are found in the following cells: + // |---|---| + // | x | | + // |---|---| + // | x | x | + // |---|---| + pile->add_draw_bitmap(lazy_bitmap[0][0], gfx::Point(0, 0)); + pile->add_draw_bitmap(lazy_bitmap[1][0], gfx::Point(0, 130)); + pile->add_draw_bitmap(lazy_bitmap[1][1], gfx::Point(140, 140)); + + RerecordPile(pile); + + // Tile sized iterators. These should find only one pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 64, 64), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + // Shifted tile sized iterators. These should find only one pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(140, 140, 128, 128), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(280, 280, 256, 256), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(70, 70, 64, 64), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + // Ensure there's no lazy pixel refs in the empty cell + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(140, 0, 128, 128), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + // Layer sized iterators. These should find all 3 pixel refs. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } +} + +TEST(PicturePileImplTest, PixelRefIteratorLazyRefsOneTile) { + gfx::Size tile_size(256, 256); + gfx::Size layer_bounds(512, 512); + + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + SkBitmap lazy_bitmap[2][2]; + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][0]); + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][1]); + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][1]); + + // Lazy pixel refs are found in the following cells: + // |---|---| + // | x | x | + // |---|---| + // | | x | + // |---|---| + pile->add_draw_bitmap(lazy_bitmap[0][0], gfx::Point(0, 0)); + pile->add_draw_bitmap(lazy_bitmap[0][1], gfx::Point(260, 0)); + pile->add_draw_bitmap(lazy_bitmap[1][1], gfx::Point(260, 260)); + + RerecordPile(pile); + + // Tile sized iterators. These should find only one pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + // Shifted tile sized iterators. These should find only one pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(260, 260, 256, 256), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(520, 520, 512, 512), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(130, 130, 128, 128), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + // Ensure there's no lazy pixel refs in the empty cell + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 256, 256, 256), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + // Layer sized iterators. These should find three pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 1024, 1024), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + + // Copy test. + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + + // copy now points to the same spot as iterator, + // but both can be incremented independently. + PicturePileImpl::PixelRefIterator copy = iterator; + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + + EXPECT_TRUE(copy); + EXPECT_TRUE(*copy == lazy_bitmap[0][1].pixelRef()); + EXPECT_TRUE(++copy); + EXPECT_TRUE(*copy == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++copy); +} + +TEST(PicturePileImplTest, PixelRefIteratorLazyRefsBaseNonLazy) { + gfx::Size tile_size(256, 256); + gfx::Size layer_bounds(512, 512); + + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + SkBitmap non_lazy_bitmap; + CreateBitmap(gfx::Size(512, 512), "notlazy", &non_lazy_bitmap); + + SkBitmap lazy_bitmap[2][2]; + CreateBitmap(gfx::Size(128, 128), "lazy", &lazy_bitmap[0][0]); + CreateBitmap(gfx::Size(128, 128), "lazy", &lazy_bitmap[0][1]); + CreateBitmap(gfx::Size(128, 128), "lazy", &lazy_bitmap[1][1]); + + // One large non-lazy bitmap covers the whole grid. + // Lazy pixel refs are found in the following cells: + // |---|---| + // | x | x | + // |---|---| + // | | x | + // |---|---| + pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(0, 0)); + pile->add_draw_bitmap(lazy_bitmap[0][0], gfx::Point(0, 0)); + pile->add_draw_bitmap(lazy_bitmap[0][1], gfx::Point(260, 0)); + pile->add_draw_bitmap(lazy_bitmap[1][1], gfx::Point(260, 260)); + + RerecordPile(pile); + + // Tile sized iterators. These should find only one pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + // Shifted tile sized iterators. These should find only one pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(260, 260, 256, 256), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(520, 520, 512, 512), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(130, 130, 128, 128), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + // Ensure there's no lazy pixel refs in the empty cell + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 256, 256, 256), + 1.0, + pile); + EXPECT_FALSE(iterator); + } + // Layer sized iterators. These should find three pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 512, 512), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 1024, 1024), + 2.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 256, 256), + 0.5, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } +} + +TEST(PicturePileImplTest, PixelRefIteratorMultiplePictures) { + gfx::Size tile_size(256, 256); + gfx::Size layer_bounds(256, 256); + + SkTileGridPicture::TileGridInfo tile_grid_info; + tile_grid_info.fTileInterval = SkISize::Make(256, 256); + tile_grid_info.fMargin.setEmpty(); + tile_grid_info.fOffset.setZero(); + + scoped_refptr<FakePicturePileImpl> pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + SkBitmap lazy_bitmap[2][2]; + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][0]); + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][1]); + CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][1]); + SkBitmap non_lazy_bitmap; + CreateBitmap(gfx::Size(256, 256), "notlazy", &non_lazy_bitmap); + + // Each bitmap goes into its own picture, the final layout + // has lazy pixel refs in the following regions: + // ||=======|| + // ||x| |x|| + // ||-- --|| + // || |x|| + // ||=======|| + pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(0, 0)); + RerecordPile(pile); + + FakeContentLayerClient content_layer_clients[2][2]; + scoped_refptr<Picture> pictures[2][2]; + for (int y = 0; y < 2; ++y) { + for (int x = 0; x < 2; ++x) { + if (x == 0 && y == 1) + continue; + content_layer_clients[y][x].add_draw_bitmap( + lazy_bitmap[y][x], + gfx::Point(x * 128 + 10, y * 128 + 10)); + pictures[y][x] = Picture::Create( + gfx::Rect(x * 128 + 10, y * 128 + 10, 64, 64)); + pictures[y][x]->Record( + &content_layer_clients[y][x], + NULL, + tile_grid_info); + pile->AddPictureToRecording(0, 0, pictures[y][x]); + } + } + + // These should find only one pixel ref. + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 0, 128, 128), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(128, 0, 128, 128), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(128, 128, 128, 128), + 1.0, + pile); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef()); + EXPECT_FALSE(++iterator); + } + // This one should not find any refs + { + PicturePileImpl::PixelRefIterator iterator( + gfx::Rect(0, 128, 128, 128), + 1.0, + pile); + EXPECT_FALSE(iterator); + } +} } // namespace } // namespace cc diff --git a/cc/resources/picture_unittest.cc b/cc/resources/picture_unittest.cc index f20c547..1d83207 100644 --- a/cc/resources/picture_unittest.cc +++ b/cc/resources/picture_unittest.cc @@ -5,11 +5,13 @@ #include "cc/resources/picture.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "cc/test/fake_content_layer_client.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkDevice.h" #include "third_party/skia/include/core/SkGraphics.h" +#include "third_party/skia/include/core/SkPixelRef.h" #include "third_party/skia/include/core/SkTileGridPicture.h" #include "ui/gfx/rect.h" #include "ui/gfx/skia_util.h" @@ -17,6 +19,30 @@ namespace cc { namespace { +class TestLazyPixelRef : public skia::LazyPixelRef { + public: + // Pure virtual implementation. + TestLazyPixelRef(int width, int height) + : pixels_(new char[4 * width * height]) {} + virtual SkFlattenable::Factory getFactory() OVERRIDE { return NULL; } + virtual void* onLockPixels(SkColorTable** color_table) OVERRIDE { + return pixels_.get(); + } + virtual void onUnlockPixels() OVERRIDE {} + virtual bool PrepareToDecode(const PrepareParams& params) OVERRIDE { + return true; + } + virtual SkPixelRef* deepCopy( + SkBitmap::Config config, + const SkIRect* subset) OVERRIDE { + this->ref(); + return this; + } + virtual void Decode() OVERRIDE {} + private: + scoped_ptr<char[]> pixels_; +}; + void DrawPicture(unsigned char* buffer, gfx::Rect layer_rect, scoped_refptr<Picture> picture) { @@ -31,6 +57,17 @@ void DrawPicture(unsigned char* buffer, picture->Raster(&canvas, layer_rect, 1.0f, false); } +void CreateBitmap(gfx::Size size, const char* uri, SkBitmap* bitmap) { + SkAutoTUnref<TestLazyPixelRef> lazy_pixel_ref; + lazy_pixel_ref.reset(new TestLazyPixelRef(size.width(), size.height())); + lazy_pixel_ref->setURI(uri); + + bitmap->setConfig(SkBitmap::kARGB_8888_Config, + size.width(), + size.height()); + bitmap->setPixelRef(lazy_pixel_ref); +} + TEST(PictureTest, AsBase64String) { SkGraphics::Init(); @@ -120,5 +157,277 @@ TEST(PictureTest, AsBase64String) { memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100) == 0); } +TEST(PictureTest, PixelRefIterator) { + gfx::Rect layer_rect(2048, 2048); + + SkTileGridPicture::TileGridInfo tile_grid_info; + tile_grid_info.fTileInterval = SkISize::Make(512, 512); + tile_grid_info.fMargin.setEmpty(); + tile_grid_info.fOffset.setZero(); + + FakeContentLayerClient content_layer_client; + + // Lazy pixel refs are found in the following grids: + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + SkBitmap lazy_bitmap[4][4]; + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + if ((x + y) & 1) { + CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]); + content_layer_client.add_draw_bitmap( + lazy_bitmap[y][x], + gfx::Point(x * 512 + 6, y * 512 + 6)); + } + } + } + + scoped_refptr<Picture> picture = Picture::Create(layer_rect); + picture->Record(&content_layer_client, NULL, tile_grid_info); + + // Default iterator does not have any pixel refs + { + Picture::PixelRefIterator iterator; + EXPECT_FALSE(iterator); + } + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + Picture::PixelRefIterator iterator( + gfx::Rect(x * 512, y * 512, 500, 500), + picture); + if ((x + y) & 1) { + EXPECT_TRUE(iterator) << x << " " << y; + EXPECT_TRUE(*iterator == lazy_bitmap[y][x].pixelRef()) << x << " " << y; + EXPECT_FALSE(++iterator) << x << " " << y; + } else { + EXPECT_FALSE(iterator) << x << " " << y; + } + } + } + // Capture 4 pixel refs. + { + Picture::PixelRefIterator iterator( + gfx::Rect(512, 512, 2048, 2048), + picture); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef()); + EXPECT_FALSE(++iterator); + } + + // Copy test. + Picture::PixelRefIterator iterator( + gfx::Rect(512, 512, 2048, 2048), + picture); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef()); + + // copy now points to the same spot as iterator, + // but both can be incremented independently. + Picture::PixelRefIterator copy = iterator; + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef()); + EXPECT_FALSE(++iterator); + + EXPECT_TRUE(copy); + EXPECT_TRUE(*copy == lazy_bitmap[2][1].pixelRef()); + EXPECT_TRUE(++copy); + EXPECT_TRUE(*copy == lazy_bitmap[2][3].pixelRef()); + EXPECT_TRUE(++copy); + EXPECT_TRUE(*copy == lazy_bitmap[3][2].pixelRef()); + EXPECT_FALSE(++copy); +} + +TEST(PictureTest, PixelRefIteratorNonZeroLayer) { + gfx::Rect layer_rect(1024, 0, 2048, 2048); + + SkTileGridPicture::TileGridInfo tile_grid_info; + tile_grid_info.fTileInterval = SkISize::Make(512, 512); + tile_grid_info.fMargin.setEmpty(); + tile_grid_info.fOffset.setZero(); + + FakeContentLayerClient content_layer_client; + + // Lazy pixel refs are found in the following grids: + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + SkBitmap lazy_bitmap[4][4]; + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + if ((x + y) & 1) { + CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]); + content_layer_client.add_draw_bitmap( + lazy_bitmap[y][x], + gfx::Point(1024 + x * 512 + 6, y * 512 + 6)); + } + } + } + + scoped_refptr<Picture> picture = Picture::Create(layer_rect); + picture->Record(&content_layer_client, NULL, tile_grid_info); + + // Default iterator does not have any pixel refs + { + Picture::PixelRefIterator iterator; + EXPECT_FALSE(iterator); + } + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + Picture::PixelRefIterator iterator( + gfx::Rect(1024 + x * 512, y * 512, 500, 500), + picture); + if ((x + y) & 1) { + EXPECT_TRUE(iterator) << x << " " << y; + EXPECT_TRUE(*iterator == lazy_bitmap[y][x].pixelRef()); + EXPECT_FALSE(++iterator) << x << " " << y; + } else { + EXPECT_FALSE(iterator) << x << " " << y; + } + } + } + // Capture 4 pixel refs. + { + Picture::PixelRefIterator iterator( + gfx::Rect(1024 + 512, 512, 2048, 2048), + picture); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef()); + EXPECT_FALSE(++iterator); + } + + // Copy test. + { + Picture::PixelRefIterator iterator( + gfx::Rect(1024 + 512, 512, 2048, 2048), + picture); + EXPECT_TRUE(iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef()); + + // copy now points to the same spot as iterator, + // but both can be incremented independently. + Picture::PixelRefIterator copy = iterator; + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef()); + EXPECT_TRUE(++iterator); + EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef()); + EXPECT_FALSE(++iterator); + + EXPECT_TRUE(copy); + EXPECT_TRUE(*copy == lazy_bitmap[2][1].pixelRef()); + EXPECT_TRUE(++copy); + EXPECT_TRUE(*copy == lazy_bitmap[2][3].pixelRef()); + EXPECT_TRUE(++copy); + EXPECT_TRUE(*copy == lazy_bitmap[3][2].pixelRef()); + EXPECT_FALSE(++copy); + } + + // Non intersecting rects + { + Picture::PixelRefIterator iterator( + gfx::Rect(0, 0, 1000, 1000), + picture); + EXPECT_FALSE(iterator); + } + { + Picture::PixelRefIterator iterator( + gfx::Rect(3500, 0, 1000, 1000), + picture); + EXPECT_FALSE(iterator); + } + { + Picture::PixelRefIterator iterator( + gfx::Rect(0, 1100, 1000, 1000), + picture); + EXPECT_FALSE(iterator); + } + { + Picture::PixelRefIterator iterator( + gfx::Rect(3500, 1100, 1000, 1000), + picture); + EXPECT_FALSE(iterator); + } +} + +TEST(PictureTest, PixelRefIteratorOnePixelQuery) { + gfx::Rect layer_rect(2048, 2048); + + SkTileGridPicture::TileGridInfo tile_grid_info; + tile_grid_info.fTileInterval = SkISize::Make(512, 512); + tile_grid_info.fMargin.setEmpty(); + tile_grid_info.fOffset.setZero(); + + FakeContentLayerClient content_layer_client; + + // Lazy pixel refs are found in the following grids: + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + SkBitmap lazy_bitmap[4][4]; + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + if ((x + y) & 1) { + CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]); + content_layer_client.add_draw_bitmap( + lazy_bitmap[y][x], + gfx::Point(x * 512 + 6, y * 512 + 6)); + } + } + } + + scoped_refptr<Picture> picture = Picture::Create(layer_rect); + picture->Record(&content_layer_client, NULL, tile_grid_info); + + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + Picture::PixelRefIterator iterator( + gfx::Rect(x * 512, y * 512 + 256, 1, 1), + picture); + if ((x + y) & 1) { + EXPECT_TRUE(iterator) << x << " " << y; + EXPECT_TRUE(*iterator == lazy_bitmap[y][x].pixelRef()); + EXPECT_FALSE(++iterator) << x << " " << y; + } else { + EXPECT_FALSE(iterator) << x << " " << y; + } + } + } +} } // namespace } // namespace cc diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc index 5e42642..3fe431d 100644 --- a/cc/resources/tile_manager.cc +++ b/cc/resources/tile_manager.cc @@ -686,15 +686,21 @@ void TileManager::AnalyzeTile(Tile* tile) { } void TileManager::GatherPixelRefsForTile(Tile* tile) { + // TODO(vmpstr): Remove this function and pending_pixel_refs + // when reveman's improvements to worker pool go in. TRACE_EVENT0("cc", "TileManager::GatherPixelRefsForTile"); ManagedTileState& managed_tile_state = tile->managed_state(); if (managed_tile_state.need_to_gather_pixel_refs) { base::TimeTicks start_time = rendering_stats_instrumentation_->StartRecording(); - tile->picture_pile()->GatherPixelRefs( - tile->content_rect_, - tile->contents_scale_, - managed_tile_state.pending_pixel_refs); + for (PicturePileImpl::PixelRefIterator pixel_ref_iter( + tile->content_rect(), + tile->contents_scale(), + tile->picture_pile()); + pixel_ref_iter; + ++pixel_ref_iter) { + managed_tile_state.pending_pixel_refs.push_back(*pixel_ref_iter); + } managed_tile_state.need_to_gather_pixel_refs = false; base::TimeDelta duration = rendering_stats_instrumentation_->EndRecording(start_time); diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc index 7153766..280459b 100644 --- a/cc/test/fake_content_layer_client.cc +++ b/cc/test/fake_content_layer_client.cc @@ -5,6 +5,7 @@ #include "cc/test/fake_content_layer_client.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "ui/gfx/skia_util.h" namespace cc { @@ -20,10 +21,11 @@ void FakeContentLayerClient::PaintContents(SkCanvas* canvas, if (paint_all_opaque_) *opaque_rect = rect; + canvas->clipRect(gfx::RectToSkRect(rect)); for (RectPaintVector::const_iterator it = draw_rects_.begin(); - it < draw_rects_.end(); ++it) { + it != draw_rects_.end(); ++it) { gfx::Rect rect = it->first; - SkPaint paint = it->second; + const SkPaint& paint = it->second; SkRect draw_rect = SkRect::MakeXYWH( rect.x(), rect.y(), @@ -31,6 +33,11 @@ void FakeContentLayerClient::PaintContents(SkCanvas* canvas, rect.height()); canvas->drawRect(draw_rect, paint); } + + for (BitmapVector::const_iterator it = draw_bitmaps_.begin(); + it != draw_bitmaps_.end(); ++it) { + canvas->drawBitmap(it->first, it->second.x(), it->second.y()); + } } } // namespace cc diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h index 1557754..dfc8ce7 100644 --- a/cc/test/fake_content_layer_client.h +++ b/cc/test/fake_content_layer_client.h @@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "cc/layers/content_layer_client.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkPaint.h" #include "ui/gfx/rect.h" @@ -31,11 +32,17 @@ class FakeContentLayerClient : public cc::ContentLayerClient { draw_rects_.push_back(std::make_pair(rect, paint)); } + void add_draw_bitmap(const SkBitmap& bitmap, gfx::Point point) { + draw_bitmaps_.push_back(std::make_pair(bitmap, point)); + } + private: typedef std::vector<std::pair<gfx::Rect, SkPaint> > RectPaintVector; + typedef std::vector<std::pair<SkBitmap, gfx::Point> > BitmapVector; bool paint_all_opaque_; RectPaintVector draw_rects_; + BitmapVector draw_bitmaps_; }; } // namespace cc diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc index 70d0a8d..9c58313 100644 --- a/cc/test/fake_picture_pile_impl.cc +++ b/cc/test/fake_picture_pile_impl.cc @@ -59,6 +59,13 @@ void FakePicturePileImpl::AddRecordingAt(int x, int y) { UpdateRecordedRegion(); } +void FakePicturePileImpl::AddPictureToRecording( + int x, + int y, + scoped_refptr<Picture> picture) { + picture_list_map_[std::pair<int, int>(x, y)].push_back(picture); +} + void FakePicturePileImpl::RemoveRecordingAt(int x, int y) { EXPECT_GE(x, 0); EXPECT_GE(y, 0); diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h index d6479d6..057376d 100644 --- a/cc/test/fake_picture_pile_impl.h +++ b/cc/test/fake_picture_pile_impl.h @@ -27,10 +27,19 @@ class FakePicturePileImpl : public PicturePileImpl { void RemoveRecordingAt(int x, int y); + void AddPictureToRecording( + int x, + int y, + scoped_refptr<Picture> picture); + void add_draw_rect(gfx::Rect rect) { client_.add_draw_rect(rect, default_paint_); } + void add_draw_bitmap(const SkBitmap& bitmap, gfx::Point point) { + client_.add_draw_bitmap(bitmap, point); + } + void add_draw_rect_with_paint(gfx::Rect rect, const SkPaint& paint) { client_.add_draw_rect(rect, paint); } |