static const DeprecatedPaintLayer* findParentLayerOnClippingContainerChain(const DeprecatedPaintLayer* layer) { LayoutObject* current = layer->layoutObject(); while (current) { if (current->style()->position() == FixedPosition) { for (current = current->parent(); current && !current->canContainFixedPositionObjects(); current = current->parent()) { // All types of clips apply to fixed-position descendants of other fixed-position elements. // Note: it's unclear whether this is what the spec says. Firefox does not clip, but Chrome does. if (current->style()->position() == FixedPosition && current->hasClipOrOverflowClip()) { ASSERT(current->hasLayer()); return static_cast<const LayoutBoxModelObject*>(current)->layer(); } // CSS clip applies to fixed position elements even for ancestors that are not what the // fixed element is positioned with respect to. if (current->hasClip()) { ASSERT(current->hasLayer()); return static_cast<const LayoutBoxModelObject*>(current)->layer(); } } } else { current = current->containingBlock(); } if (current->hasLayer()) return static_cast<const LayoutBoxModelObject*>(current)->layer(); // Having clip or overflow clip forces the LayoutObject to become a layer. ASSERT(!current->hasClipOrOverflowClip()); } ASSERT_NOT_REACHED(); return nullptr; }
TEST_F(ScrollingCoordinatorTest, overflowHidden) { registerMockedHttpURLLoad("overflow-hidden.html"); navigateTo(m_baseURL + "overflow-hidden.html"); forceFullCompositingUpdate(); // Verify the properties of the accelerated scrolling element starting from the LayoutObject // all the way to the WebLayer. Element* overflowElement = frame()->document()->getElementById("unscrollable-y"); ASSERT(overflowElement); LayoutObject* layoutObject = overflowElement->layoutObject(); ASSERT_TRUE(layoutObject->isBox()); ASSERT_TRUE(layoutObject->hasLayer()); LayoutBox* box = toLayoutBox(layoutObject); ASSERT_TRUE(box->usesCompositedScrolling()); ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState()); CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping(); ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer()); ASSERT(compositedLayerMapping->scrollingContentsLayer()); GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer(); ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea()); WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); ASSERT_TRUE(webScrollLayer->userScrollableHorizontal()); ASSERT_FALSE(webScrollLayer->userScrollableVertical()); overflowElement = frame()->document()->getElementById("unscrollable-x"); ASSERT(overflowElement); layoutObject = overflowElement->layoutObject(); ASSERT_TRUE(layoutObject->isBox()); ASSERT_TRUE(layoutObject->hasLayer()); box = toLayoutBox(layoutObject); ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling()); ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState()); compositedLayerMapping = box->layer()->compositedLayerMapping(); ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer()); ASSERT(compositedLayerMapping->scrollingContentsLayer()); graphicsLayer = compositedLayerMapping->scrollingContentsLayer(); ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea()); webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); ASSERT_FALSE(webScrollLayer->userScrollableHorizontal()); ASSERT_TRUE(webScrollLayer->userScrollableVertical()); }
void LayoutAnalyzer::push(const LayoutObject& o) { increment(TotalLayoutObjectsThatWereLaidOut); if (!o.everHadLayout()) increment(LayoutObjectsThatHadNeverHadLayout); if (o.selfNeedsLayout()) increment(LayoutObjectsThatNeedLayoutForThemselves); if (o.needsPositionedMovementLayout()) increment(LayoutObjectsThatNeedPositionedMovementLayout); if (o.isOutOfFlowPositioned()) increment(LayoutObjectsThatAreOutOfFlowPositioned); if (o.isTableCell()) increment(LayoutObjectsThatAreTableCells); if (o.isFloating()) increment(LayoutObjectsThatAreFloating); if (o.style()->specifiesColumns()) increment(LayoutObjectsThatSpecifyColumns); if (o.hasLayer()) increment(LayoutObjectsThatHaveALayer); if (o.isLayoutInline() && o.alwaysCreateLineBoxesForLayoutInline()) increment(LayoutInlineObjectsThatAlwaysCreateLineBoxes); if (o.isText()) { const LayoutText& t = *toLayoutText(&o); if (t.canUseSimpleFontCodePath()) { increment(LayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath); increment(CharactersInLayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath, t.textLength()); } else { increment(LayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath); increment(CharactersInLayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath, t.textLength()); } } // This might be a root in a subtree layout, in which case the LayoutObject // has a parent but the stack is empty. If a LayoutObject subclass forgets // to call push() and is a root in a subtree layout, then this // assert would only fail if that LayoutObject instance has any children // that need layout and do call push(). // LayoutBlock::layoutPositionedObjects() hoists positioned descendants. // LayoutBlockFlow::layoutInlineChildren() walks through inlines. // LayoutTableSection::layoutRows() walks through rows. if (!o.isPositioned() && !o.isTableCell() && !o.isSVGResourceContainer() && (m_stack.size() != 0) && !(o.parent()->childrenInline() && (o.isReplaced() || o.isFloating() || o.isOutOfFlowPositioned()))) { ASSERT(o.parent() == m_stack.peek()); } m_stack.push(&o); // This refers to LayoutAnalyzer depth, not layout tree depth or DOM tree // depth. LayoutAnalyzer depth is generally closer to C++ stack recursion // depth. See above exceptions for when LayoutAnalyzer depth != layout tree // depth. if (m_stack.size() > m_counters[LayoutAnalyzerStackMaximumDepth]) m_counters[LayoutAnalyzerStackMaximumDepth] = m_stack.size(); }
void PaintPropertyTreeBuilder::updateLocalBorderBoxContext(const LayoutObject& object, const PaintPropertyTreeBuilderContext& context) { // Note: Currently only layer painter makes use of the pre-computed context. // This condition may be loosened with no adverse effects beside memory use. if (!object.hasLayer()) return; std::unique_ptr<ObjectPaintProperties::LocalBorderBoxProperties> borderBoxContext = wrapUnique(new ObjectPaintProperties::LocalBorderBoxProperties); borderBoxContext->paintOffset = context.paintOffset; borderBoxContext->transform = context.currentTransform; borderBoxContext->clip = context.currentClip; borderBoxContext->effect = context.currentEffect; object.getMutableForPainting().ensureObjectPaintProperties().setLocalBorderBoxProperties(std::move(borderBoxContext)); }
void PaintPropertyTreeBuilder::updateLocalBorderBoxContext( const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since // we don't need them at the moment. if (!object.isBox() && !object.hasLayer()) return; std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset> borderBoxContext = wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset( context.current.paintOffset, PropertyTreeState(context.current.transform, context.current.clip, context.currentEffect, context.current.scroll))); object.getMutableForPainting() .ensurePaintProperties() .setLocalBorderBoxProperties(std::move(borderBoxContext)); }
void LayoutSVGResourceContainer::registerResource() { SVGDocumentExtensions& extensions = svgExtensionsFromElement(element()); if (!extensions.hasPendingResource(m_id)) { extensions.addResource(m_id, this); return; } SVGDocumentExtensions::SVGPendingElements* clients(extensions.removePendingResource(m_id)); // Cache us with the new id. extensions.addResource(m_id, this); // Update cached resources of pending clients. for (const auto& pendingClient : *clients) { ASSERT(pendingClient->hasPendingResources()); extensions.clearHasPendingResourcesIfPossible(pendingClient); LayoutObject* layoutObject = pendingClient->layoutObject(); if (!layoutObject) continue; const ComputedStyle& style = layoutObject->styleRef(); // If the client has a layer (is a non-SVGElement) we need to signal // invalidation in the same way as is done in markAllResourceClientsForInvalidation above. if (layoutObject->hasLayer() && resourceType() == FilterResourceType) { if (style.hasFilter()) toLayoutBoxModelObject(layoutObject)->layer()->filterNeedsPaintInvalidation(); // If this is the SVG root, we could have both 'filter' and // '-webkit-filter' applied, so we need to do the invalidation // below as well, unless we can optimistically determine that // 'filter' does not apply to the element in question. if (!layoutObject->isSVGRoot() || !style.svgStyle().hasFilter()) continue; } StyleDifference diff; diff.setNeedsFullLayout(); SVGResourcesCache::clientStyleChanged(layoutObject, diff, style); layoutObject->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SvgResourceInvalidated); } }
TEST_F(ScrollingCoordinatorTest, overflowScrolling) { registerMockedHttpURLLoad("overflow-scrolling.html"); navigateTo(m_baseURL + "overflow-scrolling.html"); forceFullCompositingUpdate(); // Verify the properties of the accelerated scrolling element starting from the LayoutObject // all the way to the WebLayer. Element* scrollableElement = frame()->document()->getElementById("scrollable"); ASSERT(scrollableElement); LayoutObject* layoutObject = scrollableElement->layoutObject(); ASSERT_TRUE(layoutObject->isBox()); ASSERT_TRUE(layoutObject->hasLayer()); LayoutBox* box = toLayoutBox(layoutObject); ASSERT_TRUE(box->usesCompositedScrolling()); ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState()); CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping(); ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer()); ASSERT(compositedLayerMapping->scrollingContentsLayer()); GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer(); ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea()); WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); ASSERT_TRUE(webScrollLayer->userScrollableHorizontal()); ASSERT_TRUE(webScrollLayer->userScrollableVertical()); #if OS(ANDROID) // Now verify we've attached impl-side scrollbars onto the scrollbar layers ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar()); ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar()->hasContentsLayer()); ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar()); ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar()->hasContentsLayer()); #endif }
void LayoutAnalyzer::push(const LayoutObject& o) { increment(TotalLayoutObjectsThatWereLaidOut); if (!o.everHadLayout()) increment(LayoutObjectsThatHadNeverHadLayout); if (o.selfNeedsLayout()) increment(LayoutObjectsThatNeedLayoutForThemselves); if (o.needsPositionedMovementLayout()) increment(LayoutObjectsThatNeedPositionedMovementLayout); if (o.isOutOfFlowPositioned()) increment(LayoutObjectsThatAreOutOfFlowPositioned); if (o.isTableCell()) increment(LayoutObjectsThatAreTableCells); if (o.isFloating()) increment(LayoutObjectsThatAreFloating); if (o.style()->specifiesColumns()) increment(LayoutObjectsThatSpecifyColumns); if (o.hasLayer()) increment(LayoutObjectsThatHaveALayer); if (o.isLayoutInline() && o.alwaysCreateLineBoxesForLayoutInline()) increment(LayoutInlineObjectsThatAlwaysCreateLineBoxes); if (o.isText()) { const LayoutText& t = *toLayoutText(&o); if (t.canUseSimpleFontCodePath()) { increment(LayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath); increment(CharactersInLayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath, t.textLength()); } else { increment(LayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath); increment(CharactersInLayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath, t.textLength()); } } ++m_depth; // This refers to LayoutAnalyzer depth, which is generally closer to C++ // stack recursion depth, not layout tree depth or DOM tree depth. m_counters[LayoutAnalyzerStackMaximumDepth] = max(m_counters[LayoutAnalyzerStackMaximumDepth], m_depth); }