Skip to content

Commit

Permalink
[Skia] Implement support for shadows that ignore transforms
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=270175

Reviewed by Carlos Garcia Campos and Nikolas Zimmermann.

When creating the drop shadow filter, if state.shadowsIgnoreTransforms()
is true, render the drop shadow with trasformed coordinates and blur
radius, by adjusting them against the CTM inverse.

This is enough to make various canvas tests happy. Some of them are still
failing with off-by-one colors, and it's not clear why.

* Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp:
(WebCore::GraphicsContextSkia::createDropShadowFilterIfNeeded const):

Canonical link: https://commits.webkit.org/275492@main
  • Loading branch information
GeorgesStavracas authored and carlosgcampos committed Feb 29, 2024
1 parent 1fb32b5 commit caf3994
Showing 1 changed file with 26 additions and 4 deletions.
30 changes: 26 additions & 4 deletions Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <skia/core/SkPath.h>
#include <skia/core/SkPathEffect.h>
#include <skia/core/SkPathTypes.h>
#include <skia/core/SkPoint3.h>
#include <skia/core/SkRRect.h>
#include <skia/core/SkRegion.h>
#include <skia/core/SkTileMode.h>
Expand Down Expand Up @@ -345,25 +346,46 @@ void GraphicsContextSkia::strokePath(const Path& path)

sk_sp<SkImageFilter> GraphicsContextSkia::createDropShadowFilterIfNeeded(ShadowStyle shadowStyle) const
{
// FIXME: this does not handle state.shadowsIgnoreTransforms()

if (!hasDropShadow())
return nullptr;

const auto& shadow = dropShadow();
ASSERT(shadow);

const FloatSize& offset = shadow->offset;
auto offset = shadow->offset;
const auto& shadowColor = shadow->color;

if (!shadowColor.isVisible() || (!offset.width() && !offset.height() && !shadow->radius))
return nullptr;

const auto& state = this->state();
const auto sigma = shadow->radius / 2.0;
auto sigma = shadow->radius / 2.0;

switch (shadowStyle) {
case ShadowStyle::Outset:
if (state.shadowsIgnoreTransforms()) {
// When state.shadowsIgnoreTransforms() is true, the offset is in
// natural orientation for the Y axis, like CG. Convert that back to
// the Skia coordinate system.
offset.scale(1.0, -1.0);

// Fast path: identity CTM doesn't need the transform compensation
AffineTransform ctm = getCTM(GraphicsContext::IncludeDeviceScale::PossiblyIncludeDeviceScale);
if (ctm.isIdentity())
return SkImageFilters::DropShadow(offset.width(), offset.height(), sigma, sigma, shadowColor.colorWithAlphaMultipliedBy(state.alpha()), nullptr);

// Ignoring the CTM is practically equal as applying the inverse of
// the CTM when post-processing the drop shadow.
if (const std::optional<SkMatrix>& inverse = ctm.inverse()) {
SkPoint3 p = SkPoint3::Make(offset.width(), offset.height(), 0);
inverse->mapHomogeneousPoints(&p, &p, 1);
sigma = inverse->mapRadius(sigma);
return SkImageFilters::DropShadow(p.x(), p.y(), sigma, sigma, shadowColor.colorWithAlphaMultipliedBy(state.alpha()), nullptr);
}

return nullptr;
}

return SkImageFilters::DropShadow(offset.width(), offset.height(), sigma, sigma, shadowColor.colorWithAlphaMultipliedBy(state.alpha()), nullptr);
case ShadowStyle::Inset: {
auto dropShadow = SkImageFilters::DropShadowOnly(offset.width(), offset.height(), sigma, sigma, SK_ColorBLACK, nullptr);
Expand Down

0 comments on commit caf3994

Please sign in to comment.