summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraelias@chromium.org <aelias@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-06 05:53:00 +0000
committeraelias@chromium.org <aelias@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-06 05:53:00 +0000
commit35680c0ca726980e1a380e668bf7565b39eb7ce9 (patch)
treef6c147c60ca4beae0d663efc9d211f55325a6854
parentae8be5cadd06887ae263a9e906afe297e8cffb8b (diff)
downloadchromium_src-35680c0ca726980e1a380e668bf7565b39eb7ce9.zip
chromium_src-35680c0ca726980e1a380e668bf7565b39eb7ce9.tar.gz
chromium_src-35680c0ca726980e1a380e668bf7565b39eb7ce9.tar.bz2
cc: Nine patch layer.
Review URL: https://chromiumcodereview.appspot.com/11304020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166154 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--cc/cc.gyp6
-rw-r--r--cc/cc_tests.gyp2
-rw-r--r--cc/image_layer.cc66
-rw-r--r--cc/image_layer_updater.cc55
-rw-r--r--cc/image_layer_updater.h50
-rw-r--r--cc/nine_patch_layer.cc99
-rw-r--r--cc/nine_patch_layer.h55
-rw-r--r--cc/nine_patch_layer_impl.cc117
-rw-r--r--cc/nine_patch_layer_impl.h51
-rw-r--r--cc/nine_patch_layer_impl_unittest.cc94
-rw-r--r--cc/nine_patch_layer_unittest.cc142
-rw-r--r--webkit/compositor_bindings/compositor_bindings.gyp2
-rw-r--r--webkit/compositor_bindings/web_nine_patch_layer_impl.cc36
-rw-r--r--webkit/compositor_bindings/web_nine_patch_layer_impl.h31
14 files changed, 741 insertions, 65 deletions
diff --git a/cc/cc.gyp b/cc/cc.gyp
index fde2598..1261484 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -60,6 +60,8 @@
'heads_up_display_layer.h',
'heads_up_display_layer_impl.cc',
'heads_up_display_layer_impl.h',
+ 'image_layer_updater.cc',
+ 'image_layer_updater.h',
'image_layer.cc',
'image_layer.h',
'input_handler.h',
@@ -99,6 +101,10 @@
'managed_memory_policy.h',
'math_util.cc',
'math_util.h',
+ 'nine_patch_layer.cc',
+ 'nine_patch_layer.h',
+ 'nine_patch_layer_impl.cc',
+ 'nine_patch_layer_impl.h',
'occlusion_tracker.cc',
'occlusion_tracker.h',
'overdraw_metrics.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index c51556d..df98423 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -25,6 +25,8 @@
'layer_tree_host_impl_unittest.cc',
'layer_tree_host_unittest.cc',
'math_util_unittest.cc',
+ 'nine_patch_layer_unittest.cc',
+ 'nine_patch_layer_impl_unittest.cc',
'occlusion_tracker_unittest.cc',
'prioritized_texture_unittest.cc',
'quad_culler_unittest.cc',
diff --git a/cc/image_layer.cc b/cc/image_layer.cc
index 5171799..c150c6d 100644
--- a/cc/image_layer.cc
+++ b/cc/image_layer.cc
@@ -7,77 +7,13 @@
#include "cc/image_layer.h"
#include "base/compiler_specific.h"
+#include "cc/image_layer_updater.h"
#include "cc/layer_updater.h"
#include "cc/layer_tree_host.h"
#include "cc/resource_update_queue.h"
namespace cc {
-class ImageLayerUpdater : public LayerUpdater {
-public:
- class Resource : public LayerUpdater::Resource {
- public:
- Resource(ImageLayerUpdater* updater, scoped_ptr<PrioritizedTexture> texture)
- : LayerUpdater::Resource(texture.Pass())
- , m_updater(updater)
- {
- }
-
- virtual void update(ResourceUpdateQueue& queue, const gfx::Rect& sourceRect, const gfx::Vector2d& destOffset, bool partialUpdate, RenderingStats&) OVERRIDE
- {
- updater()->updateTexture(queue, texture(), sourceRect, destOffset, partialUpdate);
- }
-
- private:
- ImageLayerUpdater* updater() { return m_updater; }
-
- ImageLayerUpdater* m_updater;
- };
-
- static scoped_refptr<ImageLayerUpdater> create()
- {
- return make_scoped_refptr(new ImageLayerUpdater());
- }
-
- virtual scoped_ptr<LayerUpdater::Resource> createResource(
- PrioritizedTextureManager* manager) OVERRIDE
- {
- return scoped_ptr<LayerUpdater::Resource>(new Resource(this, PrioritizedTexture::create(manager)));
- }
-
- void updateTexture(ResourceUpdateQueue& queue, PrioritizedTexture* texture, const gfx::Rect& sourceRect, const gfx::Vector2d& destOffset, bool partialUpdate)
- {
- // Source rect should never go outside the image pixels, even if this
- // is requested because the texture extends outside the image.
- gfx::Rect clippedSourceRect = sourceRect;
- gfx::Rect imageRect = gfx::Rect(0, 0, m_bitmap.width(), m_bitmap.height());
- clippedSourceRect.Intersect(imageRect);
-
- gfx::Vector2d clippedDestOffset = destOffset + (clippedSourceRect.origin() - sourceRect.origin());
-
- ResourceUpdate upload = ResourceUpdate::Create(texture,
- &m_bitmap,
- imageRect,
- clippedSourceRect,
- clippedDestOffset);
- if (partialUpdate)
- queue.appendPartialUpload(upload);
- else
- queue.appendFullUpload(upload);
- }
-
- void setBitmap(const SkBitmap& bitmap)
- {
- m_bitmap = bitmap;
- }
-
-private:
- ImageLayerUpdater() { }
- virtual ~ImageLayerUpdater() { }
-
- SkBitmap m_bitmap;
-};
-
scoped_refptr<ImageLayer> ImageLayer::create()
{
return make_scoped_refptr(new ImageLayer());
diff --git a/cc/image_layer_updater.cc b/cc/image_layer_updater.cc
new file mode 100644
index 0000000..9f73b80
--- /dev/null
+++ b/cc/image_layer_updater.cc
@@ -0,0 +1,55 @@
+// 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 "config.h"
+
+#include "cc/image_layer_updater.h"
+#include "cc/resource_update_queue.h"
+
+namespace cc {
+
+void ImageLayerUpdater::Resource::update(ResourceUpdateQueue& queue, const gfx::Rect& sourceRect, const gfx::Vector2d& destOffset, bool partialUpdate, RenderingStats&)
+{
+ m_updater->updateTexture(queue, texture(), sourceRect, destOffset, partialUpdate);
+}
+
+// static
+scoped_refptr<ImageLayerUpdater> ImageLayerUpdater::create()
+{
+ return make_scoped_refptr(new ImageLayerUpdater());
+}
+
+scoped_ptr<LayerUpdater::Resource> ImageLayerUpdater::createResource(
+ PrioritizedTextureManager* manager)
+{
+ return scoped_ptr<LayerUpdater::Resource>(new Resource(this, PrioritizedTexture::create(manager)));
+}
+
+void ImageLayerUpdater::updateTexture(ResourceUpdateQueue& queue, PrioritizedTexture* texture, const gfx::Rect& sourceRect, const gfx::Vector2d& destOffset, bool partialUpdate)
+{
+ // Source rect should never go outside the image pixels, even if this
+ // is requested because the texture extends outside the image.
+ gfx::Rect clippedSourceRect = sourceRect;
+ gfx::Rect imageRect = gfx::Rect(0, 0, m_bitmap.width(), m_bitmap.height());
+ clippedSourceRect.Intersect(imageRect);
+
+ gfx::Vector2d clippedDestOffset = destOffset + gfx::Vector2d(clippedSourceRect.origin() - sourceRect.origin());
+
+ ResourceUpdate upload = ResourceUpdate::Create(texture,
+ &m_bitmap,
+ imageRect,
+ clippedSourceRect,
+ clippedDestOffset);
+ if (partialUpdate)
+ queue.appendPartialUpload(upload);
+ else
+ queue.appendFullUpload(upload);
+}
+
+void ImageLayerUpdater::setBitmap(const SkBitmap& bitmap)
+{
+ m_bitmap = bitmap;
+}
+
+}
diff --git a/cc/image_layer_updater.h b/cc/image_layer_updater.h
new file mode 100644
index 0000000..89c26b2
--- /dev/null
+++ b/cc/image_layer_updater.h
@@ -0,0 +1,50 @@
+// 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 ImageLayerUpdater_h
+#define ImageLayerUpdater_h
+
+#include "config.h"
+
+#include "cc/layer_updater.h"
+
+namespace cc {
+
+class ResourceUpdateQueue;
+
+class ImageLayerUpdater : public LayerUpdater {
+public:
+ class Resource : public LayerUpdater::Resource {
+ public:
+ Resource(ImageLayerUpdater* updater, scoped_ptr<PrioritizedTexture> texture)
+ : LayerUpdater::Resource(texture.Pass())
+ , m_updater(updater)
+ {
+ }
+
+ virtual void update(ResourceUpdateQueue&, const gfx::Rect& sourceRect, const gfx::Vector2d& destOffset, bool partialUpdate, RenderingStats&) OVERRIDE;
+
+ private:
+ ImageLayerUpdater* m_updater;
+ };
+
+ static scoped_refptr<ImageLayerUpdater> create();
+
+ virtual scoped_ptr<LayerUpdater::Resource> createResource(
+ PrioritizedTextureManager*) OVERRIDE;
+
+ void updateTexture(ResourceUpdateQueue&, PrioritizedTexture*, const gfx::Rect& sourceRect, const gfx::Vector2d& destOffset, bool partialUpdate);
+
+ void setBitmap(const SkBitmap&);
+
+private:
+ ImageLayerUpdater() { }
+ virtual ~ImageLayerUpdater() { }
+
+ SkBitmap m_bitmap;
+};
+
+}
+
+#endif
diff --git a/cc/nine_patch_layer.cc b/cc/nine_patch_layer.cc
new file mode 100644
index 0000000..8ad3174
--- /dev/null
+++ b/cc/nine_patch_layer.cc
@@ -0,0 +1,99 @@
+// 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 "config.h"
+
+#include "cc/nine_patch_layer.h"
+
+#include "cc/layer_tree_host.h"
+#include "cc/nine_patch_layer_impl.h"
+#include "cc/resource_update.h"
+#include "cc/resource_update_queue.h"
+
+namespace cc {
+
+scoped_refptr<NinePatchLayer> NinePatchLayer::create()
+{
+ return make_scoped_refptr(new NinePatchLayer());
+}
+
+NinePatchLayer::NinePatchLayer()
+ : m_bitmapDirty(false)
+{
+}
+
+NinePatchLayer::~NinePatchLayer()
+{
+}
+
+scoped_ptr<LayerImpl> NinePatchLayer::createLayerImpl()
+{
+ return NinePatchLayerImpl::create(id()).PassAs<LayerImpl>();
+}
+
+void NinePatchLayer::setTexturePriorities(const PriorityCalculator& priorityCalc)
+{
+ if (m_needsDisplay && m_bitmapDirty && drawsContent()) {
+ DCHECK(!m_bitmap.isNull());
+ createUpdaterIfNeeded();
+ m_updater->setBitmap(m_bitmap);
+ m_needsDisplay = false;
+
+ if (!m_resource)
+ m_resource = m_updater->createResource(layerTreeHost()->contentsTextureManager());
+ }
+
+ if (m_resource) {
+ m_resource->texture()->setRequestPriority(PriorityCalculator::uiPriority(true));
+ // FIXME: Need to support swizzle in the shader for !PlatformColor::sameComponentOrder(textureFormat)
+ GLenum textureFormat = layerTreeHost()->rendererCapabilities().bestTextureFormat;
+ m_resource->texture()->setDimensions(gfx::Size(m_bitmap.width(), m_bitmap.height()), textureFormat);
+ }
+}
+
+void NinePatchLayer::setBitmap(const SkBitmap& bitmap, const gfx::Rect& aperture) {
+ m_bitmap = bitmap;
+ m_imageAperture = aperture;
+ m_bitmapDirty = true;
+ setNeedsDisplay();
+}
+
+void NinePatchLayer::update(ResourceUpdateQueue& queue, const OcclusionTracker* occlusion, RenderingStats& stats)
+{
+ createUpdaterIfNeeded();
+
+ if (m_resource && (m_bitmapDirty || m_resource->texture()->backingResourceWasEvicted())) {
+ gfx::Rect contentRect(gfx::Point(), gfx::Size(m_bitmap.width(), m_bitmap.height()));
+ ResourceUpdate upload = ResourceUpdate::Create(m_resource->texture(), &m_bitmap, contentRect, contentRect, gfx::Vector2d());
+ queue.appendFullUpload(upload);
+ m_bitmapDirty = false;
+ }
+}
+
+void NinePatchLayer::createUpdaterIfNeeded()
+{
+ if (m_updater)
+ return;
+
+ m_updater = ImageLayerUpdater::create();
+}
+
+bool NinePatchLayer::drawsContent() const
+{
+ bool draws = !m_bitmap.isNull() && Layer::drawsContent() && m_bitmap.width() && m_bitmap.height();
+ return draws;
+}
+
+void NinePatchLayer::pushPropertiesTo(LayerImpl* layer)
+{
+ Layer::pushPropertiesTo(layer);
+ NinePatchLayerImpl* layerImpl = static_cast<NinePatchLayerImpl*>(layer);
+
+ DCHECK(!m_bitmap.isNull());
+ DCHECK(m_resource);
+ layerImpl->setResourceId(m_resource->texture()->resourceId());
+ layerImpl->setLayout(gfx::Size(m_bitmap.width(), m_bitmap.height()), m_imageAperture);
+}
+
+}
diff --git a/cc/nine_patch_layer.h b/cc/nine_patch_layer.h
new file mode 100644
index 0000000..6e20b1f
--- /dev/null
+++ b/cc/nine_patch_layer.h
@@ -0,0 +1,55 @@
+// 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 NinePatchLayer_h
+#define NinePatchLayer_h
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/cc_export.h"
+#include "cc/layer.h"
+#include "cc/image_layer_updater.h"
+#include "ui/gfx/rect.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace cc {
+
+class ResourceUpdateQueue;
+
+class CC_EXPORT NinePatchLayer : public Layer {
+public:
+ static scoped_refptr<NinePatchLayer> create();
+
+ virtual bool drawsContent() const OVERRIDE;
+ virtual void setTexturePriorities(const PriorityCalculator&) OVERRIDE;
+ virtual void update(ResourceUpdateQueue&, const OcclusionTracker*, RenderingStats&) OVERRIDE;
+ virtual void pushPropertiesTo(LayerImpl*) OVERRIDE;
+
+ // 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, const gfx::Rect& aperture);
+
+private:
+ NinePatchLayer();
+ virtual ~NinePatchLayer();
+ virtual scoped_ptr<LayerImpl> createLayerImpl() OVERRIDE;
+
+ void createUpdaterIfNeeded();
+
+ scoped_refptr<ImageLayerUpdater> m_updater;
+ scoped_ptr<LayerUpdater::Resource> m_resource;
+
+ SkBitmap m_bitmap;
+ bool m_bitmapDirty;
+
+ // The transparent center region that shows the parent layer's contents in image space.
+ gfx::Rect m_imageAperture;
+};
+
+}
+
+#endif
diff --git a/cc/nine_patch_layer_impl.cc b/cc/nine_patch_layer_impl.cc
new file mode 100644
index 0000000..d271eb0
--- /dev/null
+++ b/cc/nine_patch_layer_impl.cc
@@ -0,0 +1,117 @@
+// 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 "config.h"
+
+#include "nine_patch_layer_impl.h"
+
+#include "cc/quad_sink.h"
+#include "cc/texture_draw_quad.h"
+#include "ui/gfx/rect_f.h"
+
+namespace cc {
+
+NinePatchLayerImpl::NinePatchLayerImpl(int id)
+ : LayerImpl(id)
+ , m_resourceId(0)
+{
+}
+
+NinePatchLayerImpl::~NinePatchLayerImpl()
+{
+}
+
+ResourceProvider::ResourceId NinePatchLayerImpl::contentsResourceId() const
+{
+ return 0;
+}
+
+void NinePatchLayerImpl::dumpLayerProperties(std::string* str, int indent) const
+{
+ LayerImpl::dumpLayerProperties(str, indent);
+}
+
+
+void NinePatchLayerImpl::willDraw(ResourceProvider* resourceProvider)
+{
+}
+
+static gfx::RectF normalizedRect(float x, float y, float width, float height, float totalWidth, float totalHeight)
+{
+ return gfx::RectF(x / totalWidth, y / totalHeight, width / totalWidth, height / totalHeight);
+}
+
+void NinePatchLayerImpl::setLayout(const gfx::Size& imageBounds, const gfx::Rect& aperture)
+{
+ m_imageBounds = imageBounds;
+ m_imageAperture = aperture;
+}
+
+void NinePatchLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuadsData)
+{
+ if (!m_resourceId)
+ return;
+
+ SharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState());
+ appendDebugBorderQuad(quadSink, sharedQuadState, appendQuadsData);
+
+ static const bool flipped = false;
+ static const bool premultipliedAlpha = true;
+
+ DCHECK(!bounds().IsEmpty());
+
+ // NinePatch border widths in bitmap pixel space
+ int leftWidth = m_imageAperture.x();
+ int topHeight = m_imageAperture.y();
+ int rightWidth = m_imageBounds.width() - m_imageAperture.right();
+ int bottomHeight = m_imageBounds.height() - m_imageAperture.bottom();
+
+ // Patch positions in layer space
+ gfx::Rect topLeft(0, 0, leftWidth, topHeight);
+ gfx::Rect topRight(bounds().width() - rightWidth, 0, rightWidth, topHeight);
+ gfx::Rect bottomLeft(0, bounds().height() - bottomHeight, leftWidth, bottomHeight);
+ gfx::Rect bottomRight(topRight.x(), bottomLeft.y(), rightWidth, bottomHeight);
+ gfx::Rect top(topLeft.right(), 0, bounds().width() - leftWidth - rightWidth, topHeight);
+ gfx::Rect left(0, topLeft.bottom(), leftWidth, bounds().height() - topHeight - bottomHeight);
+ gfx::Rect right(topRight.x(), topRight.bottom(), rightWidth, left.height());
+ gfx::Rect bottom(top.x(), bottomLeft.y(), top.width(), bottomHeight);
+
+ float imgWidth = m_imageBounds.width();
+ float imgHeight = m_imageBounds.height();
+
+ // Patch positions in bitmap UV space (from zero to one)
+ gfx::RectF uvTopLeft = normalizedRect(0, 0, leftWidth, topHeight, imgWidth, imgHeight);
+ gfx::RectF uvTopRight = normalizedRect(imgWidth - rightWidth, 0, rightWidth, topHeight, imgWidth, imgHeight);
+ gfx::RectF uvBottomLeft = normalizedRect(0, imgHeight - bottomHeight, leftWidth, bottomHeight, imgWidth, imgHeight);
+ gfx::RectF uvBottomRight = normalizedRect(imgWidth - rightWidth, imgHeight - bottomHeight, rightWidth, bottomHeight, imgWidth, imgHeight);
+ gfx::RectF uvTop(uvTopLeft.right(), 0, (imgWidth - leftWidth - rightWidth) / imgWidth, (topHeight) / imgHeight);
+ gfx::RectF uvLeft(0, uvTopLeft.bottom(), leftWidth / imgWidth, (imgHeight - topHeight - bottomHeight) / imgHeight);
+ gfx::RectF uvRight(uvTopRight.x(), uvTopRight.bottom(), rightWidth / imgWidth, uvLeft.height());
+ gfx::RectF uvBottom(uvTop.x(), uvBottomLeft.y(), uvTop.width(), bottomHeight / imgHeight);
+
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, topLeft, m_resourceId, premultipliedAlpha, uvTopLeft, flipped).PassAs<DrawQuad>(), appendQuadsData);
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, topRight, m_resourceId, premultipliedAlpha, uvTopRight, flipped).PassAs<DrawQuad>(), appendQuadsData);
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, bottomLeft, m_resourceId, premultipliedAlpha, uvBottomLeft, flipped).PassAs<DrawQuad>(), appendQuadsData);
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, bottomRight, m_resourceId, premultipliedAlpha, uvBottomRight, flipped).PassAs<DrawQuad>(), appendQuadsData);
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, top, m_resourceId, premultipliedAlpha, uvTop, flipped).PassAs<DrawQuad>(), appendQuadsData);
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, left, m_resourceId, premultipliedAlpha, uvLeft, flipped).PassAs<DrawQuad>(), appendQuadsData);
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, right, m_resourceId, premultipliedAlpha, uvRight, flipped).PassAs<DrawQuad>(), appendQuadsData);
+ quadSink.append(TextureDrawQuad::create(sharedQuadState, bottom, m_resourceId, premultipliedAlpha, uvBottom, flipped).PassAs<DrawQuad>(), appendQuadsData);
+}
+
+void NinePatchLayerImpl::didDraw(ResourceProvider* resourceProvider)
+{
+}
+
+void NinePatchLayerImpl::didLoseContext()
+{
+ m_resourceId = 0;
+}
+
+const char* NinePatchLayerImpl::layerTypeAsString() const
+{
+ return "NinePatchLayer";
+}
+
+}
diff --git a/cc/nine_patch_layer_impl.h b/cc/nine_patch_layer_impl.h
new file mode 100644
index 0000000..476f5bb
--- /dev/null
+++ b/cc/nine_patch_layer_impl.h
@@ -0,0 +1,51 @@
+// 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 NinePatchLayerImpl_h
+#define NinePatchLayerImpl_h
+
+#include "cc/cc_export.h"
+#include "cc/layer_impl.h"
+#include "cc/resource_provider.h"
+#include "ui/gfx/size.h"
+#include "ui/gfx/rect.h"
+
+namespace cc {
+
+class CC_EXPORT NinePatchLayerImpl : public LayerImpl {
+public:
+ static scoped_ptr<NinePatchLayerImpl> create(int id)
+ {
+ return make_scoped_ptr(new NinePatchLayerImpl(id));
+ }
+ virtual ~NinePatchLayerImpl();
+
+ void setResourceId(unsigned id) { m_resourceId = id; }
+ void setLayout(const gfx::Size& imageBounds, const gfx::Rect& aperture);
+
+ virtual void willDraw(ResourceProvider*) OVERRIDE;
+ virtual void appendQuads(QuadSink&, AppendQuadsData&) OVERRIDE;
+ virtual void didDraw(ResourceProvider*) OVERRIDE;
+ virtual ResourceProvider::ResourceId contentsResourceId() const OVERRIDE;
+ virtual void dumpLayerProperties(std::string*, int indent) const OVERRIDE;
+ virtual void didLoseContext() OVERRIDE;
+
+protected:
+ explicit NinePatchLayerImpl(int id);
+
+private:
+ virtual const char* layerTypeAsString() const OVERRIDE;
+
+ // The size of the NinePatch bitmap in pixels.
+ gfx::Size m_imageBounds;
+
+ // The transparent center region that shows the parent layer's contents in image space.
+ gfx::Rect m_imageAperture;
+
+ ResourceProvider::ResourceId m_resourceId;
+};
+
+}
+
+#endif
diff --git a/cc/nine_patch_layer_impl_unittest.cc b/cc/nine_patch_layer_impl_unittest.cc
new file mode 100644
index 0000000..55f0c10
--- /dev/null
+++ b/cc/nine_patch_layer_impl_unittest.cc
@@ -0,0 +1,94 @@
+// 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 "config.h"
+
+#include "cc/nine_patch_layer_impl.h"
+
+#include "cc/append_quads_data.h"
+#include "cc/single_thread_proxy.h"
+#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_test_common.h"
+#include "cc/test/mock_quad_culler.h"
+#include "cc/texture_draw_quad.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/safe_integer_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include <public/WebTransformationMatrix.h>
+
+using namespace cc;
+
+namespace {
+
+gfx::Rect ToRoundedIntRect(gfx::RectF rect_f) {
+ return gfx::Rect(gfx::ToRoundedInt(rect_f.x()), gfx::ToRoundedInt(rect_f.y()), gfx::ToRoundedInt(rect_f.width()), gfx::ToRoundedInt(rect_f.height()));
+}
+
+TEST(NinePatchLayerImplTest, verifyDrawQuads)
+{
+ DebugScopedSetImplThread implThread;
+
+ // 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.
+ MockQuadCuller quadCuller;
+ gfx::Size bitmapSize(100, 100);
+ gfx::Size layerSize(400, 400);
+ gfx::Rect visibleContentRect(gfx::Point(), layerSize);
+ gfx::Rect apertureRect(20, 30, 40, 50);
+ gfx::Rect scaledApertureNonUniform(20, 30, 340, 350);
+
+ scoped_ptr<NinePatchLayerImpl> layer = NinePatchLayerImpl::create(1);
+ layer->setVisibleContentRect(visibleContentRect);
+ layer->setBounds(layerSize);
+ layer->setContentBounds(layerSize);
+ layer->createRenderSurface();
+ layer->setRenderTarget(layer.get());
+ layer->setLayout(bitmapSize, apertureRect);
+ layer->setResourceId(1);
+
+ // This scale should not affect the generated quad geometry, but only
+ // the shared draw transform.
+ WebKit::WebTransformationMatrix transform;
+ transform.scale(10);
+ layer->setDrawTransform(transform);
+
+ AppendQuadsData data;
+ layer->appendQuads(quadCuller, data);
+
+ // Verify quad rects
+ const QuadList& quads = quadCuller.quadList();
+ EXPECT_EQ(quads.size(), 8);
+ Region remaining(visibleContentRect);
+ for (size_t i = 0; i < quads.size(); ++i) {
+ DrawQuad* quad = quads[i];
+ gfx::Rect quadRect = quad->quadRect();
+
+ EXPECT_TRUE(visibleContentRect.Contains(quadRect)) << i;
+ EXPECT_TRUE(remaining.Contains(quadRect)) << i;
+ EXPECT_EQ(quad->sharedQuadState()->quadTransform, transform) << i;
+ remaining.Subtract(Region(quadRect));
+ }
+ EXPECT_RECT_EQ(remaining.bounds(), scaledApertureNonUniform);
+ Region scaledApertureRegion(scaledApertureNonUniform);
+ EXPECT_EQ(remaining, scaledApertureRegion);
+
+ // Verify UV rects
+ gfx::Rect bitmapRect(gfx::Point(), bitmapSize);
+ Region texRemaining(bitmapRect);
+ for (size_t i = 0; i < quads.size(); ++i) {
+ DrawQuad* quad = quads[i];
+ ASSERT_EQ(quad->material(), DrawQuad::TextureContent);
+ TextureDrawQuad* texQuad = static_cast<TextureDrawQuad*>(quad);
+ gfx::RectF texRect = texQuad->uvRect();
+ texRect.Scale(bitmapSize.width(), bitmapSize.height());
+ texRemaining.Subtract(Region(ToRoundedIntRect(texRect)));
+ }
+ EXPECT_RECT_EQ(texRemaining.bounds(), apertureRect);
+ Region apertureRegion(apertureRect);
+ EXPECT_EQ(texRemaining, apertureRegion);
+}
+
+}
diff --git a/cc/nine_patch_layer_unittest.cc b/cc/nine_patch_layer_unittest.cc
new file mode 100644
index 0000000..49757fe
--- /dev/null
+++ b/cc/nine_patch_layer_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright 2012 The 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 "config.h"
+
+#include "cc/nine_patch_layer.h"
+
+#include "cc/layer_tree_host.h"
+#include "cc/occlusion_tracker.h"
+#include "cc/overdraw_metrics.h"
+#include "cc/rendering_stats.h"
+#include "cc/resource_provider.h"
+#include "cc/single_thread_proxy.h"
+#include "cc/resource_update_queue.h"
+#include "cc/texture_uploader.h"
+#include "cc/test/fake_graphics_context.h"
+#include "cc/test/fake_layer_tree_host_client.h"
+#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_tree_test_common.h"
+#include "SkBitmap.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace cc;
+using ::testing::Mock;
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::AnyNumber;
+
+namespace {
+
+class MockLayerTreeHost : public LayerTreeHost {
+public:
+ MockLayerTreeHost()
+ : LayerTreeHost(&m_fakeClient, LayerTreeSettings())
+ {
+ initialize();
+ }
+
+private:
+ FakeLayerImplTreeHostClient m_fakeClient;
+};
+
+
+class NinePatchLayerTest : public testing::Test {
+public:
+ NinePatchLayerTest()
+ {
+ }
+
+protected:
+ virtual void SetUp()
+ {
+ m_layerTreeHost.reset(new MockLayerTreeHost);
+ }
+
+ virtual void TearDown()
+ {
+ Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
+ }
+
+ scoped_ptr<MockLayerTreeHost> m_layerTreeHost;
+};
+
+TEST_F(NinePatchLayerTest, triggerFullUploadOnceWhenChangingBitmap)
+{
+ scoped_refptr<NinePatchLayer> testLayer = NinePatchLayer::create();
+ ASSERT_TRUE(testLayer);
+ testLayer->setIsDrawable(true);
+ testLayer->setBounds(gfx::Size(100, 100));
+
+ m_layerTreeHost->setRootLayer(testLayer);
+ Mock::VerifyAndClearExpectations(m_layerTreeHost.get());
+ EXPECT_EQ(testLayer->layerTreeHost(), m_layerTreeHost.get());
+
+ m_layerTreeHost->initializeRendererIfNeeded();
+
+ PriorityCalculator calculator;
+ ResourceUpdateQueue queue;
+ OcclusionTracker occlusionTracker(gfx::Rect(), false);
+ RenderingStats stats;
+
+ // No bitmap set should not trigger any uploads.
+ testLayer->setTexturePriorities(calculator);
+ testLayer->update(queue, &occlusionTracker, stats);
+ EXPECT_EQ(queue.fullUploadSize(), 0);
+ EXPECT_EQ(queue.partialUploadSize(), 0);
+
+ // Setting a bitmap set should trigger a single full upload.
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ bitmap.allocPixels();
+ testLayer->setBitmap(bitmap, gfx::Rect(5, 5, 1, 1));
+ testLayer->setTexturePriorities(calculator);
+ testLayer->update(queue, &occlusionTracker, stats);
+ EXPECT_EQ(queue.fullUploadSize(), 1);
+ EXPECT_EQ(queue.partialUploadSize(), 0);
+ ResourceUpdate params = queue.takeFirstFullUpload();
+ EXPECT_TRUE(params.texture != NULL);
+
+ // Upload the texture.
+ m_layerTreeHost->contentsTextureManager()->setMaxMemoryLimitBytes(1024 * 1024);
+ m_layerTreeHost->contentsTextureManager()->prioritizeTextures();
+
+ scoped_ptr<GraphicsContext> context;
+ scoped_ptr<ResourceProvider> resourceProvider;
+ {
+ DebugScopedSetImplThread implThread;
+ DebugScopedSetMainThreadBlocked mainThreadBlocked;
+ context = WebKit::createFakeGraphicsContext();
+ resourceProvider = ResourceProvider::create(context.get());
+ params.texture->acquireBackingTexture(resourceProvider.get());
+ ASSERT_TRUE(params.texture->haveBackingTexture());
+ }
+
+ // Nothing changed, so no repeated upload.
+ testLayer->setTexturePriorities(calculator);
+ {
+ DebugScopedSetImplThread implThread;
+ testLayer->update(queue, &occlusionTracker, stats);
+ }
+ EXPECT_EQ(queue.fullUploadSize(), 0);
+ EXPECT_EQ(queue.partialUploadSize(), 0);
+
+ {
+ DebugScopedSetImplThread implThread;
+ DebugScopedSetMainThreadBlocked mainThreadBlocked;
+ m_layerTreeHost->contentsTextureManager()->clearAllMemory(resourceProvider.get());
+ }
+
+ // Reupload after eviction
+ testLayer->setTexturePriorities(calculator);
+ {
+ DebugScopedSetImplThread implThread;
+ testLayer->update(queue, &occlusionTracker, stats);
+ }
+ EXPECT_EQ(queue.fullUploadSize(), 1);
+ EXPECT_EQ(queue.partialUploadSize(), 0);
+}
+
+} // anonymous namespace
diff --git a/webkit/compositor_bindings/compositor_bindings.gyp b/webkit/compositor_bindings/compositor_bindings.gyp
index 9f6417c..abcbaee 100644
--- a/webkit/compositor_bindings/compositor_bindings.gyp
+++ b/webkit/compositor_bindings/compositor_bindings.gyp
@@ -25,6 +25,8 @@
'web_image_layer_impl.h',
'web_layer_impl.cc',
'web_layer_impl.h',
+ 'web_nine_patch_layer_impl.cc',
+ 'web_nine_patch_layer_impl.h',
'web_to_ccinput_handler_adapter.cc',
'web_to_ccinput_handler_adapter.h',
'web_layer_tree_view_impl.cc',
diff --git a/webkit/compositor_bindings/web_nine_patch_layer_impl.cc b/webkit/compositor_bindings/web_nine_patch_layer_impl.cc
new file mode 100644
index 0000000..2d30b35
--- /dev/null
+++ b/webkit/compositor_bindings/web_nine_patch_layer_impl.cc
@@ -0,0 +1,36 @@
+// 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 "config.h"
+#include "web_nine_patch_layer_impl.h"
+
+#include "cc/nine_patch_layer.h"
+#include "ui/gfx/rect.h"
+#include "web_layer_impl.h"
+#include "SkBitmap.h"
+
+using cc::NinePatchLayer;
+
+namespace WebKit {
+
+WebNinePatchLayerImpl::WebNinePatchLayerImpl()
+ : m_layer(new WebLayerImpl(NinePatchLayer::create()))
+{
+ m_layer->layer()->setIsDrawable(true);
+}
+
+WebNinePatchLayerImpl::~WebNinePatchLayerImpl()
+{
+}
+
+WebLayer* WebNinePatchLayerImpl::layer()
+{
+ return m_layer.get();
+}
+
+void WebNinePatchLayerImpl::setBitmap(const SkBitmap& bitmap, const WebRect& aperture) {
+ static_cast<NinePatchLayer*>(m_layer->layer())->setBitmap(bitmap, gfx::Rect(aperture));
+}
+
+} // namespace WebKit
diff --git a/webkit/compositor_bindings/web_nine_patch_layer_impl.h b/webkit/compositor_bindings/web_nine_patch_layer_impl.h
new file mode 100644
index 0000000..02605d8
--- /dev/null
+++ b/webkit/compositor_bindings/web_nine_patch_layer_impl.h
@@ -0,0 +1,31 @@
+// 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 WebNinePatchLayerImpl_h
+#define WebNinePatchLayerImpl_h
+
+#include "web_layer_impl.h"
+#include "base/memory/scoped_ptr.h"
+#include "SkBitmap.h"
+
+namespace WebKit {
+
+class WebLayerImpl;
+
+class WebNinePatchLayerImpl {
+public:
+ WebNinePatchLayerImpl();
+ virtual ~WebNinePatchLayerImpl();
+
+ WebLayer* layer();
+
+ void setBitmap(const SkBitmap& bitmap, const WebRect& aperture);
+
+private:
+ scoped_ptr<WebLayerImpl> m_layer;
+};
+
+} // namespace WebKit
+
+#endif