diff options
author | Chris Craik <ccraik@google.com> | 2011-11-15 11:28:34 -0800 |
---|---|---|
committer | Chris Craik <ccraik@google.com> | 2011-11-16 16:19:16 -0800 |
commit | dfd2fb1ed3c17d0cbb4af895f74704c22130587f (patch) | |
tree | 7585dc40af1e239b777c4a339bc4ae128e796d73 /Source/WebCore/tests/TreeManager_test.cpp | |
parent | d34224ca67791aa7215160c7be4900f965f79eea (diff) | |
download | external_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.cpp | 407 |
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 |