Added: trunk/LayoutTests/compositing/reflections/mask-and-reflection-expected.html (0 => 295514)
--- trunk/LayoutTests/compositing/reflections/mask-and-reflection-expected.html (rev 0)
+++ trunk/LayoutTests/compositing/reflections/mask-and-reflection-expected.html 2022-06-14 03:34:12 UTC (rev 295514)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ .outer {
+ width: 100px;
+ height: 100px;
+ -webkit-box-reflect: below 10px;
+ }
+
+ .inner {
+ width: 100px;
+ height: 100px;
+ -webkit-box-reflect: right 10px;
+ background-color: green;
+ will-change: transform;
+ -webkit-mask-image: linear-gradient(-45deg, black, transparent);
+ mask-image: linear-gradient(-45deg, black, transparent);
+ }
+ </style>
+ </head>
+ <body>
+ <p>You should see four mirrored square boxes with linear gradient green.</p>
+ <div class="outer">
+ <div class="inner">
+ </div>
+ </div>
+ </body>
+</html>
Added: trunk/LayoutTests/compositing/reflections/mask-and-reflection.html (0 => 295514)
--- trunk/LayoutTests/compositing/reflections/mask-and-reflection.html (rev 0)
+++ trunk/LayoutTests/compositing/reflections/mask-and-reflection.html 2022-06-14 03:34:12 UTC (rev 295514)
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ .outer {
+ width: 100px;
+ height: 100px;
+ -webkit-box-reflect: below 10px;
+ }
+
+ .inner {
+ width: 100px;
+ height: 100px;
+ -webkit-box-reflect: right 10px;
+ background-color: green;
+ will-change: transform;
+ -webkit-mask-image: linear-gradient(-45deg, black, transparent);
+ mask-image: linear-gradient(-45deg, black, transparent);
+ }
+
+ .child {
+ position: relative;
+ top: 100px;
+ left: 100px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <p>You should see four mirrored square boxes with linear gradient green.</p>
+ <div class="outer">
+ <div class="inner">
+ <div class="child">
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp (295513 => 295514)
--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp 2022-06-14 03:10:02 UTC (rev 295513)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp 2022-06-14 03:34:12 UTC (rev 295514)
@@ -39,6 +39,7 @@
float opacity { 1 };
IntSize offset;
TextureMapperLayer* backdropLayer { nullptr };
+ TextureMapperLayer* replicaLayer { nullptr };
bool preserves3D { false };
};
@@ -285,10 +286,7 @@
if (m_state.preserves3D)
return false;
- return m_currentOpacity < 1
- || hasFilters()
- || m_state.maskLayer
- || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer);
+ return m_currentOpacity < 1;
}
bool TextureMapperLayer::isVisible() const
@@ -307,6 +305,7 @@
void TextureMapperLayer::paintSelfAndChildrenWithReplica(TextureMapperPaintOptions& options)
{
if (m_state.replicaLayer) {
+ SetForScope scopedReplicaLayer(options.replicaLayer, this);
SetForScope scopedTransform(options.transform, options.transform);
options.transform.multiply(replicaTransform());
paintSelfAndChildren(options);
@@ -383,10 +382,6 @@
Region overlapRegion;
Region nonOverlapRegion;
auto mode = ComputeOverlapRegionMode::Intersection;
- if (m_state.maskLayer)
- mode = ComputeOverlapRegionMode::Mask;
- else if (hasFilters() || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer))
- mode = ComputeOverlapRegionMode::Union;
ComputeOverlapRegionData data {
mode,
options.textureMapper.clipBounds(),
@@ -396,7 +391,7 @@
data.clipBounds.move(-options.offset);
computeOverlapRegions(data, options.transform);
if (overlapRegion.isEmpty()) {
- paintSelfAndChildrenWithReplica(options);
+ paintSelfChildrenReplicaFilterAndMask(options);
return;
}
@@ -412,7 +407,7 @@
for (auto& rect : rects) {
options.textureMapper.beginClip(TransformationMatrix(), FloatRoundedRect(rect));
- paintSelfAndChildrenWithReplica(options);
+ paintSelfChildrenReplicaFilterAndMask(options);
options.textureMapper.endClip();
}
@@ -436,6 +431,43 @@
}
}
+void TextureMapperLayer::paintSelfChildrenFilterAndMask(TextureMapperPaintOptions& options)
+{
+ Region overlapRegion;
+ Region nonOverlapRegion;
+ auto mode = ComputeOverlapRegionMode::Union;
+ if (m_state.maskLayer || (options.replicaLayer == this && m_state.replicaLayer->m_state.maskLayer))
+ mode = ComputeOverlapRegionMode::Mask;
+ ComputeOverlapRegionData data {
+ mode,
+ options.textureMapper.clipBounds(),
+ overlapRegion,
+ nonOverlapRegion
+ };
+ data.clipBounds.move(-options.offset);
+ computeOverlapRegions(data, options.transform, false);
+ ASSERT(nonOverlapRegion.isEmpty());
+
+ auto rects = overlapRegion.rects();
+ static const size_t OverlapRegionConsolidationThreshold = 4;
+ if (rects.size() > OverlapRegionConsolidationThreshold) {
+ rects.clear();
+ rects.append(overlapRegion.bounds());
+ }
+
+ IntSize maxTextureSize = options.textureMapper.maxTextureSize();
+ for (auto& rect : rects) {
+ for (int x = rect.x(); x < rect.maxX(); x += maxTextureSize.width()) {
+ for (int y = rect.y(); y < rect.maxY(); y += maxTextureSize.height()) {
+ IntRect tileRect(IntPoint(x, y), maxTextureSize);
+ tileRect.intersect(rect);
+
+ paintSelfAndChildrenWithIntermediateSurface(options, tileRect);
+ }
+ }
+ }
+}
+
void TextureMapperLayer::applyMask(TextureMapperPaintOptions& options)
{
options.textureMapper.setMaskMode(true);
@@ -448,10 +480,15 @@
options.textureMapper.bindSurface(options.surface.get());
if (m_isBackdrop) {
SetForScope scopedTransform(options.transform, TransformationMatrix());
+ SetForScope scopedReplicaLayer(options.replicaLayer, nullptr);
SetForScope scopedBackdropLayer(options.backdropLayer, this);
rootLayer().paintSelfAndChildren(options);
} else
paintSelfAndChildren(options);
+ if (options.replicaLayer == this) {
+ if (m_state.replicaLayer->m_state.maskLayer)
+ m_state.replicaLayer->m_state.maskLayer->applyMask(options);
+ }
if (m_state.maskLayer)
m_state.maskLayer->applyMask(options);
options.surface = options.surface->applyFilters(options.textureMapper, m_currentFilters);
@@ -473,16 +510,22 @@
SetForScope scopedSurface(options.surface, surface);
SetForScope scopedOffset(options.offset, -toIntSize(rect.location()));
SetForScope scopedOpacity(options.opacity, 1);
- if (m_state.replicaLayer) {
- {
- SetForScope scopedTransform(options.transform, options.transform);
- options.transform.multiply(replicaTransform());
- paintIntoSurface(options);
- }
- if (m_state.replicaLayer->m_state.maskLayer)
- m_state.replicaLayer->m_state.maskLayer->applyMask(options);
- }
+ options.textureMapper.bindSurface(options.surface.get());
+ paintSelfChildrenReplicaFilterAndMask(options);
+ }
+
+ commitSurface(options, *surface, rect, options.opacity);
+}
+
+void TextureMapperLayer::paintSelfAndChildrenWithIntermediateSurface(TextureMapperPaintOptions& options, const IntRect& rect)
+{
+ auto surface = options.textureMapper.acquireTextureFromPool(rect.size(), BitmapTexture::SupportsAlpha);
+ {
+ SetForScope scopedSurface(options.surface, surface);
+ SetForScope scopedOffset(options.offset, -toIntSize(rect.location()));
+ SetForScope scopedOpacity(options.opacity, 1);
+
paintIntoSurface(options);
surface = options.surface;
}
@@ -490,6 +533,29 @@
commitSurface(options, *surface, rect, options.opacity);
}
+void TextureMapperLayer::paintSelfChildrenReplicaFilterAndMask(TextureMapperPaintOptions& options)
+{
+ bool hasFilterOrMask = [&] {
+ if (hasFilters())
+ return true;
+ if (m_state.maskLayer)
+ return true;
+ if (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)
+ return true;
+ return false;
+ }();
+ if (hasFilterOrMask) {
+ if (m_state.replicaLayer) {
+ SetForScope scopedReplicaLayer(options.replicaLayer, this);
+ SetForScope scopedTransform(options.transform, options.transform);
+ options.transform.multiply(replicaTransform());
+ paintSelfChildrenFilterAndMask(options);
+ }
+ paintSelfChildrenFilterAndMask(options);
+ } else
+ paintSelfAndChildrenWithReplica(options);
+}
+
void TextureMapperLayer::paintRecursive(TextureMapperPaintOptions& options)
{
if (!isVisible())
@@ -497,12 +563,10 @@
SetForScope scopedOpacity(options.opacity, options.opacity * m_currentOpacity);
- if (!shouldBlend()) {
- paintSelfAndChildrenWithReplica(options);
- return;
- }
-
- paintUsingOverlapRegions(options);
+ if (shouldBlend())
+ paintUsingOverlapRegions(options);
+ else
+ paintSelfChildrenReplicaFilterAndMask(options);
}
void TextureMapperLayer::setChildren(const Vector<TextureMapperLayer*>& newChildren)
@@ -544,7 +608,7 @@
void TextureMapperLayer::setMaskLayer(TextureMapperLayer* maskLayer)
{
if (maskLayer) {
- maskLayer->m_effectTarget = *this;
+ maskLayer->m_effectTarget = m_isReplica ? m_effectTarget : *this;
m_state.maskLayer = *maskLayer;
} else
m_state.maskLayer = nullptr;
Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h (295513 => 295514)
--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h 2022-06-14 03:10:02 UTC (rev 295513)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h 2022-06-14 03:34:12 UTC (rev 295514)
@@ -132,9 +132,12 @@
void computeOverlapRegions(ComputeOverlapRegionData&, const TransformationMatrix&, bool includesReplica = true);
void paintRecursive(TextureMapperPaintOptions&);
+ void paintSelfChildrenReplicaFilterAndMask(TextureMapperPaintOptions&);
void paintUsingOverlapRegions(TextureMapperPaintOptions&);
void paintIntoSurface(TextureMapperPaintOptions&);
void paintWithIntermediateSurface(TextureMapperPaintOptions&, const IntRect&);
+ void paintSelfAndChildrenWithIntermediateSurface(TextureMapperPaintOptions&, const IntRect&);
+ void paintSelfChildrenFilterAndMask(TextureMapperPaintOptions&);
void paintSelf(TextureMapperPaintOptions&);
void paintSelfAndChildren(TextureMapperPaintOptions&);
void paintSelfAndChildrenWithReplica(TextureMapperPaintOptions&);