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 "cc/layers/picture_layer.h" 6 7#include "cc/layers/content_layer_client.h" 8#include "cc/layers/picture_layer_impl.h" 9#include "cc/trees/layer_tree_impl.h" 10#include "third_party/skia/include/core/SkPictureRecorder.h" 11#include "ui/gfx/rect_conversions.h" 12 13namespace cc { 14 15scoped_refptr<PictureLayer> PictureLayer::Create(ContentLayerClient* client) { 16 return make_scoped_refptr(new PictureLayer(client)); 17} 18 19PictureLayer::PictureLayer(ContentLayerClient* client) 20 : client_(client), 21 pile_(make_scoped_refptr(new PicturePile())), 22 instrumentation_object_tracker_(id()), 23 is_mask_(false), 24 update_source_frame_number_(-1), 25 can_use_lcd_text_last_frame_(can_use_lcd_text()) { 26} 27 28PictureLayer::~PictureLayer() { 29} 30 31bool PictureLayer::DrawsContent() const { 32 return Layer::DrawsContent() && client_; 33} 34 35scoped_ptr<LayerImpl> PictureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) { 36 return PictureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); 37} 38 39void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) { 40 Layer::PushPropertiesTo(base_layer); 41 PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); 42 43 if (layer_impl->bounds().IsEmpty()) { 44 // Update may not get called for an empty layer, so resize here instead. 45 // Using layer_impl because either bounds() or paint_properties().bounds 46 // may disagree and either one could have been pushed to layer_impl. 47 pile_->SetTilingRect(gfx::Rect()); 48 } else if (update_source_frame_number_ == 49 layer_tree_host()->source_frame_number()) { 50 // TODO(ernstm): This DCHECK is only valid as long as the pile's tiling_rect 51 // is identical to the layer_rect. 52 // If update called, then pile size must match bounds pushed to impl layer. 53 DCHECK_EQ(layer_impl->bounds().ToString(), 54 pile_->tiling_rect().size().ToString()); 55 } 56 57 layer_impl->SetIsMask(is_mask_); 58 59 // Unlike other properties, invalidation must always be set on layer_impl. 60 // See PictureLayerImpl::PushPropertiesTo for more details. 61 layer_impl->invalidation_.Clear(); 62 layer_impl->invalidation_.Swap(&pile_invalidation_); 63 layer_impl->pile_ = PicturePileImpl::CreateFromOther(pile_.get()); 64} 65 66void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) { 67 Layer::SetLayerTreeHost(host); 68 if (host) { 69 pile_->SetMinContentsScale(host->settings().minimum_contents_scale); 70 pile_->SetTileGridSize(host->settings().default_tile_size); 71 pile_->set_slow_down_raster_scale_factor( 72 host->debug_state().slow_down_raster_scale_factor); 73 pile_->set_show_debug_picture_borders( 74 host->debug_state().show_picture_borders); 75 } 76} 77 78void PictureLayer::SetNeedsDisplayRect(const gfx::RectF& layer_rect) { 79 gfx::Rect rect = gfx::ToEnclosedRect(layer_rect); 80 if (!rect.IsEmpty()) { 81 // Clamp invalidation to the layer bounds. 82 rect.Intersect(gfx::Rect(bounds())); 83 pending_invalidation_.Union(rect); 84 } 85 Layer::SetNeedsDisplayRect(layer_rect); 86} 87 88bool PictureLayer::Update(ResourceUpdateQueue* queue, 89 const OcclusionTracker<Layer>* occlusion) { 90 update_source_frame_number_ = layer_tree_host()->source_frame_number(); 91 bool updated = Layer::Update(queue, occlusion); 92 93 UpdateCanUseLCDText(); 94 95 gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect( 96 visible_content_rect(), 1.f / contents_scale_x()); 97 98 gfx::Rect layer_rect = gfx::Rect(paint_properties().bounds); 99 100 if (last_updated_visible_content_rect_ == visible_content_rect() && 101 pile_->tiling_rect() == layer_rect && pending_invalidation_.IsEmpty()) { 102 // Only early out if the visible content rect of this layer hasn't changed. 103 return updated; 104 } 105 106 TRACE_EVENT1("cc", "PictureLayer::Update", 107 "source_frame_number", 108 layer_tree_host()->source_frame_number()); 109 devtools_instrumentation::ScopedLayerTreeTask update_layer( 110 devtools_instrumentation::kUpdateLayer, id(), layer_tree_host()->id()); 111 112 pile_->SetTilingRect(layer_rect); 113 114 // Calling paint in WebKit can sometimes cause invalidations, so save 115 // off the invalidation prior to calling update. 116 pending_invalidation_.Swap(&pile_invalidation_); 117 pending_invalidation_.Clear(); 118 119 if (layer_tree_host()->settings().record_full_layer) { 120 // Workaround for http://crbug.com/235910 - to retain backwards compat 121 // the full page content must always be provided in the picture layer. 122 visible_layer_rect = gfx::Rect(bounds()); 123 } 124 125 // UpdateAndExpandInvalidation will give us an invalidation that covers 126 // anything not explicitly recorded in this frame. We give this region 127 // to the impl side so that it drops tiles that may not have a recording 128 // for them. 129 DCHECK(client_); 130 updated |= 131 pile_->UpdateAndExpandInvalidation(client_, 132 &pile_invalidation_, 133 SafeOpaqueBackgroundColor(), 134 contents_opaque(), 135 client_->FillsBoundsCompletely(), 136 visible_layer_rect, 137 update_source_frame_number_, 138 RecordingMode(), 139 rendering_stats_instrumentation()); 140 last_updated_visible_content_rect_ = visible_content_rect(); 141 142 if (updated) { 143 SetNeedsPushProperties(); 144 } else { 145 // If this invalidation did not affect the pile, then it can be cleared as 146 // an optimization. 147 pile_invalidation_.Clear(); 148 } 149 150 return updated; 151} 152 153void PictureLayer::SetIsMask(bool is_mask) { 154 is_mask_ = is_mask; 155} 156 157Picture::RecordingMode PictureLayer::RecordingMode() const { 158 switch (layer_tree_host()->settings().recording_mode) { 159 case LayerTreeSettings::RecordNormally: 160 return Picture::RECORD_NORMALLY; 161 case LayerTreeSettings::RecordWithSkRecord: 162 return Picture::RECORD_WITH_SKRECORD; 163 } 164 NOTREACHED(); 165 return Picture::RECORD_NORMALLY; 166} 167 168bool PictureLayer::SupportsLCDText() const { 169 return true; 170} 171 172void PictureLayer::UpdateCanUseLCDText() { 173 if (can_use_lcd_text_last_frame_ == can_use_lcd_text()) 174 return; 175 176 can_use_lcd_text_last_frame_ = can_use_lcd_text(); 177 if (client_) 178 client_->DidChangeLayerCanUseLCDText(); 179} 180 181skia::RefPtr<SkPicture> PictureLayer::GetPicture() const { 182 // We could either flatten the PicturePile into a single SkPicture, 183 // or paint a fresh one depending on what we intend to do with the 184 // picture. For now we just paint a fresh one to get consistent results. 185 if (!DrawsContent()) 186 return skia::RefPtr<SkPicture>(); 187 188 int width = bounds().width(); 189 int height = bounds().height(); 190 gfx::RectF opaque; 191 192 SkPictureRecorder recorder; 193 SkCanvas* canvas = recorder.beginRecording(width, height, NULL, 0); 194 client_->PaintContents(canvas, 195 gfx::Rect(width, height), 196 &opaque, 197 ContentLayerClient::GRAPHICS_CONTEXT_ENABLED); 198 skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording()); 199 return picture; 200} 201 202bool PictureLayer::IsSuitableForGpuRasterization() const { 203 return pile_->is_suitable_for_gpu_rasterization(); 204} 205 206void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) { 207 benchmark->RunOnLayer(this); 208} 209 210} // namespace cc 211