blob: e615a7bd6d4a70855af09fea0c39d582039dfe9c [file] [log] [blame]
/*
* Copyright (C) 2016-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. ``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 "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;
ts << *this;
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(AsTextFlags flags, ItemHandle item)
{
switch (item.type()) {
case ItemType::SetState:
if (!(flags & AsTextFlag::IncludesPlatformOperations)) {
const auto& stateItem = item.get<SetState>();
// FIXME: for now, only drop the item if the only state-change flags are platform-specific.
if (stateItem.stateChange().m_changeFlags == GraphicsContextState::ShouldSubpixelQuantizeFontsChange)
return false;
if (stateItem.stateChange().m_changeFlags == GraphicsContextState::ShouldSubpixelQuantizeFontsChange)
return false;
}
break;
#if USE(CG)
case ItemType::ApplyFillPattern:
case ItemType::ApplyStrokePattern:
if (!(flags & AsTextFlag::IncludesPlatformOperations))
return false;
break;
#endif
default:
break;
}
return true;
}
String DisplayList::asText(AsTextFlags flags) const
{
TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
for (auto displayListItem : *this) {
auto [item, extent, itemSizeInBuffer] = displayListItem.value();
if (!shouldDumpForFlags(flags, item))
continue;
TextStream::GroupScope group(stream);
stream << item;
if (item.isDrawingItem())
stream << " extent " << extent;
}
return stream.release();
}
void DisplayList::dump(TextStream& ts) const
{
TextStream::GroupScope group(ts);
ts << "display list";
for (auto displayListItem : *this) {
auto [item, extent, itemSizeInBuffer] = displayListItem.value();
TextStream::GroupScope group(ts);
ts << item;
if (item.isDrawingItem())
ts << " extent " << extent;
}
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::BeginClipToDrawingCommands:
return append<BeginClipToDrawingCommands>(item.get<BeginClipToDrawingCommands>());
case ItemType::EndClipToDrawingCommands:
return append<EndClipToDrawingCommands>(item.get<EndClipToDrawingCommands>());
case ItemType::DrawGlyphs:
return append<DrawGlyphs>(item.get<DrawGlyphs>());
case ItemType::DrawImageBuffer:
return append<DrawImageBuffer>(item.get<DrawImageBuffer>());
case ItemType::DrawNativeImage:
return append<DrawNativeImage>(item.get<DrawNativeImage>());
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>());
case ItemType::FlushContext:
return append<FlushContext>(item.get<FlushContext>());
case ItemType::GetPixelBuffer:
return append<GetPixelBuffer>(item.get<GetPixelBuffer>());
case ItemType::PutPixelBuffer:
return append<PutPixelBuffer>(item.get<PutPixelBuffer>());
#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