1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/playback/pixel_ref_map.h"
10 #include "cc/base/math_util.h"
11 #include "cc/playback/display_item_list.h"
12 #include "cc/playback/picture.h"
13 #include "skia/ext/pixel_ref_utils.h"
14 #include "ui/gfx/geometry/rect_conversions.h"
18 PixelRefMap::PixelRefMap(const gfx::Size
& cell_size
) : cell_size_(cell_size
) {
19 DCHECK(!cell_size
.IsEmpty());
22 PixelRefMap::~PixelRefMap() {
25 void PixelRefMap::GatherPixelRefsFromPicture(SkPicture
* picture
,
26 const gfx::Rect
& layer_rect
) {
29 int min_x
= std::numeric_limits
<int>::max();
30 int min_y
= std::numeric_limits
<int>::max();
34 skia::DiscardablePixelRefList pixel_refs
;
35 skia::PixelRefUtils::GatherDiscardablePixelRefs(picture
, &pixel_refs
);
36 for (skia::DiscardablePixelRefList::const_iterator it
= pixel_refs
.begin();
37 it
!= pixel_refs
.end(); ++it
) {
38 // The image rect is in space relative to the picture, but it can extend far
39 // beyond the picture itself (since it represents the rect of actual image
40 // contained within the picture, not clipped to picture bounds). We only
41 // care about image queries that intersect the picture, so insert only into
42 // the intersection of the two rects.
43 gfx::Rect rect_clipped_to_picture
= gfx::IntersectRects(
44 gfx::ToEnclosingRect(gfx::SkRectToRectF(it
->pixel_ref_rect
)),
45 gfx::Rect(layer_rect
.size()));
47 gfx::Point
min(MathUtil::UncheckedRoundDown(rect_clipped_to_picture
.x(),
49 MathUtil::UncheckedRoundDown(rect_clipped_to_picture
.y(),
50 cell_size_
.height()));
51 gfx::Point
max(MathUtil::UncheckedRoundDown(rect_clipped_to_picture
.right(),
53 MathUtil::UncheckedRoundDown(
54 rect_clipped_to_picture
.bottom(), cell_size_
.height()));
56 // We recorded the picture as if it was at (0, 0) by translating by layer
57 // rect origin. Add the rect origin back here. It really doesn't make much
58 // of a difference, since the query for pixel refs doesn't use this
59 // information. However, since picture pile / display list also returns this
60 // information, it would be nice to express it relative to the layer, not
61 // relative to the particular implementation of the raster source.
62 skia::PositionPixelRef position_pixel_ref
= *it
;
63 position_pixel_ref
.pixel_ref_rect
.setXYWH(
64 position_pixel_ref
.pixel_ref_rect
.x() + layer_rect
.x(),
65 position_pixel_ref
.pixel_ref_rect
.y() + layer_rect
.y(),
66 position_pixel_ref
.pixel_ref_rect
.width(),
67 position_pixel_ref
.pixel_ref_rect
.height());
69 for (int y
= min
.y(); y
<= max
.y(); y
+= cell_size_
.height()) {
70 for (int x
= min
.x(); x
<= max
.x(); x
+= cell_size_
.width()) {
71 PixelRefMapKey
key(x
, y
);
72 data_hash_map_
[key
].push_back(position_pixel_ref
);
76 min_x
= std::min(min_x
, min
.x());
77 min_y
= std::min(min_y
, min
.y());
78 max_x
= std::max(max_x
, max
.x());
79 max_y
= std::max(max_y
, max
.y());
82 min_pixel_cell_
= gfx::Point(min_x
, min_y
);
83 max_pixel_cell_
= gfx::Point(max_x
, max_y
);
86 base::LazyInstance
<PixelRefs
> PixelRefMap::Iterator::empty_pixel_refs_
;
88 PixelRefMap::Iterator::Iterator()
89 : target_pixel_ref_map_(NULL
),
90 current_pixel_refs_(empty_pixel_refs_
.Pointer()),
98 PixelRefMap::Iterator::Iterator(const gfx::Rect
& rect
, const Picture
* picture
)
99 : target_pixel_ref_map_(&(picture
->pixel_refs_
)),
100 current_pixel_refs_(empty_pixel_refs_
.Pointer()),
102 map_layer_rect_
= picture
->layer_rect_
;
103 PointToFirstPixelRef(rect
);
106 PixelRefMap::Iterator::Iterator(const gfx::Rect
& rect
,
107 const DisplayItemList
* display_list
)
108 : target_pixel_ref_map_(display_list
->pixel_refs_
.get()),
109 current_pixel_refs_(empty_pixel_refs_
.Pointer()),
111 map_layer_rect_
= display_list
->layer_rect_
;
112 PointToFirstPixelRef(rect
);
115 PixelRefMap::Iterator::~Iterator() {
118 PixelRefMap::Iterator
& PixelRefMap::Iterator::operator++() {
120 // If we're not at the end of the list, then we have the next item.
121 if (current_index_
< current_pixel_refs_
->size())
124 DCHECK(current_y_
<= max_point_
.y());
126 gfx::Size cell_size
= target_pixel_ref_map_
->cell_size_
;
128 // Advance the current grid cell.
129 current_x_
+= cell_size
.width();
130 if (current_x_
> max_point_
.x()) {
131 current_y_
+= cell_size
.height();
132 current_x_
= min_point_
.x();
133 if (current_y_
> max_point_
.y()) {
134 current_pixel_refs_
= empty_pixel_refs_
.Pointer();
140 // If there are no pixel refs at this grid cell, keep incrementing.
141 PixelRefMapKey
key(current_x_
, current_y_
);
142 PixelRefHashmap::const_iterator iter
=
143 target_pixel_ref_map_
->data_hash_map_
.find(key
);
144 if (iter
== target_pixel_ref_map_
->data_hash_map_
.end())
147 // We found a non-empty list: store it and get the first pixel ref.
148 current_pixel_refs_
= &iter
->second
;
155 void PixelRefMap::Iterator::PointToFirstPixelRef(const gfx::Rect
& rect
) {
156 gfx::Rect
query_rect(rect
);
157 // Early out if the query rect doesn't intersect this picture.
158 if (!query_rect
.Intersects(map_layer_rect_
) || !target_pixel_ref_map_
) {
159 min_point_
= gfx::Point(0, 0);
160 max_point_
= gfx::Point(0, 0);
166 // First, subtract the layer origin as cells are stored in layer space.
167 query_rect
.Offset(-map_layer_rect_
.OffsetFromOrigin());
169 DCHECK(!target_pixel_ref_map_
->cell_size_
.IsEmpty());
170 gfx::Size
cell_size(target_pixel_ref_map_
->cell_size_
);
171 // We have to find a cell_size aligned point that corresponds to
172 // query_rect. Point is a multiple of cell_size.
173 min_point_
= gfx::Point(
174 MathUtil::UncheckedRoundDown(query_rect
.x(), cell_size
.width()),
175 MathUtil::UncheckedRoundDown(query_rect
.y(), cell_size
.height()));
176 max_point_
= gfx::Point(
177 MathUtil::UncheckedRoundDown(query_rect
.right() - 1, cell_size
.width()),
178 MathUtil::UncheckedRoundDown(query_rect
.bottom() - 1,
179 cell_size
.height()));
181 // Limit the points to known pixel ref boundaries.
182 min_point_
= gfx::Point(
183 std::max(min_point_
.x(), target_pixel_ref_map_
->min_pixel_cell_
.x()),
184 std::max(min_point_
.y(), target_pixel_ref_map_
->min_pixel_cell_
.y()));
185 max_point_
= gfx::Point(
186 std::min(max_point_
.x(), target_pixel_ref_map_
->max_pixel_cell_
.x()),
187 std::min(max_point_
.y(), target_pixel_ref_map_
->max_pixel_cell_
.y()));
189 // Make the current x be cell_size.width() less than min point, so that
190 // the first increment will point at min_point_.
191 current_x_
= min_point_
.x() - cell_size
.width();
192 current_y_
= min_point_
.y();
193 if (current_y_
<= max_point_
.y())