summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderLayer.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/RenderLayer.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/rendering/RenderLayer.cpp')
-rw-r--r--Source/WebCore/rendering/RenderLayer.cpp4435
1 files changed, 2317 insertions, 2118 deletions
diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp
index 65e0d231d..f911119b2 100644
--- a/Source/WebCore/rendering/RenderLayer.cpp
+++ b/Source/WebCore/rendering/RenderLayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
*
* Portions are Copyright (C) 1998 Netscape Communications Corporation.
*
@@ -44,18 +44,23 @@
#include "config.h"
#include "RenderLayer.h"
-#include "AnimationController.h"
-#include "ColumnInfo.h"
+#include "BoxShape.h"
+#include "CSSAnimationController.h"
#include "CSSPropertyNames.h"
#include "Chrome.h"
+#include "DebugPageOverlays.h"
#include "Document.h"
#include "DocumentEventQueue.h"
+#include "DocumentMarkerController.h"
#include "Element.h"
#include "EventHandler.h"
-#include "FeatureObserver.h"
+#include "FEColorMatrix.h"
+#include "FEMerge.h"
+#include "FilterEffectRenderer.h"
#include "FloatConversion.h"
#include "FloatPoint3D.h"
#include "FloatRect.h"
+#include "FloatRoundedRect.h"
#include "FlowThreadController.h"
#include "FocusController.h"
#include "Frame.h"
@@ -66,14 +71,17 @@
#include "FrameView.h"
#include "Gradient.h"
#include "GraphicsContext.h"
+#include "HTMLFormControlElement.h"
#include "HTMLFrameElement.h"
#include "HTMLFrameOwnerElement.h"
+#include "HTMLIFrameElement.h"
#include "HTMLNames.h"
-#include "HistogramSupport.h"
#include "HitTestingTransformState.h"
#include "HitTestRequest.h"
#include "HitTestResult.h"
-#include "InspectorInstrumentation.h"
+#include "Logging.h"
+#include "MainFrame.h"
+#include "NoEventDispatchAssertion.h"
#include "OverflowEvent.h"
#include "OverlapTestRequestClient.h"
#include "Page.h"
@@ -81,7 +89,12 @@
#include "RenderFlowThread.h"
#include "RenderGeometryMap.h"
#include "RenderInline.h"
+#include "RenderIterator.h"
+#include "RenderLayerBacking.h"
+#include "RenderLayerCompositor.h"
+#include "RenderLayerFilterInfo.h"
#include "RenderMarquee.h"
+#include "RenderMultiColumnFlowThread.h"
#include "RenderNamedFlowFragment.h"
#include "RenderNamedFlowThread.h"
#include "RenderRegion.h"
@@ -91,9 +104,11 @@
#include "RenderScrollbarPart.h"
#include "RenderTableCell.h"
#include "RenderTableRow.h"
+#include "RenderText.h"
#include "RenderTheme.h"
#include "RenderTreeAsText.h"
#include "RenderView.h"
+#include "SVGNames.h"
#include "ScaleTransformOperation.h"
#include "ScrollAnimator.h"
#include "Scrollbar.h"
@@ -107,23 +122,13 @@
#include "TextStream.h"
#include "TransformationMatrix.h"
#include "TranslateTransformOperation.h"
+#include "WheelEventTestTrigger.h"
+#include <stdio.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/CString.h>
-#if ENABLE(CSS_FILTERS)
-#include "FEColorMatrix.h"
-#include "FEMerge.h"
-#include "FilterEffectRenderer.h"
-#include "RenderLayerFilterInfo.h"
-#endif
-
-#if USE(ACCELERATED_COMPOSITING)
-#include "RenderLayerBacking.h"
-#include "RenderLayerCompositor.h"
-#endif
-
-#if ENABLE(SVG)
-#include "SVGNames.h"
+#if ENABLE(CSS_SCROLL_SNAP)
+#include "AxisScrollSnapOffsets.h"
#endif
#define MIN_INTERSECT_FOR_REVEAL 32
@@ -132,14 +137,125 @@ namespace WebCore {
using namespace HTMLNames;
-bool ClipRect::intersects(const HitTestLocation& hitTestLocation) const
-{
- return hitTestLocation.intersects(m_rect);
-}
+class ClipRects : public RefCounted<ClipRects> {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static Ref<ClipRects> create()
+ {
+ return adoptRef(*new ClipRects);
+ }
+
+ static Ref<ClipRects> create(const ClipRects& other)
+ {
+ return adoptRef(*new ClipRects(other));
+ }
+
+ void reset()
+ {
+ m_overflowClipRect.reset();
+ m_fixedClipRect.reset();
+ m_posClipRect.reset();
+ m_fixed = false;
+ }
+
+ const ClipRect& overflowClipRect() const { return m_overflowClipRect; }
+ void setOverflowClipRect(const ClipRect& clipRect) { m_overflowClipRect = clipRect; }
+
+ const ClipRect& fixedClipRect() const { return m_fixedClipRect; }
+ void setFixedClipRect(const ClipRect& clipRect) { m_fixedClipRect = clipRect; }
+
+ const ClipRect& posClipRect() const { return m_posClipRect; }
+ void setPosClipRect(const ClipRect& clipRect) { m_posClipRect = clipRect; }
+
+ bool fixed() const { return m_fixed; }
+ void setFixed(bool fixed) { m_fixed = fixed; }
+
+ bool operator==(const ClipRects& other) const
+ {
+ return m_overflowClipRect == other.overflowClipRect()
+ && m_fixedClipRect == other.fixedClipRect()
+ && m_posClipRect == other.posClipRect()
+ && m_fixed == other.fixed();
+ }
+
+ ClipRects& operator=(const ClipRects& other)
+ {
+ m_overflowClipRect = other.overflowClipRect();
+ m_fixedClipRect = other.fixedClipRect();
+ m_posClipRect = other.posClipRect();
+ m_fixed = other.fixed();
+ return *this;
+ }
+
+private:
+ ClipRects() = default;
+
+ ClipRects(const LayoutRect& clipRect)
+ : m_overflowClipRect(clipRect)
+ , m_fixedClipRect(clipRect)
+ , m_posClipRect(clipRect)
+ {
+ }
+
+ ClipRects(const ClipRects& other)
+ : RefCounted()
+ , m_fixed(other.fixed())
+ , m_overflowClipRect(other.overflowClipRect())
+ , m_fixedClipRect(other.fixedClipRect())
+ , m_posClipRect(other.posClipRect())
+ {
+ }
+
+ bool m_fixed { false };
+ ClipRect m_overflowClipRect;
+ ClipRect m_fixedClipRect;
+ ClipRect m_posClipRect;
+};
+
+class ClipRectsCache {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ClipRectsCache()
+ {
+#ifndef NDEBUG
+ for (int i = 0; i < NumCachedClipRectsTypes; ++i) {
+ m_clipRectsRoot[i] = 0;
+ m_scrollbarRelevancy[i] = IgnoreOverlayScrollbarSize;
+ }
+#endif
+ }
+
+ ClipRects* getClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) const
+ {
+ return m_clipRects[getIndex(clipRectsType, respectOverflow)].get();
+ }
+
+ void setClipRects(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow, RefPtr<ClipRects>&& clipRects)
+ {
+ m_clipRects[getIndex(clipRectsType, respectOverflow)] = WTFMove(clipRects);
+ }
+
+#ifndef NDEBUG
+ const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes];
+ OverlayScrollbarSizeRelevancy m_scrollbarRelevancy[NumCachedClipRectsTypes];
+#endif
+
+private:
+ unsigned getIndex(ClipRectsType clipRectsType, ShouldRespectOverflowClip respectOverflow) const
+ {
+ unsigned index = static_cast<unsigned>(clipRectsType);
+ if (respectOverflow == RespectOverflowClip)
+ index += static_cast<unsigned>(NumCachedClipRectsTypes);
+ ASSERT_WITH_SECURITY_IMPLICATION(index < NumCachedClipRectsTypes * 2);
+ return index;
+ }
+
+ RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes * 2];
+};
void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
{
-#if !ENABLE(3D_RENDERING)
+#if !ENABLE(3D_TRANSFORMS)
UNUSED_PARAM(has3DRendering);
matrix.makeAffine();
#else
@@ -149,7 +265,9 @@ void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
}
RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
- : m_inResizeMode(false)
+ : m_isRootLayer(rendererLayerModelObject.isRenderView())
+ , m_forcedStackingContext(rendererLayerModelObject.isMedia())
+ , m_inResizeMode(false)
, m_scrollDimensionsDirty(true)
, m_normalFlowListDirty(true)
, m_hasSelfPaintingLayerDescendant(false)
@@ -158,7 +276,6 @@ RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
, m_hasOutOfFlowPositionedDescendantDirty(true)
, m_needsCompositedScrolling(false)
, m_descendantsAreContiguousInStackingOrder(false)
- , m_isRootLayer(rendererLayerModelObject.isRenderView())
, m_usedTransparency(false)
, m_paintingInsideReflection(false)
, m_inOverflowRelayout(false)
@@ -167,17 +284,21 @@ RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
, m_hasVisibleContent(false)
, m_visibleDescendantStatusDirty(false)
, m_hasVisibleDescendant(false)
- , m_isPaginated(false)
+ , m_registeredScrollableArea(false)
, m_3DTransformedDescendantStatusDirty(true)
, m_has3DTransformedDescendant(false)
-#if USE(ACCELERATED_COMPOSITING)
, m_hasCompositingDescendant(false)
- , m_indirectCompositingReason(NoIndirectCompositingReason)
+ , m_hasTransformedAncestor(false)
+ , m_has3DTransformedAncestor(false)
+ , m_indirectCompositingReason(static_cast<unsigned>(IndirectCompositingReason::None))
, m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
-#endif
#if PLATFORM(IOS)
, m_adjustForIOSCaretWhenScrolling(false)
+#endif
+#if PLATFORM(IOS)
+#if ENABLE(IOS_TOUCH_EVENTS)
, m_registeredAsTouchEventListenerForScrolling(false)
+#endif
, m_inUserScroll(false)
, m_requiresScrollBoundsOriginUpdate(false)
#endif
@@ -186,21 +307,23 @@ RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
#if !ASSERT_DISABLED
, m_layerListMutationAllowed(true)
#endif
-#if ENABLE(CSS_FILTERS)
, m_hasFilterInfo(false)
-#endif
+ , m_hasComputedRepaintRect(false)
#if ENABLE(CSS_COMPOSITING)
, m_blendMode(BlendModeNormal)
+ , m_hasNotIsolatedCompositedBlendingDescendants(false)
+ , m_hasNotIsolatedBlendingDescendants(false)
+ , m_hasNotIsolatedBlendingDescendantsStatusDirty(false)
#endif
, m_renderer(rendererLayerModelObject)
- , m_parent(0)
- , m_previous(0)
- , m_next(0)
- , m_first(0)
- , m_last(0)
+ , m_parent(nullptr)
+ , m_previous(nullptr)
+ , m_next(nullptr)
+ , m_first(nullptr)
+ , m_last(nullptr)
, m_staticInlinePosition(0)
, m_staticBlockPosition(0)
- , m_enclosingPaginationLayer(0)
+ , m_enclosingPaginationLayer(nullptr)
{
m_isNormalFlowOnly = shouldBeNormalFlowOnly();
m_isSelfPaintingLayer = shouldBeSelfPaintingLayer();
@@ -209,8 +332,6 @@ RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
// there is no need to dirty / recompute these lists.
m_zOrderListsDirty = isStackingContainer();
- ScrollableArea::setConstrainsScrollingToContentEdge(false);
-
if (!renderer().firstChild()) {
m_visibleContentStatusDirty = false;
m_hasVisibleContent = renderer().style().visibility() == VISIBLE;
@@ -218,59 +339,54 @@ RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
if (Element* element = renderer().element()) {
// We save and restore only the scrollOffset as the other scroll values are recalculated.
- m_scrollOffset = element->savedLayerScrollOffset();
- if (!m_scrollOffset.isZero())
- scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width(), m_scrollOffset.height()));
- element->setSavedLayerScrollOffset(IntSize());
+ m_scrollPosition = element->savedLayerScrollPosition();
+ if (!m_scrollPosition.isZero())
+ scrollAnimator().setCurrentPosition(m_scrollPosition);
+ element->setSavedLayerScrollPosition(IntPoint());
}
}
RenderLayer::~RenderLayer()
{
- if (inResizeMode() && !renderer().documentBeingDestroyed())
+ if (inResizeMode())
renderer().frame().eventHandler().resizeLayerDestroyed();
- renderer().view().frameView().removeScrollableArea(this);
+ ASSERT(m_registeredScrollableArea == renderer().view().frameView().containsScrollableArea(this));
- if (!renderer().documentBeingDestroyed()) {
-#if PLATFORM(IOS)
- unregisterAsTouchEventListenerForScrolling();
+ if (m_registeredScrollableArea)
+ renderer().view().frameView().removeScrollableArea(this);
+
+#if ENABLE(IOS_TOUCH_EVENTS)
+ unregisterAsTouchEventListenerForScrolling();
#endif
- if (Element* element = renderer().element())
- element->setSavedLayerScrollOffset(m_scrollOffset);
- }
+ if (Element* element = renderer().element())
+ element->setSavedLayerScrollPosition(m_scrollPosition);
destroyScrollbar(HorizontalScrollbar);
destroyScrollbar(VerticalScrollbar);
- if (renderer().frame().page()) {
- if (ScrollingCoordinator* scrollingCoordinator = renderer().frame().page()->scrollingCoordinator())
- scrollingCoordinator->willDestroyScrollableArea(this);
- }
+ if (auto* scrollingCoordinator = renderer().page().scrollingCoordinator())
+ scrollingCoordinator->willDestroyScrollableArea(*this);
if (m_reflection)
removeReflection();
-
-#if ENABLE(CSS_FILTERS)
+
FilterInfo::remove(*this);
-#endif
// Child layers will be deleted by their corresponding render objects, so
// we don't need to delete them ourselves.
-#if USE(ACCELERATED_COMPOSITING)
clearBacking(true);
-#endif
}
String RenderLayer::name() const
{
StringBuilder name;
- name.append(renderer().renderName());
if (Element* element = renderer().element()) {
- name.append(' ');
- name.append(element->tagName());
+ name.append(" <");
+ name.append(element->tagName().convertToLowercaseWithoutLocale());
+ name.append('>');
if (element->hasID()) {
name.appendLiteral(" id=\'");
@@ -280,14 +396,25 @@ String RenderLayer::name() const
if (element->hasClass()) {
name.appendLiteral(" class=\'");
- for (size_t i = 0; i < element->classNames().size(); ++i) {
+ size_t classNamesToDump = element->classNames().size();
+ const size_t maxNumClassNames = 7;
+ bool addEllipsis = false;
+ if (classNamesToDump > maxNumClassNames) {
+ classNamesToDump = maxNumClassNames;
+ addEllipsis = true;
+ }
+
+ for (size_t i = 0; i < classNamesToDump; ++i) {
if (i > 0)
name.append(' ');
name.append(element->classNames()[i]);
}
+ if (addEllipsis)
+ name.append("...");
name.append('\'');
}
- }
+ } else
+ name.append(renderer().renderName());
if (isReflection())
name.appendLiteral(" (reflection)");
@@ -295,8 +422,6 @@ String RenderLayer::name() const
return name.toString();
}
-#if USE(ACCELERATED_COMPOSITING)
-
RenderLayerCompositor& RenderLayer::compositor() const
{
return renderer().view().compositor();
@@ -304,33 +429,20 @@ RenderLayerCompositor& RenderLayer::compositor() const
void RenderLayer::contentChanged(ContentChangeType changeType)
{
- // This can get called when video becomes accelerated, so the layers may change.
- if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor().updateLayerCompositingState(*this))
+ if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged || changeType == ImageChanged) && compositor().updateLayerCompositingState(*this))
compositor().setCompositingLayersNeedRebuild();
if (m_backing)
m_backing->contentChanged(changeType);
}
-#endif // USE(ACCELERATED_COMPOSITING)
-
bool RenderLayer::canRender3DTransforms() const
{
-#if USE(ACCELERATED_COMPOSITING)
return compositor().canRender3DTransforms();
-#else
- return false;
-#endif
}
-#if ENABLE(CSS_FILTERS)
-
bool RenderLayer::paintsWithFilters() const
{
- // FIXME: Eventually there will be cases where we paint with filters even without accelerated compositing,
- // and this whole function won't be inside the #if below.
-
-#if USE(ACCELERATED_COMPOSITING)
if (!renderer().hasFilter())
return false;
@@ -339,7 +451,6 @@ bool RenderLayer::paintsWithFilters() const
if (!m_backing || !m_backing->canCompositeFilters())
return true;
-#endif
return false;
}
@@ -348,45 +459,21 @@ bool RenderLayer::requiresFullLayerImageForFilters() const
{
if (!paintsWithFilters())
return false;
- FilterEffectRenderer* renderer = filterRenderer();
+ auto* renderer = filterRenderer();
return renderer && renderer->hasFilterThatMovesPixels();
}
FilterEffectRenderer* RenderLayer::filterRenderer() const
{
- FilterInfo* filterInfo = FilterInfo::getIfExists(*this);
- return filterInfo ? filterInfo->renderer() : 0;
-}
-
-#endif
-
-LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const
-{
- hasLayerOffset = true;
-
- if (!parent())
- return LayoutPoint();
-
- // This is similar to root() but we check if an ancestor layer would
- // prevent the optimization from working.
- const RenderLayer* rootLayer = 0;
- for (const RenderLayer* parentLayer = parent(); parentLayer; rootLayer = parentLayer, parentLayer = parentLayer->parent()) {
- hasLayerOffset = parentLayer->canUseConvertToLayerCoords();
- if (!hasLayerOffset)
- return LayoutPoint();
- }
- ASSERT(rootLayer == root());
-
- LayoutPoint offset;
- parent()->convertToLayerCoords(rootLayer, offset);
- return offset;
+ auto* filterInfo = FilterInfo::getIfExists(*this);
+ return filterInfo ? filterInfo->renderer() : nullptr;
}
void RenderLayer::updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags flags)
{
RenderGeometryMap geometryMap(UseTransforms);
if (this != rootLayer)
- geometryMap.pushMappingsToAncestor(parent(), 0);
+ geometryMap.pushMappingsToAncestor(parent(), nullptr);
updateLayerPositions(&geometryMap, flags);
}
@@ -402,26 +489,24 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
clearClipRects();
if (hasOverflowControls()) {
- LayoutPoint offsetFromRoot;
+ LayoutSize offsetFromRoot;
if (geometryMap)
- offsetFromRoot = LayoutPoint(geometryMap->absolutePoint(FloatPoint()));
+ offsetFromRoot = LayoutSize(toFloatSize(geometryMap->absolutePoint(FloatPoint())));
else {
// FIXME: It looks suspicious to call convertToLayerCoords here
// as canUseConvertToLayerCoords may be true for an ancestor layer.
- convertToLayerCoords(root(), offsetFromRoot);
+ offsetFromRoot = offsetFromAncestor(root());
}
- positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
+ positionOverflowControls(roundedIntSize(offsetFromRoot));
}
updateDescendantDependentFlags();
if (flags & UpdatePagination)
updatePagination();
- else {
- m_isPaginated = false;
- m_enclosingPaginationLayer = 0;
- }
-
+ else
+ m_enclosingPaginationLayer = nullptr;
+
if (m_hasVisibleContent) {
// FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1
// mapping between them and the RenderObjects. It would be neat to enable
@@ -435,13 +520,13 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
// FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same
// as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
- if (flags & CheckForRepaint) {
+ if ((flags & CheckForRepaint) && m_hasComputedRepaintRect) {
if (!renderer().view().printing()) {
bool didRepaint = false;
if (m_repaintStatus & NeedsFullRepaint) {
- renderer().repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect));
+ renderer().repaintUsingContainer(repaintContainer, oldRepaintRect);
if (m_repaintRect != oldRepaintRect) {
- renderer().repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect));
+ renderer().repaintUsingContainer(repaintContainer, m_repaintRect);
didRepaint = true;
}
} else if (shouldRepaintAfterLayout()) {
@@ -452,9 +537,9 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
if (didRepaint && renderer().isRenderNamedFlowFragmentContainer()) {
// If we just repainted a region, we must also repaint the flow thread since it is the one
// doing the actual painting of the flowed content.
- RenderNamedFlowFragment* region = toRenderBlockFlow(&renderer())->renderNamedFlowFragment();
- if (region->flowThread())
- region->flowThread()->layer()->repaintIncludingDescendants();
+ RenderNamedFlowFragment& region = *downcast<RenderBlockFlow>(renderer()).renderNamedFlowFragment();
+ if (region.isValid())
+ region.flowThread()->layer()->repaintIncludingDescendants();
}
}
}
@@ -462,30 +547,32 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
clearRepaintRects();
m_repaintStatus = NeedsNormalRepaint;
+ m_hasTransformedAncestor = flags & SeenTransformedLayer;
+ m_has3DTransformedAncestor = flags & Seen3DTransformedLayer;
- // Go ahead and update the reflection's position and size.
+ // Update the reflection's position and size.
if (m_reflection)
m_reflection->layout();
-#if USE(ACCELERATED_COMPOSITING)
// Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
if (isComposited())
flags &= ~IsCompositingUpdateRoot;
-#endif
- if (useRegionBasedColumns() && renderer().isInFlowRenderFlowThread()) {
+ if (renderer().isInFlowRenderFlowThread()) {
updatePagination();
flags |= UpdatePagination;
}
-
- if (renderer().hasColumns())
- flags |= UpdatePagination;
+
+ if (transform()) {
+ flags |= SeenTransformedLayer;
+ if (!transform()->isAffine())
+ flags |= Seen3DTransformedLayer;
+ }
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(geometryMap, flags);
-#if USE(ACCELERATED_COMPOSITING)
if ((flags & UpdateCompositingLayers) && isComposited()) {
RenderLayerBacking::UpdateAfterLayoutFlags updateFlags = RenderLayerBacking::CompositingChildrenOnly;
if (flags & NeedsFullRepaintInBacking)
@@ -494,11 +581,10 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
updateFlags |= RenderLayerBacking::IsUpdateRoot;
backing()->updateAfterLayout(updateFlags);
}
-#endif
// With all our children positioned, now update our marquee if we need to.
if (m_marquee) {
- // FIXME: would like to use TemporaryChange<> but it doesn't work with bitfields.
+ // FIXME: would like to use SetForScope<> but it doesn't work with bitfields.
bool oldUpdatingMarqueePosition = m_updatingMarqueePosition;
m_updatingMarqueePosition = true;
m_marquee->updateMarqueePosition();
@@ -507,6 +593,8 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
if (geometryMap)
geometryMap->popMappingsToAncestor(parent());
+
+ renderer().document().markers().invalidateRectsForAllMarkers();
}
LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
@@ -517,7 +605,7 @@ LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const
if (child->isComposited())
continue;
- repaintRect.unite(child->repaintRectIncludingNonCompositingDescendants());
+ repaintRect.uniteIfNonZero(child->repaintRectIncludingNonCompositingDescendants());
}
return repaintRect;
}
@@ -548,7 +636,7 @@ void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus()
bool RenderLayer::acceleratedCompositingForOverflowScrollEnabled() const
{
- return renderer().frame().settings().acceleratedCompositingForOverflowScrollEnabled();
+ return renderer().settings().acceleratedCompositingForOverflowScrollEnabled();
}
// If we are a stacking container, then this function will determine if our
@@ -636,8 +724,8 @@ void RenderLayer::updateDescendantsAreContiguousInStackingOrder()
ASSERT(!m_normalFlowListDirty);
ASSERT(!m_zOrderListsDirty);
- OwnPtr<Vector<RenderLayer*>> posZOrderList;
- OwnPtr<Vector<RenderLayer*>> negZOrderList;
+ std::unique_ptr<Vector<RenderLayer*>> posZOrderList;
+ std::unique_ptr<Vector<RenderLayer*>> negZOrderList;
rebuildZOrderLists(StopAtStackingContexts, posZOrderList, negZOrderList);
// Create a reverse lookup.
@@ -697,14 +785,10 @@ void RenderLayer::updateDescendantsAreContiguousInStackingOrderRecursive(const H
if (!isStackingContext()) {
bool newValue = maxIndex - minIndex == count;
-#if USE(ACCELERATED_COMPOSITING)
bool didUpdate = newValue != m_descendantsAreContiguousInStackingOrder;
-#endif
m_descendantsAreContiguousInStackingOrder = newValue;
-#if USE(ACCELERATED_COMPOSITING)
if (didUpdate)
updateNeedsCompositedScrolling();
-#endif
}
}
@@ -712,6 +796,12 @@ void RenderLayer::computeRepaintRects(const RenderLayerModelObject* repaintConta
{
ASSERT(!m_visibleContentStatusDirty);
+ if (!isSelfPaintingLayer()) {
+ clearRepaintRects();
+ return;
+ }
+
+ m_hasComputedRepaintRect = true;
m_repaintRect = renderer().clippedOverflowRectForRepaint(repaintContainer);
m_outlineBox = renderer().outlineBoundsForRepaint(repaintContainer, geometryMap);
}
@@ -730,17 +820,19 @@ void RenderLayer::computeRepaintRectsIncludingDescendants()
void RenderLayer::clearRepaintRects()
{
- ASSERT(!m_hasVisibleContent);
ASSERT(!m_visibleContentStatusDirty);
- m_repaintRect = IntRect();
- m_outlineBox = IntRect();
+ m_hasComputedRepaintRect = false;
+ m_repaintRect = LayoutRect();
+ m_outlineBox = LayoutRect();
}
void RenderLayer::updateLayerPositionsAfterDocumentScroll()
{
ASSERT(this == renderer().view().layer());
+ LOG(Scrolling, "RenderLayer::updateLayerPositionsAfterDocumentScroll");
+
RenderGeometryMap geometryMap(UseTransforms);
updateLayerPositionsAfterScroll(&geometryMap);
}
@@ -749,7 +841,7 @@ void RenderLayer::updateLayerPositionsAfterOverflowScroll()
{
RenderGeometryMap geometryMap(UseTransforms);
if (this != renderer().view().layer())
- geometryMap.pushMappingsToAncestor(parent(), 0);
+ geometryMap.pushMappingsToAncestor(parent(), nullptr);
// FIXME: why is it OK to not check the ancestors of this layer in order to
// initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
@@ -772,9 +864,6 @@ void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap
if (positionChanged)
flags |= HasChangedAncestor;
- if (geometryMap)
- geometryMap->pushMappingsToAncestor(this, parent());
-
if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
clearClipRects();
@@ -783,15 +872,23 @@ void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap
if (renderer().hasOverflowClip())
flags |= HasSeenAncestorWithOverflowClip;
+
+ bool shouldComputeRepaintRects = (flags & HasSeenViewportConstrainedAncestor || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip)) && isSelfPaintingLayer();
+ bool isVisuallyEmpty = !isVisuallyNonEmpty();
+ bool shouldPushAndPopMappings = geometryMap && ((shouldComputeRepaintRects && !isVisuallyEmpty) || firstChild());
+ if (shouldPushAndPopMappings)
+ geometryMap->pushMappingsToAncestor(this, parent());
- if (flags & HasSeenViewportConstrainedAncestor
- || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip)) {
- // FIXME: We could track the repaint container as we walk down the tree.
- computeRepaintRects(renderer().containerForRepaint(), geometryMap);
+ if (shouldComputeRepaintRects) {
+ // When scrolling, we don't compute repaint rects for visually non-empty layers.
+ if (isVisuallyEmpty)
+ clearRepaintRects();
+ else // FIXME: We could track the repaint container as we walk down the tree.
+ computeRepaintRects(renderer().containerForRepaint(), geometryMap);
} else {
// Check that our cached rects are correct.
- ASSERT(m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()));
- ASSERT(m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint(), geometryMap));
+ ASSERT(!m_hasComputedRepaintRect || (m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint())));
+ ASSERT(!m_hasComputedRepaintRect || m_outlineBox == renderer().outlineBoundsForRepaint(renderer().containerForRepaint()));
}
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
@@ -808,11 +905,11 @@ void RenderLayer::updateLayerPositionsAfterScroll(RenderGeometryMap* geometryMap
m_updatingMarqueePosition = oldUpdatingMarqueePosition;
}
- if (geometryMap)
+ if (shouldPushAndPopMappings)
geometryMap->popMappingsToAncestor(parent());
-}
-#if USE(ACCELERATED_COMPOSITING)
+ renderer().document().markers().invalidateRectsForAllMarkers();
+}
void RenderLayer::positionNewlyCreatedOverflowControls()
{
@@ -821,41 +918,69 @@ void RenderLayer::positionNewlyCreatedOverflowControls()
RenderGeometryMap geometryMap(UseTransforms);
if (this != renderer().view().layer() && parent())
- geometryMap.pushMappingsToAncestor(parent(), 0);
+ geometryMap.pushMappingsToAncestor(parent(), nullptr);
LayoutPoint offsetFromRoot = LayoutPoint(geometryMap.absolutePoint(FloatPoint()));
positionOverflowControls(toIntSize(roundedIntPoint(offsetFromRoot)));
}
-#endif
-
#if ENABLE(CSS_COMPOSITING)
void RenderLayer::updateBlendMode()
{
+ bool hadBlendMode = m_blendMode != BlendModeNormal;
+ if (parent() && hadBlendMode != hasBlendMode()) {
+ if (hasBlendMode())
+ parent()->updateAncestorChainHasBlendingDescendants();
+ else
+ parent()->dirtyAncestorChainHasBlendingDescendants();
+ }
+
BlendMode newBlendMode = renderer().style().blendMode();
- if (newBlendMode != m_blendMode) {
+ if (newBlendMode != m_blendMode)
m_blendMode = newBlendMode;
- if (backing())
- backing()->setBlendMode(newBlendMode);
+}
+
+void RenderLayer::updateAncestorChainHasBlendingDescendants()
+{
+ for (auto* layer = this; layer; layer = layer->parent()) {
+ if (!layer->hasNotIsolatedBlendingDescendantsStatusDirty() && layer->hasNotIsolatedBlendingDescendants())
+ break;
+ layer->m_hasNotIsolatedBlendingDescendants = true;
+ layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
+
+ layer->updateSelfPaintingLayer();
+
+ if (layer->isStackingContext())
+ break;
}
}
+void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
+{
+ for (auto* layer = this; layer; layer = layer->parent()) {
+ if (layer->hasNotIsolatedBlendingDescendantsStatusDirty())
+ break;
+
+ layer->m_hasNotIsolatedBlendingDescendantsStatusDirty = true;
+
+ if (layer->isStackingContext())
+ break;
+ }
+}
#endif
void RenderLayer::updateTransform()
{
- // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
- // so check style too.
- bool hasTransform = renderer().hasTransform() && renderer().style().hasTransform();
+ bool hasTransform = renderer().hasTransform();
bool had3DTransform = has3DTransform();
- bool hadTransform = m_transform;
+ bool hadTransform = !!m_transform;
if (hasTransform != hadTransform) {
if (hasTransform)
- m_transform = adoptPtr(new TransformationMatrix);
+ m_transform = std::make_unique<TransformationMatrix>();
else
- m_transform.clear();
+ m_transform = nullptr;
// Layers with transforms act as clip rects roots, so clear the cached clip rects here.
clearClipRectsIncludingDescendants();
@@ -865,7 +990,7 @@ void RenderLayer::updateTransform()
RenderBox* box = renderBox();
ASSERT(box);
m_transform->makeIdentity();
- box->style().applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
+ box->style().applyTransform(*m_transform, snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
makeMatrixRenderable(*m_transform, canRender3DTransforms());
}
@@ -877,27 +1002,26 @@ TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOr
{
if (!m_transform)
return TransformationMatrix();
+
+ RenderBox* box = renderBox();
-#if USE(ACCELERATED_COMPOSITING)
- if (renderer().style().isRunningAcceleratedAnimation()) {
+ if (renderer().animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyTransform, AnimationBase::Running | AnimationBase::Paused)) {
TransformationMatrix currTransform;
- RefPtr<RenderStyle> style = renderer().animation().getAnimatedStyleForRenderer(&renderer());
- style->applyTransform(currTransform, renderBox()->pixelSnappedBorderBoxRect().size(), applyOrigin);
+ FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
+ std::unique_ptr<RenderStyle> style = renderer().animation().getAnimatedStyleForRenderer(renderer());
+ style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
makeMatrixRenderable(currTransform, canRender3DTransforms());
return currTransform;
}
// m_transform includes transform-origin, so we need to recompute the transform here.
if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
- RenderBox* box = renderBox();
TransformationMatrix currTransform;
- box->style().applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin);
+ FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
+ box->style().applyTransform(currTransform, pixelSnappedBorderRect, RenderStyle::ExcludeTransformOrigin);
makeMatrixRenderable(currTransform, canRender3DTransforms());
return currTransform;
}
-#else
- UNUSED_PARAM(applyOrigin);
-#endif
return *m_transform;
}
@@ -925,102 +1049,85 @@ RenderLayer* RenderLayer::enclosingOverflowClipLayer(IncludeSelfOrNot includeSel
layer = layer->parent();
}
- return 0;
+ return nullptr;
}
-static bool checkContainingBlockChainForPagination(RenderLayerModelObject* renderer, RenderBox* ancestorColumnsRenderer)
+// FIXME: This is terrible. Bring back a cached bit for this someday. This crawl is going to slow down all
+// painting of content inside paginated layers.
+bool RenderLayer::hasCompositedLayerInEnclosingPaginationChain() const
{
- RenderLayerModelObject* prevBlock = renderer;
- RenderBlock* containingBlock;
- for (containingBlock = renderer->containingBlock();
- containingBlock && containingBlock != &renderer->view() && containingBlock != ancestorColumnsRenderer;
- containingBlock = containingBlock->containingBlock()) {
- prevBlock = containingBlock;
- }
-
- // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
- if (containingBlock != ancestorColumnsRenderer)
+ // No enclosing layer means no compositing in the chain.
+ if (!m_enclosingPaginationLayer)
return false;
-
- // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
- if (prevBlock->isOutOfFlowPositioned())
+
+ // If the enclosing layer is composited, we don't have to check anything in between us and that
+ // layer.
+ if (m_enclosingPaginationLayer->isComposited())
+ return true;
+
+ // If we are the enclosing pagination layer, then we can't be composited or we'd have passed the
+ // previous check.
+ if (m_enclosingPaginationLayer == this)
return false;
-
- // Otherwise we are paginated by the columns block.
- return true;
-}
-bool RenderLayer::useRegionBasedColumns() const
-{
- const Settings& settings = renderer().frame().settings();
- return settings.regionBasedColumnsEnabled();
+ // The enclosing paginated layer is our ancestor and is not composited, so we have to check
+ // intermediate layers between us and the enclosing pagination layer. Start with our own layer.
+ if (isComposited())
+ return true;
+
+ // For normal flow layers, we can recur up the layer tree.
+ if (isNormalFlowOnly())
+ return parent()->hasCompositedLayerInEnclosingPaginationChain();
+
+ // Otherwise we have to go up the containing block chain. Find the first enclosing
+ // containing block layer ancestor, and check that.
+ for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
+ if (containingBlock->hasLayer())
+ return containingBlock->layer()->hasCompositedLayerInEnclosingPaginationChain();
+ }
+ return false;
}
void RenderLayer::updatePagination()
{
- m_isPaginated = false;
- m_enclosingPaginationLayer = 0;
-
- if (isComposited() || !parent())
- return; // FIXME: We will have to deal with paginated compositing layers someday.
- // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
-
- // The main difference between the paginated booleans for the old column code and the new column code
- // is that each paginated layer has to paint on its own with the new code. There is no
- // recurring into child layers. This means that the m_isPaginated bits for the new column code can't just be set on
- // "roots" that get split and paint all their descendants. Instead each layer has to be checked individually and
+ m_enclosingPaginationLayer = nullptr;
+
+ if (!parent())
+ return;
+
+ // Each layer that is inside a multicolumn flow thread has to be checked individually and
// genuinely know if it is going to have to split itself up when painting only its contents (and not any other descendant
// layers). We track an enclosingPaginationLayer instead of using a simple bit, since we want to be able to get back
// to that layer easily.
- bool regionBasedColumnsUsed = useRegionBasedColumns();
- if (regionBasedColumnsUsed && renderer().isInFlowRenderFlowThread()) {
+ if (renderer().isInFlowRenderFlowThread()) {
m_enclosingPaginationLayer = this;
return;
}
if (isNormalFlowOnly()) {
- if (regionBasedColumnsUsed) {
- // Content inside a transform is not considered to be paginated, since we simply
- // paint the transform multiple times in each column, so we don't have to use
- // fragments for the transformed content.
- m_enclosingPaginationLayer = parent()->enclosingPaginationLayer();
- if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
- m_enclosingPaginationLayer = 0;
- } else
- m_isPaginated = parent()->renderer().hasColumns();
+ // Content inside a transform is not considered to be paginated, since we simply
+ // paint the transform multiple times in each column, so we don't have to use
+ // fragments for the transformed content.
+ if (parent()->hasTransform())
+ m_enclosingPaginationLayer = nullptr;
+ else
+ m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
return;
}
// For the new columns code, we want to walk up our containing block chain looking for an enclosing layer. Once
// we find one, then we just check its pagination status.
- if (regionBasedColumnsUsed) {
- RenderView* renderView = &renderer().view();
- RenderBlock* containingBlock;
- for (containingBlock = renderer().containingBlock();
- containingBlock && containingBlock != renderView;
- containingBlock = containingBlock->containingBlock()) {
- if (containingBlock->hasLayer()) {
- // Content inside a transform is not considered to be paginated, since we simply
- // paint the transform multiple times in each column, so we don't have to use
- // fragments for the transformed content.
- m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer();
- if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTransform())
- m_enclosingPaginationLayer = 0;
- return;
- }
- }
- return;
- }
-
- // If we're not normal flow, then we need to look for a multi-column object between us and our stacking container.
- RenderLayer* ancestorStackingContainer = stackingContainer();
- for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
- if (curr->renderer().hasColumns()) {
- m_isPaginated = checkContainingBlockChainForPagination(&renderer(), curr->renderBox());
+ for (const auto* containingBlock = renderer().containingBlock(); containingBlock && !is<RenderView>(*containingBlock); containingBlock = containingBlock->containingBlock()) {
+ if (containingBlock->hasLayer()) {
+ // Content inside a transform is not considered to be paginated, since we simply
+ // paint the transform multiple times in each column, so we don't have to use
+ // fragments for the transformed content.
+ if (containingBlock->layer()->hasTransform())
+ m_enclosingPaginationLayer = nullptr;
+ else
+ m_enclosingPaginationLayer = containingBlock->layer()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
return;
}
- if (curr == ancestorStackingContainer)
- return;
}
}
@@ -1087,10 +1194,13 @@ void RenderLayer::setAncestorChainHasVisibleDescendant()
void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks)
{
- if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty) {
- m_hasVisibleDescendant = false;
- m_hasSelfPaintingLayerDescendant = false;
- m_hasOutOfFlowPositionedDescendant = false;
+ if (m_visibleDescendantStatusDirty || m_hasSelfPaintingLayerDescendantDirty || m_hasOutOfFlowPositionedDescendantDirty || hasNotIsolatedBlendingDescendantsStatusDirty()) {
+ bool hasVisibleDescendant = false;
+ bool hasSelfPaintingLayerDescendant = false;
+ bool hasOutOfFlowPositionedDescendant = false;
+#if ENABLE(CSS_COMPOSITING)
+ bool hasNotIsolatedBlendingDescendants = false;
+#endif
HashSet<const RenderObject*> childOutOfFlowDescendantContainingBlocks;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
@@ -1107,29 +1217,41 @@ void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* o
outOfFlowDescendantContainingBlocks->add(*it);
}
- bool hasVisibleDescendant = child->m_hasVisibleContent || child->m_hasVisibleDescendant;
- bool hasSelfPaintingLayerDescendant = child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
- bool hasOutOfFlowPositionedDescendant = !childOutOfFlowDescendantContainingBlocks.isEmpty();
-
- m_hasVisibleDescendant |= hasVisibleDescendant;
- m_hasSelfPaintingLayerDescendant |= hasSelfPaintingLayerDescendant;
- m_hasOutOfFlowPositionedDescendant |= hasOutOfFlowPositionedDescendant;
+ hasVisibleDescendant |= child->m_hasVisibleContent || child->m_hasVisibleDescendant;
+ hasSelfPaintingLayerDescendant |= child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendant();
+ hasOutOfFlowPositionedDescendant |= !childOutOfFlowDescendantContainingBlocks.isEmpty();
+#if ENABLE(CSS_COMPOSITING)
+ hasNotIsolatedBlendingDescendants |= child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending());
+#endif
- if (m_hasVisibleDescendant && m_hasSelfPaintingLayerDescendant && m_hasOutOfFlowPositionedDescendant)
+ bool allFlagsSet = hasVisibleDescendant && hasSelfPaintingLayerDescendant && hasOutOfFlowPositionedDescendant;
+#if ENABLE(CSS_COMPOSITING)
+ allFlagsSet &= hasNotIsolatedBlendingDescendants;
+#endif
+ if (allFlagsSet)
break;
}
if (outOfFlowDescendantContainingBlocks)
outOfFlowDescendantContainingBlocks->remove(&renderer());
+ m_hasVisibleDescendant = hasVisibleDescendant;
m_visibleDescendantStatusDirty = false;
+ m_hasSelfPaintingLayerDescendant = hasSelfPaintingLayerDescendant;
m_hasSelfPaintingLayerDescendantDirty = false;
-#if USE(ACCELERATED_COMPOSITING)
+ m_hasOutOfFlowPositionedDescendant = hasOutOfFlowPositionedDescendant;
if (m_hasOutOfFlowPositionedDescendantDirty)
updateNeedsCompositedScrolling();
-#endif
+
m_hasOutOfFlowPositionedDescendantDirty = false;
+#if ENABLE(CSS_COMPOSITING)
+ m_hasNotIsolatedBlendingDescendants = hasNotIsolatedBlendingDescendants;
+ if (m_hasNotIsolatedBlendingDescendantsStatusDirty) {
+ m_hasNotIsolatedBlendingDescendantsStatusDirty = false;
+ updateSelfPaintingLayer();
+ }
+#endif
}
if (m_visibleContentStatusDirty) {
@@ -1144,7 +1266,7 @@ void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* o
m_hasVisibleContent = true;
break;
}
- RenderObject* child;
+ RenderObject* child = nullptr;
if (!r->hasLayer() && (child = r->firstChildSlow()))
r = child;
else if (r->nextSibling())
@@ -1153,7 +1275,7 @@ void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* o
do {
r = r->parent();
if (r == &renderer())
- r = 0;
+ r = nullptr;
} while (r && !r->nextSibling());
if (r)
r = r->nextSibling();
@@ -1164,23 +1286,6 @@ void RenderLayer::updateDescendantDependentFlags(HashSet<const RenderObject*>* o
}
}
-#if USE(ACCELERATED_COMPOSITING)
-// Return true if the new clipping behaviour requires layer update.
-bool RenderLayer::checkIfDescendantClippingContextNeedsUpdate(bool isClipping)
-{
- for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
- RenderLayerBacking* backing = child->backing();
- // Layer subtree needs update when new clipping is added or existing clipping is removed.
- if (backing && (isClipping || backing->hasAncestorClippingLayer()))
- return true;
-
- if (child->checkIfDescendantClippingContextNeedsUpdate(isClipping))
- return true;
- }
- return false;
-}
-#endif
-
void RenderLayer::dirty3DTransformedDescendantStatus()
{
RenderLayer* curr = stackingContainer();
@@ -1206,14 +1311,14 @@ bool RenderLayer::update3DTransformedDescendantStatus()
// Transformed or preserve-3d descendants can only be in the z-order lists, not
// in the normal flow list, so we only need to check those.
if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) {
- for (unsigned i = 0; i < positiveZOrderList->size(); ++i)
- m_has3DTransformedDescendant |= positiveZOrderList->at(i)->update3DTransformedDescendantStatus();
+ for (auto* layer : *positiveZOrderList)
+ m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
}
// Now check our negative z-index children.
if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) {
- for (unsigned i = 0; i < negativeZOrderList->size(); ++i)
- m_has3DTransformedDescendant |= negativeZOrderList->at(i)->update3DTransformedDescendantStatus();
+ for (auto* layer : *negativeZOrderList)
+ m_has3DTransformedDescendant |= layer->update3DTransformedDescendantStatus();
}
m_3DTransformedDescendantStatusDirty = false;
@@ -1231,60 +1336,55 @@ bool RenderLayer::updateLayerPosition()
{
LayoutPoint localPoint;
LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
- if (renderer().isInline() && renderer().isRenderInline()) {
- RenderInline& inlineFlow = toRenderInline(renderer());
+ if (renderer().isInline() && is<RenderInline>(renderer())) {
+ auto& inlineFlow = downcast<RenderInline>(renderer());
IntRect lineBox = inlineFlow.linesBoundingBox();
setSize(lineBox.size());
- inlineBoundingBoxOffset = toSize(lineBox.location());
+ inlineBoundingBoxOffset = toLayoutSize(lineBox.location());
localPoint += inlineBoundingBoxOffset;
} else if (RenderBox* box = renderBox()) {
// FIXME: Is snapping the size really needed here for the RenderBox case?
- setSize(pixelSnappedIntSize(box->size(), box->location()));
- localPoint += box->topLeftLocationOffset();
+ setSize(snappedIntRect(box->frameRect()).size());
+ box->applyTopLeftLocationOffset(localPoint);
}
- if (!renderer().isOutOfFlowPositioned() && renderer().parent()) {
+ if (!renderer().isOutOfFlowPositioned()) {
+ auto* ancestor = renderer().parent();
// We must adjust our position by walking up the render tree looking for the
// nearest enclosing object with a layer.
- RenderElement* curr = renderer().parent();
- while (curr && !curr->hasLayer()) {
- if (curr->isBox() && !curr->isTableRow()) {
+ while (ancestor && !ancestor->hasLayer()) {
+ if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor)) {
// Rows and cells share the same coordinate space (that of the section).
// Omit them when computing our xpos/ypos.
- localPoint += toRenderBox(curr)->topLeftLocationOffset();
+ localPoint += downcast<RenderBox>(*ancestor).topLeftLocationOffset();
}
- curr = curr->parent();
+ ancestor = ancestor->parent();
}
- if (curr->isBox() && curr->isTableRow()) {
+ if (is<RenderTableRow>(ancestor)) {
// Put ourselves into the row coordinate space.
- localPoint -= toRenderBox(curr)->topLeftLocationOffset();
+ localPoint -= downcast<RenderTableRow>(*ancestor).topLeftLocationOffset();
}
}
// Subtract our parent's scroll offset.
- if (renderer().isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
- RenderLayer* positionedParent = enclosingPositionedAncestor();
-
+ RenderLayer* positionedParent;
+ if (renderer().isOutOfFlowPositioned() && (positionedParent = enclosingAncestorForPosition(renderer().style().position()))) {
// For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
- if (positionedParent->renderer().hasOverflowClip()) {
- LayoutSize offset = positionedParent->scrolledContentOffset();
- localPoint -= offset;
- }
+ if (positionedParent->renderer().hasOverflowClip())
+ localPoint -= toLayoutSize(positionedParent->scrollPosition());
- if (renderer().isOutOfFlowPositioned() && positionedParent->renderer().isInFlowPositioned() && positionedParent->renderer().isRenderInline()) {
- LayoutSize offset = toRenderInline(positionedParent->renderer()).offsetForInFlowPositionedInline(&toRenderBox(renderer()));
+ if (renderer().isOutOfFlowPositioned() && positionedParent->renderer().isInFlowPositioned() && is<RenderInline>(positionedParent->renderer())) {
+ LayoutSize offset = downcast<RenderInline>(positionedParent->renderer()).offsetForInFlowPositionedInline(&downcast<RenderBox>(renderer()));
localPoint += offset;
}
} else if (parent()) {
- if (parent()->renderer().hasOverflowClip()) {
- IntSize scrollOffset = parent()->scrolledContentOffset();
- localPoint -= scrollOffset;
- }
+ if (parent()->renderer().hasOverflowClip())
+ localPoint -= toLayoutSize(parent()->scrollPosition());
}
bool positionOrOffsetChanged = false;
if (renderer().isInFlowPositioned()) {
- LayoutSize newOffset = toRenderBoxModelObject(renderer()).offsetForInFlowPosition();
+ LayoutSize newOffset = downcast<RenderBoxModelObject>(renderer()).offsetForInFlowPosition();
positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
m_offsetForInFlowPosition = newOffset;
localPoint.move(m_offsetForInFlowPosition);
@@ -1302,25 +1402,26 @@ bool RenderLayer::updateLayerPosition()
TransformationMatrix RenderLayer::perspectiveTransform() const
{
- if (!renderer().hasTransform())
+ RenderBox* box = renderBox();
+ if (!box)
+ return TransformationMatrix();
+
+ if (!box->hasTransformRelatedProperty())
return TransformationMatrix();
- const RenderStyle& style = renderer().style();
+ const RenderStyle& style = box->style();
if (!style.hasPerspective())
return TransformationMatrix();
// Maybe fetch the perspective from the backing?
- const IntRect borderBox = toRenderBox(renderer()).pixelSnappedBorderBoxRect();
- const float boxWidth = borderBox.width();
- const float boxHeight = borderBox.height();
-
- float perspectiveOriginX = floatValueForLength(style.perspectiveOriginX(), boxWidth);
- float perspectiveOriginY = floatValueForLength(style.perspectiveOriginY(), boxHeight);
+ const FloatRect borderBox = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
+ float perspectiveOriginX = floatValueForLength(style.perspectiveOriginX(), borderBox.width());
+ float perspectiveOriginY = floatValueForLength(style.perspectiveOriginY(), borderBox.height());
// A perspective origin of 0,0 makes the vanishing point in the center of the element.
// We want it to be in the top-left, so subtract half the height and width.
- perspectiveOriginX -= boxWidth / 2.0f;
- perspectiveOriginY -= boxHeight / 2.0f;
+ perspectiveOriginX -= borderBox.width() / 2.0f;
+ perspectiveOriginY -= borderBox.height() / 2.0f;
TransformationMatrix t;
t.translate(perspectiveOriginX, perspectiveOriginY);
@@ -1332,10 +1433,10 @@ TransformationMatrix RenderLayer::perspectiveTransform() const
FloatPoint RenderLayer::perspectiveOrigin() const
{
- if (!renderer().hasTransform())
+ if (!renderer().hasTransformRelatedProperty())
return FloatPoint();
- const LayoutRect borderBox = toRenderBox(renderer()).borderBoxRect();
+ const LayoutRect borderBox = downcast<RenderBox>(renderer()).borderBoxRect();
const RenderStyle& style = renderer().style();
return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBox.width()),
@@ -1352,55 +1453,77 @@ RenderLayer* RenderLayer::stackingContainer() const
return layer;
}
-static inline bool isPositionedContainer(RenderLayer* layer)
+static inline bool isContainerForPositioned(RenderLayer& layer, EPosition position)
{
- return layer->isRootLayer() || layer->renderer().isPositioned() || layer->hasTransform();
-}
+ switch (position) {
+ case FixedPosition:
+ return layer.renderer().canContainFixedPositionObjects();
-static inline bool isFixedPositionedContainer(RenderLayer* layer)
-{
- return layer->isRootLayer() || layer->hasTransform();
+ case AbsolutePosition:
+ return layer.renderer().canContainAbsolutelyPositionedObjects();
+
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
}
-RenderLayer* RenderLayer::enclosingPositionedAncestor() const
+RenderLayer* RenderLayer::enclosingAncestorForPosition(EPosition position) const
{
RenderLayer* curr = parent();
- while (curr && !isPositionedContainer(curr))
+ while (curr && !isContainerForPositioned(*curr, position))
curr = curr->parent();
return curr;
}
-static RenderLayer* parentLayerCrossFrame(const RenderLayer* layer)
+static RenderLayer* parentLayerCrossFrame(const RenderLayer& layer)
{
- ASSERT(layer);
- if (layer->parent())
- return layer->parent();
+ if (layer.parent())
+ return layer.parent();
- HTMLFrameOwnerElement* ownerElement = layer->renderer().document().ownerElement();
+ HTMLFrameOwnerElement* ownerElement = layer.renderer().document().ownerElement();
if (!ownerElement)
- return 0;
+ return nullptr;
RenderElement* ownerRenderer = ownerElement->renderer();
if (!ownerRenderer)
- return 0;
+ return nullptr;
return ownerRenderer->enclosingLayer();
}
RenderLayer* RenderLayer::enclosingScrollableLayer() const
{
- for (RenderLayer* nextLayer = parentLayerCrossFrame(this); nextLayer; nextLayer = parentLayerCrossFrame(nextLayer)) {
- if (nextLayer->renderer().isBox() && toRenderBox(nextLayer->renderer()).canBeScrolledAndHasScrollableArea())
+ for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
+ if (is<RenderBox>(nextLayer->renderer()) && downcast<RenderBox>(nextLayer->renderer()).canBeScrolledAndHasScrollableArea())
return nextLayer;
}
- return 0;
+ return nullptr;
}
-IntRect RenderLayer::scrollableAreaBoundingBox() const
+IntRect RenderLayer::scrollableAreaBoundingBox(bool* isInsideFixed) const
{
- return renderer().absoluteBoundingBoxRect();
+ return renderer().absoluteBoundingBoxRect(/* useTransforms */ true, isInsideFixed);
+}
+
+bool RenderLayer::isRubberBandInProgress() const
+{
+#if ENABLE(RUBBER_BANDING)
+ if (!scrollsOverflow())
+ return false;
+
+ if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
+ return scrollAnimator->isRubberBandInProgress();
+#endif
+
+ return false;
+}
+
+bool RenderLayer::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
+{
+ return renderer().settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
}
RenderLayer* RenderLayer::enclosingTransformedAncestor() const
@@ -1412,14 +1535,13 @@ RenderLayer* RenderLayer::enclosingTransformedAncestor() const
return curr;
}
-static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
+static inline const RenderLayer* compositingContainer(const RenderLayer& layer)
{
- return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContainer();
+ return layer.isNormalFlowOnly() ? layer.parent() : layer.stackingContainer();
}
inline bool RenderLayer::shouldRepaintAfterLayout() const
{
-#if USE(ACCELERATED_COMPOSITING)
if (m_repaintStatus == NeedsNormalRepaint)
return true;
@@ -1427,16 +1549,11 @@ inline bool RenderLayer::shouldRepaintAfterLayout() const
// layout, don't need to be repainted. They just need to be recomposited.
ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout);
return !isComposited() || backing()->paintsIntoCompositedAncestor();
-#else
- return true;
-#endif
}
-#if USE(ACCELERATED_COMPOSITING)
-
-static bool compositedWithOwnBackingStore(const RenderLayer* layer)
+bool compositedWithOwnBackingStore(const RenderLayer& layer)
{
- return layer->isComposited() && !layer->backing()->paintsIntoCompositedAncestor();
+ return layer.isComposited() && !layer.backing()->paintsIntoCompositedAncestor();
}
RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf) const
@@ -1444,31 +1561,27 @@ RenderLayer* RenderLayer::enclosingCompositingLayer(IncludeSelfOrNot includeSelf
if (includeSelf == IncludeSelf && isComposited())
return const_cast<RenderLayer*>(this);
- for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
+ for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
if (curr->isComposited())
return const_cast<RenderLayer*>(curr);
}
- return 0;
+ return nullptr;
}
RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(IncludeSelfOrNot includeSelf) const
{
- if (includeSelf == IncludeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
+ if (includeSelf == IncludeSelf && compositedWithOwnBackingStore(*this))
return const_cast<RenderLayer*>(this);
- for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
- if (compositedWithOwnBackingStore(curr))
+ for (const RenderLayer* curr = compositingContainer(*this); curr; curr = compositingContainer(*curr)) {
+ if (compositedWithOwnBackingStore(*curr))
return const_cast<RenderLayer*>(curr);
}
- return 0;
+ return nullptr;
}
-#endif
-
-#if ENABLE(CSS_FILTERS)
-
RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) const
{
const RenderLayer* curr = (includeSelf == IncludeSelf) ? this : parent();
@@ -1477,24 +1590,19 @@ RenderLayer* RenderLayer::enclosingFilterLayer(IncludeSelfOrNot includeSelf) con
return const_cast<RenderLayer*>(curr);
}
- return 0;
+ return nullptr;
}
RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const
{
for (const RenderLayer* curr = this; curr; curr = curr->parent()) {
- if ((curr != this && curr->requiresFullLayerImageForFilters())
-#if USE(ACCELERATED_COMPOSITING)
- || compositedWithOwnBackingStore(curr)
-#endif
- || curr->isRootLayer()
- )
+ if ((curr != this && curr->requiresFullLayerImageForFilters()) || compositedWithOwnBackingStore(*curr) || curr->isRootLayer())
return const_cast<RenderLayer*>(curr);
}
- return 0;
+ return nullptr;
}
-void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect, bool immediate)
+void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect)
{
if (rect.isEmpty())
return;
@@ -1509,8 +1617,7 @@ void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect,
ASSERT(parentLayer);
FloatQuad repaintQuad(rectForRepaint);
LayoutRect parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
-
-#if USE(ACCELERATED_COMPOSITING)
+
if (parentLayer->isComposited()) {
if (!parentLayer->backing()->paintsIntoWindow()) {
parentLayer->setBackingNeedsRepaintInRect(parentLayerRect);
@@ -1520,15 +1627,14 @@ void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect,
parentLayer = renderer().view().layer();
parentLayerRect = renderer().localToContainerQuad(repaintQuad, &parentLayer->renderer()).enclosingBoundingBox();
}
-#endif
if (parentLayer->paintsWithFilters()) {
- parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect, immediate);
+ parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect);
return;
}
if (parentLayer->isRootLayer()) {
- toRenderView(parentLayer->renderer()).repaintViewRectangle(parentLayerRect, immediate);
+ downcast<RenderView>(parentLayer->renderer()).repaintViewRectangle(parentLayerRect);
return;
}
@@ -1544,38 +1650,30 @@ bool RenderLayer::hasAncestorWithFilterOutsets() const
return false;
}
-#endif
-
RenderLayer* RenderLayer::clippingRootForPainting() const
{
-#if USE(ACCELERATED_COMPOSITING)
if (isComposited())
return const_cast<RenderLayer*>(this);
-#endif
const RenderLayer* current = this;
while (current) {
if (current->isRootLayer())
return const_cast<RenderLayer*>(current);
- current = compositingContainer(current);
+ current = compositingContainer(*current);
ASSERT(current);
- if (current->transform()
-#if USE(ACCELERATED_COMPOSITING)
- || compositedWithOwnBackingStore(current)
-#endif
- )
+ if (current->transform() || compositedWithOwnBackingStore(*current))
return const_cast<RenderLayer*>(current);
}
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
LayoutPoint RenderLayer::absoluteToContents(const LayoutPoint& absolutePoint) const
{
// We don't use convertToLayerCoords because it doesn't know about transforms
- return roundedLayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
+ return LayoutPoint(renderer().absoluteToLocal(absolutePoint, UseTransforms));
}
bool RenderLayer::cannotBlitToWindow() const
@@ -1587,27 +1685,18 @@ bool RenderLayer::cannotBlitToWindow() const
return parent()->cannotBlitToWindow();
}
-bool RenderLayer::isTransparent() const
-{
-#if ENABLE(SVG)
- if (renderer().element() && renderer().element()->isSVGElement())
- return false;
-#endif
- return renderer().isTransparent() || renderer().hasMask();
-}
-
RenderLayer* RenderLayer::transparentPaintingAncestor()
{
if (isComposited())
- return 0;
+ return nullptr;
for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
if (curr->isComposited())
- return 0;
+ return nullptr;
if (curr->isTransparent())
return curr;
}
- return 0;
+ return nullptr;
}
enum TransparencyClipBoxBehavior {
@@ -1620,23 +1709,19 @@ enum TransparencyClipBoxMode {
RootOfTransparencyClipBox
};
-static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
+static LayoutRect transparencyClipBox(const RenderLayer&, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
-static void expandClipRectForRegionAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
+static void expandClipRectForRegionAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
{
// If this is a region, then the painting is actually done by its flow thread's layer.
- if (layer->renderer().isRenderNamedFlowFragmentContainer()) {
- RenderBlockFlow* regionContainer = toRenderBlockFlow(&layer->renderer());
- RenderNamedFlowFragment* region = regionContainer->renderNamedFlowFragment();
- RenderLayer* flowThreadLayer = region->flowThread()->layer();
- if (!layer->reflection() || layer->reflectionLayer() != flowThreadLayer) {
- LayoutRect flowThreadClipRect = transparencyClipBox(flowThreadLayer, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior);
-
- LayoutPoint offsetFromRoot;
- layer->convertToLayerCoords(flowThreadLayer, offsetFromRoot);
-
- LayoutSize moveOffset = (offsetFromRoot + regionContainer->contentBoxRect().location()) - region->flowThreadPortionRect().location();
+ if (layer.renderer().isRenderNamedFlowFragmentContainer()) {
+ RenderBlockFlow& regionContainer = downcast<RenderBlockFlow>(layer.renderer());
+ RenderNamedFlowFragment& region = *regionContainer.renderNamedFlowFragment();
+ RenderLayer* flowThreadLayer = region.flowThread()->layer();
+ if (flowThreadLayer && (!layer.reflection() || layer.reflectionLayer() != flowThreadLayer)) {
+ LayoutRect flowThreadClipRect = transparencyClipBox(*flowThreadLayer, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior);
+ LayoutSize moveOffset = (regionContainer.contentBoxRect().location() + layer.offsetFromAncestor(flowThreadLayer)) - region.flowThreadPortionRect().location();
flowThreadClipRect.move(moveOffset);
clipRect.unite(flowThreadClipRect);
@@ -1644,17 +1729,17 @@ static void expandClipRectForRegionAndReflection(LayoutRect& clipRect, const Ren
}
}
-static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
+static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer& layer, const RenderLayer* rootLayer,
TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
{
// If we have a mask, then the clip is limited to the border box area (and there is
// no need to examine child layers).
- if (!layer->renderer().hasMask()) {
+ if (!layer.renderer().hasMask()) {
// Note: we don't have to walk z-order lists since transparent elements always establish
// a stacking container. This means we can just walk the layer tree directly.
- for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
- if (!layer->reflection() || layer->reflectionLayer() != curr)
- clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
+ for (RenderLayer* curr = layer.firstChild(); curr; curr = curr->nextSibling()) {
+ if (!layer.reflection() || layer.reflectionLayer() != curr)
+ clipRect.unite(transparencyClipBox(*curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
}
}
@@ -1664,42 +1749,39 @@ static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons
// current transparencyClipBox to catch all child layers.
// FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
// size into the parent layer.
- if (layer->renderer().hasReflection()) {
- LayoutPoint delta;
- layer->convertToLayerCoords(rootLayer, delta);
- clipRect.move(-delta.x(), -delta.y());
- clipRect.unite(layer->renderBox()->reflectedRect(clipRect));
- clipRect.moveBy(delta);
+ if (layer.renderer().hasReflection()) {
+ LayoutSize delta = layer.offsetFromAncestor(rootLayer);
+ clipRect.move(-delta);
+ clipRect.unite(layer.renderBox()->reflectedRect(clipRect));
+ clipRect.move(delta);
}
}
-static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
+static LayoutRect transparencyClipBox(const RenderLayer& layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
{
// FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
// paintDirtyRect, and that should cut down on the amount we have to paint. Still it
// would be better to respect clips.
- if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior))
- || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransform()))) {
+ if (rootLayer != &layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer.paintsWithTransform(paintBehavior))
+ || (transparencyBehavior == HitTestingTransparencyClipBox && layer.hasTransform()))) {
// The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
// the transformed layer and all of its children.
- const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer->enclosingPaginationLayer() : 0;
+ RenderLayer::PaginationInclusionMode mode = transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::IncludeCompositedPaginatedLayers : RenderLayer::ExcludeCompositedPaginatedLayers;
+ const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer.enclosingPaginationLayer(mode) : nullptr;
const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
- LayoutPoint delta;
- layer->convertToLayerCoords(rootLayerForTransform, delta);
+ LayoutSize delta = layer.offsetFromAncestor(rootLayerForTransform);
TransformationMatrix transform;
- transform.translate(delta.x(), delta.y());
- transform = transform * *layer->transform();
+ transform.translate(delta.width(), delta.height());
+ transform.multiply(*layer.transform());
// We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
// paints unfragmented.
- LayoutRect clipRect = layer->boundingBox(layer);
- expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, paintBehavior);
-#if ENABLE(CSS_FILTERS)
- layer->renderer().style().filterOutsets().expandRect(clipRect);
-#endif
+ LayoutRect clipRect = layer.boundingBox(&layer);
+ expandClipRectForDescendantsAndReflection(clipRect, layer, &layer, transparencyBehavior, paintBehavior);
+ layer.renderer().style().filterOutsets().expandRect(clipRect);
LayoutRect result = transform.mapRect(clipRect);
if (!paginationLayer)
return result;
@@ -1707,46 +1789,58 @@ static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLaye
// We have to break up the transformed extent across our columns.
// Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
// get our true bounding box.
- RenderFlowThread& enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer());
+ auto& enclosingFlowThread = downcast<RenderFlowThread>(paginationLayer->renderer());
result = enclosingFlowThread.fragmentsBoundingBox(result);
-
- LayoutPoint rootLayerDelta;
- paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta);
- result.moveBy(rootLayerDelta);
+ result.move(paginationLayer->offsetFromAncestor(rootLayer));
return result;
}
- LayoutRect clipRect = layer->boundingBox(rootLayer, RenderLayer::UseFragmentBoxes);
+ LayoutRect clipRect = layer.boundingBox(rootLayer, layer.offsetFromAncestor(rootLayer), transparencyBehavior == HitTestingTransparencyClipBox ? RenderLayer::UseFragmentBoxesIncludingCompositing : RenderLayer::UseFragmentBoxesExcludingCompositing);
expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
-#if ENABLE(CSS_FILTERS)
- layer->renderer().style().filterOutsets().expandRect(clipRect);
-#endif
+ layer.renderer().style().filterOutsets().expandRect(clipRect);
+
return clipRect;
}
-LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
+static LayoutRect paintingExtent(const RenderLayer& currentLayer, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
{
- return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
+ return intersection(transparencyClipBox(currentLayer, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
}
-void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
+void RenderLayer::beginTransparencyLayers(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const LayoutRect& dirtyRect)
{
- if (context->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
+ if (context.paintingDisabled() || (paintsWithTransparency(paintingInfo.paintBehavior) && m_usedTransparency))
return;
-
+
RenderLayer* ancestor = transparentPaintingAncestor();
if (ancestor)
- ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
+ ancestor->beginTransparencyLayers(context, paintingInfo, dirtyRect);
- if (paintsWithTransparency(paintBehavior)) {
+ if (paintsWithTransparency(paintingInfo.paintBehavior)) {
+ ASSERT(isStackingContext());
m_usedTransparency = true;
- context->save();
- LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior);
- context->clip(clipRect);
- context->beginTransparencyLayer(renderer().opacity());
+ context.save();
+ LayoutRect adjustedClipRect = paintingExtent(*this, paintingInfo.rootLayer, dirtyRect, paintingInfo.paintBehavior);
+ adjustedClipRect.move(paintingInfo.subpixelOffset);
+ FloatRect pixelSnappedClipRect = snapRectToDevicePixels(adjustedClipRect, renderer().document().deviceScaleFactor());
+ context.clip(pixelSnappedClipRect);
+
+#if ENABLE(CSS_COMPOSITING)
+ bool usesCompositeOperation = hasBlendMode() && !(renderer().isSVGRoot() && parent() && parent()->isRootLayer());
+ if (usesCompositeOperation)
+ context.setCompositeOperation(context.compositeOperation(), blendMode());
+#endif
+
+ context.beginTransparencyLayer(renderer().opacity());
+
+#if ENABLE(CSS_COMPOSITING)
+ if (usesCompositeOperation)
+ context.setCompositeOperation(context.compositeOperation(), BlendModeNormal);
+#endif
+
#ifdef REVEAL_TRANSPARENCY_LAYERS
- context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
- context->fillRect(clipRect);
+ context.setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f));
+ context.fillRect(pixelSnappedClipRect);
#endif
}
}
@@ -1798,17 +1892,18 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
if (child->renderer().isOutOfFlowPositioned() || child->hasOutOfFlowPositionedDescendant())
setAncestorChainHasOutOfFlowPositionedDescendant(child->renderer().containingBlock());
-#if USE(ACCELERATED_COMPOSITING)
- compositor().layerWasAdded(*this, *child);
+#if ENABLE(CSS_COMPOSITING)
+ if (child->hasBlendMode() || (child->hasNotIsolatedBlendingDescendants() && !child->isolatesBlending()))
+ updateAncestorChainHasBlendingDescendants();
#endif
+
+ compositor().layerWasAdded(*this, *child);
}
RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
{
-#if USE(ACCELERATED_COMPOSITING)
- if (!renderer().documentBeingDestroyed())
+ if (!renderer().renderTreeBeingDestroyed())
compositor().layerWillBeRemoved(*this, *oldChild);
-#endif
// remove the child
if (oldChild->previousSibling())
@@ -1833,9 +1928,9 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
if (oldChild->renderer().isOutOfFlowPositioned() || oldChild->hasOutOfFlowPositionedDescendant())
dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
- oldChild->setPreviousSibling(0);
- oldChild->setNextSibling(0);
- oldChild->setParent(0);
+ oldChild->setPreviousSibling(nullptr);
+ oldChild->setNextSibling(nullptr);
+ oldChild->setParent(nullptr);
oldChild->updateDescendantDependentFlags();
if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
@@ -1844,6 +1939,11 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
if (oldChild->isSelfPaintingLayer() || oldChild->hasSelfPaintingLayerDescendant())
dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
+#if ENABLE(CSS_COMPOSITING)
+ if (oldChild->hasBlendMode() || (oldChild->hasNotIsolatedBlendingDescendants() && !oldChild->isolatesBlending()))
+ dirtyAncestorChainHasBlendingDescendants();
+#endif
+
return oldChild;
}
@@ -1856,9 +1956,7 @@ void RenderLayer::removeOnlyThisLayer()
// walks ignore this layer while we're removing it.
renderer().setHasLayer(false);
-#if USE(ACCELERATED_COMPOSITING)
compositor().layerWillBeRemoved(*m_parent, *this);
-#endif
// Dirty the clip rects.
clearClipRectsIncludingDescendants();
@@ -1879,7 +1977,7 @@ void RenderLayer::removeOnlyThisLayer()
current->setRepaintStatus(NeedsFullRepaint);
// updateLayerPositions depends on hasLayer() already being false for proper layout.
ASSERT(!renderer().hasLayer());
- current->updateLayerPositions(0); // FIXME: use geometry map.
+ current->updateLayerPositions(); // FIXME: use geometry map.
current = next;
}
@@ -1895,15 +1993,13 @@ void RenderLayer::insertOnlyThisLayer()
// Find our enclosingLayer and add ourselves.
RenderLayer* parentLayer = renderer().parent()->enclosingLayer();
ASSERT(parentLayer);
- RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer().parent()->findNextLayer(parentLayer, &renderer()) : 0;
+ RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer().parent()->findNextLayer(parentLayer, &renderer()) : nullptr;
parentLayer->addChild(this, beforeChild);
}
// Remove all descendant layers from the hierarchy and add them to the new position.
- for (RenderObject* curr = renderer().firstChild(); curr; curr = curr->nextSibling()) {
- if (curr->isRenderElement())
- toRenderElement(curr)->moveLayers(m_parent, this);
- }
+ for (auto& child : childrenOfType<RenderElement>(renderer()))
+ child.moveLayers(m_parent, this);
// Clear out all the clip rects.
clearClipRectsIncludingDescendants();
@@ -1911,18 +2007,10 @@ void RenderLayer::insertOnlyThisLayer()
void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& roundedLocation, ColumnOffsetAdjustment adjustForColumns) const
{
- LayoutPoint location = roundedLocation;
- convertToLayerCoords(ancestorLayer, location, adjustForColumns);
+ LayoutPoint location = convertToLayerCoords(ancestorLayer, roundedLocation, adjustForColumns);
roundedLocation = roundedIntPoint(location);
}
-void RenderLayer::convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect& roundedRect, ColumnOffsetAdjustment adjustForColumns) const
-{
- LayoutRect rect = roundedRect;
- convertToLayerCoords(ancestorLayer, rect, adjustForColumns);
- roundedRect = pixelSnappedIntRect(rect);
-}
-
// Returns the layer reached on the walk up towards the ancestor.
static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, LayoutPoint& location, RenderLayer::ColumnOffsetAdjustment adjustForColumns)
{
@@ -1932,9 +2020,9 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
EPosition position = renderer.style().position();
// FIXME: Special casing RenderFlowThread so much for fixed positioning here is not great.
- RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer.flowThreadContainingBlock() : 0;
+ RenderFlowThread* fixedFlowThreadContainer = position == FixedPosition ? renderer.flowThreadContainingBlock() : nullptr;
if (fixedFlowThreadContainer && !fixedFlowThreadContainer->isOutOfFlowPositioned())
- fixedFlowThreadContainer = 0;
+ fixedFlowThreadContainer = nullptr;
// FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in a RenderFlowThread
// may need to be revisited in a future patch.
@@ -1954,15 +2042,15 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
// element in render flow thread, we will hit the fixed positioned container before hitting the ancestor layer.
if (position == FixedPosition && !fixedFlowThreadContainer) {
// For a fixed layers, we need to walk up to the root to see if there's a fixed position container
- // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
+ // (e.g. a transformed layer). It's an error to call offsetFromAncestor() across a layer with a transform,
// so we should always find the ancestor at or before we find the fixed position container.
- RenderLayer* fixedPositionContainerLayer = 0;
+ RenderLayer* fixedPositionContainerLayer = nullptr;
bool foundAncestor = false;
for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = currLayer->parent()) {
if (currLayer == ancestorLayer)
foundAncestor = true;
- if (isFixedPositionedContainer(currLayer)) {
+ if (isContainerForPositioned(*currLayer, FixedPosition)) {
fixedPositionContainerLayer = currLayer;
ASSERT_UNUSED(foundAncestor, foundAncestor);
break;
@@ -1972,12 +2060,8 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
if (fixedPositionContainerLayer != ancestorLayer) {
- LayoutPoint fixedContainerCoords;
- layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContainerCoords);
-
- LayoutPoint ancestorCoords;
- ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorCoords);
-
+ LayoutSize fixedContainerCoords = layer->offsetFromAncestor(fixedPositionContainerLayer);
+ LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(fixedPositionContainerLayer);
location += (fixedContainerCoords - ancestorCoords);
return ancestorLayer;
}
@@ -1986,13 +2070,13 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
if (position == FixedPosition && fixedFlowThreadContainer) {
ASSERT(ancestorLayer);
if (ancestorLayer->isOutOfFlowRenderFlowThread()) {
- location += toSize(layer->location());
+ location += toLayoutSize(layer->location());
return ancestorLayer;
}
if (ancestorLayer == renderer.view().layer()) {
// Add location in flow thread coordinates.
- location += toSize(layer->location());
+ location += toLayoutSize(layer->location());
// Add flow thread offset in view coordinates since the view may be scrolled.
FloatPoint absPos = renderer.view().localToAbsolute(FloatPoint(), IsFixed);
@@ -2003,14 +2087,14 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
RenderLayer* parentLayer;
if (position == AbsolutePosition || position == FixedPosition) {
- // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
+ // Do what enclosingAncestorForPosition() does, but check for ancestorLayer along the way.
parentLayer = layer->parent();
bool foundAncestorFirst = false;
while (parentLayer) {
// RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
// This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
// we are bailing out before reaching root layer.
- if (isPositionedContainer(parentLayer))
+ if (isContainerForPositioned(*parentLayer, position))
break;
if (parentLayer == ancestorLayer) {
@@ -2028,15 +2112,10 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
if (foundAncestorFirst) {
// Found ancestorLayer before the abs. positioned container, so compute offset of both relative
- // to enclosingPositionedAncestor and subtract.
- RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
-
- LayoutPoint thisCoords;
- layer->convertToLayerCoords(positionedAncestor, thisCoords);
-
- LayoutPoint ancestorCoords;
- ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoords);
-
+ // to enclosingAncestorForPosition and subtract.
+ RenderLayer* positionedAncestor = parentLayer->enclosingAncestorForPosition(position);
+ LayoutSize thisCoords = layer->offsetFromAncestor(positionedAncestor);
+ LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(positionedAncestor);
location += (thisCoords - ancestorCoords);
return ancestorLayer;
}
@@ -2044,36 +2123,38 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
parentLayer = layer->parent();
if (!parentLayer)
- return 0;
+ return nullptr;
- location += toSize(layer->location());
+ location += toLayoutSize(layer->location());
if (adjustForColumns == RenderLayer::AdjustForColumns) {
if (RenderLayer* parentLayer = layer->parent()) {
- LayoutSize layerColumnOffset;
- parentLayer->renderer().adjustForColumns(layerColumnOffset, location);
- location += layerColumnOffset;
+ if (is<RenderMultiColumnFlowThread>(parentLayer->renderer())) {
+ RenderRegion* region = downcast<RenderMultiColumnFlowThread>(parentLayer->renderer()).physicalTranslationFromFlowToRegion(location);
+ if (region)
+ location.moveBy(region->topLeftLocation() + -parentLayer->renderBox()->topLeftLocation());
+ }
}
}
return parentLayer;
}
-void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
+LayoutPoint RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, const LayoutPoint& location, ColumnOffsetAdjustment adjustForColumns) const
{
if (ancestorLayer == this)
- return;
+ return location;
const RenderLayer* currLayer = this;
+ LayoutPoint locationInLayerCoords = location;
while (currLayer && currLayer != ancestorLayer)
- currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, location, adjustForColumns);
+ currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, locationInLayerCoords, adjustForColumns);
+ return locationInLayerCoords;
}
-void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutRect& rect, ColumnOffsetAdjustment adjustForColumns) const
+LayoutSize RenderLayer::offsetFromAncestor(const RenderLayer* ancestorLayer, ColumnOffsetAdjustment adjustForColumns) const
{
- LayoutPoint delta;
- convertToLayerCoords(ancestorLayer, delta, adjustForColumns);
- rect.move(-delta.x(), -delta.y());
+ return toLayoutSize(convertToLayerCoords(ancestorLayer, LayoutPoint(), adjustForColumns));
}
#if PLATFORM(IOS)
@@ -2082,36 +2163,36 @@ bool RenderLayer::hasAcceleratedTouchScrolling() const
#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
if (!scrollsOverflow())
return false;
-
- Settings* settings = renderer().document().settings();
-
- // FIXME: settings should not be null at this point. If you find a reliable way to hit this assertion, please file a bug.
- // See <rdar://problem/10266101>.
- ASSERT(settings);
-
- return renderer().style().useTouchOverflowScrolling() || (settings && settings->alwaysUseAcceleratedOverflowScroll());
+ return renderer().style().useTouchOverflowScrolling() || renderer().settings().alwaysUseAcceleratedOverflowScroll();
#else
return false;
#endif
}
-#if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
+bool RenderLayer::hasTouchScrollableOverflow() const
+{
+ return hasAcceleratedTouchScrolling() && (hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
+}
+
+#if ENABLE(TOUCH_EVENTS)
bool RenderLayer::handleTouchEvent(const PlatformTouchEvent& touchEvent)
{
// If we have accelerated scrolling, let the scrolling be handled outside of WebKit.
- if (hasAcceleratedTouchScrolling())
+ if (hasTouchScrollableOverflow())
return false;
return ScrollableArea::handleTouchEvent(touchEvent);
}
#endif
+#endif // PLATFORM(IOS)
+#if ENABLE(IOS_TOUCH_EVENTS)
void RenderLayer::registerAsTouchEventListenerForScrolling()
{
if (!renderer().element() || m_registeredAsTouchEventListenerForScrolling)
return;
- renderer().document().addTouchEventListener(renderer().element());
+ renderer().document().addTouchEventHandler(renderer().element());
m_registeredAsTouchEventListenerForScrolling = true;
}
@@ -2120,18 +2201,21 @@ void RenderLayer::unregisterAsTouchEventListenerForScrolling()
if (!renderer().element() || !m_registeredAsTouchEventListenerForScrolling)
return;
- renderer().document().removeTouchEventListener(renderer().element());
+ renderer().document().removeTouchEventHandler(renderer().element());
m_registeredAsTouchEventListenerForScrolling = false;
}
-#endif // PLATFORM(IOS)
-
-#if USE(ACCELERATED_COMPOSITING)
+#endif // ENABLE(IOS_TOUCH_EVENTS)
bool RenderLayer::usesCompositedScrolling() const
{
return isComposited() && backing()->scrollingLayer();
}
+bool RenderLayer::usesAsyncScrolling() const
+{
+ return hasAcceleratedTouchScrolling() && usesCompositedScrolling();
+}
+
bool RenderLayer::needsCompositedScrolling() const
{
return m_needsCompositedScrolling;
@@ -2155,12 +2239,6 @@ void RenderLayer::updateNeedsCompositedScrolling()
// layers in WebCore, because we use UIKit to composite our scroll bars.
m_needsCompositedScrolling = forceUseCompositedScrolling;
#endif
- // We gather a boolean value for use with Google UMA histograms to
- // quantify the actual effects of a set of patches attempting to
- // relax composited scrolling requirements, thereby increasing the
- // number of composited overflow divs.
- if (acceleratedCompositingForOverflowScrollEnabled())
- HistogramSupport::histogramEnumeration("Renderer.NeedsCompositedScrolling", m_needsCompositedScrolling, 2);
}
if (oldNeedsCompositedScrolling != m_needsCompositedScrolling) {
@@ -2177,8 +2255,6 @@ void RenderLayer::updateNeedsCompositedScrolling()
}
}
-#endif
-
static inline int adjustedScrollDelta(int beginningDelta) {
// This implemention matches Firefox's.
// http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
@@ -2219,6 +2295,7 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
}
+// FIXME: unify with the scrollRectToVisible() code below.
void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp, ScrollableArea** scrolledArea)
{
if (delta.isZero())
@@ -2229,7 +2306,7 @@ void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping
restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
- IntSize newScrollOffset = scrollOffset() + delta;
+ ScrollOffset newScrollOffset = scrollOffset() + delta;
scrollToOffset(newScrollOffset, clamp);
if (scrolledArea)
*scrolledArea = this;
@@ -2254,72 +2331,78 @@ void RenderLayer::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping
}
}
-IntSize RenderLayer::clampScrollOffset(const IntSize& scrollOffset) const
+void RenderLayer::scrollToXPosition(int x, ScrollOffsetClamping clamp)
{
- RenderBox* box = renderBox();
- ASSERT(box);
+ ScrollPosition position(x, m_scrollPosition.y());
+ scrollToOffset(scrollOffsetFromPosition(position), clamp);
+}
- int maxX = scrollWidth() - box->pixelSnappedClientWidth();
- int maxY = scrollHeight() - box->pixelSnappedClientHeight();
+void RenderLayer::scrollToYPosition(int y, ScrollOffsetClamping clamp)
+{
+ ScrollPosition position(m_scrollPosition.x(), y);
+ scrollToOffset(scrollOffsetFromPosition(position), clamp);
+}
- int x = std::max(std::min(scrollOffset.width(), maxX), 0);
- int y = std::max(std::min(scrollOffset.height(), maxY), 0);
- return IntSize(x, y);
+ScrollOffset RenderLayer::clampScrollOffset(const ScrollOffset& scrollOffset) const
+{
+ return scrollOffset.constrainedBetween(IntPoint(), maximumScrollOffset());
}
-void RenderLayer::scrollToOffset(const IntSize& scrollOffset, ScrollOffsetClamping clamp)
+void RenderLayer::scrollToOffset(const ScrollOffset& scrollOffset, ScrollOffsetClamping clamp)
{
- IntSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
+ ScrollOffset newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffset(scrollOffset) : scrollOffset;
if (newScrollOffset != this->scrollOffset())
- scrollToOffsetWithoutAnimation(IntPoint(newScrollOffset));
+ scrollToOffsetWithoutAnimation(newScrollOffset);
}
-void RenderLayer::scrollTo(int x, int y)
+void RenderLayer::scrollTo(const ScrollPosition& position)
{
RenderBox* box = renderBox();
if (!box)
return;
- if (box->style().overflowX() != OMARQUEE) {
+ LOG_WITH_STREAM(Scrolling, stream << "RenderLayer::scrollTo " << position);
+
+ ScrollPosition newPosition = position;
+ if (!box->isHTMLMarquee()) {
// Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
if (m_scrollDimensionsDirty)
computeScrollDimensions();
#if PLATFORM(IOS)
if (adjustForIOSCaretWhenScrolling()) {
- int maxX = scrollWidth() - box->clientWidth();
- if (x > maxX - caretWidth) {
- x += caretWidth;
- if (x <= caretWidth)
- x = 0;
- } else if (x < m_scrollOffset.width() - caretWidth)
- x -= caretWidth;
+ // FIXME: It's not clear what this code is trying to do. Behavior seems reasonable with it removed.
+ int maxOffset = scrollWidth() - roundToInt(box->clientWidth());
+ ScrollOffset newOffset = scrollOffsetFromPosition(newPosition);
+ int scrollXOffset = newOffset.x();
+ if (scrollXOffset > maxOffset - caretWidth) {
+ scrollXOffset += caretWidth;
+ if (scrollXOffset <= caretWidth)
+ scrollXOffset = 0;
+ } else if (scrollXOffset < m_scrollPosition.x() - caretWidth)
+ scrollXOffset -= caretWidth;
+
+ newOffset.setX(scrollXOffset);
+ newPosition = scrollPositionFromOffset(newOffset);
}
#endif
}
- // FIXME: Eventually, we will want to perform a blit. For now never
- // blit, since the check for blitting is going to be very
- // complicated (since it will involve testing whether our layer
- // is either occluded by another layer or clipped by an enclosing
- // layer or contains fixed backgrounds, etc.).
- IntSize newScrollOffset = IntSize(x - scrollOrigin().x(), y - scrollOrigin().y());
- if (m_scrollOffset == newScrollOffset) {
+ if (m_scrollPosition == newPosition) {
#if PLATFORM(IOS)
if (m_requiresScrollBoundsOriginUpdate)
updateCompositingLayersAfterScroll();
#endif
return;
}
- m_scrollOffset = newScrollOffset;
-
- InspectorInstrumentation::willScrollLayer(&renderer().frame());
+
+ ScrollPosition oldPosition = IntPoint(m_scrollPosition);
+ m_scrollPosition = newPosition;
RenderView& view = renderer().view();
// Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
// We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
- bool inLayout = view.frameView().isInLayout();
- if (!inLayout) {
+ if (!view.frameView().isInRenderTreeLayout()) {
// If we're in the middle of layout, we'll just update layers once layout has finished.
updateLayerPositionsAfterOverflowScroll();
// Update regions, scrolling may change the clip of a particular region.
@@ -2339,154 +2422,171 @@ void RenderLayer::scrollTo(int x, int y)
#if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
renderer().document().dirtyTouchEventRects();
#endif
+ DebugPageOverlays::didLayout(renderer().frame());
}
Frame& frame = renderer().frame();
RenderLayerModelObject* repaintContainer = renderer().containerForRepaint();
// The caret rect needs to be invalidated after scrolling
frame.selection().setCaretRectNeedsUpdate();
+
+ LayoutRect rectForRepaint = m_hasComputedRepaintRect ? m_repaintRect : renderer().clippedOverflowRectForRepaint(repaintContainer);
- FloatQuad quadForFakeMouseMoveEvent = FloatQuad(m_repaintRect);
+ FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint);
if (repaintContainer)
quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
frame.eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
bool requiresRepaint = true;
-
-#if USE(ACCELERATED_COMPOSITING)
if (compositor().inCompositingMode() && usesCompositedScrolling())
requiresRepaint = false;
-#endif
// Just schedule a full repaint of our object.
-#if PLATFORM(IOS)
- if (!hasAcceleratedTouchScrolling())
-#else
if (requiresRepaint)
-#endif
- renderer().repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect));
+ renderer().repaintUsingContainer(repaintContainer, rectForRepaint);
- // Schedule the scroll DOM event.
- if (Element* element = renderer().element())
+ // Schedule the scroll and scroll-related DOM events.
+ if (Element* element = renderer().element()) {
element->document().eventQueue().enqueueOrDispatchScrollEvent(*element);
+ element->document().sendWillRevealEdgeEventsIfNeeded(oldPosition, newPosition, visibleContentRect(), contentsSize(), element);
+ }
- InspectorInstrumentation::didScrollLayer(&frame);
if (scrollsOverflow())
- frame.loader().client().didChangeScrollOffset();
+ view.frameView().didChangeScrollOffset();
+
+ view.frameView().viewportContentsChanged();
}
-static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView)
+static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView& frameView)
{
// If scrollbars aren't explicitly forbidden, permit scrolling.
if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
return true;
// If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
- if (frameView->wasScrolledByUser())
+ if (frameView.wasScrolledByUser())
return false;
// Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
// like navigation to an anchor.
- return !frameView->frame().eventHandler().autoscrollInProgress();
+ return !frameView.frame().eventHandler().autoscrollInProgress();
+}
+
+bool RenderLayer::allowsCurrentScroll() const
+{
+ if (!renderer().hasOverflowClip())
+ return false;
+
+ // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
+ // FIXME: Is this still needed? It used to be relevant for Safari RSS.
+ if (renderer().parent() && !renderer().parent()->style().lineClamp().isNone())
+ return false;
+
+ RenderBox* box = renderBox();
+ ASSERT(box); // Only boxes can have overflowClip set.
+
+ if (renderer().frame().eventHandler().autoscrollInProgress()) {
+ // The "programmatically" here is misleading; this asks whether the box has scrollable overflow,
+ // or is a special case like a form control.
+ return box->canBeProgramaticallyScrolled();
+ }
+
+ // Programmatic scrolls can scroll overflow:hidden.
+ return box->hasHorizontalOverflow() || box->hasVerticalOverflow();
}
-void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+void RenderLayer::scrollRectToVisible(SelectionRevealMode revealMode, const LayoutRect& absoluteRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
- RenderLayer* parentLayer = 0;
- LayoutRect newRect = rect;
+ LOG_WITH_STREAM(Scrolling, stream << "Layer " << this << " scrollRectToVisible " << absoluteRect);
+
+ RenderLayer* parentLayer = nullptr;
+ LayoutRect newRect = absoluteRect;
// We may end up propagating a scroll event. It is important that we suspend events until
// the end of the function since they could delete the layer or the layer's renderer().
FrameView& frameView = renderer().view().frameView();
- bool restrictedByLineClamp = false;
- if (renderer().parent()) {
+ if (renderer().parent())
parentLayer = renderer().parent()->enclosingLayer();
- restrictedByLineClamp = !renderer().parent()->style().lineClamp().isNone();
- }
- if (renderer().hasOverflowClip() && !restrictedByLineClamp) {
+ if (allowsCurrentScroll()) {
// Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
// This will prevent us from revealing text hidden by the slider in Safari RSS.
RenderBox* box = renderBox();
ASSERT(box);
- LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox());
+ LayoutRect localExposeRect(box->absoluteToLocalQuad(FloatQuad(FloatRect(absoluteRect))).boundingBox());
LayoutRect layerBounds(0, 0, box->clientWidth(), box->clientHeight());
- LayoutRect r = getRectToExpose(layerBounds, layerBounds, localExposeRect, alignX, alignY);
+ LayoutRect revealRect = getRectToExpose(layerBounds, localExposeRect, insideFixed, alignX, alignY);
- IntSize clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(r).location()));
+ ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset() + toIntSize(roundedIntRect(revealRect).location()));
if (clampedScrollOffset != scrollOffset()) {
- IntSize oldScrollOffset = scrollOffset();
+ ScrollOffset oldScrollOffset = scrollOffset();
scrollToOffset(clampedScrollOffset);
IntSize scrollOffsetDifference = scrollOffset() - oldScrollOffset;
localExposeRect.move(-scrollOffsetDifference);
newRect = LayoutRect(box->localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
}
- } else if (!parentLayer && renderer().isBox() && renderBox()->canBeProgramaticallyScrolled()) {
- Element* ownerElement = renderer().document().ownerElement();
+ } else if (!parentLayer && renderer().isRenderView()) {
+ HTMLFrameOwnerElement* ownerElement = renderer().document().ownerElement();
if (ownerElement && ownerElement->renderer()) {
- HTMLFrameElementBase* frameElementBase = 0;
+ HTMLFrameElementBase* frameElementBase = nullptr;
- if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))
- frameElementBase = toHTMLFrameElementBase(ownerElement);
+ if (is<HTMLFrameElementBase>(*ownerElement))
+ frameElementBase = downcast<HTMLFrameElementBase>(ownerElement);
+
+ if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
+ // If this assertion fires we need to protect the ownerElement from being destroyed.
+ NoEventDispatchAssertion assertNoEventDispatch;
- if (frameElementAndViewPermitScroll(frameElementBase, &frameView)) {
LayoutRect viewRect = frameView.visibleContentRect(LegacyIOSDocumentVisibleRect);
- LayoutRect exposeRect = getRectToExpose(viewRect, viewRect, rect, alignX, alignY);
+ LayoutRect exposeRect = getRectToExpose(viewRect, absoluteRect, insideFixed, alignX, alignY);
- int xOffset = roundToInt(exposeRect.x());
- int yOffset = roundToInt(exposeRect.y());
+ IntPoint scrollOffset(roundedIntPoint(exposeRect.location()));
// Adjust offsets if they're outside of the allowable range.
- xOffset = std::max(0, std::min(frameView.contentsWidth(), xOffset));
- yOffset = std::max(0, std::min(frameView.contentsHeight(), yOffset));
+ scrollOffset = scrollOffset.constrainedBetween(IntPoint(), IntPoint(frameView.contentsSize()));
+ frameView.setScrollPosition(scrollOffset);
- frameView.setScrollPosition(IntPoint(xOffset, yOffset));
if (frameView.safeToPropagateScrollToParent()) {
parentLayer = ownerElement->renderer()->enclosingLayer();
- // FIXME: This doesn't correctly convert the rect to
- // absolute coordinates in the parent.
- newRect.setX(rect.x() - frameView.scrollX() + frameView.x());
- newRect.setY(rect.y() - frameView.scrollY() + frameView.y());
+ // Convert the rect into the coordinate space of the parent frame's document.
+ newRect = frameView.contentsToContainingViewContents(enclosingIntRect(newRect));
+ insideFixed = false; // FIXME: ideally need to determine if this <iframe> is inside position:fixed.
} else
- parentLayer = 0;
+ parentLayer = nullptr;
}
} else {
+ if (revealMode == SelectionRevealMode::RevealUpToMainFrame && frameView.frame().isMainFrame())
+ return;
+
#if !PLATFORM(IOS)
LayoutRect viewRect = frameView.visibleContentRect();
- LayoutRect visibleRectRelativeToDocument = viewRect;
- IntSize scrollOffsetRelativeToDocument = frameView.scrollOffsetRelativeToDocument();
- visibleRectRelativeToDocument.setLocation(IntPoint(scrollOffsetRelativeToDocument.width(), scrollOffsetRelativeToDocument.height()));
#else
- // FIXME: is this equivalent to the code above?
- LayoutRect viewRect = frameView.actualVisibleContentRect();
- LayoutRect visibleRectRelativeToDocument = viewRect;
+ LayoutRect viewRect = frameView.unobscuredContentRect();
#endif
+ // Move the target rect into "scrollView contents" coordinates.
+ LayoutRect targetRect = absoluteRect;
+ targetRect.move(0, frameView.headerHeight());
- LayoutRect r = getRectToExpose(viewRect, visibleRectRelativeToDocument, rect, alignX, alignY);
-
- frameView.setScrollPosition(roundedIntPoint(r.location()));
+ LayoutRect revealRect = getRectToExpose(viewRect, targetRect, insideFixed, alignX, alignY);
+
+ frameView.setScrollPosition(roundedIntPoint(revealRect.location()));
// This is the outermost view of a web page, so after scrolling this view we
// scroll its container by calling Page::scrollRectIntoView.
// This only has an effect on the Mac platform in applications
// that put web views into scrolling containers, such as Mac OS X Mail.
// The canAutoscroll function in EventHandler also knows about this.
- if (Page* page = frameView.frame().page())
- page->chrome().scrollRectIntoView(pixelSnappedIntRect(rect));
+ page().chrome().scrollRectIntoView(snappedIntRect(absoluteRect));
}
}
- if (renderer().frame().eventHandler().autoscrollInProgress())
- parentLayer = enclosingScrollableLayer();
-
if (parentLayer)
- parentLayer->scrollRectToVisible(newRect, alignX, alignY);
+ parentLayer->scrollRectToVisible(revealMode, newRect, insideFixed, alignX, alignY);
}
void RenderLayer::updateCompositingLayersAfterScroll()
{
-#if USE(ACCELERATED_COMPOSITING)
if (compositor().inCompositingMode()) {
// Our stacking container is guaranteed to contain all of our descendants that may need
// repositioning, so update compositing layers from there.
@@ -2497,13 +2597,42 @@ void RenderLayer::updateCompositingLayersAfterScroll()
compositor().updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
}
}
-#endif
}
-LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &visibleRectRelativeToDocument, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
+LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, bool insideFixed, const ScrollAlignment& alignX, const ScrollAlignment& alignY) const
{
+ FrameView& frameView = renderer().view().frameView();
+ if (renderer().isRenderView() && insideFixed) {
+ // If the element is inside position:fixed and we're not scaled, no amount of scrolling is going to move things around.
+ if (frameView.frameScaleFactor() == 1)
+ return visibleRect;
+
+ if (renderer().settings().visualViewportEnabled()) {
+ // exposeRect is in absolute coords, affected by page scale. Unscale it.
+ LayoutRect unscaledExposeRect = exposeRect;
+ unscaledExposeRect.scale(1 / frameView.frameScaleFactor());
+ unscaledExposeRect.move(0, -frameView.headerHeight());
+
+ // These are both in unscaled coordinates.
+ LayoutRect layoutViewport = frameView.layoutViewportRect();
+ LayoutRect visualViewport = frameView.visualViewportRect();
+
+ // The rect to expose may be partially offscreen, which we can't do anything about with position:fixed.
+ unscaledExposeRect.intersect(layoutViewport);
+ // Make sure it's not larger than the visual viewport; if so, we'll just move to the top left.
+ unscaledExposeRect.setSize(unscaledExposeRect.size().shrunkTo(visualViewport.size()));
+
+ // Compute how much we have to move the visualViewport to reveal the part of the layoutViewport that contains exposeRect.
+ LayoutRect requiredVisualViewport = getRectToExpose(visualViewport, unscaledExposeRect, false, alignX, alignY);
+ // Scale it back up.
+ requiredVisualViewport.scale(frameView.frameScaleFactor());
+ requiredVisualViewport.move(0, frameView.headerHeight());
+ return requiredVisualViewport;
+ }
+ }
+
// Determine the appropriate X behavior.
- ScrollBehavior scrollX;
+ ScrollAlignment::Behavior scrollX;
LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width();
if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
@@ -2514,8 +2643,8 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const Lay
else if (intersectWidth == visibleRect.width()) {
// If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
scrollX = ScrollAlignment::getVisibleBehavior(alignX);
- if (scrollX == alignCenter)
- scrollX = noScroll;
+ if (scrollX == ScrollAlignment::Behavior::AlignCenter)
+ scrollX = ScrollAlignment::Behavior::NoScroll;
} else if (intersectWidth > 0)
// If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
scrollX = ScrollAlignment::getPartialBehavior(alignX);
@@ -2523,32 +2652,32 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const Lay
scrollX = ScrollAlignment::getHiddenBehavior(alignX);
// If we're trying to align to the closest edge, and the exposeRect is further right
// than the visibleRect, and not bigger than the visible area, then align with the right.
- if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
- scrollX = alignRight;
+ if (scrollX == ScrollAlignment::Behavior::AlignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
+ scrollX = ScrollAlignment::Behavior::AlignRight;
// Given the X behavior, compute the X coordinate.
LayoutUnit x;
- if (scrollX == noScroll)
+ if (scrollX == ScrollAlignment::Behavior::NoScroll)
x = visibleRect.x();
- else if (scrollX == alignRight)
+ else if (scrollX == ScrollAlignment::Behavior::AlignRight)
x = exposeRect.maxX() - visibleRect.width();
- else if (scrollX == alignCenter)
+ else if (scrollX == ScrollAlignment::Behavior::AlignCenter)
x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
else
x = exposeRect.x();
// Determine the appropriate Y behavior.
- ScrollBehavior scrollY;
+ ScrollAlignment::Behavior scrollY;
LayoutRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
- LayoutUnit intersectHeight = intersection(visibleRectRelativeToDocument, exposeRectY).height();
+ LayoutUnit intersectHeight = intersection(visibleRect, exposeRectY).height();
if (intersectHeight == exposeRect.height())
// If the rectangle is fully visible, use the specified visible behavior.
scrollY = ScrollAlignment::getVisibleBehavior(alignY);
else if (intersectHeight == visibleRect.height()) {
// If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
scrollY = ScrollAlignment::getVisibleBehavior(alignY);
- if (scrollY == alignCenter)
- scrollY = noScroll;
+ if (scrollY == ScrollAlignment::Behavior::AlignCenter)
+ scrollY = ScrollAlignment::Behavior::NoScroll;
} else if (intersectHeight > 0)
// If the rectangle is partially visible, use the specified partial behavior
scrollY = ScrollAlignment::getPartialBehavior(alignY);
@@ -2556,16 +2685,16 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const Lay
scrollY = ScrollAlignment::getHiddenBehavior(alignY);
// If we're trying to align to the closest edge, and the exposeRect is further down
// than the visibleRect, and not bigger than the visible area, then align with the bottom.
- if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
- scrollY = alignBottom;
+ if (scrollY == ScrollAlignment::Behavior::AlignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
+ scrollY = ScrollAlignment::Behavior::AlignBottom;
// Given the Y behavior, compute the Y coordinate.
LayoutUnit y;
- if (scrollY == noScroll)
+ if (scrollY == ScrollAlignment::Behavior::NoScroll)
y = visibleRect.y();
- else if (scrollY == alignBottom)
+ else if (scrollY == ScrollAlignment::Behavior::AlignBottom)
y = exposeRect.maxY() - visibleRect.height();
- else if (scrollY == alignCenter)
+ else if (scrollY == ScrollAlignment::Behavior::AlignCenter)
y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
else
y = exposeRect.y();
@@ -2576,7 +2705,7 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const Lay
void RenderLayer::autoscroll(const IntPoint& position)
{
IntPoint currentDocumentPosition = renderer().view().frameView().windowToContents(position);
- scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
+ scrollRectToVisible(SelectionRevealMode::Reveal, LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
}
bool RenderLayer::canResize() const
@@ -2596,7 +2725,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOff
// FIXME: The only case where renderer->element()->renderer() != renderer is with continuations. Do they matter here?
// If they do it would still be better to deal with them explicitly.
Element* element = renderer().element();
- RenderBox* renderer = toRenderBox(element->renderer());
+ auto* renderer = downcast<RenderBox>(element->renderer());
Document& document = element->document();
if (!document.frame()->eventHandler().mousePressed())
@@ -2613,35 +2742,35 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOff
element->setMinimumSizeForResizing(minimumSize);
LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
- if (renderer->style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
+ if (shouldPlaceBlockDirectionScrollbarOnLeft()) {
newOffset.setWidth(-newOffset.width());
adjustedOldOffset.setWidth(-adjustedOldOffset.width());
}
LayoutSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
- StyledElement* styledElement = toStyledElement(element);
+ StyledElement* styledElement = downcast<StyledElement>(element);
bool isBoxSizingBorder = renderer->style().boxSizing() == BORDER_BOX;
EResize resize = renderer->style().resize();
if (resize != RESIZE_VERTICAL && difference.width()) {
- if (element->isFormControlElement()) {
+ if (is<HTMLFormControlElement>(*element)) {
// Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, renderer->marginLeft() / zoomFactor, CSSPrimitiveValue::CSS_PX);
styledElement->setInlineStyleProperty(CSSPropertyMarginRight, renderer->marginRight() / zoomFactor, CSSPrimitiveValue::CSS_PX);
}
- LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->borderAndPaddingWidth());
+ LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? LayoutUnit() : renderer->horizontalBorderAndPaddingExtent());
baseWidth = baseWidth / zoomFactor;
styledElement->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth + difference.width()), CSSPrimitiveValue::CSS_PX);
}
if (resize != RESIZE_HORIZONTAL && difference.height()) {
- if (element->isFormControlElement()) {
+ if (is<HTMLFormControlElement>(*element)) {
// Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
styledElement->setInlineStyleProperty(CSSPropertyMarginTop, renderer->marginTop() / zoomFactor, CSSPrimitiveValue::CSS_PX);
styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, renderer->marginBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX);
}
- LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->borderAndPaddingHeight());
+ LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? LayoutUnit() : renderer->verticalBorderAndPaddingExtent());
baseHeight = baseHeight / zoomFactor;
styledElement->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight + difference.height()), CSSPrimitiveValue::CSS_PX);
}
@@ -2657,117 +2786,113 @@ int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
}
-void RenderLayer::setScrollOffset(const IntPoint& offset)
+void RenderLayer::setScrollOffset(const ScrollOffset& offset)
{
- scrollTo(offset.x(), offset.y());
+ scrollTo(scrollPositionFromOffset(offset));
}
-int RenderLayer::scrollPosition(Scrollbar* scrollbar) const
+int RenderLayer::scrollOffset(ScrollbarOrientation orientation) const
{
- if (scrollbar->orientation() == HorizontalScrollbar)
- return scrollXOffset();
- if (scrollbar->orientation() == VerticalScrollbar)
- return scrollYOffset();
- return 0;
-}
+ if (orientation == HorizontalScrollbar)
+ return scrollOffset().x();
-IntPoint RenderLayer::scrollPosition() const
-{
- return IntPoint(m_scrollOffset);
-}
+ if (orientation == VerticalScrollbar)
+ return scrollOffset().y();
-IntPoint RenderLayer::minimumScrollPosition() const
-{
- return -scrollOrigin();
-}
-
-IntPoint RenderLayer::maximumScrollPosition() const
-{
- // FIXME: m_scrollSize may not be up-to-date if m_scrollDimensionsDirty is true.
- return -scrollOrigin() + roundedIntSize(m_scrollSize) - visibleContentRectIncludingScrollbars(ContentsVisibleRect).size();
+ return 0;
}
IntRect RenderLayer::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior) const
{
- int verticalScrollbarWidth = 0;
- int horizontalScrollbarHeight = 0;
- if (scrollbarInclusion == IncludeScrollbars) {
- verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) ? verticalScrollbar()->width() : 0;
- horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0;
-
-#if PLATFORM(IOS)
- if (hasAcceleratedTouchScrolling()) {
- verticalScrollbarWidth = 0;
- horizontalScrollbarHeight = 0;
- }
-#endif
- }
+ IntSize scrollbarSpace;
+ if (showsOverflowControls() && scrollbarInclusion == IncludeScrollbars)
+ scrollbarSpace = scrollbarIntrusion();
- return IntRect(IntPoint(scrollXOffset(), scrollYOffset()),
- IntSize(std::max(0, m_layerSize.width() - verticalScrollbarWidth),
- std::max(0, m_layerSize.height() - horizontalScrollbarHeight)));
+ // FIXME: This seems wrong: m_layerSize includes borders. Can we just use the ScrollableArea implementation?
+ return IntRect(scrollPosition(), IntSize(std::max(0, m_layerSize.width() - scrollbarSpace.width()), std::max(0, m_layerSize.height() - scrollbarSpace.height())));
}
IntSize RenderLayer::overhangAmount() const
{
+#if ENABLE(RUBBER_BANDING)
+ if (!renderer().settings().rubberBandingForSubScrollableRegionsEnabled())
+ return IntSize();
+
+ IntSize stretch;
+
+ // FIXME: use maximumScrollOffset(), or just move this to ScrollableArea.
+ ScrollOffset scrollOffset = scrollOffsetFromPosition(scrollPosition());
+ if (scrollOffset.y() < 0)
+ stretch.setHeight(scrollOffset.y());
+ else if (scrollableContentsSize().height() && scrollOffset.y() > scrollableContentsSize().height() - visibleHeight())
+ stretch.setHeight(scrollOffset.y() - (scrollableContentsSize().height() - visibleHeight()));
+
+ if (scrollOffset.x() < 0)
+ stretch.setWidth(scrollOffset.x());
+ else if (scrollableContentsSize().width() && scrollOffset.x() > scrollableContentsSize().width() - visibleWidth())
+ stretch.setWidth(scrollOffset.x() - (scrollableContentsSize().width() - visibleWidth()));
+
+ return stretch;
+#else
return IntSize();
+#endif
}
bool RenderLayer::isActive() const
{
- Page* page = renderer().frame().page();
- return page && page->focusController().isActive();
+ return page().focusController().isActive();
}
-static int cornerStart(const RenderLayer* layer, int minX, int maxX, int thickness)
+static int cornerStart(const RenderLayer& layer, int minX, int maxX, int thickness)
{
- if (layer->renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
- return minX + layer->renderer().style().borderLeftWidth();
- return maxX - thickness - layer->renderer().style().borderRightWidth();
+ if (layer.shouldPlaceBlockDirectionScrollbarOnLeft())
+ return minX + layer.renderer().style().borderLeftWidth();
+ return maxX - thickness - layer.renderer().style().borderRightWidth();
}
-static LayoutRect cornerRect(const RenderLayer* layer, const LayoutRect& bounds)
+static LayoutRect cornerRect(const RenderLayer& layer, const LayoutRect& bounds)
{
int horizontalThickness;
int verticalThickness;
- if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
+ if (!layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
// FIXME: This isn't right. We need to know the thickness of custom scrollbars
// even when they don't exist in order to set the resizer square size properly.
- horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness();
+ horizontalThickness = ScrollbarTheme::theme().scrollbarThickness();
verticalThickness = horizontalThickness;
- } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
- horizontalThickness = layer->verticalScrollbar()->width();
+ } else if (layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
+ horizontalThickness = layer.verticalScrollbar()->width();
verticalThickness = horizontalThickness;
- } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
- verticalThickness = layer->horizontalScrollbar()->height();
+ } else if (layer.horizontalScrollbar() && !layer.verticalScrollbar()) {
+ verticalThickness = layer.horizontalScrollbar()->height();
horizontalThickness = verticalThickness;
} else {
- horizontalThickness = layer->verticalScrollbar()->width();
- verticalThickness = layer->horizontalScrollbar()->height();
+ horizontalThickness = layer.verticalScrollbar()->width();
+ verticalThickness = layer.horizontalScrollbar()->height();
}
return LayoutRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
- bounds.maxY() - verticalThickness - layer->renderer().style().borderBottomWidth(),
+ bounds.maxY() - verticalThickness - layer.renderer().style().borderBottomWidth(),
horizontalThickness, verticalThickness);
}
IntRect RenderLayer::scrollCornerRect() const
{
- // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
+ // We have a scrollbar corner when a non overlay scrollbar is visible and not filling the entire length of the box.
// This happens when:
- // (a) A resizer is present and at least one scrollbar is present
- // (b) Both scrollbars are present.
- bool hasHorizontalBar = horizontalScrollbar();
- bool hasVerticalBar = verticalScrollbar();
+ // (a) A resizer is present and at least one non overlay scrollbar is present
+ // (b) Both non overlay scrollbars are present.
+ // Overlay scrollbars always fill the entire length of the box so we never have scroll corner in that case.
+ bool hasHorizontalBar = m_hBar && !m_hBar->isOverlayScrollbar();
+ bool hasVerticalBar = m_vBar && !m_vBar->isOverlayScrollbar();
bool hasResizer = renderer().style().resize() != RESIZE_NONE;
if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
- return pixelSnappedIntRect(cornerRect(this, renderBox()->borderBoxRect()));
+ return snappedIntRect(cornerRect(*this, renderBox()->borderBoxRect()));
return IntRect();
}
-static LayoutRect resizerCornerRect(const RenderLayer* layer, const LayoutRect& bounds)
+static LayoutRect resizerCornerRect(const RenderLayer& layer, const LayoutRect& bounds)
{
- ASSERT(layer->renderer().isBox());
- if (layer->renderer().style().resize() == RESIZE_NONE)
+ ASSERT(layer.renderer().isBox());
+ if (layer.renderer().style().resize() == RESIZE_NONE)
return LayoutRect();
return cornerRect(layer, bounds);
}
@@ -2776,10 +2901,10 @@ LayoutRect RenderLayer::scrollCornerAndResizerRect() const
{
RenderBox* box = renderBox();
if (!box)
- return IntRect();
+ return LayoutRect();
LayoutRect scrollCornerAndResizer = scrollCornerRect();
if (scrollCornerAndResizer.isEmpty())
- scrollCornerAndResizer = resizerCornerRect(this, box->borderBoxRect());
+ scrollCornerAndResizer = resizerCornerRect(*this, box->borderBoxRect());
return scrollCornerAndResizer;
}
@@ -2789,40 +2914,73 @@ bool RenderLayer::isScrollCornerVisible() const
return !scrollCornerRect().isEmpty();
}
-IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
+IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
{
IntRect rect = scrollbarRect;
rect.move(scrollbarOffset(scrollbar));
- return renderer().view().frameView().convertFromRenderer(&renderer(), rect);
+ return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), rect);
}
-IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
{
- IntRect rect = renderer().view().frameView().convertToRenderer(&renderer(), parentRect);
+ IntRect rect = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentRect);
rect.move(-scrollbarOffset(scrollbar));
return rect;
}
-IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
+IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
{
IntPoint point = scrollbarPoint;
point.move(scrollbarOffset(scrollbar));
- return renderer().view().frameView().convertFromRenderer(&renderer(), point);
+ return renderer().view().frameView().convertFromRendererToContainingView(&renderer(), point);
}
-IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
{
- IntPoint point = renderer().view().frameView().convertToRenderer(&renderer(), parentPoint);
+ IntPoint point = renderer().view().frameView().convertFromContainingViewToRenderer(&renderer(), parentPoint);
point.move(-scrollbarOffset(scrollbar));
return point;
}
+IntSize RenderLayer::visibleSize() const
+{
+ RenderBox* box = renderBox();
+ if (!box)
+ return IntSize();
+
+ return IntSize(roundToInt(box->clientWidth()), roundToInt(box->clientHeight()));
+}
+
IntSize RenderLayer::contentsSize() const
{
return IntSize(scrollWidth(), scrollHeight());
}
+IntSize RenderLayer::scrollableContentsSize() const
+{
+ IntSize contentsSize = this->contentsSize();
+
+ if (!hasScrollableHorizontalOverflow())
+ contentsSize.setWidth(std::min(contentsSize.width(), visibleSize().width()));
+
+ if (!hasScrollableVerticalOverflow())
+ contentsSize.setHeight(std::min(contentsSize.height(), visibleSize().height()));
+
+ return contentsSize;
+}
+
+void RenderLayer::availableContentSizeChanged(AvailableSizeChangeReason reason)
+{
+ ScrollableArea::availableContentSizeChanged(reason);
+
+ if (reason == AvailableSizeChangeReason::ScrollbarsChanged) {
+ if (is<RenderBlock>(renderer()))
+ downcast<RenderBlock>(renderer()).setShouldForceRelayoutChildren(true);
+ renderer().setNeedsLayout();
+ }
+}
+
bool RenderLayer::shouldSuspendScrollAnimations() const
{
return renderer().view().frameView().shouldSuspendScrollAnimations();
@@ -2831,21 +2989,18 @@ bool RenderLayer::shouldSuspendScrollAnimations() const
#if PLATFORM(IOS)
void RenderLayer::didStartScroll()
{
- if (Page* page = renderer().frame().page())
- page->chrome().client().didStartOverflowScroll();
+ page().chrome().client().didStartOverflowScroll();
}
void RenderLayer::didEndScroll()
{
- if (Page* page = renderer().frame().page())
- page->chrome().client().didEndOverflowScroll();
+ page().chrome().client().didEndOverflowScroll();
}
void RenderLayer::didUpdateScroll()
{
// Send this notification when we scroll, since this is how we keep selection updated.
- if (Page* page = renderer().frame().page())
- page->chrome().client().didLayout(ChromeClient::Scroll);
+ page().chrome().client().didLayout(ChromeClient::Scroll);
}
#endif
@@ -2890,7 +3045,7 @@ IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) cons
LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
{
const RenderBox* box = renderBox();
- if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
+ if (shouldPlaceBlockDirectionScrollbarOnLeft())
return minX + box->borderLeft();
return maxX - box->borderRight() - m_vBar->width();
}
@@ -2899,35 +3054,31 @@ LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
{
const RenderBox* box = renderBox();
int x = minX + box->borderLeft();
- if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
- x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(this, box->borderBoxRect()).width());
+ if (shouldPlaceBlockDirectionScrollbarOnLeft())
+ x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(*this, box->borderBoxRect()).width());
return x;
}
-IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
+IntSize RenderLayer::scrollbarOffset(const Scrollbar& scrollbar) const
{
RenderBox* box = renderBox();
- if (scrollbar == m_vBar.get())
+ if (&scrollbar == m_vBar.get())
return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
- if (scrollbar == m_hBar.get())
- return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
+ if (&scrollbar == m_hBar.get())
+ return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
ASSERT_NOT_REACHED();
return IntSize();
}
-void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
+void RenderLayer::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
{
-#if PLATFORM(IOS)
- // No need to invalidate scrollbars if we're using accelerated scrolling.
- if (hasAcceleratedTouchScrolling())
+ if (!showsOverflowControls())
return;
-#endif
-#if USE(ACCELERATED_COMPOSITING)
- if (scrollbar == m_vBar.get()) {
+ if (&scrollbar == m_vBar.get()) {
if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
layer->setNeedsDisplayInRect(rect);
return;
@@ -2938,7 +3089,7 @@ void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& r
return;
}
}
-#endif
+
IntRect scrollRect = rect;
RenderBox* box = renderBox();
ASSERT(box);
@@ -2946,10 +3097,10 @@ void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& r
if (!box->parent())
return;
- if (scrollbar == m_vBar.get())
+ if (&scrollbar == m_vBar.get())
scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
else
- scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar->height());
+ scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
LayoutRect repaintRect = scrollRect;
renderBox()->flipForWritingMode(repaintRect);
renderer().repaintRectangle(repaintRect);
@@ -2957,18 +3108,14 @@ void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& r
void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
{
-#if PLATFORM(IOS)
- // No need to invalidate the scroll corner if we're using accelerated scrolling.
- if (hasAcceleratedTouchScrolling())
+ if (!showsOverflowControls())
return;
-#endif
-#if USE(ACCELERATED_COMPOSITING)
if (GraphicsLayer* layer = layerForScrollCorner()) {
layer->setNeedsDisplayInRect(rect);
return;
}
-#endif
+
if (m_scrollCorner)
m_scrollCorner->repaintRectangle(rect);
if (m_resizer)
@@ -2979,27 +3126,30 @@ static inline RenderElement* rendererForScrollbar(RenderLayerModelObject& render
{
if (Element* element = renderer.element()) {
if (ShadowRoot* shadowRoot = element->containingShadowRoot()) {
- if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot)
- return shadowRoot->hostElement()->renderer();
+ if (shadowRoot->mode() == ShadowRootMode::UserAgent)
+ return shadowRoot->host()->renderer();
}
}
return &renderer;
}
-PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
+Ref<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
{
RefPtr<Scrollbar> widget;
- RenderElement* actualRenderer = rendererForScrollbar(renderer());
- bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style().hasPseudoStyle(SCROLLBAR);
+ ASSERT(rendererForScrollbar(renderer()));
+ auto& actualRenderer = *rendererForScrollbar(renderer());
+ bool hasCustomScrollbarStyle = is<RenderBox>(actualRenderer) && downcast<RenderBox>(actualRenderer).style().hasPseudoStyle(SCROLLBAR);
if (hasCustomScrollbarStyle)
- widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->element());
+ widget = RenderScrollbar::createCustomScrollbar(*this, orientation, downcast<RenderBox>(actualRenderer).element());
else {
- widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
+ widget = Scrollbar::createNativeScrollbar(*this, orientation, RegularScrollbar);
didAddScrollbar(widget.get(), orientation);
+ if (page().expectsWheelEventTriggers())
+ scrollAnimator().setWheelEventTestTrigger(page().testTrigger());
}
- renderer().view().frameView().addChild(widget.get());
- return widget.release();
+ renderer().view().frameView().addChild(*widget);
+ return widget.releaseNonNull();
}
void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
@@ -3012,16 +3162,15 @@ void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
willRemoveScrollbar(scrollbar.get(), orientation);
scrollbar->removeFromParent();
- scrollbar->disconnectFromScrollableArea();
- scrollbar = 0;
+ scrollbar = nullptr;
}
bool RenderLayer::scrollsOverflow() const
{
- if (!renderer().isBox())
+ if (!is<RenderBox>(renderer()))
return false;
- return toRenderBox(renderer()).scrollsOverflow();
+ return downcast<RenderBox>(renderer()).scrollsOverflow();
}
void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
@@ -3029,10 +3178,18 @@ void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
if (hasScrollbar == hasHorizontalScrollbar())
return;
- if (hasScrollbar)
+ if (hasScrollbar) {
m_hBar = createScrollbar(HorizontalScrollbar);
- else
+#if ENABLE(RUBBER_BANDING)
+ ScrollElasticity elasticity = scrollsOverflow() && renderer().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
+ ScrollableArea::setHorizontalScrollElasticity(elasticity);
+#endif
+ } else {
destroyScrollbar(HorizontalScrollbar);
+#if ENABLE(RUBBER_BANDING)
+ ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityNone);
+#endif
+ }
// Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
if (m_hBar)
@@ -3052,10 +3209,18 @@ void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
if (hasScrollbar == hasVerticalScrollbar())
return;
- if (hasScrollbar)
+ if (hasScrollbar) {
m_vBar = createScrollbar(VerticalScrollbar);
- else
+#if ENABLE(RUBBER_BANDING)
+ ScrollElasticity elasticity = scrollsOverflow() && renderer().settings().rubberBandingForSubScrollableRegionsEnabled() ? ScrollElasticityAutomatic : ScrollElasticityNone;
+ ScrollableArea::setVerticalScrollElasticity(elasticity);
+#endif
+ } else {
destroyScrollbar(VerticalScrollbar);
+#if ENABLE(RUBBER_BANDING)
+ ScrollableArea::setVerticalScrollElasticity(ScrollElasticityNone);
+#endif
+ }
// Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
if (m_hBar)
@@ -3077,31 +3242,73 @@ ScrollableArea* RenderLayer::enclosingScrollableArea() const
// FIXME: We should return the frame view here (or possibly an ancestor frame view,
// if the frame view isn't scrollable.
- return 0;
+ return nullptr;
}
-int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
+bool RenderLayer::isScrollableOrRubberbandable()
{
- if (!m_vBar || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
- return 0;
+ return renderer().isScrollableOrRubberbandableBox();
+}
-#if PLATFORM(IOS)
- if (hasAcceleratedTouchScrolling())
- return 0;
+bool RenderLayer::hasScrollableOrRubberbandableAncestor()
+{
+ for (RenderLayer* nextLayer = parentLayerCrossFrame(*this); nextLayer; nextLayer = parentLayerCrossFrame(*nextLayer)) {
+ if (nextLayer->isScrollableOrRubberbandable())
+ return true;
+ }
+
+ return false;
+}
+
+#if ENABLE(CSS_SCROLL_SNAP)
+void RenderLayer::updateSnapOffsets()
+{
+ // FIXME: Extend support beyond HTMLElements.
+ if (!is<HTMLElement>(enclosingElement()) || !enclosingElement()->renderBox())
+ return;
+
+ RenderBox* box = enclosingElement()->renderBox();
+ updateSnapOffsetsForScrollableArea(*this, *downcast<HTMLElement>(enclosingElement()), *box, box->style());
+}
+
+bool RenderLayer::isScrollSnapInProgress() const
+{
+ if (!scrollsOverflow())
+ return false;
+
+ if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
+ return scrollAnimator->isScrollSnapInProgress();
+
+ return false;
+}
#endif
- return m_vBar->width();
+bool RenderLayer::usesMockScrollAnimator() const
+{
+ return Settings::usesMockScrollAnimator();
}
-int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
+void RenderLayer::logMockScrollAnimatorMessage(const String& message) const
+{
+ renderer().document().addConsoleMessage(MessageSource::Other, MessageLevel::Debug, "RenderLayer: " + message);
+}
+
+int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
{
- if (!m_hBar || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
+ if (!m_vBar
+ || !showsOverflowControls()
+ || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_vBar->shouldParticipateInHitTesting())))
return 0;
-#if PLATFORM(IOS)
- if (hasAcceleratedTouchScrolling())
+ return m_vBar->width();
+}
+
+int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
+{
+ if (!m_hBar
+ || !showsOverflowControls()
+ || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayScrollbarSize || !m_hBar->shouldParticipateInHitTesting())))
return 0;
-#endif
return m_hBar->height();
}
@@ -3111,7 +3318,7 @@ IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
// Currently the resize corner is either the bottom right corner or the bottom left corner.
// FIXME: This assumes the location is 0, 0. Is this guaranteed to always be the case?
IntSize elementSize = size();
- if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
+ if (shouldPlaceBlockDirectionScrollbarOnLeft())
elementSize.setWidth(0);
IntPoint resizerPoint = IntPoint(elementSize);
IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
@@ -3132,7 +3339,7 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
if (!box)
return;
- const IntRect borderBox = box->pixelSnappedBorderBoxRect();
+ const IntRect borderBox = snappedIntRect(box->borderBoxRect());
const IntRect& scrollCorner = scrollCornerRect();
IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
if (m_vBar) {
@@ -3150,12 +3357,10 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot)
if (m_scrollCorner)
m_scrollCorner->setFrameRect(scrollCorner);
if (m_resizer)
- m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
+ m_resizer->setFrameRect(resizerCornerRect(*this, borderBox));
-#if USE(ACCELERATED_COMPOSITING)
if (isComposited())
backing()->positionOverflowControlsLayers();
-#endif
}
int RenderLayer::scrollWidth() const
@@ -3163,7 +3368,8 @@ int RenderLayer::scrollWidth() const
ASSERT(renderBox());
if (m_scrollDimensionsDirty)
const_cast<RenderLayer*>(this)->computeScrollDimensions();
- return snapSizeToPixel(m_scrollSize.width(), renderBox()->clientLeft() + renderBox()->x());
+ // FIXME: This should use snappedIntSize() instead with absolute coordinates.
+ return m_scrollSize.width();
}
int RenderLayer::scrollHeight() const
@@ -3171,7 +3377,8 @@ int RenderLayer::scrollHeight() const
ASSERT(renderBox());
if (m_scrollDimensionsDirty)
const_cast<RenderLayer*>(this)->computeScrollDimensions();
- return snapSizeToPixel(m_scrollSize.height(), renderBox()->clientTop() + renderBox()->y());
+ // FIXME: This should use snappedIntSize() instead with absolute coordinates.
+ return m_scrollSize.height();
}
LayoutUnit RenderLayer::overflowTop() const
@@ -3213,11 +3420,13 @@ void RenderLayer::computeScrollDimensions()
m_scrollDimensionsDirty = false;
- m_scrollSize.setWidth(overflowRight() - overflowLeft());
- m_scrollSize.setHeight(overflowBottom() - overflowTop());
+ m_scrollSize.setWidth(roundToInt(overflowRight() - overflowLeft()));
+ m_scrollSize.setHeight(roundToInt(overflowBottom() - overflowTop()));
- int scrollableLeftOverflow = overflowLeft() - box->borderLeft();
- int scrollableTopOverflow = overflowTop() - box->borderTop();
+ int scrollableLeftOverflow = roundToInt(overflowLeft() - box->borderLeft());
+ if (shouldPlaceBlockDirectionScrollbarOnLeft())
+ scrollableLeftOverflow -= verticalScrollbarWidth();
+ int scrollableTopOverflow = roundToInt(overflowTop() - box->borderTop());
setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow));
}
@@ -3235,14 +3444,28 @@ bool RenderLayer::hasHorizontalOverflow() const
{
ASSERT(!m_scrollDimensionsDirty);
- return scrollWidth() > renderBox()->pixelSnappedClientWidth();
+ return scrollWidth() > roundToInt(renderBox()->clientWidth());
}
bool RenderLayer::hasVerticalOverflow() const
{
ASSERT(!m_scrollDimensionsDirty);
- return scrollHeight() > renderBox()->pixelSnappedClientHeight();
+ return scrollHeight() > roundToInt(renderBox()->clientHeight());
+}
+
+static bool styleRequiresScrollbar(const RenderStyle& style, ScrollbarOrientation axis)
+{
+ EOverflow overflow = axis == ScrollbarOrientation::HorizontalScrollbar ? style.overflowX() : style.overflowY();
+ bool overflowScrollActsLikeAuto = overflow == OSCROLL && !style.hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme().usesOverlayScrollbars();
+ return overflow == OSCROLL && !overflowScrollActsLikeAuto;
+}
+
+static bool styleDefinesAutomaticScrollbar(const RenderStyle& style, ScrollbarOrientation axis)
+{
+ EOverflow overflow = axis == ScrollbarOrientation::HorizontalScrollbar ? style.overflowX() : style.overflowY();
+ bool overflowScrollActsLikeAuto = overflow == OSCROLL && !style.hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme().usesOverlayScrollbars();
+ return overflow == OAUTO || overflow == OOVERLAY || overflowScrollActsLikeAuto;
}
void RenderLayer::updateScrollbarsAfterLayout()
@@ -3257,20 +3480,20 @@ void RenderLayer::updateScrollbarsAfterLayout()
bool hasHorizontalOverflow = this->hasHorizontalOverflow();
bool hasVerticalOverflow = this->hasVerticalOverflow();
- // overflow:scroll should just enable/disable.
- if (renderer().style().overflowX() == OSCROLL)
+ // If overflow requires a scrollbar, then we just need to enable or disable.
+ if (m_hBar && styleRequiresScrollbar(renderer().style(), HorizontalScrollbar))
m_hBar->setEnabled(hasHorizontalOverflow);
- if (renderer().style().overflowY() == OSCROLL)
+ if (m_vBar && styleRequiresScrollbar(renderer().style(), VerticalScrollbar))
m_vBar->setEnabled(hasVerticalOverflow);
- // overflow:auto may need to lay out again if scrollbars got added/removed.
- bool autoHorizontalScrollBarChanged = box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
- bool autoVerticalScrollBarChanged = box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
+ // Scrollbars with auto behavior may need to lay out again if scrollbars got added or removed.
+ bool autoHorizontalScrollBarChanged = box->hasHorizontalScrollbarWithAutoBehavior() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
+ bool autoVerticalScrollBarChanged = box->hasVerticalScrollbarWithAutoBehavior() && (hasVerticalScrollbar() != hasVerticalOverflow);
if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
- if (box->hasAutoHorizontalScrollbar())
+ if (box->hasHorizontalScrollbarWithAutoBehavior())
setHasHorizontalScrollbar(hasHorizontalOverflow);
- if (box->hasAutoVerticalScrollbar())
+ if (box->hasVerticalScrollbarWithAutoBehavior())
setHasVerticalScrollbar(hasVerticalOverflow);
updateSelfPaintingLayer();
@@ -3288,8 +3511,8 @@ void RenderLayer::updateScrollbarsAfterLayout()
// Our proprietary overflow: overlay value doesn't trigger a layout.
m_inOverflowRelayout = true;
renderer().setNeedsLayout(MarkOnlyThis);
- if (renderer().isRenderBlock()) {
- RenderBlock& block = toRenderBlock(renderer());
+ if (is<RenderBlock>(renderer())) {
+ RenderBlock& block = downcast<RenderBlock>(renderer());
block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
block.layoutBlock(true);
} else
@@ -3301,14 +3524,14 @@ void RenderLayer::updateScrollbarsAfterLayout()
// Set up the range (and page step/line step).
if (m_hBar) {
- int clientWidth = box->pixelSnappedClientWidth();
- int pageStep = std::max(std::max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
+ int clientWidth = roundToInt(box->clientWidth());
+ int pageStep = Scrollbar::pageStep(clientWidth);
m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_hBar->setProportion(clientWidth, m_scrollSize.width());
}
if (m_vBar) {
- int clientHeight = box->pixelSnappedClientHeight();
- int pageStep = std::max(std::max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
+ int clientHeight = roundToInt(box->clientHeight());
+ int pageStep = Scrollbar::pageStep(clientHeight);
m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_vBar->setProportion(clientHeight, m_scrollSize.height());
}
@@ -3323,14 +3546,20 @@ void RenderLayer::updateScrollInfoAfterLayout()
return;
m_scrollDimensionsDirty = true;
- IntSize originalScrollOffset = scrollOffset();
+ ScrollOffset originalScrollOffset = scrollOffset();
computeScrollDimensions();
- if (box->style().overflowX() != OMARQUEE) {
+#if ENABLE(CSS_SCROLL_SNAP)
+ // FIXME: Ensure that offsets are also updated in case of programmatic style changes.
+ // https://bugs.webkit.org/show_bug.cgi?id=135964
+ updateSnapOffsets();
+#endif
+
+ if (!box->isHTMLMarquee() && !isRubberBandInProgress()) {
// Layout may cause us to be at an invalid scroll position. In this case we need
// to pull our scroll offsets back to the max (or push them up to the min).
- IntSize clampedScrollOffset = clampScrollOffset(scrollOffset());
+ ScrollOffset clampedScrollOffset = clampScrollOffset(scrollOffset());
#if PLATFORM(IOS)
// FIXME: This looks wrong. The caret adjust mode should only be enabled on editing related entry points.
// This code was added to fix an issue where the text insertion point would always be drawn on the right edge
@@ -3350,16 +3579,16 @@ void RenderLayer::updateScrollInfoAfterLayout()
if (originalScrollOffset != scrollOffset())
scrollToOffsetWithoutAnimation(IntPoint(scrollOffset()));
-#if USE(ACCELERATED_COMPOSITING)
// Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
if (compositor().updateLayerCompositingState(*this))
compositor().setCompositingLayersNeedRebuild();
-#endif
+
+ updateScrollSnapState();
}
bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
{
- const IntRect borderBox = renderBox()->pixelSnappedBorderBoxRect();
+ const IntRect borderBox = snappedIntRect(renderBox()->borderBoxRect());
if (rectForHorizontalScrollbar(borderBox).intersects(localRect))
return true;
@@ -3370,23 +3599,31 @@ bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
if (scrollCornerRect().intersects(localRect))
return true;
- if (resizerCornerRect(this, borderBox).intersects(localRect))
+ if (resizerCornerRect(*this, borderBox).intersects(localRect))
return true;
return false;
}
-void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
+bool RenderLayer::showsOverflowControls() const
+{
+#if PLATFORM(IOS)
+ // Don't render (custom) scrollbars if we have accelerated scrolling.
+ if (hasAcceleratedTouchScrolling())
+ return false;
+#endif
+
+ return true;
+}
+
+void RenderLayer::paintOverflowControls(GraphicsContext& context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
{
// Don't do anything if we have no overflow.
if (!renderer().hasOverflowClip())
return;
-#if PLATFORM(IOS)
- // Don't render (custom) scrollbars if we have accelerated scrolling.
- if (hasAcceleratedTouchScrolling())
+ if (!showsOverflowControls())
return;
-#endif
// Overlay scrollbars paint in a second pass through the layer tree so that they will paint
// on top of everything else. If this is the normal painting pass, paintingOverlayControls
@@ -3396,20 +3633,16 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint
// second pass doesn't need to re-enter the RenderTree to get it right.
if (hasOverlayScrollbars() && !paintingOverlayControls) {
m_cachedOverlayScrollbarOffset = paintOffset;
-#if USE(ACCELERATED_COMPOSITING)
+
// It's not necessary to do the second pass if the scrollbars paint into layers.
if ((m_hBar && layerForHorizontalScrollbar()) || (m_vBar && layerForVerticalScrollbar()))
return;
-#endif
IntRect localDamgeRect = damageRect;
localDamgeRect.moveBy(-paintOffset);
if (!overflowControlsIntersectRect(localDamgeRect))
return;
- RenderLayer* paintingRoot = 0;
-#if USE(ACCELERATED_COMPOSITING)
- paintingRoot = enclosingCompositingLayer();
-#endif
+ RenderLayer* paintingRoot = enclosingCompositingLayer();
if (!paintingRoot)
paintingRoot = renderer().view().layer();
@@ -3431,23 +3664,13 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint
positionOverflowControls(toIntSize(adjustedPaintOffset));
// Now that we're sure the scrollbars are in the right place, paint them.
- if (m_hBar
-#if USE(ACCELERATED_COMPOSITING)
- && !layerForHorizontalScrollbar()
-#endif
- )
+ if (m_hBar && !layerForHorizontalScrollbar())
m_hBar->paint(context, damageRect);
- if (m_vBar
-#if USE(ACCELERATED_COMPOSITING)
- && !layerForVerticalScrollbar()
-#endif
- )
+ if (m_vBar && !layerForVerticalScrollbar())
m_vBar->paint(context, damageRect);
-#if USE(ACCELERATED_COMPOSITING)
if (layerForScrollCorner())
return;
-#endif
// We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
// edge of the box.
@@ -3457,17 +3680,14 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint
paintResizer(context, adjustedPaintOffset, damageRect);
}
-void RenderLayer::paintScrollCorner(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect)
+void RenderLayer::paintScrollCorner(GraphicsContext& context, const IntPoint& paintOffset, const IntRect& damageRect)
{
- RenderBox* box = renderBox();
- ASSERT(box);
-
IntRect absRect = scrollCornerRect();
absRect.moveBy(paintOffset);
if (!absRect.intersects(damageRect))
return;
- if (context->updatingControlTints()) {
+ if (context.updatingControlTints()) {
updateScrollCornerStyle();
return;
}
@@ -3480,39 +3700,41 @@ void RenderLayer::paintScrollCorner(GraphicsContext* context, const IntPoint& pa
// We don't want to paint white if we have overlay scrollbars, since we need
// to see what is behind it.
if (!hasOverlayScrollbars())
- context->fillRect(absRect, Color::white, box->style().colorSpace());
+ context.fillRect(absRect, Color::white);
}
-void RenderLayer::drawPlatformResizerImage(GraphicsContext* context, const LayoutRect& resizerCornerRect)
+void RenderLayer::drawPlatformResizerImage(GraphicsContext& context, const LayoutRect& resizerCornerRect)
{
- float deviceScaleFactor = WebCore::deviceScaleFactor(&renderer().frame());
-
RefPtr<Image> resizeCornerImage;
- IntSize cornerResizerSize;
- if (deviceScaleFactor >= 2) {
- DEFINE_STATIC_LOCAL(Image*, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x").leakRef()));
+ FloatSize cornerResizerSize;
+ if (renderer().document().deviceScaleFactor() >= 2) {
+ static NeverDestroyed<Image*> resizeCornerImageHiRes(Image::loadPlatformResource("textAreaResizeCorner@2x").leakRef());
resizeCornerImage = resizeCornerImageHiRes;
cornerResizerSize = resizeCornerImage->size();
cornerResizerSize.scale(0.5f);
} else {
- DEFINE_STATIC_LOCAL(Image*, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner").leakRef()));
+ static NeverDestroyed<Image*> resizeCornerImageLoRes(Image::loadPlatformResource("textAreaResizeCorner").leakRef());
resizeCornerImage = resizeCornerImageLoRes;
cornerResizerSize = resizeCornerImage->size();
}
- if (renderer().style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
- context->save();
- context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height());
- context->scale(FloatSize(-1.0, 1.0));
- context->drawImage(resizeCornerImage.get(), renderer().style().colorSpace(), IntRect(IntPoint(), cornerResizerSize));
- context->restore();
+ if (shouldPlaceBlockDirectionScrollbarOnLeft()) {
+ context.save();
+ context.translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height());
+ context.scale(FloatSize(-1.0, 1.0));
+ if (resizeCornerImage)
+ context.drawImage(*resizeCornerImage, FloatRect(FloatPoint(), cornerResizerSize));
+ context.restore();
return;
}
- LayoutRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize);
- context->drawImage(resizeCornerImage.get(), renderer().style().colorSpace(), pixelSnappedIntRect(imageRect));
+
+ if (!resizeCornerImage)
+ return;
+ FloatRect imageRect = snapRectToDevicePixels(LayoutRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize), renderer().document().deviceScaleFactor());
+ context.drawImage(*resizeCornerImage, imageRect);
}
-void RenderLayer::paintResizer(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& damageRect)
+void RenderLayer::paintResizer(GraphicsContext& context, const LayoutPoint& paintOffset, const LayoutRect& damageRect)
{
if (renderer().style().resize() == RESIZE_NONE)
return;
@@ -3520,12 +3742,12 @@ void RenderLayer::paintResizer(GraphicsContext* context, const LayoutPoint& pain
RenderBox* box = renderBox();
ASSERT(box);
- LayoutRect absRect = resizerCornerRect(this, box->borderBoxRect());
+ LayoutRect absRect = resizerCornerRect(*this, box->borderBoxRect());
absRect.moveBy(paintOffset);
if (!absRect.intersects(damageRect))
return;
- if (context->updatingControlTints()) {
+ if (context.updatingControlTints()) {
updateResizerStyle();
return;
}
@@ -3540,14 +3762,14 @@ void RenderLayer::paintResizer(GraphicsContext* context, const LayoutPoint& pain
// Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
// Clipping will exclude the right and bottom edges of this frame.
if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) {
- GraphicsContextStateSaver stateSaver(*context);
- context->clip(absRect);
+ GraphicsContextStateSaver stateSaver(context);
+ context.clip(absRect);
LayoutRect largerCorner = absRect;
largerCorner.setSize(LayoutSize(largerCorner.width() + LayoutUnit::fromPixel(1), largerCorner.height() + LayoutUnit::fromPixel(1)));
- context->setStrokeColor(Color(makeRGB(217, 217, 217)), ColorSpaceDeviceRGB);
- context->setStrokeThickness(1.0f);
- context->setFillColor(Color::transparent, ColorSpaceDeviceRGB);
- context->drawRect(pixelSnappedIntRect(largerCorner));
+ context.setStrokeColor(Color(makeRGB(217, 217, 217)));
+ context.setStrokeThickness(1.0f);
+ context.setFillColor(Color::transparent);
+ context.drawRect(snappedIntRect(largerCorner));
}
}
@@ -3561,8 +3783,8 @@ bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
- IntRect localBounds(0, 0, box->pixelSnappedWidth(), box->pixelSnappedHeight());
- return resizerCornerRect(this, localBounds).contains(localPoint);
+ IntRect localBounds(IntPoint(), snappedIntRect(box->frameRect()).size());
+ return resizerCornerRect(*this, localBounds).contains(localPoint);
}
bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
@@ -3575,7 +3797,7 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint&
IntRect resizeControlRect;
if (renderer().style().resize() != RESIZE_NONE) {
- resizeControlRect = pixelSnappedIntRect(resizerCornerRect(this, box->borderBoxRect()));
+ resizeControlRect = snappedIntRect(resizerCornerRect(*this, box->borderBoxRect()));
if (resizeControlRect.contains(localPoint))
return true;
}
@@ -3615,19 +3837,18 @@ bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularit
return ScrollableArea::scroll(direction, granularity, multiplier);
}
-void RenderLayer::paint(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot, RenderRegion* region, PaintLayerFlags paintFlags)
+void RenderLayer::paint(GraphicsContext& context, const LayoutRect& damageRect, const LayoutSize& subpixelOffset, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot, PaintLayerFlags paintFlags, SecurityOriginPaintPolicy paintPolicy)
{
OverlapTestRequestMap overlapTestRequests;
- LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, LayoutSize(), subtreePaintRoot, region, &overlapTestRequests);
+ LayerPaintingInfo paintingInfo(this, enclosingIntRect(damageRect), paintBehavior, subpixelOffset, subtreePaintRoot, &overlapTestRequests, paintPolicy == SecurityOriginPaintPolicy::AccessibleOriginOnly);
paintLayer(context, paintingInfo, paintFlags);
- OverlapTestRequestMap::iterator end = overlapTestRequests.end();
- for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
- it->key->setOverlapTestResult(false);
+ for (auto& widget : overlapTestRequests.keys())
+ widget->setOverlapTestResult(false);
}
-void RenderLayer::paintOverlayScrollbars(GraphicsContext* context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot)
+void RenderLayer::paintOverlayScrollbars(GraphicsContext& context, const LayoutRect& damageRect, PaintBehavior paintBehavior, RenderObject* subtreePaintRoot)
{
if (!m_containsDirtyOverlayScrollbars)
return;
@@ -3642,9 +3863,7 @@ static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLaye
{
if (startLayer == endLayer)
return true;
-
- RenderView* view = &startLayer->renderer().view();
- for (RenderBlock* currentBlock = startLayer->renderer().containingBlock(); currentBlock && currentBlock != view; currentBlock = currentBlock->containingBlock()) {
+ for (const auto* currentBlock = startLayer->renderer().containingBlock(); currentBlock && !is<RenderView>(*currentBlock); currentBlock = currentBlock->containingBlock()) {
if (currentBlock->layer() == endLayer)
return true;
}
@@ -3652,96 +3871,93 @@ static bool inContainingBlockChain(RenderLayer* startLayer, RenderLayer* endLaye
return false;
}
-void RenderLayer::clipToRect(RenderLayer* rootLayer, GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect,
- BorderRadiusClippingRule rule)
+void RenderLayer::clipToRect(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const ClipRect& clipRect, BorderRadiusClippingRule rule)
{
- if (clipRect.rect() != paintDirtyRect) {
- context->save();
- context->clip(pixelSnappedIntRect(clipRect.rect()));
- }
+ float deviceScaleFactor = renderer().document().deviceScaleFactor();
+ bool needsClipping = !clipRect.isInfinite() && clipRect.rect() != paintingInfo.paintDirtyRect;
+ if (needsClipping || clipRect.affectedByRadius())
+ context.save();
- if (!clipRect.hasRadius())
- return;
+ if (needsClipping) {
+ LayoutRect adjustedClipRect = clipRect.rect();
+ adjustedClipRect.move(paintingInfo.subpixelOffset);
+ context.clip(snapRectToDevicePixels(adjustedClipRect, deviceScaleFactor));
+ }
- // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
- // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
- // containing block chain so we check that also.
- for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
- if (layer->renderer().hasOverflowClip() && layer->renderer().style().hasBorderRadius() && inContainingBlockChain(this, layer)) {
- LayoutPoint delta;
- layer->convertToLayerCoords(rootLayer, delta);
- context->clipRoundedRect(layer->renderer().style().getRoundedInnerBorderFor(LayoutRect(delta, layer->size())));
+ if (clipRect.affectedByRadius()) {
+ // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
+ // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
+ // containing block chain so we check that also.
+ for (RenderLayer* layer = rule == IncludeSelfForBorderRadius ? this : parent(); layer; layer = layer->parent()) {
+ if (layer->renderer().hasOverflowClip() && layer->renderer().style().hasBorderRadius() && inContainingBlockChain(this, layer)) {
+ LayoutRect adjustedClipRect = LayoutRect(toLayoutPoint(layer->offsetFromAncestor(paintingInfo.rootLayer, AdjustForColumns)), layer->size());
+ adjustedClipRect.move(paintingInfo.subpixelOffset);
+ FloatRoundedRect roundedRect = layer->renderer().style().getRoundedInnerBorderFor(adjustedClipRect).pixelSnappedRoundedRectForPainting(deviceScaleFactor);
+ if (roundedRect.intersectionIsRectangular(paintingInfo.paintDirtyRect))
+ context.clip(snapRectToDevicePixels(intersection(paintingInfo.paintDirtyRect, adjustedClipRect), deviceScaleFactor));
+ else
+ context.clipRoundedRect(roundedRect);
+ }
+
+ if (layer == paintingInfo.rootLayer)
+ break;
}
-
- if (layer == rootLayer)
- break;
}
}
-void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintDirtyRect, const ClipRect& clipRect)
+void RenderLayer::restoreClip(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const ClipRect& clipRect)
{
- if (clipRect.rect() == paintDirtyRect)
- return;
- context->restore();
+ if ((!clipRect.isInfinite() && clipRect.rect() != paintingInfo.paintDirtyRect) || clipRect.affectedByRadius())
+ context.restore();
}
static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
{
Vector<OverlapTestRequestClient*> overlappedRequestClients;
- OverlapTestRequestMap::iterator end = overlapTestRequests.end();
- LayoutRect boundingBox = layer->boundingBox(rootLayer);
- for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) {
- if (!boundingBox.intersects(it->value))
+ LayoutRect boundingBox = layer->boundingBox(rootLayer, layer->offsetFromAncestor(rootLayer));
+ for (auto& request : overlapTestRequests) {
+ if (!boundingBox.intersects(request.value))
continue;
- it->key->setOverlapTestResult(true);
- overlappedRequestClients.append(it->key);
+ request.key->setOverlapTestResult(true);
+ overlappedRequestClients.append(request.key);
}
- for (size_t i = 0; i < overlappedRequestClients.size(); ++i)
- overlapTestRequests.remove(overlappedRequestClients[i]);
+ for (auto* client : overlappedRequestClients)
+ overlapTestRequests.remove(client);
}
-#if USE(ACCELERATED_COMPOSITING)
-
static inline bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
{
return paintingReflection && !layer->has3DTransform();
}
-
-#endif
static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
{
// Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC.
// It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
// will do a full repaint().
- if (layer->renderer().document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer().isRoot())
+ if (layer->renderer().document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer().isDocumentElementRenderer())
return true;
// Avoid painting all layers if the document is in a state where visual updates aren't allowed.
- // A full repaint will occur in Document::implicitClose() if painting is suppressed here.
+ // A full repaint will occur in Document::setVisualUpdatesAllowed(bool) if painting is suppressed here.
if (!layer->renderer().document().visualUpdatesAllowed())
return true;
return false;
}
-#if USE(ACCELERATED_COMPOSITING)
-
static inline bool paintForFixedRootBackground(const RenderLayer* layer, RenderLayer::PaintLayerFlags paintFlags)
{
- return layer->renderer().isRoot() && (paintFlags & RenderLayer::PaintLayerPaintingRootBackgroundOnly);
+ return layer->renderer().isDocumentElementRenderer() && (paintFlags & RenderLayer::PaintLayerPaintingRootBackgroundOnly);
}
-#endif
-
-void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+void RenderLayer::paintLayer(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
-#if USE(ACCELERATED_COMPOSITING)
if (isComposited()) {
// The updatingControlTints() painting pass goes through compositing layers,
// but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
- if (context->updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers))
+ if (context.updatingControlTints() || (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers))
paintFlags |= PaintLayerTemporaryClipRects;
else if (!backing()->paintsIntoWindow()
&& !backing()->paintsIntoCompositedAncestor()
@@ -3756,7 +3972,6 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo&
ASSERT(renderer().style().position() == FixedPosition);
return;
}
-#endif
// Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself.
if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
@@ -3771,20 +3986,11 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo&
// Don't paint the layer if the renderer doesn't belong to this region.
// This is true as long as we clamp the range of a box to its containing block range.
-
- // FIXME: Hack to disable region information for in flow threads. Implement this logic in a different way.
- LayerPaintingInfo& info = const_cast<LayerPaintingInfo&>(paintingInfo);
- RenderRegion* region = info.region;
- if (region) {
- if (enclosingPaginationLayer())
- info.region = 0;
- else {
- RenderFlowThread* flowThread = region->flowThread();
- ASSERT(flowThread);
-
- if (!flowThread->objectShouldPaintInFlowRegion(&renderer(), region))
- return;
- }
+ RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment();
+ if (namedFlowFragment) {
+ ASSERT(namedFlowFragment->isValid());
+ if (!namedFlowFragment->flowThread()->objectShouldFragmentInFlowRegion(&renderer(), namedFlowFragment))
+ return;
}
if (paintsWithTransparency(paintingInfo.paintBehavior))
@@ -3794,53 +4000,48 @@ void RenderLayer::paintLayer(GraphicsContext* context, const LayerPaintingInfo&
if (paintsWithTransform(paintingInfo.paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
TransformationMatrix layerTransform = renderableTransform(paintingInfo.paintBehavior);
// If the transform can't be inverted, then don't paint anything.
- if (!layerTransform.isInvertible()) {
- info.region = region;
+ if (!layerTransform.isInvertible())
return;
- }
// If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
// layer from the parent now, assuming there is a parent
if (paintFlags & PaintLayerHaveTransparency) {
if (parent())
- parent()->beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
+ parent()->beginTransparencyLayers(context, paintingInfo, paintingInfo.paintDirtyRect);
else
- beginTransparencyLayers(context, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, paintingInfo.paintBehavior);
+ beginTransparencyLayers(context, paintingInfo, paintingInfo.paintDirtyRect);
}
- if (enclosingPaginationLayer()) {
+ if (enclosingPaginationLayer(ExcludeCompositedPaginatedLayers)) {
paintTransformedLayerIntoFragments(context, paintingInfo, paintFlags);
- info.region = region;
return;
}
// Make sure the parent's clip rects have been calculated.
ClipRect clipRect = paintingInfo.paintDirtyRect;
if (parent()) {
- ClipRectsContext clipRectsContext(paintingInfo.rootLayer, paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
+ ClipRectsContext clipRectsContext(paintingInfo.rootLayer, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
clipRect = backgroundClipRect(clipRectsContext);
clipRect.intersect(paintingInfo.paintDirtyRect);
// Push the parent coordinate space's clip.
- parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect);
+ parent()->clipToRect(context, paintingInfo, clipRect);
}
paintLayerByApplyingTransform(context, paintingInfo, paintFlags);
// Restore the clip.
if (parent())
- parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
+ parent()->restoreClip(context, paintingInfo, clipRect);
- info.region = region;
return;
}
paintLayerContentsAndReflection(context, paintingInfo, paintFlags);
- info.region = region;
}
-void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+void RenderLayer::paintLayerContentsAndReflection(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
@@ -3858,160 +4059,202 @@ void RenderLayer::paintLayerContentsAndReflection(GraphicsContext* context, cons
paintLayerContents(context, paintingInfo, localPaintFlags);
}
-bool RenderLayer::setupFontSubpixelQuantization(GraphicsContext* context, bool& didQuantizeFonts)
+bool RenderLayer::setupFontSubpixelQuantization(GraphicsContext& context, bool& didQuantizeFonts)
{
- if (context->paintingDisabled())
+ if (context.paintingDisabled())
return false;
bool scrollingOnMainThread = true;
#if ENABLE(ASYNC_SCROLLING)
- if (Page* page = renderer().frame().page()) {
- if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
- scrollingOnMainThread = scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously();
- }
+ if (ScrollingCoordinator* scrollingCoordinator = page().scrollingCoordinator())
+ scrollingOnMainThread = scrollingCoordinator->shouldUpdateScrollLayerPositionSynchronously(renderer().view().frameView());
#endif
// FIXME: We shouldn't have to disable subpixel quantization for overflow clips or subframes once we scroll those
// things on the scrolling thread.
bool contentsScrollByPainting = (renderer().hasOverflowClip() && !usesCompositedScrolling()) || (renderer().frame().ownerElement());
- if (scrollingOnMainThread || contentsScrollByPainting) {
- didQuantizeFonts = context->shouldSubpixelQuantizeFonts();
- context->setShouldSubpixelQuantizeFonts(false);
+ bool isZooming = !page().chrome().client().hasStablePageScaleFactor();
+ if (scrollingOnMainThread || contentsScrollByPainting || isZooming) {
+ didQuantizeFonts = context.shouldSubpixelQuantizeFonts();
+ context.setShouldSubpixelQuantizeFonts(false);
return true;
}
return false;
}
-bool RenderLayer::setupClipPath(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, const LayoutPoint& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed)
+template <class ReferenceBoxClipPathOperation>
+static inline LayoutRect computeReferenceBox(const RenderObject& renderer, const ReferenceBoxClipPathOperation& clippingPath, const LayoutSize& offsetFromRoot, const LayoutRect& rootRelativeBounds)
+{
+ // FIXME: Support different reference boxes for inline content.
+ // https://bugs.webkit.org/show_bug.cgi?id=129047
+ if (!renderer.isBox())
+ return rootRelativeBounds;
+
+ LayoutRect referenceBox;
+ const auto& box = downcast<RenderBox>(renderer);
+ switch (clippingPath.referenceBox()) {
+ case ContentBox:
+ referenceBox = box.contentBoxRect();
+ referenceBox.move(offsetFromRoot);
+ break;
+ case PaddingBox:
+ referenceBox = box.paddingBoxRect();
+ referenceBox.move(offsetFromRoot);
+ break;
+ // FIXME: Support margin-box. Use bounding client rect for now.
+ // https://bugs.webkit.org/show_bug.cgi?id=127984
+ case MarginBox:
+ // fill, stroke, view-box compute to border-box for HTML elements.
+ case Fill:
+ case Stroke:
+ case ViewBox:
+ case BorderBox:
+ case BoxMissing:
+ referenceBox = box.borderBoxRect();
+ referenceBox.move(offsetFromRoot);
+ break;
+ }
+
+ return referenceBox;
+}
+
+Path RenderLayer::computeClipPath(const LayoutSize& offsetFromRoot, LayoutRect& rootRelativeBounds, WindRule& windRule) const
{
- if (!renderer().hasClipPath() || context->paintingDisabled())
- return false;
+ const RenderStyle& style = renderer().style();
+ float deviceSaleFactor = renderer().document().deviceScaleFactor();
- RenderStyle& style = renderer().style();
- ASSERT(style.clipPath());
- if (style.clipPath()->type() == ClipPathOperation::Shape) {
- ShapeClipPathOperation& clippingPath = toShapeClipPathOperation(*(style.clipPath()));
+ if (is<ShapeClipPathOperation>(*style.clipPath())) {
+ auto& clipPath = downcast<ShapeClipPathOperation>(*style.clipPath());
+ FloatRect referenceBox = snapRectToDevicePixels(computeReferenceBox(renderer(), clipPath, offsetFromRoot, rootRelativeBounds), deviceSaleFactor);
- if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
- rootRelativeBoundsComputed = true;
- }
+ windRule = clipPath.windRule();
+ return clipPath.pathForReferenceRect(referenceBox);
+ }
+
+ if (is<BoxClipPathOperation>(*style.clipPath()) && is<RenderBox>(renderer())) {
- LayoutRect referenceBox;
- if (renderer().isBox()) {
- RenderBox& box = toRenderBox(renderer());
- switch (clippingPath.referenceBox()) {
- case ContentBox:
- referenceBox = box.contentBoxRect();
- referenceBox.moveBy(rootRelativeBounds.location());
- break;
- case PaddingBox:
- referenceBox = box.paddingBoxRect();
- referenceBox.moveBy(rootRelativeBounds.location());
- break;
- case BorderBox:
- referenceBox = box.borderBoxRect();
- referenceBox.moveBy(rootRelativeBounds.location());
- break;
- case MarginBox:
- // FIXME: Support margin-box. Use bounding client rect for now.
- case BoundingBox:
- case BoxMissing:
- // FIXME: If no reference box was specified the spec demands to use
- // the border-box. However, the current prefixed version of clip-path uses
- // bounding-box. Keep bounding-box for now.
- referenceBox = rootRelativeBounds;
- }
- } else
- // FIXME: Support different reference boxes for inline content.
- referenceBox = rootRelativeBounds;
+ auto& clipPath = downcast<BoxClipPathOperation>(*style.clipPath());
+
+ FloatRoundedRect shapeRect = computeRoundedRectForBoxShape(clipPath.referenceBox(), downcast<RenderBox>(renderer())).pixelSnappedRoundedRectForPainting(deviceSaleFactor);
+ shapeRect.move(offsetFromRoot);
+
+ windRule = RULE_NONZERO;
+ return clipPath.pathForReferenceRect(shapeRect);
+ }
+
+ return Path();
+}
- context->save();
- context->clipPath(clippingPath.pathForReferenceRect(referenceBox), clippingPath.windRule());
+bool RenderLayer::setupClipPath(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, const LayoutSize& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed)
+{
+ if (!renderer().hasClipPath() || context.paintingDisabled())
+ return false;
+
+ if (!rootRelativeBoundsComputed) {
+ rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, offsetFromRoot, 0);
+ rootRelativeBoundsComputed = true;
+ }
+
+ auto& style = renderer().style();
+ ASSERT(style.clipPath());
+ if (is<ShapeClipPathOperation>(*style.clipPath()) || (is<BoxClipPathOperation>(*style.clipPath()) && is<RenderBox>(renderer()))) {
+ WindRule windRule;
+ LayoutSize paintingOffsetFromRoot = LayoutSize(snapSizeToDevicePixel(offsetFromRoot + paintingInfo.subpixelOffset, LayoutPoint(), renderer().document().deviceScaleFactor()));
+ Path path = computeClipPath(paintingOffsetFromRoot, rootRelativeBounds, windRule);
+ context.save();
+ context.clipPath(path, windRule);
return true;
}
-#if ENABLE(SVG)
if (style.clipPath()->type() == ClipPathOperation::Reference) {
ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style.clipPath());
Element* element = renderer().document().getElementById(referenceClipPathOperation->fragment());
if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) {
- if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
- rootRelativeBoundsComputed = true;
- }
-
- // FIXME: This should use a safer cast such as toRenderSVGResourceContainer().
- // FIXME: Should this do a context->save() and return true so we restore the context?
- static_cast<RenderSVGResourceClipper*>(element->renderer())->applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context);
+ context.save();
+ downcast<RenderSVGResourceClipper>(*element->renderer()).applyClippingToContext(renderer(), rootRelativeBounds, paintingInfo.paintDirtyRect, context);
+ return true;
}
}
-#endif
return false;
}
-#if ENABLE(CSS_FILTERS)
-
-PassOwnPtr<FilterEffectRendererHelper> RenderLayer::setupFilters(GraphicsContext* context, LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed)
+std::pair<RenderLayer::FilterInfo*, std::unique_ptr<FilterEffectRendererHelper>> RenderLayer::filterPainter(GraphicsContext& context, PaintLayerFlags paintFlags) const
{
- if (context->paintingDisabled())
- return nullptr;
+ if (context.paintingDisabled())
+ return { };
if (paintFlags & PaintLayerPaintingOverlayScrollbars)
- return nullptr;
+ return { };
- FilterInfo* filterInfo = FilterInfo::getIfExists(*this);
- bool hasPaintedFilter = filterInfo && filterInfo->renderer() && paintsWithFilters();
- if (!hasPaintedFilter)
- return nullptr;
+ if (!paintsWithFilters())
+ return { };
- OwnPtr<FilterEffectRendererHelper> filterPainter = adoptPtr(new FilterEffectRendererHelper(hasPaintedFilter));
- if (!filterPainter->haveFilterEffect())
+ auto* info = FilterInfo::getIfExists(*this);
+ if (!info || !info->renderer())
+ return { };
+
+ auto helper = std::make_unique<FilterEffectRendererHelper>(true, context);
+ if (!helper->haveFilterEffect())
+ return { };
+
+ return { info, WTFMove(helper) };
+}
+
+bool RenderLayer::hasFilterThatIsPainting(GraphicsContext& context, PaintLayerFlags paintFlags) const
+{
+ return !!filterPainter(context, paintFlags).first;
+}
+
+std::unique_ptr<FilterEffectRendererHelper> RenderLayer::setupFilters(GraphicsContext& context, LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutSize& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed)
+{
+ auto painter = filterPainter(context, paintFlags);
+ if (!painter.first)
return nullptr;
-
- LayoutRect filterRepaintRect = filterInfo->dirtySourceRect();
- filterRepaintRect.move(offsetFromRoot.x(), offsetFromRoot.y());
+
+ auto& filterInfo = *painter.first;
+ auto& filterPainter = *painter.second;
+
+ LayoutRect filterRepaintRect = filterInfo.dirtySourceRect();
+ filterRepaintRect.move(offsetFromRoot);
if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
+ rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, offsetFromRoot, 0);
rootRelativeBoundsComputed = true;
}
- if (filterPainter->prepareFilterEffect(this, rootRelativeBounds, paintingInfo.paintDirtyRect, filterRepaintRect)) {
- // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero.
- filterInfo->resetDirtySourceRect();
+ if (!filterPainter.prepareFilterEffect(*this, enclosingIntRect(rootRelativeBounds), enclosingIntRect(paintingInfo.paintDirtyRect), enclosingIntRect(filterRepaintRect)))
+ return nullptr;
- if (!filterPainter->beginFilterEffect())
- return nullptr;
+ // Now we know for sure that the source image will be updated, so we can revert our tracking repaint rect back to zero.
+ filterInfo.resetDirtySourceRect();
- // Check that we didn't fail to allocate the graphics context for the offscreen buffer.
- ASSERT(filterPainter->hasStartedFilterEffect());
+ if (!filterPainter.beginFilterEffect())
+ return nullptr;
- paintingInfo.paintDirtyRect = filterPainter->repaintRect();
- // If the filter needs the full source image, we need to avoid using the clip rectangles.
- // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
- // Note that we will still apply the clipping on the final rendering of the filter.
- paintingInfo.clipToDirtyRect = !filterInfo->renderer()->hasFilterThatMovesPixels();
- return filterPainter.release();
- }
- return nullptr;
+ paintingInfo.paintDirtyRect = filterPainter.repaintRect();
+
+ // If the filter needs the full source image, we need to avoid using the clip rectangles.
+ // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly.
+ // Note that we will still apply the clipping on the final rendering of the filter.
+ paintingInfo.clipToDirtyRect = !filterInfo.renderer()->hasFilterThatMovesPixels();
+
+ paintingInfo.requireSecurityOriginAccessForWidgets = filterInfo.renderer()->hasFilterThatShouldBeRestrictedBySecurityOrigin();
+
+ return WTFMove(painter.second);
}
-GraphicsContext* RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext* originalContext, LayerPaintingInfo& paintingInfo, LayerFragments& layerFragments)
+void RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext& originalContext, const LayerPaintingInfo& paintingInfo, const LayerFragments& layerFragments)
{
ASSERT(filterPainter->hasStartedFilterEffect());
- // Apply the correct clipping (ie. overflow: hidden).
- // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
+
+ // FIXME: Handle more than one fragment.
ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
- clipToRect(paintingInfo.rootLayer, originalContext, paintingInfo.paintDirtyRect, backgroundRect);
+ clipToRect(originalContext, paintingInfo, backgroundRect);
filterPainter->applyFilterEffect(originalContext);
- restoreClip(originalContext, paintingInfo.paintDirtyRect, backgroundRect);
- return originalContext;
+ restoreClip(originalContext, paintingInfo, backgroundRect);
}
-#endif
-
// Helper for the sorting of layers by z-index.
static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
{
@@ -4022,7 +4265,7 @@ static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
// These layers should not be painted in a similar way as the other elements collected in
// named flows - regions -> named flows - since we do not want them to be clipped to the
// regions viewport.
-void RenderLayer::paintFixedLayersInNamedFlows(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+void RenderLayer::paintFixedLayersInNamedFlows(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
if (!isRootLayer())
return;
@@ -4039,13 +4282,11 @@ void RenderLayer::paintFixedLayersInNamedFlows(GraphicsContext* context, const L
renderer().view().flowThreadController().collectFixedPositionedLayers(fixedLayers);
// Paint the layers
- for (size_t i = 0; i < fixedLayers.size(); ++i) {
- RenderLayer* fixedLayer = fixedLayers.at(i);
+ for (auto* fixedLayer : fixedLayers)
fixedLayer->paintLayer(context, paintingInfo, paintFlags);
- }
}
-void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+void RenderLayer::paintLayerContents(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
@@ -4068,7 +4309,7 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
|| (!isPaintingScrollingContent && isPaintingCompositedForeground));
bool shouldPaintContent = m_hasVisibleContent && isSelfPaintingLayer && !isPaintingOverlayScrollbars;
- if (localPaintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer().isRenderView() && !renderer().isRoot())
+ if (localPaintFlags & PaintLayerPaintingRootBackgroundOnly && !renderer().isRenderView() && !renderer().isDocumentElementRenderer())
return;
// Ensure our lists are up-to-date.
@@ -4080,9 +4321,7 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
&& renderer().fixedPositionedWithNamedFlowContainingBlock())
return;
- LayoutPoint offsetFromRoot;
- convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);
-
+ LayoutSize offsetFromRoot = offsetFromAncestor(paintingInfo.rootLayer);
LayoutRect rootRelativeBounds;
bool rootRelativeBoundsComputed = false;
@@ -4092,149 +4331,177 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
bool needToAdjustSubpixelQuantization = setupFontSubpixelQuantization(context, didQuantizeFonts);
// Apply clip-path to context.
- bool hasClipPath = setupClipPath(context, paintingInfo, offsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
+ LayoutSize columnAwareOffsetFromRoot = offsetFromRoot;
+ if (renderer().flowThreadContainingBlock() && (renderer().hasClipPath() || hasFilterThatIsPainting(context, paintFlags)))
+ columnAwareOffsetFromRoot = toLayoutSize(convertToLayerCoords(paintingInfo.rootLayer, LayoutPoint(), AdjustForColumns));
- LayerPaintingInfo localPaintingInfo(paintingInfo);
+ bool hasClipPath = false;
+ if (shouldApplyClipPath(paintingInfo.paintBehavior, localPaintFlags))
+ hasClipPath = setupClipPath(context, paintingInfo, columnAwareOffsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
- GraphicsContext* transparencyLayerContext = context;
-#if ENABLE(CSS_FILTERS)
- OwnPtr<FilterEffectRendererHelper> filterPainter = setupFilters(context, localPaintingInfo, paintFlags, offsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
- if (filterPainter) {
- context = filterPainter->filterContext();
- if (context != transparencyLayerContext && haveTransparency) {
- // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context.
- beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, paintingInfo.paintDirtyRect, localPaintingInfo.paintBehavior);
- }
- }
-#endif
-
- // If this layer's renderer is a child of the subtreePaintRoot, we render unconditionally, which
- // is done by passing a nil subtreePaintRoot down to our renderer (as if no subtreePaintRoot was ever set).
- // Otherwise, our renderer tree may or may not contain the subtreePaintRoot root, so we pass that root along
- // so it will be tested against as we descend through the renderers.
- RenderObject* subtreePaintRootForRenderer = 0;
- if (localPaintingInfo.subtreePaintRoot && !renderer().isDescendantOf(localPaintingInfo.subtreePaintRoot))
- subtreePaintRootForRenderer = localPaintingInfo.subtreePaintRoot;
-
- if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer)
- performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this);
+ bool selectionAndBackgroundsOnly = paintingInfo.paintBehavior & PaintBehaviorSelectionAndBackgroundsOnly;
+ bool selectionOnly = paintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
+ LayerFragments layerFragments;
+ RenderObject* subtreePaintRootForRenderer = nullptr;
- bool forceBlackText = localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText;
- bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
-
- PaintBehavior paintBehavior = PaintBehaviorNormal;
- if (localPaintFlags & PaintLayerPaintingSkipRootBackground)
- paintBehavior |= PaintBehaviorSkipRootBackground;
- else if (localPaintFlags & PaintLayerPaintingRootBackgroundOnly)
- paintBehavior |= PaintBehaviorRootBackgroundOnly;
+ { // Scope for filter-related state changes.
+ LayerPaintingInfo localPaintingInfo(paintingInfo);
+ std::unique_ptr<FilterEffectRendererHelper> filterPainter = setupFilters(context, localPaintingInfo, paintFlags, columnAwareOffsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
- LayerFragments layerFragments;
- LayoutRect paintDirtyRect = localPaintingInfo.paintDirtyRect;
- if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
- // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
- // fragment should paint. If the parent's filter dictates full repaint to ensure proper filter effect,
- // use the overflow clip as dirty rect, instead of no clipping. It maintains proper clipping for overflow::scroll.
- if (!paintingInfo.clipToDirtyRect && renderer().hasOverflowClip()) {
- // We can turn clipping back by requesting full repaint for the overflow area.
- localPaintingInfo.clipToDirtyRect = true;
- paintDirtyRect = selfClipRect();
+ GraphicsContext* filterContext = filterPainter ? filterPainter->filterContext() : nullptr;
+ if (filterContext && haveTransparency) {
+ // If we have a filter and transparency, we have to eagerly start a transparency layer here, rather than risk a child layer lazily starts one with the wrong context.
+ beginTransparencyLayers(context, localPaintingInfo, paintingInfo.paintDirtyRect);
+ }
+ GraphicsContext& currentContext = filterContext ? *filterContext : context;
+
+ // If this layer's renderer is a child of the subtreePaintRoot, we render unconditionally, which
+ // is done by passing a nil subtreePaintRoot down to our renderer (as if no subtreePaintRoot was ever set).
+ // Otherwise, our renderer tree may or may not contain the subtreePaintRoot root, so we pass that root along
+ // so it will be tested against as we descend through the renderers.
+ if (localPaintingInfo.subtreePaintRoot && !renderer().isDescendantOf(localPaintingInfo.subtreePaintRoot))
+ subtreePaintRootForRenderer = localPaintingInfo.subtreePaintRoot;
+
+ if (localPaintingInfo.overlapTestRequests && isSelfPaintingLayer)
+ performOverlapTests(*localPaintingInfo.overlapTestRequests, localPaintingInfo.rootLayer, this);
+
+ PaintBehavior paintBehavior = PaintBehaviorNormal;
+ if (localPaintFlags & PaintLayerPaintingSkipRootBackground)
+ paintBehavior |= PaintBehaviorSkipRootBackground;
+ else if (localPaintFlags & PaintLayerPaintingRootBackgroundOnly)
+ paintBehavior |= PaintBehaviorRootBackgroundOnly;
+
+ LayoutRect paintDirtyRect = localPaintingInfo.paintDirtyRect;
+ if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
+ // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
+ // fragment should paint. If the parent's filter dictates full repaint to ensure proper filter effect,
+ // use the overflow clip as dirty rect, instead of no clipping. It maintains proper clipping for overflow::scroll.
+ if (!localPaintingInfo.clipToDirtyRect && renderer().hasOverflowClip()) {
+ // We can turn clipping back by requesting full repaint for the overflow area.
+ localPaintingInfo.clipToDirtyRect = true;
+ paintDirtyRect = clipRectRelativeToAncestor(localPaintingInfo.rootLayer, offsetFromRoot, LayoutRect::infiniteRect());
+ }
+ collectFragments(layerFragments, localPaintingInfo.rootLayer, paintDirtyRect, ExcludeCompositedPaginatedLayers,
+ (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
+ (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetFromRoot);
+ updatePaintingInfoForFragments(layerFragments, localPaintingInfo, localPaintFlags, shouldPaintContent, offsetFromRoot);
+ }
+
+ if (isPaintingCompositedBackground) {
+ // Paint only the backgrounds for all of the fragments of the layer.
+ if (shouldPaintContent && !selectionOnly) {
+ paintBackgroundForFragments(layerFragments, currentContext, context, paintingInfo.paintDirtyRect, haveTransparency,
+ localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
+ }
}
- collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.region, paintDirtyRect,
- (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
- (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetFromRoot);
- updatePaintingInfoForFragments(layerFragments, localPaintingInfo, localPaintFlags, shouldPaintContent, &offsetFromRoot);
- }
-
- if (isPaintingCompositedBackground) {
- // Paint only the backgrounds for all of the fragments of the layer.
- if (shouldPaintContent && !selectionOnly)
- paintBackgroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
- localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
- }
-
- // Now walk the sorted list of children with negative z-indices.
- if ((isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground))
- paintList(negZOrderList(), context, localPaintingInfo, localPaintFlags);
-
- if (isPaintingCompositedForeground) {
- if (shouldPaintContent)
- paintForegroundForFragments(layerFragments, context, transparencyLayerContext, paintingInfo.paintDirtyRect, haveTransparency,
- localPaintingInfo, paintBehavior, subtreePaintRootForRenderer, selectionOnly, forceBlackText);
- }
- if (shouldPaintOutline)
- paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
+ // Now walk the sorted list of children with negative z-indices.
+ if ((isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground))
+ paintList(negZOrderList(), currentContext, localPaintingInfo, localPaintFlags);
+
+ if (isPaintingCompositedForeground) {
+ if (shouldPaintContent) {
+ paintForegroundForFragments(layerFragments, currentContext, context, paintingInfo.paintDirtyRect, haveTransparency,
+ localPaintingInfo, paintBehavior, subtreePaintRootForRenderer, selectionOnly || selectionAndBackgroundsOnly);
+ }
+ }
- if (isPaintingCompositedForeground) {
- // Paint any child layers that have overflow.
- paintList(m_normalFlowList.get(), context, localPaintingInfo, localPaintFlags);
-
- // Now walk the sorted list of children with positive z-indices.
- paintList(posZOrderList(), context, localPaintingInfo, localPaintFlags);
+ if (shouldPaintOutline)
+ paintOutlineForFragments(layerFragments, currentContext, localPaintingInfo, paintBehavior, subtreePaintRootForRenderer);
- // Paint the fixed elements from flow threads.
- paintFixedLayersInNamedFlows(context, localPaintingInfo, localPaintFlags);
+ if (isPaintingCompositedForeground) {
+ // Paint any child layers that have overflow.
+ paintList(m_normalFlowList.get(), currentContext, localPaintingInfo, localPaintFlags);
- // If this is a region, paint its contents via the flow thread's layer.
- paintFlowThreadIfRegion(context, localPaintingInfo, localPaintFlags, offsetFromRoot, paintDirtyRect, isPaintingOverflowContents);
- }
+ // Now walk the sorted list of children with positive z-indices.
+ paintList(posZOrderList(), currentContext, localPaintingInfo, localPaintFlags);
- if (isPaintingOverlayScrollbars)
- paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo);
+ // Paint the fixed elements from flow threads.
+ paintFixedLayersInNamedFlows(currentContext, localPaintingInfo, localPaintFlags);
+
+ // If this is a region, paint its contents via the flow thread's layer.
+ if (shouldPaintContent)
+ paintFlowThreadIfRegionForFragments(layerFragments, currentContext, localPaintingInfo, localPaintFlags);
+ }
-#if ENABLE(CSS_FILTERS)
- if (filterPainter) {
- context = applyFilters(filterPainter.get(), transparencyLayerContext, localPaintingInfo, layerFragments);
- filterPainter.clear();
+ if (isPaintingOverlayScrollbars && hasScrollbars())
+ paintOverflowControlsForFragments(layerFragments, currentContext, localPaintingInfo);
+
+ if (filterContext) {
+ // When we called collectFragments() last time, paintDirtyRect was reset to represent the filter bounds.
+ // Now we need to compute the backgroundRect uncontaminated by filters, in order to clip the filtered result.
+ // Note that we also use paintingInfo here, not localPaintingInfo which filters also contaminated.
+ LayerFragments layerFragments;
+ collectFragments(layerFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, ExcludeCompositedPaginatedLayers,
+ (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
+ (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetFromRoot);
+ updatePaintingInfoForFragments(layerFragments, paintingInfo, localPaintFlags, shouldPaintContent, offsetFromRoot);
+
+ applyFilters(filterPainter.get(), context, paintingInfo, layerFragments);
+ filterPainter = nullptr;
+ }
}
-#endif
- // Make sure that we now use the original transparency context.
- ASSERT(transparencyLayerContext == context);
+ if (shouldPaintContent && !(selectionOnly || selectionAndBackgroundsOnly)) {
+ if (shouldPaintMask(paintingInfo.paintBehavior, localPaintFlags)) {
+ // Paint the mask for the fragments.
+ paintMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
+ }
- if ((localPaintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer().hasMask() && !selectionOnly) {
- // Paint the mask for the fragments.
- paintMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
+ if (!(paintFlags & PaintLayerPaintingCompositingMaskPhase) && (paintFlags & PaintLayerPaintingCompositingClipPathPhase)) {
+ // Re-use paintChildClippingMaskForFragments to paint black for the compositing clipping mask.
+ paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
+ }
+
+ if ((localPaintFlags & PaintLayerPaintingChildClippingMaskPhase)) {
+ // Paint the border radius mask for the fragments.
+ paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
+ }
}
// End our transparency layer
if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
- context->endTransparencyLayer();
- context->restore();
+ context.endTransparencyLayer();
+ context.restore();
m_usedTransparency = false;
}
// Re-set this to whatever it was before we painted the layer.
if (needToAdjustSubpixelQuantization)
- context->setShouldSubpixelQuantizeFonts(didQuantizeFonts);
+ context.setShouldSubpixelQuantizeFonts(didQuantizeFonts);
if (hasClipPath)
- context->restore();
+ context.restore();
}
-void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& translationOffset)
+void RenderLayer::paintLayerByApplyingTransform(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutSize& translationOffset)
{
// This involves subtracting out the position of the layer in our current coordinate space, but preserving
// the accumulated error for sub-pixel layout.
- LayoutPoint delta;
- convertToLayerCoords(paintingInfo.rootLayer, delta);
- delta.moveBy(translationOffset);
+ float deviceScaleFactor = renderer().document().deviceScaleFactor();
+ LayoutSize offsetFromParent = offsetFromAncestor(paintingInfo.rootLayer);
+ offsetFromParent += translationOffset;
TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
- IntPoint roundedDelta = roundedIntPoint(delta);
- transform.translateRight(roundedDelta.x(), roundedDelta.y());
- LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);
-
+ // Add the subpixel accumulation to the current layer's offset so that we can always snap the translateRight value to where the renderer() is supposed to be painting.
+ LayoutSize offsetForThisLayer = offsetFromParent + paintingInfo.subpixelOffset;
+ FloatSize devicePixelSnappedOffsetForThisLayer = toFloatSize(roundPointToDevicePixels(toLayoutPoint(offsetForThisLayer), deviceScaleFactor));
+ // We handle accumulated subpixels through nested layers here. Since the context gets translated to device pixels,
+ // all we need to do is add the delta to the accumulated pixels coming from ancestor layers.
+ // Translate the graphics context to the snapping position to avoid off-device-pixel positing.
+ transform.translateRight(devicePixelSnappedOffsetForThisLayer.width(), devicePixelSnappedOffsetForThisLayer.height());
// Apply the transform.
- GraphicsContextStateSaver stateSaver(*context);
- context->concatCTM(transform.toAffineTransform());
+ AffineTransform oldTransfrom = context.getCTM();
+ context.concatCTM(transform.toAffineTransform());
// Now do a paint with the root layer shifted to be us.
- LayerPaintingInfo transformedPaintingInfo(this, enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), paintingInfo.paintBehavior,
- adjustedSubPixelAccumulation, paintingInfo.subtreePaintRoot, paintingInfo.region, paintingInfo.overlapTestRequests);
+ LayoutSize adjustedSubpixelOffset = offsetForThisLayer - LayoutSize(devicePixelSnappedOffsetForThisLayer);
+ LayerPaintingInfo transformedPaintingInfo(this, LayoutRect(encloseRectToDevicePixels(transform.inverse().value_or(AffineTransform()).mapRect(paintingInfo.paintDirtyRect), deviceScaleFactor)),
+ paintingInfo.paintBehavior, adjustedSubpixelOffset, paintingInfo.subtreePaintRoot, paintingInfo.overlapTestRequests);
paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
+ context.setCTM(oldTransfrom);
}
-void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
if (!list)
return;
@@ -4246,58 +4513,133 @@ void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context
LayerListMutationDetector mutationChecker(this);
#endif
- for (size_t i = 0; i < list->size(); ++i) {
- RenderLayer* childLayer = list->at(i);
+ for (auto* childLayer : *list) {
if (childLayer->isFlowThreadCollectingGraphicsLayersUnderRegions())
continue;
+ childLayer->paintLayer(context, paintingInfo, paintFlags);
+ }
+}
- if (!childLayer->isPaginated())
- childLayer->paintLayer(context, paintingInfo, paintFlags);
- else
- paintPaginatedChildLayer(childLayer, context, paintingInfo, paintFlags);
+RenderLayer* RenderLayer::enclosingPaginationLayerInSubtree(const RenderLayer* rootLayer, PaginationInclusionMode mode) const
+{
+ // If we don't have an enclosing layer, or if the root layer is the same as the enclosing layer,
+ // then just return the enclosing pagination layer (it will be 0 in the former case and the rootLayer in the latter case).
+ RenderLayer* paginationLayer = enclosingPaginationLayer(mode);
+ if (!paginationLayer || rootLayer == paginationLayer)
+ return paginationLayer;
+
+ // Walk up the layer tree and see which layer we hit first. If it's the root, then the enclosing pagination
+ // layer isn't in our subtree and we return nullptr. If we hit the enclosing pagination layer first, then
+ // we can return it.
+ for (const RenderLayer* layer = this; layer; layer = layer->parent()) {
+ if (layer == rootLayer)
+ return nullptr;
+ if (layer == paginationLayer)
+ return paginationLayer;
}
+
+ // This should never be reached, since an enclosing layer should always either be the rootLayer or be
+ // our enclosing pagination layer.
+ ASSERT_NOT_REACHED();
+ return nullptr;
}
-void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& dirtyRect,
- ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
- const LayoutRect* layerBoundingBox)
+void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, const LayoutRect& dirtyRect, PaginationInclusionMode inclusionMode,
+ ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutSize& offsetFromRoot,
+ const LayoutRect* layerBoundingBox, ShouldApplyRootOffsetToFragments applyRootOffsetToFragments)
{
- if (!enclosingPaginationLayer() || hasTransform()) {
+ RenderLayer* paginationLayer = enclosingPaginationLayerInSubtree(rootLayer, inclusionMode);
+ if (!paginationLayer || hasTransform()) {
// For unpaginated layers, there is only one fragment.
LayerFragment fragment;
- ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
- calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offsetFromRoot);
+ ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
+ calculateRects(clipRectsContext, dirtyRect, fragment.layerBounds, fragment.backgroundRect, fragment.foregroundRect, offsetFromRoot);
fragments.append(fragment);
return;
}
// Compute our offset within the enclosing pagination layer.
- LayoutPoint offsetWithinPaginatedLayer;
- convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer);
+ LayoutSize offsetWithinPaginatedLayer = offsetFromAncestor(paginationLayer);
// Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate
// layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that.
- ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
+ ClipRectsContext paginationClipRectsContext(paginationLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
LayoutRect layerBoundsInFlowThread;
ClipRect backgroundRectInFlowThread;
ClipRect foregroundRectInFlowThread;
- ClipRect outlineRectInFlowThread;
calculateRects(paginationClipRectsContext, LayoutRect::infiniteRect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread,
- outlineRectInFlowThread, &offsetWithinPaginatedLayer);
+ offsetWithinPaginatedLayer);
// Take our bounding box within the flow thread and clip it.
- LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer);
+ LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(paginationLayer, offsetWithinPaginatedLayer);
layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect());
+
+ auto& enclosingFlowThread = downcast<RenderFlowThread>(paginationLayer->renderer());
+ RenderLayer* parentPaginationLayer = paginationLayer->parent()->enclosingPaginationLayerInSubtree(rootLayer, inclusionMode);
+ LayerFragments ancestorFragments;
+ if (parentPaginationLayer) {
+ // Compute a bounding box accounting for fragments.
+ LayoutRect layerFragmentBoundingBoxInParentPaginationLayer = enclosingFlowThread.fragmentsBoundingBox(layerBoundingBoxInFlowThread);
+
+ // Convert to be in the ancestor pagination context's coordinate space.
+ LayoutSize offsetWithinParentPaginatedLayer = paginationLayer->offsetFromAncestor(parentPaginationLayer);
+ layerFragmentBoundingBoxInParentPaginationLayer.move(offsetWithinParentPaginatedLayer);
+
+ // Now collect ancestor fragments.
+ parentPaginationLayer->collectFragments(ancestorFragments, rootLayer, dirtyRect, inclusionMode, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip,
+ offsetFromAncestor(rootLayer), &layerFragmentBoundingBoxInParentPaginationLayer, ApplyRootOffsetToFragments);
+
+ if (ancestorFragments.isEmpty())
+ return;
+
+ for (auto& ancestorFragment : ancestorFragments) {
+ // Shift the dirty rect into flow thread coordinates.
+ LayoutRect dirtyRectInFlowThread(dirtyRect);
+ dirtyRectInFlowThread.move(-offsetWithinParentPaginatedLayer - ancestorFragment.paginationOffset);
+
+ size_t oldSize = fragments.size();
+
+ // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns
+ // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box.
+ enclosingFlowThread.collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread);
+
+ size_t newSize = fragments.size();
+
+ if (oldSize == newSize)
+ continue;
+ for (size_t i = oldSize; i < newSize; ++i) {
+ LayerFragment& fragment = fragments.at(i);
+
+ // Set our four rects with all clipping applied that was internal to the flow thread.
+ fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, &layerBoundingBoxInFlowThread);
+
+ // Shift to the root-relative physical position used when painting the flow thread in this fragment.
+ fragment.moveBy(toLayoutPoint(ancestorFragment.paginationOffset + fragment.paginationOffset + offsetWithinParentPaginatedLayer));
+
+ // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are
+ // properly clipped by the overflow.
+ fragment.intersect(ancestorFragment.paginationClip);
+
+ // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column
+ // clip, so the column clip ends up being all we apply.
+ fragment.intersect(fragment.paginationClip);
+
+ if (applyRootOffsetToFragments == ApplyRootOffsetToFragments)
+ fragment.paginationOffset = fragment.paginationOffset + offsetWithinParentPaginatedLayer;
+ }
+ }
+
+ return;
+ }
+
// Shift the dirty rect into flow thread coordinates.
- LayoutPoint offsetOfPaginationLayerFromRoot;
- enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
+ LayoutSize offsetOfPaginationLayerFromRoot = enclosingPaginationLayer(inclusionMode)->offsetFromAncestor(rootLayer);
LayoutRect dirtyRectInFlowThread(dirtyRect);
- dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot);
+ dirtyRectInFlowThread.move(-offsetOfPaginationLayerFromRoot);
// Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns
// that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box.
- RenderFlowThread& enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
enclosingFlowThread.collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread);
if (fragments.isEmpty())
@@ -4305,130 +4647,132 @@ void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer*
// Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents.
ClipRect ancestorClipRect = dirtyRect;
- if (enclosingPaginationLayer()->parent()) {
- ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
- ancestorClipRect = enclosingPaginationLayer()->backgroundClipRect(clipRectsContext);
+ if (paginationLayer->parent()) {
+ ClipRectsContext clipRectsContext(rootLayer, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);
+ ancestorClipRect = paginationLayer->backgroundClipRect(clipRectsContext);
ancestorClipRect.intersect(dirtyRect);
}
- for (size_t i = 0; i < fragments.size(); ++i) {
- LayerFragment& fragment = fragments.at(i);
-
+ for (auto& fragment : fragments) {
// Set our four rects with all clipping applied that was internal to the flow thread.
- fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread);
+ fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, &layerBoundingBoxInFlowThread);
// Shift to the root-relative physical position used when painting the flow thread in this fragment.
- fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
+ fragment.moveBy(toLayoutPoint(fragment.paginationOffset + offsetOfPaginationLayerFromRoot));
// Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are
// properly clipped by the overflow.
- fragment.intersect(ancestorClipRect.rect());
-
+ fragment.intersect(ancestorClipRect);
+
// Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column
// clip, so the column clip ends up being all we apply.
fragment.intersect(fragment.paginationClip);
+
+ if (applyRootOffsetToFragments == ApplyRootOffsetToFragments)
+ fragment.paginationOffset = fragment.paginationOffset + offsetOfPaginationLayerFromRoot;
}
}
void RenderLayer::updatePaintingInfoForFragments(LayerFragments& fragments, const LayerPaintingInfo& localPaintingInfo, PaintLayerFlags localPaintFlags,
- bool shouldPaintContent, const LayoutPoint* offsetFromRoot)
+ bool shouldPaintContent, const LayoutSize& offsetFromRoot)
{
- ASSERT(offsetFromRoot);
- for (size_t i = 0; i < fragments.size(); ++i) {
- LayerFragment& fragment = fragments.at(i);
+ for (auto& fragment : fragments) {
fragment.shouldPaintContent = shouldPaintContent;
if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) {
- LayoutPoint newOffsetFromRoot = *offsetFromRoot + fragment.paginationOffset;
- fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, &newOffsetFromRoot, localPaintingInfo.region);
+ LayoutSize newOffsetFromRoot = offsetFromRoot + fragment.paginationOffset;
+ fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, newOffsetFromRoot, fragment.hasBoundingBox ? &fragment.boundingBox : 0);
}
}
}
-void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
+void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
LayerFragments enclosingPaginationFragments;
- LayoutPoint offsetOfPaginationLayerFromRoot;
- LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior);
- enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.region, paintingInfo.paintDirtyRect,
+ LayoutSize offsetOfPaginationLayerFromRoot;
+ RenderLayer* paginatedLayer = enclosingPaginationLayer(ExcludeCompositedPaginatedLayers);
+ LayoutRect transformedExtent = transparencyClipBox(*this, paginatedLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior);
+ paginatedLayer->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, ExcludeCompositedPaginatedLayers,
(paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
- (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
+ (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetOfPaginationLayerFromRoot, &transformedExtent);
- for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) {
- const LayerFragment& fragment = enclosingPaginationFragments.at(i);
-
+ for (const auto& fragment : enclosingPaginationFragments) {
// Apply the page/column clip for this fragment, as well as any clips established by layers in between us and
// the enclosing pagination layer.
LayoutRect clipRect = fragment.backgroundRect.rect();
// Now compute the clips within a given fragment
- if (parent() != enclosingPaginationLayer()) {
- enclosingPaginationLayer()->convertToLayerCoords(paintingInfo.rootLayer, offsetOfPaginationLayerFromRoot);
+ if (parent() != paginatedLayer) {
+ offsetOfPaginationLayerFromRoot = toLayoutSize(paginatedLayer->convertToLayerCoords(paintingInfo.rootLayer, toLayoutPoint(offsetOfPaginationLayerFromRoot)));
- ClipRectsContext clipRectsContext(enclosingPaginationLayer(), paintingInfo.region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
+ ClipRectsContext clipRectsContext(paginatedLayer, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
- parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
+ parentClipRect.move(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
clipRect.intersect(parentClipRect);
}
- parent()->clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, clipRect);
+ parent()->clipToRect(context, paintingInfo, clipRect);
paintLayerByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset);
- parent()->restoreClip(context, paintingInfo.paintDirtyRect, clipRect);
+ parent()->restoreClip(context, paintingInfo, clipRect);
}
}
-void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
+void RenderLayer::paintBackgroundForFragments(const LayerFragments& layerFragments, GraphicsContext& context, GraphicsContext& contextForTransparencyLayer,
const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
RenderObject* subtreePaintRootForRenderer)
{
- for (size_t i = 0; i < layerFragments.size(); ++i) {
- const LayerFragment& fragment = layerFragments.at(i);
+ for (const auto& fragment : layerFragments) {
if (!fragment.shouldPaintContent)
continue;
// Begin transparency layers lazily now that we know we have to paint something.
if (haveTransparency)
- beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior);
+ beginTransparencyLayers(contextForTransparencyLayer, localPaintingInfo, transparencyPaintDirtyRect);
if (localPaintingInfo.clipToDirtyRect) {
// Paint our background first, before painting any child layers.
// Establish the clip used to paint our background.
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
+ clipToRect(context, localPaintingInfo, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self.
}
// Paint the background.
// FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseBlockBackground, paintBehavior, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, &localPaintingInfo.rootLayer->renderer());
- renderer().paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhaseBlockBackground, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer());
+ renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelOffset));
if (localPaintingInfo.clipToDirtyRect)
- restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
+ restoreClip(context, localPaintingInfo, fragment.backgroundRect);
}
}
-void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext* context, GraphicsContext* transparencyLayerContext,
+void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragments, GraphicsContext& context, GraphicsContext& contextForTransparencyLayer,
const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior,
- RenderObject* subtreePaintRootForRenderer, bool selectionOnly, bool forceBlackText)
+ RenderObject* subtreePaintRootForRenderer, bool selectionOnly)
{
// Begin transparency if we have something to paint.
if (haveTransparency) {
- for (size_t i = 0; i < layerFragments.size(); ++i) {
- const LayerFragment& fragment = layerFragments.at(i);
+ for (const auto& fragment : layerFragments) {
if (fragment.shouldPaintContent && !fragment.foregroundRect.isEmpty()) {
- beginTransparencyLayers(transparencyLayerContext, localPaintingInfo.rootLayer, transparencyPaintDirtyRect, localPaintingInfo.paintBehavior);
+ beginTransparencyLayers(contextForTransparencyLayer, localPaintingInfo, transparencyPaintDirtyRect);
break;
}
}
}
-
- PaintBehavior localPaintBehavior = forceBlackText ? (PaintBehavior)PaintBehaviorForceBlackText : paintBehavior;
+
+ PaintBehavior localPaintBehavior;
+ if (localPaintingInfo.paintBehavior & PaintBehaviorForceBlackText)
+ localPaintBehavior = PaintBehaviorForceBlackText;
+ else if (localPaintingInfo.paintBehavior & PaintBehaviorForceWhiteText)
+ localPaintBehavior = PaintBehaviorForceWhiteText;
+ else
+ localPaintBehavior = paintBehavior;
// Optimize clipping for the single fragment case.
bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty();
ClipRect clippedRect;
if (shouldClip) {
clippedRect = layerFragments[0].foregroundRect;
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, clippedRect);
+ clipToRect(context, localPaintingInfo, clippedRect);
}
// We have to loop through every fragment multiple times, since we have to repaint in each specific phase in order for
@@ -4439,195 +4783,98 @@ void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragmen
if (!selectionOnly) {
paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
-
- // Switch the clipping rectangle to the outline version.
- if (shouldClip && clippedRect != layerFragments[0].outlineRect) {
- restoreClip(context, localPaintingInfo.paintDirtyRect, clippedRect);
-
- if (!layerFragments[0].outlineRect.isEmpty()) {
- clippedRect = layerFragments[0].outlineRect;
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, clippedRect);
- } else
- shouldClip = false;
- }
-
paintForegroundForFragmentsWithPhase(PaintPhaseChildOutlines, layerFragments, context, localPaintingInfo, localPaintBehavior, subtreePaintRootForRenderer);
}
if (shouldClip)
- restoreClip(context, localPaintingInfo.paintDirtyRect, clippedRect);
+ restoreClip(context, localPaintingInfo, clippedRect);
}
-void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext* context,
+void RenderLayer::paintForegroundForFragmentsWithPhase(PaintPhase phase, const LayerFragments& layerFragments, GraphicsContext& context,
const LayerPaintingInfo& localPaintingInfo, PaintBehavior paintBehavior, RenderObject* subtreePaintRootForRenderer)
{
bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() > 1;
- for (size_t i = 0; i < layerFragments.size(); ++i) {
- const LayerFragment& fragment = layerFragments.at(i);
+ for (const auto& fragment : layerFragments) {
if (!fragment.shouldPaintContent || fragment.foregroundRect.isEmpty())
continue;
if (shouldClip)
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
+ clipToRect(context, localPaintingInfo, fragment.foregroundRect);
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.foregroundRect.rect()), phase, paintBehavior, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, &localPaintingInfo.rootLayer->renderer());
+ PaintInfo paintInfo(context, fragment.foregroundRect.rect(), phase, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer(), localPaintingInfo.requireSecurityOriginAccessForWidgets);
if (phase == PaintPhaseForeground)
paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
- renderer().paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelOffset));
if (shouldClip)
- restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.foregroundRect);
+ restoreClip(context, localPaintingInfo, fragment.foregroundRect);
}
}
-void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
+void RenderLayer::paintOutlineForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo,
PaintBehavior paintBehavior, RenderObject* subtreePaintRootForRenderer)
{
- for (size_t i = 0; i < layerFragments.size(); ++i) {
- const LayerFragment& fragment = layerFragments.at(i);
- if (fragment.outlineRect.isEmpty())
+ for (const auto& fragment : layerFragments) {
+ if (fragment.backgroundRect.isEmpty())
continue;
// Paint our own outline
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.outlineRect.rect()), PaintPhaseSelfOutline, paintBehavior, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, &localPaintingInfo.rootLayer->renderer());
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.outlineRect, DoNotIncludeSelfForBorderRadius);
- renderer().paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
- restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.outlineRect);
+ PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhaseSelfOutline, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer());
+ clipToRect(context, localPaintingInfo, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius);
+ renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelOffset));
+ restoreClip(context, localPaintingInfo, fragment.backgroundRect);
}
}
-void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo,
+void RenderLayer::paintMaskForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo,
RenderObject* subtreePaintRootForRenderer)
{
- for (size_t i = 0; i < layerFragments.size(); ++i) {
- const LayerFragment& fragment = layerFragments.at(i);
+ for (const auto& fragment : layerFragments) {
if (!fragment.shouldPaintContent)
continue;
if (localPaintingInfo.clipToDirtyRect)
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
+ clipToRect(context, localPaintingInfo, fragment.backgroundRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self.
// Paint the mask.
// FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
- PaintInfo paintInfo(context, pixelSnappedIntRect(fragment.backgroundRect.rect()), PaintPhaseMask, PaintBehaviorNormal, subtreePaintRootForRenderer, localPaintingInfo.region, 0, 0, &localPaintingInfo.rootLayer->renderer());
- renderer().paint(paintInfo, toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
+ PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhaseMask, PaintBehaviorNormal, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer());
+ renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelOffset));
if (localPaintingInfo.clipToDirtyRect)
- restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
+ restoreClip(context, localPaintingInfo, fragment.backgroundRect);
}
}
-void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext* context, const LayerPaintingInfo& localPaintingInfo)
+void RenderLayer::paintChildClippingMaskForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo,
+ RenderObject* subtreePaintRootForRenderer)
{
- for (size_t i = 0; i < layerFragments.size(); ++i) {
- const LayerFragment& fragment = layerFragments.at(i);
- clipToRect(localPaintingInfo.rootLayer, context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
- paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)),
- pixelSnappedIntRect(fragment.backgroundRect.rect()), true);
- restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
- }
-}
+ for (const auto& fragment : layerFragments) {
+ if (!fragment.shouldPaintContent)
+ continue;
-void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
-{
- // We need to do multiple passes, breaking up our child layer into strips.
- Vector<RenderLayer*> columnLayers;
- RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContainer();
- for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
- if (curr->renderer().hasColumns() && checkContainingBlockChainForPagination(&childLayer->renderer(), curr->renderBox()))
- columnLayers.append(curr);
- if (curr == ancestorLayer)
- break;
- }
+ if (localPaintingInfo.clipToDirtyRect)
+ clipToRect(context, localPaintingInfo, fragment.foregroundRect, IncludeSelfForBorderRadius); // Child clipping mask painting will handle clipping to self.
- // It is possible for paintLayer() to be called after the child layer ceases to be paginated but before
- // updateLayerPositions() is called and resets the isPaginated() flag, see <rdar://problem/10098679>.
- // If this is the case, just bail out, since the upcoming call to updateLayerPositions() will repaint the layer.
- if (!columnLayers.size())
- return;
+ // Paint the clipped mask.
+ PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhaseClippingMask, PaintBehaviorNormal, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer());
+ renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelOffset));
- paintChildLayerIntoColumns(childLayer, context, paintingInfo, paintFlags, columnLayers, columnLayers.size() - 1);
+ if (localPaintingInfo.clipToDirtyRect)
+ restoreClip(context, localPaintingInfo, fragment.foregroundRect);
+ }
}
-void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, GraphicsContext* context, const LayerPaintingInfo& paintingInfo,
- PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex)
+void RenderLayer::paintOverflowControlsForFragments(const LayerFragments& layerFragments, GraphicsContext& context, const LayerPaintingInfo& localPaintingInfo)
{
- RenderBlock& columnBlock = toRenderBlock(columnLayers[colIndex]->renderer());
-
- ASSERT(columnBlock.hasColumns());
- if (!columnBlock.hasColumns())
- return;
-
- LayoutPoint layerOffset;
- // FIXME: It looks suspicious to call convertToLayerCoords here
- // as canUseConvertToLayerCoords is true for this layer.
- columnBlock.layer()->convertToLayerCoords(paintingInfo.rootLayer, layerOffset);
-
- bool isHorizontal = columnBlock.style().isHorizontalWritingMode();
-
- ColumnInfo* colInfo = columnBlock.columnInfo();
- unsigned colCount = columnBlock.columnCount(colInfo);
- LayoutUnit currLogicalTopOffset = columnBlock.initialBlockOffsetForPainting();
- LayoutUnit blockDelta = columnBlock.blockDeltaForPaintingNextColumn();
- for (unsigned i = 0; i < colCount; i++) {
- // For each rect, we clip to the rect, and then we adjust our coords.
- LayoutRect colRect = columnBlock.columnRectAt(colInfo, i);
- columnBlock.flipForWritingMode(colRect);
-
- LayoutUnit logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock.logicalLeftOffsetForContent();
- LayoutSize offset = isHorizontal ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
- colRect.moveBy(layerOffset);
-
- LayoutRect localDirtyRect(paintingInfo.paintDirtyRect);
- localDirtyRect.intersect(colRect);
- if (!localDirtyRect.isEmpty()) {
- GraphicsContextStateSaver stateSaver(*context);
-
- // Each strip pushes a clip, since column boxes are specified as being
- // like overflow:hidden.
- context->clip(pixelSnappedIntRect(colRect));
-
- if (!colIndex) {
- // Apply a translation transform to change where the layer paints.
- TransformationMatrix oldTransform;
- bool oldHasTransform = childLayer->transform();
- if (oldHasTransform)
- oldTransform = *childLayer->transform();
- TransformationMatrix newTransform(oldTransform);
- newTransform.translateRight(roundToInt(offset.width()), roundToInt(offset.height()));
-
- childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
-
- LayerPaintingInfo localPaintingInfo(paintingInfo);
- localPaintingInfo.paintDirtyRect = localDirtyRect;
- childLayer->paintLayer(context, localPaintingInfo, paintFlags);
-
- if (oldHasTransform)
- childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
- else
- childLayer->m_transform.clear();
- } else {
- // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
- // This involves subtracting out the position of the layer in our current coordinate space.
- LayoutPoint childOffset;
- columnLayers[colIndex - 1]->convertToLayerCoords(paintingInfo.rootLayer, childOffset);
- TransformationMatrix transform;
- transform.translateRight(roundToInt(childOffset.x() + offset.width()), roundToInt(childOffset.y() + offset.height()));
-
- // Apply the transform.
- context->concatCTM(transform.toAffineTransform());
-
- // Now do a paint with the root layer shifted to be the next multicol block.
- LayerPaintingInfo columnPaintingInfo(paintingInfo);
- columnPaintingInfo.rootLayer = columnLayers[colIndex - 1];
- columnPaintingInfo.paintDirtyRect = transform.inverse().mapRect(localDirtyRect);
- paintChildLayerIntoColumns(childLayer, context, columnPaintingInfo, paintFlags, columnLayers, colIndex - 1);
- }
- }
-
- // Move to the next position.
- currLogicalTopOffset += blockDelta;
+ for (const auto& fragment : layerFragments) {
+ if (fragment.backgroundRect.isEmpty())
+ continue;
+ clipToRect(context, localPaintingInfo, fragment.backgroundRect);
+ paintOverflowControls(context, roundedIntPoint(toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelOffset)),
+ snappedIntRect(fragment.backgroundRect.rect()), true);
+ restoreClip(context, localPaintingInfo, fragment.backgroundRect);
}
}
@@ -4639,20 +4886,21 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& hitTestLocation, HitTestResult& result)
{
ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
+ ASSERT(!renderer().view().needsLayout());
+
+ updateLayerListsIfNeeded();
- renderer().document().updateLayout();
-
- LayoutRect hitTestArea = isOutOfFlowRenderFlowThread() ? toRenderFlowThread(&renderer())->visualOverflowRect() : renderer().view().documentRect();
+ LayoutRect hitTestArea = isOutOfFlowRenderFlowThread() ? downcast<RenderFlowThread>(renderer()).visualOverflowRect() : renderer().view().documentRect();
if (!request.ignoreClipping())
hitTestArea.intersect(renderer().view().frameView().visibleContentRect(LegacyIOSDocumentVisibleRect));
- RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestLocation, false);
+ RenderLayer* insideLayer = hitTestLayer(this, nullptr, request, result, hitTestArea, hitTestLocation, false);
if (!insideLayer) {
// We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
// return ourselves. We do this so mouse events continue getting delivered after a drag has
// exited the WebView, and so hit testing over a scrollbar hits the content document.
if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRootLayer()) {
- renderer().updateHitTestResult(result, toRenderView(renderer()).flipForWritingMode(hitTestLocation.point()));
+ renderer().updateHitTestResult(result, downcast<RenderView>(renderer()).flipForWritingMode(hitTestLocation.point()));
insideLayer = this;
}
}
@@ -4673,8 +4921,7 @@ Element* RenderLayer::enclosingElement() const
if (Element* e = r->element())
return e;
}
- ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
RenderLayer* RenderLayer::enclosingFlowThreadAncestor() const
@@ -4683,7 +4930,7 @@ RenderLayer* RenderLayer::enclosingFlowThreadAncestor() const
for (; curr && !curr->isRenderFlowThread(); curr = curr->parent()) {
if (curr->isStackingContainer() && curr->isComposited()) {
// We only adjust the position of the first level of layers.
- return 0;
+ return nullptr;
}
}
return curr;
@@ -4691,7 +4938,7 @@ RenderLayer* RenderLayer::enclosingFlowThreadAncestor() const
bool RenderLayer::isFlowThreadCollectingGraphicsLayersUnderRegions() const
{
- return renderer().isRenderFlowThread() && toRenderFlowThread(renderer()).collectsGraphicsLayersUnderRegions();
+ return is<RenderFlowThread>(renderer()) && downcast<RenderFlowThread>(renderer()).collectsGraphicsLayersUnderRegions();
}
// Compute the z-offset of the point in the transformState.
@@ -4711,35 +4958,35 @@ static double computeZOffset(const HitTestingTransformState& transformState)
return backmappedPoint.z();
}
-PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
+Ref<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
const HitTestingTransformState* containerTransformState,
- const LayoutPoint& translationOffset) const
+ const LayoutSize& translationOffset) const
{
RefPtr<HitTestingTransformState> transformState;
- LayoutPoint offset;
+ LayoutSize offset;
if (containerTransformState) {
// If we're already computing transform state, then it's relative to the container (which we know is non-null).
transformState = HitTestingTransformState::create(*containerTransformState);
- convertToLayerCoords(containerLayer, offset);
+ offset = offsetFromAncestor(containerLayer);
} else {
// If this is the first time we need to make transform state, then base it off of hitTestLocation,
// which is relative to rootLayer.
transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect));
- convertToLayerCoords(rootLayer, offset);
+ offset = offsetFromAncestor(rootLayer);
}
- offset.moveBy(translationOffset);
+ offset += translationOffset;
- RenderObject* containerRenderer = containerLayer ? &containerLayer->renderer() : 0;
+ RenderObject* containerRenderer = containerLayer ? &containerLayer->renderer() : nullptr;
if (renderer().shouldUseTransformFromContainer(containerRenderer)) {
TransformationMatrix containerTransform;
- renderer().getTransformFromContainer(containerRenderer, toLayoutSize(offset), containerTransform);
+ renderer().getTransformFromContainer(containerRenderer, offset, containerTransform);
transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
} else {
- transformState->translate(offset.x(), offset.y(), HitTestingTransformState::AccumulateTransform);
+ transformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform);
}
- return transformState;
+ return transformState.releaseNonNull();
}
@@ -4747,6 +4994,11 @@ static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, doubl
{
if (!hitLayer)
return false;
+
+ // RenderNamedFlowFragments are not hit candidates. The hit test algorithm will pick the parent
+ // layer, the one of the region.
+ if (hitLayer->renderer().isRenderNamedFlowFragment())
+ return false;
// The hit layer is depth-sorting with other layers, so just say that it was hit.
if (canDepthSort)
@@ -4776,22 +5028,22 @@ RenderLayer* RenderLayer::hitTestFixedLayersInNamedFlows(RenderLayer* /*rootLaye
bool depthSortDescendants)
{
if (!isRootLayer())
- return 0;
+ return nullptr;
// Get the named flows for the view
if (!renderer().view().hasRenderNamedFlowThreads())
- return 0;
+ return nullptr;
Vector<RenderLayer*> fixedLayers;
renderer().view().flowThreadController().collectFixedPositionedLayers(fixedLayers);
// Hit test the layers
- RenderLayer* resultLayer = 0;
+ RenderLayer* resultLayer = nullptr;
for (int i = fixedLayers.size() - 1; i >= 0; --i) {
RenderLayer* fixedLayer = fixedLayers.at(i);
HitTestResult tempResult(result.hitTestLocation());
- RenderLayer* hitLayer = fixedLayer->hitTestLayer(fixedLayer->renderer().flowThreadContainingBlock()->layer(), 0, request, tempResult,
+ RenderLayer* hitLayer = fixedLayer->hitTestLayer(fixedLayer->renderer().flowThreadContainingBlock()->layer(), nullptr, request, tempResult,
hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants);
// If it a rect-based test, we can safely append the temporary result since it might had hit
@@ -4824,37 +5076,38 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
const HitTestingTransformState* transformState, double* zOffset)
{
if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
- return 0;
+ return nullptr;
+
+ RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment();
// Prevent hitting the fixed layers inside the flow thread when hitting through regions.
- if (renderer().fixedPositionedWithNamedFlowContainingBlock() && hitTestLocation.region())
- return 0;
+ if (renderer().fixedPositionedWithNamedFlowContainingBlock() && namedFlowFragment)
+ return nullptr;
// Don't hit-test the layer if the renderer doesn't belong to this region.
// This is true as long as we clamp the range of a box to its containing block range.
// FIXME: Fix hit testing with in-flow threads included in out-of-flow threads.
- if (hitTestLocation.region()) {
- RenderFlowThread* flowThread = hitTestLocation.region()->flowThread();
- ASSERT(flowThread);
-
- if (!flowThread->objectShouldPaintInFlowRegion(&renderer(), hitTestLocation.region()))
- return 0;
+ if (namedFlowFragment) {
+ ASSERT(namedFlowFragment->isValid());
+ RenderFlowThread* flowThread = namedFlowFragment->flowThread();
+ if (!flowThread->objectShouldFragmentInFlowRegion(&renderer(), namedFlowFragment))
+ return nullptr;
}
// The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
// Apply a transform if we have one.
if (transform() && !appliedTransform) {
- if (enclosingPaginationLayer())
+ if (enclosingPaginationLayer(IncludeCompositedPaginatedLayers))
return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
// Make sure the parent's clip rects have been calculated.
if (parent()) {
- ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
+ ClipRectsContext clipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize);
ClipRect clipRect = backgroundClipRect(clipRectsContext);
- // Go ahead and test the enclosing clip now.
+ // Test the enclosing clip now.
if (!clipRect.intersects(hitTestLocation))
- return 0;
+ return nullptr;
}
return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
@@ -4869,17 +5122,17 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
// We computed the correct state in the caller (above code), so just reference it.
ASSERT(transformState);
localTransformState = const_cast<HitTestingTransformState*>(transformState);
- } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
+ } else if (transformState || has3DTransformedDescendant() || preserves3D()) {
// We need transform state for the first time, or to offset the container state, so create it here.
localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
}
// Check for hit test on backface if backface-visibility is 'hidden'
if (localTransformState && renderer().style().backfaceVisibility() == BackfaceVisibilityHidden) {
- TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
+ std::optional<TransformationMatrix> invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
// If the z-vector of the matrix is negative, the back is facing towards the viewer.
- if (invertedMatrix.m33() < 0)
- return 0;
+ if (invertedMatrix && invertedMatrix.value().m33() < 0)
+ return nullptr;
}
RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
@@ -4893,8 +5146,8 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
// The following are used for keeping track of the z-depth of the hit point of 3d-transformed
// descendants.
double localZOffset = -std::numeric_limits<double>::infinity();
- double* zOffsetForDescendantsPtr = 0;
- double* zOffsetForContentsPtr = 0;
+ double* zOffsetForDescendantsPtr = nullptr;
+ double* zOffsetForContentsPtr = nullptr;
bool depthSortDescendants = false;
if (preserves3D()) {
@@ -4903,13 +5156,16 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
} else if (zOffset) {
- zOffsetForDescendantsPtr = 0;
+ zOffsetForDescendantsPtr = nullptr;
// Container needs us to give back a z offset for the hit layer.
zOffsetForContentsPtr = zOffset;
}
// This variable tracks which layer the mouse ends up being inside.
- RenderLayer* candidateLayer = 0;
+ RenderLayer* candidateLayer = nullptr;
+#if !ASSERT_DISABLED
+ LayerListMutationDetector mutationChecker(this);
+#endif
// Check the fixed positioned layers within flow threads that are positioned by the view.
RenderLayer* hitLayer = hitTestFixedLayersInNamedFlows(rootLayer, request, result, hitTestRect, hitTestLocation,
@@ -4938,22 +5194,24 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
candidateLayer = hitLayer;
}
- hitLayer = hitTestFlowThreadIfRegion(rootLayer, request, result, hitTestRect, hitTestLocation, localTransformState.get(), zOffsetForDescendantsPtr);
- if (hitLayer) {
- if (!depthSortDescendants)
- return hitLayer;
- candidateLayer = hitLayer;
- }
-
// Collect the fragments. This will compute the clip rectangles for each layer fragment.
LayerFragments layerFragments;
- collectFragments(layerFragments, rootLayer, hitTestLocation.region(), hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
+ collectFragments(layerFragments, rootLayer, hitTestRect, IncludeCompositedPaginatedLayers, RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip,
+ offsetFromAncestor(rootLayer));
if (canResize() && hitTestResizerInFragments(layerFragments, hitTestLocation)) {
renderer().updateHitTestResult(result, hitTestLocation.point());
return this;
}
+ hitLayer = hitTestFlowThreadIfRegionForFragments(layerFragments, rootLayer, request, result, hitTestRect, hitTestLocation,
+ localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
+ if (hitLayer) {
+ if (!depthSortDescendants)
+ return hitLayer;
+ candidateLayer = hitLayer;
+ }
+
// Next we want to see if the mouse pos is inside the child RenderObjects of the layer. Check
// every fragment in reverse order.
if (isSelfPaintingLayer()) {
@@ -5002,7 +5260,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
result.append(tempResult);
}
- return 0;
+ return nullptr;
}
bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragments, const HitTestRequest& request, HitTestResult& result,
@@ -5031,7 +5289,7 @@ bool RenderLayer::hitTestResizerInFragments(const LayerFragments& layerFragments
for (int i = layerFragments.size() - 1; i >= 0; --i) {
const LayerFragment& fragment = layerFragments.at(i);
- if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCornerRect(this, pixelSnappedIntRect(fragment.layerBounds)).contains(hitTestLocation.roundedPoint()))
+ if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCornerRect(*this, snappedIntRect(fragment.layerBounds)).contains(hitTestLocation.roundedPoint()))
return true;
}
@@ -5042,10 +5300,11 @@ RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa
const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
{
LayerFragments enclosingPaginationFragments;
- LayoutPoint offsetOfPaginationLayerFromRoot;
- LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox);
- enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestLocation.region(), hitTestRect,
- RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
+ LayoutSize offsetOfPaginationLayerFromRoot;
+ RenderLayer* paginatedLayer = enclosingPaginationLayer(IncludeCompositedPaginatedLayers);
+ LayoutRect transformedExtent = transparencyClipBox(*this, paginatedLayer, HitTestingTransparencyClipBox, RootOfTransparencyClipBox);
+ paginatedLayer->collectFragments(enclosingPaginationFragments, rootLayer, hitTestRect, IncludeCompositedPaginatedLayers,
+ RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, offsetOfPaginationLayerFromRoot, &transformedExtent);
for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) {
const LayerFragment& fragment = enclosingPaginationFragments.at(i);
@@ -5055,12 +5314,12 @@ RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa
LayoutRect clipRect = fragment.backgroundRect.rect();
// Now compute the clips within a given fragment
- if (parent() != enclosingPaginationLayer()) {
- enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOfPaginationLayerFromRoot);
+ if (parent() != paginatedLayer) {
+ offsetOfPaginationLayerFromRoot = toLayoutSize(paginatedLayer->convertToLayerCoords(rootLayer, toLayoutPoint(offsetOfPaginationLayerFromRoot)));
- ClipRectsContext clipRectsContext(enclosingPaginationLayer(), hitTestLocation.region(), RootRelativeClipRects, IncludeOverlayScrollbarSize);
+ ClipRectsContext clipRectsContext(paginatedLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize);
LayoutRect parentClipRect = backgroundClipRect(clipRectsContext).rect();
- parentClipRect.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
+ parentClipRect.move(fragment.paginationOffset + offsetOfPaginationLayerFromRoot);
clipRect.intersect(parentClipRect);
}
@@ -5073,19 +5332,19 @@ RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa
return hitLayer;
}
- return 0;
+ return nullptr;
}
RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
- const LayoutPoint& translationOffset)
+ const LayoutSize& translationOffset)
{
// Create a transform state to accumulate this transform.
- RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset);
+ Ref<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, translationOffset);
// If the transform can't be inverted, then don't hit test this layer at all.
if (!newTransformState->m_accumulatedTransform.isInvertible())
- return 0;
+ return nullptr;
// Compute the point and the hit test rect in the coords of this layer by using the values
// from the transformState, which store the point and quad in the coords of the last flattened
@@ -5103,7 +5362,7 @@ RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer
newHitTestLocation = HitTestLocation(localPoint);
// Now do a hit test with the root layer shifted to be us.
- return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset);
+ return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.ptr(), zOffset);
}
bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter) const
@@ -5122,6 +5381,13 @@ bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult&
// the content in the layer has an element. So just walk up
// the tree.
if (!result.innerNode() || !result.innerNonSharedNode()) {
+ if (isOutOfFlowRenderFlowThread()) {
+ // The flowthread doesn't have an enclosing element, so when hitting the layer of the
+ // flowthread (e.g. the descent area of the RootInlineBox for the image flowed alone
+ // inside the flow thread) we're letting the hit testing continue so it will hit the region.
+ return false;
+ }
+
Element* e = enclosingElement();
if (!result.innerNode())
result.setInnerNode(e);
@@ -5141,22 +5407,19 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r
bool depthSortDescendants)
{
if (!list)
- return 0;
+ return nullptr;
if (!hasSelfPaintingLayerDescendant())
- return 0;
+ return nullptr;
- RenderLayer* resultLayer = 0;
- for (int i = list->size() - 1; i >= 0; --i) {
- RenderLayer* childLayer = list->at(i);
+ RenderLayer* resultLayer = nullptr;
+ for (size_t i = list->size(); i > 0; --i) {
+ RenderLayer* childLayer = list->at(i - 1);
if (childLayer->isFlowThreadCollectingGraphicsLayersUnderRegions())
continue;
- RenderLayer* hitLayer = 0;
+ RenderLayer* hitLayer = nullptr;
HitTestResult tempResult(result.hitTestLocation());
- if (childLayer->isPaginated())
- hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendants);
- else
- hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants);
+ hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants);
// If it a rect-based test, we can safely append the temporary result since it might had hit
// nodes but not necesserily had hitLayer set.
@@ -5175,158 +5438,67 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r
return resultLayer;
}
-RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset)
-{
- Vector<RenderLayer*> columnLayers;
- RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContainer();
- for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
- if (curr->renderer().hasColumns() && checkContainingBlockChainForPagination(&childLayer->renderer(), curr->renderBox()))
- columnLayers.append(curr);
- if (curr == ancestorLayer)
- break;
- }
-
- ASSERT(columnLayers.size());
- return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset,
- columnLayers, columnLayers.size() - 1);
-}
-
-RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset,
- const Vector<RenderLayer*>& columnLayers, size_t columnIndex)
-{
- RenderBlock& columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer());
-
- ASSERT(columnBlock.hasColumns());
- if (!columnBlock.hasColumns())
- return 0;
-
- LayoutPoint layerOffset;
- columnBlock.layer()->convertToLayerCoords(rootLayer, layerOffset);
-
- ColumnInfo* colInfo = columnBlock.columnInfo();
- int colCount = columnBlock.columnCount(colInfo);
-
- // We have to go backwards from the last column to the first.
- bool isHorizontal = columnBlock.style().isHorizontalWritingMode();
- LayoutUnit logicalLeft = columnBlock.logicalLeftOffsetForContent();
- LayoutUnit currLogicalTopOffset = columnBlock.initialBlockOffsetForPainting();
- LayoutUnit blockDelta = columnBlock.blockDeltaForPaintingNextColumn();
- currLogicalTopOffset += colCount * blockDelta;
- for (int i = colCount - 1; i >= 0; i--) {
- // For each rect, we clip to the rect, and then we adjust our coords.
- LayoutRect colRect = columnBlock.columnRectAt(colInfo, i);
- columnBlock.flipForWritingMode(colRect);
- LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
- currLogicalTopOffset -= blockDelta;
-
- LayoutSize offset = isHorizontal ? LayoutSize(currLogicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, currLogicalLeftOffset);
-
- colRect.moveBy(layerOffset);
-
- LayoutRect localClipRect(hitTestRect);
- localClipRect.intersect(colRect);
-
- if (!localClipRect.isEmpty() && hitTestLocation.intersects(localClipRect)) {
- RenderLayer* hitLayer = 0;
- if (!columnIndex) {
- // Apply a translation transform to change where the layer paints.
- TransformationMatrix oldTransform;
- bool oldHasTransform = childLayer->transform();
- if (oldHasTransform)
- oldTransform = *childLayer->transform();
- TransformationMatrix newTransform(oldTransform);
- newTransform.translateRight(offset.width(), offset.height());
-
- childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform));
- hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestLocation, false, transformState, zOffset);
- if (oldHasTransform)
- childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform));
- else
- childLayer->m_transform.clear();
- } else {
- // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space.
- // This involves subtracting out the position of the layer in our current coordinate space.
- RenderLayer* nextLayer = columnLayers[columnIndex - 1];
- RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation, transformState);
- newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform);
- FloatPoint localPoint = newTransformState->mappedPoint();
- FloatQuad localPointQuad = newTransformState->mappedQuad();
- LayoutRect localHitTestRect = newTransformState->mappedArea().enclosingBoundingBox();
- HitTestLocation newHitTestLocation;
- if (hitTestLocation.isRectBasedTest())
- newHitTestLocation = HitTestLocation(localPoint, localPointQuad);
- else
- newHitTestLocation = HitTestLocation(localPoint);
- newTransformState->flatten();
-
- hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, newHitTestLocation,
- newTransformState.get(), zOffset, columnLayers, columnIndex - 1);
- }
-
- if (hitLayer)
- return hitLayer;
- }
- }
-
- return 0;
-}
-
-void RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext)
+Ref<ClipRects> RenderLayer::updateClipRects(const ClipRectsContext& clipRectsContext)
{
ClipRectsType clipRectsType = clipRectsContext.clipRectsType;
ASSERT(clipRectsType < NumCachedClipRectsTypes);
- if (m_clipRectsCache && m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) {
- ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]);
- ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy);
+ if (m_clipRectsCache) {
+ if (auto* clipRects = m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) {
+ ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]);
+ ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy);
#ifdef CHECK_CACHED_CLIP_RECTS
- // This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default.
- ClipRectsContext tempContext(clipRectsContext);
- tempContext.clipRectsType = TemporaryClipRects;
- ClipRects clipRects;
- calculateClipRects(tempContext, clipRects);
- ASSERT(clipRects == *m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip).get());
+ // This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default.
+ ClipRectsContext tempContext(clipRectsContext);
+ tempContext.clipRectsType = TemporaryClipRects;
+ Ref<ClipRects> tempClipRects = ClipRects::create();
+ calculateClipRects(tempContext, tempClipRects);
+ ASSERT(tempClipRects.get() == *clipRects);
#endif
- return; // We have the correct cached value.
+ return *clipRects; // We have the correct cached value.
+ }
}
- // For transformed layers, the root layer was shifted to be us, so there is no need to
- // examine the parent. We want to cache clip rects with us as the root.
- RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : 0;
- if (parentLayer)
- parentLayer->updateClipRects(clipRectsContext);
-
- ClipRects clipRects;
- calculateClipRects(clipRectsContext, clipRects);
-
if (!m_clipRectsCache)
- m_clipRectsCache = adoptPtr(new ClipRectsCache);
-
- if (parentLayer && parentLayer->clipRects(clipRectsContext) && clipRects == *parentLayer->clipRects(clipRectsContext))
- m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentLayer->clipRects(clipRectsContext));
- else
- m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, ClipRects::create(clipRects));
-
+ m_clipRectsCache = std::make_unique<ClipRectsCache>();
#ifndef NDEBUG
m_clipRectsCache->m_clipRectsRoot[clipRectsType] = clipRectsContext.rootLayer;
m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] = clipRectsContext.overlayScrollbarSizeRelevancy;
#endif
+
+ RefPtr<ClipRects> parentClipRects;
+ // For transformed layers, the root layer was shifted to be us, so there is no need to
+ // examine the parent. We want to cache clip rects with us as the root.
+ if (auto* parentLayer = (clipRectsContext.rootLayer != this ? parent() : nullptr))
+ parentClipRects = parentLayer->updateClipRects(clipRectsContext);
+
+ auto clipRects = ClipRects::create();
+ calculateClipRects(clipRectsContext, clipRects);
+
+ if (parentClipRects && *parentClipRects == clipRects) {
+ m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentClipRects.copyRef());
+ return parentClipRects.releaseNonNull();
+ }
+ m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, clipRects.copyRef());
+ return clipRects;
}
-void RenderLayer::mapLayerClipRectsToFragmentationLayer(RenderRegion* region, ClipRects& clipRects) const
+bool RenderLayer::mapLayerClipRectsToFragmentationLayer(ClipRects& clipRects) const
{
- ASSERT(region && region->parent() && region->parent()->isRenderNamedFlowFragmentContainer());
+ RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment();
+ if (!namedFlowFragment)
+ return false;
- ClipRectsContext targetClipRectsContext(region->regionContainerLayer(), 0, TemporaryClipRects);
- region->regionContainerLayer()->calculateClipRects(targetClipRectsContext, clipRects);
+ ASSERT(namedFlowFragment->parent() && namedFlowFragment->parent()->isRenderNamedFlowFragmentContainer());
- LayoutRect flowThreadPortionRect = region->flowThreadPortionRect();
+ ClipRectsContext targetClipRectsContext(&namedFlowFragment->fragmentContainerLayer(), TemporaryClipRects);
+ namedFlowFragment->fragmentContainerLayer().calculateClipRects(targetClipRectsContext, clipRects);
+
+ LayoutRect flowThreadPortionRect = namedFlowFragment->flowThreadPortionRect();
LayoutPoint portionLocation = flowThreadPortionRect.location();
- LayoutRect regionContentBox = region->contentBoxRect();
- LayoutSize moveOffset = portionLocation - regionContentBox.location();
+ LayoutRect regionContentBox = namedFlowFragment->fragmentContainer().contentBoxRect();
+ LayoutSize moveOffset = portionLocation - regionContentBox.location() + toLayoutSize(namedFlowFragment->fragmentContainer().scrollPosition());
ClipRect newOverflowClipRect = clipRects.overflowClipRect();
newOverflowClipRect.move(moveOffset);
@@ -5339,27 +5511,35 @@ void RenderLayer::mapLayerClipRectsToFragmentationLayer(RenderRegion* region, Cl
ClipRect newPosClipRect = clipRects.posClipRect();
newPosClipRect.move(moveOffset);
clipRects.setPosClipRect(newPosClipRect);
+
+ return true;
+}
+
+ClipRects* RenderLayer::clipRects(const ClipRectsContext& context) const
+{
+ ASSERT(context.clipRectsType < NumCachedClipRectsTypes);
+ if (!m_clipRectsCache)
+ return nullptr;
+ return m_clipRectsCache->getClipRects(context.clipRectsType, context.respectOverflowClip);
}
void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const
{
if (!parent()) {
// The root layer's clip rect is always infinite.
- clipRects.reset(LayoutRect::infiniteRect());
+ clipRects.reset();
return;
}
ClipRectsType clipRectsType = clipRectsContext.clipRectsType;
bool useCached = clipRectsType != TemporaryClipRects;
- if (renderer().isRenderFlowThread() && clipRectsContext.region) {
- mapLayerClipRectsToFragmentationLayer(clipRectsContext.region, clipRects);
+ if (renderer().isRenderNamedFlowThread() && mapLayerClipRectsToFragmentationLayer(clipRects))
return;
- }
// For transformed layers, the root layer was shifted to be us, so there is no need to
// examine the parent. We want to cache clip rects with us as the root.
- RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : 0;
+ RenderLayer* parentLayer = clipRectsContext.rootLayer != this ? parent() : nullptr;
// Ensure that our parent's clip has been calculated so that we can examine the values.
if (parentLayer) {
@@ -5371,7 +5551,7 @@ void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, C
parentLayer->calculateClipRects(parentContext, clipRects);
}
} else
- clipRects.reset(LayoutRect::infiniteRect());
+ clipRects.reset();
// A fixed object is essentially the root of its containing block hierarchy, so when
// we encounter such an object, we reset our clip rects to the fixedClipRect.
@@ -5395,21 +5575,19 @@ void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, C
// This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across
// some transformed layer boundary, for example, in the RenderLayerCompositor overlapMap, where
// clipRects are needed in view space.
- LayoutPoint offset;
- offset = roundedLayoutPoint(renderer().localToContainerPoint(FloatPoint(), &clipRectsContext.rootLayer->renderer()));
+ LayoutPoint offset(renderer().localToContainerPoint(FloatPoint(), &clipRectsContext.rootLayer->renderer()));
if (clipRects.fixed() && &clipRectsContext.rootLayer->renderer() == &renderer().view())
- offset -= renderer().view().frameView().scrollOffsetForFixedPosition();
+ offset -= toLayoutSize(renderer().view().frameView().scrollPositionForFixedPosition());
if (renderer().hasOverflowClip()) {
- ClipRect newOverflowClip = toRenderBox(renderer()).overflowClipRectForChildLayers(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy);
- if (renderer().style().hasBorderRadius())
- newOverflowClip.setHasRadius(true);
+ ClipRect newOverflowClip = downcast<RenderBox>(renderer()).overflowClipRectForChildLayers(offset, currentRenderNamedFlowFragment(), clipRectsContext.overlayScrollbarSizeRelevancy);
+ newOverflowClip.setAffectedByRadius(renderer().style().hasBorderRadius());
clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
if (renderer().isPositioned())
clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
}
if (renderer().hasClip()) {
- LayoutRect newPosClip = toRenderBox(renderer()).clipRect(offset, clipRectsContext.region);
+ LayoutRect newPosClip = downcast<RenderBox>(renderer()).clipRect(offset, currentRenderNamedFlowFragment());
clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
@@ -5417,21 +5595,22 @@ void RenderLayer::calculateClipRects(const ClipRectsContext& clipRectsContext, C
}
}
-void RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const
+Ref<ClipRects> RenderLayer::parentClipRects(const ClipRectsContext& clipRectsContext) const
{
ASSERT(parent());
- if (renderer().isRenderFlowThread() && clipRectsContext.region) {
- mapLayerClipRectsToFragmentationLayer(clipRectsContext.region, clipRects);
- return;
+ if (renderer().isRenderNamedFlowThread()) {
+ auto parentClipRects = ClipRects::create();
+ if (mapLayerClipRectsToFragmentationLayer(parentClipRects))
+ return parentClipRects;
}
if (clipRectsContext.clipRectsType == TemporaryClipRects) {
- parent()->calculateClipRects(clipRectsContext, clipRects);
- return;
+ auto parentClipRects = ClipRects::create();
+ parent()->calculateClipRects(clipRectsContext, parentClipRects);
+ return parentClipRects;
}
- parent()->updateClipRects(clipRectsContext);
- clipRects = *parent()->clipRects(clipRectsContext);
+ return parent()->updateClipRects(clipRectsContext);
}
static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position)
@@ -5448,30 +5627,29 @@ static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRect
ClipRect RenderLayer::backgroundClipRect(const ClipRectsContext& clipRectsContext) const
{
ASSERT(parent());
+ auto computeParentRects = [this, &clipRectsContext] () {
+ // If we cross into a different pagination context, then we can't rely on the cache.
+ // Just switch over to using TemporaryClipRects.
+ if (clipRectsContext.clipRectsType != TemporaryClipRects
+ && parent()->enclosingPaginationLayer(IncludeCompositedPaginatedLayers) != enclosingPaginationLayer(IncludeCompositedPaginatedLayers)) {
+ ClipRectsContext tempContext(clipRectsContext);
+ tempContext.clipRectsType = TemporaryClipRects;
+ return parentClipRects(tempContext);
+ }
+ return parentClipRects(clipRectsContext);
+ };
- ClipRects parentRects;
-
- // If we cross into a different pagination context, then we can't rely on the cache.
- // Just switch over to using TemporaryClipRects.
- if (clipRectsContext.clipRectsType != TemporaryClipRects && parent()->enclosingPaginationLayer() != enclosingPaginationLayer()) {
- ClipRectsContext tempContext(clipRectsContext);
- tempContext.clipRectsType = TemporaryClipRects;
- parentClipRects(tempContext, parentRects);
- } else
- parentClipRects(clipRectsContext, parentRects);
-
+ auto parentRects = computeParentRects();
ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer().style().position());
RenderView& view = renderer().view();
-
// Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite.
- if (parentRects.fixed() && &clipRectsContext.rootLayer->renderer() == &view && backgroundClipRect != LayoutRect::infiniteRect())
- backgroundClipRect.move(view.frameView().scrollOffsetForFixedPosition());
-
+ if (parentRects->fixed() && &clipRectsContext.rootLayer->renderer() == &view && !backgroundClipRect.isInfinite())
+ backgroundClipRect.moveBy(view.frameView().scrollPositionForFixedPosition());
return backgroundClipRect;
}
void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
- ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot) const
+ ClipRect& backgroundRect, ClipRect& foregroundRect, const LayoutSize& offsetFromRoot) const
{
if (clipRectsContext.rootLayer != this && parent()) {
backgroundRect = backgroundClipRect(clipRectsContext);
@@ -5479,28 +5657,24 @@ void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const
} else
backgroundRect = paintDirtyRect;
- LayoutPoint offset;
- if (offsetFromRoot)
- offset = *offsetFromRoot;
- else
- convertToLayerCoords(clipRectsContext.rootLayer, offset);
-
+ LayoutSize offsetFromRootLocal = offsetFromRoot;
+ RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment();
// If the view is scrolled, the flow thread is not scrolled with it and we should
// take the scroll offset into account.
- if (clipRectsContext.rootLayer->isOutOfFlowRenderFlowThread() && !clipRectsContext.region) {
- FloatPoint absPos = renderer().view().localToAbsolute(FloatPoint(), IsFixed);
- offset += LayoutSize(absPos.x(), absPos.y());
+ if (clipRectsContext.rootLayer->isOutOfFlowRenderFlowThread() && !namedFlowFragment) {
+ LayoutPoint absPos = LayoutPoint(renderer().view().localToAbsolute(FloatPoint(), IsFixed));
+ offsetFromRootLocal += toLayoutSize(absPos);
}
- layerBounds = LayoutRect(offset, size());
+ layerBounds = LayoutRect(toLayoutPoint(offsetFromRootLocal), size());
foregroundRect = backgroundRect;
- outlineRect = backgroundRect;
- RenderFlowThread* flowThread = clipRectsContext.region ? clipRectsContext.region->flowThread() : 0;
+ RenderFlowThread* flowThread = namedFlowFragment ? namedFlowFragment->flowThread() : nullptr;
if (isSelfPaintingLayer() && flowThread && !renderer().isInFlowRenderFlowThread()) {
- const RenderBoxModelObject& boxModelObject = toRenderBoxModelObject(renderer());
- LayoutRect layerBoundsWithVisualOverflow = clipRectsContext.region->visualOverflowRectForBox(&boxModelObject);
+ ASSERT(namedFlowFragment->isValid());
+ const RenderBoxModelObject& boxModelObject = downcast<RenderBoxModelObject>(renderer());
+ LayoutRect layerBoundsWithVisualOverflow = namedFlowFragment->visualOverflowRectForBox(boxModelObject);
// Layers are in physical coordinates so the origin must be moved to the physical top-left of the flowthread.
if (&boxModelObject == flowThread && flowThread->style().isFlippedBlocksWritingMode()) {
@@ -5509,59 +5683,63 @@ void RenderLayer::calculateRects(const ClipRectsContext& clipRectsContext, const
else
layerBoundsWithVisualOverflow.moveBy(LayoutPoint(flowThread->width(), 0));
} else {
- RenderBlock* rendererContainingBlock = boxModelObject.enclosingBox()->isRenderBlock() ? toRenderBlock(boxModelObject.enclosingBox()) : 0;
+ RenderBlock* rendererContainingBlock = is<RenderBlock>(boxModelObject.enclosingBox()) ? &downcast<RenderBlock>(boxModelObject.enclosingBox()) : nullptr;
if (rendererContainingBlock)
rendererContainingBlock->flipForWritingMode(layerBoundsWithVisualOverflow);
}
- layerBoundsWithVisualOverflow.moveBy(offset);
+ layerBoundsWithVisualOverflow.move(offsetFromRootLocal);
backgroundRect.intersect(layerBoundsWithVisualOverflow);
foregroundRect = backgroundRect;
- outlineRect = backgroundRect;
-
- // If the region does not clip its overflow, inflate the outline rect.
- if (!(clipRectsContext.region->parent()->hasOverflowClip() && (clipRectsContext.region->regionContainerLayer() != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)))
- outlineRect.inflate(renderer().maximalOutlineSize(PaintPhaseOutline));
}
// Update the clip rects that will be passed to child layers.
if (renderer().hasClipOrOverflowClip()) {
// This layer establishes a clip of some kind.
if (renderer().hasOverflowClip() && (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)) {
- foregroundRect.intersect(toRenderBox(renderer()).overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy));
+ foregroundRect.intersect(downcast<RenderBox>(renderer()).overflowClipRect(toLayoutPoint(offsetFromRootLocal), namedFlowFragment, clipRectsContext.overlayScrollbarSizeRelevancy));
if (renderer().style().hasBorderRadius())
- foregroundRect.setHasRadius(true);
+ foregroundRect.setAffectedByRadius(true);
}
if (renderer().hasClip()) {
- // Clip applies to *us* as well, so go ahead and update the damageRect.
- LayoutRect newPosClip = toRenderBox(renderer()).clipRect(offset, clipRectsContext.region);
+ // Clip applies to *us* as well, so update the damageRect.
+ LayoutRect newPosClip = downcast<RenderBox>(renderer()).clipRect(toLayoutPoint(offsetFromRootLocal), namedFlowFragment);
backgroundRect.intersect(newPosClip);
foregroundRect.intersect(newPosClip);
- outlineRect.intersect(newPosClip);
}
- // If we establish a clip at all, then go ahead and make sure our background
- // rect is intersected with our layer's bounds including our visual overflow,
+ // If we establish a clip at all, then make sure our background rect is intersected with our layer's bounds including our visual overflow,
// since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden.
if (renderBox()->hasVisualOverflow()) {
// FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the
// individual region boxes as overflow.
- LayoutRect layerBoundsWithVisualOverflow = clipRectsContext.region ? clipRectsContext.region->visualOverflowRectForBox(renderBox()) : renderBox()->visualOverflowRect();
+ LayoutRect layerBoundsWithVisualOverflow = namedFlowFragment ? namedFlowFragment->visualOverflowRectForBox(*renderBox()) : renderBox()->visualOverflowRect();
renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped.
- layerBoundsWithVisualOverflow.moveBy(offset);
+ layerBoundsWithVisualOverflow.move(offsetFromRootLocal);
if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)
backgroundRect.intersect(layerBoundsWithVisualOverflow);
} else {
// Shift the bounds to be for our region only.
- LayoutRect bounds = renderBox()->borderBoxRectInRegion(clipRectsContext.region);
- if (clipRectsContext.region)
- bounds = clipRectsContext.region->rectFlowPortionForBox(renderBox(), bounds);
+ LayoutRect bounds = renderBox()->borderBoxRectInRegion(namedFlowFragment);
+ if (namedFlowFragment)
+ bounds = namedFlowFragment->rectFlowPortionForBox(renderBox(), bounds);
- bounds.moveBy(offset);
+ bounds.move(offsetFromRootLocal);
if (this != clipRectsContext.rootLayer || clipRectsContext.respectOverflowClip == RespectOverflowClip)
backgroundRect.intersect(bounds);
+ // Boxes inside flow threads don't have their logical left computed to avoid
+ // floats. Instead, that information is kept in their RenderBoxRegionInfo structure.
+ // As such, the layer bounds must be enlarged to encompass their background rect
+ // to ensure intersecting them won't result in an empty rect, which would eventually
+ // cause paint rejection.
+ if (flowThread && flowThread->isRenderNamedFlowThread()) {
+ if (flowThread->style().isHorizontalWritingMode())
+ layerBounds.shiftMaxXEdgeTo(std::max(layerBounds.maxX(), backgroundRect.rect().maxX()));
+ else
+ layerBounds.shiftMaxYEdgeTo(std::max(layerBounds.maxY(), backgroundRect.rect().maxY()));
+ }
}
}
}
@@ -5572,43 +5750,52 @@ LayoutRect RenderLayer::childrenClipRect() const
// FIXME: Regions not accounted for.
RenderLayer* clippingRootLayer = clippingRootForPainting();
LayoutRect layerBounds;
- ClipRect backgroundRect, foregroundRect, outlineRect;
- ClipRectsContext clipRectsContext(clippingRootLayer, 0, TemporaryClipRects);
+ ClipRect backgroundRect;
+ ClipRect foregroundRect;
+ ClipRectsContext clipRectsContext(clippingRootLayer, TemporaryClipRects);
// Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>).
- calculateRects(clipRectsContext, renderer().view().unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
+ calculateRects(clipRectsContext, renderer().view().unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, offsetFromAncestor(clipRectsContext.rootLayer));
return clippingRootLayer->renderer().localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox();
}
+LayoutRect RenderLayer::clipRectRelativeToAncestor(RenderLayer* ancestor, LayoutSize offsetFromAncestor, const LayoutRect& constrainingRect) const
+{
+ LayoutRect layerBounds;
+ ClipRect backgroundRect;
+ ClipRect foregroundRect;
+ auto clipRectType = !m_enclosingPaginationLayer || m_enclosingPaginationLayer == ancestor ? PaintingClipRects : TemporaryClipRects;
+ ClipRectsContext clipRectsContext(ancestor, clipRectType);
+ calculateRects(clipRectsContext, constrainingRect, layerBounds, backgroundRect, foregroundRect, offsetFromAncestor);
+ return backgroundRect.rect();
+}
+
LayoutRect RenderLayer::selfClipRect() const
{
// FIXME: border-radius not accounted for.
// FIXME: Regions not accounted for.
RenderLayer* clippingRootLayer = clippingRootForPainting();
- LayoutRect layerBounds;
- ClipRect backgroundRect, foregroundRect, outlineRect;
- ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects);
- calculateRects(clipRectsContext, renderer().view().documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
- return clippingRootLayer->renderer().localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox();
+ LayoutRect clipRect = clipRectRelativeToAncestor(clippingRootLayer, offsetFromAncestor(clippingRootLayer), renderer().view().documentRect());
+ return clippingRootLayer->renderer().localToAbsoluteQuad(FloatQuad(clipRect)).enclosingBoundingBox();
}
-LayoutRect RenderLayer::localClipRect() const
+LayoutRect RenderLayer::localClipRect(bool& clipExceedsBounds) const
{
+ clipExceedsBounds = false;
// FIXME: border-radius not accounted for.
// FIXME: Regions not accounted for.
RenderLayer* clippingRootLayer = clippingRootForPainting();
- LayoutRect layerBounds;
- ClipRect backgroundRect, foregroundRect, outlineRect;
- ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects);
- calculateRects(clipRectsContext, LayoutRect::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
-
- LayoutRect clipRect = backgroundRect.rect();
- if (clipRect == LayoutRect::infiniteRect())
+ LayoutSize offsetFromRoot = offsetFromAncestor(clippingRootLayer);
+ LayoutRect clipRect = clipRectRelativeToAncestor(clippingRootLayer, offsetFromRoot, LayoutRect::infiniteRect());
+ if (clipRect.isInfinite())
return clipRect;
- LayoutPoint clippingRootOffset;
- convertToLayerCoords(clippingRootLayer, clippingRootOffset);
- clipRect.moveBy(-clippingRootOffset);
+ if (renderer().hasClip()) {
+ // CSS clip may be larger than our border box.
+ LayoutRect cssClipRect = downcast<RenderBox>(renderer()).clipRect(toLayoutPoint(offsetFromRoot), currentRenderNamedFlowFragment());
+ clipExceedsBounds = !clipRect.contains(cssClipRect);
+ }
+ clipRect.move(-offsetFromRoot);
return clipRect;
}
@@ -5633,47 +5820,52 @@ void RenderLayer::repaintBlockSelectionGaps()
return;
LayoutRect rect = m_blockSelectionGapsBounds;
- rect.move(-scrolledContentOffset());
+ rect.moveBy(-scrollPosition());
if (renderer().hasOverflowClip() && !usesCompositedScrolling())
- rect.intersect(toRenderBox(renderer()).overflowClipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for.
+ rect.intersect(downcast<RenderBox>(renderer()).overflowClipRect(LayoutPoint(), nullptr)); // FIXME: Regions not accounted for.
if (renderer().hasClip())
- rect.intersect(toRenderBox(renderer()).clipRect(LayoutPoint(), 0)); // FIXME: Regions not accounted for.
+ rect.intersect(downcast<RenderBox>(renderer()).clipRect(LayoutPoint(), nullptr)); // FIXME: Regions not accounted for.
if (!rect.isEmpty())
renderer().repaintRectangle(rect);
}
-bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot, RenderRegion* region) const
+bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutSize& offsetFromRoot, const LayoutRect* cachedBoundingBox) const
{
// Always examine the canvas and the root.
- // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
+ // FIXME: Could eliminate the isDocumentElementRenderer() check if we fix background painting so that the RenderView
// paints the root's background.
- if (isRootLayer() || renderer().isRoot())
+ if (isRootLayer() || renderer().isDocumentElementRenderer())
return true;
- // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
- // can go ahead and return true.
- if (!renderer().isRenderInline()) {
- LayoutRect b = layerBounds;
- b.inflate(renderer().view().maximalOutlineSize());
- if (b.intersects(damageRect))
- return true;
- }
+ if (damageRect.isInfinite())
+ return true;
+ if (damageRect.isEmpty())
+ return false;
+
+ // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we can return true.
+ if (!renderer().isRenderInline() && layerBounds.intersects(damageRect))
+ return true;
+
+ RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment();
// When using regions, some boxes might have their frame rect relative to the flow thread, which could
// cause the paint rejection algorithm to prevent them from painting when using different width regions.
// e.g. an absolutely positioned box with bottom:0px and right:0px would have it's frameRect.x relative
// to the flow thread, not the last region (in which it will end up because of bottom:0px)
- if (region && renderer().flowThreadContainingBlock()) {
- LayoutRect b = layerBounds;
- b.moveBy(region->visualOverflowRectForBox(toRenderBoxModelObject(&renderer())).location());
- b.inflate(renderer().view().maximalOutlineSize());
- if (b.intersects(damageRect))
+ if (namedFlowFragment && renderer().flowThreadContainingBlock()) {
+ LayoutRect adjustedBounds = layerBounds;
+ adjustedBounds.moveBy(namedFlowFragment->visualOverflowRectForBox(downcast<RenderBoxModelObject>(renderer())).location());
+ if (adjustedBounds.intersects(damageRect))
return true;
}
-
+
// Otherwise we need to compute the bounding box of this single layer and see if it intersects
- // the damage rect.
- return boundingBox(rootLayer, 0, offsetFromRoot).intersects(damageRect);
+ // the damage rect. It's possible the fragment computed the bounding box already, in which case we
+ // can use the cached value.
+ if (cachedBoundingBox)
+ return cachedBoundingBox->intersects(damageRect);
+
+ return boundingBox(rootLayer, offsetFromRoot).intersects(damageRect);
}
LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const
@@ -5688,10 +5880,10 @@ LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const
// as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
// floats.
LayoutRect result;
- if (renderer().isInline() && renderer().isRenderInline())
- result = toRenderInline(renderer()).linesVisualOverflowBoundingBox();
- else if (renderer().isTableRow()) {
- RenderTableRow& tableRow = toRenderTableRow(renderer());
+ if (renderer().isInline() && is<RenderInline>(renderer()))
+ result = downcast<RenderInline>(renderer()).linesVisualOverflowBoundingBox();
+ else if (is<RenderTableRow>(renderer())) {
+ auto& tableRow = downcast<RenderTableRow>(renderer());
// Our bounding box is just the union of all of our cells' border/overflow rects.
for (RenderTableCell* cell = tableRow.firstCell(); cell; cell = cell->nextCell()) {
LayoutRect bbox = cell->borderBoxRect();
@@ -5704,7 +5896,7 @@ LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const
RenderBox* box = renderBox();
ASSERT(box);
if (!(flags & DontConstrainForMask) && box->hasMask()) {
- result = box->maskClipRect();
+ result = box->maskClipRect(LayoutPoint());
box->flipForWritingMode(result); // The mask clip rect is in physical coordinates, so we have to flip, since localBoundingBox is not.
} else {
LayoutRect bbox = box->borderBoxRect();
@@ -5714,54 +5906,79 @@ LayoutRect RenderLayer::localBoundingBox(CalculateLayerBoundsFlags flags) const
result.unite(overflowRect);
}
}
-
- result.inflate(renderer().view().maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
return result;
}
-LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags flags, const LayoutPoint* offsetFromRoot) const
+LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer, const LayoutSize& offsetFromRoot, CalculateLayerBoundsFlags flags) const
{
LayoutRect result = localBoundingBox(flags);
- if (renderer().isBox())
- renderBox()->flipForWritingMode(result);
- else
- renderer().containingBlock()->flipForWritingMode(result);
+ if (renderer().view().frameView().hasFlippedBlockRenderers()) {
+ if (renderer().isBox())
+ renderBox()->flipForWritingMode(result);
+ else
+ renderer().containingBlock()->flipForWritingMode(result);
+ }
+
+ PaginationInclusionMode inclusionMode = ExcludeCompositedPaginatedLayers;
+ if (flags & UseFragmentBoxesIncludingCompositing)
+ inclusionMode = IncludeCompositedPaginatedLayers;
- if (enclosingPaginationLayer() && (flags & UseFragmentBoxes)) {
+ const RenderLayer* paginationLayer = nullptr;
+ if (flags & UseFragmentBoxesExcludingCompositing || flags & UseFragmentBoxesIncludingCompositing)
+ paginationLayer = enclosingPaginationLayerInSubtree(ancestorLayer, inclusionMode);
+
+ const RenderLayer* childLayer = this;
+ bool isPaginated = paginationLayer;
+ while (paginationLayer) {
// Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
// get our true bounding box.
- LayoutPoint offsetWithinPaginationLayer;
- convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginationLayer);
- result.moveBy(offsetWithinPaginationLayer);
+ result.move(childLayer->offsetFromAncestor(paginationLayer));
- RenderFlowThread& enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());
+ auto& enclosingFlowThread = downcast<RenderFlowThread>(paginationLayer->renderer());
result = enclosingFlowThread.fragmentsBoundingBox(result);
- LayoutPoint delta;
- if (offsetFromRoot)
- delta = *offsetFromRoot;
- else
- enclosingPaginationLayer()->convertToLayerCoords(ancestorLayer, delta);
- result.moveBy(delta);
- return result;
+ childLayer = paginationLayer;
+ paginationLayer = paginationLayer->parent()->enclosingPaginationLayerInSubtree(ancestorLayer, inclusionMode);
}
- LayoutPoint delta;
- if (offsetFromRoot)
- delta = *offsetFromRoot;
- else
- convertToLayerCoords(ancestorLayer, delta);
+ if (isPaginated) {
+ result.move(childLayer->offsetFromAncestor(ancestorLayer));
+ return result;
+ }
- result.moveBy(delta);
+ result.move(offsetFromRoot);
return result;
}
+bool RenderLayer::getOverlapBoundsIncludingChildrenAccountingForTransformAnimations(LayoutRect& bounds) const
+{
+ // The animation will override the display transform, so don't include it.
+ CalculateLayerBoundsFlags boundsFlags = DefaultCalculateLayerBoundsFlags & ~IncludeSelfTransform;
+
+ bounds = calculateLayerBounds(this, LayoutSize(), boundsFlags);
+
+ LayoutRect animatedBounds = bounds;
+ if (renderer().animation().computeExtentOfAnimation(renderer(), animatedBounds)) {
+ bounds = animatedBounds;
+ return true;
+ }
+
+ return false;
+}
+
IntRect RenderLayer::absoluteBoundingBox() const
{
- return pixelSnappedIntRect(boundingBox(root()));
+ const RenderLayer* rootLayer = root();
+ return snappedIntRect(boundingBox(rootLayer, offsetFromAncestor(rootLayer)));
}
-LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot, CalculateLayerBoundsFlags flags) const
+FloatRect RenderLayer::absoluteBoundingBoxForPainting() const
+{
+ const RenderLayer* rootLayer = root();
+ return snapRectToDevicePixels(boundingBox(rootLayer, offsetFromAncestor(rootLayer)), renderer().document().deviceScaleFactor());
+}
+
+LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutSize& offsetFromRoot, CalculateLayerBoundsFlags flags) const
{
if (!isSelfPaintingLayer())
return LayoutRect();
@@ -5776,13 +5993,14 @@ LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, c
}
LayoutRect boundingBoxRect = localBoundingBox(flags);
+ if (renderer().view().frameView().hasFlippedBlockRenderers()) {
+ if (is<RenderBox>(renderer()))
+ downcast<RenderBox>(renderer()).flipForWritingMode(boundingBoxRect);
+ else
+ renderer().containingBlock()->flipForWritingMode(boundingBoxRect);
+ }
- if (renderer().isBox())
- toRenderBox(renderer()).flipForWritingMode(boundingBoxRect);
- else
- renderer().containingBlock()->flipForWritingMode(boundingBoxRect);
-
- if (renderer().isRoot()) {
+ if (renderer().isDocumentElementRenderer()) {
// If the root layer becomes composited (e.g. because some descendant with negative z-index is composited),
// then it has to be big enough to cover the viewport in order to display the background. This is akin
// to the code in RenderBox::paintRootBoxFillLayers().
@@ -5794,14 +6012,13 @@ LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, c
LayoutRect unionBounds = boundingBoxRect;
if (flags & UseLocalClipRectIfPossible) {
- LayoutRect localClipRect = this->localClipRect();
- if (localClipRect != LayoutRect::infiniteRect()) {
+ bool clipExceedsBounds = false;
+ LayoutRect localClipRect = this->localClipRect(clipExceedsBounds);
+ if (!localClipRect.isInfinite() && !clipExceedsBounds) {
if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehaviorNormal))
localClipRect = transform()->mapRect(localClipRect);
- LayoutPoint ancestorRelOffset;
- convertToLayerCoords(ancestorLayer, ancestorRelOffset);
- localClipRect.moveBy(ancestorRelOffset);
+ localClipRect.move(offsetFromAncestor(ancestorLayer));
return localClipRect;
}
}
@@ -5813,7 +6030,7 @@ LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, c
if (RenderLayer* reflection = reflectionLayer()) {
if (!reflection->isComposited()) {
- LayoutRect childUnionBounds = reflection->calculateLayerBounds(this, 0, descendantFlags);
+ LayoutRect childUnionBounds = reflection->calculateLayerBounds(this, reflection->offsetFromAncestor(this), descendantFlags);
unionBounds.unite(childUnionBounds);
}
}
@@ -5824,64 +6041,50 @@ LayoutRect RenderLayer::calculateLayerBounds(const RenderLayer* ancestorLayer, c
LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(this));
#endif
+ auto computeLayersUnion = [this, &unionBounds, flags, descendantFlags] (const RenderLayer& childLayer) {
+ if (!(flags & IncludeCompositedDescendants) && childLayer.isComposited())
+ return;
+ LayoutRect childBounds = childLayer.calculateLayerBounds(this, childLayer.offsetFromAncestor(this), descendantFlags);
+ // Ignore child layer (and behave as if we had overflow: hidden) when it is positioned off the parent layer so much
+ // that we hit the max LayoutUnit value.
+ unionBounds.checkedUnite(childBounds);
+ };
+
if (Vector<RenderLayer*>* negZOrderList = this->negZOrderList()) {
- size_t listSize = negZOrderList->size();
- for (size_t i = 0; i < listSize; ++i) {
- RenderLayer* curLayer = negZOrderList->at(i);
- if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
- LayoutRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
- unionBounds.unite(childUnionBounds);
- }
- }
+ for (auto* childLayer : *negZOrderList)
+ computeLayersUnion(*childLayer);
}
if (Vector<RenderLayer*>* posZOrderList = this->posZOrderList()) {
- size_t listSize = posZOrderList->size();
- for (size_t i = 0; i < listSize; ++i) {
- RenderLayer* curLayer = posZOrderList->at(i);
+ for (auto* childLayer : *posZOrderList) {
// The RenderNamedFlowThread is ignored when we calculate the bounds of the RenderView.
- if ((flags & IncludeCompositedDescendants || !curLayer->isComposited()) && !curLayer->isFlowThreadCollectingGraphicsLayersUnderRegions()) {
- LayoutRect childUnionBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
- unionBounds.unite(childUnionBounds);
- }
+ if (childLayer->isFlowThreadCollectingGraphicsLayersUnderRegions())
+ continue;
+ computeLayersUnion(*childLayer);
}
}
if (Vector<RenderLayer*>* normalFlowList = this->normalFlowList()) {
- size_t listSize = normalFlowList->size();
- for (size_t i = 0; i < listSize; ++i) {
- RenderLayer* curLayer = normalFlowList->at(i);
+ for (auto* childLayer : *normalFlowList) {
// RenderView will always return the size of the document, before reaching this point,
// so there's no way we could hit a RenderNamedFlowThread here.
- ASSERT(!curLayer->isFlowThreadCollectingGraphicsLayersUnderRegions());
- if (flags & IncludeCompositedDescendants || !curLayer->isComposited()) {
- LayoutRect curAbsBounds = curLayer->calculateLayerBounds(this, 0, descendantFlags);
- unionBounds.unite(curAbsBounds);
- }
+ ASSERT(!childLayer->isFlowThreadCollectingGraphicsLayersUnderRegions());
+ computeLayersUnion(*childLayer);
}
}
-
-#if ENABLE(CSS_FILTERS)
+
// FIXME: We can optimize the size of the composited layers, by not enlarging
// filtered areas with the outsets if we know that the filter is going to render in hardware.
// https://bugs.webkit.org/show_bug.cgi?id=81239
if (flags & IncludeLayerFilterOutsets)
renderer().style().filterOutsets().expandRect(unionBounds);
-#endif
if ((flags & IncludeSelfTransform) && paintsWithTransform(PaintBehaviorNormal)) {
TransformationMatrix* affineTrans = transform();
boundingBoxRect = affineTrans->mapRect(boundingBoxRect);
unionBounds = affineTrans->mapRect(unionBounds);
}
-
- LayoutPoint ancestorRelOffset;
- if (offsetFromRoot)
- ancestorRelOffset = *offsetFromRoot;
- else
- convertToLayerCoords(ancestorLayer, ancestorRelOffset);
- unionBounds.moveBy(ancestorRelOffset);
-
+ unionBounds.move(offsetFromRoot);
return unionBounds;
}
@@ -5903,42 +6106,30 @@ void RenderLayer::clearClipRects(ClipRectsType typeToClear)
m_clipRectsCache = nullptr;
else {
ASSERT(typeToClear < NumCachedClipRectsTypes);
- RefPtr<ClipRects> dummy;
- m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, dummy);
- m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, dummy);
+ m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, nullptr);
+ m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, nullptr);
}
}
-#if USE(ACCELERATED_COMPOSITING)
-
RenderLayerBacking* RenderLayer::ensureBacking()
{
if (!m_backing) {
- m_backing = adoptPtr(new RenderLayerBacking(*this));
+ m_backing = std::make_unique<RenderLayerBacking>(*this);
compositor().layerBecameComposited(*this);
-#if ENABLE(CSS_FILTERS)
updateOrRemoveFilterEffectRenderer();
-#endif
-#if ENABLE(CSS_COMPOSITING)
- backing()->setBlendMode(m_blendMode);
-#endif
}
return m_backing.get();
}
void RenderLayer::clearBacking(bool layerBeingDestroyed)
{
- if (m_backing && !renderer().documentBeingDestroyed())
+ if (m_backing && !renderer().renderTreeBeingDestroyed())
compositor().layerBecameNonComposited(*this);
- m_backing.clear();
+ m_backing = nullptr;
-#if ENABLE(CSS_FILTERS)
if (!layerBeingDestroyed)
updateOrRemoveFilterEffectRenderer();
-#else
- UNUSED_PARAM(layerBeingDestroyed);
-#endif
}
bool RenderLayer::hasCompositedMask() const
@@ -5948,36 +6139,54 @@ bool RenderLayer::hasCompositedMask() const
GraphicsLayer* RenderLayer::layerForScrolling() const
{
- return m_backing ? m_backing->scrollingContentsLayer() : 0;
+ return m_backing ? m_backing->scrollingContentsLayer() : nullptr;
}
GraphicsLayer* RenderLayer::layerForHorizontalScrollbar() const
{
- return m_backing ? m_backing->layerForHorizontalScrollbar() : 0;
+ return m_backing ? m_backing->layerForHorizontalScrollbar() : nullptr;
}
GraphicsLayer* RenderLayer::layerForVerticalScrollbar() const
{
- return m_backing ? m_backing->layerForVerticalScrollbar() : 0;
+ return m_backing ? m_backing->layerForVerticalScrollbar() : nullptr;
}
GraphicsLayer* RenderLayer::layerForScrollCorner() const
{
- return m_backing ? m_backing->layerForScrollCorner() : 0;
+ return m_backing ? m_backing->layerForScrollCorner() : nullptr;
}
-#endif
-
bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const
{
-#if USE(ACCELERATED_COMPOSITING)
bool paintsToWindow = !isComposited() || backing()->paintsIntoWindow();
-#else
- bool paintsToWindow = true;
-#endif
return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || paintsToWindow);
}
+bool RenderLayer::shouldPaintMask(PaintBehavior paintBehavior, PaintLayerFlags paintFlags) const
+{
+ if (!renderer().hasMask())
+ return false;
+
+ bool paintsToWindow = !isComposited() || backing()->paintsIntoWindow();
+ if (paintsToWindow || (paintBehavior & PaintBehaviorFlattenCompositingLayers))
+ return true;
+
+ return (paintFlags & PaintLayerPaintingCompositingMaskPhase);
+}
+
+bool RenderLayer::shouldApplyClipPath(PaintBehavior paintBehavior, PaintLayerFlags paintFlags) const
+{
+ if (!renderer().hasClipPath())
+ return false;
+
+ bool paintsToWindow = !isComposited() || backing()->paintsIntoWindow();
+ if (paintsToWindow || (paintBehavior & PaintBehaviorFlattenCompositingLayers))
+ return true;
+
+ return (paintFlags & PaintLayerPaintingCompositingClipPathPhase);
+}
+
bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
{
if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
@@ -5986,15 +6195,19 @@ bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect)
if (paintsWithTransparency(PaintBehaviorNormal))
return false;
+ if (renderer().isDocumentElementRenderer()) {
+ // Normally the document element doens't have a layer. If it does have a layer, its background propagates to the RenderView
+ // so this layer doesn't draw it.
+ return false;
+ }
+
// We can't use hasVisibleContent(), because that will be true if our renderer is hidden, but some child
// is visible and that child doesn't cover the entire rect.
if (renderer().style().visibility() != VISIBLE)
return false;
-#if ENABLE(CSS_FILTERS)
if (paintsWithFilters() && renderer().style().filter().hasFilterThatAffectsOpacity())
return false;
-#endif
// FIXME: Handle simple transforms.
if (paintsWithTransform(PaintBehaviorNormal))
@@ -6006,6 +6219,10 @@ bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect)
if (m_zOrderListsDirty || m_normalFlowListDirty)
return false;
+ // Table painting is special; a table paints its sections.
+ if (renderer().isTablePart())
+ return false;
+
// FIXME: We currently only check the immediate renderer,
// which will miss many cases.
if (renderer().backgroundIsKnownToBeOpaqueInRect(localRect))
@@ -6026,7 +6243,7 @@ bool RenderLayer::listBackgroundIsKnownToBeOpaqueInRect(const Vector<RenderLayer
if (!list || list->isEmpty())
return false;
- for (Vector<RenderLayer*>::const_reverse_iterator iter = list->rbegin(); iter != list->rend(); ++iter) {
+ for (auto iter = list->rbegin(); iter != list->rend(); ++iter) {
const RenderLayer* childLayer = *iter;
if (childLayer->isComposited())
continue;
@@ -6034,10 +6251,8 @@ bool RenderLayer::listBackgroundIsKnownToBeOpaqueInRect(const Vector<RenderLayer
if (!childLayer->canUseConvertToLayerCoords())
continue;
- LayoutPoint childOffset;
LayoutRect childLocalRect(localRect);
- childLayer->convertToLayerCoords(this, childOffset);
- childLocalRect.moveBy(-childOffset);
+ childLocalRect.move(-childLayer->offsetFromAncestor(this));
if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
return true;
@@ -6050,17 +6265,13 @@ void RenderLayer::setParent(RenderLayer* parent)
if (parent == m_parent)
return;
-#if USE(ACCELERATED_COMPOSITING)
- if (m_parent && !renderer().documentBeingDestroyed())
+ if (m_parent && !renderer().renderTreeBeingDestroyed())
compositor().layerWillBeRemoved(*m_parent, *this);
-#endif
m_parent = parent;
-
-#if USE(ACCELERATED_COMPOSITING)
- if (m_parent && !renderer().documentBeingDestroyed())
+
+ if (m_parent && !renderer().renderTreeBeingDestroyed())
compositor().layerWasAdded(*m_parent, *this);
-#endif
}
void RenderLayer::dirtyZOrderLists()
@@ -6074,15 +6285,13 @@ void RenderLayer::dirtyZOrderLists()
m_negZOrderList->clear();
m_zOrderListsDirty = true;
-#if USE(ACCELERATED_COMPOSITING)
- if (!renderer().documentBeingDestroyed()) {
+ if (!renderer().renderTreeBeingDestroyed()) {
if (isFlowThreadCollectingGraphicsLayersUnderRegions())
- toRenderFlowThread(renderer()).setNeedsLayerToRegionMappingsUpdate();
+ downcast<RenderFlowThread>(renderer()).setNeedsLayerToRegionMappingsUpdate();
compositor().setCompositingLayersNeedRebuild();
if (acceleratedCompositingForOverflowScrollEnabled())
compositor().setShouldReevaluateCompositingAfterLayout();
}
-#endif
}
void RenderLayer::dirtyStackingContainerZOrderLists()
@@ -6100,15 +6309,13 @@ void RenderLayer::dirtyNormalFlowList()
m_normalFlowList->clear();
m_normalFlowListDirty = true;
-#if USE(ACCELERATED_COMPOSITING)
- if (!renderer().documentBeingDestroyed()) {
+ if (!renderer().renderTreeBeingDestroyed()) {
if (isFlowThreadCollectingGraphicsLayersUnderRegions())
- toRenderFlowThread(renderer()).setNeedsLayerToRegionMappingsUpdate();
+ downcast<RenderFlowThread>(renderer()).setNeedsLayerToRegionMappingsUpdate();
compositor().setCompositingLayersNeedRebuild();
if (acceleratedCompositingForOverflowScrollEnabled())
compositor().setShouldReevaluateCompositingAfterLayout();
}
-#endif
}
void RenderLayer::rebuildZOrderLists()
@@ -6119,13 +6326,9 @@ void RenderLayer::rebuildZOrderLists()
m_zOrderListsDirty = false;
}
-void RenderLayer::rebuildZOrderLists(CollectLayersBehavior behavior, OwnPtr<Vector<RenderLayer*>>& posZOrderList, OwnPtr<Vector<RenderLayer*>>& negZOrderList)
+void RenderLayer::rebuildZOrderLists(CollectLayersBehavior behavior, std::unique_ptr<Vector<RenderLayer*>>& posZOrderList, std::unique_ptr<Vector<RenderLayer*>>& negZOrderList)
{
-#if USE(ACCELERATED_COMPOSITING)
bool includeHiddenLayers = compositor().inCompositingMode();
-#else
- bool includeHiddenLayers = false;
-#endif
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
if (!m_reflection || reflectionLayer() != child)
child->collectLayers(includeHiddenLayers, behavior, posZOrderList, negZOrderList);
@@ -6149,7 +6352,7 @@ void RenderLayer::updateNormalFlowList()
// Ignore non-overflow layers and reflections.
if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) {
if (!m_normalFlowList)
- m_normalFlowList = adoptPtr(new Vector<RenderLayer*>);
+ m_normalFlowList = std::make_unique<Vector<RenderLayer*>>();
m_normalFlowList->append(child);
}
}
@@ -6157,7 +6360,7 @@ void RenderLayer::updateNormalFlowList()
m_normalFlowListDirty = false;
}
-void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior behavior, OwnPtr<Vector<RenderLayer*>>& posBuffer, OwnPtr<Vector<RenderLayer*>>& negBuffer)
+void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior behavior, std::unique_ptr<Vector<RenderLayer*>>& posBuffer, std::unique_ptr<Vector<RenderLayer*>>& negBuffer)
{
updateDescendantDependentFlags();
@@ -6166,11 +6369,11 @@ void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior
bool includeHiddenLayer = includeHiddenLayers || (m_hasVisibleContent || (m_hasVisibleDescendant && isStacking));
if (includeHiddenLayer && !isNormalFlowOnly()) {
// Determine which buffer the child should be in.
- OwnPtr<Vector<RenderLayer*>>& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
+ std::unique_ptr<Vector<RenderLayer*>>& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
// Create the buffer if it doesn't exist yet.
if (!buffer)
- buffer = adoptPtr(new Vector<RenderLayer*>);
+ buffer = std::make_unique<Vector<RenderLayer*>>();
// Append ourselves at the end of the appropriate buffer.
buffer->append(this);
@@ -6189,7 +6392,7 @@ void RenderLayer::collectLayers(bool includeHiddenLayers, CollectLayersBehavior
void RenderLayer::updateLayerListsIfNeeded()
{
- bool shouldUpdateDescendantsAreContiguousInStackingOrder = isStackingContext() && (m_zOrderListsDirty || m_normalFlowListDirty);
+ bool shouldUpdateDescendantsAreContiguousInStackingOrder = (m_zOrderListsDirty || m_normalFlowListDirty) && isStackingContext();
updateZOrderLists();
updateNormalFlowList();
@@ -6213,37 +6416,25 @@ void RenderLayer::updateDescendantsLayerListsIfNeeded(bool recursive)
if (isStackingContainer()) {
if (Vector<RenderLayer*>* list = negZOrderList()) {
- size_t listSize = list->size();
- for (size_t i = 0; i < listSize; ++i) {
- RenderLayer* childLayer = list->at(i);
+ for (auto* childLayer : *list)
layersToUpdate.append(childLayer);
- }
}
}
if (Vector<RenderLayer*>* list = normalFlowList()) {
- size_t listSize = list->size();
- for (size_t i = 0; i < listSize; ++i) {
- RenderLayer* childLayer = list->at(i);
+ for (auto* childLayer : *list)
layersToUpdate.append(childLayer);
- }
}
if (isStackingContainer()) {
if (Vector<RenderLayer*>* list = posZOrderList()) {
- size_t listSize = list->size();
- for (size_t i = 0; i < listSize; ++i) {
- RenderLayer* childLayer = list->at(i);
+ for (auto* childLayer : *list)
layersToUpdate.append(childLayer);
- }
}
}
- size_t listSize = layersToUpdate.size();
- for (size_t i = 0; i < listSize; ++i) {
- RenderLayer* childLayer = layersToUpdate.at(i);
+ for (auto* childLayer : layersToUpdate) {
childLayer->updateLayerListsIfNeeded();
-
if (recursive)
childLayer->updateDescendantsLayerListsIfNeeded(true);
}
@@ -6251,33 +6442,30 @@ void RenderLayer::updateDescendantsLayerListsIfNeeded(bool recursive)
void RenderLayer::updateCompositingAndLayerListsIfNeeded()
{
-#if USE(ACCELERATED_COMPOSITING)
if (compositor().inCompositingMode()) {
if (isDirtyStackingContainer() || m_normalFlowListDirty)
compositor().updateCompositingLayers(CompositingUpdateOnHitTest, this);
return;
}
-#endif
+
updateLayerListsIfNeeded();
}
void RenderLayer::repaintIncludingDescendants()
{
renderer().repaint();
- for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
- curr->repaintIncludingDescendants();
+ for (RenderLayer* current = firstChild(); current; current = current->nextSibling())
+ current->repaintIncludingDescendants();
// If this is a region, we must also repaint the flow thread's layer since it is the one
// doing the actual painting of the flowed content, but only if the region is valid.
if (renderer().isRenderNamedFlowFragmentContainer()) {
- RenderNamedFlowFragment* region = toRenderBlockFlow(renderer()).renderNamedFlowFragment();
- if (region->isValid())
- region->flowThread()->layer()->repaintIncludingDescendants();
+ RenderNamedFlowFragment& region = *downcast<RenderBlockFlow>(renderer()).renderNamedFlowFragment();
+ if (region.isValid())
+ region.flowThread()->layer()->repaintIncludingDescendants();
}
}
-#if USE(ACCELERATED_COMPOSITING)
-
void RenderLayer::setBackingNeedsRepaint(GraphicsLayer::ShouldClipToLayer shouldClip)
{
ASSERT(isComposited());
@@ -6298,19 +6486,17 @@ void RenderLayer::setBackingNeedsRepaintInRect(const LayoutRect& r, GraphicsLaye
// If we're trying to repaint the placeholder document layer, propagate the
// repaint to the native view system.
LayoutRect absRect(r);
- LayoutPoint delta;
- convertToLayerCoords(root(), delta);
- absRect.moveBy(delta);
+ absRect.move(offsetFromAncestor(root()));
renderer().view().repaintViewRectangle(absRect);
} else
- backing()->setContentsNeedDisplayInRect(pixelSnappedIntRect(r), shouldClip);
+ backing()->setContentsNeedDisplayInRect(r, shouldClip);
}
// Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
void RenderLayer::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer)
{
- renderer().repaintUsingContainer(repaintContainer, pixelSnappedIntRect(renderer().clippedOverflowRectForRepaint(repaintContainer)));
+ renderer().repaintUsingContainer(repaintContainer, renderer().clippedOverflowRectForRepaint(repaintContainer));
for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) {
if (!curr->isComposited())
@@ -6318,48 +6504,56 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderLayerModelObje
}
}
+static bool createsStackingContext(const RenderLayer& layer)
+{
+ auto& renderer = layer.renderer();
+ return renderer.hasTransformRelatedProperty()
+ || renderer.hasClipPath()
+ || renderer.hasFilter()
+ || renderer.hasMask()
+ || renderer.hasBackdropFilter()
+#if ENABLE(CSS_COMPOSITING)
+ || renderer.hasBlendMode()
+#endif
+ || renderer.isTransparent()
+ || renderer.isPositioned()
+ || renderer.style().hasFlowFrom()
+ || renderer.hasReflection()
+ || renderer.style().hasIsolation()
+ || layer.needsCompositedScrolling()
+#if PLATFORM(IOS)
+ || layer.hasAcceleratedTouchScrolling()
#endif
+ || (renderer.style().willChange() && renderer.style().willChange()->canCreateStackingContext());
+}
bool RenderLayer::shouldBeNormalFlowOnly() const
{
- return (renderer().hasOverflowClip()
- || renderer().hasReflection()
- || renderer().hasMask()
+ if (createsStackingContext(*this))
+ return false;
+
+ return renderer().hasOverflowClip()
|| renderer().isCanvas()
|| renderer().isVideo()
|| renderer().isEmbeddedObject()
|| renderer().isRenderIFrame()
- || (renderer().style().specifiesColumns() && !isRootLayer()))
- && !renderer().isPositioned()
- && !renderer().hasTransform()
- && !renderer().hasClipPath()
-#if ENABLE(CSS_FILTERS)
- && !renderer().hasFilter()
-#endif
-#if PLATFORM(IOS)
- && !hasAcceleratedTouchScrolling()
-#endif
-#if ENABLE(CSS_COMPOSITING)
- && !renderer().hasBlendMode()
-#endif
- && !isTransparent()
- && !needsCompositedScrolling()
- && !renderer().style().hasFlowFrom()
- ;
+ || (renderer().style().specifiesColumns() && !isRootLayer())
+ || renderer().isInFlowRenderFlowThread();
}
bool RenderLayer::shouldBeSelfPaintingLayer() const
{
- return !isNormalFlowOnly()
- || hasOverlayScrollbars()
+ if (!isNormalFlowOnly())
+ return true;
+
+ return hasOverlayScrollbars()
|| needsCompositedScrolling()
- || renderer().hasReflection()
- || renderer().hasMask()
|| renderer().isTableRow()
|| renderer().isCanvas()
|| renderer().isVideo()
|| renderer().isEmbeddedObject()
- || renderer().isRenderIFrame();
+ || renderer().isRenderIFrame()
+ || renderer().isInFlowRenderFlowThread();
}
void RenderLayer::updateSelfPaintingLayer()
@@ -6377,33 +6571,66 @@ void RenderLayer::updateSelfPaintingLayer()
parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
}
-bool RenderLayer::hasNonEmptyChildRenderers() const
+static bool hasVisibleBoxDecorationsOrBackground(const RenderElement& renderer)
+{
+ return renderer.hasVisibleBoxDecorations() || renderer.style().hasOutline();
+}
+
+// Constrain the depth and breadth of the search for performance.
+static const int maxDescendentDepth = 3;
+static const int maxSiblingCount = 20;
+
+static bool hasPaintingNonLayerDescendants(const RenderElement& renderer, int depth)
{
- // Some HTML can cause whitespace text nodes to have renderers, like:
- // <div>
- // <img src=...>
- // </div>
- // so test for 0x0 RenderTexts here
- for (RenderObject* child = renderer().firstChild(); child; child = child->nextSibling()) {
- if (!child->hasLayer()) {
- if (child->isRenderInline() || !child->isBox())
+ if (depth > maxDescendentDepth)
+ return true;
+
+ int siblingCount = 0;
+ for (const auto& child : childrenOfType<RenderObject>(renderer)) {
+ if (++siblingCount > maxSiblingCount)
+ return true;
+
+ if (is<RenderText>(child)) {
+ const auto& renderText = downcast<RenderText>(child);
+ if (renderText.linesBoundingBox().isEmpty())
+ continue;
+
+ if (renderer.style().userSelect() != SELECT_NONE)
return true;
-
- if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0)
+
+ if (!renderText.text()->containsOnlyWhitespace())
return true;
}
+
+ if (!is<RenderElement>(child))
+ continue;
+
+ const RenderElement& renderElementChild = downcast<RenderElement>(child);
+
+ if (is<RenderLayerModelObject>(renderElementChild) && downcast<RenderLayerModelObject>(renderElementChild).hasSelfPaintingLayer())
+ continue;
+
+ if (hasVisibleBoxDecorationsOrBackground(renderElementChild))
+ return true;
+
+ if (is<RenderReplaced>(renderElementChild))
+ return true;
+
+ if (hasPaintingNonLayerDescendants(renderElementChild, depth + 1))
+ return true;
}
+
return false;
}
-static bool hasBoxDecorations(const RenderStyle& style)
+bool RenderLayer::hasNonEmptyChildRenderers() const
{
- return style.hasBorder() || style.hasBorderRadius() || style.hasOutline() || style.hasAppearance() || style.boxShadow() || style.hasFilter();
+ return hasPaintingNonLayerDescendants(renderer(), 0);
}
-bool RenderLayer::hasBoxDecorationsOrBackground() const
+bool RenderLayer::hasVisibleBoxDecorationsOrBackground() const
{
- return hasBoxDecorations(renderer().style()) || renderer().hasBackground();
+ return WebCore::hasVisibleBoxDecorationsOrBackground(renderer());
}
bool RenderLayer::hasVisibleBoxDecorations() const
@@ -6411,20 +6638,23 @@ bool RenderLayer::hasVisibleBoxDecorations() const
if (!hasVisibleContent())
return false;
- return hasBoxDecorationsOrBackground() || hasOverflowControls();
+ return hasVisibleBoxDecorationsOrBackground() || hasOverflowControls();
}
bool RenderLayer::isVisuallyNonEmpty() const
{
ASSERT(!m_visibleDescendantStatusDirty);
- if (hasVisibleContent() && hasNonEmptyChildRenderers())
- return true;
+ if (!hasVisibleContent() || !renderer().style().opacity())
+ return false;
- if (renderer().isReplaced() || renderer().hasMask())
+ if (renderer().isRenderReplaced() || hasOverflowControls())
return true;
- if (hasVisibleBoxDecorations())
+ if (hasVisibleBoxDecorationsOrBackground())
+ return true;
+
+ if (hasNonEmptyChildRenderers())
return true;
return false;
@@ -6443,6 +6673,21 @@ void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldS
dirtyZOrderLists();
else
clearZOrderLists();
+
+#if ENABLE(CSS_COMPOSITING)
+ if (parent()) {
+ if (isStackingContext) {
+ if (!hasNotIsolatedBlendingDescendantsStatusDirty() && hasNotIsolatedBlendingDescendants())
+ parent()->dirtyAncestorChainHasBlendingDescendants();
+ } else {
+ if (hasNotIsolatedBlendingDescendantsStatusDirty())
+ parent()->dirtyAncestorChainHasBlendingDescendants();
+ else if (hasNotIsolatedBlendingDescendants())
+ parent()->updateAncestorChainHasBlendingDescendants();
+ }
+ }
+#endif
+
return;
}
@@ -6455,16 +6700,6 @@ void RenderLayer::updateStackingContextsAfterStyleChange(const RenderStyle* oldS
}
}
-static bool overflowRequiresScrollbar(EOverflow overflow)
-{
- return overflow == OSCROLL;
-}
-
-static bool overflowDefinesAutomaticScrollbar(EOverflow overflow)
-{
- return overflow == OAUTO || overflow == OOVERLAY;
-}
-
void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle)
{
// Overflow are a box concept.
@@ -6480,22 +6715,18 @@ void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle)
EOverflow overflowY = box->style().overflowY();
// To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep any automatic scrollbar that was already present.
- bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefinesAutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX);
- bool needsVerticalScrollbar = (hasVerticalScrollbar() && overflowDefinesAutomaticScrollbar(overflowY)) || overflowRequiresScrollbar(overflowY);
+ bool needsHorizontalScrollbar = box->hasOverflowClip() && ((hasHorizontalScrollbar() && styleDefinesAutomaticScrollbar(box->style(), HorizontalScrollbar)) || styleRequiresScrollbar(box->style(), HorizontalScrollbar));
+ bool needsVerticalScrollbar = box->hasOverflowClip() && ((hasVerticalScrollbar() && styleDefinesAutomaticScrollbar(box->style(), VerticalScrollbar)) || styleRequiresScrollbar(box->style(), VerticalScrollbar));
setHasHorizontalScrollbar(needsHorizontalScrollbar);
setHasVerticalScrollbar(needsVerticalScrollbar);
- // With overflow: scroll, scrollbars are always visible but may be disabled.
+ // With non-overlay overflow:scroll, scrollbars are always visible but may be disabled.
// When switching to another value, we need to re-enable them (see bug 11985).
- if (needsHorizontalScrollbar && oldStyle && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL) {
- ASSERT(hasHorizontalScrollbar());
+ if (m_hBar && needsHorizontalScrollbar && oldStyle && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL)
m_hBar->setEnabled(true);
- }
- if (needsVerticalScrollbar && oldStyle && oldStyle->overflowY() == OSCROLL && overflowY != OSCROLL) {
- ASSERT(hasVerticalScrollbar());
+ if (m_vBar && needsVerticalScrollbar && oldStyle && oldStyle->overflowY() == OSCROLL && overflowY != OSCROLL)
m_vBar->setEnabled(true);
- }
if (!m_scrollDimensionsDirty)
updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
@@ -6509,9 +6740,7 @@ void RenderLayer::setAncestorChainHasOutOfFlowPositionedDescendant(RenderBlock*
layer->m_hasOutOfFlowPositionedDescendantDirty = false;
layer->m_hasOutOfFlowPositionedDescendant = true;
-#if USE(ACCELERATED_COMPOSITING)
layer->updateNeedsCompositedScrolling();
-#endif
if (&layer->renderer() == containingBlock)
break;
@@ -6530,29 +6759,11 @@ void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle)
bool wasOutOfFlowPositioned = oldStyle && (oldStyle->position() == AbsolutePosition || oldStyle->position() == FixedPosition);
if (parent() && (renderer().isOutOfFlowPositioned() != wasOutOfFlowPositioned)) {
parent()->dirtyAncestorChainHasOutOfFlowPositionedDescendantStatus();
-#if USE(ACCELERATED_COMPOSITING)
- if (!renderer().documentBeingDestroyed() && acceleratedCompositingForOverflowScrollEnabled())
+ if (!renderer().renderTreeBeingDestroyed() && acceleratedCompositingForOverflowScrollEnabled())
compositor().setShouldReevaluateCompositingAfterLayout();
-#endif
}
}
-#if USE(ACCELERATED_COMPOSITING)
-
-inline bool RenderLayer::needsCompositingLayersRebuiltForClip(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
-{
- ASSERT(newStyle);
- return oldStyle && (oldStyle->clip() != newStyle->clip() || oldStyle->hasClip() != newStyle->hasClip());
-}
-
-inline bool RenderLayer::needsCompositingLayersRebuiltForOverflow(const RenderStyle* oldStyle, const RenderStyle* newStyle) const
-{
- ASSERT(newStyle);
- return !isComposited() && oldStyle && (oldStyle->overflowX() != newStyle->overflowX()) && stackingContainer()->hasCompositingDescendant();
-}
-
-#endif // USE(ACCELERATED_COMPOSITING)
-
void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
{
bool isNormalFlowOnly = shouldBeNormalFlowOnly();
@@ -6564,14 +6775,13 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
dirtyStackingContainerZOrderLists();
}
- if (renderer().style().overflowX() == OMARQUEE && renderer().style().marqueeBehavior() != MNONE && renderer().isBox()) {
+ if (renderer().isHTMLMarquee() && renderer().style().marqueeBehavior() != MNONE && renderer().isBox()) {
if (!m_marquee)
- m_marquee = adoptPtr(new RenderMarquee(this));
- FeatureObserver::observe(&renderer().document(), renderer().isHTMLMarquee() ? FeatureObserver::HTMLMarqueeElement : FeatureObserver::CSSOverflowMarquee);
+ m_marquee = std::make_unique<RenderMarquee>(this);
m_marquee->updateMarqueeStyle();
}
else if (m_marquee) {
- m_marquee.clear();
+ m_marquee = nullptr;
}
updateScrollbarsAfterStyleChange(oldStyle);
@@ -6588,7 +6798,6 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
createReflection();
else
m_reflection->setStyle(createReflectionStyle());
- FeatureObserver::observe(&renderer().document(), FeatureObserver::Reflection);
}
// FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
@@ -6605,33 +6814,13 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
#if ENABLE(CSS_COMPOSITING)
updateBlendMode();
#endif
-#if ENABLE(CSS_FILTERS)
updateOrRemoveFilterClients();
-#endif
-#if USE(ACCELERATED_COMPOSITING)
updateNeedsCompositedScrolling();
- const RenderStyle& newStyle = renderer().style();
- if (compositor().updateLayerCompositingState(*this)
- || needsCompositingLayersRebuiltForClip(oldStyle, &newStyle)
- || needsCompositingLayersRebuiltForOverflow(oldStyle, &newStyle))
- compositor().setCompositingLayersNeedRebuild();
- else if (isComposited())
- backing()->updateGraphicsLayerGeometry();
-
- if (oldStyle) {
- // Compositing layers keep track of whether they are clipped by any of the ancestors.
- // When the current layer's clipping behaviour changes, we need to propagate it to the descendants.
- const RenderStyle& style = renderer().style();
- bool wasClipping = oldStyle->hasClip() || oldStyle->overflowX() != OVISIBLE || oldStyle->overflowY() != OVISIBLE;
- bool isClipping = style.hasClip() || style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE;
- if (isClipping != wasClipping) {
- if (checkIfDescendantClippingContextNeedsUpdate(isClipping))
- compositor().setCompositingLayersNeedRebuild();
- }
- }
-#endif
+ compositor().layerStyleChanged(diff, *this, oldStyle);
+
+ updateOrRemoveFilterEffectRenderer();
#if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
if (diff == StyleDifferenceRecompositeLayer || diff >= StyleDifferenceLayoutPositionedMovementOnly)
@@ -6639,18 +6828,6 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
#else
UNUSED_PARAM(diff);
#endif
-
-#if ENABLE(CSS_FILTERS)
- updateOrRemoveFilterEffectRenderer();
-#if USE(ACCELERATED_COMPOSITING)
- bool backingDidCompositeLayers = isComposited() && backing()->canCompositeFilters();
- if (isComposited() && backingDidCompositeLayers && !backing()->canCompositeFilters()) {
- // The filters used to be drawn by platform code, but now the platform cannot draw them anymore.
- // Fallback to drawing them in software.
- setBackingNeedsRepaint();
- }
-#endif
-#endif
}
void RenderLayer::updateScrollableAreaSet(bool hasOverflow)
@@ -6663,18 +6840,23 @@ void RenderLayer::updateScrollableAreaSet(bool hasOverflow)
bool isScrollable = hasOverflow && isVisibleToHitTest;
bool addedOrRemoved = false;
- if (isScrollable)
- addedOrRemoved = frameView.addScrollableArea(this);
- else
+
+ ASSERT(m_registeredScrollableArea == frameView.containsScrollableArea(this));
+
+ if (isScrollable) {
+ if (!m_registeredScrollableArea) {
+ addedOrRemoved = frameView.addScrollableArea(this);
+ m_registeredScrollableArea = true;
+ }
+ } else if (m_registeredScrollableArea) {
addedOrRemoved = frameView.removeScrollableArea(this);
+ m_registeredScrollableArea = false;
+ }
- if (addedOrRemoved) {
-#if USE(ACCELERATED_COMPOSITING)
+ if (addedOrRemoved)
updateNeedsCompositedScrolling();
-#endif
- }
-#if PLATFORM(IOS)
+#if ENABLE(IOS_TOUCH_EVENTS)
if (addedOrRemoved) {
if (isScrollable && !hasAcceleratedTouchScrolling())
registerAsTouchEventListenerForScrolling();
@@ -6690,7 +6872,7 @@ void RenderLayer::updateScrollableAreaSet(bool hasOverflow)
void RenderLayer::updateScrollCornerStyle()
{
RenderElement* actualRenderer = rendererForScrollbar(renderer());
- RefPtr<RenderStyle> corner = renderer().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
+ auto corner = renderer().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), &actualRenderer->style()) : nullptr;
if (!corner) {
m_scrollCorner = nullptr;
@@ -6698,17 +6880,17 @@ void RenderLayer::updateScrollCornerStyle()
}
if (!m_scrollCorner) {
- m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer().document(), corner.releaseNonNull());
+ m_scrollCorner = createRenderer<RenderScrollbarPart>(renderer().document(), WTFMove(*corner));
m_scrollCorner->setParent(&renderer());
m_scrollCorner->initializeStyle();
} else
- m_scrollCorner->setStyle(corner.releaseNonNull());
+ m_scrollCorner->setStyle(WTFMove(*corner));
}
void RenderLayer::updateResizerStyle()
{
RenderElement* actualRenderer = rendererForScrollbar(renderer());
- RefPtr<RenderStyle> resizer = renderer().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), &actualRenderer->style()) : PassRefPtr<RenderStyle>(0);
+ auto resizer = renderer().hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(PseudoStyleRequest(RESIZER), &actualRenderer->style()) : nullptr;
if (!resizer) {
m_resizer = nullptr;
@@ -6716,16 +6898,16 @@ void RenderLayer::updateResizerStyle()
}
if (!m_resizer) {
- m_resizer = createRenderer<RenderScrollbarPart>(renderer().document(), resizer.releaseNonNull());
+ m_resizer = createRenderer<RenderScrollbarPart>(renderer().document(), WTFMove(*resizer));
m_resizer->setParent(&renderer());
m_resizer->initializeStyle();
} else
- m_resizer->setStyle(resizer.releaseNonNull());
+ m_resizer->setStyle(WTFMove(*resizer));
}
RenderLayer* RenderLayer::reflectionLayer() const
{
- return m_reflection ? m_reflection->layer() : 0;
+ return m_reflection ? m_reflection->layer() : nullptr;
}
void RenderLayer::createReflection()
@@ -6738,17 +6920,17 @@ void RenderLayer::createReflection()
void RenderLayer::removeReflection()
{
- if (!m_reflection->documentBeingDestroyed())
+ if (!m_reflection->renderTreeBeingDestroyed())
m_reflection->removeLayers(this);
- m_reflection->setParent(0);
+ m_reflection->setParent(nullptr);
m_reflection = nullptr;
}
-PassRef<RenderStyle> RenderLayer::createReflectionStyle()
+RenderStyle RenderLayer::createReflectionStyle()
{
auto newStyle = RenderStyle::create();
- newStyle.get().inheritFrom(&renderer().style());
+ newStyle.inheritFrom(renderer().style());
// Map in our transform.
TransformOperations transform;
@@ -6774,29 +6956,29 @@ PassRef<RenderStyle> RenderLayer::createReflectionStyle()
transform.operations().append(TranslateTransformOperation::create(renderer().style().boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
break;
}
- newStyle.get().setTransform(transform);
+ newStyle.setTransform(transform);
// Map in our mask.
- newStyle.get().setMaskBoxImage(renderer().style().boxReflect()->mask());
+ newStyle.setMaskBoxImage(renderer().style().boxReflect()->mask());
+
+ // Style has transform and mask, so needs to be stacking context.
+ newStyle.setZIndex(0);
return newStyle;
}
-#if ENABLE(CSS_FILTERS)
-
void RenderLayer::updateOrRemoveFilterClients()
{
if (!hasFilter()) {
FilterInfo::remove(*this);
return;
}
-
-#if ENABLE(SVG)
- if (renderer().style().filter().hasReferenceFilter())
+ // Add the filter as a client to this renderer, unless we are a RenderLayer accommodating
+ // an SVG. In that case it takes care of its own resource management for filters.
+ if (renderer().style().filter().hasReferenceFilter() && !renderer().isSVGRoot())
FilterInfo::get(*this).updateReferenceFilterClients(renderer().style().filter());
else if (FilterInfo* filterInfo = FilterInfo::getIfExists(*this))
filterInfo->removeReferenceFilterClients();
-#endif
}
void RenderLayer::updateOrRemoveFilterEffectRenderer()
@@ -6808,7 +6990,7 @@ void RenderLayer::updateOrRemoveFilterEffectRenderer()
// Don't delete the whole filter info here, because we might use it
// for loading SVG reference filter files.
if (FilterInfo* filterInfo = FilterInfo::getIfExists(*this))
- filterInfo->setRenderer(0);
+ filterInfo->setRenderer(nullptr);
// Early-return only if we *don't* have reference filters.
// For reference filters, we still want the FilterEffect graph built
@@ -6820,154 +7002,171 @@ void RenderLayer::updateOrRemoveFilterEffectRenderer()
FilterInfo& filterInfo = FilterInfo::get(*this);
if (!filterInfo.renderer()) {
RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create();
- RenderingMode renderingMode = renderer().frame().settings().acceleratedFiltersEnabled() ? Accelerated : Unaccelerated;
- filterRenderer->setRenderingMode(renderingMode);
- filterInfo.setRenderer(filterRenderer.release());
+ filterRenderer->setFilterScale(page().deviceScaleFactor());
+ filterRenderer->setRenderingMode(renderer().settings().acceleratedFiltersEnabled() ? Accelerated : Unaccelerated);
+ filterInfo.setRenderer(WTFMove(filterRenderer));
// We can optimize away code paths in other places if we know that there are no software filters.
renderer().view().setHasSoftwareFilters(true);
+ } else if (filterInfo.renderer()->filterScale() != page().deviceScaleFactor()) {
+ filterInfo.renderer()->setFilterScale(page().deviceScaleFactor());
+ filterInfo.renderer()->clearIntermediateResults();
}
// If the filter fails to build, remove it from the layer. It will still attempt to
// go through regular processing (e.g. compositing), but never apply anything.
- if (!filterInfo.renderer()->build(&renderer(), renderer().style().filter(), FilterProperty))
- filterInfo.setRenderer(0);
+ if (!filterInfo.renderer()->build(renderer(), renderer().style().filter(), FilterProperty))
+ filterInfo.setRenderer(nullptr);
}
void RenderLayer::filterNeedsRepaint()
{
- renderer().element()->setNeedsStyleRecalc(SyntheticStyleChange);
+ // We use the enclosing element so that we recalculate style for the ancestor of an anonymous object.
+ if (Element* element = enclosingElement())
+ element->invalidateStyleAndLayerComposition();
renderer().repaint();
}
-#endif
-
-void RenderLayer::paintNamedFlowThreadInsideRegion(GraphicsContext* context, RenderNamedFlowFragment* region, LayoutRect paintDirtyRect, LayoutPoint paintOffset, PaintBehavior paintBehavior, PaintLayerFlags paintFlags)
+void RenderLayer::paintNamedFlowThreadInsideRegion(GraphicsContext& context, RenderNamedFlowFragment* region, LayoutRect paintDirtyRect, LayoutPoint paintOffset, PaintBehavior paintBehavior, PaintLayerFlags paintFlags)
{
- LayoutRect regionContentBox = toRenderBox(region->layerOwner()).contentBoxRect();
- LayoutSize moveOffset = region->flowThreadPortionLocation() - (paintOffset + regionContentBox.location());
- IntPoint adjustedPaintOffset = roundedIntPoint(-moveOffset);
- paintDirtyRect.move(moveOffset);
+ LayoutRect regionContentBox = downcast<RenderBox>(region->layerOwner()).contentBoxRect();
+ CurrentRenderRegionMaintainer regionMaintainer(*region);
+ region->setRegionObjectsRegionStyle();
- context->save();
- context->translate(adjustedPaintOffset.x(), adjustedPaintOffset.y());
+ LayoutSize moveOffset = region->flowThreadPortionLocation() - (paintOffset + regionContentBox.location()) + toLayoutSize(region->fragmentContainer().scrollPosition());
+ FloatPoint adjustedPaintOffset = roundPointToDevicePixels(toLayoutPoint(moveOffset), renderer().document().deviceScaleFactor());
+ context.save();
+ context.translate(-adjustedPaintOffset.x(), -adjustedPaintOffset.y());
- region->setRegionObjectsRegionStyle();
- paint(context, paintDirtyRect, paintBehavior, 0, region, paintFlags | PaintLayerTemporaryClipRects);
+ LayoutSize subpixelOffset = moveOffset - toLayoutSize(LayoutPoint(adjustedPaintOffset));
+ paintDirtyRect.move(moveOffset);
+ paint(context, paintDirtyRect, LayoutSize(-subpixelOffset.width(), -subpixelOffset.height()), paintBehavior, nullptr, paintFlags | PaintLayerTemporaryClipRects);
region->restoreRegionObjectsOriginalStyle();
-
- context->restore();
+ context.restore();
}
-void RenderLayer::paintFlowThreadIfRegion(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, LayoutPoint paintOffset, LayoutRect dirtyRect, bool isPaintingOverflowContents)
+void RenderLayer::paintFlowThreadIfRegionForFragments(const LayerFragments& fragments, GraphicsContext& context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
if (!renderer().isRenderNamedFlowFragmentContainer())
return;
- RenderBlockFlow* renderNamedFlowFragmentContainer = toRenderBlockFlow(&renderer());
- RenderNamedFlowFragment* flowFragment = renderNamedFlowFragmentContainer->renderNamedFlowFragment();
+ RenderBlockFlow& renderNamedFlowFragmentContainer = downcast<RenderBlockFlow>(renderer());
+ RenderNamedFlowFragment* flowFragment = renderNamedFlowFragmentContainer.renderNamedFlowFragment();
if (!flowFragment->isValid())
return;
-
- ClipRect regionClipRect;
+
RenderNamedFlowThread* flowThread = flowFragment->namedFlowThread();
RenderLayer* flowThreadLayer = flowThread->layer();
- bool isLastRegionWithRegionFragmentBreak = (flowFragment->isLastRegion() && flowFragment->style().regionFragment() == BreakRegionFragment);
- if (flowFragment->hasOverflowClip() || isLastRegionWithRegionFragmentBreak) {
- regionClipRect = renderNamedFlowFragmentContainer->paddingBoxRect();
+
+ LayoutRect regionClipRect = LayoutRect::infiniteRect();
+ if (flowFragment->shouldClipFlowThreadContent()) {
+ regionClipRect = renderNamedFlowFragmentContainer.paddingBoxRect();
// When the layer of the flow fragment's container is composited, the flow fragment container receives a
// GraphicsLayer of its own so the clipping coordinates (caused by overflow:hidden) must be relative to the
// GraphicsLayer coordinates in which the fragment gets painted. So what is computed so far is enough.
// If the layer of the flowFragment is not composited, then we change the coordinates to be relative to the flow
// thread's layer.
- if (!isComposited()) {
- LayoutPoint regionOffsetFromRoot;
- convertToLayerCoords(flowThreadLayer, regionOffsetFromRoot);
- regionClipRect.moveBy(regionOffsetFromRoot);
- }
- } else {
- if (paintingInfo.rootLayer != this && parent()) {
- ClipRectsContext clipRectsContext(paintingInfo.rootLayer, flowFragment,
- (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects,
- IgnoreOverlayScrollbarSize, (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip);
- regionClipRect = backgroundClipRect(clipRectsContext);
- } else
- regionClipRect = dirtyRect;
+ if (!isComposited())
+ regionClipRect.move(offsetFromAncestor(paintingInfo.rootLayer));
}
+
+ for (const auto& fragment : fragments) {
+ ClipRect clipRect = fragment.foregroundRect;
+ if (flowFragment->shouldClipFlowThreadContent())
+ clipRect.intersect(regionClipRect);
- // Optimize clipping for the single fragment case.
- if (!regionClipRect.isEmpty() && regionClipRect != LayoutRect::infiniteRect())
- clipToRect(paintingInfo.rootLayer, context, paintingInfo.paintDirtyRect, regionClipRect);
+ bool shouldClip = !clipRect.isInfinite();
+ // Optimize clipping for the single fragment case.
+ if (shouldClip)
+ clipToRect(context, paintingInfo, clipRect);
- flowThreadLayer->paintNamedFlowThreadInsideRegion(context, flowFragment, paintingInfo.paintDirtyRect, paintOffset, paintingInfo.paintBehavior, paintFlags);
+ flowThreadLayer->paintNamedFlowThreadInsideRegion(context, flowFragment, paintingInfo.paintDirtyRect, fragment.layerBounds.location() + paintingInfo.subpixelOffset,
+ paintingInfo.paintBehavior, paintFlags);
- if (!regionClipRect.isEmpty() && regionClipRect != LayoutRect::infiniteRect())
- restoreClip(context, paintingInfo.paintDirtyRect, regionClipRect);
+ if (shouldClip)
+ restoreClip(context, paintingInfo, clipRect);
+ }
}
-RenderLayer* RenderLayer::hitTestFlowThreadIfRegion(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, const LayoutRect& hitTestRect,
+RenderLayer* RenderLayer::hitTestFlowThreadIfRegionForFragments(const LayerFragments& fragments, RenderLayer*, const HitTestRequest& request, HitTestResult& result, const LayoutRect& hitTestRect,
const HitTestLocation& hitTestLocation,
const HitTestingTransformState* transformState,
- double* zOffsetForDescendants)
+ double* zOffsetForDescendants, double* zOffset,
+ const HitTestingTransformState* unflattenedTransformState, bool depthSortDescendants)
{
if (!renderer().isRenderNamedFlowFragmentContainer())
- return 0;
-
- RenderNamedFlowFragment* region = toRenderBlockFlow(&renderer())->renderNamedFlowFragment();
- if (!region->isValid())
- return 0;
-
- RenderFlowThread* flowThread = region->flowThread();
-
- // If the hit location is inside a clipped out area, don't forward the hit test to the flow thread.
- if (rootLayer != this && parent()) {
- ClipRectsContext clipRectsContext(rootLayer, hitTestLocation.region(), TemporaryClipRects);
- ClipRect clipRect = backgroundClipRect(clipRectsContext);
- if (!clipRect.intersects(hitTestLocation))
- return 0;
- }
-
- LayoutPoint regionOffsetFromRoot;
- convertToLayerCoords(rootLayer, regionOffsetFromRoot);
+ return nullptr;
- LayoutPoint portionLocation = region->flowThreadPortionRect().location();
+ RenderNamedFlowFragment& region = *downcast<RenderBlockFlow>(renderer()).renderNamedFlowFragment();
+ if (!region.isValid())
+ return nullptr;
+ RenderFlowThread* flowThread = region.flowThread();
+ LayoutPoint portionLocation = region.flowThreadPortionRect().location();
if (flowThread->style().isFlippedBlocksWritingMode()) {
// The portion location coordinate must be translated into physical coordinates.
if (flowThread->style().isHorizontalWritingMode())
- portionLocation.setY(flowThread->height() - (portionLocation.y() + region->contentHeight()));
+ portionLocation.setY(flowThread->height() - (portionLocation.y() + region.contentHeight()));
else
- portionLocation.setX(flowThread->width() - (portionLocation.x() + region->contentWidth()));
+ portionLocation.setX(flowThread->width() - (portionLocation.x() + region.contentWidth()));
}
- LayoutRect regionContentBox = toRenderBlockFlow(&renderer())->contentBoxRect();
- LayoutSize hitTestOffset = portionLocation - (regionOffsetFromRoot + regionContentBox.location());
+ LayoutRect regionContentBox = downcast<RenderBlockFlow>(renderer()).contentBoxRect();
+
+ RenderLayer* resultLayer = nullptr;
+ for (int i = fragments.size() - 1; i >= 0; --i) {
+ const LayerFragment& fragment = fragments.at(i);
+
+ if (!fragment.backgroundRect.intersects(hitTestLocation))
+ continue;
+
+ LayoutSize hitTestOffset = portionLocation - (fragment.layerBounds.location() + regionContentBox.location()) + toLayoutSize(region.fragmentContainer().scrollPosition());
- // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView.
- HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
+ // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView.
+ HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent);
- // Make a new temporary HitTestLocation in the new region.
- HitTestLocation newHitTestLocation(hitTestLocation, hitTestOffset, region);
+ // Make a new temporary HitTestLocation in the new region.
+ HitTestLocation newHitTestLocation(hitTestLocation, hitTestOffset);
- // Expand the hit-test rect to the flow thread's coordinate system.
- LayoutRect hitTestRectInFlowThread = hitTestRect;
- hitTestRectInFlowThread.move(hitTestOffset.width(), hitTestOffset.height());
- hitTestRectInFlowThread.expand(LayoutSize(fabs((double)hitTestOffset.width()), fabs((double)hitTestOffset.height())));
+ // Expand the hit-test rect to the flow thread's coordinate system.
+ LayoutRect hitTestRectInFlowThread = hitTestRect;
+ hitTestRectInFlowThread.move(hitTestOffset);
+ hitTestRectInFlowThread.expand(LayoutSize(fabs((double)hitTestOffset.width()), fabs((double)hitTestOffset.height())));
- return flowThread->layer()->hitTestLayer(flowThread->layer(), 0, newRequest, result, hitTestRectInFlowThread, newHitTestLocation, false, transformState, zOffsetForDescendants);
+ CurrentRenderRegionMaintainer regionMaintainer(region);
+
+ HitTestResult tempResult(result.hitTestLocation());
+ RenderLayer* hitLayer = flowThread->layer()->hitTestLayer(flowThread->layer(), nullptr, newRequest, tempResult, hitTestRectInFlowThread, newHitTestLocation, false, transformState, zOffsetForDescendants);
+ if (result.isRectBasedTest())
+ result.append(tempResult);
+ if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) {
+ resultLayer = hitLayer;
+ if (!result.isRectBasedTest())
+ result = tempResult;
+ if (!depthSortDescendants)
+ break;
+ }
+ }
+
+ return resultLayer;
+}
+
+RenderNamedFlowFragment* RenderLayer::currentRenderNamedFlowFragment() const
+{
+ return renderer().currentRenderNamedFlowFragment();
}
} // namespace WebCore
-#ifndef NDEBUG
+#if ENABLE(TREE_DEBUGGING)
void showLayerTree(const WebCore::RenderLayer* layer)
{
if (!layer)
return;
- WTF::String output = externalRepresentation(&layer->renderer().frame(), WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState | WebCore::RenderAsTextShowOverflow);
+ WTF::String output = externalRepresentation(&layer->renderer().frame(), WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState | WebCore::RenderAsTextShowOverflow | WebCore::RenderAsTextShowSVGGeometry);
fprintf(stderr, "%s\n", output.utf8().data());
}