Skip to content

Commit

Permalink
Associate a purpose for each GraphicsContextState in the context stat…
Browse files Browse the repository at this point in the history
…e stack

https://bugs.webkit.org/show_bug.cgi?id=261296
rdar://115138846

Reviewed by Simon Fraser.

We internally call GraphicsContext::save() when we begin a transparency layer and
we call GraphicsContext::restore() when we end the transparency layer.

Differentiating when this happens from normal save/restore will make it easy to
unwind the stack of the GraphicsContextState and the transparency layers in the
right order.

* Source/WebCore/platform/graphics/BifurcatedGraphicsContext.cpp:
(WebCore::BifurcatedGraphicsContext::save):
(WebCore::BifurcatedGraphicsContext::restore):
(WebCore::BifurcatedGraphicsContext::beginTransparencyLayer):
(WebCore::BifurcatedGraphicsContext::endTransparencyLayer):
* Source/WebCore/platform/graphics/BifurcatedGraphicsContext.h:
* Source/WebCore/platform/graphics/FontCascade.cpp:
(WebCore::FontCascade::displayListForTextRun const):
* Source/WebCore/platform/graphics/GraphicsContext.cpp:
(WebCore::GraphicsContext::save):
(WebCore::GraphicsContext::restore):
* Source/WebCore/platform/graphics/GraphicsContext.h:
* Source/WebCore/platform/graphics/GraphicsContextState.cpp:
(WebCore::GraphicsContextState::repurpose):
(WebCore::GraphicsContextState::clone const):
(WebCore::GraphicsContextState::cloneForRecording const): Deleted.
(WebCore::GraphicsContextState::didBeginTransparencyLayer): Deleted.
* Source/WebCore/platform/graphics/GraphicsContextState.h:
(WebCore::GraphicsContextState::purpose const):
* Source/WebCore/platform/graphics/NullGraphicsContext.h:
* Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp:
(WebCore::GraphicsContextCairo::save):
(WebCore::GraphicsContextCairo::restore):
* Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.h:
* Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp:
(WebCore::GraphicsContextCG::save):
(WebCore::GraphicsContextCG::restore):
(WebCore::GraphicsContextCG::beginTransparencyLayer):
(WebCore::GraphicsContextCG::endTransparencyLayer):
* Source/WebCore/platform/graphics/cg/GraphicsContextCG.h:
* Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp:
(WebCore::DisplayList::Recorder::save):
(WebCore::DisplayList::Recorder::restore):
(WebCore::DisplayList::Recorder::beginTransparencyLayer):
(WebCore::DisplayList::Recorder::endTransparencyLayer):
* Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.h:
(WebCore::DisplayList::Recorder::ContextState::cloneForTransparencyLayer const):
(WebCore::DisplayList::Recorder::ContextState::ContextState): Deleted.
* Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.cpp:
(Nicosia::CairoOperationRecorder::save):
(Nicosia::CairoOperationRecorder::restore):
* Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.h:

Canonical link: https://commits.webkit.org/267790@main
  • Loading branch information
shallawa authored and Said Abou-Hallawa committed Sep 8, 2023
1 parent 6dd9b4c commit 7d3126b
Show file tree
Hide file tree
Showing 16 changed files with 105 additions and 89 deletions.
21 changes: 10 additions & 11 deletions Source/WebCore/platform/graphics/BifurcatedGraphicsContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,22 @@ const DestinationColorSpace& BifurcatedGraphicsContext::colorSpace() const
return m_primaryContext.colorSpace();
}

void BifurcatedGraphicsContext::save()
void BifurcatedGraphicsContext::save(GraphicsContextState::Purpose purpose)
{
// FIXME: Consider not using the BifurcatedGraphicsContext's state stack at all,
// and making all of the state getters and setters virtual.
GraphicsContext::save();
m_primaryContext.save();
m_secondaryContext.save();
GraphicsContext::save(purpose);
m_primaryContext.save(purpose);
m_secondaryContext.save(purpose);

VERIFY_STATE_SYNCHRONIZATION();
}

