| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "cc/playback/raster_source.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include "base/trace_event/trace_event.h" | |
| 10 #include "cc/base/math_util.h" | |
| 11 #include "cc/base/region.h" | |
| 12 #include "cc/debug/debug_colors.h" | |
| 13 #include "cc/debug/traced_value.h" | |
| 14 #include "cc/playback/display_item_list.h" | |
| 15 #include "cc/playback/image_hijack_canvas.h" | |
| 16 #include "cc/playback/skip_image_canvas.h" | |
| 17 #include "skia/ext/analysis_canvas.h" | |
| 18 #include "third_party/skia/include/core/SkCanvas.h" | |
| 19 #include "third_party/skia/include/core/SkColorSpaceXformCanvas.h" | |
| 20 #include "third_party/skia/include/core/SkPictureRecorder.h" | |
| 21 #include "ui/gfx/geometry/rect_conversions.h" | |
| 22 | |
| 23 namespace cc { | |
| 24 | |
| 25 scoped_refptr<RasterSource> RasterSource::CreateFromRecordingSource( | |
| 26 const RecordingSource* other, | |
| 27 bool can_use_lcd_text) { | |
| 28 return make_scoped_refptr(new RasterSource(other, can_use_lcd_text)); | |
| 29 } | |
| 30 | |
| 31 RasterSource::RasterSource(const RecordingSource* other, bool can_use_lcd_text) | |
| 32 : display_list_(other->display_list_), | |
| 33 painter_reported_memory_usage_(other->painter_reported_memory_usage_), | |
| 34 background_color_(other->background_color_), | |
| 35 requires_clear_(other->requires_clear_), | |
| 36 can_use_lcd_text_(can_use_lcd_text), | |
| 37 is_solid_color_(other->is_solid_color_), | |
| 38 solid_color_(other->solid_color_), | |
| 39 recorded_viewport_(other->recorded_viewport_), | |
| 40 size_(other->size_), | |
| 41 clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), | |
| 42 slow_down_raster_scale_factor_for_debug_( | |
| 43 other->slow_down_raster_scale_factor_for_debug_), | |
| 44 image_decode_cache_(nullptr) {} | |
| 45 | |
| 46 RasterSource::RasterSource(const RasterSource* other, bool can_use_lcd_text) | |
| 47 : display_list_(other->display_list_), | |
| 48 painter_reported_memory_usage_(other->painter_reported_memory_usage_), | |
| 49 background_color_(other->background_color_), | |
| 50 requires_clear_(other->requires_clear_), | |
| 51 can_use_lcd_text_(can_use_lcd_text), | |
| 52 is_solid_color_(other->is_solid_color_), | |
| 53 solid_color_(other->solid_color_), | |
| 54 recorded_viewport_(other->recorded_viewport_), | |
| 55 size_(other->size_), | |
| 56 clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), | |
| 57 slow_down_raster_scale_factor_for_debug_( | |
| 58 other->slow_down_raster_scale_factor_for_debug_), | |
| 59 image_decode_cache_(other->image_decode_cache_) {} | |
| 60 | |
| 61 RasterSource::~RasterSource() { | |
| 62 } | |
| 63 | |
| 64 void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas, | |
| 65 const gfx::ColorSpace& canvas_color_space, | |
| 66 const gfx::Rect& canvas_bitmap_rect, | |
| 67 const gfx::Rect& canvas_playback_rect, | |
| 68 float raster_scale, | |
| 69 const PlaybackSettings& settings) const { | |
| 70 SkIRect raster_bounds = gfx::RectToSkIRect(canvas_bitmap_rect); | |
| 71 if (!canvas_playback_rect.IsEmpty() && | |
| 72 !raster_bounds.intersect(gfx::RectToSkIRect(canvas_playback_rect))) | |
| 73 return; | |
| 74 // Treat all subnormal values as zero for performance. | |
| 75 ScopedSubnormalFloatDisabler disabler; | |
| 76 | |
| 77 raster_canvas->save(); | |
| 78 raster_canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); | |
| 79 raster_canvas->clipRect(SkRect::MakeFromIRect(raster_bounds)); | |
| 80 raster_canvas->scale(raster_scale, raster_scale); | |
| 81 PlaybackToCanvas(raster_canvas, canvas_color_space, settings); | |
| 82 raster_canvas->restore(); | |
| 83 } | |
| 84 | |
| 85 void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas, | |
| 86 const gfx::ColorSpace& canvas_color_space, | |
| 87 const PlaybackSettings& settings) const { | |
| 88 if (!settings.playback_to_shared_canvas) | |
| 89 PrepareForPlaybackToCanvas(raster_canvas); | |
| 90 | |
| 91 if (settings.skip_images) { | |
| 92 SkipImageCanvas canvas(raster_canvas); | |
| 93 RasterCommon(&canvas, canvas_color_space, nullptr); | |
| 94 } else if (settings.use_image_hijack_canvas) { | |
| 95 const SkImageInfo& info = raster_canvas->imageInfo(); | |
| 96 ImageHijackCanvas canvas(info.width(), info.height(), image_decode_cache_, | |
| 97 &settings.images_to_skip); | |
| 98 // Before adding the canvas, make sure that the ImageHijackCanvas is aware | |
| 99 // of the current transform and clip, which may affect the clip bounds. | |
| 100 // Since we query the clip bounds of the current canvas to get the list of | |
| 101 // draw commands to process, this is important to produce correct content. | |
| 102 canvas.clipRect( | |
| 103 SkRect::MakeFromIRect(raster_canvas->getDeviceClipBounds())); | |
| 104 canvas.setMatrix(raster_canvas->getTotalMatrix()); | |
| 105 canvas.addCanvas(raster_canvas); | |
| 106 | |
| 107 RasterCommon(&canvas, canvas_color_space, nullptr); | |
| 108 } else { | |
| 109 RasterCommon(raster_canvas, canvas_color_space, nullptr); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 namespace { | |
| 114 | |
| 115 bool CanvasIsUnclipped(const SkCanvas* canvas) { | |
| 116 if (!canvas->isClipRect()) | |
| 117 return false; | |
| 118 | |
| 119 SkIRect bounds; | |
| 120 if (!canvas->getDeviceClipBounds(&bounds)) | |
| 121 return false; | |
| 122 | |
| 123 SkISize size = canvas->getBaseLayerSize(); | |
| 124 return bounds.contains(0, 0, size.width(), size.height()); | |
| 125 } | |
| 126 | |
| 127 } // namespace | |
| 128 | |
| 129 void RasterSource::PrepareForPlaybackToCanvas(SkCanvas* canvas) const { | |
| 130 // TODO(hendrikw): See if we can split this up into separate functions. | |
| 131 | |
| 132 if (CanvasIsUnclipped(canvas)) | |
| 133 canvas->discard(); | |
| 134 | |
| 135 // If this raster source has opaque contents, it is guaranteeing that it will | |
| 136 // draw an opaque rect the size of the layer. If it is not, then we must | |
| 137 // clear this canvas ourselves. | |
| 138 if (requires_clear_) { | |
| 139 canvas->clear(SK_ColorTRANSPARENT); | |
| 140 return; | |
| 141 } | |
| 142 | |
| 143 if (clear_canvas_with_debug_color_) | |
| 144 canvas->clear(DebugColors::NonPaintedFillColor()); | |
| 145 | |
| 146 // If the canvas wants us to raster with complex transform, it is hard to | |
| 147 // determine the exact region we must clear. Just clear everything. | |
| 148 // TODO(trchen): Optimize the common case that transformed content bounds | |
| 149 // covers the whole clip region. | |
| 150 if (!canvas->getTotalMatrix().rectStaysRect()) { | |
| 151 canvas->clear(SK_ColorTRANSPARENT); | |
| 152 return; | |
| 153 } | |
| 154 | |
| 155 SkRect content_device_rect; | |
| 156 canvas->getTotalMatrix().mapRect( | |
| 157 &content_device_rect, SkRect::MakeWH(size_.width(), size_.height())); | |
| 158 | |
| 159 // The final texel of content may only be partially covered by a | |
| 160 // rasterization; this rect represents the content rect that is fully | |
| 161 // covered by content. | |
| 162 SkIRect opaque_rect; | |
| 163 content_device_rect.roundIn(&opaque_rect); | |
| 164 | |
| 165 if (opaque_rect.contains(canvas->getDeviceClipBounds())) | |
| 166 return; | |
| 167 | |
| 168 // Even if completely covered, for rasterizations that touch the edge of the | |
| 169 // layer, we also need to raster the background color underneath the last | |
| 170 // texel (since the recording won't cover it) and outside the last texel | |
| 171 // (due to linear filtering when using this texture). | |
| 172 SkIRect interest_rect; | |
| 173 content_device_rect.roundOut(&interest_rect); | |
| 174 interest_rect.outset(1, 1); | |
| 175 | |
| 176 if (clear_canvas_with_debug_color_) { | |
| 177 // Any non-painted areas outside of the content bounds are left in | |
| 178 // this color. If this is seen then it means that cc neglected to | |
| 179 // rerasterize a tile that used to intersect with the content rect | |
| 180 // after the content bounds grew. | |
| 181 canvas->save(); | |
| 182 // Use clipRegion to bypass CTM because the rects are device rects. | |
| 183 SkRegion interest_region; | |
| 184 interest_region.setRect(interest_rect); | |
| 185 canvas->clipRegion(interest_region, SkClipOp::kDifference); | |
| 186 canvas->clear(DebugColors::MissingResizeInvalidations()); | |
| 187 canvas->restore(); | |
| 188 } | |
| 189 | |
| 190 // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X | |
| 191 // faster than clearing, so special case this. | |
| 192 canvas->save(); | |
| 193 // Use clipRegion to bypass CTM because the rects are device rects. | |
| 194 SkRegion interest_region; | |
| 195 interest_region.setRect(interest_rect); | |
| 196 interest_region.op(opaque_rect, SkRegion::kDifference_Op); | |
| 197 canvas->clipRegion(interest_region); | |
| 198 canvas->clear(background_color_); | |
| 199 canvas->restore(); | |
| 200 } | |
| 201 | |
| 202 void RasterSource::RasterCommon(SkCanvas* input_canvas, | |
| 203 const gfx::ColorSpace& target_color_space, | |
| 204 SkPicture::AbortCallback* callback) const { | |
| 205 SkCanvas* raster_canvas = input_canvas; | |
| 206 std::unique_ptr<SkCanvas> color_transform_canvas; | |
| 207 if (target_color_space.IsValid()) { | |
| 208 color_transform_canvas = SkCreateColorSpaceXformCanvas( | |
| 209 input_canvas, target_color_space.ToSkColorSpace()); | |
| 210 raster_canvas = color_transform_canvas.get(); | |
| 211 } | |
| 212 DCHECK(display_list_.get()); | |
| 213 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); | |
| 214 for (int i = 0; i < repeat_count; ++i) | |
| 215 display_list_->Raster(raster_canvas, callback); | |
| 216 } | |
| 217 | |
| 218 sk_sp<SkPicture> RasterSource::GetFlattenedPicture() { | |
| 219 TRACE_EVENT0("cc", "RasterSource::GetFlattenedPicture"); | |
| 220 | |
| 221 SkPictureRecorder recorder; | |
| 222 SkCanvas* canvas = recorder.beginRecording(size_.width(), size_.height()); | |
| 223 if (!size_.IsEmpty()) { | |
| 224 PrepareForPlaybackToCanvas(canvas); | |
| 225 // No target color space should be set for generating an SkPicture. | |
| 226 RasterCommon(canvas, gfx::ColorSpace(), nullptr); | |
| 227 } | |
| 228 | |
| 229 return recorder.finishRecordingAsPicture(); | |
| 230 } | |
| 231 | |
| 232 size_t RasterSource::GetMemoryUsage() const { | |
| 233 if (!display_list_) | |
| 234 return 0; | |
| 235 return display_list_->ApproximateMemoryUsage() + | |
| 236 painter_reported_memory_usage_; | |
| 237 } | |
| 238 | |
| 239 bool RasterSource::PerformSolidColorAnalysis(const gfx::Rect& content_rect, | |
| 240 float contents_scale, | |
| 241 SkColor* color) const { | |
| 242 TRACE_EVENT0("cc", "RasterSource::PerformSolidColorAnalysis"); | |
| 243 | |
| 244 gfx::Rect layer_rect = | |
| 245 gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale); | |
| 246 | |
| 247 layer_rect.Intersect(gfx::Rect(size_)); | |
| 248 skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height()); | |
| 249 canvas.translate(-layer_rect.x(), -layer_rect.y()); | |
| 250 // No target color space should be set for solid color analysis (the | |
| 251 // resulting solid color will be known to be sRGB). | |
| 252 RasterCommon(&canvas, gfx::ColorSpace(), &canvas); | |
| 253 return canvas.GetColorIfSolid(color); | |
| 254 } | |
| 255 | |
| 256 void RasterSource::GetDiscardableImagesInRect( | |
| 257 const gfx::Rect& layer_rect, | |
| 258 float contents_scale, | |
| 259 std::vector<DrawImage>* images) const { | |
| 260 DCHECK_EQ(0u, images->size()); | |
| 261 display_list_->GetDiscardableImagesInRect(layer_rect, contents_scale, images); | |
| 262 } | |
| 263 | |
| 264 gfx::Rect RasterSource::GetRectForImage(ImageId image_id) const { | |
| 265 if (!display_list_) | |
| 266 return gfx::Rect(); | |
| 267 return display_list_->GetRectForImage(image_id); | |
| 268 } | |
| 269 | |
| 270 bool RasterSource::CoversRect(const gfx::Rect& layer_rect) const { | |
| 271 if (size_.IsEmpty()) | |
| 272 return false; | |
| 273 gfx::Rect bounded_rect = layer_rect; | |
| 274 bounded_rect.Intersect(gfx::Rect(size_)); | |
| 275 return recorded_viewport_.Contains(bounded_rect); | |
| 276 } | |
| 277 | |
| 278 gfx::Size RasterSource::GetSize() const { | |
| 279 return size_; | |
| 280 } | |
| 281 | |
| 282 bool RasterSource::IsSolidColor() const { | |
| 283 return is_solid_color_; | |
| 284 } | |
| 285 | |
| 286 SkColor RasterSource::GetSolidColor() const { | |
| 287 DCHECK(IsSolidColor()); | |
| 288 return solid_color_; | |
| 289 } | |
| 290 | |
| 291 bool RasterSource::HasRecordings() const { | |
| 292 return !!display_list_.get(); | |
| 293 } | |
| 294 | |
| 295 gfx::Rect RasterSource::RecordedViewport() const { | |
| 296 return recorded_viewport_; | |
| 297 } | |
| 298 | |
| 299 void RasterSource::AsValueInto(base::trace_event::TracedValue* array) const { | |
| 300 if (display_list_.get()) | |
| 301 TracedValue::AppendIDRef(display_list_.get(), array); | |
| 302 } | |
| 303 | |
| 304 void RasterSource::DidBeginTracing() { | |
| 305 if (display_list_.get()) | |
| 306 display_list_->EmitTraceSnapshot(); | |
| 307 } | |
| 308 | |
| 309 bool RasterSource::CanUseLCDText() const { | |
| 310 return can_use_lcd_text_; | |
| 311 } | |
| 312 | |
| 313 scoped_refptr<RasterSource> RasterSource::CreateCloneWithoutLCDText() const { | |
| 314 bool can_use_lcd_text = false; | |
| 315 return scoped_refptr<RasterSource>(new RasterSource(this, can_use_lcd_text)); | |
| 316 } | |
| 317 | |
| 318 RasterSource::PlaybackSettings::PlaybackSettings() | |
| 319 : playback_to_shared_canvas(false), | |
| 320 skip_images(false), | |
| 321 use_image_hijack_canvas(true) {} | |
| 322 | |
| 323 RasterSource::PlaybackSettings::PlaybackSettings(const PlaybackSettings&) = | |
| 324 default; | |
| 325 | |
| 326 RasterSource::PlaybackSettings::PlaybackSettings(PlaybackSettings&&) = default; | |
| 327 | |
| 328 RasterSource::PlaybackSettings::~PlaybackSettings() = default; | |
| 329 | |
| 330 } // namespace cc | |
| OLD | NEW |