diff --git a/engine/core/rendering/RenderView.h b/engine/core/rendering/RenderView.h index 8f45f3a89e2..5e4a17f98bd 100644 --- a/engine/core/rendering/RenderView.h +++ b/engine/core/rendering/RenderView.h @@ -26,7 +26,6 @@ #include "core/rendering/LayoutState.h" #include "core/rendering/PaintInvalidationState.h" #include "core/rendering/RenderBlockFlow.h" -#include "platform/PODFreeListArena.h" #include "platform/scroll/ScrollableArea.h" #include "wtf/OwnPtr.h" diff --git a/engine/platform/BUILD.gn b/engine/platform/BUILD.gn index 1d8c372ab4e..583cdb0a95e 100644 --- a/engine/platform/BUILD.gn +++ b/engine/platform/BUILD.gn @@ -128,11 +128,6 @@ component("platform") { "MIMETypeRegistry.h", "NotImplemented.cpp", "NotImplemented.h", - "PODArena.h", - "PODFreeListArena.h", - "PODInterval.h", - "PODIntervalTree.h", - "PODRedBlackTree.h", "ParsingUtilities.h", "Partitions.cpp", "Partitions.h", @@ -289,8 +284,6 @@ component("platform") { "fonts/skia/FontPlatformDataSkia.cpp", "fonts/skia/SimpleFontDataSkia.cpp", "geometry/FloatBoxExtent.h", - "geometry/FloatPolygon.cpp", - "geometry/FloatPolygon.h", "geometry/FloatPoint.cpp", "geometry/FloatPoint.h", "geometry/FloatPoint3D.cpp", @@ -717,10 +710,6 @@ test("platform_unittests") { "DecimalTest.cpp", "LayoutUnitTest.cpp", "LifecycleContextTest.cpp", - "PODArenaTest.cpp", - "PODFreeListArenaTest.cpp", - "PODIntervalTreeTest.cpp", - "PODRedBlackTreeTest.cpp", "PurgeableVectorTest.cpp", "SharedBufferTest.cpp", "TestingPlatformSupport.cpp", @@ -737,7 +726,6 @@ test("platform_unittests") { "fonts/android/FontCacheAndroidTest.cpp", "geometry/FloatBoxTest.cpp", "geometry/FloatBoxTestHelpers.cpp", - "geometry/FloatPolygonTest.cpp", "geometry/FloatRoundedRectTest.cpp", "geometry/RegionTest.cpp", "geometry/RoundedRectTest.cpp", @@ -749,7 +737,6 @@ test("platform_unittests") { "image-decoders/ImageDecoderTest.cpp", "mac/ScrollElasticityControllerTest.mm", "network/HTTPParsersTest.cpp", - "testing/ArenaTestHelpers.h", "testing/TreeTestHelpers.cpp", "testing/TreeTestHelpers.h", "testing/RunAllTests.cpp", diff --git a/engine/platform/PODArena.h b/engine/platform/PODArena.h deleted file mode 100644 index 604d513cf75..00000000000 --- a/engine/platform/PODArena.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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. - */ - -#ifndef PODArena_h -#define PODArena_h - -#include -#include "wtf/Assertions.h" -#include "wtf/FastMalloc.h" -#include "wtf/Noncopyable.h" -#include "wtf/OwnPtr.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/RefCounted.h" -#include "wtf/Vector.h" - -namespace blink { - -// An arena which allocates only Plain Old Data (POD), or classes and -// structs bottoming out in Plain Old Data. NOTE: the constructors of -// the objects allocated in this arena are called, but _not_ their -// destructors. - -class PODArena final : public RefCounted { -public: - // The arena is configured with an allocator, which is responsible - // for allocating and freeing chunks of memory at a time. - class Allocator : public RefCounted { - public: - virtual void* allocate(size_t size) = 0; - virtual void free(void* ptr) = 0; - protected: - virtual ~Allocator() { } - friend class WTF::RefCounted; - }; - - // The Arena's default allocator, which uses fastMalloc and - // fastFree to allocate chunks of storage. - class FastMallocAllocator : public Allocator { - public: - static PassRefPtr create() - { - return adoptRef(new FastMallocAllocator); - } - - virtual void* allocate(size_t size) override { return fastMalloc(size); } - virtual void free(void* ptr) override { fastFree(ptr); } - - protected: - FastMallocAllocator() { } - }; - - // Creates a new PODArena configured with a FastMallocAllocator. - static PassRefPtr create() - { - return adoptRef(new PODArena); - } - - // Creates a new PODArena configured with the given Allocator. - static PassRefPtr create(PassRefPtr allocator) - { - return adoptRef(new PODArena(allocator)); - } - - // Allocates an object from the arena. - template T* allocateObject() - { - return new (allocateBase()) T(); - } - - // Allocates an object from the arena, calling a single-argument constructor. - template T* allocateObject(const Argument1Type& argument1) - { - return new (allocateBase()) T(argument1); - } - - // The initial size of allocated chunks; increases as necessary to - // satisfy large allocations. Mainly public for unit tests. - enum { - DefaultChunkSize = 16384 - }; - -protected: - friend class WTF::RefCounted; - - PODArena() - : m_allocator(FastMallocAllocator::create()) - , m_current(0) - , m_currentChunkSize(DefaultChunkSize) { } - - explicit PODArena(PassRefPtr allocator) - : m_allocator(allocator) - , m_current(0) - , m_currentChunkSize(DefaultChunkSize) { } - - // Returns the alignment requirement for classes and structs on the - // current platform. - template static size_t minAlignment() - { - return WTF_ALIGN_OF(T); - } - - template void* allocateBase() - { - void* ptr = 0; - size_t roundedSize = roundUp(sizeof(T), minAlignment()); - if (m_current) - ptr = m_current->allocate(roundedSize); - - if (!ptr) { - if (roundedSize > m_currentChunkSize) - m_currentChunkSize = roundedSize; - m_chunks.append(adoptPtr(new Chunk(m_allocator.get(), m_currentChunkSize))); - m_current = m_chunks.last().get(); - ptr = m_current->allocate(roundedSize); - } - return ptr; - } - - // Rounds up the given allocation size to the specified alignment. - size_t roundUp(size_t size, size_t alignment) - { - ASSERT(!(alignment % 2)); - return (size + alignment - 1) & ~(alignment - 1); - } - - // Manages a chunk of memory and individual allocations out of it. - class Chunk final { - WTF_MAKE_NONCOPYABLE(Chunk); - public: - // Allocates a block of memory of the given size from the passed - // Allocator. - Chunk(Allocator* allocator, size_t size) - : m_allocator(allocator) - , m_size(size) - , m_currentOffset(0) - { - m_base = static_cast(m_allocator->allocate(size)); - } - - // Frees the memory allocated from the Allocator in the - // constructor. - ~Chunk() - { - m_allocator->free(m_base); - } - - // Returns a pointer to "size" bytes of storage, or 0 if this - // Chunk could not satisfy the allocation. - void* allocate(size_t size) - { - // Check for overflow - if (m_currentOffset + size < m_currentOffset) - return 0; - - if (m_currentOffset + size > m_size) - return 0; - - void* result = m_base + m_currentOffset; - m_currentOffset += size; - return result; - } - - protected: - Allocator* m_allocator; - uint8_t* m_base; - size_t m_size; - size_t m_currentOffset; - }; - - RefPtr m_allocator; - Chunk* m_current; - size_t m_currentChunkSize; - Vector > m_chunks; -}; - -} // namespace blink - -#endif // PODArena_h diff --git a/engine/platform/PODArenaTest.cpp b/engine/platform/PODArenaTest.cpp deleted file mode 100644 index 8e30dc3e658..00000000000 --- a/engine/platform/PODArenaTest.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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 "platform/PODArena.h" - -#include "platform/testing/ArenaTestHelpers.h" -#include "wtf/FastMalloc.h" -#include "wtf/RefPtr.h" - -#include -#include - -namespace blink { - -using ArenaTestHelpers::TrackedAllocator; - -namespace { - -// A couple of simple structs to allocate. -struct TestClass1 { - TestClass1() - : x(0), y(0), z(0), w(1) { } - - float x, y, z, w; -}; - -struct TestClass2 { - TestClass2() - : a(1), b(2), c(3), d(4) { } - - float a, b, c, d; -}; - -} // anonymous namespace - -class PODArenaTest : public testing::Test { -}; - -// Make sure the arena can successfully allocate from more than one -// region. -TEST_F(PODArenaTest, CanAllocateFromMoreThanOneRegion) -{ - RefPtr allocator = TrackedAllocator::create(); - RefPtr arena = PODArena::create(allocator); - int numIterations = 10 * PODArena::DefaultChunkSize / sizeof(TestClass1); - for (int i = 0; i < numIterations; ++i) - arena->allocateObject(); - EXPECT_GT(allocator->numRegions(), 1); -} - -// Make sure the arena frees all allocated regions during destruction. -TEST_F(PODArenaTest, FreesAllAllocatedRegions) -{ - RefPtr allocator = TrackedAllocator::create(); - { - RefPtr arena = PODArena::create(allocator); - for (int i = 0; i < 3; i++) - arena->allocateObject(); - EXPECT_GT(allocator->numRegions(), 0); - } - EXPECT_TRUE(allocator->isEmpty()); -} - -// Make sure the arena runs constructors of the objects allocated within. -TEST_F(PODArenaTest, RunsConstructors) -{ - RefPtr arena = PODArena::create(); - for (int i = 0; i < 10000; i++) { - TestClass1* tc1 = arena->allocateObject(); - EXPECT_EQ(0, tc1->x); - EXPECT_EQ(0, tc1->y); - EXPECT_EQ(0, tc1->z); - EXPECT_EQ(1, tc1->w); - TestClass2* tc2 = arena->allocateObject(); - EXPECT_EQ(1, tc2->a); - EXPECT_EQ(2, tc2->b); - EXPECT_EQ(3, tc2->c); - EXPECT_EQ(4, tc2->d); - } -} - -} // namespace blink diff --git a/engine/platform/PODFreeListArena.h b/engine/platform/PODFreeListArena.h deleted file mode 100644 index 9e965c152e5..00000000000 --- a/engine/platform/PODFreeListArena.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. - */ - -#ifndef PODFreeListArena_h -#define PODFreeListArena_h - -#include "platform/PODArena.h" - -namespace blink { - -template -class PODFreeListArena : public RefCounted > { -public: - static PassRefPtr create() - { - return adoptRef(new PODFreeListArena); - } - - // Creates a new PODFreeListArena configured with the given Allocator. - static PassRefPtr create(PassRefPtr allocator) - { - return adoptRef(new PODFreeListArena(allocator)); - } - - // Allocates an object from the arena. - T* allocateObject() - { - void* ptr = allocateFromFreeList(); - - if (ptr) { - // Use placement operator new to allocate a T at this location. - new(ptr) T(); - return static_cast(ptr); - } - - // PODArena::allocateObject calls T's constructor. - return static_cast(m_arena->allocateObject()); - } - - template T* allocateObject(const Argument1Type& argument1) - { - void* ptr = allocateFromFreeList(); - - if (ptr) { - // Use placement operator new to allocate a T at this location. - new(ptr) T(argument1); - return static_cast(ptr); - } - - // PODArena::allocateObject calls T's constructor. - return static_cast(m_arena->allocateObject(argument1)); - } - - void freeObject(T* ptr) - { - FixedSizeMemoryChunk* oldFreeList = m_freeList; - - m_freeList = reinterpret_cast(ptr); - m_freeList->next = oldFreeList; - } - -private: - PODFreeListArena() - : m_arena(PODArena::create()), m_freeList(0) { } - - explicit PODFreeListArena(PassRefPtr allocator) - : m_arena(PODArena::create(allocator)), m_freeList(0) { } - - ~PODFreeListArena() { } - - void* allocateFromFreeList() - { - if (m_freeList) { - void* memory = m_freeList; - m_freeList = m_freeList->next; - return memory; - } - return 0; - } - - int getFreeListSizeForTesting() const - { - int total = 0; - for (FixedSizeMemoryChunk* cur = m_freeList; cur; cur = cur->next) { - total++; - } - return total; - } - - RefPtr m_arena; - - // This free list contains pointers within every chunk that's been allocated so - // far. None of the individual chunks can be freed until the arena is - // destroyed. - struct FixedSizeMemoryChunk { - FixedSizeMemoryChunk* next; - }; - FixedSizeMemoryChunk* m_freeList; - - COMPILE_ASSERT(sizeof(T) >= sizeof(FixedSizeMemoryChunk), PODFreeListArena_type_should_be_larger); - - friend class WTF::RefCounted; - friend class PODFreeListArenaTest; -}; - -} // namespace blink - -#endif diff --git a/engine/platform/PODFreeListArenaTest.cpp b/engine/platform/PODFreeListArenaTest.cpp deleted file mode 100644 index 77b27727429..00000000000 --- a/engine/platform/PODFreeListArenaTest.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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 "platform/PODFreeListArena.h" - -#include "platform/testing/ArenaTestHelpers.h" -#include "wtf/FastMalloc.h" -#include "wtf/RefPtr.h" - -#include - -namespace blink { - -using ArenaTestHelpers::TrackedAllocator; - -namespace { - -// A couple of simple structs to allocate. -struct TestClass1 { - TestClass1() - : x(0), y(0), z(0), w(1) { } - - float x, y, z, w; -}; - -struct TestClass2 { - TestClass2() - : padding(0) - { - static int TestIds = 0; - id = TestIds++; - } - int id; - int padding; -}; - -} // anonymous namespace - -class PODFreeListArenaTest : public testing::Test { -protected: - int getFreeListSize(const PassRefPtr > arena) const - { - return arena->getFreeListSizeForTesting(); - } -}; - -// Make sure the arena can successfully allocate from more than one -// region. -TEST_F(PODFreeListArenaTest, CanAllocateFromMoreThanOneRegion) -{ - RefPtr allocator = TrackedAllocator::create(); - RefPtr > arena = PODFreeListArena::create(allocator); - int numIterations = 10 * PODArena::DefaultChunkSize / sizeof(TestClass1); - for (int i = 0; i < numIterations; ++i) - arena->allocateObject(); - EXPECT_GT(allocator->numRegions(), 1); -} - -// Make sure the arena frees all allocated regions during destruction. -TEST_F(PODFreeListArenaTest, FreesAllAllocatedRegions) -{ - RefPtr allocator = TrackedAllocator::create(); - { - RefPtr > arena = PODFreeListArena::create(allocator); - for (int i = 0; i < 3; i++) - arena->allocateObject(); - EXPECT_GT(allocator->numRegions(), 0); - } - EXPECT_TRUE(allocator->isEmpty()); -} - -// Make sure the arena runs constructors of the objects allocated within. -TEST_F(PODFreeListArenaTest, RunsConstructorsOnNewObjects) -{ - RefPtr > arena = PODFreeListArena::create(); - for (int i = 0; i < 10000; i++) { - TestClass1* tc1 = arena->allocateObject(); - EXPECT_EQ(0, tc1->x); - EXPECT_EQ(0, tc1->y); - EXPECT_EQ(0, tc1->z); - EXPECT_EQ(1, tc1->w); - } -} - -// Make sure the arena runs constructors of the objects allocated within. -TEST_F(PODFreeListArenaTest, RunsConstructorsOnReusedObjects) -{ - std::set objects; - RefPtr > arena = PODFreeListArena::create(); - for (int i = 0; i < 100; i++) { - TestClass1* tc1 = arena->allocateObject(); - tc1->x = 100; - tc1->y = 101; - tc1->z = 102; - tc1->w = 103; - - objects.insert(tc1); - } - for (std::set::iterator it = objects.begin(); it != objects.end(); ++it) { - arena->freeObject(*it); - } - for (int i = 0; i < 100; i++) { - TestClass1* cur = arena->allocateObject(); - EXPECT_TRUE(objects.find(cur) != objects.end()); - EXPECT_EQ(0, cur->x); - EXPECT_EQ(0, cur->y); - EXPECT_EQ(0, cur->z); - EXPECT_EQ(1, cur->w); - - objects.erase(cur); - } -} - -// Make sure freeObject puts the object in the free list. -TEST_F(PODFreeListArenaTest, AddsFreedObjectsToFreedList) -{ - std::vector objects; - RefPtr > arena = PODFreeListArena::create(); - for (int i = 0; i < 100; i++) { - objects.push_back(arena->allocateObject()); - } - for (std::vector::iterator it = objects.begin(); it != objects.end(); ++it) { - arena->freeObject(*it); - } - EXPECT_EQ(100, getFreeListSize(arena)); -} - -// Make sure allocations use previously freed memory. -TEST_F(PODFreeListArenaTest, ReusesPreviouslyFreedObjects) -{ - std::set objects; - RefPtr > arena = PODFreeListArena::create(); - for (int i = 0; i < 100; i++) { - objects.insert(arena->allocateObject()); - } - for (std::set::iterator it = objects.begin(); it != objects.end(); ++it) { - arena->freeObject(*it); - } - for (int i = 0; i < 100; i++) { - TestClass2* cur = arena->allocateObject(); - EXPECT_TRUE(objects.find(cur) != objects.end()); - EXPECT_TRUE(cur->id >= 100 && cur->id < 200); - objects.erase(cur); - } -} - -} // namespace blink diff --git a/engine/platform/PODInterval.h b/engine/platform/PODInterval.h deleted file mode 100644 index 394560d98fe..00000000000 --- a/engine/platform/PODInterval.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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. - */ - -#ifndef PODInterval_h -#define PODInterval_h - -#ifndef NDEBUG -#include "wtf/text/StringBuilder.h" -#endif - -namespace blink { - -// Class representing a closed interval which can hold an arbitrary -// Plain Old Datatype (POD) as its endpoints and a piece of user -// data. An important characteristic for the algorithms we use is that -// if two intervals have identical endpoints but different user data, -// they are not considered to be equal. This situation can arise when -// representing the vertical extents of bounding boxes of overlapping -// triangles, where the pointer to the triangle is the user data of -// the interval. -// -// *Note* that the destructors of type T and UserData will *not* be -// called by this class. They must not allocate any memory that is -// required to be cleaned up in their destructors. -// -// The following constructors and operators must be implemented on -// type T: -// -// - Copy constructor (if user data is desired) -// - operator< -// - operator== -// - operator= -// -// If the UserData type is specified, it must support a copy -// constructor and assignment operator. -// -// In debug mode, printing of intervals and the data they contain is -// enabled. This requires the following template specializations to be -// available: -// -// template<> struct ValueToString { -// static String string(const T& t); -// }; -// template<> struct ValueToString { -// static String string(const UserData& t); -// }; -// -// Note that this class requires a copy constructor and assignment -// operator in order to be stored in the red-black tree. - -#ifndef NDEBUG -template -struct ValueToString; -#endif - -template -class PODInterval { -public: - // Constructor from endpoints. This constructor only works when the - // UserData type is a pointer or other type which can be initialized - // with 0. - PODInterval(const T& low, const T& high) - : m_low(low) - , m_high(high) - , m_data(0) - , m_maxHigh(high) - { - } - - // Constructor from two endpoints plus explicit user data. - PODInterval(const T& low, const T& high, const UserData data) - : m_low(low) - , m_high(high) - , m_data(data) - , m_maxHigh(high) - { - } - - const T& low() const { return m_low; } - const T& high() const { return m_high; } - const UserData& data() const { return m_data; } - - bool overlaps(const T& low, const T& high) const - { - if (this->high() < low) - return false; - if (high < this->low()) - return false; - return true; - } - - bool overlaps(const PODInterval& other) const - { - return overlaps(other.low(), other.high()); - } - - // Returns true if this interval is "less" than the other. The - // comparison is performed on the low endpoints of the intervals. - bool operator<(const PODInterval& other) const - { - return low() < other.low(); - } - - // Returns true if this interval is strictly equal to the other, - // including comparison of the user data. - bool operator==(const PODInterval& other) const - { - return (low() == other.low() && high() == other.high() && data() == other.data()); - } - - const T& maxHigh() const { return m_maxHigh; } - void setMaxHigh(const T& maxHigh) { m_maxHigh = maxHigh; } - -#ifndef NDEBUG - // Support for printing PODIntervals. - String toString() const - { - StringBuilder builder; - builder.appendLiteral("[PODInterval ("); - builder.append(ValueToString::string(low())); - builder.appendLiteral(", "); - builder.append(ValueToString::string(high())); - builder.appendLiteral("), data="); - builder.append(ValueToString::string(data())); - builder.appendLiteral(", maxHigh="); - builder.append(ValueToString::string(maxHigh())); - builder.append(']'); - return builder.toString(); - } -#endif - -private: - T m_low; - T m_high; - UserData m_data; - T m_maxHigh; -}; - -} // namespace blink - -#endif // PODInterval_h diff --git a/engine/platform/PODIntervalTree.h b/engine/platform/PODIntervalTree.h deleted file mode 100644 index 93f27eba0f4..00000000000 --- a/engine/platform/PODIntervalTree.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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. - */ - -#ifndef PODIntervalTree_h -#define PODIntervalTree_h - -#include "platform/PODArena.h" -#include "platform/PODInterval.h" -#include "platform/PODRedBlackTree.h" -#include "wtf/Assertions.h" -#include "wtf/Noncopyable.h" -#include "wtf/Vector.h" - -namespace blink { - -#ifndef NDEBUG -template -struct ValueToString; -#endif - -template -class PODIntervalSearchAdapter { -public: - typedef PODInterval IntervalType; - - PODIntervalSearchAdapter(Vector& result, const T& lowValue, const T& highValue) - : m_result(result) - , m_lowValue(lowValue) - , m_highValue(highValue) - { - } - - const T& lowValue() const { return m_lowValue; } - const T& highValue() const { return m_highValue; } - void collectIfNeeded(const IntervalType& data) const - { - if (data.overlaps(m_lowValue, m_highValue)) - m_result.append(data); - } - -private: - Vector& m_result; - T m_lowValue; - T m_highValue; -}; - -// An interval tree, which is a form of augmented red-black tree. It -// supports efficient (O(lg n)) insertion, removal and querying of -// intervals in the tree. -template -class PODIntervalTree final : public PODRedBlackTree > { - WTF_MAKE_NONCOPYABLE(PODIntervalTree); -public: - // Typedef to reduce typing when declaring intervals to be stored in - // this tree. - typedef PODInterval IntervalType; - typedef PODIntervalSearchAdapter IntervalSearchAdapterType; - - PODIntervalTree(UninitializedTreeEnum unitializedTree) - : PODRedBlackTree(unitializedTree) - { - init(); - } - - PODIntervalTree() - : PODRedBlackTree() - { - init(); - } - - explicit PODIntervalTree(PassRefPtr arena) - : PODRedBlackTree(arena) - { - init(); - } - - // Returns all intervals in the tree which overlap the given query - // interval. The returned intervals are sorted by increasing low - // endpoint. - Vector allOverlaps(const IntervalType& interval) const - { - Vector result; - allOverlaps(interval, result); - return result; - } - - // Returns all intervals in the tree which overlap the given query - // interval. The returned intervals are sorted by increasing low - // endpoint. - void allOverlaps(const IntervalType& interval, Vector& result) const - { - // Explicit dereference of "this" required because of - // inheritance rules in template classes. - IntervalSearchAdapterType adapter(result, interval.low(), interval.high()); - searchForOverlapsFrom(this->root(), adapter); - } - - template - void allOverlapsWithAdapter(AdapterType& adapter) const - { - // Explicit dereference of "this" required because of - // inheritance rules in template classes. - searchForOverlapsFrom(this->root(), adapter); - } - - // Helper to create interval objects. - static IntervalType createInterval(const T& low, const T& high, const UserData data = 0) - { - return IntervalType(low, high, data); - } - - virtual bool checkInvariants() const override - { - if (!PODRedBlackTree::checkInvariants()) - return false; - if (!this->root()) - return true; - return checkInvariantsFromNode(this->root(), 0); - } - -private: - typedef typename PODRedBlackTree::Node IntervalNode; - - // Initializes the tree. - void init() - { - // Explicit dereference of "this" required because of - // inheritance rules in template classes. - this->setNeedsFullOrderingComparisons(true); - } - - // Starting from the given node, adds all overlaps with the given - // interval to the result vector. The intervals are sorted by - // increasing low endpoint. - template - void searchForOverlapsFrom(IntervalNode* node, AdapterType& adapter) const - { - if (!node) - return; - - // Because the intervals are sorted by left endpoint, inorder - // traversal produces results sorted as desired. - - // See whether we need to traverse the left subtree. - IntervalNode* left = node->left(); - if (left - // This is phrased this way to avoid the need for operator - // <= on type T. - && !(left->data().maxHigh() < adapter.lowValue())) - searchForOverlapsFrom(left, adapter); - - // Check for overlap with current node. - adapter.collectIfNeeded(node->data()); - - // See whether we need to traverse the right subtree. - // This is phrased this way to avoid the need for operator <= - // on type T. - if (!(adapter.highValue() < node->data().low())) - searchForOverlapsFrom(node->right(), adapter); - } - - virtual bool updateNode(IntervalNode* node) override - { - // Would use const T&, but need to reassign this reference in this - // function. - const T* curMax = &node->data().high(); - IntervalNode* left = node->left(); - if (left) { - if (*curMax < left->data().maxHigh()) - curMax = &left->data().maxHigh(); - } - IntervalNode* right = node->right(); - if (right) { - if (*curMax < right->data().maxHigh()) - curMax = &right->data().maxHigh(); - } - // This is phrased like this to avoid needing operator!= on type T. - if (!(*curMax == node->data().maxHigh())) { - node->data().setMaxHigh(*curMax); - return true; - } - return false; - } - - bool checkInvariantsFromNode(IntervalNode* node, T* currentMaxValue) const - { - // These assignments are only done in order to avoid requiring - // a default constructor on type T. - T leftMaxValue(node->data().maxHigh()); - T rightMaxValue(node->data().maxHigh()); - IntervalNode* left = node->left(); - IntervalNode* right = node->right(); - if (left) { - if (!checkInvariantsFromNode(left, &leftMaxValue)) - return false; - } - if (right) { - if (!checkInvariantsFromNode(right, &rightMaxValue)) - return false; - } - if (!left && !right) { - // Base case. - if (currentMaxValue) - *currentMaxValue = node->data().high(); - return (node->data().high() == node->data().maxHigh()); - } - T localMaxValue(node->data().maxHigh()); - if (!left || !right) { - if (left) - localMaxValue = leftMaxValue; - else - localMaxValue = rightMaxValue; - } else { - localMaxValue = (leftMaxValue < rightMaxValue) ? rightMaxValue : leftMaxValue; - } - if (localMaxValue < node->data().high()) - localMaxValue = node->data().high(); - if (!(localMaxValue == node->data().maxHigh())) { -#ifndef NDEBUG - String localMaxValueString = ValueToString::string(localMaxValue); - WTF_LOG_ERROR("PODIntervalTree verification failed at node 0x%p: localMaxValue=%s and data=%s", - node, localMaxValueString.utf8().data(), node->data().toString().utf8().data()); -#endif - return false; - } - if (currentMaxValue) - *currentMaxValue = localMaxValue; - return true; - } -}; - -#ifndef NDEBUG -// Support for printing PODIntervals at the PODRedBlackTree level. -template -struct ValueToString > { - static String string(const PODInterval& interval) - { - return interval.toString(); - } -}; -#endif - -} // namespace blink - -#endif // PODIntervalTree_h diff --git a/engine/platform/PODIntervalTreeTest.cpp b/engine/platform/PODIntervalTreeTest.cpp deleted file mode 100644 index 497ac8011de..00000000000 --- a/engine/platform/PODIntervalTreeTest.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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. - */ - -// Tests for the interval tree class. - -#include "config.h" -#include "platform/PODIntervalTree.h" - -#include "platform/Logging.h" -#include "platform/testing/TreeTestHelpers.h" -#include "wtf/Vector.h" -#include "wtf/text/WTFString.h" - -#include - -namespace blink { - -using TreeTestHelpers::initRandom; -using TreeTestHelpers::nextRandom; - -#ifndef NDEBUG -template<> -struct ValueToString { - static String string(const float& value) { return String::number(value); } -}; - -template<> -struct ValueToString { - static String string(void* const& value) - { - return String::format("0x%p", value); - } -}; -#endif - -TEST(PODIntervalTreeTest, TestInsertion) -{ - PODIntervalTree tree; - tree.add(PODInterval(2, 4)); - ASSERT_TRUE(tree.checkInvariants()); -} - -TEST(PODIntervalTreeTest, TestInsertionAndQuery) -{ - PODIntervalTree tree; - tree.add(PODInterval(2, 4)); - ASSERT_TRUE(tree.checkInvariants()); - Vector > result = tree.allOverlaps(PODInterval(1, 3)); - EXPECT_EQ(1U, result.size()); - EXPECT_EQ(2, result[0].low()); - EXPECT_EQ(4, result[0].high()); -} - -TEST(PODIntervalTreeTest, TestQueryAgainstZeroSizeInterval) -{ - PODIntervalTree tree; - tree.add(PODInterval(1, 2.5)); - tree.add(PODInterval(3.5, 5)); - tree.add(PODInterval(2, 4)); - ASSERT_TRUE(tree.checkInvariants()); - Vector > result = tree.allOverlaps(PODInterval(3, 3)); - EXPECT_EQ(1U, result.size()); - EXPECT_EQ(2, result[0].low()); - EXPECT_EQ(4, result[0].high()); -} - -#ifndef NDEBUG -template<> -struct ValueToString { - static String string(int* const& value) - { - return String::format("0x%p", value); - } -}; -#endif - -TEST(PODIntervalTreeTest, TestDuplicateElementInsertion) -{ - PODIntervalTree tree; - int tmp1 = 1; - int tmp2 = 2; - typedef PODIntervalTree::IntervalType IntervalType; - IntervalType interval1(1, 3, &tmp1); - IntervalType interval2(1, 3, &tmp2); - tree.add(interval1); - tree.add(interval2); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(interval1)); - EXPECT_TRUE(tree.contains(interval2)); - EXPECT_TRUE(tree.remove(interval1)); - EXPECT_TRUE(tree.contains(interval2)); - EXPECT_FALSE(tree.contains(interval1)); - EXPECT_TRUE(tree.remove(interval2)); - EXPECT_EQ(0, tree.size()); -} - -namespace { - -struct UserData1 { -public: - UserData1() - : a(0), b(1) { } - - float a; - int b; -}; - -} // anonymous namespace - -#ifndef NDEBUG -template<> -struct ValueToString { - static String string(const UserData1& value) - { - return String("[UserData1 a=") + String::number(value.a) + " b=" + String::number(value.b) + "]"; - } -}; -#endif - -TEST(PODIntervalTreeTest, TestInsertionOfComplexUserData) -{ - PODIntervalTree tree; - UserData1 data1; - data1.a = 5; - data1.b = 6; - tree.add(tree.createInterval(2, 4, data1)); - ASSERT_TRUE(tree.checkInvariants()); -} - -TEST(PODIntervalTreeTest, TestQueryingOfComplexUserData) -{ - PODIntervalTree tree; - UserData1 data1; - data1.a = 5; - data1.b = 6; - tree.add(tree.createInterval(2, 4, data1)); - ASSERT_TRUE(tree.checkInvariants()); - Vector > overlaps = tree.allOverlaps(tree.createInterval(3, 5, data1)); - EXPECT_EQ(1U, overlaps.size()); - EXPECT_EQ(5, overlaps[0].data().a); - EXPECT_EQ(6, overlaps[0].data().b); -} - -namespace { - -class EndpointType1 { -public: - explicit EndpointType1(int value) - : m_value(value) { } - - int value() const { return m_value; } - - bool operator<(const EndpointType1& other) const { return m_value < other.m_value; } - bool operator==(const EndpointType1& other) const { return m_value == other.m_value; } - -private: - int m_value; - // These operators should not be called by the interval tree. - bool operator>(const EndpointType1& other); - bool operator<=(const EndpointType1& other); - bool operator>=(const EndpointType1& other); - bool operator!=(const EndpointType1& other); -}; - -} // anonymous namespace - -#ifndef NDEBUG -template<> -struct ValueToString { - static String string(const EndpointType1& value) - { - return String("[EndpointType1 value=") + String::number(value.value()) + "]"; - } -}; -#endif - -TEST(PODIntervalTreeTest, TestTreeDoesNotRequireMostOperators) -{ - PODIntervalTree tree; - tree.add(tree.createInterval(EndpointType1(1), EndpointType1(2))); - ASSERT_TRUE(tree.checkInvariants()); -} - -// Uncomment to debug a failure of the insertion and deletion test. Won't work -// in release builds. -// #define DEBUG_INSERTION_AND_DELETION_TEST - -#ifndef NDEBUG -template<> -struct ValueToString { - static String string(const int& value) { return String::number(value); } -}; -#endif - -namespace { - -void InsertionAndDeletionTest(int32_t seed, int treeSize) -{ - initRandom(seed); - int maximumValue = treeSize; - // Build the tree - PODIntervalTree tree; - Vector > addedElements; - Vector > removedElements; - for (int i = 0; i < treeSize; i++) { - int left = nextRandom(maximumValue); - int length = nextRandom(maximumValue); - PODInterval interval(left, left + length); - tree.add(interval); -#ifdef DEBUG_INSERTION_AND_DELETION_TEST - WTF_LOG_ERROR("*** Adding element %s", ValueToString >::string(interval).ascii().data()); -#endif - addedElements.append(interval); - } - // Churn the tree's contents. - // First remove half of the elements in random order. - for (int i = 0; i < treeSize / 2; i++) { - int index = nextRandom(addedElements.size()); -#ifdef DEBUG_INSERTION_AND_DELETION_TEST - WTF_LOG_ERROR("*** Removing element %s", ValueToString >::string(addedElements[index]).ascii().data()); -#endif - ASSERT_TRUE(tree.contains(addedElements[index])) << "Test failed for seed " << seed; - tree.remove(addedElements[index]); - removedElements.append(addedElements[index]); - addedElements.remove(index); - ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; - } - // Now randomly add or remove elements. - for (int i = 0; i < 2 * treeSize; i++) { - bool add = false; - if (!addedElements.size()) - add = true; - else if (!removedElements.size()) - add = false; - else - add = (nextRandom(2) == 1); - if (add) { - int index = nextRandom(removedElements.size()); -#ifdef DEBUG_INSERTION_AND_DELETION_TEST - WTF_LOG_ERROR("*** Adding element %s", ValueToString >::string(removedElements[index]).ascii().data()); -#endif - tree.add(removedElements[index]); - addedElements.append(removedElements[index]); - removedElements.remove(index); - } else { - int index = nextRandom(addedElements.size()); -#ifdef DEBUG_INSERTION_AND_DELETION_TEST - WTF_LOG_ERROR("*** Removing element %s", ValueToString >::string(addedElements[index]).ascii().data()); -#endif - ASSERT_TRUE(tree.contains(addedElements[index])) << "Test failed for seed " << seed; - ASSERT_TRUE(tree.remove(addedElements[index])) << "Test failed for seed " << seed; - removedElements.append(addedElements[index]); - addedElements.remove(index); - } - ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; - } -} - -} // anonymous namespace - -TEST(PODIntervalTreeTest, RandomDeletionAndInsertionRegressionTest1) -{ - InsertionAndDeletionTest(13972, 100); -} - -TEST(PODIntervalTreeTest, RandomDeletionAndInsertionRegressionTest2) -{ - InsertionAndDeletionTest(1283382113, 10); -} - -TEST(PODIntervalTreeTest, RandomDeletionAndInsertionRegressionTest3) -{ - // This is the sequence of insertions and deletions that triggered - // the failure in RandomDeletionAndInsertionRegressionTest2. - PODIntervalTree tree; - tree.add(tree.createInterval(0, 5)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(4, 5)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(8, 9)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(1, 4)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(3, 5)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(4, 12)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(0, 2)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(0, 2)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(9, 13)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(0, 1)); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(tree.createInterval(0, 2)); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(tree.createInterval(9, 13)); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(tree.createInterval(0, 2)); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(tree.createInterval(0, 1)); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(tree.createInterval(4, 5)); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(tree.createInterval(4, 12)); - ASSERT_TRUE(tree.checkInvariants()); -} - -TEST(PODIntervalTreeTest, RandomDeletionAndInsertionRegressionTest4) -{ - // Even further reduced test case for RandomDeletionAndInsertionRegressionTest3. - PODIntervalTree tree; - tree.add(tree.createInterval(0, 5)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(8, 9)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(1, 4)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(3, 5)); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(tree.createInterval(4, 12)); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(tree.createInterval(4, 12)); - ASSERT_TRUE(tree.checkInvariants()); -} - -} // namespace blink diff --git a/engine/platform/PODRedBlackTree.h b/engine/platform/PODRedBlackTree.h deleted file mode 100644 index 41ed7b97565..00000000000 --- a/engine/platform/PODRedBlackTree.h +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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. - */ - -// A red-black tree, which is a form of a balanced binary tree. It -// supports efficient insertion, deletion and queries of comparable -// elements. The same element may be inserted multiple times. The -// algorithmic complexity of common operations is: -// -// Insertion: O(lg(n)) -// Deletion: O(lg(n)) -// Querying: O(lg(n)) -// -// The data type T that is stored in this red-black tree must be only -// Plain Old Data (POD), or bottom out into POD. It must _not_ rely on -// having its destructor called. This implementation internally -// allocates storage in large chunks and does not call the destructor -// on each object. -// -// Type T must supply a default constructor, a copy constructor, and -// the "<" and "==" operators. -// -// In debug mode, printing of the data contained in the tree is -// enabled. This requires the template specialization to be available: -// -// template<> struct ValueToString { -// static String string(const T& t); -// }; -// -// Note that when complex types are stored in this red/black tree, it -// is possible that single invocations of the "<" and "==" operators -// will be insufficient to describe the ordering of elements in the -// tree during queries. As a concrete example, consider the case where -// intervals are stored in the tree sorted by low endpoint. The "<" -// operator on the Interval class only compares the low endpoint, but -// the "==" operator takes into account the high endpoint as well. -// This makes the necessary logic for querying and deletion somewhat -// more complex. In order to properly handle such situations, the -// property "needsFullOrderingComparisons" must be set to true on -// the tree. -// -// This red-black tree is designed to be _augmented_; subclasses can -// add additional and summary information to each node to efficiently -// store and index more complex data structures. A concrete example is -// the IntervalTree, which extends each node with a summary statistic -// to efficiently store one-dimensional intervals. -// -// The design of this red-black tree comes from Cormen, Leiserson, -// and Rivest, _Introduction to Algorithms_, MIT Press, 1990. - -#ifndef PODRedBlackTree_h -#define PODRedBlackTree_h - -#include "platform/PODFreeListArena.h" -#include "wtf/Assertions.h" -#include "wtf/Noncopyable.h" -#include "wtf/RefPtr.h" -#ifndef NDEBUG -#include "wtf/text/CString.h" -#include "wtf/text/StringBuilder.h" -#include "wtf/text/WTFString.h" -#endif - -namespace blink { - -#ifndef NDEBUG -template -struct ValueToString; -#endif - -enum UninitializedTreeEnum { - UninitializedTree -}; - -template -class PODRedBlackTree { -public: - class Node; - - // Visitor interface for walking all of the tree's elements. - class Visitor { - public: - virtual void visit(const T& data) = 0; - protected: - virtual ~Visitor() { } - }; - - // Constructs a new red-black tree without allocating an arena. - // isInitialized will return false in this case. initIfNeeded can be used - // to init the structure. This constructor is usefull for creating - // lazy initialized tree. - explicit PODRedBlackTree(UninitializedTreeEnum) - : m_root(0) - , m_needsFullOrderingComparisons(false) -#ifndef NDEBUG - , m_verboseDebugging(false) -#endif - { - } - - // Constructs a new red-black tree, allocating temporary objects - // from a newly constructed PODFreeListArena. - PODRedBlackTree() - : m_arena(PODFreeListArena::create()) - , m_root(0) - , m_needsFullOrderingComparisons(false) -#ifndef NDEBUG - , m_verboseDebugging(false) -#endif - { - } - - // Constructs a new red-black tree, allocating temporary objects - // from the given PODArena. - explicit PODRedBlackTree(PassRefPtr > arena) - : m_arena(arena) - , m_root(0) - , m_needsFullOrderingComparisons(false) -#ifndef NDEBUG - , m_verboseDebugging(false) -#endif - { - } - - virtual ~PODRedBlackTree() { } - - // Clearing will delete the contents of the tree. After this call - // isInitialized will return false. - void clear() - { - markFree(m_root); - m_arena = nullptr; - m_root = 0; - } - - bool isInitialized() const - { - return m_arena; - } - - void initIfNeeded() - { - if (!m_arena) - m_arena = PODFreeListArena::create(); - } - - void initIfNeeded(PODFreeListArena* arena) - { - if (!m_arena) - m_arena = arena; - } - - void add(const T& data) - { - ASSERT(isInitialized()); - Node* node = m_arena->template allocateObject(data); - insertNode(node); - } - - // Returns true if the datum was found in the tree. - bool remove(const T& data) - { - ASSERT(isInitialized()); - Node* node = treeSearch(data); - if (node) { - deleteNode(node); - return true; - } - return false; - } - - bool contains(const T& data) const - { - ASSERT(isInitialized()); - return treeSearch(data); - } - - void visitInorder(Visitor* visitor) const - { - ASSERT(isInitialized()); - if (!m_root) - return; - visitInorderImpl(m_root, visitor); - } - - int size() const - { - ASSERT(isInitialized()); - Counter counter; - visitInorder(&counter); - return counter.count(); - } - - // See the class documentation for an explanation of this property. - void setNeedsFullOrderingComparisons(bool needsFullOrderingComparisons) - { - m_needsFullOrderingComparisons = needsFullOrderingComparisons; - } - - virtual bool checkInvariants() const - { - ASSERT(isInitialized()); - int blackCount; - return checkInvariantsFromNode(m_root, &blackCount); - } - -#ifndef NDEBUG - // Dumps the tree's contents to the logging info stream for - // debugging purposes. - void dump() const - { - if (m_arena) - dumpFromNode(m_root, 0); - } - - // Turns on or off verbose debugging of the tree, causing many - // messages to be logged during insertion and other operations in - // debug mode. - void setVerboseDebugging(bool verboseDebugging) - { - m_verboseDebugging = verboseDebugging; - } -#endif - - enum Color { - Red = 1, - Black - }; - - // The base Node class which is stored in the tree. Nodes are only - // an internal concept; users of the tree deal only with the data - // they store in it. - class Node { - WTF_MAKE_NONCOPYABLE(Node); - public: - // Constructor. Newly-created nodes are colored red. - explicit Node(const T& data) - : m_left(0) - , m_right(0) - , m_parent(0) - , m_color(Red) - , m_data(data) - { - } - - virtual ~Node() { } - - Color color() const { return m_color; } - void setColor(Color color) { m_color = color; } - - // Fetches the user data. - T& data() { return m_data; } - - // Copies all user-level fields from the source node, but not - // internal fields. For example, the base implementation of this - // method copies the "m_data" field, but not the child or parent - // fields. Any augmentation information also does not need to be - // copied, as it will be recomputed. Subclasses must call the - // superclass implementation. - virtual void copyFrom(Node* src) { m_data = src->data(); } - - Node* left() const { return m_left; } - void setLeft(Node* node) { m_left = node; } - - Node* right() const { return m_right; } - void setRight(Node* node) { m_right = node; } - - Node* parent() const { return m_parent; } - void setParent(Node* node) { m_parent = node; } - - private: - Node* m_left; - Node* m_right; - Node* m_parent; - Color m_color; - T m_data; - }; - -protected: - // Returns the root of the tree, which is needed by some subclasses. - Node* root() const { return m_root; } - -private: - // This virtual method is the hook that subclasses should use when - // augmenting the red-black tree with additional per-node summary - // information. For example, in the case of an interval tree, this - // is used to compute the maximum endpoint of the subtree below the - // given node based on the values in the left and right children. It - // is guaranteed that this will be called in the correct order to - // properly update such summary information based only on the values - // in the left and right children. This method should return true if - // the node's summary information changed. - virtual bool updateNode(Node*) { return false; } - - //---------------------------------------------------------------------- - // Generic binary search tree operations - // - - // Searches the tree for the given datum. - Node* treeSearch(const T& data) const - { - if (m_needsFullOrderingComparisons) - return treeSearchFullComparisons(m_root, data); - - return treeSearchNormal(m_root, data); - } - - // Searches the tree using the normal comparison operations, - // suitable for simple data types such as numbers. - Node* treeSearchNormal(Node* current, const T& data) const - { - while (current) { - if (current->data() == data) - return current; - if (data < current->data()) - current = current->left(); - else - current = current->right(); - } - return 0; - } - - // Searches the tree using multiple comparison operations, required - // for data types with more complex behavior such as intervals. - Node* treeSearchFullComparisons(Node* current, const T& data) const - { - if (!current) - return 0; - if (data < current->data()) - return treeSearchFullComparisons(current->left(), data); - if (current->data() < data) - return treeSearchFullComparisons(current->right(), data); - if (data == current->data()) - return current; - - // We may need to traverse both the left and right subtrees. - Node* result = treeSearchFullComparisons(current->left(), data); - if (!result) - result = treeSearchFullComparisons(current->right(), data); - return result; - } - - void treeInsert(Node* z) - { - Node* y = 0; - Node* x = m_root; - while (x) { - y = x; - if (z->data() < x->data()) - x = x->left(); - else - x = x->right(); - } - z->setParent(y); - if (!y) { - m_root = z; - } else { - if (z->data() < y->data()) - y->setLeft(z); - else - y->setRight(z); - } - } - - // Finds the node following the given one in sequential ordering of - // their data, or null if none exists. - Node* treeSuccessor(Node* x) - { - if (x->right()) - return treeMinimum(x->right()); - Node* y = x->parent(); - while (y && x == y->right()) { - x = y; - y = y->parent(); - } - return y; - } - - // Finds the minimum element in the sub-tree rooted at the given - // node. - Node* treeMinimum(Node* x) - { - while (x->left()) - x = x->left(); - return x; - } - - // Helper for maintaining the augmented red-black tree. - void propagateUpdates(Node* start) - { - bool shouldContinue = true; - while (start && shouldContinue) { - shouldContinue = updateNode(start); - start = start->parent(); - } - } - - //---------------------------------------------------------------------- - // Red-Black tree operations - // - - // Left-rotates the subtree rooted at x. - // Returns the new root of the subtree (x's right child). - Node* leftRotate(Node* x) - { - // Set y. - Node* y = x->right(); - - // Turn y's left subtree into x's right subtree. - x->setRight(y->left()); - if (y->left()) - y->left()->setParent(x); - - // Link x's parent to y. - y->setParent(x->parent()); - if (!x->parent()) { - m_root = y; - } else { - if (x == x->parent()->left()) - x->parent()->setLeft(y); - else - x->parent()->setRight(y); - } - - // Put x on y's left. - y->setLeft(x); - x->setParent(y); - - // Update nodes lowest to highest. - updateNode(x); - updateNode(y); - return y; - } - - // Right-rotates the subtree rooted at y. - // Returns the new root of the subtree (y's left child). - Node* rightRotate(Node* y) - { - // Set x. - Node* x = y->left(); - - // Turn x's right subtree into y's left subtree. - y->setLeft(x->right()); - if (x->right()) - x->right()->setParent(y); - - // Link y's parent to x. - x->setParent(y->parent()); - if (!y->parent()) { - m_root = x; - } else { - if (y == y->parent()->left()) - y->parent()->setLeft(x); - else - y->parent()->setRight(x); - } - - // Put y on x's right. - x->setRight(y); - y->setParent(x); - - // Update nodes lowest to highest. - updateNode(y); - updateNode(x); - return x; - } - - // Inserts the given node into the tree. - void insertNode(Node* x) - { - treeInsert(x); - x->setColor(Red); - updateNode(x); - - logIfVerbose(" PODRedBlackTree::InsertNode"); - - // The node from which to start propagating updates upwards. - Node* updateStart = x->parent(); - - while (x != m_root && x->parent()->color() == Red) { - if (x->parent() == x->parent()->parent()->left()) { - Node* y = x->parent()->parent()->right(); - if (y && y->color() == Red) { - // Case 1 - logIfVerbose(" Case 1/1"); - x->parent()->setColor(Black); - y->setColor(Black); - x->parent()->parent()->setColor(Red); - updateNode(x->parent()); - x = x->parent()->parent(); - updateNode(x); - updateStart = x->parent(); - } else { - if (x == x->parent()->right()) { - logIfVerbose(" Case 1/2"); - // Case 2 - x = x->parent(); - leftRotate(x); - } - // Case 3 - logIfVerbose(" Case 1/3"); - x->parent()->setColor(Black); - x->parent()->parent()->setColor(Red); - Node* newSubTreeRoot = rightRotate(x->parent()->parent()); - updateStart = newSubTreeRoot->parent(); - } - } else { - // Same as "then" clause with "right" and "left" exchanged. - Node* y = x->parent()->parent()->left(); - if (y && y->color() == Red) { - // Case 1 - logIfVerbose(" Case 2/1"); - x->parent()->setColor(Black); - y->setColor(Black); - x->parent()->parent()->setColor(Red); - updateNode(x->parent()); - x = x->parent()->parent(); - updateNode(x); - updateStart = x->parent(); - } else { - if (x == x->parent()->left()) { - // Case 2 - logIfVerbose(" Case 2/2"); - x = x->parent(); - rightRotate(x); - } - // Case 3 - logIfVerbose(" Case 2/3"); - x->parent()->setColor(Black); - x->parent()->parent()->setColor(Red); - Node* newSubTreeRoot = leftRotate(x->parent()->parent()); - updateStart = newSubTreeRoot->parent(); - } - } - } - - propagateUpdates(updateStart); - - m_root->setColor(Black); - } - - // Restores the red-black property to the tree after splicing out - // a node. Note that x may be null, which is why xParent must be - // supplied. - void deleteFixup(Node* x, Node* xParent) - { - while (x != m_root && (!x || x->color() == Black)) { - if (x == xParent->left()) { - // Note: the text points out that w can not be null. - // The reason is not obvious from simply looking at - // the code; it comes about from the properties of the - // red-black tree. - Node* w = xParent->right(); - ASSERT(w); // x's sibling should not be null. - if (w->color() == Red) { - // Case 1 - w->setColor(Black); - xParent->setColor(Red); - leftRotate(xParent); - w = xParent->right(); - } - if ((!w->left() || w->left()->color() == Black) - && (!w->right() || w->right()->color() == Black)) { - // Case 2 - w->setColor(Red); - x = xParent; - xParent = x->parent(); - } else { - if (!w->right() || w->right()->color() == Black) { - // Case 3 - w->left()->setColor(Black); - w->setColor(Red); - rightRotate(w); - w = xParent->right(); - } - // Case 4 - w->setColor(xParent->color()); - xParent->setColor(Black); - if (w->right()) - w->right()->setColor(Black); - leftRotate(xParent); - x = m_root; - xParent = x->parent(); - } - } else { - // Same as "then" clause with "right" and "left" - // exchanged. - - // Note: the text points out that w can not be null. - // The reason is not obvious from simply looking at - // the code; it comes about from the properties of the - // red-black tree. - Node* w = xParent->left(); - ASSERT(w); // x's sibling should not be null. - if (w->color() == Red) { - // Case 1 - w->setColor(Black); - xParent->setColor(Red); - rightRotate(xParent); - w = xParent->left(); - } - if ((!w->right() || w->right()->color() == Black) - && (!w->left() || w->left()->color() == Black)) { - // Case 2 - w->setColor(Red); - x = xParent; - xParent = x->parent(); - } else { - if (!w->left() || w->left()->color() == Black) { - // Case 3 - w->right()->setColor(Black); - w->setColor(Red); - leftRotate(w); - w = xParent->left(); - } - // Case 4 - w->setColor(xParent->color()); - xParent->setColor(Black); - if (w->left()) - w->left()->setColor(Black); - rightRotate(xParent); - x = m_root; - xParent = x->parent(); - } - } - } - if (x) - x->setColor(Black); - } - - // Deletes the given node from the tree. Note that this - // particular node may not actually be removed from the tree; - // instead, another node might be removed and its contents - // copied into z. - void deleteNode(Node* z) - { - // Y is the node to be unlinked from the tree. - Node* y; - if (!z->left() || !z->right()) - y = z; - else - y = treeSuccessor(z); - - // Y is guaranteed to be non-null at this point. - Node* x; - if (y->left()) - x = y->left(); - else - x = y->right(); - - // X is the child of y which might potentially replace y in - // the tree. X might be null at this point. - Node* xParent; - if (x) { - x->setParent(y->parent()); - xParent = x->parent(); - } else { - xParent = y->parent(); - } - if (!y->parent()) { - m_root = x; - } else { - if (y == y->parent()->left()) - y->parent()->setLeft(x); - else - y->parent()->setRight(x); - } - if (y != z) { - z->copyFrom(y); - // This node has changed location in the tree and must be updated. - updateNode(z); - // The parent and its parents may now be out of date. - propagateUpdates(z->parent()); - } - - // If we haven't already updated starting from xParent, do so now. - if (xParent && xParent != y && xParent != z) - propagateUpdates(xParent); - if (y->color() == Black) - deleteFixup(x, xParent); - - m_arena->freeObject(y); - } - - // Visits the subtree rooted at the given node in order. - void visitInorderImpl(Node* node, Visitor* visitor) const - { - if (node->left()) - visitInorderImpl(node->left(), visitor); - visitor->visit(node->data()); - if (node->right()) - visitInorderImpl(node->right(), visitor); - } - - void markFree(Node *node) - { - if (!node) - return; - - if (node->left()) - markFree(node->left()); - if (node->right()) - markFree(node->right()); - m_arena->freeObject(node); - } - - //---------------------------------------------------------------------- - // Helper class for size() - - // A Visitor which simply counts the number of visited elements. - class Counter : public Visitor { - WTF_MAKE_NONCOPYABLE(Counter); - public: - Counter() - : m_count(0) { } - - virtual void visit(const T&) { ++m_count; } - int count() const { return m_count; } - - private: - int m_count; - }; - - //---------------------------------------------------------------------- - // Verification and debugging routines - // - - // Returns in the "blackCount" parameter the number of black - // children along all paths to all leaves of the given node. - bool checkInvariantsFromNode(Node* node, int* blackCount) const - { - // Base case is a leaf node. - if (!node) { - *blackCount = 1; - return true; - } - - // Each node is either red or black. - if (!(node->color() == Red || node->color() == Black)) - return false; - - // Every leaf (or null) is black. - - if (node->color() == Red) { - // Both of its children are black. - if (!((!node->left() || node->left()->color() == Black))) - return false; - if (!((!node->right() || node->right()->color() == Black))) - return false; - } - - // Every simple path to a leaf node contains the same number of - // black nodes. - int leftCount = 0, rightCount = 0; - bool leftValid = checkInvariantsFromNode(node->left(), &leftCount); - bool rightValid = checkInvariantsFromNode(node->right(), &rightCount); - if (!leftValid || !rightValid) - return false; - *blackCount = leftCount + (node->color() == Black ? 1 : 0); - return leftCount == rightCount; - } - -#ifdef NDEBUG - void logIfVerbose(const char*) const { } -#else - void logIfVerbose(const char* output) const - { - if (m_verboseDebugging) - WTF_LOG_ERROR("%s", output); - } -#endif - -#ifndef NDEBUG - // Dumps the subtree rooted at the given node. - void dumpFromNode(Node* node, int indentation) const - { - StringBuilder builder; - for (int i = 0; i < indentation; i++) - builder.append(' '); - builder.append('-'); - if (node) { - builder.append(' '); - builder.append(ValueToString::string(node->data())); - builder.append((node->color() == Black) ? " (black)" : " (red)"); - } - WTF_LOG_ERROR("%s", builder.toString().ascii().data()); - if (node) { - dumpFromNode(node->left(), indentation + 2); - dumpFromNode(node->right(), indentation + 2); - } - } -#endif - - //---------------------------------------------------------------------- - // Data members - - RefPtr > m_arena; - Node* m_root; - bool m_needsFullOrderingComparisons; -#ifndef NDEBUG - bool m_verboseDebugging; -#endif -}; - -} // namespace blink - -#endif // PODRedBlackTree_h diff --git a/engine/platform/PODRedBlackTreeTest.cpp b/engine/platform/PODRedBlackTreeTest.cpp deleted file mode 100644 index 2ad47fd4ee5..00000000000 --- a/engine/platform/PODRedBlackTreeTest.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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. - */ - -// Tests for the red-black tree class. - -#include "config.h" -#include "platform/PODRedBlackTree.h" - -#include "platform/testing/ArenaTestHelpers.h" -#include "platform/testing/TreeTestHelpers.h" -#include "wtf/Vector.h" - -#include - -namespace blink { - -using ArenaTestHelpers::TrackedAllocator; -using TreeTestHelpers::initRandom; -using TreeTestHelpers::nextRandom; - -TEST(PODRedBlackTreeTest, TestTreeAllocatesFromArena) -{ - RefPtr allocator = TrackedAllocator::create(); - { - typedef PODFreeListArena::Node> PODIntegerArena; - RefPtr arena = PODIntegerArena::create(allocator); - PODRedBlackTree tree(arena); - int numAdditions = 2 * PODArena::DefaultChunkSize / sizeof(int); - for (int i = 0; i < numAdditions; ++i) - tree.add(i); - EXPECT_GT(allocator->numRegions(), 1); - } - EXPECT_EQ(allocator->numRegions(), 0); -} - -TEST(PODRedBlackTreeTest, TestSingleElementInsertion) -{ - PODRedBlackTree tree; - tree.add(5); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(5)); -} - -TEST(PODRedBlackTreeTest, TestMultipleElementInsertion) -{ - PODRedBlackTree tree; - tree.add(4); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(4)); - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(3)); - tree.add(5); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(5)); - EXPECT_TRUE(tree.contains(4)); - EXPECT_TRUE(tree.contains(3)); -} - -TEST(PODRedBlackTreeTest, TestDuplicateElementInsertion) -{ - PODRedBlackTree tree; - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_EQ(3, tree.size()); - EXPECT_TRUE(tree.contains(3)); -} - -TEST(PODRedBlackTreeTest, TestSingleElementInsertionAndDeletion) -{ - PODRedBlackTree tree; - tree.add(5); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(5)); - tree.remove(5); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_FALSE(tree.contains(5)); -} - -TEST(PODRedBlackTreeTest, TestMultipleElementInsertionAndDeletion) -{ - PODRedBlackTree tree; - tree.add(4); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(4)); - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(3)); - tree.add(5); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(5)); - EXPECT_TRUE(tree.contains(4)); - EXPECT_TRUE(tree.contains(3)); - tree.remove(4); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(3)); - EXPECT_FALSE(tree.contains(4)); - EXPECT_TRUE(tree.contains(5)); - tree.remove(5); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_TRUE(tree.contains(3)); - EXPECT_FALSE(tree.contains(4)); - EXPECT_FALSE(tree.contains(5)); - EXPECT_EQ(1, tree.size()); -} - -TEST(PODRedBlackTreeTest, TestDuplicateElementInsertionAndDeletion) -{ - PODRedBlackTree tree; - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(3); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_EQ(3, tree.size()); - EXPECT_TRUE(tree.contains(3)); - tree.remove(3); - ASSERT_TRUE(tree.checkInvariants()); - tree.remove(3); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_EQ(1, tree.size()); - EXPECT_TRUE(tree.contains(3)); - tree.remove(3); - ASSERT_TRUE(tree.checkInvariants()); - EXPECT_EQ(0, tree.size()); - EXPECT_FALSE(tree.contains(3)); -} - -TEST(PODRedBlackTreeTest, FailingInsertionRegressionTest1) -{ - // These numbers came from a previously-failing randomized test run. - PODRedBlackTree tree; - tree.add(5113); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(4517); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(3373); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(9307); - ASSERT_TRUE(tree.checkInvariants()); - tree.add(7077); - ASSERT_TRUE(tree.checkInvariants()); -} - -namespace { -void InsertionAndDeletionTest(const int32_t seed, const int treeSize) -{ - initRandom(seed); - const int maximumValue = treeSize; - // Build the tree. - PODRedBlackTree tree; - Vector values; - for (int i = 0; i < treeSize; i++) { - int value = nextRandom(maximumValue); - tree.add(value); - ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; - values.append(value); - } - // Churn the tree's contents. - for (int i = 0; i < treeSize; i++) { - // Pick a random value to remove. - int index = nextRandom(treeSize); - int value = values[index]; - // Remove this value. - tree.remove(value); - ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; - // Replace it with a new one. - value = nextRandom(maximumValue); - values[index] = value; - tree.add(value); - ASSERT_TRUE(tree.checkInvariants()) << "Test failed for seed " << seed; - } -} -} // anonymous namespace - -TEST(PODRedBlackTreeTest, RandomDeletionAndInsertionRegressionTest1) -{ - InsertionAndDeletionTest(12311, 100); -} - -} // namespace blink diff --git a/engine/platform/geometry/FloatPolygon.cpp b/engine/platform/geometry/FloatPolygon.cpp deleted file mode 100644 index e88f8d7eed8..00000000000 --- a/engine/platform/geometry/FloatPolygon.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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 AND CONTRIBUTORS - * "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 HOLDER 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 "platform/geometry/FloatPolygon.h" - -#include "wtf/MathExtras.h" - -namespace blink { - -static inline float determinant(const FloatSize& a, const FloatSize& b) -{ - return a.width() * b.height() - a.height() * b.width(); -} - -static inline bool areCollinearPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2) -{ - return !determinant(p1 - p0, p2 - p0); -} - -static inline bool areCoincidentPoints(const FloatPoint& p0, const FloatPoint& p1) -{ - return p0.x() == p1.x() && p0.y() == p1.y(); -} - -static inline bool isPointOnLineSegment(const FloatPoint& vertex1, const FloatPoint& vertex2, const FloatPoint& point) -{ - return point.x() >= std::min(vertex1.x(), vertex2.x()) - && point.x() <= std::max(vertex1.x(), vertex2.x()) - && areCollinearPoints(vertex1, vertex2, point); -} - -static inline unsigned nextVertexIndex(unsigned vertexIndex, unsigned nVertices, bool clockwise) -{ - return ((clockwise) ? vertexIndex + 1 : vertexIndex - 1 + nVertices) % nVertices; -} - -static unsigned findNextEdgeVertexIndex(const FloatPolygon& polygon, unsigned vertexIndex1, bool clockwise) -{ - unsigned nVertices = polygon.numberOfVertices(); - unsigned vertexIndex2 = nextVertexIndex(vertexIndex1, nVertices, clockwise); - - while (vertexIndex2 && areCoincidentPoints(polygon.vertexAt(vertexIndex1), polygon.vertexAt(vertexIndex2))) - vertexIndex2 = nextVertexIndex(vertexIndex2, nVertices, clockwise); - - while (vertexIndex2) { - unsigned vertexIndex3 = nextVertexIndex(vertexIndex2, nVertices, clockwise); - if (!areCollinearPoints(polygon.vertexAt(vertexIndex1), polygon.vertexAt(vertexIndex2), polygon.vertexAt(vertexIndex3))) - break; - vertexIndex2 = vertexIndex3; - } - - return vertexIndex2; -} - -FloatPolygon::FloatPolygon(PassOwnPtr > vertices, WindRule fillRule) - : m_vertices(vertices) - , m_fillRule(fillRule) -{ - unsigned nVertices = numberOfVertices(); - m_edges.resize(nVertices); - m_empty = nVertices < 3; - - if (nVertices) - m_boundingBox.setLocation(vertexAt(0)); - - if (m_empty) - return; - - unsigned minVertexIndex = 0; - for (unsigned i = 1; i < nVertices; ++i) { - const FloatPoint& vertex = vertexAt(i); - if (vertex.y() < vertexAt(minVertexIndex).y() || (vertex.y() == vertexAt(minVertexIndex).y() && vertex.x() < vertexAt(minVertexIndex).x())) - minVertexIndex = i; - } - FloatPoint nextVertex = vertexAt((minVertexIndex + 1) % nVertices); - FloatPoint prevVertex = vertexAt((minVertexIndex + nVertices - 1) % nVertices); - bool clockwise = determinant(vertexAt(minVertexIndex) - prevVertex, nextVertex - prevVertex) > 0; - - unsigned edgeIndex = 0; - unsigned vertexIndex1 = 0; - do { - m_boundingBox.extend(vertexAt(vertexIndex1)); - unsigned vertexIndex2 = findNextEdgeVertexIndex(*this, vertexIndex1, clockwise); - m_edges[edgeIndex].m_polygon = this; - m_edges[edgeIndex].m_vertexIndex1 = vertexIndex1; - m_edges[edgeIndex].m_vertexIndex2 = vertexIndex2; - m_edges[edgeIndex].m_edgeIndex = edgeIndex; - ++edgeIndex; - vertexIndex1 = vertexIndex2; - } while (vertexIndex1); - - if (edgeIndex > 3) { - const FloatPolygonEdge& firstEdge = m_edges[0]; - const FloatPolygonEdge& lastEdge = m_edges[edgeIndex - 1]; - if (areCollinearPoints(lastEdge.vertex1(), lastEdge.vertex2(), firstEdge.vertex2())) { - m_edges[0].m_vertexIndex1 = lastEdge.m_vertexIndex1; - edgeIndex--; - } - } - - m_edges.resize(edgeIndex); - m_empty = m_edges.size() < 3; - - if (m_empty) - return; - - for (unsigned i = 0; i < m_edges.size(); ++i) { - FloatPolygonEdge* edge = &m_edges[i]; - m_edgeTree.add(EdgeInterval(edge->minY(), edge->maxY(), edge)); - } -} - -bool FloatPolygon::overlappingEdges(float minY, float maxY, Vector& result) const -{ - Vector overlappingEdgeIntervals; - m_edgeTree.allOverlaps(FloatPolygon::EdgeInterval(minY, maxY, 0), overlappingEdgeIntervals); - unsigned overlappingEdgeIntervalsSize = overlappingEdgeIntervals.size(); - result.resize(overlappingEdgeIntervalsSize); - for (unsigned i = 0; i < overlappingEdgeIntervalsSize; ++i) { - const FloatPolygonEdge* edge = static_cast(overlappingEdgeIntervals[i].data()); - ASSERT(edge); - result[i] = edge; - } - return overlappingEdgeIntervalsSize > 0; -} - -static inline float leftSide(const FloatPoint& vertex1, const FloatPoint& vertex2, const FloatPoint& point) -{ - return ((point.x() - vertex1.x()) * (vertex2.y() - vertex1.y())) - ((vertex2.x() - vertex1.x()) * (point.y() - vertex1.y())); -} - -bool FloatPolygon::containsEvenOdd(const FloatPoint& point) const -{ - unsigned crossingCount = 0; - for (unsigned i = 0; i < numberOfEdges(); ++i) { - const FloatPoint& vertex1 = edgeAt(i).vertex1(); - const FloatPoint& vertex2 = edgeAt(i).vertex2(); - if (isPointOnLineSegment(vertex1, vertex2, point)) - return true; - if ((vertex1.y() <= point.y() && vertex2.y() > point.y()) || (vertex1.y() > point.y() && vertex2.y() <= point.y())) { - float vt = (point.y() - vertex1.y()) / (vertex2.y() - vertex1.y()); - if (point.x() < vertex1.x() + vt * (vertex2.x() - vertex1.x())) - ++crossingCount; - } - } - return crossingCount & 1; -} - -bool FloatPolygon::containsNonZero(const FloatPoint& point) const -{ - int windingNumber = 0; - for (unsigned i = 0; i < numberOfEdges(); ++i) { - const FloatPoint& vertex1 = edgeAt(i).vertex1(); - const FloatPoint& vertex2 = edgeAt(i).vertex2(); - if (isPointOnLineSegment(vertex1, vertex2, point)) - return true; - if (vertex2.y() <= point.y()) { - if ((vertex1.y() > point.y()) && (leftSide(vertex1, vertex2, point) > 0)) - ++windingNumber; - } else if (vertex2.y() >= point.y()) { - if ((vertex1.y() <= point.y()) && (leftSide(vertex1, vertex2, point) < 0)) - --windingNumber; - } - } - return windingNumber; -} - -bool FloatPolygon::contains(const FloatPoint& point) const -{ - if (!m_boundingBox.contains(point)) - return false; - return (fillRule() == RULE_NONZERO) ? containsNonZero(point) : containsEvenOdd(point); -} - -bool VertexPair::intersection(const VertexPair& other, FloatPoint& point) const -{ - // See: http://paulbourke.net/geometry/pointlineplane/, "Intersection point of two lines in 2 dimensions" - - const FloatSize& thisDelta = vertex2() - vertex1(); - const FloatSize& otherDelta = other.vertex2() - other.vertex1(); - float denominator = determinant(thisDelta, otherDelta); - if (!denominator) - return false; - - // The two line segments: "this" vertex1,vertex2 and "other" vertex1,vertex2, have been defined - // in parametric form. Each point on the line segment is: vertex1 + u * (vertex2 - vertex1), - // when 0 <= u <= 1. We're computing the values of u for each line at their intersection point. - - const FloatSize& vertex1Delta = vertex1() - other.vertex1(); - float uThisLine = determinant(otherDelta, vertex1Delta) / denominator; - float uOtherLine = determinant(thisDelta, vertex1Delta) / denominator; - - if (uThisLine < 0 || uOtherLine < 0 || uThisLine > 1 || uOtherLine > 1) - return false; - - point = vertex1() + uThisLine * thisDelta; - return true; -} - -} // namespace blink diff --git a/engine/platform/geometry/FloatPolygon.h b/engine/platform/geometry/FloatPolygon.h deleted file mode 100644 index 875c321633d..00000000000 --- a/engine/platform/geometry/FloatPolygon.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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 AND CONTRIBUTORS - * "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 HOLDER 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. - */ - -#ifndef FloatPolygon_h -#define FloatPolygon_h - -#include "platform/PODIntervalTree.h" -#include "platform/geometry/FloatPoint.h" -#include "platform/geometry/FloatRect.h" -#include "platform/graphics/GraphicsTypes.h" -#include "wtf/OwnPtr.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/Vector.h" - -namespace blink { - -class FloatPolygonEdge; - -// This class is used by PODIntervalTree for debugging. -#ifndef NDEBUG -template struct ValueToString; -#endif - -class PLATFORM_EXPORT FloatPolygon { -public: - FloatPolygon(PassOwnPtr > vertices, WindRule fillRule); - - const FloatPoint& vertexAt(unsigned index) const { return (*m_vertices)[index]; } - unsigned numberOfVertices() const { return m_vertices->size(); } - - WindRule fillRule() const { return m_fillRule; } - - const FloatPolygonEdge& edgeAt(unsigned index) const { return m_edges[index]; } - unsigned numberOfEdges() const { return m_edges.size(); } - - FloatRect boundingBox() const { return m_boundingBox; } - bool overlappingEdges(float minY, float maxY, Vector& result) const; - bool contains(const FloatPoint&) const; - bool isEmpty() const { return m_empty; } - -private: - typedef PODInterval EdgeInterval; - typedef PODIntervalTree EdgeIntervalTree; - - bool containsNonZero(const FloatPoint&) const; - bool containsEvenOdd(const FloatPoint&) const; - - OwnPtr > m_vertices; - WindRule m_fillRule; - FloatRect m_boundingBox; - bool m_empty; - Vector m_edges; - EdgeIntervalTree m_edgeTree; // Each EdgeIntervalTree node stores minY, maxY, and a ("UserData") pointer to a FloatPolygonEdge. - -}; - -class PLATFORM_EXPORT VertexPair { -public: - virtual ~VertexPair() { } - - virtual const FloatPoint& vertex1() const = 0; - virtual const FloatPoint& vertex2() const = 0; - - float minX() const { return std::min(vertex1().x(), vertex2().x()); } - float minY() const { return std::min(vertex1().y(), vertex2().y()); } - float maxX() const { return std::max(vertex1().x(), vertex2().x()); } - float maxY() const { return std::max(vertex1().y(), vertex2().y()); } - - bool intersection(const VertexPair&, FloatPoint&) const; -}; - -class PLATFORM_EXPORT FloatPolygonEdge : public VertexPair { - friend class FloatPolygon; -public: - virtual const FloatPoint& vertex1() const override - { - ASSERT(m_polygon); - return m_polygon->vertexAt(m_vertexIndex1); - } - - virtual const FloatPoint& vertex2() const override - { - ASSERT(m_polygon); - return m_polygon->vertexAt(m_vertexIndex2); - } - - const FloatPolygonEdge& previousEdge() const - { - ASSERT(m_polygon && m_polygon->numberOfEdges() > 1); - return m_polygon->edgeAt((m_edgeIndex + m_polygon->numberOfEdges() - 1) % m_polygon->numberOfEdges()); - } - - const FloatPolygonEdge& nextEdge() const - { - ASSERT(m_polygon && m_polygon->numberOfEdges() > 1); - return m_polygon->edgeAt((m_edgeIndex + 1) % m_polygon->numberOfEdges()); - } - - const FloatPolygon* polygon() const { return m_polygon; } - unsigned vertexIndex1() const { return m_vertexIndex1; } - unsigned vertexIndex2() const { return m_vertexIndex2; } - unsigned edgeIndex() const { return m_edgeIndex; } - -private: - // Edge vertex index1 is less than index2, except the last edge, where index2 is 0. When a polygon edge - // is defined by 3 or more colinear vertices, index2 can be the the index of the last colinear vertex. - unsigned m_vertexIndex1; - unsigned m_vertexIndex2; - unsigned m_edgeIndex; - const FloatPolygon* m_polygon; -}; - -// These structures are used by PODIntervalTree for debugging. -#ifndef NDEBUG -template <> struct ValueToString { - static String string(const float value) { return String::number(value); } -}; - -template<> struct ValueToString { - static String string(const FloatPolygonEdge* edge) { return String::format("%p (%f,%f %f,%f)", edge, edge->vertex1().x(), edge->vertex1().y(), edge->vertex2().x(), edge->vertex2().y()); } -}; -#endif - -} // namespace blink - -#endif // FloatPolygon_h diff --git a/engine/platform/geometry/FloatPolygonTest.cpp b/engine/platform/geometry/FloatPolygonTest.cpp deleted file mode 100644 index 4ff2936324b..00000000000 --- a/engine/platform/geometry/FloatPolygonTest.cpp +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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 AND CONTRIBUTORS - * "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 HOLDER 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 "platform/geometry/FloatPolygon.h" - -#include - -namespace blink { - -class FloatPolygonTestValue { -public: - FloatPolygonTestValue(const float* coordinates, unsigned coordinatesLength, WindRule fillRule) - { - ASSERT(!(coordinatesLength % 2)); - OwnPtr > vertices = adoptPtr(new Vector(coordinatesLength / 2)); - for (unsigned i = 0; i < coordinatesLength; i += 2) - (*vertices)[i / 2] = FloatPoint(coordinates[i], coordinates[i + 1]); - m_polygon = adoptPtr(new FloatPolygon(vertices.release(), fillRule)); - } - - const FloatPolygon& polygon() const { return *m_polygon; } - -private: - OwnPtr m_polygon; -}; - -} // namespace blink - -namespace { - -using namespace blink; - -static bool compareEdgeIndex(const FloatPolygonEdge* edge1, const FloatPolygonEdge* edge2) -{ - return edge1->edgeIndex() < edge2->edgeIndex(); -} - -static Vector sortedOverlappingEdges(const FloatPolygon& polygon, float minY, float maxY) -{ - Vector result; - polygon.overlappingEdges(minY, maxY, result); - std::sort(result.begin(), result.end(), compareEdgeIndex); - return result; -} - -#define SIZEOF_ARRAY(p) (sizeof(p) / sizeof(p[0])) - -/** - * Checks a right triangle. This test covers all of the trivial FloatPolygon accessors. - * - * 200,100 - * /| - * / | - * / | - * ----- - * 100,200 200,200 - */ -TEST(FloatPolygonTest, basics) -{ - const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200}; - FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_NONZERO); - const FloatPolygon& triangle = triangleTestValue.polygon(); - - EXPECT_EQ(RULE_NONZERO, triangle.fillRule()); - EXPECT_FALSE(triangle.isEmpty()); - - EXPECT_EQ(3u, triangle.numberOfVertices()); - EXPECT_EQ(FloatPoint(200, 100), triangle.vertexAt(0)); - EXPECT_EQ(FloatPoint(200, 200), triangle.vertexAt(1)); - EXPECT_EQ(FloatPoint(100, 200), triangle.vertexAt(2)); - - EXPECT_EQ(3u, triangle.numberOfEdges()); - EXPECT_EQ(FloatPoint(200, 100), triangle.edgeAt(0).vertex1()); - EXPECT_EQ(FloatPoint(200, 200), triangle.edgeAt(0).vertex2()); - EXPECT_EQ(FloatPoint(200, 200), triangle.edgeAt(1).vertex1()); - EXPECT_EQ(FloatPoint(100, 200), triangle.edgeAt(1).vertex2()); - EXPECT_EQ(FloatPoint(100, 200), triangle.edgeAt(2).vertex1()); - EXPECT_EQ(FloatPoint(200, 100), triangle.edgeAt(2).vertex2()); - - EXPECT_EQ(0u, triangle.edgeAt(0).vertexIndex1()); - EXPECT_EQ(1u, triangle.edgeAt(0).vertexIndex2()); - EXPECT_EQ(1u, triangle.edgeAt(1).vertexIndex1()); - EXPECT_EQ(2u, triangle.edgeAt(1).vertexIndex2()); - EXPECT_EQ(2u, triangle.edgeAt(2).vertexIndex1()); - EXPECT_EQ(0u, triangle.edgeAt(2).vertexIndex2()); - - EXPECT_EQ(200, triangle.edgeAt(0).minX()); - EXPECT_EQ(200, triangle.edgeAt(0).maxX()); - EXPECT_EQ(100, triangle.edgeAt(1).minX()); - EXPECT_EQ(200, triangle.edgeAt(1).maxX()); - EXPECT_EQ(100, triangle.edgeAt(2).minX()); - EXPECT_EQ(200, triangle.edgeAt(2).maxX()); - - EXPECT_EQ(100, triangle.edgeAt(0).minY()); - EXPECT_EQ(200, triangle.edgeAt(0).maxY()); - EXPECT_EQ(200, triangle.edgeAt(1).minY()); - EXPECT_EQ(200, triangle.edgeAt(1).maxY()); - EXPECT_EQ(100, triangle.edgeAt(2).minY()); - EXPECT_EQ(200, triangle.edgeAt(2).maxY()); - - EXPECT_EQ(0u, triangle.edgeAt(0).edgeIndex()); - EXPECT_EQ(1u, triangle.edgeAt(1).edgeIndex()); - EXPECT_EQ(2u, triangle.edgeAt(2).edgeIndex()); - - EXPECT_EQ(2u, triangle.edgeAt(0).previousEdge().edgeIndex()); - EXPECT_EQ(1u, triangle.edgeAt(0).nextEdge().edgeIndex()); - EXPECT_EQ(0u, triangle.edgeAt(1).previousEdge().edgeIndex()); - EXPECT_EQ(2u, triangle.edgeAt(1).nextEdge().edgeIndex()); - EXPECT_EQ(1u, triangle.edgeAt(2).previousEdge().edgeIndex()); - EXPECT_EQ(0u, triangle.edgeAt(2).nextEdge().edgeIndex()); - - EXPECT_EQ(FloatRect(100, 100, 100, 100), triangle.boundingBox()); - - Vector resultA = sortedOverlappingEdges(triangle, 100, 200); - EXPECT_EQ(3u, resultA.size()); - if (resultA.size() == 3) { - EXPECT_EQ(0u, resultA[0]->edgeIndex()); - EXPECT_EQ(1u, resultA[1]->edgeIndex()); - EXPECT_EQ(2u, resultA[2]->edgeIndex()); - } - - Vector resultB = sortedOverlappingEdges(triangle, 200, 200); - EXPECT_EQ(3u, resultB.size()); - if (resultB.size() == 3) { - EXPECT_EQ(0u, resultB[0]->edgeIndex()); - EXPECT_EQ(1u, resultB[1]->edgeIndex()); - EXPECT_EQ(2u, resultB[2]->edgeIndex()); - } - - Vector resultC = sortedOverlappingEdges(triangle, 100, 150); - EXPECT_EQ(2u, resultC.size()); - if (resultC.size() == 2) { - EXPECT_EQ(0u, resultC[0]->edgeIndex()); - EXPECT_EQ(2u, resultC[1]->edgeIndex()); - } - - Vector resultD = sortedOverlappingEdges(triangle, 201, 300); - EXPECT_EQ(0u, resultD.size()); - - Vector resultE = sortedOverlappingEdges(triangle, 98, 99); - EXPECT_EQ(0u, resultE.size()); -} - -/** - * Tests FloatPolygon::contains() with a right triangle, and fillRule = nonzero. - * - * 200,100 - * /| - * / | - * / | - * ----- - * 100,200 200,200 - */ -TEST(FloatPolygonTest, triangle_nonzero) -{ - const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200}; - FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_NONZERO); - const FloatPolygon& triangle = triangleTestValue.polygon(); - - EXPECT_EQ(RULE_NONZERO, triangle.fillRule()); - EXPECT_TRUE(triangle.contains(FloatPoint(200, 100))); - EXPECT_TRUE(triangle.contains(FloatPoint(200, 200))); - EXPECT_TRUE(triangle.contains(FloatPoint(100, 200))); - EXPECT_TRUE(triangle.contains(FloatPoint(150, 150))); - EXPECT_FALSE(triangle.contains(FloatPoint(100, 100))); - EXPECT_FALSE(triangle.contains(FloatPoint(149, 149))); - EXPECT_FALSE(triangle.contains(FloatPoint(150, 200.5))); - EXPECT_FALSE(triangle.contains(FloatPoint(201, 200.5))); -} - -/** - * Tests FloatPolygon::contains() with a right triangle, and fillRule = evenodd; - * - * 200,100 - * /| - * / | - * / | - * ----- - * 100,200 200,200 - */ -TEST(FloatPolygonTest, triangle_evenodd) -{ - const float triangleCoordinates[] = {200, 100, 200, 200, 100, 200}; - FloatPolygonTestValue triangleTestValue(triangleCoordinates, SIZEOF_ARRAY(triangleCoordinates), RULE_EVENODD); - const FloatPolygon& triangle = triangleTestValue.polygon(); - - EXPECT_EQ(RULE_EVENODD, triangle.fillRule()); - EXPECT_TRUE(triangle.contains(FloatPoint(200, 100))); - EXPECT_TRUE(triangle.contains(FloatPoint(200, 200))); - EXPECT_TRUE(triangle.contains(FloatPoint(100, 200))); - EXPECT_TRUE(triangle.contains(FloatPoint(150, 150))); - EXPECT_FALSE(triangle.contains(FloatPoint(100, 100))); - EXPECT_FALSE(triangle.contains(FloatPoint(149, 149))); - EXPECT_FALSE(triangle.contains(FloatPoint(150, 200.5))); - EXPECT_FALSE(triangle.contains(FloatPoint(201, 200.5))); -} - -#define TEST_EMPTY(coordinates) \ -{ \ - FloatPolygonTestValue emptyPolygonTestValue(coordinates, SIZEOF_ARRAY(coordinates), RULE_NONZERO); \ - const FloatPolygon& emptyPolygon = emptyPolygonTestValue.polygon(); \ - EXPECT_TRUE(emptyPolygon.isEmpty()); \ -} - -TEST(FloatPolygonTest, emptyPolygons) -{ - const float emptyCoordinates1[] = {0, 0}; - TEST_EMPTY(emptyCoordinates1); - - const float emptyCoordinates2[] = {0, 0, 1, 1}; - TEST_EMPTY(emptyCoordinates2); - - const float emptyCoordinates3[] = {0, 0, 1, 1, 2, 2, 3, 3}; - TEST_EMPTY(emptyCoordinates3); - - const float emptyCoordinates4[] = {0, 0, 1, 1, 2, 2, 3, 3, 1, 1}; - TEST_EMPTY(emptyCoordinates4); - - const float emptyCoordinates5[] = {0, 0, 0, 1, 0, 2, 0, 3, 0, 1}; - TEST_EMPTY(emptyCoordinates5); - - const float emptyCoordinates6[] = {0, 0, 1, 0, 2, 0, 3, 0, 1, 0}; - TEST_EMPTY(emptyCoordinates6); -} - -/* - * Test FloatPolygon::contains() with a trapezoid. The vertices are listed in counter-clockwise order. - * - * 150,100 250,100 - * +----------+ - * / \ - * / \ - * +----------------+ - * 100,150 300,150 - */ -TEST(FloatPolygonTest, trapezoid) -{ - const float trapezoidCoordinates[] = {100, 150, 300, 150, 250, 100, 150, 100}; - FloatPolygonTestValue trapezoidTestValue(trapezoidCoordinates, SIZEOF_ARRAY(trapezoidCoordinates), RULE_EVENODD); - const FloatPolygon& trapezoid = trapezoidTestValue.polygon(); - - EXPECT_FALSE(trapezoid.isEmpty()); - EXPECT_EQ(4u, trapezoid.numberOfVertices()); - EXPECT_EQ(FloatRect(100, 100, 200, 50), trapezoid.boundingBox()); - - EXPECT_TRUE(trapezoid.contains(FloatPoint(150, 100))); - EXPECT_TRUE(trapezoid.contains(FloatPoint(150, 101))); - EXPECT_TRUE(trapezoid.contains(FloatPoint(200, 125))); - EXPECT_FALSE(trapezoid.contains(FloatPoint(149, 100))); - EXPECT_FALSE(trapezoid.contains(FloatPoint(301, 150))); -} - - -/* - * Test FloatPolygon::contains() with a non-convex rectilinear polygon. The polygon has the same shape - * as the letter "H": - * - * 100,100 150,100 200,100 250,100 - * +--------+ +--------+ - * | | | | - * | | | | - * | +--------+ | - * | 150,150 200,150 | - * | | - * | 150,200 200,200 | - * | +--------+ | - * | | | | - * | | | | - * +--------+ +--------+ - * 100,250 150,250 200,250 250,250 - */ -TEST(FloatPolygonTest, rectilinear) -{ - const float hCoordinates[] = {100, 100, 150, 100, 150, 150, 200, 150, 200, 100, 250, 100, 250, 250, 200, 250, 200, 200, 150, 200, 150, 250, 100, 250}; - FloatPolygonTestValue hTestValue(hCoordinates, SIZEOF_ARRAY(hCoordinates), RULE_NONZERO); - const FloatPolygon& h = hTestValue.polygon(); - - EXPECT_FALSE(h.isEmpty()); - EXPECT_EQ(12u, h.numberOfVertices()); - EXPECT_EQ(FloatRect(100, 100, 150, 150), h.boundingBox()); - - EXPECT_TRUE(h.contains(FloatPoint(100, 100))); - EXPECT_TRUE(h.contains(FloatPoint(125, 100))); - EXPECT_TRUE(h.contains(FloatPoint(125, 125))); - EXPECT_TRUE(h.contains(FloatPoint(150, 100))); - EXPECT_TRUE(h.contains(FloatPoint(200, 200))); - EXPECT_TRUE(h.contains(FloatPoint(225, 225))); - EXPECT_TRUE(h.contains(FloatPoint(250, 250))); - EXPECT_TRUE(h.contains(FloatPoint(100, 250))); - EXPECT_TRUE(h.contains(FloatPoint(125, 250))); - - EXPECT_FALSE(h.contains(FloatPoint(99, 100))); - EXPECT_FALSE(h.contains(FloatPoint(251, 100))); - EXPECT_FALSE(h.contains(FloatPoint(151, 100))); - EXPECT_FALSE(h.contains(FloatPoint(199, 100))); - EXPECT_FALSE(h.contains(FloatPoint(175, 125))); - EXPECT_FALSE(h.contains(FloatPoint(151, 250))); - EXPECT_FALSE(h.contains(FloatPoint(199, 250))); - EXPECT_FALSE(h.contains(FloatPoint(199, 250))); - EXPECT_FALSE(h.contains(FloatPoint(175, 225))); -} - -} // namespace diff --git a/engine/platform/testing/ArenaTestHelpers.h b/engine/platform/testing/ArenaTestHelpers.h deleted file mode 100644 index 19d3b81c483..00000000000 --- a/engine/platform/testing/ArenaTestHelpers.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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. - */ - -#ifndef ArenaTestHelpers_h -#define ArenaTestHelpers_h - -#include "platform/PODArena.h" -#include "wtf/NotFound.h" -#include "wtf/Vector.h" - -#include - -namespace blink { -namespace ArenaTestHelpers { - -// An allocator for the PODArena which tracks the regions which have -// been allocated. -class TrackedAllocator final : public PODArena::FastMallocAllocator { -public: - static PassRefPtr create() - { - return adoptRef(new TrackedAllocator); - } - - virtual void* allocate(size_t size) override - { - void* result = PODArena::FastMallocAllocator::allocate(size); - m_allocatedRegions.append(result); - return result; - } - - virtual void free(void* ptr) override - { - size_t slot = m_allocatedRegions.find(ptr); - ASSERT_NE(slot, kNotFound); - m_allocatedRegions.remove(slot); - PODArena::FastMallocAllocator::free(ptr); - } - - bool isEmpty() const - { - return !numRegions(); - } - - int numRegions() const - { - return m_allocatedRegions.size(); - } - -private: - TrackedAllocator() { } - Vector m_allocatedRegions; -}; - -} // namespace ArenaTestHelpers -} // namespace blink - -#endif // ArenaTestHelpers_h