void BifurcatedGraphicsContext::restore()
void BifurcatedGraphicsContext::restore(GraphicsContextState::Purpose purpose)
{
GraphicsContext::restore();
m_primaryContext.restore();
m_secondaryContext.restore();
GraphicsContext::restore(purpose);
m_primaryContext.restore(purpose);
m_secondaryContext.restore(purpose);

VERIFY_STATE_SYNCHRONIZATION();
}
Expand Down Expand Up @@ -154,8 +154,7 @@ void BifurcatedGraphicsContext::beginTransparencyLayer(float opacity)
m_primaryContext.beginTransparencyLayer(opacity);
m_secondaryContext.beginTransparencyLayer(opacity);

GraphicsContext::save();
m_state.didBeginTransparencyLayer();
GraphicsContext::save(GraphicsContextState::Purpose::TransparencyLayer);

VERIFY_STATE_SYNCHRONIZATION();
}
Expand All @@ -166,7 +165,7 @@ void BifurcatedGraphicsContext::endTransparencyLayer()
m_primaryContext.endTransparencyLayer();
m_secondaryContext.endTransparencyLayer();

GraphicsContext::restore();
GraphicsContext::restore(GraphicsContextState::Purpose::TransparencyLayer);

VERIFY_STATE_SYNCHRONIZATION();
}
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/graphics/BifurcatedGraphicsContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ class WEBCORE_EXPORT BifurcatedGraphicsContext : public GraphicsContext {

const DestinationColorSpace& colorSpace() const final;

void save() final;
void restore() final;
void save(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final;
void restore(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final;

void drawRect(const FloatRect&, float borderThickness = 1) final;
void drawLine(const FloatPoint&, const FloatPoint&) final;
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/platform/graphics/FontCascade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ std::unique_ptr<DisplayList::DisplayList> FontCascade::displayListForTextRun(Gra
return nullptr;

std::unique_ptr<DisplayList::DisplayList> displayList = makeUnique<DisplayList::DisplayList>();
DisplayList::RecorderImpl recordingContext(*displayList, context.state().cloneForRecording(), { },
DisplayList::RecorderImpl recordingContext(*displayList, context.state().clone(GraphicsContextState::Purpose::Initial), { },
context.getCTM(GraphicsContext::DefinitelyIncludeDeviceScale), context.colorSpace(),
DisplayList::Recorder::DrawGlyphsMode::DeconstructUsingDrawDecomposedGlyphsCommands);

Expand Down
9 changes: 7 additions & 2 deletions Source/WebCore/platform/graphics/GraphicsContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,23 @@ GraphicsContext::~GraphicsContext()
ASSERT(!m_transparencyLayerCount);
}

void GraphicsContext::save()
void GraphicsContext::save(GraphicsContextState::Purpose purpose)
{
ASSERT(purpose == GraphicsContextState::Purpose::SaveRestore || purpose == GraphicsContextState::Purpose::TransparencyLayer);
m_stack.append(m_state);
m_state.repurpose(purpose);
}

void GraphicsContext::restore()
void GraphicsContext::restore(GraphicsContextState::Purpose purpose)
{
if (m_stack.isEmpty()) {
LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
return;
}

ASSERT_UNUSED(purpose, purpose == m_state.purpose());
ASSERT_UNUSED(purpose, purpose == GraphicsContextState::Purpose::SaveRestore || purpose == GraphicsContextState::Purpose::TransparencyLayer);

m_state = m_stack.last();
m_stack.removeLast();

Expand Down
6 changes: 3 additions & 3 deletions Source/WebCore/platform/graphics/GraphicsContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ class GraphicsContext {
// to the platform context's state.
virtual void didUpdateState(GraphicsContextState&) = 0;

WEBCORE_EXPORT virtual void save();
WEBCORE_EXPORT virtual void restore();
WEBCORE_EXPORT virtual void save(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore);
WEBCORE_EXPORT virtual void restore(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore);

unsigned stackSize() const { return m_stack.size(); }

#if USE(CG)
Expand Down
39 changes: 24 additions & 15 deletions Source/WebCore/platform/graphics/GraphicsContextState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@ GraphicsContextState::GraphicsContextState(const ChangeFlags& changeFlags, Inter
{
}

void GraphicsContextState::repurpose(Purpose purpose)
{
if (purpose == m_purpose)
return;

if (purpose == Purpose::Initial)
m_changeFlags = { };

#if USE(CG)
// CGContextBeginTransparencyLayer() sets the CG global alpha to 1. Keep the clone's alpha in sync.
if (purpose == Purpose::TransparencyLayer)
m_alpha = 1;
#endif

m_purpose = purpose;
}

GraphicsContextState GraphicsContextState::clone(Purpose purpose) const
{
auto clone = *this;
clone.repurpose(purpose);
return clone;
}

std::optional<GraphicsDropShadow> GraphicsContextState::dropShadow() const
{
if (!m_style)
Expand All @@ -48,13 +72,6 @@ std::optional<GraphicsDropShadow> GraphicsContextState::dropShadow() const
return std::get<GraphicsDropShadow>(*m_style);
}

GraphicsContextState GraphicsContextState::cloneForRecording() const
{
auto clone = *this;
clone.m_changeFlags = { };
return clone;
}

bool GraphicsContextState::containsOnlyInlineChanges() const
{
if (m_changeFlags.isEmpty() || m_changeFlags != (m_changeFlags & basicChangeFlags))
Expand Down Expand Up @@ -188,14 +205,6 @@ void GraphicsContextState::mergeAllChanges(const GraphicsContextState& state)
#endif
}

void GraphicsContextState::didBeginTransparencyLayer()
{
#if USE(CG)
// CGContextBeginTransparencyLayer() sets the CG global alpha to 1. Keep our alpha in sync.
m_alpha = 1;
#endif
}

static const char* stateChangeName(GraphicsContextState::Change change)
{
switch (change) {
Expand Down
15 changes: 12 additions & 3 deletions Source/WebCore/platform/graphics/GraphicsContextState.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,20 @@ class GraphicsContextState {
static constexpr ChangeFlags basicChangeFlags { Change::StrokeThickness, Change::StrokeBrush, Change::FillBrush };
static constexpr ChangeFlags strokeChangeFlags { Change::StrokeThickness, Change::StrokeBrush };

enum class Purpose : uint8_t {
Initial,
SaveRestore,
TransparencyLayer
};

WEBCORE_EXPORT GraphicsContextState(const ChangeFlags& = { }, InterpolationQuality = InterpolationQuality::Default);

void repurpose(Purpose);
GraphicsContextState clone(Purpose) const;

ChangeFlags changes() const { return m_changeFlags; }
void didApplyChanges() { m_changeFlags = { }; }

GraphicsContextState cloneForRecording() const;

SourceBrush& fillBrush() { return m_fillBrush; }
const SourceBrush& fillBrush() const { return m_fillBrush; }
void setFillBrush(const SourceBrush& brush) { setProperty(Change::FillBrush, &GraphicsContextState::m_fillBrush, brush); }
Expand Down Expand Up @@ -137,7 +144,7 @@ class GraphicsContextState {
void mergeLastChanges(const GraphicsContextState&, const std::optional<GraphicsContextState>& lastDrawingState = std::nullopt);
void mergeAllChanges(const GraphicsContextState&);

void didBeginTransparencyLayer();
Purpose purpose() const { return m_purpose; }

WTF::TextStream& dump(WTF::TextStream&) const;

Expand Down Expand Up @@ -191,6 +198,8 @@ class GraphicsContextState {
#if HAVE(OS_DARK_MODE_SUPPORT)
bool m_useDarkAppearance { false };
#endif

Purpose m_purpose { Purpose::Initial };
};

template<class Encoder>
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/graphics/NullGraphicsContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ class NullGraphicsContext : public GraphicsContext {
void resetClip() final { }
void clip(const FloatRect&) final { }
void clipOut(const FloatRect&) final { }
void save() final { }
void restore() final { }
void save(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final { }
void restore(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final { }

void drawRaisedEllipse(const FloatRect&, const Color&, const Color&) final { }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,22 @@ GraphicsContextCairo* GraphicsContextCairo::platformContext() const
return const_cast<GraphicsContextCairo*>(this);
}

void GraphicsContextCairo::save()
void GraphicsContextCairo::save(GraphicsContextState::Purpose purpose)
{
GraphicsContext::save();
GraphicsContext::save(purpose);

m_cairoStateStack.append(CairoState());
m_cairoState = &m_cairoStateStack.last();

cairo_save(m_cr.get());
}

void GraphicsContextCairo::restore()
void GraphicsContextCairo::restore(GraphicsContextState::Purpose purpose)
{
if (!stackSize())
return;

GraphicsContext::restore();
GraphicsContext::restore(purpose);

if (m_cairoStateStack.isEmpty())
return;
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ class WEBCORE_EXPORT GraphicsContextCairo final : public GraphicsContext {
void drawFocusRing(const Path&, float outlineWidth, const Color&) final;
void drawFocusRing(const Vector<FloatRect>&, float outlineOffset, float outlineWidth, const Color&) final;

void save() final;
void restore() final;
void save(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final;
void restore(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final;

void translate(float, float) final;
void rotate(float) final;
Expand Down
13 changes: 6 additions & 7 deletions Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,18 +251,18 @@ const DestinationColorSpace& GraphicsContextCG::colorSpace() const
return *m_colorSpace;
}

void GraphicsContextCG::save()
void GraphicsContextCG::save(GraphicsContextState::Purpose purpose)
{
GraphicsContext::save();
GraphicsContext::save(purpose);
CGContextSaveGState(contextForState());
}

void GraphicsContextCG::restore()
void GraphicsContextCG::restore(GraphicsContextState::Purpose purpose)
{
if (!stackSize())
return;

GraphicsContext::restore();
GraphicsContext::restore(purpose);
CGContextRestoreGState(contextForState());
m_userToDeviceTransformKnownToBeIdentity = false;
}
Expand Down Expand Up @@ -1054,13 +1054,12 @@ void GraphicsContextCG::beginTransparencyLayer(float opacity)
{
GraphicsContext::beginTransparencyLayer(opacity);

save();
save(GraphicsContextState::Purpose::TransparencyLayer);

CGContextRef context = platformContext();
CGContextSetAlpha(context, opacity);
CGContextBeginTransparencyLayer(context, 0);

m_state.didBeginTransparencyLayer();
m_userToDeviceTransformKnownToBeIdentity = false;
}

Expand All @@ -1071,7 +1070,7 @@ void GraphicsContextCG::endTransparencyLayer()
CGContextRef context = platformContext();
CGContextEndTransparencyLayer(context);

restore();
restore(GraphicsContextState::Purpose::TransparencyLayer);
}

static void applyShadowOffsetWorkaroundIfNeeded(CGContextRef context, CGFloat& xOffset, CGFloat& yOffset)
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/graphics/cg/GraphicsContextCG.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class WEBCORE_EXPORT GraphicsContextCG : public GraphicsContext {

const DestinationColorSpace& colorSpace() const final;

void save() final;
void restore() final;
void save(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final;
void restore(GraphicsContextState::Purpose = GraphicsContextState::Purpose::SaveRestore) final;

void drawRect(const FloatRect&, float borderThickness = 1) final;
void drawLine(const FloatPoint&, const FloatPoint&) final;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,18 +279,22 @@ void Recorder::drawPattern(ImageBuffer& imageBuffer, const FloatRect& destRect,
recordDrawPattern(imageBuffer.renderingResourceIdentifier(), destRect, tileRect, patternTransform, phase, spacing, options);
}

void Recorder::save()
void Recorder::save(GraphicsContextState::Purpose purpose)
{
ASSERT(purpose == GraphicsContextState::Purpose::SaveRestore);

appendStateChangeItemIfNecessary();
GraphicsContext::save();
GraphicsContext::save(purpose);
recordSave();
m_stateStack.append(m_stateStack.last());
}

void Recorder::restore()
void Recorder::restore(GraphicsContextState::Purpose purpose)
{
ASSERT(purpose == GraphicsContextState::Purpose::SaveRestore);

appendStateChangeItemIfNecessary();
GraphicsContext::restore();
GraphicsContext::restore(purpose);

if (!m_stateStack.size())
return;
Expand Down Expand Up @@ -350,10 +354,8 @@ void Recorder::beginTransparencyLayer(float opacity)
appendStateChangeItemIfNecessary();
recordBeginTransparencyLayer(opacity);

GraphicsContext::save();
GraphicsContext::save(GraphicsContextState::Purpose::TransparencyLayer);
m_stateStack.append(m_stateStack.last().cloneForTransparencyLayer());

m_state.didBeginTransparencyLayer();
}

void Recorder::endTransparencyLayer()
Expand All @@ -364,7 +366,7 @@ void Recorder::endTransparencyLayer()
recordEndTransparencyLayer();

m_stateStack.removeLast();
GraphicsContext::restore();
GraphicsContext::restore(GraphicsContextState::Purpose::TransparencyLayer);
}

void Recorder::drawRect(const FloatRect& rect, float borderThickness)
Expand Down
Loading

0 comments on commit 7d3126b

Please sign in to comment.