Index: third_party/WebKit/Source/core/paint/PaintLayer.cpp |
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp |
index 8f1f0f4ef00283350b9dc167cce91cc5b4168e6d..fb600ab13a691f07035a913c2e55db4e6ebefe88 100644 |
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp |
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp |
@@ -251,7 +251,7 @@ void PaintLayer::contentChanged(ContentChangeType changeType) |
bool PaintLayer::paintsWithFilters() const |
{ |
- if (!layoutObject()->hasFilter()) |
+ if (!layoutObject()->hasFilterInducingProperty()) |
return false; |
// https://code.google.com/p/chromium/issues/detail?id=343759 |
@@ -1063,8 +1063,7 @@ void PaintLayer::setShouldIsolateCompositedDescendants(bool shouldIsolateComposi |
bool PaintLayer::hasAncestorWithFilterOutsets() const |
{ |
for (const PaintLayer* curr = this; curr; curr = curr->parent()) { |
- LayoutBoxModelObject* layoutObject = curr->layoutObject(); |
- if (layoutObject->style()->hasFilterOutsets()) |
+ if (curr->hasFilterOutsets()) |
return true; |
} |
return false; |
@@ -2131,9 +2130,19 @@ LayoutRect PaintLayer::boundingBoxForCompositingOverlapTest() const |
return overlapBoundsIncludeChildren() ? boundingBoxForCompositing(this, NeverIncludeTransformForAncestorLayer) : fragmentsBoundingBox(this); |
} |
+bool PaintLayer::overlapBoundsIncludeChildren() const |
+{ |
+ const auto* style = layoutObject()->style(); |
+ if (style && style->filter().hasFilterThatMovesPixels()) |
+ return true; |
+ if (RuntimeEnabledFeatures::cssBoxReflectFilterEnabled() && layoutObject()->hasReflection()) |
+ return true; |
+ return false; |
+} |
+ |
static void expandRectForReflectionAndStackingChildren(const PaintLayer* ancestorLayer, LayoutRect& result) |
{ |
- if (ancestorLayer->reflectionInfo() && !ancestorLayer->reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping()) |
+ if (ancestorLayer->reflectionInfo() && !ancestorLayer->reflectionInfo()->reflectionLayer()->hasCompositedLayerMapping() && !RuntimeEnabledFeatures::cssBoxReflectFilterEnabled()) |
result.unite(ancestorLayer->reflectionInfo()->reflectionLayer()->boundingBoxForCompositing(ancestorLayer)); |
ASSERT(ancestorLayer->stackingNode()->isStackingContext() || !ancestorLayer->stackingNode()->hasPositiveZOrderList()); |
@@ -2470,7 +2479,7 @@ bool PaintLayer::hasVisibleBoxDecorations() const |
void PaintLayer::updateFilters(const ComputedStyle* oldStyle, const ComputedStyle& newStyle) |
{ |
- if (!newStyle.hasFilter() && (!oldStyle || !oldStyle->hasFilter())) |
+ if (!newStyle.hasFilterInducingProperty() && (!oldStyle || !oldStyle->hasFilterInducingProperty())) |
return; |
updateOrRemoveFilterClients(); |
@@ -2603,7 +2612,43 @@ FilterOperations computeFilterOperationsHandleReferenceFilters(const FilterOpera |
FilterOperations PaintLayer::computeFilterOperations(const ComputedStyle& style) const |
{ |
- return computeFilterOperationsHandleReferenceFilters(style.filter(), style.effectiveZoom(), enclosingNode()); |
+ FilterOperations filterOperations = style.filter(); |
+ if (RuntimeEnabledFeatures::cssBoxReflectFilterEnabled() && layoutObject()->hasReflection() && layoutObject()->isBox()) { |
+ // TODO(jbroman): Incorporate the mask image. |
+ const auto* reflectStyle = style.boxReflect(); |
+ FloatRect frameRect(toLayoutBox(layoutObject())->frameRect()); |
+ ReflectionDirection direction = VerticalReflection; |
+ float offset = 0; |
+ switch (reflectStyle->direction()) { |
+ case ReflectionAbove: |
+ direction = VerticalReflection; |
+ offset = -floatValueForLength(reflectStyle->offset(), frameRect.height()); |
+ break; |
+ case ReflectionBelow: |
+ direction = VerticalReflection; |
+ offset = 2 * frameRect.height() + floatValueForLength(reflectStyle->offset(), frameRect.height()); |
+ break; |
+ case ReflectionLeft: |
+ direction = HorizontalReflection; |
+ offset = -floatValueForLength(reflectStyle->offset(), frameRect.width()); |
+ break; |
+ case ReflectionRight: |
+ direction = HorizontalReflection; |
+ offset = 2 * frameRect.width() + floatValueForLength(reflectStyle->offset(), frameRect.width()); |
+ break; |
+ } |
+ |
+ // Since the filter origin is the corner of the input bounds, which may |
+ // include visual overflow (e.g. due to box-shadow), we must adjust the |
+ // offset to also account for this offset (this is equivalent to using |
+ // SkLocalMatrixImageFilter, but simpler). |
+ // The rect used here should match the one used in FilterPainter. |
+ LayoutRect filterInputBounds = physicalBoundingBoxIncludingReflectionAndStackingChildren(LayoutPoint()); |
+ offset -= 2 * (direction == VerticalReflection ? filterInputBounds.y() : filterInputBounds.x()).toFloat(); |
+ |
+ filterOperations.operations().append(BoxReflectFilterOperation::create(direction, offset)); |
+ } |
+ return computeFilterOperationsHandleReferenceFilters(filterOperations, style.effectiveZoom(), enclosingNode()); |
} |
FilterOperations PaintLayer::computeBackdropFilterOperations(const ComputedStyle& style) const |
@@ -2621,10 +2666,11 @@ PaintLayerFilterInfo& PaintLayer::ensureFilterInfo() |
void PaintLayer::updateOrRemoveFilterClients() |
{ |
- if (!hasFilter() && m_rareData) { |
+ const auto& filter = layoutObject()->style()->filter(); |
+ if (filter.isEmpty() && m_rareData) { |
m_rareData->filterInfo = nullptr; |
- } else if (layoutObject()->style()->filter().hasReferenceFilter()) { |
- ensureFilterInfo().updateReferenceFilterClients(layoutObject()->style()->filter()); |
+ } else if (filter.hasReferenceFilter()) { |
+ ensureFilterInfo().updateReferenceFilterClients(filter); |
} else if (filterInfo()) { |
filterInfo()->clearFilterReferences(); |
} |
@@ -2662,13 +2708,26 @@ FilterEffect* PaintLayer::lastFilterEffect() const |
return builder->lastEffect().get(); |
} |
+bool PaintLayer::hasFilterOutsets() const |
+{ |
+ if (!layoutObject()->hasFilterInducingProperty()) |
+ return false; |
+ const ComputedStyle& style = layoutObject()->styleRef(); |
+ if (style.hasFilter() && style.filter().hasOutsets()) |
+ return true; |
+ if (RuntimeEnabledFeatures::cssBoxReflectFilterEnabled() && style.hasBoxReflect()) |
+ return true; |
+ return false; |
+} |
+ |
FilterOutsets PaintLayer::filterOutsets() const |
{ |
- if (!layoutObject()->hasFilter()) |
+ if (!layoutObject()->hasFilterInducingProperty()) |
return FilterOutsets(); |
// Ensure the filter-chain is refreshed wrt reference filters. |
updateFilterEffectBuilder(); |
+ |
return layoutObject()->style()->filter().outsets(); |
} |