blob: e80509ecca05d2cc8ed106607041f5cccc3e3794 [file] [log] [blame]
/*
* Copyright (C) 2020-2021 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 INC. 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 INC. 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 "DisplayListItemBuffer.h"
#include "DisplayListItemBufferIdentifier.h"
#include "DisplayListItems.h"
#include <wtf/FastMalloc.h>
namespace WebCore {
namespace DisplayList {
#if !defined(NDEBUG) || !LOG_DISABLED
CString ItemHandle::description() const
{
TextStream ts;
ts << *this;
return ts.release().utf8();
}
#endif
void ItemHandle::apply(GraphicsContext& context)
{
switch (type()) {
case ItemType::Save:
get<Save>().apply(context);
return;
case ItemType::Restore:
get<Restore>().apply(context);
return;
case ItemType::Translate:
get<Translate>().apply(context);
return;
case ItemType::Rotate:
get<Rotate>().apply(context);
return;
case ItemType::Scale:
get<Scale>().apply(context);
return;
case ItemType::ConcatenateCTM:
get<ConcatenateCTM>().apply(context);
return;
case ItemType::SetCTM:
get<SetCTM>().apply(context);
return;
case ItemType::SetInlineFillColor:
get<SetInlineFillColor>().apply(context);
return;
case ItemType::SetInlineStrokeColor:
get<SetInlineStrokeColor>().apply(context);
return;
case ItemType::SetStrokeThickness:
get<SetStrokeThickness>().apply(context);
return;
case ItemType::SetState:
ASSERT_NOT_REACHED();
return;
case ItemType::SetLineCap:
get<SetLineCap>().apply(context);
return;
case ItemType::SetLineDash:
get<SetLineDash>().apply(context);
return;
case ItemType::SetLineJoin:
get<SetLineJoin>().apply(context);
return;
case ItemType::SetMiterLimit:
get<SetMiterLimit>().apply(context);
return;
case ItemType::ClearShadow:
get<ClearShadow>().apply(context);
return;
case ItemType::Clip:
get<Clip>().apply(context);
return;
case ItemType::ClipOut:
get<ClipOut>().apply(context);
return;
case ItemType::ClipToImageBuffer:
get<ClipToImageBuffer>().apply(context);
return;
case ItemType::ClipOutToPath:
get<ClipOutToPath>().apply(context);
return;
case ItemType::ClipPath:
get<ClipPath>().apply(context);
return;
case ItemType::BeginClipToDrawingCommands:
ASSERT_NOT_REACHED();
return;
case ItemType::EndClipToDrawingCommands:
ASSERT_NOT_REACHED();
return;
case ItemType::DrawGlyphs:
ASSERT_NOT_REACHED();
return;
case ItemType::DrawImageBuffer:
get<DrawImageBuffer>().apply(context);
return;
case ItemType::DrawNativeImage:
get<DrawNativeImage>().apply(context);
return;
case ItemType::DrawPattern:
get<DrawPattern>().apply(context);
return;
case ItemType::DrawRect:
get<DrawRect>().apply(context);
return;
case ItemType::DrawLine:
get<DrawLine>().apply(context);
return;
case ItemType::DrawLinesForText:
get<DrawLinesForText>().apply(context);
return;
case ItemType::DrawDotsForDocumentMarker:
get<DrawDotsForDocumentMarker>().apply(context);
return;
case ItemType::DrawEllipse:
get<DrawEllipse>().apply(context);
return;
case ItemType::DrawPath:
get<DrawPath>().apply(context);
return;
case ItemType::DrawFocusRingPath:
get<DrawFocusRingPath>().apply(context);
return;
case ItemType::DrawFocusRingRects:
get<DrawFocusRingRects>().apply(context);
return;
case ItemType::FillRect:
get<FillRect>().apply(context);
return;
case ItemType::FillRectWithColor:
get<FillRectWithColor>().apply(context);
return;
case ItemType::FillRectWithGradient:
get<FillRectWithGradient>().apply(context);
return;
case ItemType::FillCompositedRect:
get<FillCompositedRect>().apply(context);
return;
case ItemType::FillRoundedRect:
get<FillRoundedRect>().apply(context);
return;
case ItemType::FillRectWithRoundedHole:
get<FillRectWithRoundedHole>().apply(context);
return;
#if ENABLE(INLINE_PATH_DATA)
case ItemType::FillLine:
get<FillLine>().apply(context);
return;
case ItemType::FillArc:
get<FillArc>().apply(context);
return;
case ItemType::FillQuadCurve:
get<FillQuadCurve>().apply(context);
return;
case ItemType::FillBezierCurve:
get<FillBezierCurve>().apply(context);
return;
#endif
case ItemType::FillPath:
get<FillPath>().apply(context);
return;
case ItemType::FillEllipse:
get<FillEllipse>().apply(context);
return;
case ItemType::FlushContext:
get<FlushContext>().apply(context);
return;
case ItemType::GetPixelBuffer:
case ItemType::PutPixelBuffer:
// Should already be handled by the delegate.
ASSERT_NOT_REACHED();
return;
#if ENABLE(VIDEO)
case ItemType::PaintFrameForMedia:
get<PaintFrameForMedia>().apply(context);
return;
#endif
case ItemType::StrokeRect:
get<StrokeRect>().apply(context);
return;
case ItemType::StrokeLine:
get<StrokeLine>().apply(context);
return;
#if ENABLE(INLINE_PATH_DATA)
case ItemType::StrokeArc:
get<StrokeArc>().apply(context);
return;
case ItemType::StrokeQuadCurve:
get<StrokeQuadCurve>().apply(context);
return;
case ItemType::StrokeBezierCurve:
get<StrokeBezierCurve>().apply(context);
return;
#endif
case ItemType::StrokePath:
get<StrokePath>().apply(context);
return;
case ItemType::StrokeEllipse:
get<StrokeEllipse>().apply(context);
return;
case ItemType::ClearRect:
get<ClearRect>().apply(context);
return;
case ItemType::BeginTransparencyLayer:
get<BeginTransparencyLayer>().apply(context);
return;
case ItemType::EndTransparencyLayer:
get<EndTransparencyLayer>().apply(context);
return;
#if USE(CG)
case ItemType::ApplyStrokePattern:
get<ApplyStrokePattern>().apply(context);
return;
case ItemType::ApplyFillPattern:
get<ApplyFillPattern>().apply(context);
return;
#endif
case ItemType::ApplyDeviceScaleFactor:
get<ApplyDeviceScaleFactor>().apply(context);
return;
}
}
void ItemHandle::destroy()
{
switch (type()) {
case ItemType::ClipOutToPath:
get<ClipOutToPath>().~ClipOutToPath();
return;
case ItemType::ClipPath:
get<ClipPath>().~ClipPath();
return;
case ItemType::DrawFocusRingPath:
get<DrawFocusRingPath>().~DrawFocusRingPath();
return;
case ItemType::DrawFocusRingRects:
get<DrawFocusRingRects>().~DrawFocusRingRects();
return;
case ItemType::DrawGlyphs:
get<DrawGlyphs>().~DrawGlyphs();
return;
case ItemType::DrawLinesForText:
get<DrawLinesForText>().~DrawLinesForText();
return;
case ItemType::DrawPath:
get<DrawPath>().~DrawPath();
return;
case ItemType::FillCompositedRect:
get<FillCompositedRect>().~FillCompositedRect();
return;
case ItemType::FillPath:
get<FillPath>().~FillPath();
return;
case ItemType::FillRectWithColor:
get<FillRectWithColor>().~FillRectWithColor();
return;
case ItemType::FillRectWithGradient:
get<FillRectWithGradient>().~FillRectWithGradient();
return;
case ItemType::FillRectWithRoundedHole:
get<FillRectWithRoundedHole>().~FillRectWithRoundedHole();
return;
case ItemType::FillRoundedRect:
get<FillRoundedRect>().~FillRoundedRect();
return;
case ItemType::GetPixelBuffer:
get<GetPixelBuffer>().~GetPixelBuffer();
return;
case ItemType::PutPixelBuffer:
get<PutPixelBuffer>().~PutPixelBuffer();
return;
case ItemType::SetLineDash:
get<SetLineDash>().~SetLineDash();
return;
case ItemType::SetState:
get<SetState>().~SetState();
return;
case ItemType::StrokePath:
get<StrokePath>().~StrokePath();
return;
case ItemType::ApplyDeviceScaleFactor:
static_assert(std::is_trivially_destructible<ApplyDeviceScaleFactor>::value);
return;
#if USE(CG)
case ItemType::ApplyFillPattern:
static_assert(std::is_trivially_destructible<ApplyFillPattern>::value);
return;
case ItemType::ApplyStrokePattern:
static_assert(std::is_trivially_destructible<ApplyStrokePattern>::value);
return;
#endif
case ItemType::BeginClipToDrawingCommands:
get<BeginClipToDrawingCommands>().~BeginClipToDrawingCommands();
return;
case ItemType::BeginTransparencyLayer:
static_assert(std::is_trivially_destructible<BeginTransparencyLayer>::value);
return;
case ItemType::ClearRect:
static_assert(std::is_trivially_destructible<ClearRect>::value);
return;
case ItemType::ClearShadow:
static_assert(std::is_trivially_destructible<ClearShadow>::value);
return;
case ItemType::Clip:
static_assert(std::is_trivially_destructible<Clip>::value);
return;
case ItemType::ClipOut:
static_assert(std::is_trivially_destructible<ClipOut>::value);
return;
case ItemType::ClipToImageBuffer:
static_assert(std::is_trivially_destructible<ClipToImageBuffer>::value);
return;
case ItemType::ConcatenateCTM:
static_assert(std::is_trivially_destructible<ConcatenateCTM>::value);
return;
case ItemType::DrawDotsForDocumentMarker:
static_assert(std::is_trivially_destructible<DrawDotsForDocumentMarker>::value);
return;
case ItemType::DrawEllipse:
static_assert(std::is_trivially_destructible<DrawEllipse>::value);
return;
case ItemType::DrawImageBuffer:
static_assert(std::is_trivially_destructible<DrawImageBuffer>::value);
return;
case ItemType::DrawNativeImage:
static_assert(std::is_trivially_destructible<DrawNativeImage>::value);
return;
case ItemType::DrawPattern:
static_assert(std::is_trivially_destructible<DrawPattern>::value);
return;
case ItemType::DrawLine:
static_assert(std::is_trivially_destructible<DrawLine>::value);
return;
case ItemType::DrawRect:
static_assert(std::is_trivially_destructible<DrawRect>::value);
return;
case ItemType::EndClipToDrawingCommands:
static_assert(std::is_trivially_destructible<EndClipToDrawingCommands>::value);
return;
case ItemType::EndTransparencyLayer:
static_assert(std::is_trivially_destructible<EndTransparencyLayer>::value);
return;
case ItemType::FillEllipse:
static_assert(std::is_trivially_destructible<FillEllipse>::value);
return;
#if ENABLE(INLINE_PATH_DATA)
case ItemType::FillLine:
static_assert(std::is_trivially_destructible<FillLine>::value);
return;
case ItemType::FillArc:
static_assert(std::is_trivially_destructible<FillArc>::value);
return;
case ItemType::FillQuadCurve:
static_assert(std::is_trivially_destructible<FillQuadCurve>::value);
return;
case ItemType::FillBezierCurve:
static_assert(std::is_trivially_destructible<FillBezierCurve>::value);
return;
#endif
case ItemType::FillRect:
static_assert(std::is_trivially_destructible<FillRect>::value);
return;
case ItemType::FlushContext:
static_assert(std::is_trivially_destructible<FlushContext>::value);
return;
#if ENABLE(VIDEO)
case ItemType::PaintFrameForMedia:
static_assert(std::is_trivially_destructible<PaintFrameForMedia>::value);
return;
#endif
case ItemType::Restore:
static_assert(std::is_trivially_destructible<Restore>::value);
return;
case ItemType::Rotate:
static_assert(std::is_trivially_destructible<Rotate>::value);
return;
case ItemType::Save:
static_assert(std::is_trivially_destructible<Save>::value);
return;
case ItemType::Scale:
static_assert(std::is_trivially_destructible<Scale>::value);
return;
case ItemType::SetCTM:
static_assert(std::is_trivially_destructible<SetCTM>::value);
return;
case ItemType::SetInlineFillColor:
static_assert(std::is_trivially_destructible<SetInlineFillColor>::value);
return;
case ItemType::SetInlineStrokeColor:
static_assert(std::is_trivially_destructible<SetInlineStrokeColor>::value);
return;
case ItemType::SetLineCap:
static_assert(std::is_trivially_destructible<SetLineCap>::value);
return;
case ItemType::SetLineJoin:
static_assert(std::is_trivially_destructible<SetLineJoin>::value);
return;
case ItemType::SetMiterLimit:
static_assert(std::is_trivially_destructible<SetMiterLimit>::value);
return;
case ItemType::SetStrokeThickness:
static_assert(std::is_trivially_destructible<SetStrokeThickness>::value);
return;
case ItemType::StrokeEllipse:
static_assert(std::is_trivially_destructible<StrokeEllipse>::value);
return;
#if ENABLE(INLINE_PATH_DATA)
case ItemType::StrokeArc:
static_assert(std::is_trivially_destructible<StrokeArc>::value);
return;
case ItemType::StrokeQuadCurve:
static_assert(std::is_trivially_destructible<StrokeQuadCurve>::value);
return;
case ItemType::StrokeBezierCurve:
static_assert(std::is_trivially_destructible<StrokeBezierCurve>::value);
return;
#endif
case ItemType::StrokeRect:
static_assert(std::is_trivially_destructible<StrokeRect>::value);
return;
case ItemType::StrokeLine:
static_assert(std::is_trivially_destructible<StrokeLine>::value);
return;
case ItemType::Translate:
static_assert(std::is_trivially_destructible<Translate>::value);
return;
}
}
template<typename, typename = void> inline constexpr bool HasIsValid = false;
template<typename T> inline constexpr bool HasIsValid<T, std::void_t<decltype(std::declval<T>().isValid())>> = true;
template<typename Item>
static inline typename std::enable_if_t<!HasIsValid<Item>, bool> isValid(const Item&)
{
return true;
}
template<typename Item>
static inline typename std::enable_if_t<HasIsValid<Item>, bool> isValid(const Item& item)
{
return item.isValid();
}
template<typename Item>
static inline bool copyInto(uint8_t* destinationWithOffset, const Item& item)
{
auto* newItem = new (destinationWithOffset) Item(item);
return isValid(*newItem);
}
template<typename Item>
static inline bool copyInto(uint8_t* destinationWithOffset, const ItemHandle& itemHandle)
{
return copyInto(destinationWithOffset, itemHandle.get<Item>());
}
bool ItemHandle::safeCopy(ItemType itemType, ItemHandle destination) const
{
ASSERT(itemType == type());
destination.data[0] = static_cast<uint8_t>(itemType);
auto itemOffset = destination.data + sizeof(uint64_t);
switch (itemType) {
case ItemType::ClipOutToPath:
return copyInto<ClipOutToPath>(itemOffset, *this);
case ItemType::ClipPath:
return copyInto<ClipPath>(itemOffset, *this);
case ItemType::DrawFocusRingPath:
return copyInto<DrawFocusRingPath>(itemOffset, *this);
case ItemType::DrawFocusRingRects:
return copyInto<DrawFocusRingRects>(itemOffset, *this);
case ItemType::DrawGlyphs:
return copyInto<DrawGlyphs>(itemOffset, *this);
case ItemType::DrawImageBuffer:
return copyInto<DrawImageBuffer>(itemOffset, *this);
case ItemType::DrawLinesForText:
return copyInto<DrawLinesForText>(itemOffset, *this);
case ItemType::DrawNativeImage:
return copyInto<DrawNativeImage>(itemOffset, *this);
case ItemType::DrawPattern:
return copyInto<DrawPattern>(itemOffset, *this);
case ItemType::DrawPath:
return copyInto<DrawPath>(itemOffset, *this);
case ItemType::FillCompositedRect:
return copyInto<FillCompositedRect>(itemOffset, *this);
case ItemType::FillPath:
return copyInto<FillPath>(itemOffset, *this);
case ItemType::FillRectWithColor:
return copyInto<FillRectWithColor>(itemOffset, *this);
case ItemType::FillRectWithGradient:
return copyInto<FillRectWithGradient>(itemOffset, *this);
case ItemType::FillRectWithRoundedHole:
return copyInto<FillRectWithRoundedHole>(itemOffset, *this);
case ItemType::FillRoundedRect:
return copyInto<FillRoundedRect>(itemOffset, *this);
case ItemType::GetPixelBuffer:
return copyInto<GetPixelBuffer>(itemOffset, *this);
case ItemType::PutPixelBuffer:
return copyInto<PutPixelBuffer>(itemOffset, *this);
case ItemType::SetLineDash:
return copyInto<SetLineDash>(itemOffset, *this);
case ItemType::SetState:
return copyInto<SetState>(itemOffset, *this);
case ItemType::StrokePath:
return copyInto<StrokePath>(itemOffset, *this);
case ItemType::ApplyDeviceScaleFactor:
return copyInto<ApplyDeviceScaleFactor>(itemOffset, *this);
#if USE(CG)
case ItemType::ApplyFillPattern:
return copyInto<ApplyFillPattern>(itemOffset, *this);
case ItemType::ApplyStrokePattern:
return copyInto<ApplyStrokePattern>(itemOffset, *this);
#endif
case ItemType::BeginClipToDrawingCommands:
return copyInto<BeginClipToDrawingCommands>(itemOffset, *this);
case ItemType::BeginTransparencyLayer:
return copyInto<BeginTransparencyLayer>(itemOffset, *this);
case ItemType::ClearRect:
return copyInto<ClearRect>(itemOffset, *this);
case ItemType::ClearShadow:
return copyInto<ClearShadow>(itemOffset, *this);
case ItemType::Clip:
return copyInto<Clip>(itemOffset, *this);
case ItemType::ClipOut:
return copyInto<ClipOut>(itemOffset, *this);
case ItemType::ClipToImageBuffer:
return copyInto<ClipToImageBuffer>(itemOffset, *this);
case ItemType::ConcatenateCTM:
return copyInto<ConcatenateCTM>(itemOffset, *this);
case ItemType::DrawDotsForDocumentMarker:
return copyInto<DrawDotsForDocumentMarker>(itemOffset, *this);
case ItemType::DrawEllipse:
return copyInto<DrawEllipse>(itemOffset, *this);
case ItemType::DrawLine:
return copyInto<DrawLine>(itemOffset, *this);
case ItemType::DrawRect:
return copyInto<DrawRect>(itemOffset, *this);
case ItemType::EndClipToDrawingCommands:
return copyInto<EndClipToDrawingCommands>(itemOffset, *this);
case ItemType::EndTransparencyLayer:
return copyInto<EndTransparencyLayer>(itemOffset, *this);
case ItemType::FillEllipse:
return copyInto<FillEllipse>(itemOffset, *this);
#if ENABLE(INLINE_PATH_DATA)
case ItemType::FillLine:
return copyInto<FillLine>(itemOffset, *this);
case ItemType::FillArc:
return copyInto<FillArc>(itemOffset, *this);
case ItemType::FillQuadCurve:
return copyInto<FillQuadCurve>(itemOffset, *this);
case ItemType::FillBezierCurve:
return copyInto<FillBezierCurve>(itemOffset, *this);
#endif
case ItemType::FillRect:
return copyInto<FillRect>(itemOffset, *this);
case ItemType::FlushContext:
return copyInto<FlushContext>(itemOffset, *this);
#if ENABLE(VIDEO)
case ItemType::PaintFrameForMedia:
return copyInto<PaintFrameForMedia>(itemOffset, *this);
#endif
case ItemType::Restore:
return copyInto<Restore>(itemOffset, *this);
case ItemType::Rotate:
return copyInto<Rotate>(itemOffset, *this);
case ItemType::Save:
return copyInto<Save>(itemOffset, *this);
case ItemType::Scale:
return copyInto<Scale>(itemOffset, *this);
case ItemType::SetCTM:
return copyInto<SetCTM>(itemOffset, *this);
case ItemType::SetInlineFillColor:
return copyInto<SetInlineFillColor>(itemOffset, *this);
case ItemType::SetInlineStrokeColor:
return copyInto<SetInlineStrokeColor>(itemOffset, *this);
case ItemType::SetLineCap:
return copyInto<SetLineCap>(itemOffset, *this);
case ItemType::SetLineJoin:
return copyInto<SetLineJoin>(itemOffset, *this);
case ItemType::SetMiterLimit:
return copyInto<SetMiterLimit>(itemOffset, *this);
case ItemType::SetStrokeThickness:
return copyInto<SetStrokeThickness>(itemOffset, *this);
case ItemType::StrokeEllipse:
return copyInto<StrokeEllipse>(itemOffset, *this);
#if ENABLE(INLINE_PATH_DATA)
case ItemType::StrokeArc:
return copyInto<StrokeArc>(itemOffset, *this);
case ItemType::StrokeQuadCurve:
return copyInto<StrokeQuadCurve>(itemOffset, *this);
case ItemType::StrokeBezierCurve:
return copyInto<StrokeBezierCurve>(itemOffset, *this);
#endif
case ItemType::StrokeRect:
return copyInto<StrokeRect>(itemOffset, *this);
case ItemType::StrokeLine:
return copyInto<StrokeLine>(itemOffset, *this);
case ItemType::Translate:
return copyInto<Translate>(itemOffset, *this);
}
return false;
}
bool safeCopy(ItemHandle destination, const DisplayListItem& source)
{
return std::visit([&](const auto& source) {
using DisplayListItemType = typename WTF::RemoveCVAndReference<decltype(source)>::type;
constexpr auto itemType = DisplayListItemType::itemType;
destination.data[0] = static_cast<uint8_t>(itemType);
auto itemOffset = destination.data + sizeof(uint64_t);
return copyInto<DisplayListItemType>(itemOffset, source);
}, source);
}
ItemBuffer::ItemBuffer(ItemBufferHandles&& handles)
: m_readOnlyBuffers(WTFMove(handles))
{
}
ItemBuffer::ItemBuffer() = default;
ItemBuffer::~ItemBuffer()
{
clear();
}
ItemBuffer::ItemBuffer(ItemBuffer&& other)
: m_readingClient(std::exchange(other.m_readingClient, nullptr))
, m_writingClient(std::exchange(other.m_writingClient, nullptr))
, m_allocatedBuffers(std::exchange(other.m_allocatedBuffers, { }))
, m_readOnlyBuffers(std::exchange(other.m_readOnlyBuffers, { }))
, m_writableBuffer(std::exchange(other.m_writableBuffer, { }))
, m_writtenNumberOfBytes(std::exchange(other.m_writtenNumberOfBytes, 0))
{
}
ItemBuffer& ItemBuffer::operator=(ItemBuffer&& other)
{
m_readingClient = std::exchange(other.m_readingClient, nullptr);
m_writingClient = std::exchange(other.m_writingClient, nullptr);
m_allocatedBuffers = std::exchange(other.m_allocatedBuffers, { });
m_readOnlyBuffers = std::exchange(other.m_readOnlyBuffers, { });
m_writableBuffer = std::exchange(other.m_writableBuffer, { });
m_writtenNumberOfBytes = std::exchange(other.m_writtenNumberOfBytes, 0);
return *this;
}
ItemBufferHandle ItemBuffer::createItemBuffer(size_t capacity)
{
if (m_writingClient) {
if (auto handle = m_writingClient->createItemBuffer(capacity))
return handle;
}
constexpr size_t defaultItemBufferCapacity = 1 << 10;
auto newBufferCapacity = std::max(capacity, defaultItemBufferCapacity);
auto* buffer = static_cast<uint8_t*>(fastMalloc(newBufferCapacity));
m_allocatedBuffers.append(buffer);
return { ItemBufferIdentifier::generate(), buffer, newBufferCapacity };
}
void ItemBuffer::forEachItemBuffer(Function<void(const ItemBufferHandle&)>&& mapFunction) const
{
for (auto& handle : m_readOnlyBuffers)
mapFunction(handle);
if (m_writableBuffer && m_writtenNumberOfBytes)
mapFunction({ m_writableBuffer.identifier, m_writableBuffer.data, m_writtenNumberOfBytes });
}
void ItemBuffer::clear()
{
for (auto* buffer : std::exchange(m_allocatedBuffers, { }))
fastFree(buffer);
m_readOnlyBuffers.clear();
m_writableBuffer = { };
m_writtenNumberOfBytes = 0;
}
void ItemBuffer::shrinkToFit()
{
m_allocatedBuffers.shrinkToFit();
}
DidChangeItemBuffer ItemBuffer::swapWritableBufferIfNeeded(size_t numberOfBytes)
{
if (m_writtenNumberOfBytes + numberOfBytes <= m_writableBuffer.capacity)
return DidChangeItemBuffer::No;
auto nextBuffer = createItemBuffer(numberOfBytes);
bool hadPreviousBuffer = m_writableBuffer && m_writableBuffer.identifier != nextBuffer.identifier;
if (hadPreviousBuffer) {
m_writableBuffer.capacity = m_writtenNumberOfBytes;
m_readOnlyBuffers.append(m_writableBuffer);
}
m_writtenNumberOfBytes = 0;
m_writableBuffer = WTFMove(nextBuffer);
return hadPreviousBuffer ? DidChangeItemBuffer::Yes : DidChangeItemBuffer::No;
}
void ItemBuffer::append(const DisplayListItem& temporaryItem)
{
auto requiredSizeForItem = m_writingClient->requiredSizeForItem(temporaryItem);
RefPtr<SharedBuffer> outOfLineItem;
if (!requiredSizeForItem) {
outOfLineItem = m_writingClient->encodeItemOutOfLine(temporaryItem);
if (!outOfLineItem)
return;
}
auto dataLength = valueOrCompute(requiredSizeForItem, [&] {
ASSERT(outOfLineItem);
return outOfLineItem->size();
});
auto additionalCapacityForEncodedItem = 2 * sizeof(uint64_t) + roundUpToMultipleOf(alignof(uint64_t), dataLength);
auto bufferChanged = swapWritableBufferIfNeeded(additionalCapacityForEncodedItem);
m_writableBuffer.data[m_writtenNumberOfBytes] = static_cast<uint8_t>(displayListItemType(temporaryItem));
reinterpret_cast<uint64_t*>(m_writableBuffer.data + m_writtenNumberOfBytes)[1] = dataLength;
auto* location = m_writableBuffer.data + m_writtenNumberOfBytes + 2 * sizeof(uint64_t);
if (requiredSizeForItem)
m_writingClient->encodeItemInline(temporaryItem, location);
else
outOfLineItem->copyTo(location, dataLength);
didAppendData(additionalCapacityForEncodedItem, bufferChanged);
}
void ItemBuffer::didAppendData(size_t numberOfBytes, DidChangeItemBuffer didChangeItemBuffer)
{
m_writtenNumberOfBytes += numberOfBytes;
if (m_writingClient)
m_writingClient->didAppendData(m_writableBuffer, numberOfBytes, didChangeItemBuffer);
}
void ItemBuffer::prepareToAppend(ItemBufferHandle&& handle)
{
m_writtenNumberOfBytes = 0;
m_readOnlyBuffers.append(std::exchange(m_writableBuffer, WTFMove(handle)));
}
} // namespace DisplayList
} // namespace WebCore