summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/tests/TreeManager_test.cpp
diff options
context:
space:
mode:
authorChris Craik <ccraik@google.com>2011-11-15 11:28:34 -0800
committerChris Craik <ccraik@google.com>2011-11-16 16:19:16 -0800
commitdfd2fb1ed3c17d0cbb4af895f74704c22130587f (patch)
tree7585dc40af1e239b777c4a339bc4ae128e796d73 /Source/WebCore/tests/TreeManager_test.cpp
parentd34224ca67791aa7215160c7be4900f965f79eea (diff)
downloadexternal_webkit-dfd2fb1ed3c17d0cbb4af895f74704c22130587f.zip
external_webkit-dfd2fb1ed3c17d0cbb4af895f74704c22130587f.tar.gz
external_webkit-dfd2fb1ed3c17d0cbb4af895f74704c22130587f.tar.bz2
synchronous layer updates, and animation deferral during paint
bug:5522081 bug:5239801 bug:5297563 Change-Id: I600f66999e093f720a8ea97ef3e15d3d1d297a8f
Diffstat (limited to 'Source/WebCore/tests/TreeManager_test.cpp')
-rw-r--r--Source/WebCore/tests/TreeManager_test.cpp407
1 files changed, 407 insertions, 0 deletions
diff --git a/Source/WebCore/tests/TreeManager_test.cpp b/Source/WebCore/tests/TreeManager_test.cpp
new file mode 100644
index 0000000..3837627
--- /dev/null
+++ b/Source/WebCore/tests/TreeManager_test.cpp
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "SkRefCnt.h"
+#include "TransformationMatrix.h"
+#include "IntRect.h"
+#include "Layer.h"
+#include "LayerAndroid.h"
+#include "TreeManager.h"
+#include "SkPicture.h"
+
+#include <cutils/log.h>
+#include <wtf/text/CString.h>
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager_test", __VA_ARGS__)
+
+namespace WebCore {
+
+// Used for testing simple cases for tree painting, drawing, swapping
+class TestLayer : public Layer {
+public:
+ TestLayer()
+ : m_isDrawing(false)
+ , m_isPainting(false)
+ , m_isDonePainting(false)
+ , m_drawCount(0)
+ {}
+
+ bool m_isDrawing;
+ bool m_isPainting;
+ bool m_isDonePainting;
+ double m_drawCount;
+
+ bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) {
+ m_drawCount++;
+ return false;
+ }
+
+ bool isReady() {
+ return m_isDonePainting;
+ }
+
+ void setIsDrawing(bool isDrawing) {
+ m_isDrawing = isDrawing;
+ if (isDrawing)
+ m_isPainting = false;
+ }
+
+ void setIsPainting(Layer* drawingTree) {
+ m_isPainting = true;
+ m_isDonePainting = false;
+ setIsDrawing(false);
+ }
+};
+
+// Used for testing complex trees, and painted surfaces
+class TestLayerAndroid : public LayerAndroid {
+public:
+ TestLayerAndroid(SkPicture* picture) : LayerAndroid(picture)
+ , m_isDonePainting(false)
+ , m_drawCount(0)
+ {}
+
+ TestLayerAndroid(const TestLayerAndroid& testLayer) : LayerAndroid(testLayer)
+ , m_isDonePainting(testLayer.m_isDonePainting)
+ , m_drawCount(testLayer.m_drawCount)
+ {
+ XLOGC("copying TLA %p as %p", &testLayer, this);
+ }
+
+ bool m_isDonePainting;
+ double m_drawCount;
+
+ bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) {
+ m_drawCount++;
+ return false;
+ }
+
+ bool isReady() {
+ return m_isDonePainting;
+ }
+
+ LayerAndroid* copy() const { return new TestLayerAndroid(*this); }
+};
+
+class TreeManagerTest : public testing::Test {
+protected:
+ IntRect m_iRect;
+ SkRect m_sRect;
+ double m_scale;
+
+ void allocLayerWithPicture(bool useTestLayer, LayerAndroid** layerHandle, SkPicture** pictureHandle) {
+ SkPicture* p = new SkPicture();
+ p->beginRecording(16,16, 0);
+ p->endRecording();
+
+ LayerAndroid* l;
+ if (useTestLayer)
+ l = new TestLayerAndroid(p);
+ else
+ l = new LayerAndroid(p);
+ l->setSize(16, 16);
+ SkSafeUnref(p); // layer takes sole ownership of picture
+
+ if (layerHandle)
+ *layerHandle = l;
+ if (pictureHandle)
+ *pictureHandle = p;
+ }
+
+ bool drawGL(TreeManager& manager, bool* swappedPtr) {
+ // call draw gl here in one place, so that when its parameters change,
+ // the tests only have to be updated in one place
+ return manager.drawGL(0, m_iRect, m_sRect, m_scale, false, swappedPtr, 0);
+ }
+
+ virtual void SetUp() {
+ m_iRect = IntRect(0, 0, 1, 1);
+ m_sRect = SkRect::MakeWH(1, 1);
+ m_scale = 1.0;
+ }
+ virtual void TearDown() { }
+};
+
+TEST_F(TreeManagerTest, EmptyTree_DoesntRedraw) {
+ TreeManager manager;
+
+ drawGL(manager, false);
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_SingleTree_SwapCheck) {
+ TreeManager manager;
+ TestLayer layer;
+
+ // initialize with tree, should be painting
+ manager.updateWithTree(&layer, true);
+
+ ASSERT_TRUE(layer.m_isPainting);
+ ASSERT_FALSE(layer.m_isDrawing);
+
+ // should not call swap, and return true since content isn't done
+ for (int i = 1; i < 6; i++) {
+ bool swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped);
+ ASSERT_EQ(layer.m_drawCount, 0);
+ }
+
+ layer.m_isDonePainting = true;
+
+ // swap content, should return false since no new picture
+ bool swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped);
+ ASSERT_EQ(layer.m_drawCount, 1); // verify layer drawn
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_SingleTree_RefCountCorrectly) {
+ TreeManager manager;
+ TestLayer* layer = new TestLayer();
+ ASSERT_EQ(layer->getRefCnt(), 1);
+
+ // initialize with tree, should be painting
+ manager.updateWithTree(layer, true);
+ ASSERT_EQ(layer->getRefCnt(), 2);
+
+ layer->m_isDonePainting = true;
+ ASSERT_FALSE(drawGL(manager, 0));
+
+ // should be drawing
+ ASSERT_EQ(layer->getRefCnt(), 2);
+
+ manager.updateWithTree(0, false);
+
+ // layer should be removed
+ ASSERT_EQ(layer->getRefCnt(), 1);
+ SkSafeUnref(layer);
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_TwoTreeFlush_PaintDrawRefCheck) {
+ TreeManager manager;
+ TestLayer* firstLayer = new TestLayer();
+ TestLayer* secondLayer = new TestLayer();
+ ASSERT_EQ(firstLayer->getRefCnt(), 1);
+ ASSERT_EQ(secondLayer->getRefCnt(), 1);
+
+ ///// ENQUEUE 2 TREES
+
+ // first starts painting
+ manager.updateWithTree(firstLayer, true);
+ ASSERT_TRUE(firstLayer->m_isPainting);
+ ASSERT_FALSE(firstLayer->m_isDrawing);
+
+ // second is queued
+ manager.updateWithTree(secondLayer, false);
+ ASSERT_FALSE(secondLayer->m_isPainting);
+ ASSERT_FALSE(secondLayer->m_isDrawing);
+
+ // nothing changes
+ ASSERT_TRUE(drawGL(manager, 0));
+
+ ////////// FIRST FINISHES PAINTING, SWAP THE TREES
+
+ firstLayer->m_isDonePainting = true;
+ bool swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped);
+
+ // first is drawing
+ ASSERT_EQ(firstLayer->m_drawCount, 1);
+ ASSERT_FALSE(firstLayer->m_isPainting);
+ ASSERT_TRUE(firstLayer->m_isDrawing);
+ ASSERT_EQ(firstLayer->getRefCnt(), 2);
+
+ // second is painting (and hasn't drawn)
+ ASSERT_EQ(secondLayer->m_drawCount, 0);
+ ASSERT_TRUE(secondLayer->m_isPainting);
+ ASSERT_FALSE(secondLayer->m_isDrawing);
+ ASSERT_EQ(secondLayer->getRefCnt(), 2);
+
+ ////////// SECOND FINISHES PAINTING, SWAP AGAIN
+
+ secondLayer->m_isDonePainting = true;
+
+ // draw again, swap, first should be deleted
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped)); // no painting layer
+ ASSERT_TRUE(swapped);
+
+ // first layer gone!
+ ASSERT_EQ(firstLayer->getRefCnt(), 1);
+ SkSafeUnref(firstLayer);
+
+ // second is drawing
+ ASSERT_EQ(secondLayer->m_drawCount, 1);
+ ASSERT_FALSE(secondLayer->m_isPainting);
+ ASSERT_TRUE(secondLayer->m_isDrawing);
+ ASSERT_EQ(secondLayer->getRefCnt(), 2);
+
+ ////////// INSERT NULL, BOTH TREES NOW REMOVED
+
+ // insert null tree, which should deref secondLayer immediately
+ manager.updateWithTree(0, false);
+ ASSERT_EQ(secondLayer->getRefCnt(), 1);
+ SkSafeUnref(secondLayer);
+
+ // nothing to draw or swap
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped);
+}
+
+TEST_F(TreeManagerTest, LayerAndroidTree_PictureRefCount) {
+ RenderLayer* renderLayer = 0;
+ LayerAndroid* l;
+ SkPicture* p;
+ allocLayerWithPicture(false, &l, &p);
+ ASSERT_TRUE(l->needsTexture());
+ SkSafeRef(p); // ref picture locally so it exists after layer (so we can see
+ // layer derefs it)
+
+ ASSERT_EQ(l->getRefCnt(), 1);
+ ASSERT_EQ(p->getRefCnt(), 2);
+ SkSafeUnref(l);
+
+ ASSERT_EQ(p->getRefCnt(), 1);
+ SkSafeUnref(p);
+}
+
+TEST_F(TreeManagerTest, LayerAndroidTree_PaintTreeWithPictures) {
+ XLOGC("STARTING PAINT TEST");
+
+ TreeManager manager;
+ RenderLayer* renderLayer = 0;
+ LayerAndroid root(renderLayer);
+ LayerAndroid* noPaintChild = new LayerAndroid(renderLayer);
+ root.addChild(noPaintChild);
+
+ root.showLayer(0);
+
+ ASSERT_EQ(noPaintChild->getRefCnt(), 2);
+
+
+ LayerAndroid* copy = new LayerAndroid(root);
+ copy->showLayer(0);
+ manager.updateWithTree(copy, true);
+
+
+ // no painting layer, should swap immediately
+ bool swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped);
+
+
+ ////////// add 2 painting layers, push new tree copy into tree manager
+
+ LayerAndroid* paintChildA;
+ allocLayerWithPicture(true, &paintChildA, 0);
+ noPaintChild->addChild(paintChildA);
+ ASSERT_TRUE(paintChildA->needsTexture());
+
+ LayerAndroid* paintChildB;
+ allocLayerWithPicture(true, &paintChildB, 0);
+ noPaintChild->addChild(paintChildB);
+ ASSERT_TRUE(paintChildB->needsTexture());
+
+ LayerAndroid* copy1 = new LayerAndroid(root);
+ copy1->showLayer(0);
+ manager.updateWithTree(copy1, false);
+
+ swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped); // painting layers not ready
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2);
+
+ ////////// remove painting layer, add new painting layer, push new tree copy into tree manager
+
+ LayerAndroid* paintChildC;
+ allocLayerWithPicture(true, &paintChildC, 0);
+ noPaintChild->addChild(paintChildC);
+ ASSERT_TRUE(paintChildC->needsTexture());
+
+ paintChildB->detachFromParent();
+ ASSERT_EQ(paintChildB->getRefCnt(), 1);
+ SkSafeUnref(paintChildB);
+
+ LayerAndroid* copy2 = new LayerAndroid(root);
+ copy2->showLayer(0);
+ manager.updateWithTree(copy2, false);
+
+ swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_FALSE(swapped); // painting layers not ready
+
+
+ ////////// swap layers
+
+ static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(0))->m_isDonePainting = true;
+ static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(1))->m_isDonePainting = true;
+
+ XLOGC("painting should be %p, queued %p", copy1, copy2);
+ swapped = false;
+ ASSERT_TRUE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped); // paint complete, new layer tree to paint
+ XLOGC("drawing should be %p, painting %p", copy1, copy2);
+
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 3);
+
+
+ ////////// swap layers again
+
+ static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(0))->m_isDonePainting = true;
+ static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(1))->m_isDonePainting = true;
+
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2);
+
+ ////////// remove all painting layers
+
+ paintChildA->detachFromParent();
+ SkSafeUnref(paintChildA);
+ paintChildC->detachFromParent();
+ SkSafeUnref(paintChildC);
+
+
+ copy = new LayerAndroid(root);
+ copy->showLayer(0);
+ manager.updateWithTree(copy, false);
+
+ swapped = false;
+ ASSERT_FALSE(drawGL(manager, &swapped));
+ ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint
+
+ ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 0);
+}
+
+} // namespace WebCore