| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 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. | |
| 4 | |
| 5 #include "base/debug/trace_event.h" | |
| 6 #include "cc/base/region.h" | |
| 7 #include "cc/debug/debug_colors.h" | |
| 8 #include "cc/debug/rendering_stats.h" | |
| 9 #include "cc/picture_pile_impl.h" | |
| 10 #include "skia/ext/analysis_canvas.h" | |
| 11 #include "third_party/skia/include/core/SkCanvas.h" | |
| 12 #include "third_party/skia/include/core/SkSize.h" | |
| 13 #include "ui/gfx/rect_conversions.h" | |
| 14 #include "ui/gfx/size_conversions.h" | |
| 15 #include "ui/gfx/skia_util.h" | |
| 16 | |
| 17 namespace cc { | |
| 18 | |
| 19 PicturePileImpl::ClonesForDrawing::ClonesForDrawing( | |
| 20 const PicturePileImpl* pile, int num_threads) { | |
| 21 for (int i = 0; i < num_threads; i++) { | |
| 22 scoped_refptr<PicturePileImpl> clone = | |
| 23 PicturePileImpl::CreateCloneForDrawing(pile, i); | |
| 24 clones_.push_back(clone); | |
| 25 } | |
| 26 } | |
| 27 | |
| 28 PicturePileImpl::ClonesForDrawing::~ClonesForDrawing() { | |
| 29 } | |
| 30 | |
| 31 scoped_refptr<PicturePileImpl> PicturePileImpl::Create() { | |
| 32 return make_scoped_refptr(new PicturePileImpl()); | |
| 33 } | |
| 34 | |
| 35 scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther( | |
| 36 const PicturePileBase* other) { | |
| 37 return make_scoped_refptr(new PicturePileImpl(other)); | |
| 38 } | |
| 39 | |
| 40 scoped_refptr<PicturePileImpl> PicturePileImpl::CreateCloneForDrawing( | |
| 41 const PicturePileImpl* other, unsigned thread_index) { | |
| 42 return make_scoped_refptr(new PicturePileImpl(other, thread_index)); | |
| 43 } | |
| 44 | |
| 45 PicturePileImpl::PicturePileImpl() | |
| 46 : clones_for_drawing_(ClonesForDrawing(this, 0)) { | |
| 47 } | |
| 48 | |
| 49 PicturePileImpl::PicturePileImpl(const PicturePileBase* other) | |
| 50 : PicturePileBase(other), | |
| 51 clones_for_drawing_(ClonesForDrawing(this, num_raster_threads())) { | |
| 52 } | |
| 53 | |
| 54 PicturePileImpl::PicturePileImpl( | |
| 55 const PicturePileImpl* other, unsigned thread_index) | |
| 56 : PicturePileBase(other, thread_index), | |
| 57 clones_for_drawing_(ClonesForDrawing(this, 0)) { | |
| 58 } | |
| 59 | |
| 60 PicturePileImpl::~PicturePileImpl() { | |
| 61 } | |
| 62 | |
| 63 PicturePileImpl* PicturePileImpl::GetCloneForDrawingOnThread( | |
| 64 unsigned thread_index) const { | |
| 65 CHECK_GT(clones_for_drawing_.clones_.size(), thread_index); | |
| 66 return clones_for_drawing_.clones_[thread_index]; | |
| 67 } | |
| 68 | |
| 69 void PicturePileImpl::Raster( | |
| 70 SkCanvas* canvas, | |
| 71 gfx::Rect canvas_rect, | |
| 72 float contents_scale, | |
| 73 int64* total_pixels_rasterized) { | |
| 74 | |
| 75 DCHECK(contents_scale >= min_contents_scale_); | |
| 76 | |
| 77 #ifndef NDEBUG | |
| 78 // Any non-painted areas will be left in this color. | |
| 79 canvas->clear(DebugColors::NonPaintedFillColor()); | |
| 80 #endif // NDEBUG | |
| 81 | |
| 82 canvas->save(); | |
| 83 canvas->translate(-canvas_rect.x(), -canvas_rect.y()); | |
| 84 | |
| 85 gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(), | |
| 86 contents_scale); | |
| 87 gfx::Rect total_content_rect(gfx::ToCeiledSize(total_content_size)); | |
| 88 gfx::Rect content_rect = total_content_rect; | |
| 89 content_rect.Intersect(canvas_rect); | |
| 90 | |
| 91 // Clear one texel inside the right/bottom edge of the content rect, | |
| 92 // as it may only be partially covered by the picture playback. | |
| 93 // Also clear one texel outside the right/bottom edge of the content rect, | |
| 94 // as it may get blended in by linear filtering when zoomed in. | |
| 95 gfx::Rect deflated_content_rect = total_content_rect; | |
| 96 deflated_content_rect.Inset(0, 0, 1, 1); | |
| 97 | |
| 98 gfx::Rect canvas_outside_content_rect = canvas_rect; | |
| 99 canvas_outside_content_rect.Subtract(deflated_content_rect); | |
| 100 | |
| 101 if (!canvas_outside_content_rect.IsEmpty()) { | |
| 102 gfx::Rect inflated_content_rect = total_content_rect; | |
| 103 inflated_content_rect.Inset(0, 0, -1, -1); | |
| 104 canvas->clipRect(gfx::RectToSkRect(inflated_content_rect), | |
| 105 SkRegion::kReplace_Op); | |
| 106 canvas->clipRect(gfx::RectToSkRect(deflated_content_rect), | |
| 107 SkRegion::kDifference_Op); | |
| 108 canvas->drawColor(background_color_, SkXfermode::kSrc_Mode); | |
| 109 } | |
| 110 | |
| 111 // Rasterize the collection of relevant picture piles. | |
| 112 gfx::Rect layer_rect = gfx::ToEnclosingRect( | |
| 113 gfx::ScaleRect(content_rect, 1.f / contents_scale)); | |
| 114 | |
| 115 canvas->clipRect(gfx::RectToSkRect(content_rect), | |
| 116 SkRegion::kReplace_Op); | |
| 117 Region unclipped(content_rect); | |
| 118 for (TilingData::Iterator tile_iter(&tiling_, layer_rect); | |
| 119 tile_iter; ++tile_iter) { | |
| 120 PictureListMap::iterator map_iter = | |
| 121 picture_list_map_.find(tile_iter.index()); | |
| 122 if (map_iter == picture_list_map_.end()) | |
| 123 continue; | |
| 124 PictureList& pic_list= map_iter->second; | |
| 125 if (pic_list.empty()) | |
| 126 continue; | |
| 127 | |
| 128 // Raster through the picture list top down, using clips to make sure that | |
| 129 // pictures on top are not overdrawn by pictures on the bottom. | |
| 130 for (PictureList::reverse_iterator i = pic_list.rbegin(); | |
| 131 i != pic_list.rend(); ++i) { | |
| 132 // This is intentionally *enclosed* rect, so that the clip is aligned on | |
| 133 // integral post-scale content pixels and does not extend past the edges | |
| 134 // of the picture's layer rect. The min_contents_scale enforces that | |
| 135 // enough buffer pixels have been added such that the enclosed rect | |
| 136 // encompasses all invalidated pixels at any larger scale level. | |
| 137 gfx::Rect content_clip = gfx::ToEnclosedRect( | |
| 138 gfx::ScaleRect((*i)->LayerRect(), contents_scale)); | |
| 139 DCHECK(!content_clip.IsEmpty()); | |
| 140 if (!unclipped.Intersects(content_clip)) | |
| 141 continue; | |
| 142 | |
| 143 if (slow_down_raster_scale_factor_for_debug_) { | |
| 144 for (int j = 0; j < slow_down_raster_scale_factor_for_debug_; ++j) | |
| 145 (*i)->Raster(canvas, content_clip, contents_scale); | |
| 146 } else { | |
| 147 (*i)->Raster(canvas, content_clip, contents_scale); | |
| 148 } | |
| 149 | |
| 150 // Don't allow pictures underneath to draw where this picture did. | |
| 151 canvas->clipRect( | |
| 152 gfx::RectToSkRect(content_clip), | |
| 153 SkRegion::kDifference_Op); | |
| 154 unclipped.Subtract(content_clip); | |
| 155 | |
| 156 *total_pixels_rasterized += | |
| 157 content_clip.width() * content_clip.height(); | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 #ifndef NDEBUG | |
| 162 // Fill the remaining clip with debug color. This allows us to | |
| 163 // distinguish between non painted areas and problems with missing | |
| 164 // pictures. | |
| 165 SkPaint paint; | |
| 166 paint.setColor(DebugColors::MissingPictureFillColor()); | |
| 167 paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
| 168 canvas->drawPaint(paint); | |
| 169 #endif // NDEBUG | |
| 170 | |
| 171 // We should always paint some part of |content_rect|. | |
| 172 DCHECK(!unclipped.Contains(content_rect)); | |
| 173 | |
| 174 canvas->restore(); | |
| 175 } | |
| 176 | |
| 177 void PicturePileImpl::GatherPixelRefs( | |
| 178 gfx::Rect content_rect, | |
| 179 float contents_scale, | |
| 180 std::list<skia::LazyPixelRef*>& pixel_refs) { | |
| 181 std::list<skia::LazyPixelRef*> result; | |
| 182 | |
| 183 gfx::Rect layer_rect = gfx::ToEnclosingRect( | |
| 184 gfx::ScaleRect(content_rect, 1.f / contents_scale)); | |
| 185 | |
| 186 for (TilingData::Iterator tile_iter(&tiling_, layer_rect); | |
| 187 tile_iter; ++tile_iter) { | |
| 188 PictureListMap::iterator map_iter = | |
| 189 picture_list_map_.find(tile_iter.index()); | |
| 190 if (map_iter == picture_list_map_.end()) | |
| 191 continue; | |
| 192 | |
| 193 PictureList& pic_list = map_iter->second; | |
| 194 for (PictureList::const_iterator i = pic_list.begin(); | |
| 195 i != pic_list.end(); ++i) { | |
| 196 (*i)->GatherPixelRefs(layer_rect, result); | |
| 197 pixel_refs.splice(pixel_refs.end(), result); | |
| 198 } | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { | |
| 203 TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture"); | |
| 204 | |
| 205 gfx::Rect layer_rect(tiling_.total_size()); | |
| 206 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); | |
| 207 if (layer_rect.IsEmpty()) | |
| 208 return picture; | |
| 209 | |
| 210 SkCanvas* canvas = picture->beginRecording( | |
| 211 layer_rect.width(), | |
| 212 layer_rect.height(), | |
| 213 SkPicture::kUsePathBoundsForClip_RecordingFlag); | |
| 214 | |
| 215 int64 total_pixels_rasterized = 0; | |
| 216 Raster(canvas, layer_rect, 1.0, &total_pixels_rasterized); | |
| 217 picture->endRecording(); | |
| 218 | |
| 219 return picture; | |
| 220 } | |
| 221 | |
| 222 void PicturePileImpl::AnalyzeInRect(const gfx::Rect& content_rect, | |
| 223 float contents_scale, | |
| 224 PicturePileImpl::Analysis* analysis) { | |
| 225 DCHECK(analysis); | |
| 226 TRACE_EVENT0("cc", "PicturePileImpl::AnalyzeInRect"); | |
| 227 | |
| 228 gfx::Rect layer_rect = gfx::ToEnclosingRect( | |
| 229 gfx::ScaleRect(content_rect, 1.f / contents_scale)); | |
| 230 | |
| 231 SkBitmap emptyBitmap; | |
| 232 emptyBitmap.setConfig(SkBitmap::kNo_Config, content_rect.width(), | |
| 233 content_rect.height()); | |
| 234 skia::AnalysisDevice device(emptyBitmap); | |
| 235 skia::AnalysisCanvas canvas(&device); | |
| 236 | |
| 237 int64 total_pixels_rasterized = 0; | |
| 238 Raster(&canvas, content_rect, contents_scale, &total_pixels_rasterized); | |
| 239 | |
| 240 analysis->is_transparent = canvas.isTransparent(); | |
| 241 analysis->is_solid_color = canvas.getColorIfSolid(&analysis->solid_color); | |
| 242 analysis->is_cheap_to_raster = canvas.isCheap(); | |
| 243 } | |
| 244 | |
| 245 PicturePileImpl::Analysis::Analysis() : | |
| 246 is_solid_color(false), | |
| 247 is_transparent(false), | |
| 248 is_cheap_to_raster(false) { | |
| 249 } | |
| 250 | |
| 251 } // namespace cc | |
| OLD | NEW |