summaryrefslogtreecommitdiff
path: root/chromium/cc/layers
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/layers')
-rw-r--r--chromium/cc/layers/compositing_reasons.h3
-rw-r--r--chromium/cc/layers/content_layer.cc26
-rw-r--r--chromium/cc/layers/content_layer.h2
-rw-r--r--chromium/cc/layers/delegated_renderer_layer.cc112
-rw-r--r--chromium/cc/layers/delegated_renderer_layer.h25
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl.cc136
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl.h21
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc128
-rw-r--r--chromium/cc/layers/draw_properties.h5
-rw-r--r--chromium/cc/layers/heads_up_display_layer.cc4
-rw-r--r--chromium/cc/layers/heads_up_display_layer.h4
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc5
-rw-r--r--chromium/cc/layers/image_layer.cc5
-rw-r--r--chromium/cc/layers/io_surface_layer_impl.cc16
-rw-r--r--chromium/cc/layers/layer.cc211
-rw-r--r--chromium/cc/layers/layer.h85
-rw-r--r--chromium/cc/layers/layer_client.h24
-rw-r--r--chromium/cc/layers/layer_impl.cc312
-rw-r--r--chromium/cc/layers/layer_impl.h71
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc6
-rw-r--r--chromium/cc/layers/layer_unittest.cc3
-rw-r--r--chromium/cc/layers/nine_patch_layer.cc168
-rw-r--r--chromium/cc/layers/nine_patch_layer.h43
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl.cc307
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl.h42
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl_unittest.cc199
-rw-r--r--chromium/cc/layers/nine_patch_layer_unittest.cc102
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc244
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.h (renamed from chromium/cc/layers/scrollbar_layer.h)75
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc181
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.h82
-rw-r--r--chromium/cc/layers/picture_layer.cc47
-rw-r--r--chromium/cc/layers/picture_layer.h1
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc214
-rw-r--r--chromium/cc/layers/picture_layer_impl.h14
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc179
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc69
-rw-r--r--chromium/cc/layers/scrollbar_layer.cc353
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl.cc328
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl.h103
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.cc170
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.h91
-rw-r--r--chromium/cc/layers/scrollbar_layer_interface.h30
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc389
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.cc68
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.h54
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl.cc88
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl.h52
-rw-r--r--chromium/cc/layers/texture_layer.cc100
-rw-r--r--chromium/cc/layers/texture_layer.h116
-rw-r--r--chromium/cc/layers/texture_layer_client.h8
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc24
-rw-r--r--chromium/cc/layers/texture_layer_impl.h5
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc1120
-rw-r--r--chromium/cc/layers/tiled_layer.cc10
-rw-r--r--chromium/cc/layers/tiled_layer.h8
-rw-r--r--chromium/cc/layers/tiled_layer_unittest.cc48
-rw-r--r--chromium/cc/layers/video_layer_impl.cc17
-rw-r--r--chromium/cc/layers/video_layer_impl.h4
59 files changed, 4448 insertions, 1909 deletions
diff --git a/chromium/cc/layers/compositing_reasons.h b/chromium/cc/layers/compositing_reasons.h
index 28c2f7b4dc6..02354a03283 100644
--- a/chromium/cc/layers/compositing_reasons.h
+++ b/chromium/cc/layers/compositing_reasons.h
@@ -22,7 +22,6 @@ const uint64 kCompositingReasonFilters = GG_UINT64_C(1) << 7;
const uint64 kCompositingReasonPositionFixed = GG_UINT64_C(1) << 8;
const uint64 kCompositingReasonPositionSticky = GG_UINT64_C(1) << 9;
const uint64 kCompositingReasonOverflowScrollingTouch = GG_UINT64_C(1) << 10;
-const uint64 kCompositingReasonBlending = GG_UINT64_C(1) << 11;
const uint64 kCompositingReasonAssumedOverlap = GG_UINT64_C(1) << 12;
const uint64 kCompositingReasonOverlap = GG_UINT64_C(1) << 13;
const uint64 kCompositingReasonNegativeZIndexChildren = GG_UINT64_C(1) << 14;
@@ -52,6 +51,8 @@ const uint64 kCompositingReasonLayerForScrollingContainer =
const uint64 kCompositingReasonLayerForForeground = GG_UINT64_C(1) << 29;
const uint64 kCompositingReasonLayerForBackground = GG_UINT64_C(1) << 30;
const uint64 kCompositingReasonLayerForMask = GG_UINT64_C(1) << 31;
+const uint64 kCompositingReasonOverflowScrollingParent = GG_UINT64_C(1) << 32;
+const uint64 kCompositingReasonOutOfFlowClipping = GG_UINT64_C(1) << 33;
typedef uint64 CompositingReasons;
diff --git a/chromium/cc/layers/content_layer.cc b/chromium/cc/layers/content_layer.cc
index 2053ecbeac1..3d611eeef28 100644
--- a/chromium/cc/layers/content_layer.cc
+++ b/chromium/cc/layers/content_layer.cc
@@ -29,6 +29,12 @@ void ContentLayerPainter::Paint(SkCanvas* canvas,
base::TimeTicks paint_start = base::TimeTicks::HighResNow();
client_->PaintContents(canvas, content_rect, opaque);
base::TimeTicks paint_end = base::TimeTicks::HighResNow();
+ // The start and end times might be the same if the paint was very fast or if
+ // our timer granularity is poor. Treat this as a very short time duration
+ // instead of none to avoid dividing by zero.
+ if (paint_end == paint_start)
+ paint_end += base::TimeDelta::FromMicroseconds(1);
+
double pixels_per_sec = (content_rect.width() * content_rect.height()) /
(paint_end - paint_start).InSecondsF();
UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.AccelContentPaintDurationMS",
@@ -121,9 +127,8 @@ void ContentLayer::CreateUpdaterIfNeeded() {
}
updater_->SetOpaque(contents_opaque());
- unsigned texture_format =
- layer_tree_host()->GetRendererCapabilities().best_texture_format;
- SetTextureFormat(texture_format);
+ SetTextureFormat(
+ layer_tree_host()->GetRendererCapabilities().best_texture_format);
}
void ContentLayer::SetContentsOpaque(bool opaque) {
@@ -145,4 +150,19 @@ bool ContentLayer::SupportsLCDText() const {
return true;
}
+skia::RefPtr<SkPicture> ContentLayer::GetPicture() const {
+ if (!DrawsContent())
+ return skia::RefPtr<SkPicture>();
+
+ int width = bounds().width();
+ int height = bounds().height();
+ gfx::RectF opaque;
+
+ skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
+ SkCanvas* canvas = picture->beginRecording(width, height);
+ client_->PaintContents(canvas, gfx::Rect(width, height), &opaque);
+ picture->endRecording();
+ return picture;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/content_layer.h b/chromium/cc/layers/content_layer.h
index f49215b6b40..a076c31dcac 100644
--- a/chromium/cc/layers/content_layer.h
+++ b/chromium/cc/layers/content_layer.h
@@ -52,6 +52,8 @@ class CC_EXPORT ContentLayer : public TiledLayer {
virtual bool SupportsLCDText() const OVERRIDE;
+ virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE;
+
protected:
explicit ContentLayer(ContentLayerClient* client);
virtual ~ContentLayer();
diff --git a/chromium/cc/layers/delegated_renderer_layer.cc b/chromium/cc/layers/delegated_renderer_layer.cc
index 66064d9e849..cc49c753e25 100644
--- a/chromium/cc/layers/delegated_renderer_layer.cc
+++ b/chromium/cc/layers/delegated_renderer_layer.cc
@@ -7,6 +7,9 @@
#include "cc/layers/delegated_renderer_layer_client.h"
#include "cc/layers/delegated_renderer_layer_impl.h"
#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/trees/blocking_task_runner.h"
+#include "cc/trees/layer_tree_host.h"
namespace cc {
@@ -19,7 +22,10 @@ scoped_refptr<DelegatedRendererLayer> DelegatedRendererLayer::Create(
DelegatedRendererLayer::DelegatedRendererLayer(
DelegatedRendererLayerClient* client)
: Layer(),
- client_(client) {}
+ client_(client),
+ needs_filter_context_(false),
+ main_thread_runner_(BlockingTaskRunner::current()),
+ weak_ptrs_(this) {}
DelegatedRendererLayer::~DelegatedRendererLayer() {}
@@ -29,6 +35,26 @@ scoped_ptr<LayerImpl> DelegatedRendererLayer::CreateLayerImpl(
tree_impl, layer_id_).PassAs<LayerImpl>();
}
+void DelegatedRendererLayer::SetLayerTreeHost(LayerTreeHost* host) {
+ if (layer_tree_host() == host) {
+ Layer::SetLayerTreeHost(host);
+ return;
+ }
+
+ if (!host) {
+ // The active frame needs to be removed from the active tree and resources
+ // returned before the commit is called complete.
+ // TODO(danakj): Don't need to do this if the last frame commited was empty
+ // or we never commited a frame with resources.
+ SetNextCommitWaitsForActivation();
+ } else {
+ if (needs_filter_context_)
+ host->set_needs_filter_context();
+ }
+
+ Layer::SetLayerTreeHost(host);
+}
+
bool DelegatedRendererLayer::DrawsContent() const {
return Layer::DrawsContent() && !frame_size_.IsEmpty();
}
@@ -41,19 +67,23 @@ void DelegatedRendererLayer::PushPropertiesTo(LayerImpl* impl) {
delegated_impl->SetDisplaySize(display_size_);
+ delegated_impl->CreateChildIdIfNeeded(
+ base::Bind(&DelegatedRendererLayer::ReceiveUnusedResourcesOnImplThread,
+ main_thread_runner_,
+ weak_ptrs_.GetWeakPtr()));
+
if (frame_data_)
delegated_impl->SetFrameData(frame_data_.Pass(), damage_in_frame_);
frame_data_.reset();
damage_in_frame_ = gfx::RectF();
- delegated_impl->CollectUnusedResources(
- &unused_resources_for_child_compositor_);
-
+ // The ResourceProvider will have the new frame as soon as we push it to the
+ // pending tree. So unused resources will be returned as well.
if (client_)
client_->DidCommitFrameData();
- // TODO(danakj): TakeUnusedResourcesForChildCompositor requires a push
- // properties to happen in order to collect unused resources returned
+ // TODO(danakj): The DidCommitFrameData() notification requires a push
+ // properties to happen in order to notify about unused resources returned
// from the parent compositor. crbug.com/259090
needs_push_properties_ = true;
}
@@ -67,48 +97,74 @@ void DelegatedRendererLayer::SetDisplaySize(gfx::Size size) {
void DelegatedRendererLayer::SetFrameData(
scoped_ptr<DelegatedFrameData> new_frame_data) {
+ DCHECK(new_frame_data);
+
if (frame_data_) {
- // Copy the resources from the last provided frame into the new frame, as
- // it may use resources that were transferred in the last frame.
- new_frame_data->resource_list.insert(new_frame_data->resource_list.end(),
- frame_data_->resource_list.begin(),
- frame_data_->resource_list.end());
+ // Copy the resources from the last provided frame into the unused resources
+ // list, as the new frame will provide its own resources.
+ TransferableResource::ReturnResources(
+ frame_data_->resource_list,
+ &unused_resources_for_child_compositor_);
}
frame_data_ = new_frame_data.Pass();
if (!frame_data_->render_pass_list.empty()) {
RenderPass* root_pass = frame_data_->render_pass_list.back();
damage_in_frame_.Union(root_pass->damage_rect);
frame_size_ = root_pass->output_rect.size();
-
- // TODO(danakj): This could be optimized to only add resources to the
- // frame_data_ if they are actually used in the frame. For now, it will
- // cause the parent (this layer) to hold onto some resources it doesn't
- // need to for an extra frame.
- for (size_t i = 0; i < unused_resources_for_child_compositor_.size(); ++i) {
- frame_data_->resource_list.push_back(
- unused_resources_for_child_compositor_[i]);
- }
- unused_resources_for_child_compositor_.clear();
} else {
frame_size_ = gfx::Size();
}
+
+ // If any RenderPassDrawQuad has a filter operation, then we need a filter
+ // context to draw this layer's content.
+ for (size_t i = 0;
+ !needs_filter_context_ && i < frame_data_->render_pass_list.size();
+ ++i) {
+ const QuadList& quad_list = frame_data_->render_pass_list[i]->quad_list;
+ for (size_t j = 0; !needs_filter_context_ && j < quad_list.size(); ++j) {
+ if (quad_list[j]->material != DrawQuad::RENDER_PASS)
+ continue;
+ const RenderPassDrawQuad* render_pass_quad =
+ RenderPassDrawQuad::MaterialCast(quad_list[j]);
+ if (!render_pass_quad->filters.IsEmpty() ||
+ !render_pass_quad->background_filters.IsEmpty())
+ needs_filter_context_ = true;
+ }
+ }
+ if (needs_filter_context_ && layer_tree_host())
+ layer_tree_host()->set_needs_filter_context();
+
SetNeedsCommit();
+ // The active frame needs to be replaced and resources returned before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
void DelegatedRendererLayer::TakeUnusedResourcesForChildCompositor(
- TransferableResourceArray* array) {
+ ReturnedResourceArray* array) {
DCHECK(array->empty());
array->clear();
array->swap(unused_resources_for_child_compositor_);
}
-bool DelegatedRendererLayer::BlocksPendingCommit() const {
- // The active frame needs to be replaced and resources returned before the
- // commit is called complete. This is true even whenever there may be
- // resources to return, regardless of if the layer will draw in its new
- // state.
- return true;
+void DelegatedRendererLayer::ReceiveUnusedResources(
+ const ReturnedResourceArray& unused) {
+ unused_resources_for_child_compositor_.insert(
+ unused_resources_for_child_compositor_.end(),
+ unused.begin(),
+ unused.end());
+}
+
+// static
+void DelegatedRendererLayer::ReceiveUnusedResourcesOnImplThread(
+ scoped_refptr<BlockingTaskRunner> task_runner,
+ base::WeakPtr<DelegatedRendererLayer> self,
+ const ReturnedResourceArray& unused) {
+ task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &DelegatedRendererLayer::ReceiveUnusedResources, self, unused));
}
} // namespace cc
diff --git a/chromium/cc/layers/delegated_renderer_layer.h b/chromium/cc/layers/delegated_renderer_layer.h
index 3f5280eec5f..60e9c3c05d9 100644
--- a/chromium/cc/layers/delegated_renderer_layer.h
+++ b/chromium/cc/layers/delegated_renderer_layer.h
@@ -5,12 +5,15 @@
#ifndef CC_LAYERS_DELEGATED_RENDERER_LAYER_H_
#define CC_LAYERS_DELEGATED_RENDERER_LAYER_H_
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
#include "cc/base/cc_export.h"
#include "cc/layers/layer.h"
-#include "cc/resources/transferable_resource.h"
+#include "cc/resources/returned_resource.h"
namespace cc {
-
+class BlockingTaskRunner;
class DelegatedFrameData;
class DelegatedRendererLayerClient;
@@ -21,6 +24,7 @@ class CC_EXPORT DelegatedRendererLayer : public Layer {
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
+ virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* impl) OVERRIDE;
virtual bool DrawsContent() const OVERRIDE;
@@ -34,25 +38,34 @@ class CC_EXPORT DelegatedRendererLayer : public Layer {
// Passes ownership of any unused resources that had been given by the child
// compositor to the given array, so they can be given back to the child.
- void TakeUnusedResourcesForChildCompositor(TransferableResourceArray* array);
-
- virtual bool BlocksPendingCommit() const OVERRIDE;
+ void TakeUnusedResourcesForChildCompositor(ReturnedResourceArray* array);
protected:
explicit DelegatedRendererLayer(DelegatedRendererLayerClient* client);
virtual ~DelegatedRendererLayer();
private:
+ void ReceiveUnusedResources(const ReturnedResourceArray& unused);
+ static void ReceiveUnusedResourcesOnImplThread(
+ scoped_refptr<BlockingTaskRunner> task_runner,
+ base::WeakPtr<DelegatedRendererLayer> self,
+ const ReturnedResourceArray& unused);
+
scoped_ptr<DelegatedFrameData> frame_data_;
gfx::RectF damage_in_frame_;
gfx::Size frame_size_;
gfx::Size display_size_;
- TransferableResourceArray unused_resources_for_child_compositor_;
DelegatedRendererLayerClient* client_;
+ bool needs_filter_context_;
+
+ ReturnedResourceArray unused_resources_for_child_compositor_;
+ scoped_refptr<BlockingTaskRunner> main_thread_runner_;
+ base::WeakPtrFactory<DelegatedRendererLayer> weak_ptrs_;
DISALLOW_COPY_AND_ASSIGN(DelegatedRendererLayer);
};
} // namespace cc
+
#endif // CC_LAYERS_DELEGATED_RENDERER_LAYER_H_
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.cc b/chromium/cc/layers/delegated_renderer_layer_impl.cc
index 2dfdac6eb2d..34a1cd86755 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl.cc
+++ b/chromium/cc/layers/delegated_renderer_layer_impl.cc
@@ -47,7 +47,7 @@ bool DelegatedRendererLayerImpl::HasContributingDelegatedRenderPasses() const {
static ResourceProvider::ResourceId ResourceRemapHelper(
bool* invalid_frame,
const ResourceProvider::ResourceIdMap& child_to_parent_map,
- ResourceProvider::ResourceIdSet *remapped_resources,
+ ResourceProvider::ResourceIdArray* resources_in_frame,
ResourceProvider::ResourceId id) {
ResourceProvider::ResourceIdMap::const_iterator it =
@@ -59,7 +59,7 @@ static ResourceProvider::ResourceId ResourceRemapHelper(
DCHECK_EQ(it->first, id);
ResourceProvider::ResourceId remapped_id = it->second;
- remapped_resources->insert(remapped_id);
+ resources_in_frame->push_back(id);
return remapped_id;
}
@@ -85,23 +85,31 @@ void DelegatedRendererLayerImpl::PushPropertiesTo(LayerImpl* layer) {
have_render_passes_to_push_ = false;
}
- // This is just a copy for testing since we keep the data on the pending layer
- // for returning resources to the child for now.
+ // This is just a copy for testing, since resources are added to the
+ // ResourceProvider in the pending tree.
delegated_layer->resources_ = resources_;
}
+void DelegatedRendererLayerImpl::CreateChildIdIfNeeded(
+ const ReturnCallback& return_callback) {
+ if (child_id_)
+ return;
+
+ ResourceProvider* resource_provider = layer_tree_impl()->resource_provider();
+ child_id_ = resource_provider->CreateChild(return_callback);
+ own_child_id_ = true;
+}
+
void DelegatedRendererLayerImpl::SetFrameData(
scoped_ptr<DelegatedFrameData> frame_data,
gfx::RectF damage_in_frame) {
DCHECK(frame_data);
+ DCHECK(child_id_) << "CreateChildIdIfNeeded must be called first.";
// A frame with an empty root render pass is invalid.
DCHECK(frame_data->render_pass_list.empty() ||
!frame_data->render_pass_list.back()->output_rect.IsEmpty());
- CreateChildIdIfNeeded();
- DCHECK(child_id_);
-
ResourceProvider* resource_provider = layer_tree_impl()->resource_provider();
const ResourceProvider::ResourceIdMap& resource_map =
resource_provider->GetChildToParentMap(child_id_);
@@ -109,12 +117,12 @@ void DelegatedRendererLayerImpl::SetFrameData(
resource_provider->ReceiveFromChild(child_id_, frame_data->resource_list);
bool invalid_frame = false;
- ResourceProvider::ResourceIdSet used_resources;
+ ResourceProvider::ResourceIdArray resources_in_frame;
DrawQuad::ResourceIteratorCallback remap_resources_to_parent_callback =
base::Bind(&ResourceRemapHelper,
&invalid_frame,
resource_map,
- &used_resources);
+ &resources_in_frame);
for (size_t i = 0; i < frame_data->render_pass_list.size(); ++i) {
RenderPass* pass = frame_data->render_pass_list[i];
for (size_t j = 0; j < pass->quad_list.size(); ++j) {
@@ -123,8 +131,15 @@ void DelegatedRendererLayerImpl::SetFrameData(
}
}
- if (invalid_frame)
+ if (invalid_frame) {
+ // Declare we are still using the last frame's resources.
+ resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_);
return;
+ }
+
+ // Declare we are using the new frame's resources.
+ resources_.swap(resources_in_frame);
+ resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_);
// Display size is already set so we can compute what the damage rect
// will be in layer space.
@@ -140,33 +155,9 @@ void DelegatedRendererLayerImpl::SetFrameData(
// Save the remapped quads on the layer. This steals the quads and render
// passes from the frame_data.
SetRenderPasses(&frame_data->render_pass_list);
- resources_.swap(used_resources);
have_render_passes_to_push_ = true;
}
-void DelegatedRendererLayerImpl::CollectUnusedResources(
- TransferableResourceArray* resources_for_ack) {
- CreateChildIdIfNeeded();
- DCHECK(child_id_);
-
- ResourceProvider* resource_provider = layer_tree_impl()->resource_provider();
- const ResourceProvider::ResourceIdMap& resource_map =
- resource_provider->GetChildToParentMap(child_id_);
-
- ResourceProvider::ResourceIdArray unused_resources;
- for (ResourceProvider::ResourceIdMap::const_iterator it =
- resource_map.begin();
- it != resource_map.end();
- ++it) {
- bool resource_is_in_current_frame = resources_.count(it->second) > 0;
- bool resource_is_in_use = resource_provider->InUseByConsumer(it->second);
- if (!resource_is_in_current_frame && !resource_is_in_use)
- unused_resources.push_back(it->second);
- }
- resource_provider->PrepareSendToChild(
- child_id_, unused_resources, resources_for_ack);
-}
-
void DelegatedRendererLayerImpl::SetDisplaySize(gfx::Size size) {
if (display_size_ == size)
return;
@@ -176,10 +167,6 @@ void DelegatedRendererLayerImpl::SetDisplaySize(gfx::Size size) {
void DelegatedRendererLayerImpl::SetRenderPasses(
ScopedPtrVector<RenderPass>* render_passes_in_draw_order) {
- gfx::RectF old_root_damage;
- if (!render_passes_in_draw_order_.empty())
- old_root_damage = render_passes_in_draw_order_.back()->damage_rect;
-
ClearRenderPasses();
for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) {
@@ -192,9 +179,6 @@ void DelegatedRendererLayerImpl::SetRenderPasses(
render_passes_in_draw_order_.push_back(taken_render_pass.Pass());
}
- if (!render_passes_in_draw_order_.empty())
- render_passes_in_draw_order_.back()->damage_rect.Union(old_root_damage);
-
// Give back an empty array instead of nulls.
render_passes_in_draw_order->clear();
}
@@ -240,13 +224,19 @@ RenderPass::Id DelegatedRendererLayerImpl::NextContributingRenderPassId(
return RenderPass::Id(previous.layer_id, previous.index + 1);
}
-RenderPass::Id DelegatedRendererLayerImpl::ConvertDelegatedRenderPassId(
- RenderPass::Id delegated_render_pass_id) const {
+bool DelegatedRendererLayerImpl::ConvertDelegatedRenderPassId(
+ RenderPass::Id delegated_render_pass_id,
+ RenderPass::Id* output_render_pass_id) const {
base::hash_map<RenderPass::Id, int>::const_iterator found =
render_passes_index_by_id_.find(delegated_render_pass_id);
- DCHECK(found != render_passes_index_by_id_.end());
+ if (found == render_passes_index_by_id_.end()) {
+ // Be robust against a RenderPass id that isn't part of the frame.
+ return false;
+ }
unsigned delegated_render_pass_index = found->second;
- return RenderPass::Id(id(), IndexToId(delegated_render_pass_index));
+ *output_render_pass_id =
+ RenderPass::Id(id(), IndexToId(delegated_render_pass_index));
+ return true;
}
void DelegatedRendererLayerImpl::AppendContributingRenderPasses(
@@ -254,10 +244,14 @@ void DelegatedRendererLayerImpl::AppendContributingRenderPasses(
DCHECK(HasContributingDelegatedRenderPasses());
for (size_t i = 0; i < render_passes_in_draw_order_.size() - 1; ++i) {
- RenderPass::Id output_render_pass_id =
- ConvertDelegatedRenderPassId(render_passes_in_draw_order_[i]->id);
+ RenderPass::Id output_render_pass_id(-1, -1);
+ bool present =
+ ConvertDelegatedRenderPassId(render_passes_in_draw_order_[i]->id,
+ &output_render_pass_id);
// Don't clash with the RenderPass we generate if we own a RenderSurface.
+ DCHECK(present) << render_passes_in_draw_order_[i]->id.layer_id << ", "
+ << render_passes_in_draw_order_[i]->id.index;
DCHECK_GT(output_render_pass_id.index, 0);
render_pass_sink->AppendRenderPass(
@@ -288,13 +282,13 @@ void DelegatedRendererLayerImpl::AppendQuads(
DCHECK(root_delegated_render_pass->output_rect.origin().IsOrigin());
gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
- // If the index of the EenderPassId is 0, then it is a RenderPass generated
- // for a layer in this compositor, not the delegated renderer. Then we want to
- // merge our root RenderPass with the target RenderPass. Otherwise, it is some
- // RenderPass which we added from the delegated renderer.
+ // If the index of the RenderPassId is 0, then it is a RenderPass generated
+ // for a layer in this compositor, not the delegating renderer. Then we want
+ // to merge our root RenderPass with the target RenderPass. Otherwise, it is
+ // some RenderPass which we added from the delegating renderer.
bool should_merge_root_render_pass_with_target = !target_render_pass_id.index;
if (should_merge_root_render_pass_with_target) {
- // Verify that the RenderPass we are appending to is created our
+ // Verify that the RenderPass we are appending to is created by our
// render_target.
DCHECK(target_render_pass_id.layer_id == render_target()->id());
@@ -421,6 +415,7 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
if (render_target() == this) {
DCHECK(!is_clipped());
DCHECK(render_surface());
+ DCHECK_EQ(0, num_unclipped_descendants());
output_shared_quad_state->clip_rect = MathUtil::MapClippedRect(
delegated_frame_to_target_transform,
output_shared_quad_state->clip_rect);
@@ -446,18 +441,26 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
} else {
RenderPass::Id delegated_contributing_render_pass_id =
RenderPassDrawQuad::MaterialCast(delegated_quad)->render_pass_id;
- RenderPass::Id output_contributing_render_pass_id =
- ConvertDelegatedRenderPassId(delegated_contributing_render_pass_id);
- DCHECK(output_contributing_render_pass_id !=
- append_quads_data->render_pass_id);
-
- output_quad = RenderPassDrawQuad::MaterialCast(delegated_quad)->Copy(
- output_shared_quad_state,
- output_contributing_render_pass_id).PassAs<DrawQuad>();
+ RenderPass::Id output_contributing_render_pass_id(-1, -1);
+
+ bool present =
+ ConvertDelegatedRenderPassId(delegated_contributing_render_pass_id,
+ &output_contributing_render_pass_id);
+
+ // The frame may have a RenderPassDrawQuad that points to a RenderPass not
+ // part of the frame. Just ignore these quads.
+ if (present) {
+ DCHECK(output_contributing_render_pass_id !=
+ append_quads_data->render_pass_id);
+
+ output_quad = RenderPassDrawQuad::MaterialCast(delegated_quad)->Copy(
+ output_shared_quad_state,
+ output_contributing_render_pass_id).PassAs<DrawQuad>();
+ }
}
- DCHECK(output_quad.get());
- quad_sink->Append(output_quad.Pass(), append_quads_data);
+ if (output_quad)
+ quad_sink->Append(output_quad.Pass(), append_quads_data);
}
}
@@ -465,15 +468,6 @@ const char* DelegatedRendererLayerImpl::LayerTypeAsString() const {
return "cc::DelegatedRendererLayerImpl";
}
-void DelegatedRendererLayerImpl::CreateChildIdIfNeeded() {
- if (child_id_)
- return;
-
- ResourceProvider* resource_provider = layer_tree_impl()->resource_provider();
- child_id_ = resource_provider->CreateChild();
- own_child_id_ = true;
-}
-
void DelegatedRendererLayerImpl::ClearChildId() {
if (!child_id_)
return;
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.h b/chromium/cc/layers/delegated_renderer_layer_impl.h
index 9cfdcb6a351..7d774f1c357 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl.h
+++ b/chromium/cc/layers/delegated_renderer_layer_impl.h
@@ -40,11 +40,14 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
void AppendContributingRenderPasses(RenderPassSink* render_pass_sink);
+ // Creates an ID with the resource provider for the child renderer
+ // that will be sending quads to the layer. Registers the callback to
+ // inform when resources are no longer in use.
+ void CreateChildIdIfNeeded(const ReturnCallback& return_callback);
+
void SetFrameData(scoped_ptr<DelegatedFrameData> frame_data,
gfx::RectF damage_in_frame);
- void CollectUnusedResources(TransferableResourceArray* resources_for_ack);
-
void SetDisplaySize(gfx::Size size);
protected:
@@ -54,14 +57,11 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
const ScopedPtrVector<RenderPass>& RenderPassesInDrawOrderForTesting() const {
return render_passes_in_draw_order_;
}
- const ResourceProvider::ResourceIdSet& ResourcesForTesting() const {
+ const ResourceProvider::ResourceIdArray& ResourcesForTesting() const {
return resources_;
}
private:
- // Creates an ID with the resource provider for the child renderer
- // that will be sending quads to the layer.
- void CreateChildIdIfNeeded();
void ClearChildId();
void AppendRainbowDebugBorder(QuadSink* quad_sink,
@@ -71,8 +71,11 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
ScopedPtrVector<RenderPass>* render_passes_in_draw_order);
void ClearRenderPasses();
- RenderPass::Id ConvertDelegatedRenderPassId(
- RenderPass::Id delegated_render_pass_id) const;
+ // Returns |true| if the delegated_render_pass_id is part of the current
+ // frame and can be converted.
+ bool ConvertDelegatedRenderPassId(
+ RenderPass::Id delegated_render_pass_id,
+ RenderPass::Id* output_render_pass_id) const;
gfx::Transform DelegatedFrameToLayerSpaceTransform(gfx::Size frame_size)
const;
@@ -89,7 +92,7 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
bool have_render_passes_to_push_;
ScopedPtrVector<RenderPass> render_passes_in_draw_order_;
base::hash_map<RenderPass::Id, int> render_passes_index_by_id_;
- ResourceProvider::ResourceIdSet resources_;
+ ResourceProvider::ResourceIdArray resources_;
gfx::Size display_size_;
int child_id_;
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
index 1584782f109..a641e00eaf0 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "cc/layers/delegated_renderer_layer_impl.h"
#include "cc/base/scoped_ptr_vector.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/quad_sink.h"
#include "cc/layers/solid_color_layer_impl.h"
@@ -20,7 +21,6 @@
#include "cc/test/mock_quad_culler.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/render_pass_test_utils.h"
-#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
@@ -38,20 +38,15 @@ class DelegatedRendererLayerImplTest : public testing::Test {
LayerTreeSettings settings;
settings.minimum_occlusion_tracking_size = gfx::Size();
- host_impl_ = LayerTreeHostImpl::Create(settings,
- &client_,
- &proxy_,
- &stats_instrumentation_);
+ host_impl_.reset(new FakeLayerTreeHostImpl(settings, &proxy_));
host_impl_->InitializeRenderer(CreateFakeOutputSurface());
host_impl_->SetViewportSize(gfx::Size(10, 10));
}
protected:
FakeProxy proxy_;
- FakeLayerTreeHostImplClient client_;
DebugScopedSetImplThreadAndMainThreadBlocked
always_impl_thread_and_main_thread_blocked_;
- FakeRenderingStatsInstrumentation stats_instrumentation_;
scoped_ptr<LayerTreeHostImpl> host_impl_;
};
@@ -472,8 +467,8 @@ class DelegatedRendererLayerImplTestTransform
root_layer->SetBounds(gfx::Size(100, 100));
delegated_renderer_layer->SetPosition(gfx::Point(20, 20));
- delegated_renderer_layer->SetBounds(gfx::Size(30, 30));
- delegated_renderer_layer->SetContentBounds(gfx::Size(30, 30));
+ delegated_renderer_layer->SetBounds(gfx::Size(75, 75));
+ delegated_renderer_layer->SetContentBounds(gfx::Size(75, 75));
delegated_renderer_layer->SetDrawsContent(true);
gfx::Transform transform;
transform.Scale(2.0, 2.0);
@@ -518,8 +513,8 @@ class DelegatedRendererLayerImplTestTransform
quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
}
- gfx::Size root_pass_content_bounds(50, 50);
- gfx::Rect root_pass_rect(0, 0, 50, 50);
+ gfx::Size root_pass_content_bounds(100, 100);
+ gfx::Rect root_pass_rect(0, 0, 100, 100);
gfx::Transform root_pass_transform;
root_pass_transform.Scale(1.5, 1.5);
root_pass_transform.Translate(7.0, 7.0);
@@ -653,7 +648,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_NoSurface) {
// When the quads don't have a clip of their own, the clip rect is set to
// the drawable_content_rect of the delegated renderer layer.
- EXPECT_EQ(gfx::Rect(42, 42, 120, 120).ToString(),
+ EXPECT_EQ(delegated_renderer_layer_->drawable_content_rect().ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// Even though the quads in the root pass have no clip of their own, they
@@ -665,12 +660,12 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_NoSurface) {
// Device scale factor is 2.
expected.Scale(2.0, 2.0);
// This is the transform from the layer's space to its target.
- // The position (20) - the width / scale (30 / 2) = 20 - 15 = 5
- expected.Translate(5.0, 5.0);
+ // The position (20) - the width / scale (75 / 2) = 20 - 37.5 = -17.5
+ expected.Translate(-17.5, -17.5);
expected.Scale(2.0, 2.0);
expected.Translate(8.0, 8.0);
- // The frame has size 50x50 but the layer's bounds are 30x30.
- expected.Scale(30.0 / 50.0, 30.0 / 50.0);
+ // The frame has size 100x100 but the layer's bounds are 75x75.
+ expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
@@ -710,15 +705,15 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_NoSurface) {
// Since the quads have a clip_rect it should be modified by delegated
// renderer layer's draw_transform.
// The position of the resulting clip_rect is:
- // (clip rect position (10) * scale to layer (30/50) + translate (8)) *
- // layer scale (2) + layer position (20) = 48
- // But the layer is centered, so: 48 - (width / 2) = 48 - 30 / 2 = 33
- // The device scale is 2, so everything gets doubled, giving 66.
+ // (clip rect position (10) * scale to layer (75/100) + translate (8)) *
+ // layer scale (2) + layer position (20) = 51
+ // But the layer is centered, so: 51 - (75 / 2) = 51 - 75 / 2 = 13.5
+ // The device scale is 2, so everything gets doubled, giving 27.
//
- // The size is 35x35 scaled to fit inside the layer's bounds at 30x30 from
- // a frame at 50x50: 35 * 2 (device scale) * 30 / 50 = 42. The device scale
- // doubles this to 84.
- EXPECT_EQ(gfx::Rect(66, 66, 84, 84).ToString(),
+ // The size is 35x35 scaled to fit inside the layer's bounds at 75x75 from
+ // a frame at 100x100: 35 * 2 (device scale) * 75 / 100 = 52.5. The device
+ // scale doubles this to 105.
+ EXPECT_EQ(gfx::Rect(27, 27, 105, 105).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// The quads had a clip and it should be preserved.
@@ -728,12 +723,12 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_NoSurface) {
// Device scale factor is 2.
expected.Scale(2.0, 2.0);
// This is the transform from the layer's space to its target.
- // The position (20) - the width / scale (30 / 2) = 20 - 15 = 5
- expected.Translate(5.0, 5.0);
+ // The position (20) - the width / scale (75 / 2) = 20 - 37.5 = -17.5
+ expected.Translate(-17.5, -17.5);
expected.Scale(2.0, 2.0);
expected.Translate(8.0, 8.0);
- // The frame has size 50x50 but the layer's bounds are 30x30.
- expected.Scale(30.0 / 50.0, 30.0 / 50.0);
+ // The frame has size 100x100 but the layer's bounds are 75x75.
+ expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
@@ -775,10 +770,10 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
// When the layer owns a surface, then its position and translation are not
// a part of its draw transform.
// The position of the resulting clip_rect is:
- // (clip rect position (10) * scale to layer (30/50)) * device scale (2) = 12
- // The size is 35x35 scaled to fit inside the layer's bounds at 30x30 from
- // a frame at 50x50: 35 * 2 (device scale) * 30 / 50 = 42.
- EXPECT_EQ(gfx::Rect(12, 12, 42, 42).ToString(),
+ // (clip rect position (10) * scale to layer (75/100)) * device scale (2) = 15
+ // The size is 35x35 scaled to fit inside the layer's bounds at 75x75 from
+ // a frame at 100x100: 35 * 2 (device scale) * 75 / 100 = 52.5.
+ EXPECT_EQ(gfx::Rect(15, 15, 53, 53).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// Since the layer owns a surface it doesn't need to clip its quads, so
@@ -788,8 +783,8 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
gfx::Transform expected;
// Device scale factor is 2.
expected.Scale(2.0, 2.0);
- // The frame has size 50x50 but the layer's bounds are 30x30.
- expected.Scale(30.0 / 50.0, 30.0 / 50.0);
+ // The frame has size 100x100 but the layer's bounds are 75x75.
+ expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
@@ -831,10 +826,10 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
// When the layer owns a surface, then its position and translation are not
// a part of its draw transform.
// The position of the resulting clip_rect is:
- // (clip rect position (10) * scale to layer (30/50)) * device scale (2) = 12
- // The size is 35x35 scaled to fit inside the layer's bounds at 30x30 from
- // a frame at 50x50: 35 * 2 (device scale) * 30 / 50 = 42.
- EXPECT_EQ(gfx::Rect(12, 12, 42, 42).ToString(),
+ // (clip rect position (10) * scale to layer (75/100)) * device scale (2) = 15
+ // The size is 35x35 scaled to fit inside the layer's bounds at 75x75 from
+ // a frame at 100x100: 35 * 2 (device scale) * 75 / 100 = 52.5.
+ EXPECT_EQ(gfx::Rect(15, 15, 53, 53).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// The quads had a clip and it should be preserved.
@@ -843,8 +838,8 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
gfx::Transform expected;
// Device scale factor is 2.
expected.Scale(2.0, 2.0);
- // The frame has size 50x50 but the layer's bounds are 30x30.
- expected.Scale(30.0 / 50.0, 30.0 / 50.0);
+ // The frame has size 100x100 but the layer's bounds are 75x75.
+ expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
@@ -1250,5 +1245,58 @@ TEST_F(DelegatedRendererLayerImplTestClip, QuadsClipped_LayerClipped_Surface) {
host_impl_->DidDrawAllLayers(frame);
}
+TEST_F(DelegatedRendererLayerImplTest, InvalidRenderPassDrawQuad) {
+ scoped_ptr<LayerImpl> root_layer = LayerImpl::Create(
+ host_impl_->active_tree(), 1).PassAs<LayerImpl>();
+ scoped_ptr<FakeDelegatedRendererLayerImpl> delegated_renderer_layer =
+ FakeDelegatedRendererLayerImpl::Create(host_impl_->active_tree(), 4);
+
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+
+ delegated_renderer_layer->SetPosition(gfx::Point(3, 3));
+ delegated_renderer_layer->SetBounds(gfx::Size(10, 10));
+ delegated_renderer_layer->SetContentBounds(gfx::Size(10, 10));
+ delegated_renderer_layer->SetDrawsContent(true);
+
+ ScopedPtrVector<RenderPass> delegated_render_passes;
+ TestRenderPass* pass1 = AddRenderPass(
+ &delegated_render_passes,
+ RenderPass::Id(9, 6),
+ gfx::Rect(0, 0, 10, 10),
+ gfx::Transform());
+ AddQuad(pass1, gfx::Rect(0, 0, 6, 6), 33u);
+
+ // This render pass isn't part of the frame.
+ scoped_ptr<TestRenderPass> missing_pass(TestRenderPass::Create());
+ missing_pass->SetNew(RenderPass::Id(9, 7),
+ gfx::Rect(7, 7, 7, 7),
+ gfx::Rect(7, 7, 7, 7),
+ gfx::Transform());
+
+ // But a render pass quad refers to it.
+ AddRenderPassQuad(pass1, missing_pass.get());
+
+ delegated_renderer_layer->SetFrameDataForRenderPasses(
+ &delegated_render_passes);
+
+ // The RenderPasses should be taken by the layer.
+ EXPECT_EQ(0u, delegated_render_passes.size());
+
+ root_layer->AddChild(delegated_renderer_layer.PassAs<LayerImpl>());
+ host_impl_->active_tree()->SetRootLayer(root_layer.Pass());
+
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+
+ // The DelegatedRendererLayerImpl should drop the bad RenderPassDrawQuad.
+ ASSERT_EQ(1u, frame.render_passes.size());
+ ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
+ EXPECT_EQ(DrawQuad::SOLID_COLOR,
+ frame.render_passes[0]->quad_list[0]->material);
+
+ host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/draw_properties.h b/chromium/cc/layers/draw_properties.h
index bb80dce0adf..181d900f267 100644
--- a/chromium/cc/layers/draw_properties.h
+++ b/chromium/cc/layers/draw_properties.h
@@ -27,6 +27,7 @@ struct CC_EXPORT DrawProperties {
contents_scale_x(1.f),
contents_scale_y(1.f),
num_descendants_that_draw_content(0),
+ num_unclipped_descendants(0),
descendants_can_clip_selves(false),
can_draw_directly_to_backbuffer(false),
layer_or_descendant_has_copy_request(false) {}
@@ -88,6 +89,10 @@ struct CC_EXPORT DrawProperties {
// Does not include this layer itself, only its children and descendants.
int num_descendants_that_draw_content;
+ // Number of descendants with a clip parent that is our ancestor. NB - this
+ // does not include our clip children because they are clipped by us.
+ int num_unclipped_descendants;
+
// If true, every descendant in the sub-tree can clip itself without the
// need to use hardware sissoring or a new render target.
bool descendants_can_clip_selves;
diff --git a/chromium/cc/layers/heads_up_display_layer.cc b/chromium/cc/layers/heads_up_display_layer.cc
index 92486cc8515..d9fab902ef9 100644
--- a/chromium/cc/layers/heads_up_display_layer.cc
+++ b/chromium/cc/layers/heads_up_display_layer.cc
@@ -55,4 +55,8 @@ scoped_ptr<LayerImpl> HeadsUpDisplayLayer::CreateLayerImpl(
PassAs<LayerImpl>();
}
+std::string HeadsUpDisplayLayer::DebugName() {
+ return std::string("Heads Up Display Layer");
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/heads_up_display_layer.h b/chromium/cc/layers/heads_up_display_layer.h
index 7038cd480c3..f13d56bba67 100644
--- a/chromium/cc/layers/heads_up_display_layer.h
+++ b/chromium/cc/layers/heads_up_display_layer.h
@@ -5,6 +5,8 @@
#ifndef CC_LAYERS_HEADS_UP_DISPLAY_LAYER_H_
#define CC_LAYERS_HEADS_UP_DISPLAY_LAYER_H_
+#include <string>
+
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "cc/layers/contents_scaling_layer.h"
@@ -23,6 +25,8 @@ class CC_EXPORT HeadsUpDisplayLayer : public ContentsScalingLayer {
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
+ virtual std::string DebugName() OVERRIDE;
+
protected:
HeadsUpDisplayLayer();
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index 8728d704ca4..c1fa9f37dbc 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -94,8 +94,9 @@ bool HeadsUpDisplayLayerImpl::WillDraw(DrawMode draw_mode,
hud_resource_->Free();
if (!hud_resource_->id()) {
- hud_resource_->Allocate(
- content_bounds(), GL_RGBA, ResourceProvider::TextureUsageAny);
+ hud_resource_->Allocate(content_bounds(),
+ ResourceProvider::TextureUsageAny,
+ RGBA_8888);
}
return LayerImpl::WillDraw(draw_mode, resource_provider);
diff --git a/chromium/cc/layers/image_layer.cc b/chromium/cc/layers/image_layer.cc
index 8ba1908131d..bbf1aa82e34 100644
--- a/chromium/cc/layers/image_layer.cc
+++ b/chromium/cc/layers/image_layer.cc
@@ -56,9 +56,8 @@ void ImageLayer::CreateUpdaterIfNeeded() {
return;
updater_ = ImageLayerUpdater::Create();
- GLenum texture_format =
- layer_tree_host()->GetRendererCapabilities().best_texture_format;
- SetTextureFormat(texture_format);
+ SetTextureFormat(
+ layer_tree_host()->GetRendererCapabilities().best_texture_format);
}
LayerUpdater* ImageLayer::Updater() const {
diff --git a/chromium/cc/layers/io_surface_layer_impl.cc b/chromium/cc/layers/io_surface_layer_impl.cc
index f8577a37765..e8c627be08b 100644
--- a/chromium/cc/layers/io_surface_layer_impl.cc
+++ b/chromium/cc/layers/io_surface_layer_impl.cc
@@ -39,11 +39,11 @@ void IOSurfaceLayerImpl::DestroyTexture() {
}
if (io_surface_texture_id_) {
- OutputSurface* output_surface = layer_tree_impl()->output_surface();
+ ContextProvider* context_provider =
+ layer_tree_impl()->output_surface()->context_provider().get();
// TODO(skaslev): Implement this path for software compositing.
- WebKit::WebGraphicsContext3D* context3d = output_surface->context3d();
- if (context3d)
- context3d->deleteTexture(io_surface_texture_id_);
+ if (context_provider)
+ context_provider->Context3d()->deleteTexture(io_surface_texture_id_);
io_surface_texture_id_ = 0;
}
}
@@ -67,13 +67,15 @@ bool IOSurfaceLayerImpl::WillDraw(DrawMode draw_mode,
return false;
if (io_surface_changed_) {
- WebKit::WebGraphicsContext3D* context3d =
- resource_provider->GraphicsContext3D();
- if (!context3d) {
+ ContextProvider* context_provider =
+ layer_tree_impl()->output_surface()->context_provider().get();
+ if (!context_provider) {
// TODO(skaslev): Implement this path for software compositing.
return false;
}
+ WebKit::WebGraphicsContext3D* context3d = context_provider->Context3d();
+
// TODO(ernstm): Do this in a way that we can track memory usage.
if (!io_surface_texture_id_) {
io_surface_texture_id_ = context3d->createTexture();
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index aa4a002dff4..86887a6ad2c 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -6,12 +6,14 @@
#include <algorithm>
+#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/metrics/histogram.h"
#include "base/single_thread_task_runner.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_events.h"
#include "cc/animation/layer_animation_controller.h"
+#include "cc/layers/layer_client.h"
#include "cc/layers/layer_impl.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
@@ -54,8 +56,11 @@ Layer::Layer()
use_parent_backface_visibility_(false),
draw_checkerboard_for_missing_tiles_(false),
force_render_surface_(false),
+ scroll_parent_(NULL),
+ clip_parent_(NULL),
replica_layer_(NULL),
- raster_scale_(0.f) {
+ raster_scale_(0.f),
+ client_(NULL) {
if (layer_id_ < 0) {
s_next_layer_id = 1;
layer_id_ = s_next_layer_id++;
@@ -85,6 +90,9 @@ Layer::~Layer() {
DCHECK_EQ(this, replica_layer_->parent());
replica_layer_->RemoveFromParent();
}
+
+ RemoveFromScrollTree();
+ RemoveFromClipTree();
}
void Layer::SetLayerTreeHost(LayerTreeHost* host) {
@@ -144,14 +152,11 @@ void Layer::SetNeedsFullTreeSync() {
layer_tree_host_->SetNeedsFullTreeSync();
}
-bool Layer::IsPropertyChangeAllowed() const {
+void Layer::SetNextCommitWaitsForActivation() {
if (!layer_tree_host_)
- return true;
-
- if (!layer_tree_host_->settings().strict_layer_property_change_checking)
- return true;
+ return;
- return !layer_tree_host_->in_paint_layer_contents();
+ layer_tree_host_->SetNextCommitWaitsForActivation();
}
void Layer::SetNeedsPushProperties() {
@@ -179,6 +184,16 @@ void Layer::RemoveDependentNeedsPushProperties() {
parent_->RemoveDependentNeedsPushProperties();
}
+bool Layer::IsPropertyChangeAllowed() const {
+ if (!layer_tree_host_)
+ return true;
+
+ if (!layer_tree_host_->settings().strict_layer_property_change_checking)
+ return true;
+
+ return !layer_tree_host_->in_paint_layer_contents();
+}
+
gfx::Rect Layer::LayerRectToContentRect(const gfx::RectF& layer_rect) const {
gfx::RectF content_rect =
gfx::ScaleRect(layer_rect, contents_scale_x(), contents_scale_y());
@@ -188,28 +203,14 @@ gfx::Rect Layer::LayerRectToContentRect(const gfx::RectF& layer_rect) const {
return gfx::ToEnclosingRect(content_rect);
}
-bool Layer::BlocksPendingCommit() const {
- return false;
+skia::RefPtr<SkPicture> Layer::GetPicture() const {
+ return skia::RefPtr<SkPicture>();
}
bool Layer::CanClipSelf() const {
return false;
}
-bool Layer::BlocksPendingCommitRecursive() const {
- if (BlocksPendingCommit())
- return true;
- if (mask_layer() && mask_layer()->BlocksPendingCommitRecursive())
- return true;
- if (replica_layer() && replica_layer()->BlocksPendingCommitRecursive())
- return true;
- for (size_t i = 0; i < children_.size(); ++i) {
- if (children_[i]->BlocksPendingCommitRecursive())
- return true;
- }
- return false;
-}
-
void Layer::SetParent(Layer* layer) {
DCHECK(!layer || !layer->HasAncestor(this));
@@ -559,6 +560,66 @@ bool Layer::TransformIsAnimating() const {
return layer_animation_controller_->IsAnimatingProperty(Animation::Transform);
}
+void Layer::SetScrollParent(Layer* parent) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (scroll_parent_ == parent)
+ return;
+
+ if (scroll_parent_)
+ scroll_parent_->RemoveScrollChild(this);
+
+ scroll_parent_ = parent;
+
+ if (scroll_parent_)
+ scroll_parent_->AddScrollChild(this);
+
+ SetNeedsCommit();
+}
+
+void Layer::AddScrollChild(Layer* child) {
+ if (!scroll_children_)
+ scroll_children_.reset(new std::set<Layer*>);
+ scroll_children_->insert(child);
+ SetNeedsCommit();
+}
+
+void Layer::RemoveScrollChild(Layer* child) {
+ scroll_children_->erase(child);
+ if (scroll_children_->empty())
+ scroll_children_.reset();
+ SetNeedsCommit();
+}
+
+void Layer::SetClipParent(Layer* ancestor) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (clip_parent_ == ancestor)
+ return;
+
+ if (clip_parent_)
+ clip_parent_->RemoveClipChild(this);
+
+ clip_parent_ = ancestor;
+
+ if (clip_parent_)
+ clip_parent_->AddClipChild(this);
+
+ SetNeedsCommit();
+}
+
+void Layer::AddClipChild(Layer* child) {
+ if (!clip_children_)
+ clip_children_.reset(new std::set<Layer*>);
+ clip_children_->insert(child);
+ SetNeedsCommit();
+}
+
+void Layer::RemoveClipChild(Layer* child) {
+ clip_children_->erase(child);
+ if (clip_children_->empty())
+ clip_children_.reset();
+ SetNeedsCommit();
+}
+
void Layer::SetScrollOffset(gfx::Vector2d scroll_offset) {
DCHECK(IsPropertyChangeAllowed());
if (scroll_offset_ == scroll_offset)
@@ -627,6 +688,7 @@ void Layer::SetTouchEventHandlerRegion(const Region& region) {
if (touch_event_handler_region_ == region)
return;
touch_event_handler_region_ = region;
+ SetNeedsCommit();
}
void Layer::SetDrawCheckerboardForMissingTiles(bool checkerboard) {
@@ -742,7 +804,15 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
: bounds_);
layer->SetContentBounds(content_bounds());
layer->SetContentsScale(contents_scale_x(), contents_scale_y());
- layer->SetDebugName(debug_name_);
+
+ bool is_tracing;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ &is_tracing);
+ if (is_tracing)
+ layer->SetDebugName(DebugName());
+ else
+ layer->SetDebugName(std::string());
+
layer->SetCompositingReasons(compositing_reasons_);
layer->SetDoubleSided(double_sided_);
layer->SetDrawCheckerboardForMissingTiles(
@@ -775,9 +845,50 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
DCHECK(!(TransformIsAnimating() && layer->TransformIsAnimatingOnImplOnly()));
layer->SetScrollable(scrollable_);
- layer->SetScrollOffset(scroll_offset_);
layer->SetMaxScrollOffset(max_scroll_offset_);
+ LayerImpl* scroll_parent = NULL;
+ if (scroll_parent_)
+ scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
+
+ layer->SetScrollParent(scroll_parent);
+ if (scroll_children_) {
+ std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>;
+ for (std::set<Layer*>::iterator it = scroll_children_->begin();
+ it != scroll_children_->end(); ++it)
+ scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+ layer->SetScrollChildren(scroll_children);
+ }
+
+ LayerImpl* clip_parent = NULL;
+ if (clip_parent_) {
+ clip_parent =
+ layer->layer_tree_impl()->LayerById(clip_parent_->id());
+ }
+
+ layer->SetClipParent(clip_parent);
+ if (clip_children_) {
+ std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>;
+ for (std::set<Layer*>::iterator it = clip_children_->begin();
+ it != clip_children_->end(); ++it) {
+ LayerImpl* clip_child = layer->layer_tree_impl()->LayerById((*it)->id());
+ DCHECK(clip_child);
+ clip_children->insert(clip_child);
+ }
+ layer->SetClipChildren(clip_children);
+ }
+
+ // Adjust the scroll delta to be just the scrolls that have happened since
+ // the begin frame was sent. This happens for impl-side painting
+ // in LayerImpl::ApplyScrollDeltasSinceBeginFrame in a separate tree walk.
+ if (layer->layer_tree_impl()->settings().impl_side_painting) {
+ layer->SetScrollOffset(scroll_offset_);
+ } else {
+ layer->SetScrollOffsetAndDelta(
+ scroll_offset_, layer->ScrollDelta() - layer->sent_scroll_delta());
+ layer->SetSentScrollDelta(gfx::Vector2d());
+ }
+
// Wrap the copy_requests_ in a PostTask to the main thread.
ScopedPtrVector<CopyOutputRequest> main_thread_copy_requests;
for (ScopedPtrVector<CopyOutputRequest>::iterator it = copy_requests_.begin();
@@ -805,23 +916,6 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
update_rect_.Union(layer->update_rect());
layer->set_update_rect(update_rect_);
- if (layer->layer_tree_impl()->settings().impl_side_painting) {
- DCHECK(layer->layer_tree_impl()->IsPendingTree());
- LayerImpl* active_twin =
- layer->layer_tree_impl()->FindActiveTreeLayerById(id());
- // Update the scroll delta from the active layer, which may have
- // adjusted its scroll delta prior to this pending layer being created.
- // This code is identical to that in LayerImpl::SetScrollDelta.
- if (active_twin) {
- DCHECK(layer->sent_scroll_delta().IsZero());
- layer->SetScrollDelta(active_twin->ScrollDelta() -
- active_twin->sent_scroll_delta());
- }
- } else {
- layer->SetScrollDelta(layer->ScrollDelta() - layer->sent_scroll_delta());
- layer->SetSentScrollDelta(gfx::Vector2d());
- }
-
layer->SetStackingOrderChanged(stacking_order_changed_);
layer_animation_controller_->PushAnimationUpdatesTo(
@@ -868,9 +962,8 @@ bool Layer::NeedMoreUpdates() {
return false;
}
-void Layer::SetDebugName(const std::string& debug_name) {
- debug_name_ = debug_name;
- SetNeedsCommit();
+std::string Layer::DebugName() {
+ return client_ ? client_->DebugName() : std::string();
}
void Layer::SetCompositingReasons(CompositingReasons reasons) {
@@ -967,7 +1060,7 @@ Region Layer::VisibleContentOpaqueRegion() const {
return Region();
}
-ScrollbarLayer* Layer::ToScrollbarLayer() {
+ScrollbarLayerInterface* Layer::ToScrollbarLayer() {
return NULL;
}
@@ -979,4 +1072,30 @@ bool Layer::SupportsLCDText() const {
return false;
}
+void Layer::RemoveFromScrollTree() {
+ if (scroll_children_.get()) {
+ for (std::set<Layer*>::iterator it = scroll_children_->begin();
+ it != scroll_children_->end(); ++it)
+ (*it)->scroll_parent_ = NULL;
+ }
+
+ if (scroll_parent_)
+ scroll_parent_->RemoveScrollChild(this);
+
+ scroll_parent_ = NULL;
+}
+
+void Layer::RemoveFromClipTree() {
+ if (clip_children_.get()) {
+ for (std::set<Layer*>::iterator it = clip_children_->begin();
+ it != clip_children_->end(); ++it)
+ (*it)->clip_parent_ = NULL;
+ }
+
+ if (clip_parent_)
+ clip_parent_->RemoveClipChild(this);
+
+ clip_parent_ = NULL;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index 035e071a5fd..737e83df067 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -5,6 +5,7 @@
#ifndef CC_LAYERS_LAYER_H_
#define CC_LAYERS_LAYER_H_
+#include <set>
#include <string>
#include "base/callback.h"
@@ -26,10 +27,15 @@
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkPicture.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_f.h"
#include "ui/gfx/transform.h"
+namespace gfx {
+class BoxF;
+}
+
namespace cc {
class Animation;
@@ -38,13 +44,14 @@ struct AnimationEvent;
class CopyOutputRequest;
class LayerAnimationDelegate;
class LayerAnimationEventObserver;
+class LayerClient;
class LayerImpl;
class LayerTreeHost;
class LayerTreeImpl;
class PriorityCalculator;
class RenderingStatsInstrumentation;
class ResourceUpdateQueue;
-class ScrollbarLayer;
+class ScrollbarLayerInterface;
struct AnimationEvent;
// Base class for composited layers. Special layer types are derived from
@@ -151,6 +158,34 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
const gfx::Transform& transform() const { return transform_; }
bool TransformIsAnimating() const;
+ void SetScrollParent(Layer* parent);
+
+ Layer* scroll_parent() { return scroll_parent_; }
+ const Layer* scroll_parent() const { return scroll_parent_; }
+
+ void AddScrollChild(Layer* child);
+ void RemoveScrollChild(Layer* child);
+
+ std::set<Layer*>* scroll_children() { return scroll_children_.get(); }
+ const std::set<Layer*>* scroll_children() const {
+ return scroll_children_.get();
+ }
+
+ void SetClipParent(Layer* ancestor);
+
+ Layer* clip_parent() { return clip_parent_; }
+ const Layer* clip_parent() const {
+ return clip_parent_;
+ }
+
+ void AddClipChild(Layer* child);
+ void RemoveClipChild(Layer* child);
+
+ std::set<Layer*>* clip_children() { return clip_children_.get(); }
+ const std::set<Layer*>* clip_children() const {
+ return clip_children_.get();
+ }
+
DrawProperties<Layer, RenderSurface>& draw_properties() {
return draw_properties_;
}
@@ -201,6 +236,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
RenderSurface* render_surface() const {
return draw_properties_.render_surface.get();
}
+ int num_unclipped_descendants() const {
+ return draw_properties_.num_unclipped_descendants;
+ }
void SetScrollOffset(gfx::Vector2d scroll_offset);
gfx::Vector2d scroll_offset() const { return scroll_offset_; }
@@ -292,7 +330,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual void SetIsMask(bool is_mask) {}
virtual void ReduceMemoryUsage() {}
- void SetDebugName(const std::string& debug_name);
+ virtual std::string DebugName();
+
+ void SetLayerClient(LayerClient* client) { client_ = client; }
+
void SetCompositingReasons(CompositingReasons reasons);
virtual void PushPropertiesTo(LayerImpl* layer);
@@ -316,7 +357,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
float* contents_scale_y,
gfx::Size* content_bounds);
- LayerTreeHost* layer_tree_host() const { return layer_tree_host_; }
+ LayerTreeHost* layer_tree_host() { return layer_tree_host_; }
+ const LayerTreeHost* layer_tree_host() const { return layer_tree_host_; }
// Set the priority of all desired textures in this layer.
virtual void SetTexturePriorities(const PriorityCalculator& priority_calc) {}
@@ -328,6 +370,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void SuspendAnimations(double monotonic_time);
void ResumeAnimations(double monotonic_time);
+ bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) {
+ return layer_animation_controller_->AnimatedBoundsForBox(box, bounds);
+ }
+
LayerAnimationController* layer_animation_controller() {
return layer_animation_controller_.get();
}
@@ -347,16 +393,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual Region VisibleContentOpaqueRegion() const;
- virtual ScrollbarLayer* ToScrollbarLayer();
+ virtual ScrollbarLayerInterface* ToScrollbarLayer();
gfx::Rect LayerRectToContentRect(const gfx::RectF& layer_rect) const;
- // In impl-side painting, this returns true if this layer type is not
- // compatible with the main thread running freely, such as a double-buffered
- // canvas that doesn't want to be triple-buffered across all three trees.
- virtual bool BlocksPendingCommit() const;
- // Returns true if anything in this tree blocksPendingCommit.
- bool BlocksPendingCommitRecursive() const;
+ virtual skia::RefPtr<SkPicture> GetPicture() const;
virtual bool CanClipSelf() const;
@@ -407,7 +448,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// Called when there's been a change in layer structure. Implies both
// SetNeedsUpdate and SetNeedsCommit, but not SetNeedsPushProperties.
void SetNeedsFullTreeSync();
- bool IsPropertyChangeAllowed() const;
+
+ // Called when the next commit should wait until the pending tree is activated
+ // before finishing the commit and unblocking the main thread. Used to ensure
+ // unused resources on the impl thread are returned before commit completes.
+ void SetNextCommitWaitsForActivation();
void SetNeedsPushProperties();
void AddDependentNeedsPushProperties();
@@ -416,6 +461,16 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
return needs_push_properties() || descendant_needs_push_properties();
}
+ bool IsPropertyChangeAllowed() const;
+
+ // If this layer has a scroll parent, it removes |this| from its list of
+ // scroll children.
+ void RemoveFromScrollTree();
+
+ // If this layer has a clip parent, it removes |this| from its list of clip
+ // children.
+ void RemoveFromClipTree();
+
void reset_raster_scale_to_unknown() { raster_scale_ = 0.f; }
// This flag is set when the layer needs to push properties to the impl
@@ -486,7 +541,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
gfx::PointF position_;
gfx::PointF anchor_point_;
SkColor background_color_;
- std::string debug_name_;
CompositingReasons compositing_reasons_;
float opacity_;
skia::RefPtr<SkImageFilter> filter_;
@@ -504,6 +558,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
bool use_parent_backface_visibility_;
bool draw_checkerboard_for_missing_tiles_;
bool force_render_surface_;
+ Layer* scroll_parent_;
+ scoped_ptr<std::set<Layer*> > scroll_children_;
+
+ Layer* clip_parent_;
+ scoped_ptr<std::set<Layer*> > clip_children_;
gfx::Transform transform_;
gfx::Transform sublayer_transform_;
@@ -514,6 +573,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// Transient properties.
float raster_scale_;
+ LayerClient* client_;
+
ScopedPtrVector<CopyOutputRequest> copy_requests_;
base::Closure did_scroll_callback_;
diff --git a/chromium/cc/layers/layer_client.h b/chromium/cc/layers/layer_client.h
new file mode 100644
index 00000000000..73c0fd2514b
--- /dev/null
+++ b/chromium/cc/layers/layer_client.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_LAYER_CLIENT_H_
+#define CC_LAYERS_LAYER_CLIENT_H_
+
+#include <string>
+
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+class CC_EXPORT LayerClient {
+ public:
+ virtual std::string DebugName() = 0;
+
+ protected:
+ virtual ~LayerClient() {}
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_LAYER_CLIENT_H_
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index b78cf1a45a8..b0c5399d32e 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -9,13 +9,14 @@
#include "cc/animation/animation_registrar.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
+#include "cc/animation/scrollbar_animation_controller_thinning.h"
#include "cc/base/math_util.h"
#include "cc/debug/debug_colors.h"
#include "cc/debug/layer_tree_debug_state.h"
#include "cc/debug/traced_value.h"
#include "cc/input/layer_scroll_offset_delegate.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
#include "cc/layers/quad_sink.h"
-#include "cc/layers/scrollbar_layer_impl.h"
#include "cc/output/copy_output_request.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/trees/layer_tree_impl.h"
@@ -29,6 +30,8 @@ namespace cc {
LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
: parent_(NULL),
+ scroll_parent_(NULL),
+ clip_parent_(NULL),
mask_layer_id_(-1),
replica_layer_id_(-1),
layer_id_(id),
@@ -73,6 +76,24 @@ LayerImpl::~LayerImpl() {
layer_tree_impl_->UnregisterLayer(this);
layer_animation_controller_->RemoveValueObserver(this);
+
+ if (scroll_children_) {
+ for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
+ it != scroll_children_->end(); ++it)
+ (*it)->scroll_parent_ = NULL;
+ }
+
+ if (scroll_parent_)
+ scroll_parent_->RemoveScrollChild(this);
+
+ if (clip_children_) {
+ for (std::set<LayerImpl*>::iterator it = clip_children_->begin();
+ it != clip_children_->end(); ++it)
+ (*it)->clip_parent_ = NULL;
+ }
+
+ if (clip_parent_)
+ clip_parent_->RemoveClipChild(this);
}
void LayerImpl::AddChild(scoped_ptr<LayerImpl> child) {
@@ -104,6 +125,67 @@ void LayerImpl::ClearChildList() {
layer_tree_impl()->set_needs_update_draw_properties();
}
+bool LayerImpl::HasAncestor(const LayerImpl* ancestor) const {
+ if (!ancestor)
+ return false;
+
+ for (const LayerImpl* layer = this; layer; layer = layer->parent()) {
+ if (layer == ancestor)
+ return true;
+ }
+
+ return false;
+}
+
+void LayerImpl::SetScrollParent(LayerImpl* parent) {
+ if (scroll_parent_ == parent)
+ return;
+
+ // Having both a scroll parent and a scroll offset delegate is unsupported.
+ DCHECK(!scroll_offset_delegate_);
+
+ if (scroll_parent_)
+ scroll_parent_->RemoveScrollChild(this);
+
+ scroll_parent_ = parent;
+}
+
+void LayerImpl::SetScrollChildren(std::set<LayerImpl*>* children) {
+ if (scroll_children_.get() == children)
+ return;
+ scroll_children_.reset(children);
+}
+
+void LayerImpl::RemoveScrollChild(LayerImpl* child) {
+ DCHECK(scroll_children_);
+ scroll_children_->erase(child);
+ if (scroll_children_->empty())
+ scroll_children_.reset();
+}
+
+void LayerImpl::SetClipParent(LayerImpl* ancestor) {
+ if (clip_parent_ == ancestor)
+ return;
+
+ if (clip_parent_)
+ clip_parent_->RemoveClipChild(this);
+
+ clip_parent_ = ancestor;
+}
+
+void LayerImpl::SetClipChildren(std::set<LayerImpl*>* children) {
+ if (clip_children_.get() == children)
+ return;
+ clip_children_.reset(children);
+}
+
+void LayerImpl::RemoveClipChild(LayerImpl* child) {
+ DCHECK(clip_children_);
+ clip_children_->erase(child);
+ if (clip_children_->empty())
+ clip_children_.reset();
+}
+
void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) {
if (requests->empty())
return;
@@ -272,7 +354,7 @@ gfx::Vector2dF LayerImpl::ScrollBy(gfx::Vector2dF scroll) {
return unscrolled;
}
-void LayerImpl::ApplySentScrollDeltas() {
+void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() {
// Pending tree never has sent scroll deltas
DCHECK(layer_tree_impl()->IsActiveTree());
@@ -292,6 +374,25 @@ void LayerImpl::ApplySentScrollDeltas() {
sent_scroll_delta_ = gfx::Vector2d();
}
+void LayerImpl::ApplyScrollDeltasSinceBeginFrame() {
+ // Only the pending tree can have missing scrolls.
+ DCHECK(layer_tree_impl()->IsPendingTree());
+ if (!scrollable())
+ return;
+
+ // Pending tree should never have sent scroll deltas.
+ DCHECK(sent_scroll_delta().IsZero());
+
+ LayerImpl* active_twin = layer_tree_impl()->FindActiveTreeLayerById(id());
+ if (active_twin) {
+ // Scrolls that happens after begin frame (where the sent scroll delta
+ // comes from) and commit need to be applied to the pending tree
+ // so that it is up to date with the total scroll.
+ SetScrollDelta(active_twin->ScrollDelta() -
+ active_twin->sent_scroll_delta());
+ }
+}
+
InputHandler::ScrollStatus LayerImpl::TryScroll(
gfx::PointF screen_space_point,
InputHandler::ScrollInputType type) const {
@@ -419,9 +520,40 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetTransform(transform_);
layer->SetScrollable(scrollable_);
- layer->SetScrollOffset(scroll_offset_);
+ layer->SetScrollOffsetAndDelta(
+ scroll_offset_, layer->ScrollDelta() - layer->sent_scroll_delta());
+ layer->SetSentScrollDelta(gfx::Vector2d());
+
layer->SetMaxScrollOffset(max_scroll_offset_);
+ LayerImpl* scroll_parent = NULL;
+ if (scroll_parent_)
+ scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
+
+ layer->SetScrollParent(scroll_parent);
+ if (scroll_children_) {
+ std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>;
+ for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
+ it != scroll_children_->end(); ++it)
+ scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+ layer->SetScrollChildren(scroll_children);
+ }
+
+ LayerImpl* clip_parent = NULL;
+ if (clip_parent_) {
+ clip_parent = layer->layer_tree_impl()->LayerById(
+ clip_parent_->id());
+ }
+
+ layer->SetClipParent(clip_parent);
+ if (clip_children_) {
+ std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>;
+ for (std::set<LayerImpl*>::iterator it = clip_children_->begin();
+ it != clip_children_->end(); ++it)
+ clip_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+ layer->SetClipChildren(clip_children);
+ }
+
layer->PassCopyRequests(&copy_requests_);
// If the main thread commits multiple times before the impl thread actually
@@ -431,9 +563,6 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
update_rect_.Union(layer->update_rect());
layer->set_update_rect(update_rect_);
- layer->SetScrollDelta(layer->ScrollDelta() - layer->sent_scroll_delta());
- layer->SetSentScrollDelta(gfx::Vector2d());
-
layer->SetStackingOrderChanged(stacking_order_changed_);
// Reset any state that should be cleared for the next update.
@@ -622,7 +751,7 @@ scoped_ptr<LayerImpl> LayerImpl::TakeReplicaLayer() {
return replica_layer_.Pass();
}
-ScrollbarLayerImpl* LayerImpl::ToScrollbarLayer() {
+ScrollbarLayerImplBase* LayerImpl::ToScrollbarLayer() {
return NULL;
}
@@ -847,10 +976,11 @@ void LayerImpl::UpdateScrollbarPositions() {
return;
last_scroll_offset_ = current_offset;
- if (scrollbar_animation_controller_ &&
- !scrollbar_animation_controller_->IsScrollGestureInProgress()) {
- scrollbar_animation_controller_->DidProgrammaticallyUpdateScroll(
+ if (scrollbar_animation_controller_) {
+ bool should_animate = scrollbar_animation_controller_->DidScrollUpdate(
layer_tree_impl_->CurrentPhysicalTimeTicks());
+ if (should_animate)
+ layer_tree_impl_->StartScrollbarAnimation();
}
// Get the current_offset_.y() value for a sanity-check on scrolling
@@ -863,6 +993,8 @@ void LayerImpl::UpdateScrollbarPositions() {
void LayerImpl::SetScrollOffsetDelegate(
LayerScrollOffsetDelegate* scroll_offset_delegate) {
+ // Having both a scroll parent and a scroll offset delegate is unsupported.
+ DCHECK(!scroll_parent_);
if (!scroll_offset_delegate && scroll_offset_delegate_) {
scroll_delta_ =
scroll_offset_delegate_->GetTotalScrollOffset() - scroll_offset_;
@@ -874,16 +1006,49 @@ void LayerImpl::SetScrollOffsetDelegate(
}
void LayerImpl::SetScrollOffset(gfx::Vector2d scroll_offset) {
- if (scroll_offset_ == scroll_offset)
- return;
+ SetScrollOffsetAndDelta(scroll_offset, ScrollDelta());
+}
- scroll_offset_ = scroll_offset;
+void LayerImpl::SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset,
+ gfx::Vector2dF scroll_delta) {
+ bool changed = false;
- if (scroll_offset_delegate_)
- scroll_offset_delegate_->SetTotalScrollOffset(TotalScrollOffset());
+ if (scroll_offset_ != scroll_offset) {
+ changed = true;
+ scroll_offset_ = scroll_offset;
- NoteLayerPropertyChangedForSubtree();
- UpdateScrollbarPositions();
+ if (scroll_offset_delegate_)
+ scroll_offset_delegate_->SetTotalScrollOffset(TotalScrollOffset());
+ }
+
+ if (ScrollDelta() != scroll_delta) {
+ changed = true;
+ if (layer_tree_impl()->IsActiveTree()) {
+ LayerImpl* pending_twin =
+ layer_tree_impl()->FindPendingTreeLayerById(id());
+ if (pending_twin) {
+ // The pending twin can't mirror the scroll delta of the active
+ // layer. Although the delta - sent scroll delta difference is
+ // identical for both twins, the sent scroll delta for the pending
+ // layer is zero, as anything that has been sent has been baked
+ // into the layer's position/scroll offset as a part of commit.
+ DCHECK(pending_twin->sent_scroll_delta().IsZero());
+ pending_twin->SetScrollDelta(scroll_delta - sent_scroll_delta());
+ }
+ }
+
+ if (scroll_offset_delegate_) {
+ scroll_offset_delegate_->SetTotalScrollOffset(scroll_offset_ +
+ scroll_delta);
+ } else {
+ scroll_delta_ = scroll_delta;
+ }
+ }
+
+ if (changed) {
+ NoteLayerPropertyChangedForSubtree();
+ UpdateScrollbarPositions();
+ }
}
gfx::Vector2dF LayerImpl::ScrollDelta() const {
@@ -893,31 +1058,7 @@ gfx::Vector2dF LayerImpl::ScrollDelta() const {
}
void LayerImpl::SetScrollDelta(gfx::Vector2dF scroll_delta) {
- if (ScrollDelta() == scroll_delta)
- return;
-
- if (layer_tree_impl()->IsActiveTree()) {
- LayerImpl* pending_twin = layer_tree_impl()->FindPendingTreeLayerById(id());
- if (pending_twin) {
- // The pending twin can't mirror the scroll delta of the active
- // layer. Although the delta - sent scroll delta difference is
- // identical for both twins, the sent scroll delta for the pending
- // layer is zero, as anything that has been sent has been baked
- // into the layer's position/scroll offset as a part of commit.
- DCHECK(pending_twin->sent_scroll_delta().IsZero());
- pending_twin->SetScrollDelta(scroll_delta - sent_scroll_delta());
- }
- }
-
- if (scroll_offset_delegate_) {
- scroll_offset_delegate_->SetTotalScrollOffset(
- scroll_offset_ + scroll_delta);
- } else {
- scroll_delta_ = scroll_delta;
- }
-
- NoteLayerPropertyChangedForSubtree();
- UpdateScrollbarPositions();
+ SetScrollOffsetAndDelta(scroll_offset_, scroll_delta);
}
gfx::Vector2dF LayerImpl::TotalScrollOffset() const {
@@ -951,42 +1092,55 @@ void LayerImpl::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) {
UpdateScrollbarPositions();
}
-void LayerImpl::SetScrollbarOpacity(float opacity) {
- if (horizontal_scrollbar_layer_)
- horizontal_scrollbar_layer_->SetOpacity(opacity);
- if (vertical_scrollbar_layer_)
- vertical_scrollbar_layer_->SetOpacity(opacity);
-}
-
void LayerImpl::DidBecomeActive() {
- if (!layer_tree_impl_->settings().use_linear_fade_scrollbar_animator)
+ if (layer_tree_impl_->settings().scrollbar_animator ==
+ LayerTreeSettings::NoAnimator) {
return;
+ }
bool need_scrollbar_animation_controller = horizontal_scrollbar_layer_ ||
vertical_scrollbar_layer_;
- if (need_scrollbar_animation_controller) {
- if (!scrollbar_animation_controller_) {
- base::TimeDelta fadeout_delay = base::TimeDelta::FromMilliseconds(
- layer_tree_impl_->settings().scrollbar_linear_fade_delay_ms);
- base::TimeDelta fadeout_length = base::TimeDelta::FromMilliseconds(
- layer_tree_impl_->settings().scrollbar_linear_fade_length_ms);
- scrollbar_animation_controller_ =
- ScrollbarAnimationControllerLinearFade::Create(
- this, fadeout_delay, fadeout_length)
- .PassAs<ScrollbarAnimationController>();
- }
- } else {
+ if (!need_scrollbar_animation_controller) {
scrollbar_animation_controller_.reset();
+ return;
+ }
+
+ if (scrollbar_animation_controller_)
+ return;
+
+ switch (layer_tree_impl_->settings().scrollbar_animator) {
+ case LayerTreeSettings::LinearFade: {
+ base::TimeDelta fadeout_delay = base::TimeDelta::FromMilliseconds(
+ layer_tree_impl_->settings().scrollbar_linear_fade_delay_ms);
+ base::TimeDelta fadeout_length = base::TimeDelta::FromMilliseconds(
+ layer_tree_impl_->settings().scrollbar_linear_fade_length_ms);
+
+ scrollbar_animation_controller_ =
+ ScrollbarAnimationControllerLinearFade::Create(
+ this, fadeout_delay, fadeout_length)
+ .PassAs<ScrollbarAnimationController>();
+ break;
+ }
+ case LayerTreeSettings::Thinning: {
+ scrollbar_animation_controller_ =
+ ScrollbarAnimationControllerThinning::Create(this)
+ .PassAs<ScrollbarAnimationController>();
+ break;
+ }
+ case LayerTreeSettings::NoAnimator:
+ NOTREACHED();
+ break;
}
}
void LayerImpl::SetHorizontalScrollbarLayer(
- ScrollbarLayerImpl* scrollbar_layer) {
+ ScrollbarLayerImplBase* scrollbar_layer) {
horizontal_scrollbar_layer_ = scrollbar_layer;
if (horizontal_scrollbar_layer_)
horizontal_scrollbar_layer_->set_scroll_layer_id(id());
}
-void LayerImpl::SetVerticalScrollbarLayer(ScrollbarLayerImpl* scrollbar_layer) {
+void LayerImpl::SetVerticalScrollbarLayer(
+ ScrollbarLayerImplBase* scrollbar_layer) {
vertical_scrollbar_layer_ = scrollbar_layer;
if (vertical_scrollbar_layer_)
vertical_scrollbar_layer_->set_scroll_layer_id(id());
@@ -1034,9 +1188,6 @@ CompositingReasonsAsValue(CompositingReasons reasons) {
if (reasons & kCompositingReasonOverflowScrollingTouch)
reason_list->AppendString("Is a scrollable overflow element");
- if (reasons & kCompositingReasonBlending)
- reason_list->AppendString("Has a blend mode");
-
if (reasons & kCompositingReasonAssumedOverlap)
reason_list->AppendString("Might overlap a composited animation");
@@ -1109,12 +1260,19 @@ CompositingReasonsAsValue(CompositingReasons reasons) {
if (reasons & kCompositingReasonLayerForMask)
reason_list->AppendString("Is a mask layer");
+ if (reasons & kCompositingReasonOverflowScrollingParent)
+ reason_list->AppendString("Scroll parent is not an ancestor");
+
+ if (reasons & kCompositingReasonOutOfFlowClipping)
+ reason_list->AppendString("Has clipping ancestor");
+
return reason_list.PassAs<base::Value>();
}
void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
TracedValue::MakeDictIntoImplicitSnapshot(state, LayerTypeAsString(), this);
state->SetInteger("layer_id", id());
+ state->SetString("layer_name", debug_name());
state->Set("bounds", MathUtil::AsValue(bounds()).release());
state->SetInteger("draws_content", DrawsContent());
state->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
@@ -1128,6 +1286,20 @@ void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
&clipped);
state->Set("layer_quad", MathUtil::AsValue(layer_quad).release());
+ if (!touch_event_handler_region_.IsEmpty()) {
+ state->Set("touch_event_handler_region",
+ touch_event_handler_region_.AsValue().release());
+ }
+ if (have_wheel_event_handlers_) {
+ gfx::Rect wheel_rect(content_bounds());
+ Region wheel_region(wheel_rect);
+ state->Set("wheel_event_handler_region",
+ wheel_region.AsValue().release());
+ }
+ if (!non_fast_scrollable_region_.IsEmpty()) {
+ state->Set("non_fast_scrollable_region",
+ non_fast_scrollable_region_.AsValue().release());
+ }
scoped_ptr<base::ListValue> children_list(new base::ListValue());
for (size_t i = 0; i < children_.size(); ++i)
@@ -1137,6 +1309,12 @@ void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
state->Set("mask_layer", mask_layer_->AsValue().release());
if (replica_layer_)
state->Set("replica_layer", replica_layer_->AsValue().release());
+
+ if (scroll_parent_)
+ state->SetInteger("scroll_parent", scroll_parent_->id());
+
+ if (clip_parent_)
+ state->SetInteger("clip_parent", clip_parent_->id());
}
size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; }
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index 90da41a1c6c..ba0ff7b8216 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -5,6 +5,7 @@
#ifndef CC_LAYERS_LAYER_IMPL_H_
#define CC_LAYERS_LAYER_IMPL_H_
+#include <set>
#include <string>
#include "base/logging.h"
@@ -44,7 +45,7 @@ class LayerTreeImpl;
class QuadSink;
class Renderer;
class ScrollbarAnimationController;
-class ScrollbarLayerImpl;
+class ScrollbarLayerImplBase;
class Layer;
struct AppendQuadsData;
@@ -83,6 +84,38 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
// Warning: This does not preserve tree structure invariants.
void ClearChildList();
+ bool HasAncestor(const LayerImpl* ancestor) const;
+
+ void SetScrollParent(LayerImpl* parent);
+
+ LayerImpl* scroll_parent() { return scroll_parent_; }
+ const LayerImpl* scroll_parent() const { return scroll_parent_; }
+
+ void SetScrollChildren(std::set<LayerImpl*>* children);
+ void RemoveScrollChild(LayerImpl* child);
+
+ std::set<LayerImpl*>* scroll_children() { return scroll_children_.get(); }
+ const std::set<LayerImpl*>* scroll_children() const {
+ return scroll_children_.get();
+ }
+
+ void SetClipParent(LayerImpl* ancestor);
+
+ LayerImpl* clip_parent() {
+ return clip_parent_;
+ }
+ const LayerImpl* clip_parent() const {
+ return clip_parent_;
+ }
+
+ void SetClipChildren(std::set<LayerImpl*>* children);
+ void RemoveClipChild(LayerImpl* child);
+
+ std::set<LayerImpl*>* clip_children() { return clip_children_.get(); }
+ const std::set<LayerImpl*>* clip_children() const {
+ return clip_children_.get();
+ }
+
void PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests);
void TakeCopyRequestsAndTransformToTarget(
ScopedPtrVector<CopyOutputRequest>* request);
@@ -128,7 +161,7 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
virtual void UpdateTilePriorities() {}
- virtual ScrollbarLayerImpl* ToScrollbarLayer();
+ virtual ScrollbarLayerImplBase* ToScrollbarLayer();
// Returns true if this layer has content to draw.
void SetDrawsContent(bool draws_content);
@@ -284,6 +317,9 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
RenderSurfaceImpl* render_surface() const {
return draw_properties_.render_surface.get();
}
+ int num_unclipped_descendants() const {
+ return draw_properties_.num_unclipped_descendants;
+ }
// The client should be responsible for setting bounds, content bounds and
// contents scale to appropriate values. LayerImpl doesn't calculate any of
@@ -310,6 +346,8 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
void SetScrollOffsetDelegate(
LayerScrollOffsetDelegate* scroll_offset_delegate);
void SetScrollOffset(gfx::Vector2d scroll_offset);
+ void SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset,
+ gfx::Vector2dF scroll_delta);
gfx::Vector2d scroll_offset() const { return scroll_offset_; }
void SetMaxScrollOffset(gfx::Vector2d max_scroll_offset);
@@ -330,7 +368,8 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
void SetScrollable(bool scrollable) { scrollable_ = scrollable; }
bool scrollable() const { return scrollable_; }
- void ApplySentScrollDeltas();
+ void ApplySentScrollDeltasFromAbortedCommit();
+ void ApplyScrollDeltasSinceBeginFrame();
void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) {
should_scroll_on_main_thread_ = should_scroll_on_main_thread;
@@ -413,15 +452,13 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
return scrollbar_animation_controller_.get();
}
- void SetScrollbarOpacity(float opacity);
-
- void SetHorizontalScrollbarLayer(ScrollbarLayerImpl* scrollbar_layer);
- ScrollbarLayerImpl* horizontal_scrollbar_layer() {
+ void SetHorizontalScrollbarLayer(ScrollbarLayerImplBase* scrollbar_layer);
+ ScrollbarLayerImplBase* horizontal_scrollbar_layer() {
return horizontal_scrollbar_layer_;
}
- void SetVerticalScrollbarLayer(ScrollbarLayerImpl* scrollbar_layer);
- ScrollbarLayerImpl* vertical_scrollbar_layer() {
+ void SetVerticalScrollbarLayer(ScrollbarLayerImplBase* scrollbar_layer);
+ ScrollbarLayerImplBase* vertical_scrollbar_layer() {
return vertical_scrollbar_layer_;
}
@@ -475,6 +512,18 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
// Properties internal to LayerImpl
LayerImpl* parent_;
OwnedLayerImplList children_;
+
+ LayerImpl* scroll_parent_;
+
+ // Storing a pointer to a set rather than a set since this will be rarely
+ // used. If this pointer turns out to be too heavy, we could have this (and
+ // the scroll parent above) be stored in a LayerImpl -> scroll_info
+ // map somewhere.
+ scoped_ptr<std::set<LayerImpl*> > scroll_children_;
+
+ LayerImpl* clip_parent_;
+ scoped_ptr<std::set<LayerImpl*> > clip_children_;
+
// mask_layer_ can be temporarily stolen during tree sync, we need this ID to
// confirm newly assigned layer is still the previous one
int mask_layer_id_;
@@ -567,8 +616,8 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
// Weak pointers to this layer's scrollbars, if it has them. Updated during
// tree synchronization.
- ScrollbarLayerImpl* horizontal_scrollbar_layer_;
- ScrollbarLayerImpl* vertical_scrollbar_layer_;
+ ScrollbarLayerImplBase* horizontal_scrollbar_layer_;
+ ScrollbarLayerImplBase* vertical_scrollbar_layer_;
ScopedPtrVector<CopyOutputRequest> copy_requests_;
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index 9c6dbfe3790..1ab7a71b2ca 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -502,7 +502,7 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsNoDelegate) {
EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
- layer()->ApplySentScrollDeltas();
+ layer()->ApplySentScrollDeltasFromAbortedCommit();
EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
EXPECT_VECTOR_EQ(scroll_delta - sent_scroll_delta, layer()->ScrollDelta());
@@ -527,7 +527,7 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsWithIgnoringDelegate) {
EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
- layer()->ApplySentScrollDeltas();
+ layer()->ApplySentScrollDeltasFromAbortedCommit();
EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
EXPECT_VECTOR_EQ(scroll_offset + sent_scroll_delta, layer()->scroll_offset());
@@ -551,7 +551,7 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) {
EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
- layer()->ApplySentScrollDeltas();
+ layer()->ApplySentScrollDeltasFromAbortedCommit();
EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
EXPECT_VECTOR_EQ(scroll_offset + sent_scroll_delta, layer()->scroll_offset());
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index bd1e16fa658..c5c5286d2aa 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -559,7 +559,8 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(
gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDoubleSided(false));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDebugName("Test Layer"));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTouchEventHandlerRegion(
+ gfx::Rect(10, 10)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDrawCheckerboardForMissingTiles(
!test_layer->DrawCheckerboardForMissingTiles()));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurface(true));
diff --git a/chromium/cc/layers/nine_patch_layer.cc b/chromium/cc/layers/nine_patch_layer.cc
index e32f6e0b125..5e000072f28 100644
--- a/chromium/cc/layers/nine_patch_layer.cc
+++ b/chromium/cc/layers/nine_patch_layer.cc
@@ -8,16 +8,55 @@
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/resource_update.h"
#include "cc/resources/resource_update_queue.h"
+#include "cc/resources/scoped_ui_resource.h"
+#include "cc/resources/ui_resource_bitmap.h"
#include "cc/trees/layer_tree_host.h"
namespace cc {
+
+namespace {
+
+class ScopedUIResourceHolder : public NinePatchLayer::UIResourceHolder {
+ public:
+ static scoped_ptr<ScopedUIResourceHolder> Create(LayerTreeHost* host,
+ const SkBitmap& skbitmap) {
+ return make_scoped_ptr(new ScopedUIResourceHolder(host, skbitmap));
+ }
+ virtual UIResourceId id() OVERRIDE { return resource_->id(); }
+
+ private:
+ ScopedUIResourceHolder(LayerTreeHost* host, const SkBitmap& skbitmap) {
+ resource_ = ScopedUIResource::Create(host, UIResourceBitmap(skbitmap));
+ }
+
+ scoped_ptr<ScopedUIResource> resource_;
+};
+
+class SharedUIResourceHolder : public NinePatchLayer::UIResourceHolder {
+ public:
+ static scoped_ptr<SharedUIResourceHolder> Create(UIResourceId id) {
+ return make_scoped_ptr(new SharedUIResourceHolder(id));
+ }
+
+ virtual UIResourceId id() OVERRIDE { return id_; }
+
+ private:
+ explicit SharedUIResourceHolder(UIResourceId id) : id_(id) {}
+
+ UIResourceId id_;
+};
+
+} // anonymous namespace
+
+
+NinePatchLayer::UIResourceHolder::~UIResourceHolder() {}
+
scoped_refptr<NinePatchLayer> NinePatchLayer::Create() {
return make_scoped_refptr(new NinePatchLayer());
}
-NinePatchLayer::NinePatchLayer()
- : bitmap_dirty_(false) {}
+NinePatchLayer::NinePatchLayer() : fill_center_(false) {}
NinePatchLayer::~NinePatchLayer() {}
@@ -26,90 +65,89 @@ scoped_ptr<LayerImpl> NinePatchLayer::CreateLayerImpl(
return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}
-void NinePatchLayer::SetTexturePriorities(
- const PriorityCalculator& priority_calc) {
- if (resource_ && !resource_->texture()->resource_manager()) {
- // Release the resource here, as it is no longer tied to a resource manager.
- resource_.reset();
- if (!bitmap_.isNull())
- CreateResource();
- } else if (bitmap_dirty_ && DrawsContent()) {
- CreateResource();
- }
+void NinePatchLayer::SetLayerTreeHost(LayerTreeHost* host) {
+ if (host == layer_tree_host())
+ return;
- if (resource_) {
- resource_->texture()->set_request_priority(
- PriorityCalculator::UIPriority(true));
- GLenum texture_format =
- layer_tree_host()->GetRendererCapabilities().best_texture_format;
- resource_->texture()->SetDimensions(
- gfx::Size(bitmap_.width(), bitmap_.height()), texture_format);
- }
-}
+ Layer::SetLayerTreeHost(host);
-void NinePatchLayer::SetBitmap(const SkBitmap& bitmap, gfx::Rect aperture) {
- bitmap_ = bitmap;
- image_aperture_ = aperture;
- bitmap_dirty_ = true;
- SetNeedsDisplay();
+ // Recreate the resource hold against the new LTH.
+ RecreateUIResourceHolder();
}
-bool NinePatchLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
- bool updated = Layer::Update(queue, occlusion);
-
- CreateUpdaterIfNeeded();
-
- if (resource_ &&
- (bitmap_dirty_ || resource_->texture()->resource_id() == 0)) {
- gfx::Rect content_rect(0, 0, bitmap_.width(), bitmap_.height());
- ResourceUpdate upload = ResourceUpdate::Create(resource_->texture(),
- &bitmap_,
- content_rect,
- content_rect,
- gfx::Vector2d());
- queue->AppendFullUpload(upload);
- bitmap_dirty_ = false;
- updated = true;
- }
- return updated;
+void NinePatchLayer::RecreateUIResourceHolder() {
+ ui_resource_holder_.reset();
+ if (!layer_tree_host() || bitmap_.empty())
+ return;
+
+ ui_resource_holder_ =
+ ScopedUIResourceHolder::Create(layer_tree_host(), bitmap_);
}
-void NinePatchLayer::CreateUpdaterIfNeeded() {
- if (updater_.get())
+void NinePatchLayer::SetBorder(gfx::Rect border) {
+ if (border == border_)
return;
+ border_ = border;
+ SetNeedsCommit();
+}
- updater_ = ImageLayerUpdater::Create();
+void NinePatchLayer::SetBitmap(const SkBitmap& skbitmap, gfx::Rect aperture) {
+ image_aperture_ = aperture;
+ bitmap_ = skbitmap;
+
+ // TODO(ccameron): Remove this. This provides the default border that was
+ // provided before borders were required to be explicitly provided. Once Blink
+ // fixes its callers to call SetBorder, this can be removed.
+ SetBorder(gfx::Rect(aperture.x(),
+ aperture.y(),
+ skbitmap.width() - aperture.width(),
+ skbitmap.height() - aperture.height()));
+ RecreateUIResourceHolder();
+ SetNeedsCommit();
}
-void NinePatchLayer::CreateResource() {
- DCHECK(!bitmap_.isNull());
- CreateUpdaterIfNeeded();
- updater_->SetBitmap(bitmap_);
+void NinePatchLayer::SetUIResourceId(UIResourceId resource_id,
+ gfx::Rect aperture) {
+ if (ui_resource_holder_ && ui_resource_holder_->id() == resource_id &&
+ image_aperture_ == aperture)
+ return;
- if (!resource_) {
- resource_ = updater_->CreateResource(
- layer_tree_host()->contents_texture_manager());
+ image_aperture_ = aperture;
+ if (resource_id) {
+ ui_resource_holder_ = SharedUIResourceHolder::Create(resource_id);
+ } else {
+ ui_resource_holder_.reset();
}
+
+ SetNeedsCommit();
+}
+
+void NinePatchLayer::SetFillCenter(bool fill_center) {
+ if (fill_center_ == fill_center)
+ return;
+
+ fill_center_ = fill_center;
+ SetNeedsCommit();
}
bool NinePatchLayer::DrawsContent() const {
- bool draws = !bitmap_.isNull() &&
- Layer::DrawsContent() &&
- bitmap_.width() &&
- bitmap_.height();
- return draws;
+ return ui_resource_holder_ && ui_resource_holder_->id() &&
+ Layer::DrawsContent();
}
void NinePatchLayer::PushPropertiesTo(LayerImpl* layer) {
Layer::PushPropertiesTo(layer);
NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer);
- if (resource_) {
- DCHECK(!bitmap_.isNull());
- layer_impl->SetResourceId(resource_->texture()->resource_id());
- layer_impl->SetLayout(
- gfx::Size(bitmap_.width(), bitmap_.height()), image_aperture_);
+ if (!ui_resource_holder_) {
+ layer_impl->SetUIResourceId(0);
+ } else {
+ DCHECK(layer_tree_host());
+
+ gfx::Size image_size =
+ layer_tree_host()->GetUIResourceSize(ui_resource_holder_->id());
+ layer_impl->SetUIResourceId(ui_resource_holder_->id());
+ layer_impl->SetLayout(image_size, image_aperture_, border_, fill_center_);
}
}
diff --git a/chromium/cc/layers/nine_patch_layer.h b/chromium/cc/layers/nine_patch_layer.h
index 35d08812cff..5880635389a 100644
--- a/chromium/cc/layers/nine_patch_layer.h
+++ b/chromium/cc/layers/nine_patch_layer.h
@@ -8,47 +8,60 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "cc/layers/layer.h"
-#include "cc/resources/image_layer_updater.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+#include "cc/resources/ui_resource_client.h"
#include "ui/gfx/rect.h"
namespace cc {
-class ResourceUpdateQueue;
+class LayerTreeHost;
+class ScopedUIResource;
class CC_EXPORT NinePatchLayer : public Layer {
public:
static scoped_refptr<NinePatchLayer> Create();
virtual bool DrawsContent() const OVERRIDE;
- virtual void SetTexturePriorities(const PriorityCalculator& priority_calc)
- OVERRIDE;
- virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+ virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
+
+ // |border| is the space around the center rectangular region in layer space
+ // (known as aperture in image space). |border.x()| and |border.y()| are the
+ // size of the left and top boundary, respectively.
+ // |border.width()-border.x()| and |border.height()-border.y()| are the size
+ // of the right and bottom boundary, respectively.
+ void SetBorder(gfx::Rect border);
+
// aperture is in the pixel space of the bitmap resource and refers to
// the center patch of the ninepatch (which is unused in this
// implementation). We split off eight rects surrounding it and stick them
// on the edges of the layer. The corners are unscaled, the top and bottom
// rects are x-stretched to fit, and the left and right rects are
// y-stretched to fit.
- void SetBitmap(const SkBitmap& bitmap, gfx::Rect aperture);
+ void SetBitmap(const SkBitmap& skbitmap, gfx::Rect aperture);
+
+ // An alternative way of setting the resource to allow for sharing.
+ void SetUIResourceId(UIResourceId resource_id, gfx::Rect aperture);
+ void SetFillCenter(bool fill_center);
+
+ class UIResourceHolder {
+ public:
+ virtual UIResourceId id() = 0;
+ virtual ~UIResourceHolder();
+ };
private:
NinePatchLayer();
virtual ~NinePatchLayer();
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
+ void RecreateUIResourceHolder();
- void CreateUpdaterIfNeeded();
- void CreateResource();
-
- scoped_refptr<ImageLayerUpdater> updater_;
- scoped_ptr<LayerUpdater::Resource> resource_;
-
+ gfx::Rect border_;
+ bool fill_center_;
+ scoped_ptr<UIResourceHolder> ui_resource_holder_;
SkBitmap bitmap_;
- bool bitmap_dirty_;
// The transparent center region that shows the parent layer's contents in
// image space.
diff --git a/chromium/cc/layers/nine_patch_layer_impl.cc b/chromium/cc/layers/nine_patch_layer_impl.cc
index 103f7656eb8..f609c3d2fda 100644
--- a/chromium/cc/layers/nine_patch_layer_impl.cc
+++ b/chromium/cc/layers/nine_patch_layer_impl.cc
@@ -6,15 +6,18 @@
#include "base/strings/stringprintf.h"
#include "base/values.h"
+#include "cc/base/math_util.h"
#include "cc/layers/quad_sink.h"
#include "cc/quads/texture_draw_quad.h"
+#include "cc/trees/layer_tree_impl.h"
#include "ui/gfx/rect_f.h"
namespace cc {
NinePatchLayerImpl::NinePatchLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
- resource_id_(0) {}
+ fill_center_(false),
+ ui_resource_id_(0) {}
NinePatchLayerImpl::~NinePatchLayerImpl() {}
@@ -31,11 +34,8 @@ void NinePatchLayerImpl::PushPropertiesTo(LayerImpl* layer) {
LayerImpl::PushPropertiesTo(layer);
NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer);
- if (!resource_id_)
- return;
-
- layer_impl->SetResourceId(resource_id_);
- layer_impl->SetLayout(image_bounds_, image_aperture_);
+ layer_impl->SetUIResourceId(ui_resource_id_);
+ layer_impl->SetLayout(image_bounds_, image_aperture_, border_, fill_center_);
}
static gfx::RectF NormalizedRect(float x,
@@ -50,120 +50,188 @@ static gfx::RectF NormalizedRect(float x,
height / total_height);
}
-void NinePatchLayerImpl::SetLayout(gfx::Size image_bounds, gfx::Rect aperture) {
+void NinePatchLayerImpl::SetUIResourceId(UIResourceId uid) {
+ if (uid == ui_resource_id_)
+ return;
+ ui_resource_id_ = uid;
+ NoteLayerPropertyChanged();
+}
+
+void NinePatchLayerImpl::SetLayout(gfx::Size image_bounds,
+ gfx::Rect aperture,
+ gfx::Rect border,
+ bool fill_center) {
+ // This check imposes an ordering on the call sequence. An UIResource must
+ // exist before SetLayout can be called.
+ DCHECK(ui_resource_id_);
+
+ // TODO(ccameron): the following "greater than or equal to" (GE) checks should
+ // be greater than (GT) to avoid degenerate nine-patches. The relaxed
+ // condition "equal to" is a workaround for the overhang shadow use case and
+ // should be investigated further.
+
+ // |border| is in layer space. It cannot exceed the bounds of the layer.
+ DCHECK(!border.size().IsEmpty());
+ DCHECK_GE(bounds().width(), border.width());
+ DCHECK_GE(bounds().height(), border.height());
+
+ // Sanity Check on |border|
+ DCHECK_LT(border.x(), border.width());
+ DCHECK_LT(border.y(), border.height());
+ DCHECK_GE(border.x(), 0);
+ DCHECK_GE(border.y(), 0);
+
+ // |aperture| is in image space. It cannot exceed the bounds of the bitmap.
+ DCHECK(!aperture.size().IsEmpty());
+ DCHECK(gfx::Rect(image_bounds.width(), image_bounds.height())
+ .Contains(aperture));
+
+ // Avoid the degenerate cases where the aperture touches the edge of the
+ // image.
+ DCHECK_LT(aperture.width(), image_bounds.width() - 1);
+ DCHECK_LT(aperture.height(), image_bounds.height() - 1);
+ DCHECK_GT(aperture.x(), 0);
+ DCHECK_GT(aperture.y(), 0);
+
+ if (image_bounds_ == image_bounds && image_aperture_ == aperture &&
+ border_ == border && fill_center_ == fill_center)
+ return;
+
image_bounds_ = image_bounds;
image_aperture_ = aperture;
+ border_ = border;
+ fill_center_ = fill_center;
+
+ NoteLayerPropertyChanged();
}
bool NinePatchLayerImpl::WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) {
- if (!resource_id_ || draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
+ if (!ui_resource_id_ || draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
return false;
return LayerImpl::WillDraw(draw_mode, resource_provider);
}
void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
- DCHECK(resource_id_);
-
SharedQuadState* shared_quad_state =
quad_sink->UseSharedQuadState(CreateSharedQuadState());
AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ if (!ui_resource_id_)
+ return;
+
+ ResourceProvider::ResourceId resource =
+ layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_);
+
+ if (!resource)
+ return;
+
static const bool flipped = false;
static const bool premultiplied_alpha = true;
DCHECK(!bounds().IsEmpty());
- // NinePatch border widths in bitmap pixel space
- int left_width = image_aperture_.x();
- int top_height = image_aperture_.y();
- int right_width = image_bounds_.width() - image_aperture_.right();
- int bottom_height = image_bounds_.height() - image_aperture_.bottom();
+ // NinePatch border widths in layer space.
+ int layer_left_width = border_.x();
+ int layer_top_height = border_.y();
+ int layer_right_width = border_.width() - layer_left_width;
+ int layer_bottom_height = border_.height() - layer_top_height;
- // If layer can't fit the corners, clip to show the outer edges of the
- // image.
- int corner_total_width = left_width + right_width;
- int middle_width = bounds().width() - corner_total_width;
- if (middle_width < 0) {
- float left_width_proportion =
- static_cast<float>(left_width) / corner_total_width;
- int left_width_crop = middle_width * left_width_proportion;
- left_width += left_width_crop;
- right_width = bounds().width() - left_width;
- middle_width = 0;
- }
- int corner_total_height = top_height + bottom_height;
- int middle_height = bounds().height() - corner_total_height;
- if (middle_height < 0) {
- float top_height_proportion =
- static_cast<float>(top_height) / corner_total_height;
- int top_height_crop = middle_height * top_height_proportion;
- top_height += top_height_crop;
- bottom_height = bounds().height() - top_height;
- middle_height = 0;
- }
+ int layer_middle_width = bounds().width() - border_.width();
+ int layer_middle_height = bounds().height() - border_.height();
// Patch positions in layer space
- gfx::Rect top_left(0, 0, left_width, top_height);
- gfx::Rect top_right(
- bounds().width() - right_width, 0, right_width, top_height);
- gfx::Rect bottom_left(
- 0, bounds().height() - bottom_height, left_width, bottom_height);
- gfx::Rect bottom_right(
- top_right.x(), bottom_left.y(), right_width, bottom_height);
- gfx::Rect top(top_left.right(), 0, middle_width, top_height);
- gfx::Rect left(0, top_left.bottom(), left_width, middle_height);
- gfx::Rect right(top_right.x(),
- top_right.bottom(),
- right_width,
- left.height());
- gfx::Rect bottom(top.x(), bottom_left.y(), top.width(), bottom_height);
-
- float img_width = image_bounds_.width();
- float img_height = image_bounds_.height();
-
+ gfx::Rect layer_top_left(0, 0, layer_left_width, layer_top_height);
+ gfx::Rect layer_top_right(bounds().width() - layer_right_width,
+ 0,
+ layer_right_width,
+ layer_top_height);
+ gfx::Rect layer_bottom_left(0,
+ bounds().height() - layer_bottom_height,
+ layer_left_width,
+ layer_bottom_height);
+ gfx::Rect layer_bottom_right(layer_top_right.x(),
+ layer_bottom_left.y(),
+ layer_right_width,
+ layer_bottom_height);
+ gfx::Rect layer_top(
+ layer_top_left.right(), 0, layer_middle_width, layer_top_height);
+ gfx::Rect layer_left(
+ 0, layer_top_left.bottom(), layer_left_width, layer_middle_height);
+ gfx::Rect layer_right(layer_top_right.x(),
+ layer_top_right.bottom(),
+ layer_right_width,
+ layer_left.height());
+ gfx::Rect layer_bottom(layer_top.x(),
+ layer_bottom_left.y(),
+ layer_top.width(),
+ layer_bottom_height);
+ gfx::Rect layer_center(layer_left_width,
+ layer_top_height,
+ layer_middle_width,
+ layer_middle_height);
+
+ // Note the following values are in image (bitmap) space.
+ float image_width = image_bounds_.width();
+ float image_height = image_bounds_.height();
+
+ int image_aperture_left_width = image_aperture_.x();
+ int image_aperture_top_height = image_aperture_.y();
+ int image_aperture_right_width = image_width - image_aperture_.right();
+ int image_aperture_bottom_height = image_height - image_aperture_.bottom();
// Patch positions in bitmap UV space (from zero to one)
gfx::RectF uv_top_left = NormalizedRect(0,
0,
- left_width,
- top_height,
- img_width,
- img_height);
- gfx::RectF uv_top_right = NormalizedRect(img_width - right_width,
- 0,
- right_width,
- top_height,
- img_width,
- img_height);
- gfx::RectF uv_bottom_left = NormalizedRect(0,
- img_height - bottom_height,
- left_width,
- bottom_height,
- img_width,
- img_height);
- gfx::RectF uv_bottom_right = NormalizedRect(img_width - right_width,
- img_height - bottom_height,
- right_width,
- bottom_height,
- img_width,
- img_height);
- gfx::RectF uv_top(uv_top_left.right(),
- 0,
- (img_width - left_width - right_width) / img_width,
- (top_height) / img_height);
+ image_aperture_left_width,
+ image_aperture_top_height,
+ image_width,
+ image_height);
+ gfx::RectF uv_top_right =
+ NormalizedRect(image_width - image_aperture_right_width,
+ 0,
+ image_aperture_right_width,
+ image_aperture_top_height,
+ image_width,
+ image_height);
+ gfx::RectF uv_bottom_left =
+ NormalizedRect(0,
+ image_height - image_aperture_bottom_height,
+ image_aperture_left_width,
+ image_aperture_bottom_height,
+ image_width,
+ image_height);
+ gfx::RectF uv_bottom_right =
+ NormalizedRect(image_width - image_aperture_right_width,
+ image_height - image_aperture_bottom_height,
+ image_aperture_right_width,
+ image_aperture_bottom_height,
+ image_width,
+ image_height);
+ gfx::RectF uv_top(
+ uv_top_left.right(),
+ 0,
+ (image_width - image_aperture_left_width - image_aperture_right_width) /
+ image_width,
+ (image_aperture_top_height) / image_height);
gfx::RectF uv_left(0,
- uv_top_left.bottom(),
- left_width / img_width,
- (img_height - top_height - bottom_height) / img_height);
+ uv_top_left.bottom(),
+ image_aperture_left_width / image_width,
+ (image_height - image_aperture_top_height -
+ image_aperture_bottom_height) /
+ image_height);
gfx::RectF uv_right(uv_top_right.x(),
- uv_top_right.bottom(),
- right_width / img_width,
- uv_left.height());
+ uv_top_right.bottom(),
+ image_aperture_right_width / image_width,
+ uv_left.height());
gfx::RectF uv_bottom(uv_top.x(),
- uv_bottom_left.y(),
- uv_top.width(),
- bottom_height / img_height);
+ uv_bottom_left.y(),
+ uv_top.width(),
+ image_aperture_bottom_height / image_height);
+ gfx::RectF uv_center(uv_top_left.right(),
+ uv_top_left.bottom(),
+ uv_top.width(),
+ uv_left.height());
// Nothing is opaque here.
// TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
@@ -173,9 +241,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- top_left,
+ layer_top_left,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_top_left.origin(),
uv_top_left.bottom_right(),
@@ -186,9 +254,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- top_right,
+ layer_top_right,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_top_right.origin(),
uv_top_right.bottom_right(),
@@ -199,9 +267,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- bottom_left,
+ layer_bottom_left,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_bottom_left.origin(),
uv_bottom_left.bottom_right(),
@@ -212,9 +280,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- bottom_right,
+ layer_bottom_right,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_bottom_right.origin(),
uv_bottom_right.bottom_right(),
@@ -225,9 +293,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- top,
+ layer_top,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_top.origin(),
uv_top.bottom_right(),
@@ -238,9 +306,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- left,
+ layer_left,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_left.origin(),
uv_left.bottom_right(),
@@ -251,9 +319,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- right,
+ layer_right,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_right.origin(),
uv_right.bottom_right(),
@@ -264,9 +332,9 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- bottom,
+ layer_bottom,
opaque_rect,
- resource_id_,
+ resource,
premultiplied_alpha,
uv_bottom.origin(),
uv_bottom.bottom_right(),
@@ -274,10 +342,21 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
vertex_opacity,
flipped);
quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-}
-void NinePatchLayerImpl::DidLoseOutputSurface() {
- resource_id_ = 0;
+ if (fill_center_) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_center,
+ opaque_rect,
+ resource,
+ premultiplied_alpha,
+ uv_center.origin(),
+ uv_center.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ }
}
const char* NinePatchLayerImpl::LayerTypeAsString() const {
@@ -294,10 +373,12 @@ base::DictionaryValue* NinePatchLayerImpl::LayerTreeAsJson() const {
list->AppendInteger(image_aperture_.size().height());
result->Set("ImageAperture", list);
- list = new base::ListValue;
- list->AppendInteger(image_bounds_.width());
- list->AppendInteger(image_bounds_.height());
- result->Set("ImageBounds", list);
+ result->Set("ImageBounds", MathUtil::AsValue(image_bounds_).release());
+ result->Set("Border", MathUtil::AsValue(border_).release());
+
+ base::FundamentalValue* fill_center =
+ base::Value::CreateBooleanValue(fill_center_);
+ result->Set("FillCenter", fill_center);
return result;
}
diff --git a/chromium/cc/layers/nine_patch_layer_impl.h b/chromium/cc/layers/nine_patch_layer_impl.h
index bc442d43f33..ba414aed391 100644
--- a/chromium/cc/layers/nine_patch_layer_impl.h
+++ b/chromium/cc/layers/nine_patch_layer_impl.h
@@ -10,6 +10,7 @@
#include "cc/base/cc_export.h"
#include "cc/layers/layer_impl.h"
#include "cc/resources/resource_provider.h"
+#include "cc/resources/ui_resource_client.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
@@ -27,8 +28,37 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl {
}
virtual ~NinePatchLayerImpl();
- void SetResourceId(unsigned id) { resource_id_ = id; }
- void SetLayout(gfx::Size image_bounds, gfx::Rect aperture);
+
+ void SetUIResourceId(UIResourceId uid);
+
+ // The bitmap stretches out the bounds of the layer. The following picture
+ // illustrates the parameters associated with the dimensions.
+ //
+ // Layer space layout Bitmap space layout
+ //
+ // ------------------------ ~~~~~~~~~~ W ~~~~~~~~~~
+ // | : | : : |
+ // | C | : Y |
+ // | : | : : |
+ // | ------------ | :~~X~~------------ |
+ // | | | | : | : |
+ // | | | | : | : |
+ // |~~A~~| |~~B~~| H | Q |
+ // | | | | : | : |
+ // | ------------ | : ~~~~~P~~~~~ |
+ // | : | : |
+ // | D | : |
+ // | : | : |
+ // ------------------------ ------------------------
+ //
+ // |image_bounds| = (W, H)
+ // |image_aperture| = (X, Y, P, Q)
+ // |border| = (A, C, A + B, C + D)
+ // |fill_center| indicates whether to draw the center quad or not.
+ void SetLayout(gfx::Size image_bounds,
+ gfx::Rect image_aperture,
+ gfx::Rect border,
+ bool fill_center);
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
@@ -39,7 +69,6 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl {
virtual void AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) OVERRIDE;
virtual ResourceProvider::ResourceId ContentsResourceId() const OVERRIDE;
- virtual void DidLoseOutputSurface() OVERRIDE;
virtual base::DictionaryValue* LayerTreeAsJson() const OVERRIDE;
@@ -56,7 +85,12 @@ class CC_EXPORT NinePatchLayerImpl : public LayerImpl {
// image space.
gfx::Rect image_aperture_;
- ResourceProvider::ResourceId resource_id_;
+ // An inset border that the patches will be mapped to.
+ gfx::Rect border_;
+
+ bool fill_center_;
+
+ UIResourceId ui_resource_id_;
DISALLOW_COPY_AND_ASSIGN(NinePatchLayerImpl);
};
diff --git a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
index 1985bd4c29c..0fbc645be1b 100644
--- a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <stdio.h>
-
+#include "base/containers/hash_tables.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/nine_patch_layer_impl.h"
#include "cc/quads/texture_draw_quad.h"
+#include "cc/resources/ui_resource_bitmap.h"
+#include "cc/resources/ui_resource_client.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
@@ -22,6 +23,40 @@
namespace cc {
namespace {
+class FakeUIResourceLayerTreeHostImpl : public FakeLayerTreeHostImpl {
+ public:
+ explicit FakeUIResourceLayerTreeHostImpl(Proxy* proxy)
+ : FakeLayerTreeHostImpl(proxy), fake_next_resource_id_(1) {}
+
+ virtual void CreateUIResource(
+ UIResourceId uid,
+ const UIResourceBitmap& bitmap) OVERRIDE {
+ if (ResourceIdForUIResource(uid))
+ DeleteUIResource(uid);
+ fake_ui_resource_map_[uid] = fake_next_resource_id_;
+ }
+
+ virtual void DeleteUIResource(UIResourceId uid) OVERRIDE {
+ ResourceProvider::ResourceId id = ResourceIdForUIResource(uid);
+ if (id)
+ fake_ui_resource_map_.erase(uid);
+ }
+
+ virtual ResourceProvider::ResourceId ResourceIdForUIResource(
+ UIResourceId uid) const OVERRIDE {
+ UIResourceMap::const_iterator iter = fake_ui_resource_map_.find(uid);
+ if (iter != fake_ui_resource_map_.end())
+ return iter->second;
+ return 0;
+ }
+
+ private:
+ ResourceProvider::ResourceId fake_next_resource_id_;
+ typedef base::hash_map<UIResourceId, ResourceProvider::ResourceId>
+ UIResourceMap;
+ UIResourceMap fake_ui_resource_map_;
+};
+
gfx::Rect ToRoundedIntRect(gfx::RectF rect_f) {
return gfx::Rect(gfx::ToRoundedInt(rect_f.x()),
gfx::ToRoundedInt(rect_f.y()),
@@ -29,19 +64,21 @@ gfx::Rect ToRoundedIntRect(gfx::RectF rect_f) {
gfx::ToRoundedInt(rect_f.height()));
}
-TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
- // Input is a 100x100 bitmap with a 40x50 aperture at x=20, y=30.
- // The bounds of the layer are set to 400x400, so the draw quads
- // generated should leave the border width (40) intact.
+void NinePatchLayerLayoutTest(gfx::Size bitmap_size,
+ gfx::Rect aperture_rect,
+ gfx::Size layer_size,
+ gfx::Rect border,
+ bool fill_center,
+ size_t expected_quad_size) {
MockQuadCuller quad_culler;
- gfx::Size bitmap_size(100, 100);
- gfx::Size layer_size(400, 400);
gfx::Rect visible_content_rect(layer_size);
- gfx::Rect aperture_rect(20, 30, 40, 50);
- gfx::Rect scaled_aperture_non_uniform(20, 30, 340, 350);
+ gfx::Rect expected_remaining(border.x(),
+ border.y(),
+ layer_size.width() - border.width(),
+ layer_size.height() - border.height());
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ FakeUIResourceLayerTreeHostImpl host_impl(&proxy);
scoped_ptr<NinePatchLayerImpl> layer =
NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -49,21 +86,26 @@ TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
layer->SetContentBounds(layer_size);
layer->CreateRenderSurface();
layer->draw_properties().render_target = layer.get();
- layer->SetLayout(bitmap_size, aperture_rect);
- layer->SetResourceId(1);
- // This scale should not affect the generated quad geometry, but only
- // the shared draw transform.
- gfx::Transform transform;
- transform.Scale(10, 10);
- layer->draw_properties().target_space_transform = transform;
+ UIResourceId uid = 1;
+ SkBitmap skbitmap;
+ skbitmap.setConfig(
+ SkBitmap::kARGB_8888_Config, bitmap_size.width(), bitmap_size.height());
+ skbitmap.allocPixels();
+ skbitmap.setImmutable();
+ UIResourceBitmap bitmap(skbitmap);
+
+ host_impl.CreateUIResource(uid, bitmap);
+ layer->SetUIResourceId(uid);
+ layer->SetLayout(bitmap_size, aperture_rect, border, fill_center);
AppendQuadsData data;
layer->AppendQuads(&quad_culler, &data);
// Verify quad rects
const QuadList& quads = quad_culler.quad_list();
- EXPECT_EQ(8u, quads.size());
+ EXPECT_EQ(expected_quad_size, quads.size());
+
Region remaining(visible_content_rect);
for (size_t i = 0; i < quads.size(); ++i) {
DrawQuad* quad = quads[i];
@@ -71,12 +113,16 @@ TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
EXPECT_TRUE(visible_content_rect.Contains(quad_rect)) << i;
EXPECT_TRUE(remaining.Contains(quad_rect)) << i;
- EXPECT_EQ(transform, quad->quadTransform());
remaining.Subtract(Region(quad_rect));
}
- EXPECT_RECT_EQ(scaled_aperture_non_uniform, remaining.bounds());
- Region scaled_aperture_region(scaled_aperture_non_uniform);
- EXPECT_EQ(scaled_aperture_region, remaining);
+
+ // Check if the left-over quad is the same size as the mapped aperture quad in
+ // layer space.
+ if (!fill_center) {
+ EXPECT_RECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds()));
+ } else {
+ EXPECT_TRUE(remaining.bounds().IsEmpty());
+ }
// Verify UV rects
gfx::Rect bitmap_rect(bitmap_size);
@@ -89,66 +135,59 @@ TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
tex_rect.Scale(bitmap_size.width(), bitmap_size.height());
tex_remaining.Subtract(Region(ToRoundedIntRect(tex_rect)));
}
- EXPECT_RECT_EQ(aperture_rect, tex_remaining.bounds());
- Region aperture_region(aperture_rect);
- EXPECT_EQ(aperture_region, tex_remaining);
-}
-
-TEST(NinePatchLayerImplTest, VerifyDrawQuadsForSqueezedLayer) {
- // Test with a layer much smaller than the bitmap.
- MockQuadCuller quad_culler;
- gfx::Size bitmap_size(101, 101);
- gfx::Size layer_size(51, 51);
- gfx::Rect visible_content_rect(layer_size);
- gfx::Rect aperture_rect(20, 30, 40, 45); // rightWidth: 40, botHeight: 25
-
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<NinePatchLayerImpl> layer =
- NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
- layer->draw_properties().visible_content_rect = visible_content_rect;
- layer->SetBounds(layer_size);
- layer->SetContentBounds(layer_size);
- layer->CreateRenderSurface();
- layer->draw_properties().render_target = layer.get();
- layer->SetLayout(bitmap_size, aperture_rect);
- layer->SetResourceId(1);
- AppendQuadsData data;
- layer->AppendQuads(&quad_culler, &data);
-
- // Verify corner rects fill the layer and don't overlap
- const QuadList& quads = quad_culler.quad_list();
- EXPECT_EQ(4u, quads.size());
- Region filled;
- for (size_t i = 0; i < quads.size(); ++i) {
- DrawQuad* quad = quads[i];
- gfx::Rect quad_rect = quad->rect;
-
- EXPECT_FALSE(filled.Intersects(quad_rect));
- filled.Union(quad_rect);
+ if (!fill_center) {
+ EXPECT_RECT_EQ(aperture_rect, tex_remaining.bounds());
+ Region aperture_region(aperture_rect);
+ EXPECT_EQ(aperture_region, tex_remaining);
+ } else {
+ EXPECT_TRUE(remaining.bounds().IsEmpty());
}
- Region expected_full(visible_content_rect);
- EXPECT_EQ(expected_full, filled);
+}
- // Verify UV rects cover the corners of the bitmap and the crop is weighted
- // proportionately to the relative corner sizes (for uneven apertures).
- gfx::Rect bitmap_rect(bitmap_size);
- Region tex_remaining(bitmap_rect);
- for (size_t i = 0; i < quads.size(); ++i) {
- DrawQuad* quad = quads[i];
- const TextureDrawQuad* tex_quad = TextureDrawQuad::MaterialCast(quad);
- gfx::RectF tex_rect =
- gfx::BoundingRect(tex_quad->uv_top_left, tex_quad->uv_bottom_right);
- tex_rect.Scale(bitmap_size.width(), bitmap_size.height());
- tex_remaining.Subtract(Region(ToRoundedIntRect(tex_rect)));
- }
- Region expected_remaining_region = Region(gfx::Rect(bitmap_size));
- expected_remaining_region.Subtract(gfx::Rect(0, 0, 17, 28));
- expected_remaining_region.Subtract(gfx::Rect(67, 0, 34, 28));
- expected_remaining_region.Subtract(gfx::Rect(0, 78, 17, 23));
- expected_remaining_region.Subtract(gfx::Rect(67, 78, 34, 23));
- EXPECT_EQ(expected_remaining_region, tex_remaining);
+TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
+ // Input is a 100x100 bitmap with a 40x50 aperture at x=20, y=30.
+ // The bounds of the layer are set to 400x400.
+ gfx::Size bitmap_size(100, 100);
+ gfx::Size layer_size(400, 500);
+ gfx::Rect aperture_rect(20, 30, 40, 50);
+ gfx::Rect border(40, 40, 80, 80);
+ bool fill_center = false;
+ size_t expected_quad_size = 8;
+ NinePatchLayerLayoutTest(bitmap_size,
+ aperture_rect,
+ layer_size,
+ border,
+ fill_center,
+ expected_quad_size);
+
+ // The bounds of the layer are set to less than the bitmap size.
+ bitmap_size = gfx::Size(100, 100);
+ layer_size = gfx::Size(40, 50);
+ aperture_rect = gfx::Rect(20, 30, 40, 50);
+ border = gfx::Rect(10, 10, 25, 15);
+ fill_center = true;
+ expected_quad_size = 9;
+ NinePatchLayerLayoutTest(bitmap_size,
+ aperture_rect,
+ layer_size,
+ border,
+ fill_center,
+ expected_quad_size);
+
+ // Layer and image sizes are equal.
+ bitmap_size = gfx::Size(100, 100);
+ layer_size = gfx::Size(100, 100);
+ aperture_rect = gfx::Rect(20, 30, 40, 50);
+ border = gfx::Rect(20, 30, 40, 50);
+ fill_center = true;
+ expected_quad_size = 9;
+ NinePatchLayerLayoutTest(bitmap_size,
+ aperture_rect,
+ layer_size,
+ border,
+ fill_center,
+ expected_quad_size);
}
} // namespace
diff --git a/chromium/cc/layers/nine_patch_layer_unittest.cc b/chromium/cc/layers/nine_patch_layer_unittest.cc
index 5268d02472f..101146c0077 100644
--- a/chromium/cc/layers/nine_patch_layer_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_unittest.cc
@@ -8,9 +8,11 @@
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/resource_update_queue.h"
+#include "cc/resources/scoped_ui_resource.h"
#include "cc/scheduler/texture_uploader.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/occlusion_tracker.h"
@@ -54,7 +56,7 @@ class NinePatchLayerTest : public testing::Test {
FakeLayerTreeHostClient fake_client_;
};
-TEST_F(NinePatchLayerTest, TriggerFullUploadOnceWhenChangingBitmap) {
+TEST_F(NinePatchLayerTest, SetBitmap) {
scoped_refptr<NinePatchLayer> test_layer = NinePatchLayer::Create();
ASSERT_TRUE(test_layer.get());
test_layer->SetIsDrawable(true);
@@ -66,80 +68,60 @@ TEST_F(NinePatchLayerTest, TriggerFullUploadOnceWhenChangingBitmap) {
layer_tree_host_->InitializeOutputSurfaceIfNeeded();
- PriorityCalculator calculator;
ResourceUpdateQueue queue;
OcclusionTracker occlusion_tracker(gfx::Rect(), false);
-
- // No bitmap set should not trigger any uploads.
test_layer->SavePaintProperties();
- test_layer->SetTexturePriorities(calculator);
test_layer->Update(&queue, &occlusion_tracker);
- EXPECT_EQ(0u, queue.FullUploadSize());
- EXPECT_EQ(0u, queue.PartialUploadSize());
- // Setting a bitmap set should trigger a single full upload.
+ EXPECT_FALSE(test_layer->DrawsContent());
+
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
bitmap.allocPixels();
- test_layer->SetBitmap(bitmap, gfx::Rect(5, 5, 1, 1));
- test_layer->SavePaintProperties();
- test_layer->SetTexturePriorities(calculator);
+ bitmap.setImmutable();
+
+ gfx::Rect aperture(5, 5, 1, 1);
+ bool fill_center = false;
+ test_layer->SetBitmap(bitmap, aperture);
+ test_layer->SetFillCenter(fill_center);
test_layer->Update(&queue, &occlusion_tracker);
- EXPECT_EQ(1u, queue.FullUploadSize());
- EXPECT_EQ(0u, queue.PartialUploadSize());
- ResourceUpdate params = queue.TakeFirstFullUpload();
- EXPECT_TRUE(params.texture != NULL);
-
- // Upload the texture.
- layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes(
- 1024 * 1024);
- layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
-
- scoped_ptr<OutputSurface> output_surface;
- scoped_ptr<ResourceProvider> resource_provider;
- {
- DebugScopedSetImplThread impl_thread(Proxy());
- DebugScopedSetMainThreadBlocked main_thread_blocked(Proxy());
- output_surface = CreateFakeOutputSurface();
- resource_provider = ResourceProvider::Create(output_surface.get(), 0);
- params.texture->AcquireBackingTexture(resource_provider.get());
- ASSERT_TRUE(params.texture->have_backing_texture());
- }
- // Nothing changed, so no repeated upload.
+ EXPECT_TRUE(test_layer->DrawsContent());
+}
+
+TEST_F(NinePatchLayerTest, SetUIResourceId) {
+ scoped_refptr<NinePatchLayer> test_layer = NinePatchLayer::Create();
+ ASSERT_TRUE(test_layer.get());
+ test_layer->SetIsDrawable(true);
+ test_layer->SetBounds(gfx::Size(100, 100));
+
+ layer_tree_host_->SetRootLayer(test_layer);
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+ EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
+
+ layer_tree_host_->InitializeOutputSurfaceIfNeeded();
+
+ ResourceUpdateQueue queue;
+ OcclusionTracker occlusion_tracker(gfx::Rect(), false);
test_layer->SavePaintProperties();
- test_layer->SetTexturePriorities(calculator);
test_layer->Update(&queue, &occlusion_tracker);
- EXPECT_EQ(0u, queue.FullUploadSize());
- EXPECT_EQ(0u, queue.PartialUploadSize());
- {
- DebugScopedSetImplThread impl_thread(Proxy());
- DebugScopedSetMainThreadBlocked main_thread_blocked(Proxy());
- layer_tree_host_->contents_texture_manager()->ClearAllMemory(
- resource_provider.get());
- }
- // Reupload after eviction
- test_layer->SavePaintProperties();
- test_layer->SetTexturePriorities(calculator);
+ EXPECT_FALSE(test_layer->DrawsContent());
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ bitmap.allocPixels();
+ bitmap.setImmutable();
+
+ scoped_ptr<ScopedUIResource> resource = ScopedUIResource::Create(
+ layer_tree_host_.get(), UIResourceBitmap(bitmap));
+ gfx::Rect aperture(5, 5, 1, 1);
+ bool fill_center = true;
+ test_layer->SetUIResourceId(resource->id(), aperture);
+ test_layer->SetFillCenter(fill_center);
test_layer->Update(&queue, &occlusion_tracker);
- EXPECT_EQ(1u, queue.FullUploadSize());
- EXPECT_EQ(0u, queue.PartialUploadSize());
- // PrioritizedResourceManager clearing
- layer_tree_host_->contents_texture_manager()->UnregisterTexture(
- params.texture);
- EXPECT_EQ(NULL, params.texture->resource_manager());
- test_layer->SavePaintProperties();
- test_layer->SetTexturePriorities(calculator);
- ResourceUpdateQueue queue2;
- test_layer->Update(&queue2, &occlusion_tracker);
- EXPECT_EQ(1u, queue2.FullUploadSize());
- EXPECT_EQ(0u, queue2.PartialUploadSize());
- params = queue2.TakeFirstFullUpload();
- EXPECT_TRUE(params.texture != NULL);
- EXPECT_EQ(params.texture->resource_manager(),
- layer_tree_host_->contents_texture_manager());
+ EXPECT_TRUE(test_layer->DrawsContent());
}
} // namespace
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
new file mode 100644
index 00000000000..4272fe688cc
--- /dev/null
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -0,0 +1,244 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/painted_scrollbar_layer.h"
+
+#include "base/auto_reset.h"
+#include "base/basictypes.h"
+#include "base/debug/trace_event.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/resources/ui_resource_bitmap.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "skia/ext/platform_canvas.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSize.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+scoped_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) {
+ return PaintedScrollbarLayerImpl::Create(
+ tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>();
+}
+
+scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create(
+ scoped_ptr<Scrollbar> scrollbar,
+ int scroll_layer_id) {
+ return make_scoped_refptr(
+ new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer_id));
+}
+
+PaintedScrollbarLayer::PaintedScrollbarLayer(
+ scoped_ptr<Scrollbar> scrollbar,
+ int scroll_layer_id)
+ : scrollbar_(scrollbar.Pass()),
+ scroll_layer_id_(scroll_layer_id),
+ thumb_thickness_(scrollbar_->ThumbThickness()),
+ thumb_length_(scrollbar_->ThumbLength()) {
+ if (!scrollbar_->IsOverlay())
+ SetShouldScrollOnMainThread(true);
+}
+
+PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
+
+int PaintedScrollbarLayer::ScrollLayerId() const {
+ return scroll_layer_id_;
+}
+
+void PaintedScrollbarLayer::SetScrollLayerId(int id) {
+ if (id == scroll_layer_id_)
+ return;
+
+ scroll_layer_id_ = id;
+ SetNeedsFullTreeSync();
+}
+
+bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const {
+ return scrollbar_->IsOverlay();
+}
+
+ScrollbarOrientation PaintedScrollbarLayer::orientation() const {
+ return scrollbar_->Orientation();
+}
+
+int PaintedScrollbarLayer::MaxTextureSize() {
+ DCHECK(layer_tree_host());
+ return layer_tree_host()->GetRendererCapabilities().max_texture_size;
+}
+
+float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
+ // If the scaled content_bounds() is bigger than the max texture size of the
+ // device, we need to clamp it by rescaling, since content_bounds() is used
+ // below to set the texture size.
+ gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
+ if (scaled_bounds.width() > MaxTextureSize() ||
+ scaled_bounds.height() > MaxTextureSize()) {
+ if (scaled_bounds.width() > scaled_bounds.height())
+ return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
+ else
+ return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
+ }
+ return scale;
+}
+
+void PaintedScrollbarLayer::CalculateContentsScale(
+ float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ bool animating_transform_to_screen,
+ float* contents_scale_x,
+ float* contents_scale_y,
+ gfx::Size* content_bounds) {
+ ContentsScalingLayer::CalculateContentsScale(
+ ClampScaleToMaxTextureSize(ideal_contents_scale),
+ device_scale_factor,
+ page_scale_factor,
+ animating_transform_to_screen,
+ contents_scale_x,
+ contents_scale_y,
+ content_bounds);
+}
+
+void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
+ ContentsScalingLayer::PushPropertiesTo(layer);
+
+ PaintedScrollbarLayerImpl* scrollbar_layer =
+ static_cast<PaintedScrollbarLayerImpl*>(layer);
+
+ scrollbar_layer->SetThumbThickness(thumb_thickness_);
+ scrollbar_layer->SetThumbLength(thumb_length_);
+ if (orientation() == HORIZONTAL) {
+ scrollbar_layer->SetTrackStart(
+ track_rect_.x() - location_.x());
+ scrollbar_layer->SetTrackLength(track_rect_.width());
+ } else {
+ scrollbar_layer->SetTrackStart(
+ track_rect_.y() - location_.y());
+ scrollbar_layer->SetTrackLength(track_rect_.height());
+ }
+
+ if (track_resource_.get())
+ scrollbar_layer->set_track_ui_resource_id(track_resource_->id());
+ if (thumb_resource_.get())
+ scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id());
+
+ scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay());
+
+ // PaintedScrollbarLayer must push properties every frame. crbug.com/259095
+ needs_push_properties_ = true;
+}
+
+ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() {
+ return this;
+}
+
+void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
+ // When the LTH is set to null or has changed, then this layer should remove
+ // all of its associated resources.
+ if (!host || host != layer_tree_host()) {
+ track_resource_.reset();
+ thumb_resource_.reset();
+ }
+
+ ContentsScalingLayer::SetLayerTreeHost(host);
+}
+
+gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
+ gfx::Rect layer_rect) const {
+ // Don't intersect with the bounds as in LayerRectToContentRect() because
+ // layer_rect here might be in coordinates of the containing layer.
+ gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
+ layer_rect, contents_scale_y(), contents_scale_y());
+ // We should never return a rect bigger than the content_bounds().
+ gfx::Size clamped_size = expanded_rect.size();
+ clamped_size.SetToMin(content_bounds());
+ expanded_rect.set_size(clamped_size);
+ return expanded_rect;
+}
+
+gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const {
+ gfx::Size thumb_size;
+ if (orientation() == HORIZONTAL) {
+ thumb_size =
+ gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness());
+ } else {
+ thumb_size =
+ gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength());
+ }
+ return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size));
+}
+
+void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
+ track_rect_ = scrollbar_->TrackRect();
+ location_ = scrollbar_->Location();
+ if (scrollbar_->HasThumb()) {
+ thumb_thickness_ = scrollbar_->ThumbThickness();
+ thumb_length_ = scrollbar_->ThumbLength();
+ }
+}
+
+bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
+ const OcclusionTracker* occlusion) {
+ UpdateThumbAndTrackGeometry();
+
+ gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect(
+ gfx::Rect(location_, bounds()));
+
+ if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty())
+ return false;
+
+ {
+ base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
+ true);
+ ContentsScalingLayer::Update(queue, occlusion);
+ }
+
+ track_resource_ = ScopedUIResource::Create(
+ layer_tree_host(), RasterizeScrollbarPart(scaled_track_rect, TRACK));
+ gfx::Rect thumb_rect = OriginThumbRect();
+
+ if (scrollbar_->HasThumb() && !thumb_rect.IsEmpty()) {
+ thumb_resource_ = ScopedUIResource::Create(
+ layer_tree_host(), RasterizeScrollbarPart(thumb_rect, THUMB));
+ }
+
+ return true;
+}
+
+UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart(
+ gfx::Rect rect,
+ ScrollbarPart part) {
+ DCHECK(!rect.size().IsEmpty());
+
+ SkBitmap skbitmap;
+ skbitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
+ skbitmap.allocPixels();
+
+ SkCanvas skcanvas(skbitmap);
+ skcanvas.translate(SkFloatToScalar(-rect.x()), SkFloatToScalar(-rect.y()));
+ skcanvas.scale(SkFloatToScalar(contents_scale_x()),
+ SkFloatToScalar(contents_scale_y()));
+
+ gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
+ rect, 1.f / contents_scale_x(), 1.f / contents_scale_y());
+ SkRect layer_skrect = RectToSkRect(layer_rect);
+ SkPaint paint;
+ paint.setAntiAlias(false);
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ skcanvas.drawRect(layer_skrect, paint);
+ skcanvas.clipRect(layer_skrect);
+
+ scrollbar_->PaintPart(&skcanvas, part, layer_rect);
+ // Make sure that the pixels are no longer mutable to unavoid unnecessary
+ // allocation and copying.
+ skbitmap.setImmutable();
+
+ return UIResourceBitmap(skbitmap);
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer.h b/chromium/cc/layers/painted_scrollbar_layer.h
index 6d0e58f7a4e..e84377d1e5a 100644
--- a/chromium/cc/layers/scrollbar_layer.h
+++ b/chromium/cc/layers/painted_scrollbar_layer.h
@@ -1,40 +1,41 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_LAYERS_SCROLLBAR_LAYER_H_
-#define CC_LAYERS_SCROLLBAR_LAYER_H_
+#ifndef CC_LAYERS_PAINTED_SCROLLBAR_LAYER_H_
+#define CC_LAYERS_PAINTED_SCROLLBAR_LAYER_H_
#include "cc/base/cc_export.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/contents_scaling_layer.h"
+#include "cc/layers/scrollbar_layer_interface.h"
#include "cc/layers/scrollbar_theme_painter.h"
#include "cc/resources/layer_updater.h"
+#include "cc/resources/scoped_ui_resource.h"
namespace cc {
-class CachingBitmapContentLayerUpdater;
-class ResourceUpdateQueue;
class ScrollbarThemeComposite;
-class CC_EXPORT ScrollbarLayer : public ContentsScalingLayer {
+class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
+ public ContentsScalingLayer {
public:
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
- static scoped_refptr<ScrollbarLayer> Create(
+ static scoped_refptr<PaintedScrollbarLayer> Create(
scoped_ptr<Scrollbar> scrollbar,
int scroll_layer_id);
- int scroll_layer_id() const { return scroll_layer_id_; }
- void SetScrollLayerId(int id);
-
virtual bool OpacityCanAnimateOnImplThread() const OVERRIDE;
+ virtual ScrollbarLayerInterface* ToScrollbarLayer() OVERRIDE;
+
+ // ScrollbarLayerInterface
+ virtual int ScrollLayerId() const OVERRIDE;
+ virtual void SetScrollLayerId(int id) OVERRIDE;
- ScrollbarOrientation Orientation() const;
+ virtual ScrollbarOrientation orientation() const OVERRIDE;
// Layer interface
- virtual void SetTexturePriorities(const PriorityCalculator& priority_calc)
- OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
const OcclusionTracker* occlusion) OVERRIDE;
virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
@@ -47,49 +48,45 @@ class CC_EXPORT ScrollbarLayer : public ContentsScalingLayer {
float* contents_scale_y,
gfx::Size* content_bounds) OVERRIDE;
- virtual ScrollbarLayer* ToScrollbarLayer() OVERRIDE;
-
protected:
- ScrollbarLayer(scoped_ptr<Scrollbar> scrollbar,
- int scroll_layer_id);
- virtual ~ScrollbarLayer();
+ PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, int scroll_layer_id);
+ virtual ~PaintedScrollbarLayer();
+
+ // For unit tests
+ UIResourceId track_resource_id() {
+ return track_resource_.get() ? track_resource_->id() : 0;
+ }
+ UIResourceId thumb_resource_id() {
+ return thumb_resource_.get() ? thumb_resource_->id() : 0;
+ }
+ void UpdateThumbAndTrackGeometry();
private:
- bool UpdatePart(CachingBitmapContentLayerUpdater* painter,
- LayerUpdater::Resource* resource,
- gfx::Rect rect,
- ResourceUpdateQueue* queue);
- void CreateUpdaterIfNeeded();
gfx::Rect ScrollbarLayerRectToContentRect(gfx::Rect layer_rect) const;
gfx::Rect OriginThumbRect() const;
- bool is_dirty() const { return !dirty_rect_.IsEmpty(); }
-
int MaxTextureSize();
float ClampScaleToMaxTextureSize(float scale);
+ UIResourceBitmap RasterizeScrollbarPart(gfx::Rect rect,
+ ScrollbarPart part);
+
scoped_ptr<Scrollbar> scrollbar_;
+ int scroll_layer_id_;
+ // Snapshot of properties taken in UpdateThumbAndTrackGeometry and used in
+ // PushPropertiesTo.
int thumb_thickness_;
int thumb_length_;
- gfx::Rect track_rect_;
gfx::Point location_;
- int scroll_layer_id_;
-
- unsigned texture_format_;
-
- gfx::RectF dirty_rect_;
-
- scoped_refptr<CachingBitmapContentLayerUpdater> track_updater_;
- scoped_refptr<CachingBitmapContentLayerUpdater> thumb_updater_;
+ gfx::Rect track_rect_;
- // All the parts of the scrollbar except the thumb
- scoped_ptr<LayerUpdater::Resource> track_;
- scoped_ptr<LayerUpdater::Resource> thumb_;
+ scoped_ptr<ScopedUIResource> track_resource_;
+ scoped_ptr<ScopedUIResource> thumb_resource_;
- DISALLOW_COPY_AND_ASSIGN(ScrollbarLayer);
+ DISALLOW_COPY_AND_ASSIGN(PaintedScrollbarLayer);
};
} // namespace cc
-#endif // CC_LAYERS_SCROLLBAR_LAYER_H_
+#endif // CC_LAYERS_PAINTED_SCROLLBAR_LAYER_H_
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
new file mode 100644
index 00000000000..e38a1a640be
--- /dev/null
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -0,0 +1,181 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/painted_scrollbar_layer_impl.h"
+
+#include <algorithm>
+
+#include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/quad_sink.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/layer_tree_settings.h"
+#include "ui/gfx/rect_conversions.h"
+
+namespace cc {
+
+scoped_ptr<PaintedScrollbarLayerImpl> PaintedScrollbarLayerImpl::Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation) {
+ return make_scoped_ptr(
+ new PaintedScrollbarLayerImpl(tree_impl, id, orientation));
+}
+
+PaintedScrollbarLayerImpl::PaintedScrollbarLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation)
+ : ScrollbarLayerImplBase(tree_impl, id, orientation, false),
+ track_ui_resource_id_(0),
+ thumb_ui_resource_id_(0),
+ thumb_thickness_(0),
+ thumb_length_(0),
+ track_start_(0),
+ track_length_(0),
+ vertical_adjust_(0.f),
+ scroll_layer_id_(Layer::INVALID_ID) {}
+
+PaintedScrollbarLayerImpl::~PaintedScrollbarLayerImpl() {}
+
+scoped_ptr<LayerImpl> PaintedScrollbarLayerImpl::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) {
+ return PaintedScrollbarLayerImpl::Create(tree_impl, id(), orientation())
+ .PassAs<LayerImpl>();
+}
+
+void PaintedScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
+ ScrollbarLayerImplBase::PushPropertiesTo(layer);
+
+ PaintedScrollbarLayerImpl* scrollbar_layer =
+ static_cast<PaintedScrollbarLayerImpl*>(layer);
+
+ scrollbar_layer->SetThumbThickness(thumb_thickness_);
+ scrollbar_layer->SetThumbLength(thumb_length_);
+ scrollbar_layer->SetTrackStart(track_start_);
+ scrollbar_layer->SetTrackLength(track_length_);
+
+ scrollbar_layer->set_track_ui_resource_id(track_ui_resource_id_);
+ scrollbar_layer->set_thumb_ui_resource_id(thumb_ui_resource_id_);
+}
+
+bool PaintedScrollbarLayerImpl::WillDraw(DrawMode draw_mode,
+ ResourceProvider* resource_provider) {
+ DCHECK(draw_mode != DRAW_MODE_RESOURCELESS_SOFTWARE);
+ return LayerImpl::WillDraw(draw_mode, resource_provider);
+}
+
+void PaintedScrollbarLayerImpl::AppendQuads(
+ QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) {
+ bool premultipled_alpha = true;
+ bool flipped = false;
+ gfx::PointF uv_top_left(0.f, 0.f);
+ gfx::PointF uv_bottom_right(1.f, 1.f);
+ gfx::Rect bounds_rect(bounds());
+ gfx::Rect content_bounds_rect(content_bounds());
+
+ SharedQuadState* shared_quad_state =
+ quad_sink->UseSharedQuadState(CreateSharedQuadState());
+ AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+
+ gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
+
+ ResourceProvider::ResourceId thumb_resource_id =
+ layer_tree_impl()->ResourceIdForUIResource(thumb_ui_resource_id_);
+ ResourceProvider::ResourceId track_resource_id =
+ layer_tree_impl()->ResourceIdForUIResource(track_ui_resource_id_);
+
+ if (thumb_resource_id && !thumb_quad_rect.IsEmpty()) {
+ gfx::Rect opaque_rect;
+ const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ thumb_quad_rect,
+ opaque_rect,
+ thumb_resource_id,
+ premultipled_alpha,
+ uv_top_left,
+ uv_bottom_right,
+ SK_ColorTRANSPARENT,
+ opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ }
+
+ gfx::Rect track_quad_rect = content_bounds_rect;
+ if (track_resource_id && !track_quad_rect.IsEmpty()) {
+ gfx::Rect opaque_rect(contents_opaque() ? track_quad_rect : gfx::Rect());
+ const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ track_quad_rect,
+ opaque_rect,
+ track_resource_id,
+ premultipled_alpha,
+ uv_top_left,
+ uv_bottom_right,
+ SK_ColorTRANSPARENT,
+ opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ }
+}
+
+void PaintedScrollbarLayerImpl::DidLoseOutputSurface() {
+ track_ui_resource_id_ = 0;
+ thumb_ui_resource_id_ = 0;
+}
+
+void PaintedScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) {
+ if (thumb_thickness_ == thumb_thickness)
+ return;
+ thumb_thickness_ = thumb_thickness;
+ NoteLayerPropertyChanged();
+}
+
+int PaintedScrollbarLayerImpl::ThumbThickness() const {
+ return thumb_thickness_;
+}
+
+void PaintedScrollbarLayerImpl::SetThumbLength(int thumb_length) {
+ if (thumb_length_ == thumb_length)
+ return;
+ thumb_length_ = thumb_length;
+ NoteLayerPropertyChanged();
+}
+
+int PaintedScrollbarLayerImpl::ThumbLength() const {
+ return thumb_length_;
+}
+
+void PaintedScrollbarLayerImpl::SetTrackStart(int track_start) {
+ if (track_start_ == track_start)
+ return;
+ track_start_ = track_start;
+ NoteLayerPropertyChanged();
+}
+
+int PaintedScrollbarLayerImpl::TrackStart() const {
+ return track_start_;
+}
+
+void PaintedScrollbarLayerImpl::SetTrackLength(int track_length) {
+ if (track_length_ == track_length)
+ return;
+ track_length_ = track_length;
+ NoteLayerPropertyChanged();
+}
+
+float PaintedScrollbarLayerImpl::TrackLength() const {
+ return track_length_ + (orientation() == VERTICAL ? vertical_adjust() : 0);
+}
+
+const char* PaintedScrollbarLayerImpl::LayerTypeAsString() const {
+ return "cc::PaintedScrollbarLayerImpl";
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h
new file mode 100644
index 00000000000..c9d1f3dc0fc
--- /dev/null
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h
@@ -0,0 +1,82 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_PAINTED_SCROLLBAR_LAYER_IMPL_H_
+#define CC_LAYERS_PAINTED_SCROLLBAR_LAYER_IMPL_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/input/scrollbar.h"
+#include "cc/layers/scrollbar_layer_impl_base.h"
+#include "cc/resources/ui_resource_client.h"
+
+namespace cc {
+
+class LayerTreeImpl;
+class ScrollView;
+
+class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
+ public:
+ static scoped_ptr<PaintedScrollbarLayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation);
+ virtual ~PaintedScrollbarLayerImpl();
+
+ // LayerImpl implementation.
+ virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+ OVERRIDE;
+ virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+
+ virtual bool WillDraw(DrawMode draw_mode,
+ ResourceProvider* resource_provider) OVERRIDE;
+ virtual void AppendQuads(QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) OVERRIDE;
+
+ virtual void DidLoseOutputSurface() OVERRIDE;
+
+ void SetThumbThickness(int thumb_thickness);
+ void SetThumbLength(int thumb_length);
+ void SetTrackStart(int track_start);
+ void SetTrackLength(int track_length);
+
+ void set_track_ui_resource_id(UIResourceId uid) {
+ track_ui_resource_id_ = uid;
+ }
+ void set_thumb_ui_resource_id(UIResourceId uid) {
+ thumb_ui_resource_id_ = uid;
+ }
+
+ protected:
+ PaintedScrollbarLayerImpl(LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation);
+
+ // ScrollbarLayerImplBase implementation.
+ virtual int ThumbThickness() const OVERRIDE;
+ virtual int ThumbLength() const OVERRIDE;
+ virtual float TrackLength() const OVERRIDE;
+ virtual int TrackStart() const OVERRIDE;
+
+ private:
+ virtual const char* LayerTypeAsString() const OVERRIDE;
+
+ UIResourceId track_ui_resource_id_;
+ UIResourceId thumb_ui_resource_id_;
+
+ int thumb_thickness_;
+ int thumb_length_;
+ int track_start_;
+ int track_length_;
+
+ // Difference between the clip layer's height and the visible viewport
+ // height (which may differ in the presence of top-controls hiding).
+ float vertical_adjust_;
+
+ int scroll_layer_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaintedScrollbarLayerImpl);
+};
+
+} // namespace cc
+#endif // CC_LAYERS_PAINTED_SCROLLBAR_LAYER_IMPL_H_
diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc
index 889e2fbd3f6..4226f1ba713 100644
--- a/chromium/cc/layers/picture_layer.cc
+++ b/chromium/cc/layers/picture_layer.cc
@@ -6,6 +6,7 @@
#include "cc/debug/benchmark_instrumentation.h"
#include "cc/debug/devtools_instrumentation.h"
+#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer_impl.h"
#include "cc/trees/layer_tree_impl.h"
#include "ui/gfx/rect_conversions.h"
@@ -36,25 +37,26 @@ scoped_ptr<LayerImpl> PictureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
Layer::PushPropertiesTo(base_layer);
-
PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
- // This should be first so others can use it.
- layer_impl->UpdateTwinLayer();
+
+ if (layer_impl->bounds().IsEmpty()) {
+ // Update may not get called for an empty layer, so resize here instead.
+ // Using layer_impl because either bounds() or paint_properties().bounds
+ // may disagree and either one could have been pushed to layer_impl.
+ pile_->Resize(layer_impl->bounds());
+ pile_->UpdateRecordedRegion();
+ }
+
+ if (DrawsContent()) {
+ DCHECK(paint_properties().bounds == pile_->size());
+ }
layer_impl->SetIsMask(is_mask_);
- layer_impl->CreateTilingSetIfNeeded();
// Unlike other properties, invalidation must always be set on layer_impl.
// See PictureLayerImpl::PushPropertiesTo for more details.
layer_impl->invalidation_.Clear();
layer_impl->invalidation_.Swap(&pile_invalidation_);
layer_impl->pile_ = PicturePileImpl::CreateFromOther(pile_.get());
- layer_impl->SyncFromActiveLayer();
-
- // PictureLayer must push properties every frame.
- // TODO(danakj): If we can avoid requiring to do CreateTilingSetIfNeeded() and
- // SyncFromActiveLayer() on every commit then this could go away, maybe
- // conditionally. crbug.com/259402
- needs_push_properties_ = true;
}
void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
@@ -114,11 +116,14 @@ bool PictureLayer::Update(ResourceUpdateQueue* queue,
pile_invalidation_,
visible_layer_rect,
rendering_stats_instrumentation());
- if (!updated) {
+ if (updated) {
+ SetNeedsPushProperties();
+ } else {
// If this invalidation did not affect the pile, then it can be cleared as
// an optimization.
pile_invalidation_.Clear();
}
+
return updated;
}
@@ -130,4 +135,22 @@ bool PictureLayer::SupportsLCDText() const {
return true;
}
+skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
+ // We could either flatten the PicturePile into a single SkPicture,
+ // or paint a fresh one depending on what we intend to do with the
+ // picture. For now we just paint a fresh one to get consistent results.
+ if (!DrawsContent())
+ return skia::RefPtr<SkPicture>();
+
+ int width = bounds().width();
+ int height = bounds().height();
+ gfx::RectF opaque;
+
+ skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
+ SkCanvas* canvas = picture->beginRecording(width, height);
+ client_->PaintContents(canvas, gfx::Rect(width, height), &opaque);
+ picture->endRecording();
+ return picture;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer.h b/chromium/cc/layers/picture_layer.h
index 7a9a427d427..d7943307ddc 100644
--- a/chromium/cc/layers/picture_layer.h
+++ b/chromium/cc/layers/picture_layer.h
@@ -34,6 +34,7 @@ class CC_EXPORT PictureLayer : public Layer {
const OcclusionTracker* occlusion) OVERRIDE;
virtual void SetIsMask(bool is_mask) OVERRIDE;
virtual bool SupportsLCDText() const OVERRIDE;
+ virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE;
protected:
explicit PictureLayer(ContentLayerClient* client);
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index 2f1878bc3a6..95a4a076520 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -45,11 +45,11 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
raster_contents_scale_(0.f),
low_res_raster_contents_scale_(0.f),
raster_source_scale_was_animating_(false),
- is_using_lcd_text_(tree_impl->settings().can_use_lcd_text) {
-}
+ is_using_lcd_text_(tree_impl->settings().can_use_lcd_text),
+ needs_post_commit_initialization_(true),
+ should_update_tile_priorities_(false) {}
-PictureLayerImpl::~PictureLayerImpl() {
-}
+PictureLayerImpl::~PictureLayerImpl() {}
const char* PictureLayerImpl::LayerTypeAsString() const {
return "cc::PictureLayerImpl";
@@ -60,13 +60,11 @@ scoped_ptr<LayerImpl> PictureLayerImpl::CreateLayerImpl(
return PictureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}
-void PictureLayerImpl::CreateTilingSetIfNeeded() {
- DCHECK(layer_tree_impl()->IsPendingTree());
- if (!tilings_)
- tilings_.reset(new PictureLayerTilingSet(this, bounds()));
-}
-
void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
+ // It's possible this layer was never drawn or updated (e.g. because it was
+ // a descendant of an opacity 0 layer).
+ DoPostCommitInitializationIfNeeded();
+
LayerImpl::PushPropertiesTo(base_layer);
PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
@@ -78,8 +76,9 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
layer_impl->SetIsMask(is_mask_);
layer_impl->pile_ = pile_;
- pile_ = NULL;
+ // Tilings would be expensive to push, so we swap. This optimization requires
+ // an extra invalidation in SyncFromActiveLayer.
layer_impl->tilings_.swap(tilings_);
layer_impl->tilings_->SetClient(layer_impl);
if (tilings_)
@@ -92,19 +91,19 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
layer_impl->low_res_raster_contents_scale_ = low_res_raster_contents_scale_;
layer_impl->UpdateLCDTextStatus(is_using_lcd_text_);
+ layer_impl->needs_post_commit_initialization_ = false;
- // As an optimization, don't make a copy of this potentially complex region,
- // and swap it directly from the pending to the active layer. In general, any
- // property pushed to a LayerImpl continues to live on that LayerImpl.
- // However, invalidation is the difference between two main thread frames, so
- // it no longer makes sense once the pending tree gets recycled. It will
- // always get pushed during PictureLayer::PushPropertiesTo.
+ // The invalidation on this soon-to-be-recycled layer must be cleared to
+ // mirror clearing the invalidation in PictureLayer's version of this function
+ // in case push properties is skipped.
layer_impl->invalidation_.Swap(&invalidation_);
invalidation_.Clear();
+ needs_post_commit_initialization_ = true;
}
void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
+ DCHECK(!needs_post_commit_initialization_);
gfx::Rect rect(visible_content_rect());
gfx::Rect content_rect(content_bounds());
@@ -137,7 +136,7 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
opaque_rect,
texture_rect,
texture_size,
- false,
+ RGBA_8888,
quad_content_rect,
contents_scale,
draw_direct_to_backbuffer,
@@ -149,11 +148,6 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
- bool clipped = false;
- gfx::QuadF target_quad = MathUtil::MapQuad(
- draw_transform(),
- gfx::QuadF(rect),
- &clipped);
if (ShowDebugBorders()) {
for (PictureLayerTilingSet::CoverageIterator iter(
tilings_.get(), contents_scale_x(), rect, ideal_contents_scale_);
@@ -228,6 +222,7 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
const ManagedTileState::TileVersion& tile_version =
iter->GetTileVersionForDrawing();
+ scoped_ptr<DrawQuad> draw_quad;
switch (tile_version.mode()) {
case ManagedTileState::TileVersion::RESOURCE_MODE: {
gfx::RectF texture_rect = iter.texture_rect();
@@ -245,7 +240,7 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
texture_rect,
iter.texture_size(),
tile_version.contents_swizzled());
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ draw_quad = quad.PassAs<DrawQuad>();
break;
}
case ManagedTileState::TileVersion::PICTURE_PILE_MODE: {
@@ -253,22 +248,22 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
gfx::Rect opaque_rect = iter->opaque_rect();
opaque_rect.Intersect(content_rect);
+ ResourceProvider* resource_provider =
+ layer_tree_impl()->resource_provider();
+ ResourceFormat format =
+ resource_provider->memory_efficient_texture_format();
scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create();
quad->SetNew(shared_quad_state,
geometry_rect,
opaque_rect,
texture_rect,
iter.texture_size(),
- // TODO(reveman): This assumes the renderer will use
- // GL_RGBA as format of temporary resource. The need
- // to swizzle should instead be determined by the
- // renderer.
- !PlatformColor::SameComponentOrder(GL_RGBA),
+ format,
iter->content_rect(),
iter->contents_scale(),
draw_direct_to_backbuffer,
pile_);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ draw_quad = quad.PassAs<DrawQuad>();
break;
}
case ManagedTileState::TileVersion::SOLID_COLOR_MODE: {
@@ -277,14 +272,15 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
geometry_rect,
tile_version.get_solid_color(),
false);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ draw_quad = quad.PassAs<DrawQuad>();
break;
}
- default:
- NOTREACHED();
}
- if (!seen_tilings.size() || seen_tilings.back() != iter.CurrentTiling())
+ DCHECK(draw_quad);
+ quad_sink->Append(draw_quad.Pass(), append_quads_data);
+
+ if (seen_tilings.empty() || seen_tilings.back() != iter.CurrentTiling())
seen_tilings.push_back(iter.CurrentTiling());
}
@@ -296,6 +292,15 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
}
void PictureLayerImpl::UpdateTilePriorities() {
+ DCHECK(!needs_post_commit_initialization_);
+ CHECK(should_update_tile_priorities_);
+
+ if (!layer_tree_impl()->device_viewport_valid_for_tile_management()) {
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i)
+ DCHECK(tilings_->tiling_at(i)->has_ever_been_updated());
+ return;
+ }
+
if (!tilings_->num_tilings())
return;
@@ -314,19 +319,17 @@ void PictureLayerImpl::UpdateTilePriorities() {
if (!tiling_needs_update)
return;
- // At this point, tile priorities are going to be modified.
- layer_tree_impl()->WillModifyTilePriorities();
-
UpdateLCDTextStatus(can_use_lcd_text());
gfx::Transform current_screen_space_transform = screen_space_transform();
+ gfx::Size viewport_size = layer_tree_impl()->DrawViewportSize();
gfx::Rect viewport_in_content_space;
gfx::Transform screen_to_layer(gfx::Transform::kSkipInitialization);
if (screen_space_transform().GetInverse(&screen_to_layer)) {
- gfx::Rect device_viewport(layer_tree_impl()->device_viewport_size());
- viewport_in_content_space = gfx::ToEnclosingRect(
- MathUtil::ProjectClippedRect(screen_to_layer, device_viewport));
+ viewport_in_content_space =
+ gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
+ screen_to_layer, gfx::Rect(viewport_size)));
}
WhichTree tree =
@@ -335,7 +338,7 @@ void PictureLayerImpl::UpdateTilePriorities() {
layer_tree_impl()->settings().max_tiles_for_interest_area;
tilings_->UpdateTilePriorities(
tree,
- layer_tree_impl()->device_viewport_size(),
+ viewport_size,
viewport_in_content_space,
visible_content_rect(),
last_bounds_,
@@ -353,12 +356,15 @@ void PictureLayerImpl::UpdateTilePriorities() {
last_screen_space_transform_ = current_screen_space_transform;
last_bounds_ = bounds();
last_content_scale_ = contents_scale_x();
+
+ // Tile priorities were modified.
+ layer_tree_impl()->DidModifyTilePriorities();
}
void PictureLayerImpl::DidBecomeActive() {
LayerImpl::DidBecomeActive();
tilings_->DidBecomeActive();
- layer_tree_impl()->WillModifyTilePriorities();
+ layer_tree_impl()->DidModifyTilePriorities();
}
void PictureLayerImpl::DidBeginTracing() {
@@ -380,6 +386,12 @@ void PictureLayerImpl::CalculateContentsScale(
float* contents_scale_x,
float* contents_scale_y,
gfx::Size* content_bounds) {
+ DoPostCommitInitializationIfNeeded();
+
+ // This function sets valid raster scales and manages tilings, so tile
+ // priorities can now be updated.
+ should_update_tile_priorities_ = true;
+
if (!CanHaveTilings()) {
ideal_page_scale_ = page_scale_factor;
ideal_device_scale_ = device_scale_factor;
@@ -525,14 +537,10 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
return default_tile_size;
}
-void PictureLayerImpl::SyncFromActiveLayer() {
- DCHECK(layer_tree_impl()->IsPendingTree());
-
- if (twin_layer_)
- SyncFromActiveLayer(twin_layer_);
-}
-
void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
+ DCHECK(!other->needs_post_commit_initialization_);
+ DCHECK(other->tilings_);
+
UpdateLCDTextStatus(other->is_using_lcd_text_);
if (!DrawsContent()) {
@@ -581,6 +589,8 @@ void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
} else {
tilings_->RemoveAllTilings();
}
+
+ SanityCheckTilingState();
}
void PictureLayerImpl::SyncTiling(
@@ -593,19 +603,11 @@ void PictureLayerImpl::SyncTiling(
// get updated prior to drawing or activation. If this tree does not
// need update draw properties, then its transforms are up to date and
// we can create tiles for this tiling immediately.
- if (!layer_tree_impl()->needs_update_draw_properties())
+ if (!layer_tree_impl()->needs_update_draw_properties() &&
+ should_update_tile_priorities_)
UpdateTilePriorities();
}
-void PictureLayerImpl::UpdateTwinLayer() {
- DCHECK(layer_tree_impl()->IsPendingTree());
-
- twin_layer_ = static_cast<PictureLayerImpl*>(
- layer_tree_impl()->FindActiveTreeLayerById(id()));
- if (twin_layer_)
- twin_layer_->twin_layer_ = this;
-}
-
void PictureLayerImpl::SetIsMask(bool is_mask) {
if (is_mask_ == is_mask)
return;
@@ -617,27 +619,24 @@ void PictureLayerImpl::SetIsMask(bool is_mask) {
ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
gfx::Rect content_rect(content_bounds());
float scale = contents_scale_x();
- for (PictureLayerTilingSet::CoverageIterator
- iter(tilings_.get(), scale, content_rect, ideal_contents_scale_);
- iter;
- ++iter) {
- // Mask resource not ready yet.
- if (!*iter)
- return 0;
+ PictureLayerTilingSet::CoverageIterator iter(
+ tilings_.get(), scale, content_rect, ideal_contents_scale_);
- const ManagedTileState::TileVersion& tile_version =
- iter->GetTileVersionForDrawing();
- if (!tile_version.IsReadyToDraw() ||
- tile_version.mode() != ManagedTileState::TileVersion::RESOURCE_MODE)
- return 0;
+ // Mask resource not ready yet.
+ if (!iter || !*iter)
+ return 0;
- // Masks only supported if they fit on exactly one tile.
- if (iter.geometry_rect() != content_rect)
- return 0;
+ // Masks only supported if they fit on exactly one tile.
+ if (iter.geometry_rect() != content_rect)
+ return 0;
- return tile_version.get_resource_id();
- }
- return 0;
+ const ManagedTileState::TileVersion& tile_version =
+ iter->GetTileVersionForDrawing();
+ if (!tile_version.IsReadyToDraw() ||
+ tile_version.mode() != ManagedTileState::TileVersion::RESOURCE_MODE)
+ return 0;
+
+ return tile_version.get_resource_id();
}
void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
@@ -695,7 +694,7 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
continue;
missing_region.Subtract(iter.geometry_rect());
- iter->mark_required_for_activation();
+ iter->MarkRequiredForActivation();
}
}
@@ -720,8 +719,30 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
if (!missing_region.Intersects(iter.geometry_rect()))
continue;
- iter->mark_required_for_activation();
+ iter->MarkRequiredForActivation();
+ }
+}
+
+void PictureLayerImpl::DoPostCommitInitialization() {
+ DCHECK(needs_post_commit_initialization_);
+ DCHECK(layer_tree_impl()->IsPendingTree());
+
+ if (!tilings_)
+ tilings_.reset(new PictureLayerTilingSet(this, bounds()));
+
+ DCHECK(!twin_layer_);
+ twin_layer_ = static_cast<PictureLayerImpl*>(
+ layer_tree_impl()->FindActiveTreeLayerById(id()));
+ if (twin_layer_) {
+ DCHECK(!twin_layer_->twin_layer_);
+ twin_layer_->twin_layer_ = this;
+ // If the twin has never been pushed to, do not sync from it.
+ // This can happen if this function is called during activation.
+ if (!twin_layer_->needs_post_commit_initialization_)
+ SyncFromActiveLayer(twin_layer_);
}
+
+ needs_post_commit_initialization_ = false;
}
PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) {
@@ -747,6 +768,7 @@ void PictureLayerImpl::RemoveTiling(float contents_scale) {
break;
}
}
+ SanityCheckTilingState();
}
namespace {
@@ -775,6 +797,7 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
DCHECK(ideal_device_scale_);
DCHECK(ideal_source_scale_);
DCHECK(CanHaveTilings());
+ DCHECK(!needs_post_commit_initialization_);
bool change_target_tiling =
raster_page_scale_ == 0.f ||
@@ -790,6 +813,9 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
if (!change_target_tiling)
return;
+ if (!layer_tree_impl()->device_viewport_valid_for_tile_management())
+ return;
+
raster_page_scale_ = ideal_page_scale_;
raster_device_scale_ = ideal_device_scale_;
raster_source_scale_ = ideal_source_scale_;
@@ -829,12 +855,13 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
low_res != high_res)
low_res = AddTiling(low_res_raster_contents_scale_);
- if (high_res)
- high_res->set_resolution(HIGH_RESOLUTION);
+ high_res->set_resolution(HIGH_RESOLUTION);
if (low_res && low_res != high_res)
low_res->set_resolution(LOW_RESOLUTION);
else if (!low_res && previous_low_res)
previous_low_res->set_resolution(LOW_RESOLUTION);
+
+ SanityCheckTilingState();
}
bool PictureLayerImpl::ShouldAdjustRasterScale(
@@ -947,6 +974,8 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
twin->RemoveTiling(to_remove[i]->contents_scale());
tilings_->Remove(to_remove[i]);
}
+
+ SanityCheckTilingState();
}
float PictureLayerImpl::MinimumContentsScale() const {
@@ -981,6 +1010,10 @@ void PictureLayerImpl::ResetRasterScale() {
raster_source_scale_ = 0.f;
raster_contents_scale_ = 0.f;
low_res_raster_contents_scale_ = 0.f;
+
+ // When raster scales aren't valid, don't update tile priorities until
+ // this layer has been updated via UpdateDrawProperties.
+ should_update_tile_priorities_ = false;
}
bool PictureLayerImpl::CanHaveTilings() const {
@@ -1002,6 +1035,22 @@ bool PictureLayerImpl::CanHaveTilingWithScale(float contents_scale) const {
return true;
}
+void PictureLayerImpl::SanityCheckTilingState() const {
+ if (!DCHECK_IS_ON())
+ return;
+
+ if (!CanHaveTilings()) {
+ DCHECK_EQ(0u, tilings_->num_tilings());
+ return;
+ }
+ if (tilings_->num_tilings() == 0)
+ return;
+
+ // MarkVisibleResourcesAsRequired depends on having exactly 1 high res
+ // tiling to mark its tiles as being required for activation.
+ DCHECK_EQ(1, tilings_->NumHighResTilings());
+}
+
void PictureLayerImpl::GetDebugBorderProperties(
SkColor* color,
float* width) const {
@@ -1012,6 +1061,7 @@ void PictureLayerImpl::GetDebugBorderProperties(
void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const {
LayerImpl::AsValueInto(state);
state->SetDouble("ideal_contents_scale", ideal_contents_scale_);
+ state->SetDouble("geometry_contents_scale", contents_scale_x());
state->Set("tilings", tilings_->AsValue().release());
state->Set("pictures", pile_->AsValue().release());
state->Set("invalidation", invalidation_.AsValue().release());
@@ -1019,7 +1069,7 @@ void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const {
scoped_ptr<base::ListValue> coverage_tiles(new base::ListValue);
for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
contents_scale_x(),
- gfx::Rect(bounds()),
+ gfx::Rect(content_bounds()),
ideal_contents_scale_);
iter;
++iter) {
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index 25cc5d0b7e7..fd5c0677a98 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -62,11 +62,7 @@ class CC_EXPORT PictureLayerImpl
const PictureLayerTiling* tiling) OVERRIDE;
// PushPropertiesTo active tree => pending tree.
- void SyncFromActiveLayer();
void SyncTiling(const PictureLayerTiling* tiling);
- void UpdateTwinLayer();
-
- void CreateTilingSetIfNeeded();
// Mask-related functions
void SetIsMask(bool is_mask);
@@ -92,9 +88,15 @@ class CC_EXPORT PictureLayerImpl
void UpdateLCDTextStatus(bool new_status);
void ResetRasterScale();
void MarkVisibleResourcesAsRequired() const;
+ void DoPostCommitInitializationIfNeeded() {
+ if (needs_post_commit_initialization_)
+ DoPostCommitInitialization();
+ }
+ void DoPostCommitInitialization();
bool CanHaveTilings() const;
bool CanHaveTilingWithScale(float contents_scale) const;
+ void SanityCheckTilingState() const;
virtual void GetDebugBorderProperties(
SkColor* color, float* width) const OVERRIDE;
@@ -124,6 +126,10 @@ class CC_EXPORT PictureLayerImpl
bool raster_source_scale_was_animating_;
bool is_using_lcd_text_;
+ bool needs_post_commit_initialization_;
+ // A sanity state check to make sure UpdateTilePriorities only gets called
+ // after a CalculateContentsScale/ManageTilings.
+ bool should_update_tile_priorities_;
friend class PictureLayer;
DISALLOW_COPY_AND_ASSIGN(PictureLayerImpl);
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index 047a529924a..e1cd39ada41 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "cc/debug/test_web_graphics_context_3d.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/picture_layer.h"
#include "cc/test/fake_content_layer_client.h"
@@ -19,7 +20,7 @@
#include "cc/test/mock_quad_culler.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkDevice.h"
+#include "third_party/skia/include/core/SkBitmapDevice.h"
#include "ui/gfx/rect_conversions.h"
namespace cc {
@@ -27,7 +28,7 @@ namespace {
class MockCanvas : public SkCanvas {
public:
- explicit MockCanvas(SkDevice* device) : SkCanvas(device) {}
+ explicit MockCanvas(SkBaseDevice* device) : SkCanvas(device) {}
virtual void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE {
// Capture calls before SkCanvas quickReject() kicks in.
@@ -40,14 +41,22 @@ class MockCanvas : public SkCanvas {
class PictureLayerImplTest : public testing::Test {
public:
PictureLayerImplTest()
- : host_impl_(ImplSidePaintingSettings(), &proxy_),
- id_(7) {
- host_impl_.InitializeRenderer(CreateFakeOutputSurface());
- }
+ : host_impl_(ImplSidePaintingSettings(), &proxy_), id_(7) {}
+
+ explicit PictureLayerImplTest(const LayerTreeSettings& settings)
+ : host_impl_(settings, &proxy_), id_(7) {}
virtual ~PictureLayerImplTest() {
}
+ virtual void SetUp() OVERRIDE {
+ InitializeRenderer();
+ }
+
+ virtual void InitializeRenderer() {
+ host_impl_.InitializeRenderer(CreateFakeOutputSurface());
+ }
+
void SetupDefaultTrees(gfx::Size layer_bounds) {
gfx::Size tile_size(100, 100);
@@ -69,7 +78,6 @@ class PictureLayerImplTest : public testing::Test {
host_impl_.active_tree()->LayerById(id_));
SetupPendingTree(pending_pile);
- pending_layer_->UpdateTwinLayer();
}
void AddDefaultTilingsWithInvalidation(const Region& invalidation) {
@@ -79,7 +87,6 @@ class PictureLayerImplTest : public testing::Test {
for (size_t i = 0; i < active_layer_->tilings()->num_tilings(); ++i)
active_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
pending_layer_->set_invalidation(invalidation);
- pending_layer_->SyncFromActiveLayer();
for (size_t i = 0; i < pending_layer_->tilings()->num_tilings(); ++i)
pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
}
@@ -98,6 +105,7 @@ class PictureLayerImplTest : public testing::Test {
pending_layer_ = static_cast<FakePictureLayerImpl*>(
host_impl_.pending_tree()->LayerById(id_));
+ pending_layer_->DoPostCommitInitializationIfNeeded();
}
static void VerifyAllTilesExistAndHavePile(
@@ -180,7 +188,7 @@ class PictureLayerImplTest : public testing::Test {
SkBitmap store;
store.setConfig(SkBitmap::kNo_Config, 1000, 1000);
- SkDevice device(store);
+ SkBitmapDevice device(store);
std::vector<SkRect>::const_iterator rect_iter = rects.begin();
for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
@@ -241,6 +249,62 @@ TEST_F(PictureLayerImplTest, CloneNoInvalidation) {
VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), active_pile.get());
}
+TEST_F(PictureLayerImplTest, SuppressUpdateTilePriorities) {
+ base::TimeTicks time_ticks;
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ Region invalidation;
+ AddDefaultTilingsWithInvalidation(invalidation);
+ float dummy_contents_scale_x;
+ float dummy_contents_scale_y;
+ gfx::Size dummy_content_bounds;
+ active_layer_->CalculateContentsScale(1.f,
+ 1.f,
+ 1.f,
+ false,
+ &dummy_contents_scale_x,
+ &dummy_contents_scale_y,
+ &dummy_content_bounds);
+
+ EXPECT_TRUE(host_impl_.manage_tiles_needed());
+ active_layer_->UpdateTilePriorities();
+ host_impl_.ManageTiles();
+ EXPECT_FALSE(host_impl_.manage_tiles_needed());
+
+ time_ticks += base::TimeDelta::FromMilliseconds(200);
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+ // Setting this boolean should cause an early out in UpdateTilePriorities.
+ bool valid_for_tile_management = false;
+ host_impl_.SetExternalDrawConstraints(gfx::Transform(),
+ gfx::Rect(layer_bounds),
+ gfx::Rect(layer_bounds),
+ valid_for_tile_management);
+ active_layer_->UpdateTilePriorities();
+ EXPECT_FALSE(host_impl_.manage_tiles_needed());
+
+ time_ticks += base::TimeDelta::FromMilliseconds(200);
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+ valid_for_tile_management = true;
+ host_impl_.SetExternalDrawConstraints(gfx::Transform(),
+ gfx::Rect(layer_bounds),
+ gfx::Rect(layer_bounds),
+ valid_for_tile_management);
+ active_layer_->UpdateTilePriorities();
+ EXPECT_TRUE(host_impl_.manage_tiles_needed());
+}
+
TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -822,7 +886,7 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
TestWebGraphicsContext3D::Create();
context->set_max_texture_size(140);
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
- context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>());
+ context.Pass()).PassAs<OutputSurface>());
pending_layer_->CalculateContentsScale(
1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
@@ -873,7 +937,7 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
TestWebGraphicsContext3D::Create();
context->set_max_texture_size(140);
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
- context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>());
+ context.Pass()).PassAs<OutputSurface>());
pending_layer_->CalculateContentsScale(
1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
@@ -1007,5 +1071,98 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
EXPECT_GT(num_offscreen, 0);
}
+TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ host_impl_.CreatePendingTree();
+ LayerTreeImpl* pending_tree = host_impl_.pending_tree();
+
+ scoped_ptr<FakePictureLayerImpl> pending_layer =
+ FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pending_pile);
+ pending_layer->SetDrawsContent(true);
+ pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>());
+
+ pending_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.pending_tree()->LayerById(id_));
+
+ // Set some state on the pending layer, make sure it is not clobbered
+ // by a sync from the active layer. This could happen because if the
+ // pending layer has not been post-commit initialized it will attempt
+ // to sync from the active layer.
+ bool default_lcd_text_setting = pending_layer_->is_using_lcd_text();
+ pending_layer_->force_set_lcd_text(!default_lcd_text_setting);
+ EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
+
+ host_impl_.ActivatePendingTree();
+
+ active_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.active_tree()->LayerById(id_));
+
+ EXPECT_EQ(0u, active_layer_->num_tilings());
+ EXPECT_EQ(!default_lcd_text_setting, active_layer_->is_using_lcd_text());
+ EXPECT_FALSE(active_layer_->needs_post_commit_initialization());
+}
+
+// Solid color scrollbar setting is required for deferred initialization.
+class ImplSidePaintingSolidColorScrollbarSettings
+ : public ImplSidePaintingSettings {
+ public:
+ ImplSidePaintingSolidColorScrollbarSettings() {
+ solid_color_scrollbars = true;
+ }
+};
+
+class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
+ public:
+ DeferredInitPictureLayerImplTest()
+ : PictureLayerImplTest(ImplSidePaintingSolidColorScrollbarSettings()) {}
+
+ virtual void InitializeRenderer() OVERRIDE {
+ host_impl_.InitializeRenderer(FakeOutputSurface::CreateDeferredGL(
+ scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice))
+ .PassAs<OutputSurface>());
+ }
+
+ virtual void SetUp() OVERRIDE {
+ PictureLayerImplTest::SetUp();
+
+ // Create some default active and pending trees.
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+ }
+};
+
+// This test is really a LayerTreeHostImpl test, in that it makes sure
+// that trees need update draw properties after deferred initialization.
+// However, this is also a regression test for PictureLayerImpl in that
+// not having this update will cause a crash.
+TEST_F(DeferredInitPictureLayerImplTest,
+ PreventUpdateTilePrioritiesDuringLostContext) {
+ host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties();
+ EXPECT_FALSE(host_impl_.pending_tree()->needs_update_draw_properties());
+ EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
+
+ FakeOutputSurface* fake_output_surface =
+ static_cast<FakeOutputSurface*>(host_impl_.output_surface());
+ ASSERT_TRUE(fake_output_surface->InitializeAndSetContext3d(
+ TestContextProvider::Create(), NULL));
+
+ // These will crash PictureLayerImpl if this is not true.
+ ASSERT_TRUE(host_impl_.pending_tree()->needs_update_draw_properties());
+ ASSERT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
+ host_impl_.active_tree()->UpdateDrawProperties();
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
new file mode 100644
index 00000000000..c3dd244c2ef
--- /dev/null
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/picture_layer.h"
+
+#include "cc/layers/content_layer_client.h"
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/resource_update_queue.h"
+#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/fake_picture_layer_impl.h"
+#include "cc/test/fake_proxy.h"
+#include "cc/test/impl_side_painting_settings.h"
+#include "cc/trees/occlusion_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class MockContentLayerClient : public ContentLayerClient {
+ public:
+ virtual void PaintContents(SkCanvas* canvas,
+ gfx::Rect clip,
+ gfx::RectF* opaque) OVERRIDE {}
+ virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+};
+
+TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
+ MockContentLayerClient client;
+ scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
+ layer->SetBounds(gfx::Size(10, 10));
+
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ host->SetRootLayer(layer);
+ layer->SetIsDrawable(true);
+ layer->SavePaintProperties();
+
+ OcclusionTracker occlusion(gfx::Rect(0, 0, 1000, 1000), false);
+ scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue);
+ layer->Update(queue.get(), &occlusion);
+
+ layer->SetBounds(gfx::Size(0, 0));
+ layer->SavePaintProperties();
+ // Intentionally skipping Update since it would normally be skipped on
+ // a layer with empty bounds.
+
+ FakeProxy proxy;
+#ifndef NDEBUG
+ proxy.SetCurrentThreadIsImplThread(true);
+#endif
+ {
+ FakeLayerTreeHostImpl host_impl(ImplSidePaintingSettings(), &proxy);
+ host_impl.CreatePendingTree();
+ scoped_ptr<FakePictureLayerImpl> layer_impl =
+ FakePictureLayerImpl::Create(host_impl.pending_tree(), 1);
+
+ layer->PushPropertiesTo(layer_impl.get());
+ EXPECT_FALSE(layer_impl->CanHaveTilings());
+ EXPECT_TRUE(layer_impl->bounds() == gfx::Size(0, 0));
+ EXPECT_TRUE(layer_impl->pile()->size() == gfx::Size(0, 0));
+ EXPECT_TRUE(layer_impl->pile()->recorded_region().IsEmpty());
+ }
+#ifndef NDEBUG
+ proxy.SetCurrentThreadIsImplThread(false);
+#endif
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer.cc b/chromium/cc/layers/scrollbar_layer.cc
deleted file mode 100644
index 95eb6384732..00000000000
--- a/chromium/cc/layers/scrollbar_layer.cc
+++ /dev/null
@@ -1,353 +0,0 @@
-
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/layers/scrollbar_layer.h"
-
-#include "base/auto_reset.h"
-#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
-#include "cc/layers/scrollbar_layer_impl.h"
-#include "cc/resources/caching_bitmap_content_layer_updater.h"
-#include "cc/resources/layer_painter.h"
-#include "cc/resources/prioritized_resource.h"
-#include "cc/resources/resource_update_queue.h"
-#include "cc/trees/layer_tree_host.h"
-#include "ui/gfx/rect_conversions.h"
-
-namespace cc {
-
-scoped_ptr<LayerImpl> ScrollbarLayer::CreateLayerImpl(
- LayerTreeImpl* tree_impl) {
- return ScrollbarLayerImpl::Create(
- tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>();
-}
-
-scoped_refptr<ScrollbarLayer> ScrollbarLayer::Create(
- scoped_ptr<Scrollbar> scrollbar,
- int scroll_layer_id) {
- return make_scoped_refptr(new ScrollbarLayer(scrollbar.Pass(),
- scroll_layer_id));
-}
-
-ScrollbarLayer::ScrollbarLayer(
- scoped_ptr<Scrollbar> scrollbar,
- int scroll_layer_id)
- : scrollbar_(scrollbar.Pass()),
- scroll_layer_id_(scroll_layer_id),
- texture_format_(GL_INVALID_ENUM) {
- if (!scrollbar_->IsOverlay())
- SetShouldScrollOnMainThread(true);
-}
-
-ScrollbarLayer::~ScrollbarLayer() {}
-
-void ScrollbarLayer::SetScrollLayerId(int id) {
- if (id == scroll_layer_id_)
- return;
-
- scroll_layer_id_ = id;
- SetNeedsFullTreeSync();
-}
-
-bool ScrollbarLayer::OpacityCanAnimateOnImplThread() const {
- return scrollbar_->IsOverlay();
-}
-
-ScrollbarOrientation ScrollbarLayer::Orientation() const {
- return scrollbar_->Orientation();
-}
-
-int ScrollbarLayer::MaxTextureSize() {
- DCHECK(layer_tree_host());
- return layer_tree_host()->GetRendererCapabilities().max_texture_size;
-}
-
-float ScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
- if (layer_tree_host()->settings().solid_color_scrollbars)
- return scale;
-
- // If the scaled content_bounds() is bigger than the max texture size of the
- // device, we need to clamp it by rescaling, since content_bounds() is used
- // below to set the texture size.
- gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
- if (scaled_bounds.width() > MaxTextureSize() ||
- scaled_bounds.height() > MaxTextureSize()) {
- if (scaled_bounds.width() > scaled_bounds.height())
- return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
- else
- return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
- }
- return scale;
-}
-
-void ScrollbarLayer::CalculateContentsScale(float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) {
- ContentsScalingLayer::CalculateContentsScale(
- ClampScaleToMaxTextureSize(ideal_contents_scale),
- device_scale_factor,
- page_scale_factor,
- animating_transform_to_screen,
- contents_scale_x,
- contents_scale_y,
- content_bounds);
-}
-
-void ScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
- ContentsScalingLayer::PushPropertiesTo(layer);
-
- ScrollbarLayerImpl* scrollbar_layer = static_cast<ScrollbarLayerImpl*>(layer);
-
- if (layer_tree_host() &&
- layer_tree_host()->settings().solid_color_scrollbars) {
- int thickness_override =
- layer_tree_host()->settings().solid_color_scrollbar_thickness_dip;
- if (thickness_override != -1) {
- scrollbar_layer->SetThumbThickness(thickness_override);
- } else {
- if (Orientation() == HORIZONTAL)
- scrollbar_layer->SetThumbThickness(bounds().height());
- else
- scrollbar_layer->SetThumbThickness(bounds().width());
- }
- } else {
- scrollbar_layer->SetThumbThickness(thumb_thickness_);
- }
- scrollbar_layer->SetThumbLength(thumb_length_);
- if (Orientation() == HORIZONTAL) {
- scrollbar_layer->SetTrackStart(track_rect_.x() - location_.x());
- scrollbar_layer->SetTrackLength(track_rect_.width());
- } else {
- scrollbar_layer->SetTrackStart(track_rect_.y() - location_.y());
- scrollbar_layer->SetTrackLength(track_rect_.height());
- }
-
- if (track_ && track_->texture()->have_backing_texture())
- scrollbar_layer->set_track_resource_id(track_->texture()->resource_id());
- else
- scrollbar_layer->set_track_resource_id(0);
-
- if (thumb_ && thumb_->texture()->have_backing_texture())
- scrollbar_layer->set_thumb_resource_id(thumb_->texture()->resource_id());
- else
- scrollbar_layer->set_thumb_resource_id(0);
-
- scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay());
-
- // ScrollbarLayer must push properties every frame. crbug.com/259095
- needs_push_properties_ = true;
-}
-
-ScrollbarLayer* ScrollbarLayer::ToScrollbarLayer() {
- return this;
-}
-
-void ScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
- if (!host || host != layer_tree_host()) {
- track_updater_ = NULL;
- track_.reset();
- thumb_updater_ = NULL;
- thumb_.reset();
- }
-
- ContentsScalingLayer::SetLayerTreeHost(host);
-}
-
-class ScrollbarPartPainter : public LayerPainter {
- public:
- ScrollbarPartPainter(Scrollbar* scrollbar, ScrollbarPart part)
- : scrollbar_(scrollbar),
- part_(part) {}
- virtual ~ScrollbarPartPainter() {}
-
- // LayerPainter implementation
- virtual void Paint(SkCanvas* canvas,
- gfx::Rect content_rect,
- gfx::RectF* opaque) OVERRIDE {
- scrollbar_->PaintPart(canvas, part_, content_rect);
- }
-
- private:
- Scrollbar* scrollbar_;
- ScrollbarPart part_;
-};
-
-void ScrollbarLayer::CreateUpdaterIfNeeded() {
- if (layer_tree_host()->settings().solid_color_scrollbars)
- return;
-
- texture_format_ =
- layer_tree_host()->GetRendererCapabilities().best_texture_format;
-
- if (!track_updater_.get()) {
- track_updater_ = CachingBitmapContentLayerUpdater::Create(
- scoped_ptr<LayerPainter>(
- new ScrollbarPartPainter(scrollbar_.get(), TRACK))
- .Pass(),
- rendering_stats_instrumentation(),
- id());
- }
- if (!track_) {
- track_ = track_updater_->CreateResource(
- layer_tree_host()->contents_texture_manager());
- }
-
- if (!thumb_updater_.get()) {
- thumb_updater_ = CachingBitmapContentLayerUpdater::Create(
- scoped_ptr<LayerPainter>(
- new ScrollbarPartPainter(scrollbar_.get(), THUMB))
- .Pass(),
- rendering_stats_instrumentation(),
- id());
- }
- if (!thumb_ && scrollbar_->HasThumb()) {
- thumb_ = thumb_updater_->CreateResource(
- layer_tree_host()->contents_texture_manager());
- }
-}
-
-bool ScrollbarLayer::UpdatePart(CachingBitmapContentLayerUpdater* painter,
- LayerUpdater::Resource* resource,
- gfx::Rect rect,
- ResourceUpdateQueue* queue) {
- if (layer_tree_host()->settings().solid_color_scrollbars)
- return false;
-
- // Skip painting and uploading if there are no invalidations and
- // we already have valid texture data.
- if (resource->texture()->have_backing_texture() &&
- resource->texture()->size() == rect.size() &&
- !is_dirty())
- return false;
-
- // We should always have enough memory for UI.
- DCHECK(resource->texture()->can_acquire_backing_texture());
- if (!resource->texture()->can_acquire_backing_texture())
- return false;
-
- // Paint and upload the entire part.
- gfx::Rect painted_opaque_rect;
- painter->PrepareToUpdate(rect,
- rect.size(),
- contents_scale_x(),
- contents_scale_y(),
- &painted_opaque_rect);
- if (!painter->pixels_did_change() &&
- resource->texture()->have_backing_texture()) {
- TRACE_EVENT_INSTANT0("cc",
- "ScrollbarLayer::UpdatePart no texture upload needed",
- TRACE_EVENT_SCOPE_THREAD);
- return false;
- }
-
- bool partial_updates_allowed =
- layer_tree_host()->settings().max_partial_texture_updates > 0;
- if (!partial_updates_allowed)
- resource->texture()->ReturnBackingTexture();
-
- gfx::Vector2d dest_offset(0, 0);
- resource->Update(queue, rect, dest_offset, partial_updates_allowed);
- return true;
-}
-
-gfx::Rect ScrollbarLayer::ScrollbarLayerRectToContentRect(
- gfx::Rect layer_rect) const {
- // Don't intersect with the bounds as in LayerRectToContentRect() because
- // layer_rect here might be in coordinates of the containing layer.
- gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
- layer_rect, contents_scale_y(), contents_scale_y());
- // We should never return a rect bigger than the content_bounds().
- gfx::Size clamped_size = expanded_rect.size();
- clamped_size.SetToMin(content_bounds());
- expanded_rect.set_size(clamped_size);
- return expanded_rect;
-}
-
-void ScrollbarLayer::SetTexturePriorities(
- const PriorityCalculator& priority_calc) {
- if (layer_tree_host()->settings().solid_color_scrollbars)
- return;
-
- if (content_bounds().IsEmpty())
- return;
- DCHECK_LE(content_bounds().width(), MaxTextureSize());
- DCHECK_LE(content_bounds().height(), MaxTextureSize());
-
- CreateUpdaterIfNeeded();
-
- bool draws_to_root = !render_target()->parent();
- if (track_) {
- track_->texture()->SetDimensions(content_bounds(), texture_format_);
- track_->texture()->set_request_priority(
- PriorityCalculator::UIPriority(draws_to_root));
- }
- if (thumb_) {
- gfx::Size thumb_size = OriginThumbRect().size();
- thumb_->texture()->SetDimensions(thumb_size, texture_format_);
- thumb_->texture()->set_request_priority(
- PriorityCalculator::UIPriority(draws_to_root));
- }
-}
-
-bool ScrollbarLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
- track_rect_ = scrollbar_->TrackRect();
- location_ = scrollbar_->Location();
-
- if (layer_tree_host()->settings().solid_color_scrollbars)
- return false;
-
- bool updated = false;
-
- {
- base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
- true);
- updated = ContentsScalingLayer::Update(queue, occlusion);
- }
-
- dirty_rect_.Union(update_rect_);
- if (content_bounds().IsEmpty())
- return false;
- if (visible_content_rect().IsEmpty())
- return false;
-
- CreateUpdaterIfNeeded();
-
- gfx::Rect content_rect = ScrollbarLayerRectToContentRect(
- gfx::Rect(scrollbar_->Location(), bounds()));
- updated |= UpdatePart(track_updater_.get(), track_.get(), content_rect,
- queue);
-
- if (scrollbar_->HasThumb()) {
- thumb_thickness_ = scrollbar_->ThumbThickness();
- thumb_length_ = scrollbar_->ThumbLength();
- gfx::Rect origin_thumb_rect = OriginThumbRect();
- if (!origin_thumb_rect.IsEmpty()) {
- updated |= UpdatePart(thumb_updater_.get(), thumb_.get(),
- origin_thumb_rect, queue);
- }
- }
-
- dirty_rect_ = gfx::RectF();
- return updated;
-}
-
-gfx::Rect ScrollbarLayer::OriginThumbRect() const {
- gfx::Size thumb_size;
- if (Orientation() == HORIZONTAL) {
- thumb_size = gfx::Size(scrollbar_->ThumbLength(),
- scrollbar_->ThumbThickness());
- } else {
- thumb_size = gfx::Size(scrollbar_->ThumbThickness(),
- scrollbar_->ThumbLength());
- }
- return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size));
-}
-
-} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer_impl.cc b/chromium/cc/layers/scrollbar_layer_impl.cc
deleted file mode 100644
index 1de185a77dd..00000000000
--- a/chromium/cc/layers/scrollbar_layer_impl.cc
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/layers/scrollbar_layer_impl.h"
-
-#include <algorithm>
-
-#include "cc/animation/scrollbar_animation_controller.h"
-#include "cc/layers/layer.h"
-#include "cc/layers/quad_sink.h"
-#include "cc/quads/solid_color_draw_quad.h"
-#include "cc/quads/texture_draw_quad.h"
-#include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/layer_tree_settings.h"
-#include "ui/gfx/rect_conversions.h"
-
-namespace cc {
-
-scoped_ptr<ScrollbarLayerImpl> ScrollbarLayerImpl::Create(
- LayerTreeImpl* tree_impl,
- int id,
- ScrollbarOrientation orientation) {
- return make_scoped_ptr(new ScrollbarLayerImpl(tree_impl,
- id,
- orientation));
-}
-
-ScrollbarLayerImpl::ScrollbarLayerImpl(
- LayerTreeImpl* tree_impl,
- int id,
- ScrollbarOrientation orientation)
- : LayerImpl(tree_impl, id),
- track_resource_id_(0),
- thumb_resource_id_(0),
- current_pos_(0.f),
- maximum_(0),
- thumb_thickness_(0),
- thumb_length_(0),
- track_start_(0),
- track_length_(0),
- orientation_(orientation),
- vertical_adjust_(0.f),
- visible_to_total_length_ratio_(1.f),
- scroll_layer_id_(Layer::INVALID_ID),
- is_overlay_scrollbar_(false) {}
-
-ScrollbarLayerImpl::~ScrollbarLayerImpl() {}
-
-ScrollbarLayerImpl* ScrollbarLayerImpl::ToScrollbarLayer() {
- return this;
-}
-
-scoped_ptr<LayerImpl> ScrollbarLayerImpl::CreateLayerImpl(
- LayerTreeImpl* tree_impl) {
- return ScrollbarLayerImpl::Create(tree_impl,
- id(),
- orientation_).PassAs<LayerImpl>();
-}
-
-void ScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
- LayerImpl::PushPropertiesTo(layer);
-
- ScrollbarLayerImpl* scrollbar_layer = static_cast<ScrollbarLayerImpl*>(layer);
-
- scrollbar_layer->SetThumbThickness(thumb_thickness_);
- scrollbar_layer->SetThumbLength(thumb_length_);
- scrollbar_layer->SetTrackStart(track_start_);
- scrollbar_layer->SetTrackLength(track_length_);
- scrollbar_layer->set_is_overlay_scrollbar(is_overlay_scrollbar_);
-
- scrollbar_layer->set_track_resource_id(track_resource_id_);
- scrollbar_layer->set_thumb_resource_id(thumb_resource_id_);
-}
-
-bool ScrollbarLayerImpl::WillDraw(DrawMode draw_mode,
- ResourceProvider* resource_provider) {
- if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE &&
- !layer_tree_impl()->settings().solid_color_scrollbars)
- return false;
- return LayerImpl::WillDraw(draw_mode, resource_provider);
-}
-
-void ScrollbarLayerImpl::AppendQuads(QuadSink* quad_sink,
- AppendQuadsData* append_quads_data) {
- bool premultipled_alpha = true;
- bool flipped = false;
- gfx::PointF uv_top_left(0.f, 0.f);
- gfx::PointF uv_bottom_right(1.f, 1.f);
- gfx::Rect bounds_rect(bounds());
- gfx::Rect content_bounds_rect(content_bounds());
-
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
-
- gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
-
- if (layer_tree_impl()->settings().solid_color_scrollbars) {
- scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- thumb_quad_rect,
- layer_tree_impl()->settings().solid_color_scrollbar_color,
- false);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
- return;
- }
-
- if (thumb_resource_id_ && !thumb_quad_rect.IsEmpty()) {
- gfx::Rect opaque_rect;
- const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
- scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- thumb_quad_rect,
- opaque_rect,
- thumb_resource_id_,
- premultipled_alpha,
- uv_top_left,
- uv_bottom_right,
- SK_ColorTRANSPARENT,
- opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
- }
-
- if (!track_resource_id_)
- return;
-
- // Order matters here: since the back track texture is being drawn to the
- // entire contents rect, we must append it after the thumb and fore track
- // quads. The back track texture contains (and displays) the buttons.
- if (!content_bounds_rect.IsEmpty()) {
- gfx::Rect quad_rect(content_bounds_rect);
- gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
- const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
- scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- quad_rect,
- opaque_rect,
- track_resource_id_,
- premultipled_alpha,
- uv_top_left,
- uv_bottom_right,
- SK_ColorTRANSPARENT,
- opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
- }
-}
-
-ScrollbarOrientation ScrollbarLayerImpl::Orientation() const {
- return orientation_;
-}
-
-float ScrollbarLayerImpl::CurrentPos() const {
- return current_pos_;
-}
-
-int ScrollbarLayerImpl::Maximum() const {
- return maximum_;
-}
-
-gfx::Rect ScrollbarLayerImpl::ScrollbarLayerRectToContentRect(
- gfx::RectF layer_rect) const {
- // Don't intersect with the bounds as in layerRectToContentRect() because
- // layer_rect here might be in coordinates of the containing layer.
- gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
- contents_scale_x(),
- contents_scale_y());
- return gfx::ToEnclosingRect(content_rect);
-}
-
-void ScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) {
- if (thumb_thickness_ == thumb_thickness)
- return;
- thumb_thickness_ = thumb_thickness;
- NoteLayerPropertyChanged();
-}
-
-void ScrollbarLayerImpl::SetThumbLength(int thumb_length) {
- if (thumb_length_ == thumb_length)
- return;
- thumb_length_ = thumb_length;
- NoteLayerPropertyChanged();
-}
-void ScrollbarLayerImpl::SetTrackStart(int track_start) {
- if (track_start_ == track_start)
- return;
- track_start_ = track_start;
- NoteLayerPropertyChanged();
-}
-
-void ScrollbarLayerImpl::SetTrackLength(int track_length) {
- if (track_length_ == track_length)
- return;
- track_length_ = track_length;
- NoteLayerPropertyChanged();
-}
-
-void ScrollbarLayerImpl::SetVerticalAdjust(float vertical_adjust) {
- if (vertical_adjust_ == vertical_adjust)
- return;
- vertical_adjust_ = vertical_adjust;
- NoteLayerPropertyChanged();
-}
-
-void ScrollbarLayerImpl::SetVisibleToTotalLengthRatio(float ratio) {
- if (visible_to_total_length_ratio_ == ratio)
- return;
- visible_to_total_length_ratio_ = ratio;
- NoteLayerPropertyChanged();
-}
-
-void ScrollbarLayerImpl::SetCurrentPos(float current_pos) {
- if (current_pos_ == current_pos)
- return;
- current_pos_ = current_pos;
- NoteLayerPropertyChanged();
-}
-
-void ScrollbarLayerImpl::SetMaximum(int maximum) {
- if (maximum_ == maximum)
- return;
- maximum_ = maximum;
- NoteLayerPropertyChanged();
-}
-
-gfx::Rect ScrollbarLayerImpl::ComputeThumbQuadRect() const {
- // Thumb extent is the length of the thumb in the scrolling direction, thumb
- // thickness is in the perpendicular direction. Here's an example of a
- // horizontal scrollbar - inputs are above the scrollbar, computed values
- // below:
- //
- // |<------------------- track_length_ ------------------->|
- //
- // |--| <-- start_offset
- //
- // +--+----------------------------+------------------+-------+--+
- // |<|| |##################| ||>|
- // +--+----------------------------+------------------+-------+--+
- //
- // |<- thumb_length ->|
- //
- // |<------- thumb_offset -------->|
- //
- // For painted, scrollbars, the length is fixed. For solid color scrollbars we
- // have to compute it. The ratio of the thumb's length to the track's length
- // is the same as that of the visible viewport to the total viewport, unless
- // that would make the thumb's length less than its thickness.
- //
- // vertical_adjust_ is used when the layer geometry from the main thread is
- // not in sync with what the user sees. For instance on Android scrolling the
- // top bar controls out of view reveals more of the page content. We want the
- // root layer scrollbars to reflect what the user sees even if we haven't
- // received new layer geometry from the main thread. If the user has scrolled
- // down by 50px and the initial viewport size was 950px the geometry would
- // look something like this:
- //
- // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
- // Layer geometry: Desired thumb positions:
- // +--------------------+-+ +----------------------+ <-- 0px
- // | |v| | #|
- // | |e| | #|
- // | |r| | #|
- // | |t| | #|
- // | |i| | #|
- // | |c| | #|
- // | |a| | #|
- // | |l| | #|
- // | | | | #|
- // | |l| | #|
- // | |a| | #|
- // | |y| | #|
- // | |e| | #|
- // | |r| | #|
- // +--------------------+-+ | #|
- // | horizontal layer | | | #|
- // +--------------------+-+ | #| <-- 950px
- // | | | #|
- // | | |##################### |
- // +----------------------+ +----------------------+ <-- 1000px
- //
- // The layer geometry is set up for a 950px tall viewport, but the user can
- // actually see down to 1000px. Thus we have to move the quad for the
- // horizontal scrollbar down by the vertical_adjust_ factor and lay the
- // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
- // means the quads may extend outside the layer's bounds.
-
- int thumb_length = thumb_length_;
- float track_length = track_length_;
- if (orientation_ == VERTICAL)
- track_length += vertical_adjust_;
-
- if (layer_tree_impl()->settings().solid_color_scrollbars) {
- thumb_length = std::max(
- static_cast<int>(visible_to_total_length_ratio_ * track_length),
- thumb_thickness_);
- }
-
- // With the length known, we can compute the thumb's position.
- float clamped_current_pos =
- std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_));
- float ratio = clamped_current_pos / maximum_;
- float max_offset = track_length - thumb_length;
- int thumb_offset = static_cast<int>(ratio * max_offset) + track_start_;
-
- gfx::RectF thumb_rect;
- if (orientation_ == HORIZONTAL) {
- thumb_rect = gfx::RectF(thumb_offset, vertical_adjust_,
- thumb_length, thumb_thickness_);
- } else {
- thumb_rect = gfx::RectF(0.f, thumb_offset,
- thumb_thickness_, thumb_length);
- }
-
- return ScrollbarLayerRectToContentRect(thumb_rect);
-}
-
-void ScrollbarLayerImpl::DidLoseOutputSurface() {
- track_resource_id_ = 0;
- thumb_resource_id_ = 0;
-}
-
-const char* ScrollbarLayerImpl::LayerTypeAsString() const {
- return "cc::ScrollbarLayerImpl";
-}
-
-} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer_impl.h b/chromium/cc/layers/scrollbar_layer_impl.h
deleted file mode 100644
index 6347c413dfc..00000000000
--- a/chromium/cc/layers/scrollbar_layer_impl.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_LAYERS_SCROLLBAR_LAYER_IMPL_H_
-#define CC_LAYERS_SCROLLBAR_LAYER_IMPL_H_
-
-#include "cc/base/cc_export.h"
-#include "cc/input/scrollbar.h"
-#include "cc/layers/layer_impl.h"
-
-namespace cc {
-
-class LayerTreeImpl;
-class ScrollView;
-
-class CC_EXPORT ScrollbarLayerImpl : public LayerImpl {
- public:
- static scoped_ptr<ScrollbarLayerImpl> Create(
- LayerTreeImpl* tree_impl,
- int id,
- ScrollbarOrientation orientation);
- virtual ~ScrollbarLayerImpl();
-
- // LayerImpl implementation.
- virtual ScrollbarLayerImpl* ToScrollbarLayer() OVERRIDE;
- virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
- OVERRIDE;
- virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
-
- virtual bool WillDraw(DrawMode draw_mode,
- ResourceProvider* resource_provider) OVERRIDE;
- virtual void AppendQuads(QuadSink* quad_sink,
- AppendQuadsData* append_quads_data) OVERRIDE;
-
- virtual void DidLoseOutputSurface() OVERRIDE;
-
- int scroll_layer_id() const { return scroll_layer_id_; }
- void set_scroll_layer_id(int id) { scroll_layer_id_ = id; }
-
- ScrollbarOrientation Orientation() const;
- float CurrentPos() const;
- int Maximum() const;
-
- void SetThumbThickness(int thumb_thickness);
- int thumb_thickness() const { return thumb_thickness_; }
- void SetThumbLength(int thumb_length);
- void SetTrackStart(int track_start);
- void SetTrackLength(int track_length);
- void SetVerticalAdjust(float vertical_adjust);
- void set_track_resource_id(ResourceProvider::ResourceId id) {
- track_resource_id_ = id;
- }
- void set_thumb_resource_id(ResourceProvider::ResourceId id) {
- thumb_resource_id_ = id;
- }
- void SetVisibleToTotalLengthRatio(float ratio);
- void set_is_overlay_scrollbar(bool is_overlay_scrollbar) {
- is_overlay_scrollbar_ = is_overlay_scrollbar;
- }
- bool is_overlay_scrollbar() const { return is_overlay_scrollbar_; }
-
- void SetCurrentPos(float current_pos);
- void SetMaximum(int maximum);
-
- gfx::Rect ComputeThumbQuadRect() const;
-
- protected:
- ScrollbarLayerImpl(LayerTreeImpl* tree_impl,
- int id,
- ScrollbarOrientation orientation);
-
- private:
- virtual const char* LayerTypeAsString() const OVERRIDE;
-
- gfx::Rect ScrollbarLayerRectToContentRect(gfx::RectF layer_rect) const;
-
- ResourceProvider::ResourceId track_resource_id_;
- ResourceProvider::ResourceId thumb_resource_id_;
-
- float current_pos_;
- int maximum_;
- int thumb_thickness_;
- int thumb_length_;
- int track_start_;
- int track_length_;
- ScrollbarOrientation orientation_;
-
- // Difference between the clip layer's height and the visible viewport
- // height (which may differ in the presence of top-controls hiding).
- float vertical_adjust_;
-
- float visible_to_total_length_ratio_;
-
- int scroll_layer_id_;
-
- bool is_overlay_scrollbar_;
-
- DISALLOW_COPY_AND_ASSIGN(ScrollbarLayerImpl);
-};
-
-} // namespace cc
-#endif // CC_LAYERS_SCROLLBAR_LAYER_IMPL_H_
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc
new file mode 100644
index 00000000000..c1e7126ff52
--- /dev/null
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc
@@ -0,0 +1,170 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/scrollbar_layer_impl_base.h"
+
+#include <algorithm>
+#include "cc/layers/layer.h"
+#include "ui/gfx/rect_conversions.h"
+
+namespace cc {
+
+ScrollbarLayerImplBase::ScrollbarLayerImplBase(
+ LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation,
+ bool is_left_side_vertical_scrollbar)
+ : LayerImpl(tree_impl, id),
+ scroll_layer_id_(Layer::INVALID_ID),
+ is_overlay_scrollbar_(false),
+ thumb_thickness_scale_factor_(1.f),
+ current_pos_(0.f),
+ maximum_(0),
+ orientation_(orientation),
+ is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar),
+ vertical_adjust_(0.f),
+ visible_to_total_length_ratio_(1.f) {}
+
+void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) {
+ LayerImpl::PushPropertiesTo(layer);
+}
+
+ScrollbarLayerImplBase* ScrollbarLayerImplBase::ToScrollbarLayer() {
+ return this;
+}
+
+gfx::Rect ScrollbarLayerImplBase::ScrollbarLayerRectToContentRect(
+ gfx::RectF layer_rect) const {
+ // Don't intersect with the bounds as in LayerRectToContentRect() because
+ // layer_rect here might be in coordinates of the containing layer.
+ gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
+ contents_scale_x(),
+ contents_scale_y());
+ return gfx::ToEnclosingRect(content_rect);
+}
+
+void ScrollbarLayerImplBase::SetCurrentPos(float current_pos) {
+ if (current_pos_ == current_pos)
+ return;
+ current_pos_ = current_pos;
+ NoteLayerPropertyChanged();
+}
+
+void ScrollbarLayerImplBase::SetMaximum(int maximum) {
+ if (maximum_ == maximum)
+ return;
+ maximum_ = maximum;
+ NoteLayerPropertyChanged();
+}
+
+void ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) {
+ if (vertical_adjust_ == vertical_adjust)
+ return;
+ vertical_adjust_ = vertical_adjust;
+ NoteLayerPropertyChanged();
+}
+
+void ScrollbarLayerImplBase::SetVisibleToTotalLengthRatio(float ratio) {
+ if (visible_to_total_length_ratio_ == ratio)
+ return;
+ visible_to_total_length_ratio_ = ratio;
+ NoteLayerPropertyChanged();
+}
+
+gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
+ // Thumb extent is the length of the thumb in the scrolling direction, thumb
+ // thickness is in the perpendicular direction. Here's an example of a
+ // horizontal scrollbar - inputs are above the scrollbar, computed values
+ // below:
+ //
+ // |<------------------- track_length_ ------------------->|
+ //
+ // |--| <-- start_offset
+ //
+ // +--+----------------------------+------------------+-------+--+
+ // |<|| |##################| ||>|
+ // +--+----------------------------+------------------+-------+--+
+ //
+ // |<- thumb_length ->|
+ //
+ // |<------- thumb_offset -------->|
+ //
+ // For painted, scrollbars, the length is fixed. For solid color scrollbars we
+ // have to compute it. The ratio of the thumb's length to the track's length
+ // is the same as that of the visible viewport to the total viewport, unless
+ // that would make the thumb's length less than its thickness.
+ //
+ // vertical_adjust_ is used when the layer geometry from the main thread is
+ // not in sync with what the user sees. For instance on Android scrolling the
+ // top bar controls out of view reveals more of the page content. We want the
+ // root layer scrollbars to reflect what the user sees even if we haven't
+ // received new layer geometry from the main thread. If the user has scrolled
+ // down by 50px and the initial viewport size was 950px the geometry would
+ // look something like this:
+ //
+ // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
+ // Layer geometry: Desired thumb positions:
+ // +--------------------+-+ +----------------------+ <-- 0px
+ // | |v| | #|
+ // | |e| | #|
+ // | |r| | #|
+ // | |t| | #|
+ // | |i| | #|
+ // | |c| | #|
+ // | |a| | #|
+ // | |l| | #|
+ // | | | | #|
+ // | |l| | #|
+ // | |a| | #|
+ // | |y| | #|
+ // | |e| | #|
+ // | |r| | #|
+ // +--------------------+-+ | #|
+ // | horizontal layer | | | #|
+ // +--------------------+-+ | #| <-- 950px
+ // | | | #|
+ // | | |##################### |
+ // +----------------------+ +----------------------+ <-- 1000px
+ //
+ // The layer geometry is set up for a 950px tall viewport, but the user can
+ // actually see down to 1000px. Thus we have to move the quad for the
+ // horizontal scrollbar down by the vertical_adjust_ factor and lay the
+ // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
+ // means the quads may extend outside the layer's bounds.
+
+ // With the length known, we can compute the thumb's position.
+ float track_length = TrackLength();
+ int thumb_length = ThumbLength();
+ int thumb_thickness = ThumbThickness();
+
+ // With the length known, we can compute the thumb's position.
+ float clamped_current_pos =
+ std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_));
+ float ratio = clamped_current_pos / maximum_;
+ float max_offset = track_length - thumb_length;
+ int thumb_offset = static_cast<int>(ratio * max_offset) + TrackStart();
+
+ float thumb_thickness_adjustment =
+ thumb_thickness * (1.f - thumb_thickness_scale_factor_);
+
+ gfx::RectF thumb_rect;
+ if (orientation_ == HORIZONTAL) {
+ thumb_rect = gfx::RectF(thumb_offset,
+ vertical_adjust_ + thumb_thickness_adjustment,
+ thumb_length,
+ thumb_thickness - thumb_thickness_adjustment);
+ } else {
+ thumb_rect = gfx::RectF(
+ is_left_side_vertical_scrollbar_
+ ? bounds().width() - thumb_thickness
+ : thumb_thickness_adjustment,
+ thumb_offset,
+ thumb_thickness - thumb_thickness_adjustment,
+ thumb_length);
+ }
+
+ return ScrollbarLayerRectToContentRect(thumb_rect);
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h
new file mode 100644
index 00000000000..55ade6ab04f
--- /dev/null
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.h
@@ -0,0 +1,91 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_SCROLLBAR_LAYER_IMPL_BASE_H_
+#define CC_LAYERS_SCROLLBAR_LAYER_IMPL_BASE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/input/scrollbar.h"
+#include "cc/layers/layer_impl.h"
+
+namespace cc {
+
+class LayerTreeImpl;
+
+class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
+ public:
+ int ScrollLayerId() const { return scroll_layer_id_; }
+ void set_scroll_layer_id(int id) { scroll_layer_id_ = id; }
+
+ float current_pos() const { return current_pos_; }
+ void SetCurrentPos(float current_pos);
+ int maximum() const { return maximum_; }
+ void SetMaximum(int maximum);
+
+ void SetVerticalAdjust(float vertical_adjust);
+
+ bool is_overlay_scrollbar() const { return is_overlay_scrollbar_; }
+ void set_is_overlay_scrollbar(bool is_overlay) {
+ is_overlay_scrollbar_ = is_overlay;
+ }
+
+ ScrollbarOrientation orientation() const { return orientation_; }
+ bool is_left_side_vertical_scrollbar() {
+ return is_left_side_vertical_scrollbar_;
+ }
+
+ virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+ virtual ScrollbarLayerImplBase* ToScrollbarLayer() OVERRIDE;
+
+ void SetVisibleToTotalLengthRatio(float ratio);
+ virtual gfx::Rect ComputeThumbQuadRect() const;
+
+ float thumb_thickness_scale_factor() {
+ return thumb_thickness_scale_factor_;
+ }
+ void set_thumb_thickness_scale_factor(float thumb_thickness_scale_factor) {
+ thumb_thickness_scale_factor_ = thumb_thickness_scale_factor;
+ }
+
+ protected:
+ ScrollbarLayerImplBase(LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation,
+ bool is_left_side_vertical_scrollbar);
+ virtual ~ScrollbarLayerImplBase() {}
+
+ gfx::Rect ScrollbarLayerRectToContentRect(gfx::RectF layer_rect) const;
+
+ float visible_to_total_length_ratio() const {
+ return visible_to_total_length_ratio_;
+ }
+ float vertical_adjust() const { return vertical_adjust_; }
+
+ virtual int ThumbThickness() const = 0;
+ virtual int ThumbLength() const = 0;
+ virtual float TrackLength() const = 0;
+ virtual int TrackStart() const = 0;
+
+ private:
+ int scroll_layer_id_;
+ bool is_overlay_scrollbar_;
+
+ float thumb_thickness_scale_factor_;
+ float current_pos_;
+ int maximum_;
+ ScrollbarOrientation orientation_;
+ bool is_left_side_vertical_scrollbar_;
+
+ // Difference between the clip layer's height and the visible viewport
+ // height (which may differ in the presence of top-controls hiding).
+ float vertical_adjust_;
+
+ float visible_to_total_length_ratio_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScrollbarLayerImplBase);
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_SCROLLBAR_LAYER_IMPL_BASE_H_
diff --git a/chromium/cc/layers/scrollbar_layer_interface.h b/chromium/cc/layers/scrollbar_layer_interface.h
new file mode 100644
index 00000000000..bbb0da6ae2b
--- /dev/null
+++ b/chromium/cc/layers/scrollbar_layer_interface.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_SCROLLBAR_LAYER_INTERFACE_H_
+#define CC_LAYERS_SCROLLBAR_LAYER_INTERFACE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/input/scrollbar.h"
+
+namespace cc {
+
+class CC_EXPORT ScrollbarLayerInterface {
+ public:
+ virtual int ScrollLayerId() const = 0;
+ virtual void SetScrollLayerId(int id) = 0;
+
+ virtual ScrollbarOrientation orientation() const = 0;
+
+ protected:
+ ScrollbarLayerInterface() {}
+ virtual ~ScrollbarLayerInterface() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScrollbarLayerInterface);
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_SCROLLBAR_LAYER_INTERFACE_H_
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index b7981041f09..2e1b4b6f483 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -2,24 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/layers/scrollbar_layer.h"
-
+#include "base/containers/hash_tables.h"
#include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
#include "cc/layers/append_quads_data.h"
-#include "cc/layers/scrollbar_layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/layers/scrollbar_layer_interface.h"
+#include "cc/layers/solid_color_scrollbar_layer.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/quads/solid_color_draw_quad.h"
-#include "cc/resources/prioritized_resource_manager.h"
-#include "cc/resources/priority_calculator.h"
#include "cc/resources/resource_update_queue.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_painted_scrollbar_layer.h"
#include "cc/test/fake_scrollbar.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/mock_quad_culler.h"
-#include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
@@ -32,12 +35,20 @@ namespace {
LayerImpl* LayerImplForScrollAreaAndScrollbar(
FakeLayerTreeHost* host,
scoped_ptr<Scrollbar> scrollbar,
- bool reverse_order) {
+ bool reverse_order,
+ bool use_solid_color_scrollbar,
+ int thumb_thickness) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> child1 = Layer::Create();
- scoped_refptr<Layer> child2 =
- ScrollbarLayer::Create(scrollbar.Pass(),
- child1->id());
+ scoped_refptr<Layer> child2;
+ if (use_solid_color_scrollbar) {
+ const bool kIsLeftSideVerticalScrollbar = false;
+ child2 = SolidColorScrollbarLayer::Create(
+ scrollbar->Orientation(), thumb_thickness,
+ kIsLeftSideVerticalScrollbar, child1->id());
+ } else {
+ child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id());
+ }
layer_tree_root->AddChild(child1);
layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
host->SetRootLayer(layer_tree_root);
@@ -47,12 +58,13 @@ LayerImpl* LayerImplForScrollAreaAndScrollbar(
TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
- LayerImpl* layer_impl_tree_root =
- LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
+ LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
+ host.get(), scrollbar.Pass(), false, false, 0);
LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
- ScrollbarLayerImpl* cc_child2 = static_cast<ScrollbarLayerImpl*>(
- layer_impl_tree_root->children()[1]);
+ PaintedScrollbarLayerImpl* cc_child2 =
+ static_cast<PaintedScrollbarLayerImpl*>(
+ layer_impl_tree_root->children()[1]);
EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2);
}
@@ -60,11 +72,12 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
- LayerImpl* layer_impl_tree_root =
- LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), true);
+ LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
+ host.get(), scrollbar.Pass(), true, false, 0);
- ScrollbarLayerImpl* cc_child1 = static_cast<ScrollbarLayerImpl*>(
- layer_impl_tree_root->children()[0]);
+ PaintedScrollbarLayerImpl* cc_child1 =
+ static_cast<PaintedScrollbarLayerImpl*>(
+ layer_impl_tree_root->children()[0]);
LayerImpl* cc_child2 = layer_impl_tree_root->children()[1];
EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1);
@@ -75,10 +88,11 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
// Create and attach a non-overlay scrollbar.
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
- LayerImpl* layer_impl_tree_root =
- LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
- ScrollbarLayerImpl* scrollbar_layer_impl =
- static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+ LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
+ host.get(), scrollbar.Pass(), false, false, 0);
+ PaintedScrollbarLayerImpl* scrollbar_layer_impl =
+ static_cast<PaintedScrollbarLayerImpl*>(
+ layer_impl_tree_root->children()[1]);
// When the scrollbar is not an overlay scrollbar, the scroll should be
// responded to on the main thread as the compositor does not yet implement
@@ -90,10 +104,10 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
// Create and attach an overlay scrollbar.
scrollbar.reset(new FakeScrollbar(false, false, true));
- layer_impl_tree_root =
- LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
- scrollbar_layer_impl =
- static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+ layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
+ host.get(), scrollbar.Pass(), false, false, 0);
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+ layer_impl_tree_root->children()[1]);
// The user shouldn't be able to drag an overlay scrollbar and the scroll
// may be handled in the compositor.
@@ -102,15 +116,14 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
InputHandler::Gesture));
}
-TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) {
+TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
scoped_refptr<Layer> scrollbar_layer =
- ScrollbarLayer::Create(scrollbar.Pass(),
- layer_tree_root->id());
+ PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
layer_tree_root->SetScrollable(true);
layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
@@ -127,11 +140,12 @@ TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) {
LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
- ScrollbarLayerImpl* cc_scrollbar_layer =
- static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+ ScrollbarLayerImplBase* cc_scrollbar_layer =
+ static_cast<PaintedScrollbarLayerImpl*>(
+ layer_impl_tree_root->children()[1]);
- EXPECT_EQ(10.f, cc_scrollbar_layer->CurrentPos());
- EXPECT_EQ(30, cc_scrollbar_layer->Maximum());
+ EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos());
+ EXPECT_EQ(30, cc_scrollbar_layer->maximum());
layer_tree_root->SetScrollOffset(gfx::Vector2d(100, 200));
layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(300, 500));
@@ -146,31 +160,124 @@ TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) {
EXPECT_EQ(scrollbar_controller,
layer_impl_tree_root->scrollbar_animation_controller());
- EXPECT_EQ(100.f, cc_scrollbar_layer->CurrentPos());
- EXPECT_EQ(300, cc_scrollbar_layer->Maximum());
+ EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos());
+ EXPECT_EQ(300, cc_scrollbar_layer->maximum());
layer_impl_tree_root->ScrollBy(gfx::Vector2d(12, 34));
- EXPECT_EQ(112.f, cc_scrollbar_layer->CurrentPos());
- EXPECT_EQ(300, cc_scrollbar_layer->Maximum());
+ EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos());
+ EXPECT_EQ(300, cc_scrollbar_layer->maximum());
+}
+
+TEST(ScrollbarLayerTest, ThumbRect) {
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ scoped_refptr<Layer> root_layer = Layer::Create();
+ scoped_refptr<Layer> content_layer = Layer::Create();
+ scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
+ FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
+
+ root_layer->SetScrollable(true);
+ root_layer->SetMaxScrollOffset(gfx::Vector2d(80, 0));
+ root_layer->SetBounds(gfx::Size(100, 50));
+ content_layer->SetBounds(gfx::Size(100, 50));
+
+ host->SetRootLayer(root_layer);
+ root_layer->AddChild(content_layer);
+ root_layer->AddChild(scrollbar_layer);
+
+ root_layer->SetScrollOffset(gfx::Vector2d(0, 0));
+ scrollbar_layer->SetBounds(gfx::Size(70, 10));
+ scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
+ scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+ scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
+ scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
+ scrollbar_layer->UpdateThumbAndTrackGeometry();
+ LayerImpl* root_layer_impl = NULL;
+ PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL;
+
+ // Thumb is at the edge of the scrollbar (should be inset to
+ // the start of the track within the scrollbar layer's
+ // position).
+ scrollbar_layer->UpdateThumbAndTrackGeometry();
+ root_layer_impl = host->CommitAndCreateLayerImplTree();
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+ root_layer_impl->children()[1]);
+ EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
+ scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+ // Under-scroll (thumb position should clamp and be unchanged).
+ root_layer->SetScrollOffset(gfx::Vector2d(-5, 0));
+
+ scrollbar_layer->UpdateThumbAndTrackGeometry();
+ root_layer_impl = host->CommitAndCreateLayerImplTree();
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+ root_layer_impl->children()[1]);
+ EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
+ scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+ // Over-scroll (thumb position should clamp on the far side).
+ root_layer->SetScrollOffset(gfx::Vector2d(85, 0));
+
+ scrollbar_layer->UpdateThumbAndTrackGeometry();
+ root_layer_impl = host->CommitAndCreateLayerImplTree();
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+ root_layer_impl->children()[1]);
+ EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
+ scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+ // Change thumb thickness and length.
+ scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4);
+ scrollbar_layer->fake_scrollbar()->set_thumb_length(6);
+
+ scrollbar_layer->UpdateThumbAndTrackGeometry();
+ root_layer_impl = host->CommitAndCreateLayerImplTree();
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+ root_layer_impl->children()[1]);
+ EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(),
+ scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+ // Shrink the scrollbar layer to cover only the track.
+ scrollbar_layer->SetBounds(gfx::Size(50, 10));
+ scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10));
+ scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+
+ scrollbar_layer->UpdateThumbAndTrackGeometry();
+ root_layer_impl = host->CommitAndCreateLayerImplTree();
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+ root_layer_impl->children()[1]);
+ EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
+ scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+ // Shrink the track in the non-scrolling dimension so that it only covers the
+ // middle third of the scrollbar layer (this does not affect the thumb
+ // position).
+ scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6));
+
+ scrollbar_layer->UpdateThumbAndTrackGeometry();
+ root_layer_impl = host->CommitAndCreateLayerImplTree();
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+ root_layer_impl->children()[1]);
+ EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
+ scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
}
TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
+ const int kThumbThickness = 3;
+ const int kTrackLength = 100;
+
LayerTreeSettings layer_tree_settings;
- layer_tree_settings.solid_color_scrollbars = true;
- layer_tree_settings.solid_color_scrollbar_thickness_dip = 3;
scoped_ptr<FakeLayerTreeHost> host =
FakeLayerTreeHost::Create(layer_tree_settings);
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
- LayerImpl* layer_impl_tree_root =
- LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
- ScrollbarLayerImpl* scrollbar_layer_impl =
- static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
- scrollbar_layer_impl->SetThumbThickness(3);
+ LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
+ host.get(), scrollbar.Pass(), false, true, kThumbThickness);
+ ScrollbarLayerImplBase* scrollbar_layer_impl =
+ static_cast<SolidColorScrollbarLayerImpl*>(
+ layer_impl_tree_root->children()[1]);
+ scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
scrollbar_layer_impl->SetCurrentPos(10.f);
scrollbar_layer_impl->SetMaximum(100);
- scrollbar_layer_impl->SetTrackLength(100);
scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.4f);
// Thickness should be overridden to 3.
@@ -217,20 +324,21 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
}
TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
+ const int kThumbThickness = 3;
+ const int kTrackLength = 10;
+
LayerTreeSettings layer_tree_settings;
- layer_tree_settings.solid_color_scrollbars = true;
- layer_tree_settings.solid_color_scrollbar_thickness_dip = 3;
scoped_ptr<FakeLayerTreeHost> host =
FakeLayerTreeHost::Create(layer_tree_settings);
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
- LayerImpl* layer_impl_tree_root =
- LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
- ScrollbarLayerImpl* scrollbar_layer_impl =
- static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+ LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
+ host.get(), scrollbar.Pass(), false, true, kThumbThickness);
+ ScrollbarLayerImplBase* scrollbar_layer_impl =
+ static_cast<PaintedScrollbarLayerImpl*>(
+ layer_impl_tree_root->children()[1]);
- scrollbar_layer_impl->SetThumbThickness(3);
- scrollbar_layer_impl->SetTrackLength(10);
+ scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
scrollbar_layer_impl->SetCurrentPos(4.f);
scrollbar_layer_impl->SetMaximum(8);
@@ -259,40 +367,43 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
layer_tree_settings.solid_color_scrollbars = true;
host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_));
- horizontal_scrollbar_layer_ = ScrollbarLayerImpl::Create(
- host_impl_->active_tree(), 1, HORIZONTAL);
- vertical_scrollbar_layer_ = ScrollbarLayerImpl::Create(
- host_impl_->active_tree(), 2, VERTICAL);
+ const int kThumbThickness = 3;
+ const bool kIsLeftSideVerticalScrollbar = false;
+
+ horizontal_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
+ host_impl_->active_tree(), 1, HORIZONTAL, kThumbThickness,
+ kIsLeftSideVerticalScrollbar);
+ vertical_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
+ host_impl_->active_tree(), 2, VERTICAL, kThumbThickness,
+ kIsLeftSideVerticalScrollbar);
}
protected:
FakeImplProxy proxy_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
- scoped_ptr<ScrollbarLayerImpl> horizontal_scrollbar_layer_;
- scoped_ptr<ScrollbarLayerImpl> vertical_scrollbar_layer_;
+ scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
+ scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
};
TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbLength) {
horizontal_scrollbar_layer_->SetCurrentPos(0);
horizontal_scrollbar_layer_->SetMaximum(10);
- horizontal_scrollbar_layer_->SetThumbThickness(3);
// Simple case - one third of the scrollable area is visible, so the thumb
// should be one third as long as the track.
horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.33f);
- horizontal_scrollbar_layer_->SetTrackLength(100);
+ horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
// The thumb's length should never be less than its thickness.
horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.01f);
- horizontal_scrollbar_layer_->SetTrackLength(100);
+ horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
EXPECT_EQ(3, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
}
TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) {
- horizontal_scrollbar_layer_->SetTrackLength(100);
+ horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.1f);
- horizontal_scrollbar_layer_->SetThumbThickness(3);
horizontal_scrollbar_layer_->SetCurrentPos(0);
horizontal_scrollbar_layer_->SetMaximum(100);
@@ -311,15 +422,15 @@ TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) {
}
TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
- ScrollbarLayerImpl* layers[2] =
+ SolidColorScrollbarLayerImpl* layers[2] =
{ horizontal_scrollbar_layer_.get(), vertical_scrollbar_layer_.get() };
for (size_t i = 0; i < 2; ++i) {
- layers[i]->SetTrackLength(100);
layers[i]->SetVisibleToTotalLengthRatio(0.2f);
- layers[i]->SetThumbThickness(3);
layers[i]->SetCurrentPos(25);
layers[i]->SetMaximum(100);
}
+ layers[0]->SetBounds(gfx::Size(100, 3));
+ layers[1]->SetBounds(gfx::Size(3, 100));
EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
horizontal_scrollbar_layer_->ComputeThumbQuadRect());
@@ -347,7 +458,7 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
virtual void BeginTest() OVERRIDE {
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
- scrollbar_layer_ = ScrollbarLayer::Create(scrollbar.Pass(), 1);
+ scrollbar_layer_ = PaintedScrollbarLayer::Create(scrollbar.Pass(), 1);
scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
scrollbar_layer_->SetBounds(bounds_);
layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
@@ -377,7 +488,7 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
virtual void AfterTest() OVERRIDE {}
private:
- scoped_refptr<ScrollbarLayer> scrollbar_layer_;
+ scoped_refptr<PaintedScrollbarLayer> scrollbar_layer_;
scoped_refptr<Layer> scroll_layer_;
gfx::Size bounds_;
};
@@ -404,9 +515,49 @@ class MockLayerTreeHost : public LayerTreeHost {
public:
MockLayerTreeHost(LayerTreeHostClient* client,
const LayerTreeSettings& settings)
- : LayerTreeHost(client, settings) {
+ : LayerTreeHost(client, settings),
+ next_id_(1),
+ total_ui_resource_created_(0),
+ total_ui_resource_deleted_(0) {
Initialize(NULL);
}
+
+ virtual UIResourceId CreateUIResource(UIResourceClient* content) OVERRIDE {
+ total_ui_resource_created_++;
+ UIResourceId nid = next_id_++;
+ ui_resource_bitmap_map_.insert(
+ std::make_pair(nid, content->GetBitmap(nid, false)));
+ return nid;
+ }
+
+ // Deletes a UI resource. May safely be called more than once.
+ virtual void DeleteUIResource(UIResourceId id) OVERRIDE {
+ UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+ if (iter != ui_resource_bitmap_map_.end()) {
+ ui_resource_bitmap_map_.erase(iter);
+ total_ui_resource_deleted_++;
+ }
+ }
+
+ size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
+ int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
+ int TotalUIResourceCreated() { return total_ui_resource_created_; }
+
+ gfx::Size ui_resource_size(UIResourceId id) {
+ UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+ if (iter != ui_resource_bitmap_map_.end())
+ return iter->second.GetSize();
+ return gfx::Size();
+ }
+
+ private:
+ typedef base::hash_map<UIResourceId, UIResourceBitmap>
+ UIResourceBitmapMap;
+ UIResourceBitmapMap ui_resource_bitmap_map_;
+
+ int next_id_;
+ int total_ui_resource_created_;
+ int total_ui_resource_deleted_;
};
@@ -415,21 +566,34 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
ScrollbarLayerTestResourceCreation()
: fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
- void TestResourceUpload(size_t expected_resources) {
+ void TestResourceUpload(int num_updates,
+ size_t expected_resources,
+ int expected_created,
+ int expected_deleted,
+ bool use_solid_color_scrollbar) {
layer_tree_host_.reset(
new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
- scoped_refptr<Layer> scrollbar_layer =
- ScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
+ scoped_refptr<Layer> scrollbar_layer;
+ if (use_solid_color_scrollbar) {
+ const int kThumbThickness = 3;
+ const bool kIsLeftSideVerticalScrollbar = false;
+ scrollbar_layer =
+ SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
+ kThumbThickness,
+ kIsLeftSideVerticalScrollbar,
+ layer_tree_root->id());
+ } else {
+ scrollbar_layer = PaintedScrollbarLayer::Create(scrollbar.Pass(),
+ layer_tree_root->id());
+ }
layer_tree_root->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
layer_tree_host_->InitializeOutputSurfaceIfNeeded();
- layer_tree_host_->contents_texture_manager()->
- SetMaxMemoryLimitBytes(1024 * 1024);
layer_tree_host_->SetRootLayer(layer_tree_root);
scrollbar_layer->SetIsDrawable(true);
@@ -447,16 +611,17 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
- PriorityCalculator calculator;
ResourceUpdateQueue queue;
OcclusionTracker occlusion_tracker(gfx::Rect(), false);
scrollbar_layer->SavePaintProperties();
- scrollbar_layer->SetTexturePriorities(calculator);
- layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
- scrollbar_layer->Update(&queue, &occlusion_tracker);
- EXPECT_EQ(0u, queue.FullUploadSize());
- EXPECT_EQ(expected_resources, queue.PartialUploadSize());
+ for (int update_counter = 0; update_counter < num_updates; update_counter++)
+ scrollbar_layer->Update(&queue, &occlusion_tracker);
+
+ // A non-solid-color scrollbar should have requested two textures.
+ EXPECT_EQ(expected_resources, layer_tree_host_->UIResourceCount());
+ EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+ EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
@@ -470,13 +635,22 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
};
TEST_F(ScrollbarLayerTestResourceCreation, ResourceUpload) {
- layer_tree_settings_.solid_color_scrollbars = false;
- TestResourceUpload(2);
+ bool use_solid_color_scrollbars = false;
+ TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
+ int num_updates[3] = {1, 5, 10};
+ for (int j = 0; j < 3; j++) {
+ TestResourceUpload(num_updates[j],
+ 2,
+ num_updates[j] * 2,
+ (num_updates[j] - 1) * 2,
+ use_solid_color_scrollbars);
+ }
}
TEST_F(ScrollbarLayerTestResourceCreation, SolidColorNoResourceUpload) {
- layer_tree_settings_.solid_color_scrollbars = true;
- TestResourceUpload(0);
+ bool use_solid_color_scrollbars = true;
+ TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
+ TestResourceUpload(1, 0, 0, 0, use_solid_color_scrollbars);
}
class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
@@ -484,25 +658,20 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
ScaledScrollbarLayerTestResourceCreation()
: fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
- void TestResourceUpload(size_t expected_resources, const float test_scale) {
+ void TestResourceUpload(const float test_scale) {
layer_tree_host_.reset(
new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
gfx::Point scrollbar_location(0, 185);
- scoped_ptr<FakeScrollbar> scrollbar(new FakeScrollbar(false, true, false));
- scrollbar->set_location(scrollbar_location);
-
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
- scoped_refptr<Layer> scrollbar_layer =
- ScrollbarLayer::Create(scrollbar.PassAs<cc::Scrollbar>(),
- layer_tree_root->id());
+ scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
+ FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
+
layer_tree_root->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
layer_tree_host_->InitializeOutputSurfaceIfNeeded();
- layer_tree_host_->contents_texture_manager()->
- SetMaxMemoryLimitBytes(1024 * 1024);
layer_tree_host_->SetRootLayer(layer_tree_root);
scrollbar_layer->SetIsDrawable(true);
@@ -529,30 +698,23 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
- PriorityCalculator calculator;
ResourceUpdateQueue queue;
OcclusionTracker occlusion_tracker(gfx::Rect(), false);
-
scrollbar_layer->SavePaintProperties();
- scrollbar_layer->SetTexturePriorities(calculator);
- layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
scrollbar_layer->Update(&queue, &occlusion_tracker);
- EXPECT_EQ(expected_resources, queue.PartialUploadSize());
// Verify that we have not generated any content uploads that are larger
// than their destination textures.
- while (queue.HasMoreUpdates()) {
- ResourceUpdate update = queue.TakeFirstPartialUpload();
- EXPECT_LE(update.texture->size().width(),
- scrollbar_layer->content_bounds().width());
- EXPECT_LE(update.texture->size().height(),
- scrollbar_layer->content_bounds().height());
-
- EXPECT_LE(update.dest_offset.x() + update.content_rect.width(),
- update.texture->size().width());
- EXPECT_LE(update.dest_offset.y() + update.content_rect.height(),
- update.texture->size().height());
- }
+
+ gfx::Size track_size = layer_tree_host_->ui_resource_size(
+ scrollbar_layer->track_resource_id());
+ gfx::Size thumb_size = layer_tree_host_->ui_resource_size(
+ scrollbar_layer->thumb_resource_id());
+
+ EXPECT_LE(track_size.width(), scrollbar_layer->content_bounds().width());
+ EXPECT_LE(track_size.height(), scrollbar_layer->content_bounds().height());
+ EXPECT_LE(thumb_size.width(), scrollbar_layer->content_bounds().width());
+ EXPECT_LE(thumb_size.height(), scrollbar_layer->content_bounds().height());
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
@@ -566,10 +728,11 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
};
TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
- layer_tree_settings_.solid_color_scrollbars = false;
// Pick a test scale that moves the scrollbar's (non-zero) position to
// a non-pixel-aligned location.
- TestResourceUpload(2, 1.41f);
+ TestResourceUpload(.041f);
+ TestResourceUpload(1.41f);
+ TestResourceUpload(4.1f);
}
} // namespace
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.cc b/chromium/cc/layers/solid_color_scrollbar_layer.cc
new file mode 100644
index 00000000000..d9ed922e5d8
--- /dev/null
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/solid_color_scrollbar_layer.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
+
+namespace cc {
+
+scoped_ptr<LayerImpl> SolidColorScrollbarLayer::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) {
+ return SolidColorScrollbarLayerImpl::Create(
+ tree_impl, id(), orientation(), thumb_thickness_,
+ is_left_side_vertical_scrollbar_).PassAs<LayerImpl>();
+}
+
+scoped_refptr<SolidColorScrollbarLayer> SolidColorScrollbarLayer::Create(
+ ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar,
+ int scroll_layer_id) {
+ return make_scoped_refptr(new SolidColorScrollbarLayer(
+ orientation,
+ thumb_thickness,
+ is_left_side_vertical_scrollbar,
+ scroll_layer_id));
+}
+
+SolidColorScrollbarLayer::SolidColorScrollbarLayer(
+ ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar,
+ int scroll_layer_id)
+ : scroll_layer_id_(scroll_layer_id),
+ orientation_(orientation),
+ thumb_thickness_(thumb_thickness),
+ is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar) {}
+
+SolidColorScrollbarLayer::~SolidColorScrollbarLayer() {}
+
+ScrollbarLayerInterface* SolidColorScrollbarLayer::ToScrollbarLayer() {
+ return this;
+}
+
+bool SolidColorScrollbarLayer::OpacityCanAnimateOnImplThread() const {
+ return true;
+}
+
+int SolidColorScrollbarLayer::ScrollLayerId() const {
+ return scroll_layer_id_;
+}
+
+void SolidColorScrollbarLayer::SetScrollLayerId(int id) {
+ if (id == scroll_layer_id_)
+ return;
+
+ scroll_layer_id_ = id;
+ SetNeedsFullTreeSync();
+}
+
+ScrollbarOrientation SolidColorScrollbarLayer::orientation() const {
+ return orientation_;
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.h b/chromium/cc/layers/solid_color_scrollbar_layer.h
new file mode 100644
index 00000000000..9c0dc1ed473
--- /dev/null
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.h
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_SOLID_COLOR_SCROLLBAR_LAYER_H_
+#define CC_LAYERS_SOLID_COLOR_SCROLLBAR_LAYER_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/scrollbar_layer_interface.h"
+
+namespace cc {
+
+class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
+ public Layer {
+ public:
+ virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+ OVERRIDE;
+
+ static scoped_refptr<SolidColorScrollbarLayer> Create(
+ ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar,
+ int scroll_layer_id);
+
+ // Layer overrides.
+ virtual bool OpacityCanAnimateOnImplThread() const OVERRIDE;
+ virtual ScrollbarLayerInterface* ToScrollbarLayer() OVERRIDE;
+
+ // ScrollbarLayerInterface
+ virtual int ScrollLayerId() const OVERRIDE;
+ virtual void SetScrollLayerId(int id) OVERRIDE;
+
+ virtual ScrollbarOrientation orientation() const OVERRIDE;
+
+ protected:
+ SolidColorScrollbarLayer(ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar,
+ int scroll_layer_id);
+ virtual ~SolidColorScrollbarLayer();
+
+ private:
+ int scroll_layer_id_;
+ ScrollbarOrientation orientation_;
+ int thumb_thickness_;
+ bool is_left_side_vertical_scrollbar_;
+
+ DISALLOW_COPY_AND_ASSIGN(SolidColorScrollbarLayer);
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_SOLID_COLOR_SCROLLBAR_LAYER_H_
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
new file mode 100644
index 00000000000..9f46a8080f5
--- /dev/null
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/quad_sink.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/layer_tree_settings.h"
+
+namespace cc {
+
+scoped_ptr<SolidColorScrollbarLayerImpl> SolidColorScrollbarLayerImpl::Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar) {
+ return make_scoped_ptr(new SolidColorScrollbarLayerImpl(
+ tree_impl, id, orientation, thumb_thickness,
+ is_left_side_vertical_scrollbar));
+}
+
+SolidColorScrollbarLayerImpl::~SolidColorScrollbarLayerImpl() {}
+
+scoped_ptr<LayerImpl> SolidColorScrollbarLayerImpl::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) {
+ return SolidColorScrollbarLayerImpl::Create(
+ tree_impl, id(), orientation(), thumb_thickness_,
+ is_left_side_vertical_scrollbar()).PassAs<LayerImpl>();
+}
+
+SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar)
+ : ScrollbarLayerImplBase(tree_impl, id, orientation,
+ is_left_side_vertical_scrollbar),
+ thumb_thickness_(thumb_thickness),
+ color_(tree_impl->settings().solid_color_scrollbar_color) {}
+
+void SolidColorScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
+ ScrollbarLayerImplBase::PushPropertiesTo(layer);
+}
+
+int SolidColorScrollbarLayerImpl::ThumbThickness() const {
+ if (thumb_thickness_ != -1)
+ return thumb_thickness_;
+
+ if (orientation() == HORIZONTAL)
+ return bounds().height();
+ else
+ return bounds().width();
+}
+
+int SolidColorScrollbarLayerImpl::ThumbLength() const {
+ return std::max(
+ static_cast<int>(visible_to_total_length_ratio() * TrackLength()),
+ ThumbThickness());
+}
+
+float SolidColorScrollbarLayerImpl::TrackLength() const {
+ if (orientation() == HORIZONTAL)
+ return bounds().width();
+ else
+ return bounds().height() + vertical_adjust();
+}
+
+int SolidColorScrollbarLayerImpl::TrackStart() const {
+ return 0;
+}
+
+void SolidColorScrollbarLayerImpl::AppendQuads(QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) {
+ gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
+
+ SharedQuadState* shared_quad_state =
+ quad_sink->UseSharedQuadState(CreateSharedQuadState());
+ AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+
+ scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
+ quad->SetNew(shared_quad_state, thumb_quad_rect, color_, false);
+ quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
new file mode 100644
index 00000000000..56cbacd888c
--- /dev/null
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_SOLID_COLOR_SCROLLBAR_LAYER_IMPL_H_
+#define CC_LAYERS_SOLID_COLOR_SCROLLBAR_LAYER_IMPL_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/layers/scrollbar_layer_impl_base.h"
+
+namespace cc {
+
+class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase {
+ public:
+ static scoped_ptr<SolidColorScrollbarLayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar);
+ virtual ~SolidColorScrollbarLayerImpl();
+
+ // LayerImpl overrides.
+ virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+ OVERRIDE;
+ virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+
+ virtual void AppendQuads(QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) OVERRIDE;
+
+
+ protected:
+ SolidColorScrollbarLayerImpl(LayerTreeImpl* tree_impl,
+ int id,
+ ScrollbarOrientation orientation,
+ int thumb_thickness,
+ bool is_left_side_vertical_scrollbar);
+
+ // ScrollbarLayerImplBase implementation.
+ virtual int ThumbThickness() const OVERRIDE;
+ virtual int ThumbLength() const OVERRIDE;
+ virtual float TrackLength() const OVERRIDE;
+ virtual int TrackStart() const OVERRIDE;
+
+ private:
+ int thumb_thickness_;
+ SkColor color_;
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_SOLID_COLOR_SCROLLBAR_LAYER_IMPL_H_
diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc
index 11009fa1b68..a845709448f 100644
--- a/chromium/cc/layers/texture_layer.cc
+++ b/chromium/cc/layers/texture_layer.cc
@@ -5,10 +5,13 @@
#include "cc/layers/texture_layer.h"
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/synchronization/lock.h"
#include "cc/layers/texture_layer_client.h"
#include "cc/layers/texture_layer_impl.h"
+#include "cc/resources/single_release_callback.h"
+#include "cc/trees/blocking_task_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
@@ -51,7 +54,7 @@ void TextureLayer::ClearClient() {
layer_tree_host()->StopRateLimiter(client_->Context3d());
client_ = NULL;
if (uses_mailbox_)
- SetTextureMailbox(TextureMailbox());
+ SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
else
SetTextureId(0);
}
@@ -125,23 +128,34 @@ void TextureLayer::SetTextureId(unsigned id) {
layer_tree_host()->AcquireLayerTextures();
texture_id_ = id;
SetNeedsCommit();
+ // The texture id needs to be removed from the active tree before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
-void TextureLayer::SetTextureMailbox(const TextureMailbox& mailbox) {
+void TextureLayer::SetTextureMailbox(
+ const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback) {
DCHECK(uses_mailbox_);
DCHECK(!mailbox.IsValid() || !holder_ref_ ||
!mailbox.Equals(holder_ref_->holder()->mailbox()));
+ DCHECK_EQ(mailbox.IsValid(), !!release_callback);
+
// If we never commited the mailbox, we need to release it here.
if (mailbox.IsValid())
- holder_ref_ = MailboxHolder::Create(mailbox);
+ holder_ref_ = MailboxHolder::Create(mailbox, release_callback.Pass());
else
holder_ref_.reset();
needs_set_mailbox_ = true;
SetNeedsCommit();
+ // The active frame needs to be replaced and the mailbox returned before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
void TextureLayer::WillModifyTexture() {
- if (layer_tree_host() && (DrawsContent() || content_committed_)) {
+ if (!uses_mailbox_ && layer_tree_host() && (DrawsContent() ||
+ content_committed_)) {
layer_tree_host()->AcquireLayerTextures();
content_committed_ = false;
}
@@ -161,16 +175,24 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
}
if (layer_tree_host()) {
- if (texture_id_)
+ if (texture_id_) {
layer_tree_host()->AcquireLayerTextures();
+ // The texture id needs to be removed from the active tree before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
+ }
if (rate_limit_context_ && client_)
layer_tree_host()->StopRateLimiter(client_->Context3d());
}
// If we're removed from the tree, the TextureLayerImpl will be destroyed, and
// we will need to set the mailbox again on a new TextureLayerImpl the next
// time we push.
- if (!host && uses_mailbox_ && holder_ref_)
+ if (!host && uses_mailbox_ && holder_ref_) {
needs_set_mailbox_ = true;
+ // The active frame needs to be replaced and the mailbox returned before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
+ }
Layer::SetLayerTreeHost(host);
}
@@ -184,19 +206,25 @@ bool TextureLayer::Update(ResourceUpdateQueue* queue,
if (client_) {
if (uses_mailbox_) {
TextureMailbox mailbox;
+ scoped_ptr<SingleReleaseCallback> release_callback;
if (client_->PrepareTextureMailbox(
- &mailbox, layer_tree_host()->UsingSharedMemoryResources())) {
- SetTextureMailbox(mailbox);
+ &mailbox,
+ &release_callback,
+ layer_tree_host()->UsingSharedMemoryResources())) {
+ SetTextureMailbox(mailbox, release_callback.Pass());
updated = true;
}
} else {
- DCHECK(client_->Context3d());
texture_id_ = client_->PrepareTexture();
+ DCHECK_EQ(!!texture_id_, !!client_->Context3d());
if (client_->Context3d() &&
client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR)
texture_id_ = 0;
updated = true;
SetNeedsPushProperties();
+ // The texture id needs to be removed from the active tree before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
}
@@ -218,18 +246,18 @@ void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
texture_layer->set_blend_background_color(blend_background_color_);
if (uses_mailbox_ && needs_set_mailbox_) {
TextureMailbox texture_mailbox;
+ scoped_ptr<SingleReleaseCallback> release_callback;
if (holder_ref_) {
MailboxHolder* holder = holder_ref_->holder();
- TextureMailbox::ReleaseCallback callback =
- holder->GetCallbackForImplThread();
- texture_mailbox = holder->mailbox().CopyWithNewCallback(callback);
+ texture_mailbox = holder->mailbox();
+ release_callback = holder->GetCallbackForImplThread();
}
- texture_layer->SetTextureMailbox(texture_mailbox);
+ texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
needs_set_mailbox_ = false;
} else {
texture_layer->set_texture_id(texture_id_);
+ content_committed_ = DrawsContent();
}
- content_committed_ = DrawsContent();
}
Region TextureLayer::VisibleContentOpaqueRegion() const {
@@ -242,13 +270,6 @@ Region TextureLayer::VisibleContentOpaqueRegion() const {
return Region();
}
-bool TextureLayer::BlocksPendingCommit() const {
- // Double-buffered texture layers need to be blocked until they can be made
- // triple-buffered. Single-buffered layers already prevent draws, so
- // can block too for simplicity.
- return DrawsContent();
-}
-
bool TextureLayer::CanClipSelf() const {
return true;
}
@@ -263,10 +284,13 @@ TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() {
holder_->InternalRelease();
}
-TextureLayer::MailboxHolder::MailboxHolder(const TextureMailbox& mailbox)
- : message_loop_(base::MessageLoopProxy::current()),
+TextureLayer::MailboxHolder::MailboxHolder(
+ const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback)
+ : message_loop_(BlockingTaskRunner::current()),
internal_references_(0),
mailbox_(mailbox),
+ release_callback_(release_callback.Pass()),
sync_point_(mailbox.sync_point()),
is_lost_(false) {
}
@@ -276,23 +300,27 @@ TextureLayer::MailboxHolder::~MailboxHolder() {
}
scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference>
-TextureLayer::MailboxHolder::Create(const TextureMailbox& mailbox) {
+TextureLayer::MailboxHolder::Create(
+ const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback) {
return scoped_ptr<MainThreadReference>(new MainThreadReference(
- new MailboxHolder(mailbox)));
+ new MailboxHolder(mailbox, release_callback.Pass())));
}
void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) {
+ base::AutoLock lock(arguments_lock_);
sync_point_ = sync_point;
is_lost_ = is_lost;
}
-TextureMailbox::ReleaseCallback
+scoped_ptr<SingleReleaseCallback>
TextureLayer::MailboxHolder::GetCallbackForImplThread() {
// We can't call GetCallbackForImplThread if we released the main thread
// reference.
DCHECK_GT(internal_references_, 0u);
InternalAddRef();
- return base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this);
+ return SingleReleaseCallback::Create(
+ base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this));
}
void TextureLayer::MailboxHolder::InternalAddRef() {
@@ -302,23 +330,17 @@ void TextureLayer::MailboxHolder::InternalAddRef() {
void TextureLayer::MailboxHolder::InternalRelease() {
DCHECK(message_loop_->BelongsToCurrentThread());
if (!--internal_references_) {
- mailbox_.RunReleaseCallback(sync_point_, is_lost_);
+ release_callback_->Run(sync_point_, is_lost_);
mailbox_ = TextureMailbox();
+ release_callback_.reset();
}
}
-void TextureLayer::MailboxHolder::ReturnAndReleaseOnMainThread(
- unsigned sync_point, bool is_lost) {
- DCHECK(message_loop_->BelongsToCurrentThread());
- Return(sync_point, is_lost);
- InternalRelease();
-}
-
void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread(
unsigned sync_point, bool is_lost) {
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &MailboxHolder::ReturnAndReleaseOnMainThread,
- this, sync_point, is_lost));
+ Return(sync_point, is_lost);
+ message_loop_->PostTask(FROM_HERE,
+ base::Bind(&MailboxHolder::InternalRelease, this));
}
} // namespace cc
diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h
index 9e63b6825eb..5fb214c2c13 100644
--- a/chromium/cc/layers/texture_layer.h
+++ b/chromium/cc/layers/texture_layer.h
@@ -8,23 +8,80 @@
#include <string>
#include "base/callback.h"
+#include "base/synchronization/lock.h"
#include "cc/base/cc_export.h"
#include "cc/layers/layer.h"
#include "cc/resources/texture_mailbox.h"
namespace WebKit { class WebGraphicsContext3D; }
-namespace base {
-class MessageLoopProxy;
-}
-
namespace cc {
-
+class BlockingTaskRunner;
+class SingleReleaseCallback;
class TextureLayerClient;
// A Layer containing a the rendered output of a plugin instance.
class CC_EXPORT TextureLayer : public Layer {
public:
+ class CC_EXPORT MailboxHolder
+ : public base::RefCountedThreadSafe<MailboxHolder> {
+ public:
+ class CC_EXPORT MainThreadReference {
+ public:
+ explicit MainThreadReference(MailboxHolder* holder);
+ ~MainThreadReference();
+ MailboxHolder* holder() { return holder_.get(); }
+
+ private:
+ scoped_refptr<MailboxHolder> holder_;
+ DISALLOW_COPY_AND_ASSIGN(MainThreadReference);
+ };
+
+ const TextureMailbox& mailbox() const { return mailbox_; }
+ void Return(unsigned sync_point, bool is_lost);
+
+ // Gets a ReleaseCallback that can be called from another thread. Note: the
+ // caller must ensure the callback is called.
+ scoped_ptr<SingleReleaseCallback> GetCallbackForImplThread();
+
+ protected:
+ friend class TextureLayer;
+
+ // Protected visiblity so only TextureLayer and unit tests can create these.
+ static scoped_ptr<MainThreadReference> Create(
+ const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback);
+ virtual ~MailboxHolder();
+
+ private:
+ friend class base::RefCountedThreadSafe<MailboxHolder>;
+ friend class MainThreadReference;
+ explicit MailboxHolder(const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback);
+
+ void InternalAddRef();
+ void InternalRelease();
+ void ReturnAndReleaseOnImplThread(unsigned sync_point, bool is_lost);
+
+ // This member is thread safe, and is accessed on main and impl threads.
+ const scoped_refptr<BlockingTaskRunner> message_loop_;
+
+ // These members are only accessed on the main thread, or on the impl thread
+ // during commit where the main thread is blocked.
+ unsigned internal_references_;
+ TextureMailbox mailbox_;
+ scoped_ptr<SingleReleaseCallback> release_callback_;
+
+ // This lock guards the sync_point_ and is_lost_ fields because they can be
+ // accessed on both the impl and main thread. We do this to ensure that the
+ // values of these fields are well-ordered such that the last call to
+ // ReturnAndReleaseOnImplThread() defines their values.
+ base::Lock arguments_lock_;
+ unsigned sync_point_;
+ bool is_lost_;
+ DISALLOW_COPY_AND_ASSIGN(MailboxHolder);
+ };
+
// If this texture layer requires special preparation logic for each frame
// driven by the compositor, pass in a non-nil client. Pass in a nil client
// pointer if texture updates are driven by an external process.
@@ -67,11 +124,13 @@ class CC_EXPORT TextureLayer : public Layer {
void SetRateLimitContext(bool rate_limit);
// Code path for plugins which supply their own texture ID.
+ // DEPRECATED. DO NOT USE.
void SetTextureId(unsigned texture_id);
// Code path for plugins which supply their own mailbox.
bool uses_mailbox() const { return uses_mailbox_; }
- void SetTextureMailbox(const TextureMailbox& mailbox);
+ void SetTextureMailbox(const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback);
void WillModifyTexture();
@@ -83,7 +142,6 @@ class CC_EXPORT TextureLayer : public Layer {
const OcclusionTracker* occlusion) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual Region VisibleContentOpaqueRegion() const OVERRIDE;
- virtual bool BlocksPendingCommit() const OVERRIDE;
virtual bool CanClipSelf() const OVERRIDE;
@@ -92,50 +150,6 @@ class CC_EXPORT TextureLayer : public Layer {
virtual ~TextureLayer();
private:
- class MailboxHolder : public base::RefCountedThreadSafe<MailboxHolder> {
- public:
- class MainThreadReference {
- public:
- explicit MainThreadReference(MailboxHolder* holder);
- ~MainThreadReference();
- MailboxHolder* holder() { return holder_.get(); }
-
- private:
- scoped_refptr<MailboxHolder> holder_;
- DISALLOW_COPY_AND_ASSIGN(MainThreadReference);
- };
-
- static scoped_ptr<MainThreadReference> Create(
- const TextureMailbox& mailbox);
-
- const TextureMailbox& mailbox() const { return mailbox_; }
- void Return(unsigned sync_point, bool is_lost);
-
- // Gets a ReleaseCallback that can be called from another thread. Note: the
- // caller must ensure the callback is called.
- TextureMailbox::ReleaseCallback GetCallbackForImplThread();
-
- private:
- friend class base::RefCountedThreadSafe<MailboxHolder>;
- friend class MainThreadReference;
- explicit MailboxHolder(const TextureMailbox& mailbox);
- ~MailboxHolder();
- void InternalAddRef();
- void InternalRelease();
- void ReturnAndReleaseOnMainThread(unsigned sync_point, bool is_lost);
- void ReturnAndReleaseOnImplThread(unsigned sync_point, bool is_lost);
-
- // Thread safety notes: except for the thread-safe message_loop_, all fields
- // are only used on the main thread, or on the impl thread during commit
- // where the main thread is blocked.
- const scoped_refptr<base::MessageLoopProxy> message_loop_;
- unsigned internal_references_;
- TextureMailbox mailbox_;
- unsigned sync_point_;
- bool is_lost_;
- DISALLOW_COPY_AND_ASSIGN(MailboxHolder);
- };
-
TextureLayerClient* client_;
bool uses_mailbox_;
diff --git a/chromium/cc/layers/texture_layer_client.h b/chromium/cc/layers/texture_layer_client.h
index 73d34b30775..187b12f16c4 100644
--- a/chromium/cc/layers/texture_layer_client.h
+++ b/chromium/cc/layers/texture_layer_client.h
@@ -5,6 +5,8 @@
#ifndef CC_LAYERS_TEXTURE_LAYER_CLIENT_H_
#define CC_LAYERS_TEXTURE_LAYER_CLIENT_H_
+#include "cc/resources/single_release_callback.h"
+
namespace WebKit { class WebGraphicsContext3D; }
namespace cc {
@@ -24,8 +26,10 @@ class TextureLayerClient {
// Returns true and provides a mailbox if a new frame is available.
// Returns false if no new data is available
// and the old mailbox is to be reused.
- virtual bool PrepareTextureMailbox(TextureMailbox* mailbox,
- bool use_shared_memory) = 0;
+ virtual bool PrepareTextureMailbox(
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) = 0;
protected:
virtual ~TextureLayerClient() {}
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index 851bf9a145b..e16fd3c3f18 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -4,12 +4,15 @@
#include "cc/layers/texture_layer_impl.h"
+#include <vector>
+
#include "base/strings/stringprintf.h"
#include "cc/layers/quad_sink.h"
#include "cc/output/renderer.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/platform_color.h"
#include "cc/resources/scoped_resource.h"
+#include "cc/resources/single_release_callback.h"
#include "cc/trees/layer_tree_impl.h"
namespace cc {
@@ -36,10 +39,14 @@ TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* tree_impl,
TextureLayerImpl::~TextureLayerImpl() { FreeTextureMailbox(); }
-void TextureLayerImpl::SetTextureMailbox(const TextureMailbox& mailbox) {
+void TextureLayerImpl::SetTextureMailbox(
+ const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback) {
DCHECK(uses_mailbox_);
+ DCHECK_EQ(mailbox.IsValid(), !!release_callback);
FreeTextureMailbox();
texture_mailbox_ = mailbox;
+ release_callback_ = release_callback.Pass();
own_mailbox_ = true;
valid_texture_copy_ = false;
}
@@ -60,7 +67,8 @@ void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
texture_layer->set_vertex_opacity(vertex_opacity_);
texture_layer->set_premultiplied_alpha(premultiplied_alpha_);
if (uses_mailbox_ && own_mailbox_) {
- texture_layer->SetTextureMailbox(texture_mailbox_);
+ texture_layer->SetTextureMailbox(texture_mailbox_,
+ release_callback_.Pass());
own_mailbox_ = false;
} else {
texture_layer->set_texture_id(texture_id_);
@@ -80,7 +88,8 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
texture_mailbox_.IsSharedMemory())) {
external_texture_resource_ =
resource_provider->CreateResourceFromTextureMailbox(
- texture_mailbox_);
+ texture_mailbox_,
+ release_callback_.Pass());
DCHECK(external_texture_resource_);
texture_copy_.reset();
valid_texture_copy_ = false;
@@ -102,8 +111,8 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
if (!texture_copy_->id()) {
texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
- resource_provider->best_texture_format(),
- ResourceProvider::TextureUsageAny);
+ ResourceProvider::TextureUsageAny,
+ resource_provider->best_texture_format());
}
if (texture_copy_->id()) {
@@ -229,7 +238,10 @@ void TextureLayerImpl::FreeTextureMailbox() {
return;
if (own_mailbox_) {
DCHECK(!external_texture_resource_);
- texture_mailbox_.RunReleaseCallback(texture_mailbox_.sync_point(), false);
+ if (release_callback_)
+ release_callback_->Run(texture_mailbox_.sync_point(), false);
+ texture_mailbox_ = TextureMailbox();
+ release_callback_.reset();
} else if (external_texture_resource_) {
DCHECK(!own_mailbox_);
ResourceProvider* resource_provider =
diff --git a/chromium/cc/layers/texture_layer_impl.h b/chromium/cc/layers/texture_layer_impl.h
index f85720688a6..90c26923c8e 100644
--- a/chromium/cc/layers/texture_layer_impl.h
+++ b/chromium/cc/layers/texture_layer_impl.h
@@ -12,6 +12,7 @@
#include "cc/layers/layer_impl.h"
namespace cc {
+class SingleReleaseCallback;
class ScopedResource;
class CC_EXPORT TextureLayerImpl : public LayerImpl {
@@ -61,7 +62,8 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
virtual bool CanClipSelf() const OVERRIDE;
- void SetTextureMailbox(const TextureMailbox& mailbox);
+ void SetTextureMailbox(const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback);
private:
TextureLayerImpl(LayerTreeImpl* tree_impl, int id, bool uses_mailbox);
@@ -81,6 +83,7 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
scoped_ptr<ScopedResource> texture_copy_;
TextureMailbox texture_mailbox_;
+ scoped_ptr<SingleReleaseCallback> release_callback_;
bool uses_mailbox_;
bool own_mailbox_;
bool valid_texture_copy_;
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index aa08e9f81ee..239c5b8fa22 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -4,16 +4,28 @@
#include "cc/layers/texture_layer.h"
+#include <algorithm>
#include <string>
+#include "base/bind.h"
#include "base/callback.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
+#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer_client.h"
#include "cc/layers/texture_layer_impl.h"
+#include "cc/output/compositor_frame_ack.h"
+#include "cc/output/context_provider.h"
+#include "cc/resources/returned_resource.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/trees/blocking_task_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
@@ -187,7 +199,7 @@ TEST_F(TextureLayerTest, SyncImplWhenRemovingFromTree) {
TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
- layer_tree_host_->SetRootLayer(test_layer);
+ EXPECT_SET_NEEDS_COMMIT(1, layer_tree_host_->SetRootLayer(test_layer));
// Test properties that should call SetNeedsCommit. All properties need to
// be set to new values in order for SetNeedsCommit to be called.
@@ -243,9 +255,12 @@ class FakeTextureLayerClient : public TextureLayerClient {
return context_.get();
}
- virtual bool PrepareTextureMailbox(TextureMailbox* mailbox,
- bool use_shared_memory) OVERRIDE {
+ virtual bool PrepareTextureMailbox(
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
*mailbox = TextureMailbox();
+ *release_callback = scoped_ptr<SingleReleaseCallback>();
return true;
}
@@ -328,25 +343,25 @@ struct CommonMailboxObjects {
mailbox_name2_);
gpu::Mailbox m1;
m1.SetName(reinterpret_cast<const int8*>(mailbox_name1_.data()));
- mailbox1_ = TextureMailbox(m1, release_mailbox1_, sync_point1_);
+ mailbox1_ = TextureMailbox(m1, sync_point1_);
gpu::Mailbox m2;
m2.SetName(reinterpret_cast<const int8*>(mailbox_name2_.data()));
- mailbox2_ = TextureMailbox(m2, release_mailbox2_, sync_point2_);
+ mailbox2_ = TextureMailbox(m2, sync_point2_);
gfx::Size size(128, 128);
EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea()));
release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2,
base::Unretained(&mock_callback_),
shared_memory_.get());
- mailbox3_ = TextureMailbox(shared_memory_.get(), size, release_mailbox3_);
+ mailbox3_ = TextureMailbox(shared_memory_.get(), size);
}
std::string mailbox_name1_;
std::string mailbox_name2_;
MockMailboxCallback mock_callback_;
- TextureMailbox::ReleaseCallback release_mailbox1_;
- TextureMailbox::ReleaseCallback release_mailbox2_;
- TextureMailbox::ReleaseCallback release_mailbox3_;
+ ReleaseCallback release_mailbox1_;
+ ReleaseCallback release_mailbox2_;
+ ReleaseCallback release_mailbox3_;
TextureMailbox mailbox1_;
TextureMailbox mailbox2_;
TextureMailbox mailbox3_;
@@ -355,6 +370,14 @@ struct CommonMailboxObjects {
scoped_ptr<base::SharedMemory> shared_memory_;
};
+class TestMailboxHolder : public TextureLayer::MailboxHolder {
+ public:
+ using TextureLayer::MailboxHolder::Create;
+
+ protected:
+ virtual ~TestMailboxHolder() {}
+};
+
class TextureLayerWithMailboxTest : public TextureLayerTest {
protected:
virtual void TearDown() {
@@ -380,7 +403,9 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureMailbox(test_data_.mailbox1_);
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
@@ -390,7 +415,9 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
test_data_.sync_point1_,
false))
.Times(1);
- test_layer->SetTextureMailbox(test_data_.mailbox2_);
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox2_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox2_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -401,11 +428,16 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
test_data_.sync_point2_,
false))
.Times(1);
- test_layer->SetTextureMailbox(TextureMailbox());
+ test_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
- test_layer->SetTextureMailbox(test_data_.mailbox3_);
+ EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox3_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox3_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -415,13 +447,309 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
Release2(test_data_.shared_memory_.get(),
0, false))
.Times(1);
- test_layer->SetTextureMailbox(TextureMailbox());
+ test_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
// Test destructor.
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureMailbox(test_data_.mailbox1_);
+ test_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
+}
+
+class TextureLayerMailboxHolderTest : public TextureLayerTest {
+ public:
+ TextureLayerMailboxHolderTest()
+ : main_thread_("MAIN") {
+ main_thread_.Start();
+ }
+
+ void Wait(const base::Thread& thread) {
+ bool manual_reset = false;
+ bool initially_signaled = false;
+ base::WaitableEvent event(manual_reset, initially_signaled);
+ thread.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
+ event.Wait();
+ }
+
+ void CreateMainRef() {
+ main_ref_ = TestMailboxHolder::Create(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_)).Pass();
+ }
+
+ void ReleaseMainRef() {
+ main_ref_.reset();
+ }
+
+ void CreateImplRef(scoped_ptr<SingleReleaseCallback>* impl_ref) {
+ *impl_ref = main_ref_->holder()->GetCallbackForImplThread();
+ }
+
+ void CapturePostTasksAndWait(base::WaitableEvent* begin_capture,
+ base::WaitableEvent* wait_for_capture,
+ base::WaitableEvent* stop_capture) {
+ begin_capture->Wait();
+ BlockingTaskRunner::CapturePostTasks capture;
+ wait_for_capture->Signal();
+ stop_capture->Wait();
+ }
+
+ protected:
+ scoped_ptr<TestMailboxHolder::MainThreadReference>
+ main_ref_;
+ base::Thread main_thread_;
+ CommonMailboxObjects test_data_;
+};
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_BothReleaseThenMain) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The compositors both destroy their impl trees before the main thread layer
+ // is destroyed.
+ compositor1->Run(100, false);
+ compositor2->Run(200, false);
+
+ Wait(main_thread_);
+
+ EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The main thread ref is the last one, so the mailbox is released back to the
+ // embedder, with the last sync point provided by the impl trees.
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 200, false)).Times(1);
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+}
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleaseBetween) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // One compositor destroys their impl tree.
+ compositor1->Run(100, false);
+
+ // Then the main thread reference is destroyed.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The second impl reference is destroyed last, causing the mailbox to be
+ // released back to the embedder with the last sync point from the impl tree.
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 200, true)).Times(1);
+
+ compositor2->Run(200, true);
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+}
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleasedFirst) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The main thread reference is destroyed first.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+
+ // One compositor destroys their impl tree.
+ compositor2->Run(200, false);
+
+ Wait(main_thread_);
+
+ EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The second impl reference is destroyed last, causing the mailbox to be
+ // released back to the embedder with the last sync point from the impl tree.
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 100, true)).Times(1);
+
+ compositor1->Run(100, true);
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+}
+
+TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_SecondImplRefShortcut) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
+
+ Wait(main_thread_);
+
+ // The texture layer is attached to compositor1, and passes a reference to its
+ // impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor1;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor1));
+
+ // Then the texture layer is removed and attached to compositor2, and passes a
+ // reference to its impl tree.
+ scoped_ptr<SingleReleaseCallback> compositor2;
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this),
+ &compositor2));
+
+ Wait(main_thread_);
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
+
+ // The main thread reference is destroyed first.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
+
+ EXPECT_CALL(test_data_.mock_callback_,
+ Release(test_data_.mailbox_name1_, 200, true)).Times(1);
+
+ bool manual_reset = false;
+ bool initially_signaled = false;
+ base::WaitableEvent begin_capture(manual_reset, initially_signaled);
+ base::WaitableEvent wait_for_capture(manual_reset, initially_signaled);
+ base::WaitableEvent stop_capture(manual_reset, initially_signaled);
+
+ // Post a task to start capturing tasks on the main thread. This will block
+ // the main thread until we signal the |stop_capture| event.
+ main_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxHolderTest::CapturePostTasksAndWait,
+ base::Unretained(this),
+ &begin_capture,
+ &wait_for_capture,
+ &stop_capture));
+
+ // Before the main thread capturing starts, one compositor destroys their
+ // impl reference. Since capturing did not start, this gets post-tasked to
+ // the main thread.
+ compositor1->Run(100, false);
+
+ // Start capturing on the main thread.
+ begin_capture.Signal();
+ wait_for_capture.Wait();
+
+ // Meanwhile, the second compositor released its impl reference, but this task
+ // gets shortcutted directly to the main thread. This means the reference is
+ // released before compositor1, whose reference will be released later when
+ // the post-task is serviced. But since it was destroyed _on the impl thread_
+ // last, its sync point values should be used.
+ compositor2->Run(200, true);
+
+ stop_capture.Signal();
+ Wait(main_thread_);
+
+ Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
}
class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
@@ -432,21 +760,24 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
// Make sure callback is received on main and doesn't block the impl thread.
void ReleaseCallback(unsigned sync_point, bool lost_resource) {
- EXPECT_EQ(true, proxy()->IsMainThread());
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
}
void SetMailbox(char mailbox_char) {
- TextureMailbox mailbox(
- std::string(64, mailbox_char),
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox);
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
}
virtual void BeginTest() OVERRIDE {
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+
gfx::Size bounds(100, 100);
root_ = Layer::Create();
root_->SetAnchorPoint(gfx::PointF());
@@ -481,61 +812,58 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
EXPECT_EQ(1, callback_count_);
break;
case 2:
- // Old mailbox was released, task was posted, but won't execute
- // until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(1, callback_count_);
- layer_tree_host()->SetNeedsCommit();
- break;
- case 3:
EXPECT_EQ(2, callback_count_);
// Case #3: change mailbox when the layer doesn't draw. The old
// mailbox should be released during the next commit.
layer_->SetBounds(gfx::Size());
SetMailbox('4');
break;
- case 4:
- // Old mailbox was released, task was posted, but won't execute
- // until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(2, callback_count_);
- layer_tree_host()->SetNeedsCommit();
- break;
- case 5:
+ case 3:
EXPECT_EQ(3, callback_count_);
// Case #4: release mailbox that was committed but never drawn. The
// old mailbox should be released during the next commit.
- layer_->SetTextureMailbox(TextureMailbox());
- break;
- case 6:
- // Old mailbox was released, task was posted, but won't execute
- // until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(3, callback_count_);
- layer_tree_host()->SetNeedsCommit();
+ layer_->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
break;
- case 7:
+ case 4:
+ if (layer_tree_host()->settings().impl_side_painting) {
+ // With impl painting, the texture mailbox will still be on the impl
+ // thread when the commit finishes, because the layer is not drawble
+ // when it has no texture mailbox, and thus does not block the commit
+ // on activation. So, we wait for activation.
+ // TODO(danakj): fix this. crbug.com/277953
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ } else {
+ ++commit_count_;
+ }
+ case 5:
EXPECT_EQ(4, callback_count_);
// Restore a mailbox for the next step.
SetMailbox('5');
break;
- case 8:
+ case 6:
// Case #5: remove layer from tree. Callback should *not* be called, the
// mailbox is returned to the main thread.
EXPECT_EQ(4, callback_count_);
layer_->RemoveFromParent();
break;
- case 9:
- // Mailbox was released to the main thread, task was posted, but won't
- // execute until this DidCommit returns.
- // TODO(piman): fix this.
- EXPECT_EQ(4, callback_count_);
- layer_tree_host()->SetNeedsCommit();
- break;
- case 10:
+ case 7:
+ if (layer_tree_host()->settings().impl_side_painting) {
+ // With impl painting, the texture mailbox will still be on the impl
+ // thread when the commit finishes, because the layer is not around to
+ // block the commit on activation anymore. So, we wait for activation.
+ // TODO(danakj): fix this. crbug.com/277953
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ } else {
+ ++commit_count_;
+ }
+ case 8:
EXPECT_EQ(4, callback_count_);
// Resetting the mailbox will call the callback now.
- layer_->SetTextureMailbox(TextureMailbox());
+ layer_->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
EXPECT_EQ(5, callback_count_);
EndTest();
break;
@@ -548,6 +876,7 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
virtual void AfterTest() OVERRIDE {}
private:
+ base::ThreadChecker main_thread_;
int callback_count_;
int commit_count_;
scoped_refptr<Layer> root_;
@@ -557,6 +886,247 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
TextureLayerImplWithMailboxThreadedCallback);
+
+class TextureLayerNoMailboxIsActivatedDuringCommit : public LayerTreeTest,
+ public TextureLayerClient {
+ protected:
+ TextureLayerNoMailboxIsActivatedDuringCommit()
+ : wait_thread_("WAIT"),
+ wait_event_(false, false) {
+ wait_thread_.Start();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ activate_count_ = 0;
+
+ gfx::Size bounds(100, 100);
+ root_ = Layer::Create();
+ root_->SetAnchorPoint(gfx::PointF());
+ root_->SetBounds(bounds);
+
+ layer_ = TextureLayer::Create(this);
+ layer_->SetIsDrawable(true);
+ layer_->SetAnchorPoint(gfx::PointF());
+ layer_->SetBounds(bounds);
+
+ root_->AddChild(layer_);
+ layer_tree_host()->SetRootLayer(root_);
+ layer_tree_host()->SetViewportSize(bounds);
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ // TextureLayerClient implementation.
+ virtual unsigned PrepareTexture() OVERRIDE {
+ return OffscreenContextProviderForMainThread()
+ ->Context3d()->createTexture();
+ }
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return OffscreenContextProviderForMainThread()->Context3d();
+ }
+ virtual bool PrepareTextureMailbox(
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
+ return false;
+ }
+
+ virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // Slow down activation so the main thread DidCommit() will run if
+ // not blocked.
+ wait_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_event_)),
+ base::TimeDelta::FromMilliseconds(10));
+ wait_event_.Wait();
+
+ base::AutoLock lock(activate_lock_);
+ ++activate_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // The main thread is awake now, and will run DidCommit() immediately.
+ // Run DidActivate() afterwards by posting it now.
+ proxy()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerNoMailboxIsActivatedDuringCommit::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ base::AutoLock lock(activate_lock_);
+ switch (activate_count_) {
+ case 1:
+ // The first texture has been activated. Invalidate the layer so it
+ // grabs a new texture id from the client.
+ layer_->SetNeedsDisplay();
+ // So this commit number should complete after the second activate.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ break;
+ case 2:
+ // The second mailbox has been activated. Remove the layer from
+ // the tree to cause another commit/activation. The commit should
+ // finish *after* the layer is removed from the active tree.
+ layer_->RemoveFromParent();
+ // So this commit number should complete after the third activate.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 2: {
+ // The activate for the 2nd texture should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(2, activate_count_);
+ break;
+ }
+ case 3: {
+ // The activate to remove the layer should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(3, activate_count_);
+ break;
+ }
+ }
+ }
+
+
+ virtual void AfterTest() OVERRIDE {}
+
+ base::Thread wait_thread_;
+ base::WaitableEvent wait_event_;
+ base::Lock activate_lock_;
+ int activate_count_;
+ int activate_commit_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<TextureLayer> layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ TextureLayerNoMailboxIsActivatedDuringCommit);
+
+class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest {
+ protected:
+ TextureLayerMailboxIsActivatedDuringCommit()
+ : wait_thread_("WAIT"),
+ wait_event_(false, false) {
+ wait_thread_.Start();
+ }
+
+ static void ReleaseCallback(unsigned sync_point, bool lost_resource) {}
+
+ void SetMailbox(char mailbox_char) {
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
+ base::Bind(
+ &TextureLayerMailboxIsActivatedDuringCommit::ReleaseCallback));
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ activate_count_ = 0;
+
+ gfx::Size bounds(100, 100);
+ root_ = Layer::Create();
+ root_->SetAnchorPoint(gfx::PointF());
+ root_->SetBounds(bounds);
+
+ layer_ = TextureLayer::CreateForMailbox(NULL);
+ layer_->SetIsDrawable(true);
+ layer_->SetAnchorPoint(gfx::PointF());
+ layer_->SetBounds(bounds);
+
+ root_->AddChild(layer_);
+ layer_tree_host()->SetRootLayer(root_);
+ layer_tree_host()->SetViewportSize(bounds);
+ SetMailbox('1');
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // Slow down activation so the main thread DidCommit() will run if
+ // not blocked.
+ wait_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_event_)),
+ base::TimeDelta::FromMilliseconds(10));
+ wait_event_.Wait();
+
+ base::AutoLock lock(activate_lock_);
+ ++activate_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // The main thread is awake now, and will run DidCommit() immediately.
+ // Run DidActivate() afterwards by posting it now.
+ proxy()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxIsActivatedDuringCommit::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ base::AutoLock lock(activate_lock_);
+ switch (activate_count_) {
+ case 1:
+ // The first mailbox has been activated. Set a new mailbox, and
+ // expect the next commit to finish *after* it is activated.
+ SetMailbox('2');
+ // So this commit number should complete after the second activate.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ break;
+ case 2:
+ // The second mailbox has been activated. Remove the layer from
+ // the tree to cause another commit/activation. The commit should
+ // finish *after* the layer is removed from the active tree.
+ layer_->RemoveFromParent();
+ // So this commit number should complete after the third activate.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 2: {
+ // The activate for the 2nd mailbox should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(2, activate_count_);
+ break;
+ }
+ case 3: {
+ // The activate to remove the layer should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(3, activate_count_);
+ break;
+ }
+ }
+ }
+
+
+ virtual void AfterTest() OVERRIDE {}
+
+ base::Thread wait_thread_;
+ base::WaitableEvent wait_event_;
+ base::Lock activate_lock_;
+ int activate_count_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<TextureLayer> layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ TextureLayerMailboxIsActivatedDuringCommit);
+
class TextureLayerImplWithMailboxTest : public TextureLayerTest {
protected:
TextureLayerImplWithMailboxTest()
@@ -596,14 +1166,17 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(TextureMailbox());
+ impl_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
@@ -611,15 +1184,19 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
// Software resource.
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox3_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox3_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox3_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+ ContextProvider* context_provider =
+ host_impl_.output_surface()->context_provider();
unsigned texture =
- host_impl_.output_surface()->context3d()->createTexture();
+ context_provider->Context3d()->createTexture();
impl_layer->set_texture_id(texture);
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
@@ -635,14 +1212,17 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(TextureMailbox());
+ impl_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
@@ -650,15 +1230,19 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
// Software resource.
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox3_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox3_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox3_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+ ContextProvider* context_provider =
+ host_impl_.output_surface()->context_provider();
unsigned texture =
- host_impl_.output_surface()->context3d()->createTexture();
+ context_provider->Context3d()->createTexture();
impl_layer->set_texture_id(texture);
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
@@ -674,15 +1258,19 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
}
{
scoped_ptr<TextureLayerImpl> impl_layer =
TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+ ContextProvider* context_provider =
+ host_impl_.output_surface()->context_provider();
unsigned texture =
- host_impl_.output_surface()->context3d()->createTexture();
+ context_provider->Context3d()->createTexture();
impl_layer->set_texture_id(texture);
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
}
@@ -698,7 +1286,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
pending_layer->CreateLayerImpl(host_impl_.active_tree()));
ASSERT_TRUE(active_layer);
- pending_layer->SetTextureMailbox(test_data_.mailbox1_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
// Test multiple commits without an activation.
EXPECT_CALL(test_data_.mock_callback_,
@@ -706,7 +1296,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
test_data_.sync_point1_,
false))
.Times(1);
- pending_layer->SetTextureMailbox(test_data_.mailbox2_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox2_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox2_));
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
// Test callback after activation.
@@ -714,7 +1306,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
active_layer->DidBecomeActive();
EXPECT_CALL(test_data_.mock_callback_, Release(_, _, _)).Times(0);
- pending_layer->SetTextureMailbox(test_data_.mailbox1_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
EXPECT_CALL(test_data_.mock_callback_,
@@ -728,7 +1322,8 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, _, false))
.Times(1);
- pending_layer->SetTextureMailbox(TextureMailbox());
+ pending_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
pending_layer->PushPropertiesTo(active_layer.get());
active_layer->DidBecomeActive();
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -739,7 +1334,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
test_data_.sync_point1_,
false))
.Times(1);
- pending_layer->SetTextureMailbox(test_data_.mailbox1_);
+ pending_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
}
TEST_F(TextureLayerImplWithMailboxTest,
@@ -751,18 +1348,23 @@ TEST_F(TextureLayerImplWithMailboxTest,
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, _, false))
.Times(1);
- impl_layer->SetTextureMailbox(test_data_.mailbox1_);
+ impl_layer->SetTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
impl_layer->DidBecomeActive();
EXPECT_TRUE(impl_layer->WillDraw(
DRAW_MODE_HARDWARE, host_impl_.active_tree()->resource_provider()));
impl_layer->DidDraw(host_impl_.active_tree()->resource_provider());
- impl_layer->SetTextureMailbox(TextureMailbox());
+ impl_layer->SetTextureMailbox(TextureMailbox(),
+ scoped_ptr<SingleReleaseCallback>());
}
TEST_F(TextureLayerImplWithMailboxTest, TestCallbackOnInUseResource) {
ResourceProvider* provider = host_impl_.active_tree()->resource_provider();
ResourceProvider::ResourceId id =
- provider->CreateResourceFromTextureMailbox(test_data_.mailbox1_);
+ provider->CreateResourceFromTextureMailbox(
+ test_data_.mailbox1_,
+ SingleReleaseCallback::Create(test_data_.release_mailbox1_));
provider->AllocateForTesting(id);
// Transfer some resources to the parent.
@@ -777,7 +1379,9 @@ TEST_F(TextureLayerImplWithMailboxTest, TestCallbackOnInUseResource) {
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, _, false))
.Times(1);
- provider->ReceiveFromParent(list);
+ ReturnedResourceArray returned;
+ TransferableResource::ReturnResources(list, &returned);
+ provider->ReceiveReturnsFromParent(returned);
}
// Check that ClearClient correctly clears the state so that the impl side
@@ -799,8 +1403,7 @@ class TextureLayerClientTest
TestWebGraphicsContext3D::Create());
context_ = context.get();
texture_ = context->createTexture();
- return FakeOutputSurface::Create3d(
- context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
+ return FakeOutputSurface::Create3d(context.Pass()).PassAs<OutputSurface>();
}
virtual unsigned PrepareTexture() OVERRIDE {
@@ -812,7 +1415,9 @@ class TextureLayerClientTest
}
virtual bool PrepareTextureMailbox(
- cc::TextureMailbox* mailbox, bool use_shared_memory) OVERRIDE {
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
return false;
}
@@ -899,6 +1504,343 @@ class TextureLayerClientTest
// renderer.
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerClientTest);
+
+// Checks that changing a texture in the client for a TextureLayer that's
+// invisible correctly works without drawing a deleted texture. See
+// crbug.com/266628
+class TextureLayerChangeInvisibleTest
+ : public LayerTreeTest,
+ public TextureLayerClient {
+ public:
+ TextureLayerChangeInvisibleTest()
+ : client_context_(TestWebGraphicsContext3D::Create()),
+ texture_(client_context_->createTexture()),
+ texture_to_delete_on_next_commit_(0),
+ prepare_called_(0),
+ commit_count_(0),
+ expected_texture_on_draw_(0) {}
+
+ // TextureLayerClient implementation.
+ virtual unsigned PrepareTexture() OVERRIDE {
+ ++prepare_called_;
+ return texture_;
+ }
+
+ // TextureLayerClient implementation.
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return client_context_.get();
+ }
+
+ // TextureLayerClient implementation.
+ virtual bool PrepareTextureMailbox(
+ cc::TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
+ return false;
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(10, 10));
+ root->SetAnchorPoint(gfx::PointF());
+ root->SetIsDrawable(true);
+
+ solid_layer_ = SolidColorLayer::Create();
+ solid_layer_->SetBounds(gfx::Size(10, 10));
+ solid_layer_->SetIsDrawable(true);
+ solid_layer_->SetBackgroundColor(SK_ColorWHITE);
+ root->AddChild(solid_layer_);
+
+ parent_layer_ = Layer::Create();
+ parent_layer_->SetBounds(gfx::Size(10, 10));
+ parent_layer_->SetIsDrawable(true);
+ root->AddChild(parent_layer_);
+
+ texture_layer_ = TextureLayer::Create(this);
+ texture_layer_->SetBounds(gfx::Size(10, 10));
+ texture_layer_->SetAnchorPoint(gfx::PointF());
+ texture_layer_->SetIsDrawable(true);
+ parent_layer_->AddChild(texture_layer_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ ++commit_count_;
+ switch (commit_count_) {
+ case 1:
+ // We should have updated the layer, committing the texture.
+ EXPECT_EQ(1, prepare_called_);
+ // Make layer invisible.
+ parent_layer_->SetOpacity(0.f);
+ break;
+ case 2: {
+ // Layer shouldn't have been updated.
+ EXPECT_EQ(1, prepare_called_);
+ // Change the texture.
+ texture_to_delete_on_next_commit_ = texture_;
+ texture_ = client_context_->createTexture();
+ texture_layer_->SetNeedsDisplay();
+ // Force a change to make sure we draw a frame.
+ solid_layer_->SetBackgroundColor(SK_ColorGRAY);
+ break;
+ }
+ case 3:
+ EXPECT_EQ(1, prepare_called_);
+ client_context_->deleteTexture(texture_to_delete_on_next_commit_);
+ texture_to_delete_on_next_commit_ = 0;
+ // Make layer visible again.
+ parent_layer_->SetOpacity(1.f);
+ break;
+ case 4: {
+ // Layer should have been updated.
+ EXPECT_EQ(2, prepare_called_);
+ texture_layer_->ClearClient();
+ client_context_->deleteTexture(texture_);
+ texture_ = 0;
+ break;
+ }
+ case 5:
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ ASSERT_TRUE(proxy()->IsMainThreadBlocked());
+ // This is the only texture that can be drawn this frame.
+ expected_texture_on_draw_ = texture_;
+ }
+
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ bool result) OVERRIDE {
+ ContextForImplThread(host_impl)->ResetUsedTextures();
+ return true;
+ }
+
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ ASSERT_TRUE(result);
+ TestWebGraphicsContext3D* context = ContextForImplThread(host_impl);
+ int used_textures = context->NumUsedTextures();
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_EQ(1, used_textures);
+ EXPECT_TRUE(context->UsedTexture(expected_texture_on_draw_));
+ break;
+ case 1:
+ case 2:
+ EXPECT_EQ(0, used_textures);
+ break;
+ case 3:
+ EXPECT_EQ(1, used_textures);
+ EXPECT_TRUE(context->UsedTexture(expected_texture_on_draw_));
+ break;
+ default:
+ break;
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ TestWebGraphicsContext3D* ContextForImplThread(LayerTreeHostImpl* host_impl) {
+ return static_cast<TestWebGraphicsContext3D*>(
+ host_impl->output_surface()->context_provider()->Context3d());
+ }
+
+ scoped_refptr<SolidColorLayer> solid_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<TextureLayer> texture_layer_;
+ scoped_ptr<TestWebGraphicsContext3D> client_context_;
+
+ // Used on the main thread, and on the impl thread while the main thread is
+ // blocked.
+ unsigned texture_;
+
+ // Used on the main thread.
+ unsigned texture_to_delete_on_next_commit_;
+ int prepare_called_;
+ int commit_count_;
+
+ // Used on the compositor thread.
+ unsigned expected_texture_on_draw_;
+};
+
+// The TextureLayerChangeInvisibleTest does not use mailboxes, so can't use a
+// delegating renderer.
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerChangeInvisibleTest);
+
+// Checks that changing a mailbox in the client for a TextureLayer that's
+// invisible correctly works and uses the new mailbox as soon as the layer
+// becomes visible (and returns the old one).
+class TextureLayerChangeInvisibleMailboxTest
+ : public LayerTreeTest,
+ public TextureLayerClient {
+ public:
+ TextureLayerChangeInvisibleMailboxTest()
+ : mailbox_changed_(true),
+ mailbox_returned_(0),
+ prepare_called_(0),
+ commit_count_(0) {
+ mailbox_ = MakeMailbox('1');
+ }
+
+ // TextureLayerClient implementation.
+ virtual unsigned PrepareTexture() OVERRIDE {
+ NOTREACHED();
+ return 0;
+ }
+
+ // TextureLayerClient implementation.
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ NOTREACHED();
+ return NULL;
+ }
+
+ // TextureLayerClient implementation.
+ virtual bool PrepareTextureMailbox(
+ cc::TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
+ ++prepare_called_;
+ if (!mailbox_changed_)
+ return false;
+ *mailbox = mailbox_;
+ *release_callback = SingleReleaseCallback::Create(
+ base::Bind(&TextureLayerChangeInvisibleMailboxTest::MailboxReleased,
+ base::Unretained(this)));
+ return true;
+ }
+
+ TextureMailbox MakeMailbox(char name) {
+ return TextureMailbox(std::string(64, name));
+ }
+
+ void MailboxReleased(unsigned sync_point, bool lost_resource) {
+ ++mailbox_returned_;
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(10, 10));
+ root->SetAnchorPoint(gfx::PointF());
+ root->SetIsDrawable(true);
+
+ solid_layer_ = SolidColorLayer::Create();
+ solid_layer_->SetBounds(gfx::Size(10, 10));
+ solid_layer_->SetIsDrawable(true);
+ solid_layer_->SetBackgroundColor(SK_ColorWHITE);
+ root->AddChild(solid_layer_);
+
+ parent_layer_ = Layer::Create();
+ parent_layer_->SetBounds(gfx::Size(10, 10));
+ parent_layer_->SetIsDrawable(true);
+ root->AddChild(parent_layer_);
+
+ texture_layer_ = TextureLayer::CreateForMailbox(this);
+ texture_layer_->SetBounds(gfx::Size(10, 10));
+ texture_layer_->SetAnchorPoint(gfx::PointF());
+ texture_layer_->SetIsDrawable(true);
+ parent_layer_->AddChild(texture_layer_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ ++commit_count_;
+ switch (commit_count_) {
+ case 1:
+ // We should have updated the layer, committing the texture.
+ EXPECT_EQ(1, prepare_called_);
+ // Make layer invisible.
+ parent_layer_->SetOpacity(0.f);
+ break;
+ case 2:
+ // Layer shouldn't have been updated.
+ EXPECT_EQ(1, prepare_called_);
+ // Change the texture.
+ mailbox_ = MakeMailbox('2');
+ mailbox_changed_ = true;
+ texture_layer_->SetNeedsDisplay();
+ // Force a change to make sure we draw a frame.
+ solid_layer_->SetBackgroundColor(SK_ColorGRAY);
+ break;
+ case 3:
+ // Layer shouldn't have been updated.
+ EXPECT_EQ(1, prepare_called_);
+ // So the old mailbox isn't returned yet.
+ EXPECT_EQ(0, mailbox_returned_);
+ // Make layer visible again.
+ parent_layer_->SetOpacity(1.f);
+ break;
+ case 4:
+ // Layer should have been updated.
+ EXPECT_EQ(2, prepare_called_);
+ // So the old mailbox should have been returned already.
+ EXPECT_EQ(1, mailbox_returned_);
+ texture_layer_->ClearClient();
+ break;
+ case 5:
+ EXPECT_EQ(2, mailbox_returned_);
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ ASSERT_TRUE(result);
+ DelegatedFrameData* delegated_frame_data =
+ output_surface()->last_sent_frame().delegated_frame_data.get();
+ if (!delegated_frame_data)
+ return;
+
+ // Return all resources immediately.
+ TransferableResourceArray resources_to_return =
+ output_surface()->resources_held_by_parent();
+
+ CompositorFrameAck ack;
+ for (size_t i = 0; i < resources_to_return.size(); ++i)
+ output_surface()->ReturnResource(resources_to_return[i].id, &ack);
+ host_impl->ReclaimResources(&ack);
+ host_impl->OnSwapBuffersComplete();
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ scoped_refptr<SolidColorLayer> solid_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<TextureLayer> texture_layer_;
+
+ // Used on the main thread.
+ bool mailbox_changed_;
+ TextureMailbox mailbox_;
+ int mailbox_returned_;
+ int prepare_called_;
+ int commit_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerChangeInvisibleMailboxTest);
+
// Test recovering from a lost context.
class TextureLayerLostContextTest
: public LayerTreeTest,
@@ -928,7 +1870,9 @@ class TextureLayerLostContextTest
}
virtual bool PrepareTextureMailbox(
- cc::TextureMailbox* mailbox, bool use_shared_memory) OVERRIDE {
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
return false;
}
@@ -981,19 +1925,20 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerLostContextTest);
class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
public:
void ReleaseCallback(unsigned sync_point, bool lost_resource) {
- EXPECT_EQ(true, proxy()->IsMainThread());
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
EndTest();
}
void SetMailbox(char mailbox_char) {
- TextureMailbox mailbox(
- std::string(64, mailbox_char),
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerWithMailboxMainThreadDeleted::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox);
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
}
virtual void SetupTree() OVERRIDE {
@@ -1013,6 +1958,8 @@ class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
}
virtual void BeginTest() OVERRIDE {
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+
callback_count_ = 0;
// Set the mailbox on the main thread.
@@ -1038,6 +1985,7 @@ class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
}
private:
+ base::ThreadChecker main_thread_;
int callback_count_;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;
@@ -1049,19 +1997,20 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
public:
void ReleaseCallback(unsigned sync_point, bool lost_resource) {
- EXPECT_EQ(true, proxy()->IsMainThread());
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
EndTest();
}
void SetMailbox(char mailbox_char) {
- TextureMailbox mailbox(
- std::string(64, mailbox_char),
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+ TextureMailbox mailbox(std::string(64, mailbox_char));
+ scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerWithMailboxImplThreadDeleted::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox);
+ layer_->SetTextureMailbox(mailbox, callback.Pass());
}
virtual void SetupTree() OVERRIDE {
@@ -1081,6 +2030,8 @@ class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
}
virtual void BeginTest() OVERRIDE {
+ EXPECT_EQ(true, main_thread_.CalledOnValidThread());
+
callback_count_ = 0;
// Set the mailbox on the main thread.
@@ -1109,6 +2060,7 @@ class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
}
private:
+ base::ThreadChecker main_thread_;
int callback_count_;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;
diff --git a/chromium/cc/layers/tiled_layer.cc b/chromium/cc/layers/tiled_layer.cc
index bac12f0d422..8bbf2271bc4 100644
--- a/chromium/cc/layers/tiled_layer.cc
+++ b/chromium/cc/layers/tiled_layer.cc
@@ -86,7 +86,7 @@ class UpdatableTile : public LayerTilingData::Tile {
TiledLayer::TiledLayer()
: ContentsScalingLayer(),
- texture_format_(GL_INVALID_ENUM),
+ texture_format_(RGBA_8888),
skips_draw_(false),
failed_update_(false),
tiling_option_(AUTO_TILE) {
@@ -235,9 +235,7 @@ void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
needs_push_properties_ = true;
}
-bool TiledLayer::BlocksPendingCommit() const { return true; }
-
-PrioritizedResourceManager* TiledLayer::ResourceManager() const {
+PrioritizedResourceManager* TiledLayer::ResourceManager() {
if (!layer_tree_host())
return NULL;
return layer_tree_host()->contents_texture_manager();
@@ -731,6 +729,10 @@ bool TiledLayer::Update(ResourceUpdateQueue* queue,
const OcclusionTracker* occlusion) {
DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped?
+ // Tiled layer always causes commits to wait for activation, as it does
+ // not support pending trees.
+ SetNextCommitWaitsForActivation();
+
bool updated = false;
{
diff --git a/chromium/cc/layers/tiled_layer.h b/chromium/cc/layers/tiled_layer.h
index 8ad7df95e38..3870d69956b 100644
--- a/chromium/cc/layers/tiled_layer.h
+++ b/chromium/cc/layers/tiled_layer.h
@@ -8,6 +8,7 @@
#include "cc/base/cc_export.h"
#include "cc/layers/contents_scaling_layer.h"
#include "cc/resources/layer_tiling_data.h"
+#include "cc/resources/resource_format.h"
namespace cc {
class LayerUpdater;
@@ -26,7 +27,6 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
// Layer implementation.
virtual void SetIsMask(bool is_mask) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
- virtual bool BlocksPendingCommit() const OVERRIDE;
virtual bool DrawsContent() const OVERRIDE;
virtual void ReduceMemoryUsage() OVERRIDE;
virtual void SetNeedsDisplayRect(const gfx::RectF& dirty_rect) OVERRIDE;
@@ -46,7 +46,7 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
// Exposed to subclasses for testing.
void SetTileSize(gfx::Size size);
- void SetTextureFormat(unsigned texture_format) {
+ void SetTextureFormat(ResourceFormat texture_format) {
texture_format_ = texture_format;
}
void SetBorderTexelOption(LayerTilingData::BorderTexelOption option);
@@ -68,7 +68,7 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
bool SkipsDraw() const { return skips_draw_; }
// Virtual for testing
- virtual PrioritizedResourceManager* ResourceManager() const;
+ virtual PrioritizedResourceManager* ResourceManager();
const LayerTilingData* TilerForTesting() const { return tiler_.get(); }
const PrioritizedResource* ResourceAtForTesting(int i, int j) const;
@@ -121,7 +121,7 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
bool IsSmallAnimatedLayer() const;
- unsigned texture_format_;
+ ResourceFormat texture_format_;
bool skips_draw_;
bool failed_update_;
diff --git a/chromium/cc/layers/tiled_layer_unittest.cc b/chromium/cc/layers/tiled_layer_unittest.cc
index a2f0ca7a64d..b6da0769f95 100644
--- a/chromium/cc/layers/tiled_layer_unittest.cc
+++ b/chromium/cc/layers/tiled_layer_unittest.cc
@@ -16,6 +16,7 @@
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_proxy.h"
#include "cc/test/fake_rendering_stats_instrumentation.h"
#include "cc/test/geometry_test_utils.h"
@@ -47,7 +48,7 @@ class TiledLayerTest : public testing::Test {
public:
TiledLayerTest()
: proxy_(NULL),
- output_surface_(CreateFakeOutputSurface()),
+ output_surface_(FakeOutputSurface::Create3d()),
queue_(make_scoped_ptr(new ResourceUpdateQueue)),
fake_layer_impl_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D),
occlusion_(NULL) {
@@ -64,9 +65,12 @@ class TiledLayerTest : public testing::Test {
layer_tree_host_->InitializeOutputSurfaceIfNeeded();
layer_tree_host_->SetRootLayer(Layer::Create());
+ CHECK(output_surface_->BindToClient(&output_surface_client_));
+
DebugScopedSetImplThreadAndMainThreadBlocked
- impl_thread_and_main_thread_blocked(proxy_);
- resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
+ impl_thread_and_main_thread_blocked(proxy_);
+ resource_provider_ =
+ ResourceProvider::Create(output_surface_.get(), 0, false);
host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(proxy_));
}
@@ -183,6 +187,7 @@ class TiledLayerTest : public testing::Test {
public:
Proxy* proxy_;
LayerTreeSettings settings_;
+ FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<OutputSurface> output_surface_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<ResourceUpdateQueue> queue_;
@@ -951,8 +956,10 @@ TEST_F(TiledLayerTest, SkipsDrawGetsReset) {
layer_tree_host_->SetRootLayer(root_layer);
layer_tree_host_->SetViewportSize(gfx::Size(300, 300));
+ layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes(
+ memory_limit);
- layer_tree_host_->UpdateLayers(queue_.get(), memory_limit);
+ layer_tree_host_->UpdateLayers(queue_.get());
// We'll skip the root layer.
EXPECT_TRUE(root_layer->SkipsDraw());
@@ -963,7 +970,7 @@ TEST_F(TiledLayerTest, SkipsDrawGetsReset) {
// Remove the child layer.
root_layer->RemoveAllChildren();
- layer_tree_host_->UpdateLayers(queue_.get(), memory_limit);
+ layer_tree_host_->UpdateLayers(queue_.get());
EXPECT_FALSE(root_layer->SkipsDraw());
ResourceManagerClearAllMemory(layer_tree_host_->contents_texture_manager(),
@@ -1029,8 +1036,7 @@ TEST_F(TiledLayerPartialUpdateTest, PartialUpdates) {
layer_tree_host_->SetViewportSize(gfx::Size(300, 200));
// Full update of all 6 tiles.
- layer_tree_host_->UpdateLayers(queue_.get(),
- std::numeric_limits<size_t>::max());
+ layer_tree_host_->UpdateLayers(queue_.get());
{
scoped_ptr<FakeTiledLayerImpl> layer_impl =
make_scoped_ptr(new FakeTiledLayerImpl(host_impl_->active_tree(), 1));
@@ -1046,8 +1052,7 @@ TEST_F(TiledLayerPartialUpdateTest, PartialUpdates) {
// Full update of 3 tiles and partial update of 3 tiles.
layer->InvalidateContentRect(gfx::Rect(0, 0, 300, 150));
- layer_tree_host_->UpdateLayers(queue_.get(),
- std::numeric_limits<size_t>::max());
+ layer_tree_host_->UpdateLayers(queue_.get());
{
scoped_ptr<FakeTiledLayerImpl> layer_impl =
make_scoped_ptr(new FakeTiledLayerImpl(host_impl_->active_tree(), 1));
@@ -1066,8 +1071,7 @@ TEST_F(TiledLayerPartialUpdateTest, PartialUpdates) {
{
scoped_ptr<FakeTiledLayerImpl> layer_impl =
make_scoped_ptr(new FakeTiledLayerImpl(host_impl_->active_tree(), 1));
- layer_tree_host_->UpdateLayers(queue_.get(),
- std::numeric_limits<size_t>::max());
+ layer_tree_host_->UpdateLayers(queue_.get());
EXPECT_EQ(2u, queue_->FullUploadSize());
EXPECT_EQ(4u, queue_->PartialUploadSize());
UpdateTextures();
@@ -1092,8 +1096,7 @@ TEST_F(TiledLayerPartialUpdateTest, PartialUpdates) {
{
scoped_ptr<FakeTiledLayerImpl> layer_impl =
make_scoped_ptr(new FakeTiledLayerImpl(host_impl_->active_tree(), 1));
- layer_tree_host_->UpdateLayers(queue_.get(),
- std::numeric_limits<size_t>::max());
+ layer_tree_host_->UpdateLayers(queue_.get());
EXPECT_EQ(6u, queue_->FullUploadSize());
EXPECT_EQ(0u, queue_->PartialUploadSize());
UpdateTextures();
@@ -1109,8 +1112,7 @@ TEST_F(TiledLayerPartialUpdateTest, PartialUpdates) {
{
scoped_ptr<FakeTiledLayerImpl> layer_impl =
make_scoped_ptr(new FakeTiledLayerImpl(host_impl_->active_tree(), 1));
- layer_tree_host_->UpdateLayers(queue_.get(),
- std::numeric_limits<size_t>::max());
+ layer_tree_host_->UpdateLayers(queue_.get());
EXPECT_EQ(0u, queue_->FullUploadSize());
EXPECT_EQ(4u, queue_->PartialUploadSize());
UpdateTextures();
@@ -1708,8 +1710,7 @@ TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) {
root->InvalidateContentRect(root_rect);
child->InvalidateContentRect(child_rect);
child2->InvalidateContentRect(child2_rect);
- layer_tree_host_->UpdateLayers(queue_.get(),
- std::numeric_limits<size_t>::max());
+ layer_tree_host_->UpdateLayers(queue_.get());
{
UpdateTextures();
EXPECT_EQ(6, root->fake_layer_updater()->update_count());
@@ -1747,8 +1748,11 @@ TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) {
root->InvalidateContentRect(root_rect);
child->InvalidateContentRect(child_rect);
child2->InvalidateContentRect(child2_rect);
- layer_tree_host_->UpdateLayers(queue_.get(),
- (3 * 2 + 3 * 1) * (100 * 100) * 4);
+
+ size_t memory_limit = (3 * 2 + 3 * 1) * (100 * 100) * 4;
+ layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes(
+ memory_limit);
+ layer_tree_host_->UpdateLayers(queue_.get());
{
UpdateTextures();
EXPECT_EQ(6, root->fake_layer_updater()->update_count());
@@ -1786,7 +1790,11 @@ TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) {
root->InvalidateContentRect(root_rect);
child->InvalidateContentRect(child_rect);
child2->InvalidateContentRect(child2_rect);
- layer_tree_host_->UpdateLayers(queue_.get(), (3 * 1) * (100 * 100) * 4);
+
+ memory_limit = (3 * 1) * (100 * 100) * 4;
+ layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes(
+ memory_limit);
+ layer_tree_host_->UpdateLayers(queue_.get());
{
UpdateTextures();
EXPECT_EQ(0, root->fake_layer_updater()->update_count());
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index 4b5671ff90e..28e470e7c3b 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -13,6 +13,7 @@
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/yuv_video_draw_quad.h"
#include "cc/resources/resource_provider.h"
+#include "cc/resources/single_release_callback.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/proxy.h"
#include "media/base/video_frame.h"
@@ -93,8 +94,11 @@ bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
if (!LayerImpl::WillDraw(draw_mode, resource_provider))
return false;
- if (!updater_)
- updater_.reset(new VideoResourceUpdater(resource_provider));
+ if (!updater_) {
+ updater_.reset(
+ new VideoResourceUpdater(layer_tree_impl()->context_provider(),
+ layer_tree_impl()->resource_provider()));
+ }
VideoFrameExternalResources external_resources =
updater_->CreateExternalResourcesFromVideoFrame(frame_);
@@ -108,10 +112,13 @@ bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
return true;
}
+ DCHECK_EQ(external_resources.mailboxes.size(),
+ external_resources.release_callbacks.size());
for (size_t i = 0; i < external_resources.mailboxes.size(); ++i) {
- frame_resources_.push_back(
- resource_provider->CreateResourceFromTextureMailbox(
- external_resources.mailboxes[i]));
+ unsigned resource_id = resource_provider->CreateResourceFromTextureMailbox(
+ external_resources.mailboxes[i],
+ SingleReleaseCallback::Create(external_resources.release_callbacks[i]));
+ frame_resources_.push_back(resource_id);
}
return true;
diff --git a/chromium/cc/layers/video_layer_impl.h b/chromium/cc/layers/video_layer_impl.h
index b07187115ed..b4df1417bf1 100644
--- a/chromium/cc/layers/video_layer_impl.h
+++ b/chromium/cc/layers/video_layer_impl.h
@@ -9,6 +9,7 @@
#include "cc/base/cc_export.h"
#include "cc/layers/layer_impl.h"
+#include "cc/resources/release_callback.h"
#include "cc/resources/video_resource_updater.h"
namespace media {
@@ -59,7 +60,8 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl {
// TODO(danakj): Remove these, hide software path inside ResourceProvider and
// ExternalResource (aka TextureMailbox) classes.
std::vector<unsigned> software_resources_;
- TextureMailbox::ReleaseCallback software_release_callback_;
+ // Called once for each software resource.
+ ReleaseCallback software_release_callback_;
DISALLOW_COPY_AND_ASSIGN(VideoLayerImpl);
};