| /* |
| * Copyright (C) 2016-2022 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. ``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 |
| * 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 "DisplayList.h" |
| |
| #include "DisplayListItemBuffer.h" |
| #include "DisplayListItems.h" |
| #include "DisplayListIterator.h" |
| #include "Filter.h" |
| #include "Logging.h" |
| #include <wtf/FastMalloc.h> |
| #include <wtf/StdLibExtras.h> |
| #include <wtf/text/TextStream.h> |
| |
| namespace WebCore { |
| namespace DisplayList { |
| |
| #if !defined(NDEBUG) || !LOG_DISABLED |
| CString DisplayList::description() const |
| { |
| TextStream ts; |
| dump(ts); |
| return ts.release().utf8(); |
| } |
| |
| void DisplayList::dump() const |
| { |
| fprintf(stderr, "%s", description().data()); |
| } |
| #endif |
| |
| DisplayList::DisplayList(DisplayList&& other) |
| : m_resourceHeap(std::exchange(other.m_resourceHeap, { })) |
| , m_items(std::exchange(other.m_items, nullptr)) |
| , m_drawingItemExtents(std::exchange(other.m_drawingItemExtents, { })) |
| { |
| } |
| |
| DisplayList::DisplayList(ItemBufferHandles&& handles) |
| : m_items(makeUnique<ItemBuffer>(WTFMove(handles))) |
| { |
| } |
| |
| DisplayList::DisplayList() = default; |
| DisplayList::~DisplayList() = default; |
| |
| DisplayList& DisplayList::operator=(DisplayList&& other) |
| { |
| m_resourceHeap = std::exchange(other.m_resourceHeap, { }); |
| m_items = std::exchange(other.m_items, nullptr); |
| m_drawingItemExtents = std::exchange(other.m_drawingItemExtents, { }); |
| return *this; |
| } |
| |
| void DisplayList::clear() |
| { |
| if (m_items) |
| m_items->clear(); |
| m_drawingItemExtents.clear(); |
| m_resourceHeap.clear(); |
| } |
| |
| bool DisplayList::shouldDumpForFlags(OptionSet<AsTextFlag> flags, ItemHandle item) |
| { |
| switch (item.type()) { |
| case ItemType::SetState: |
| if (flags.contains(AsTextFlag::IncludePlatformOperations)) { |
| const auto& stateItem = item.get<SetState>(); |
| // FIXME: for now, only drop the item if the only state-change flags are platform-specific. |
| if (stateItem.state().changes() == GraphicsContextState::Change::ShouldSubpixelQuantizeFonts) |
| return false; |
| } |
| break; |
| #if USE(CG) |
| case ItemType::ApplyFillPattern: |
| case ItemType::ApplyStrokePattern: |
| if (flags.contains(AsTextFlag::IncludePlatformOperations)) |
| return false; |
| break; |
| #endif |
| default: |
| break; |
| } |
| return true; |
| } |
| |
| String DisplayList::asText(OptionSet<AsTextFlag> flags) const |
| { |
| TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect); |
| #if !LOG_DISABLED |
| for (auto displayListItem : *this) { |
| auto [item, extent, itemSizeInBuffer] = displayListItem.value(); |
| if (!shouldDumpForFlags(flags, item)) |
| continue; |
| |
| TextStream::GroupScope group(stream); |
| dumpItemHandle(stream, item, flags); |
| if (item.isDrawingItem()) |
| stream << " extent " << extent; |
| } |
| #else |
| UNUSED_PARAM(flags); |
| #endif |
| return stream.release(); |
| } |
| |
| void DisplayList::dump(TextStream& ts) const |
| { |
| TextStream::GroupScope group(ts); |
| ts << "display list"; |
| |
| #if !LOG_DISABLED |
| for (auto displayListItem : *this) { |
| auto [item, extent, itemSizeInBuffer] = displayListItem.value(); |
| TextStream::GroupScope group(ts); |
| dumpItemHandle(ts, item, { AsTextFlag::IncludePlatformOperations, AsTextFlag::IncludeResourceIdentifiers }); |
| if (item.isDrawingItem()) |
| ts << " extent " << extent; |
| } |
| #endif |
| |
| ts.startGroup(); |
| ts << "size in bytes: " << sizeInBytes(); |
| ts.endGroup(); |
| } |
| |
| size_t DisplayList::sizeInBytes() const |
| { |
| return m_items ? m_items->sizeInBytes() : 0; |
| } |
| |
| bool DisplayList::isEmpty() const |
| { |
| return !m_items || m_items->isEmpty(); |
| } |
| |
| ItemBuffer& DisplayList::itemBuffer() |
| { |
| if (!m_items) |
| m_items = makeUnique<ItemBuffer>(); |
| return *m_items; |
| } |
| |
| void DisplayList::shrinkToFit() |
| { |
| if (auto* itemBuffer = itemBufferIfExists()) |
| itemBuffer->shrinkToFit(); |
| |
| m_drawingItemExtents.shrinkToFit(); |
| } |
| |
| void DisplayList::setItemBufferReadingClient(ItemBufferReadingClient* client) |
| { |
| itemBuffer().setClient(client); |
| } |
| |
| void DisplayList::setItemBufferWritingClient(ItemBufferWritingClient* client) |
| { |
| itemBuffer().setClient(client); |
| } |
| |
| void DisplayList::prepareToAppend(ItemBufferHandle&& handle) |
| { |
| itemBuffer().prepareToAppend(WTFMove(handle)); |
| } |
| |
| void DisplayList::forEachItemBuffer(Function<void(const ItemBufferHandle&)>&& mapFunction) const |
| { |
| if (m_items) |
| m_items->forEachItemBuffer(WTFMove(mapFunction)); |
| } |
| |
| void DisplayList::setTracksDrawingItemExtents(bool value) |
| { |
| RELEASE_ASSERT(isEmpty()); |
| m_tracksDrawingItemExtents = value; |
| } |
| |
| void DisplayList::append(ItemHandle item) |
| { |
| switch (item.type()) { |
| case ItemType::Save: |
| return append<Save>(item.get<Save>()); |
| case ItemType::Restore: |
| return append<Restore>(item.get<Restore>()); |
| case ItemType::Translate: |
| return append<Translate>(item.get<Translate>()); |
| case ItemType::Rotate: |
| return append<Rotate>(item.get<Rotate>()); |
| case ItemType::Scale: |
| return append<Scale>(item.get<Scale>()); |
| case ItemType::ConcatenateCTM: |
| return append<ConcatenateCTM>(item.get<ConcatenateCTM>()); |
| case ItemType::SetCTM: |
| return append<SetCTM>(item.get<SetCTM>()); |
| case ItemType::SetInlineFillColor: |
| return append<SetInlineFillColor>(item.get<SetInlineFillColor>()); |
| case ItemType::SetInlineStrokeColor: |
| return append<SetInlineStrokeColor>(item.get<SetInlineStrokeColor>()); |
| case ItemType::SetStrokeThickness: |
| return append<SetStrokeThickness>(item.get<SetStrokeThickness>()); |
| case ItemType::SetState: |
| return append<SetState>(item.get<SetState>()); |
| case ItemType::SetLineCap: |
| return append<SetLineCap>(item.get<SetLineCap>()); |
| case ItemType::SetLineDash: |
| return append<SetLineDash>(item.get<SetLineDash>()); |
| case ItemType::SetLineJoin: |
| return append<SetLineJoin>(item.get<SetLineJoin>()); |
| case ItemType::SetMiterLimit: |
| return append<SetMiterLimit>(item.get<SetMiterLimit>()); |
| case ItemType::ClearShadow: |
| return append<ClearShadow>(item.get<ClearShadow>()); |
| case ItemType::Clip: |
| return append<Clip>(item.get<Clip>()); |
| case ItemType::ClipOut: |
| return append<ClipOut>(item.get<ClipOut>()); |
| case ItemType::ClipToImageBuffer: |
| return append<ClipToImageBuffer>(item.get<ClipToImageBuffer>()); |
| case ItemType::ClipOutToPath: |
| return append<ClipOutToPath>(item.get<ClipOutToPath>()); |
| case ItemType::ClipPath: |
| return append<ClipPath>(item.get<ClipPath>()); |
| case ItemType::DrawFilteredImageBuffer: |
| return append<DrawFilteredImageBuffer>(item.get<DrawFilteredImageBuffer>()); |
| case ItemType::DrawGlyphs: |
| return append<DrawGlyphs>(item.get<DrawGlyphs>()); |
| case ItemType::DrawDecomposedGlyphs: |
| return append<DrawDecomposedGlyphs>(item.get<DrawDecomposedGlyphs>()); |
| case ItemType::DrawImageBuffer: |
| return append<DrawImageBuffer>(item.get<DrawImageBuffer>()); |
| case ItemType::DrawNativeImage: |
| return append<DrawNativeImage>(item.get<DrawNativeImage>()); |
| case ItemType::DrawSystemImage: |
| return append<DrawSystemImage>(item.get<DrawSystemImage>()); |
| case ItemType::DrawPattern: |
| return append<DrawPattern>(item.get<DrawPattern>()); |
| case ItemType::DrawRect: |
| return append<DrawRect>(item.get<DrawRect>()); |
| case ItemType::DrawLine: |
| return append<DrawLine>(item.get<DrawLine>()); |
| case ItemType::DrawLinesForText: |
| return append<DrawLinesForText>(item.get<DrawLinesForText>()); |
| case ItemType::DrawDotsForDocumentMarker: |
| return append<DrawDotsForDocumentMarker>(item.get<DrawDotsForDocumentMarker>()); |
| case ItemType::DrawEllipse: |
| return append<DrawEllipse>(item.get<DrawEllipse>()); |
| case ItemType::DrawPath: |
| return append<DrawPath>(item.get<DrawPath>()); |
| case ItemType::DrawFocusRingPath: |
| return append<DrawFocusRingPath>(item.get<DrawFocusRingPath>()); |
| case ItemType::DrawFocusRingRects: |
| return append<DrawFocusRingRects>(item.get<DrawFocusRingRects>()); |
| case ItemType::FillRect: |
| return append<FillRect>(item.get<FillRect>()); |
| case ItemType::FillRectWithColor: |
| return append<FillRectWithColor>(item.get<FillRectWithColor>()); |
| case ItemType::FillRectWithGradient: |
| return append<FillRectWithGradient>(item.get<FillRectWithGradient>()); |
| case ItemType::FillCompositedRect: |
| return append<FillCompositedRect>(item.get<FillCompositedRect>()); |
| case ItemType::FillRoundedRect: |
| return append<FillRoundedRect>(item.get<FillRoundedRect>()); |
| case ItemType::FillRectWithRoundedHole: |
| return append<FillRectWithRoundedHole>(item.get<FillRectWithRoundedHole>()); |
| #if ENABLE(INLINE_PATH_DATA) |
| case ItemType::FillLine: |
| return append<FillLine>(item.get<FillLine>()); |
| case ItemType::FillArc: |
| return append<FillArc>(item.get<FillArc>()); |
| case ItemType::FillQuadCurve: |
| return append<FillQuadCurve>(item.get<FillQuadCurve>()); |
| case ItemType::FillBezierCurve: |
| return append<FillBezierCurve>(item.get<FillBezierCurve>()); |
| #endif |
| case ItemType::FillPath: |
| return append<FillPath>(item.get<FillPath>()); |
| case ItemType::FillEllipse: |
| return append<FillEllipse>(item.get<FillEllipse>()); |
| #if ENABLE(VIDEO) |
| case ItemType::PaintFrameForMedia: |
| return append<PaintFrameForMedia>(item.get<PaintFrameForMedia>()); |
| #endif |
| case ItemType::StrokeRect: |
| return append<StrokeRect>(item.get<StrokeRect>()); |
| case ItemType::StrokeLine: |
| return append<StrokeLine>(item.get<StrokeLine>()); |
| #if ENABLE(INLINE_PATH_DATA) |
| case ItemType::StrokeArc: |
| return append<StrokeArc>(item.get<StrokeArc>()); |
| case ItemType::StrokeQuadCurve: |
| return append<StrokeQuadCurve>(item.get<StrokeQuadCurve>()); |
| case ItemType::StrokeBezierCurve: |
| return append<StrokeBezierCurve>(item.get<StrokeBezierCurve>()); |
| #endif |
| case ItemType::StrokePath: |
| return append<StrokePath>(item.get<StrokePath>()); |
| case ItemType::StrokeEllipse: |
| return append<StrokeEllipse>(item.get<StrokeEllipse>()); |
| case ItemType::ClearRect: |
| return append<ClearRect>(item.get<ClearRect>()); |
| case ItemType::BeginTransparencyLayer: |
| return append<BeginTransparencyLayer>(item.get<BeginTransparencyLayer>()); |
| case ItemType::EndTransparencyLayer: |
| return append<EndTransparencyLayer>(item.get<EndTransparencyLayer>()); |
| #if USE(CG) |
| case ItemType::ApplyStrokePattern: |
| return append<ApplyStrokePattern>(item.get<ApplyStrokePattern>()); |
| case ItemType::ApplyFillPattern: |
| return append<ApplyFillPattern>(item.get<ApplyFillPattern>()); |
| #endif |
| case ItemType::ApplyDeviceScaleFactor: |
| return append<ApplyDeviceScaleFactor>(item.get<ApplyDeviceScaleFactor>()); |
| } |
| } |
| |
| auto DisplayList::begin() const -> Iterator |
| { |
| return { *this }; |
| } |
| |
| auto DisplayList::end() const -> Iterator |
| { |
| return { *this, Iterator::ImmediatelyMoveToEnd::Yes }; |
| } |
| |
| TextStream& operator<<(TextStream& ts, const DisplayList& displayList) |
| { |
| displayList.dump(ts); |
| return ts; |
| } |
| |
| } // namespace DisplayList |
| |
| } // namespace WebCore |