Index: Source/platform/graphics/paint/DisplayItems.cpp |
diff --git a/Source/platform/graphics/paint/DisplayItems.cpp b/Source/platform/graphics/paint/DisplayItems.cpp |
index 78c940dd9fbb388db8aafa2f38485e799f974a76..ad3612d29396432ddb96e85e8bd164382e7cdf20 100644 |
--- a/Source/platform/graphics/paint/DisplayItems.cpp |
+++ b/Source/platform/graphics/paint/DisplayItems.cpp |
@@ -5,8 +5,12 @@ |
#include "config.h" |
#include "platform/graphics/paint/DisplayItems.h" |
+#include <algorithm> |
+ |
namespace blink { |
+static const size_t capacityOfFirstInnerVector = 32; |
+ |
DisplayItems::DisplayItems() |
{ |
} |
@@ -15,36 +19,89 @@ DisplayItems::~DisplayItems() |
{ |
} |
-void DisplayItems::append(PassOwnPtr<DisplayItem> displayItem) |
-{ |
- m_items.append(displayItem); |
-} |
- |
void DisplayItems::appendByMoving(const Iterator& it) |
{ |
- // Release the underlying OwnPtr to move the display item ownership. |
ASSERT(!it->isGone()); |
- append(it.m_iterator->release()); |
+ |
+ DisplayItem& oldItem = *it->m_ptr; |
+ |
+ DisplayItemClient scopeContainer = oldItem.m_scopeContainer; |
+ int scopeId = oldItem.m_scopeId; |
+ bool skippedCache = oldItem.skippedCache(); |
+ |
+ oldItem.appendByMoving(*this); |
+ |
+ // TODO(jbroman): appendByMoving should preserve these properties, but at |
+ // present it does not. |
+ DisplayItem& newItem = *m_items.last(); |
+ if (scopeContainer) |
+ newItem.setScope(scopeId, scopeContainer); |
+ if (skippedCache) |
+ newItem.setSkippedCache(); |
} |
void DisplayItems::removeLast() |
{ |
+ ASSERT(!isEmpty()); |
+ |
+ // Find the last non-empty buffer. This is where the last element is. |
+ auto it = std::find_if( |
+ m_buffers.rbegin(), m_buffers.rend(), |
+ [](const OwnPtr<InnerVector>& innerVector) { return !innerVector->isEmpty(); }); |
+ ASSERT(it != m_buffers.rend()); |
+ |
+ // This is the vector which contains the last element. |
+ // We can now remove the element. |
+ // (The pointer in m_items may be null to indicate "gone".) |
+ InnerVector& innerVector = **it; |
+ RELEASE_ASSERT(innerVector.last().asDisplayItem() == m_items.last() || !m_items.last()); |
+ innerVector.removeLast(); |
m_items.removeLast(); |
+ |
+ // If there's an empty buffer after this one, remove it. |
+ if (it != m_buffers.rbegin()) |
+ m_buffers.removeLast(); |
} |
void DisplayItems::clear() |
{ |
+ m_buffers.clear(); |
m_items.clear(); |
} |
void DisplayItems::swap(DisplayItems& other) |
{ |
+ m_buffers.swap(other.m_buffers); |
m_items.swap(other.m_items); |
} |
void DisplayItems::setGone(const Iterator& it) |
{ |
- it.m_iterator->clear(); |
+ *it.m_iterator = nullptr; |
+} |
+ |
+DisplayItems::StorageBuffer& DisplayItems::appendStorageBuffer() |
+{ |
+ // Find the first inner vector with space in it. |
+ // We don't want to increase capacity of these vectors. |
+ auto it = std::find_if( |
+ m_buffers.begin(), m_buffers.end(), |
+ [](const OwnPtr<InnerVector>& innerVector) { return innerVector->size() != innerVector->capacity(); }); |
+ |
+ // If there's no space, allocate a new inner vector. |
+ if (it == m_buffers.end()) { |
+ size_t capacity = m_buffers.isEmpty() ? capacityOfFirstInnerVector : 2 * m_buffers.last()->capacity(); |
+ OwnPtr<InnerVector> innerVector = adoptPtr(new InnerVector); |
+ innerVector->reserveInitialCapacity(capacity); |
+ m_buffers.append(innerVector.release()); |
+ it = m_buffers.end() - 1; |
+ } |
+ |
+ // Now that we have the inner vector, we can create storage buffer for one |
+ // display item. |
+ InnerVector& innerVector = **it; |
+ innerVector.grow(innerVector.size() + 1); |
+ return innerVector.last(); |
} |
} // namespace blink |