| /* |
| * 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 |