PaintInvalidationState::PaintInvalidationState(PaintInvalidationState& next, LayoutBoxModelObject& layoutObject, const LayoutBoxModelObject& paintInvalidationContainer) : m_clipped(false) , m_cachedOffsetsEnabled(true) , m_forcedSubtreeInvalidationWithinContainer(next.m_forcedSubtreeInvalidationWithinContainer) , m_forcedSubtreeInvalidationRectUpdateWithinContainer(next.m_forcedSubtreeInvalidationRectUpdateWithinContainer) , m_viewClippingAndScrollOffsetDisabled(false) , m_paintInvalidationContainer(paintInvalidationContainer) , m_pendingDelayedPaintInvalidations(next.pendingDelayedPaintInvalidationTargets()) , m_enclosingSelfPaintingLayer(next.enclosingSelfPaintingLayer(layoutObject)) { // FIXME: SVG could probably benefit from a stack-based optimization like html does. crbug.com/391054 bool establishesPaintInvalidationContainer = layoutObject == m_paintInvalidationContainer; bool fixed = layoutObject.style()->position() == FixedPosition; if (!layoutObject.supportsPaintInvalidationStateCachedOffsets() || !next.m_cachedOffsetsEnabled) m_cachedOffsetsEnabled = false; if (establishesPaintInvalidationContainer) { // When we hit a new paint invalidation container, we don't need to // continue forcing a check for paint invalidation, since we're // descending into a different invalidation container. (For instance if // our parents were moved, the entire container will just move.) m_forcedSubtreeInvalidationWithinContainer = false; } else { if (m_cachedOffsetsEnabled) { if (fixed) { FloatPoint fixedOffset = layoutObject.localToAncestorPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()); } else { LayoutSize offset = layoutObject.isBox() && !layoutObject.isTableRow() ? toLayoutBox(layoutObject).locationOffset() : LayoutSize(); m_paintOffset = next.m_paintOffset + offset; } if (layoutObject.isOutOfFlowPositioned() && !fixed) { if (LayoutObject* container = layoutObject.container()) { if (container->style()->hasInFlowPosition() && container->isLayoutInline()) m_paintOffset += toLayoutInline(container)->offsetForInFlowPositionedInline(toLayoutBox(layoutObject)); } } if (layoutObject.style()->hasInFlowPosition() && layoutObject.hasLayer()) m_paintOffset += layoutObject.layer()->offsetForInFlowPosition(); } m_clipped = !fixed && next.m_clipped; if (m_clipped) m_clipRect = next.m_clipRect; } if (m_cachedOffsetsEnabled && layoutObject.isSVGRoot()) { const LayoutSVGRoot& svgRoot = toLayoutSVGRoot(layoutObject); m_svgTransform = AffineTransform(svgRoot.localToBorderBoxTransform()); if (svgRoot.shouldApplyViewportClip()) addClipRectRelativeToPaintOffset(LayoutSize(svgRoot.pixelSnappedSize())); } applyClipIfNeeded(layoutObject); // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. }
static void applyClipRects(const ClipRectsContext& context, const LayoutBoxModelObject& layoutObject, LayoutPoint offset, ClipRects& clipRects) { DCHECK(layoutObject.hasClipRelatedProperty() || (layoutObject.isSVGRoot() && toLayoutSVGRoot(&layoutObject)->shouldApplyViewportClip())); LayoutView* view = layoutObject.view(); DCHECK(view); if (clipRects.fixed() && context.rootLayer->layoutObject() == view) offset -= LayoutSize(view->frameView()->scrollOffset()); if (layoutObject.hasOverflowClip() || (layoutObject.isSVGRoot() && toLayoutSVGRoot(&layoutObject)->shouldApplyViewportClip()) || (layoutObject.styleRef().containsPaint() && layoutObject.isBox())) { ClipRect newOverflowClip = toLayoutBox(layoutObject) .overflowClipRect(offset, context.overlayScrollbarClipBehavior); newOverflowClip.setHasRadius(layoutObject.styleRef().hasBorderRadius()); clipRects.setOverflowClipRect( intersection(newOverflowClip, clipRects.overflowClipRect())); if (layoutObject.isPositioned()) clipRects.setPosClipRect( intersection(newOverflowClip, clipRects.posClipRect())); if (layoutObject.isLayoutView()) clipRects.setFixedClipRect( intersection(newOverflowClip, clipRects.fixedClipRect())); if (layoutObject.styleRef().containsPaint()) { clipRects.setPosClipRect( intersection(newOverflowClip, clipRects.posClipRect())); clipRects.setFixedClipRect( intersection(newOverflowClip, clipRects.fixedClipRect())); } } if (layoutObject.hasClip()) { LayoutRect newClip = toLayoutBox(layoutObject).clipRect(offset); clipRects.setPosClipRect( intersection(newClip, clipRects.posClipRect()).setIsClippedByClipCss()); clipRects.setOverflowClipRect( intersection(newClip, clipRects.overflowClipRect()) .setIsClippedByClipCss()); clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect()) .setIsClippedByClipCss()); } }
void PaintPropertyTreeBuilder::walk(LayoutBoxModelObject& object, const PaintPropertyTreeBuilderContext& context) { ASSERT(object.isBox() != object.isLayoutInline()); // Either or. PaintPropertyTreeBuilderContext localContext(context); deriveBorderBoxFromContainerContext(object, localContext); RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = createPaintOffsetTranslationIfNeeded(object, localContext); RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTransformIfNeeded(object, localContext); RefPtr<EffectPaintPropertyNode> newEffectNode = createEffectIfNeeded(object, localContext); RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPerspectiveIfNeeded(object, localContext); RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = createScrollTranslationIfNeeded(object, localContext); updateOutOfFlowContext(object, localContext); if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransform || newEffectNode || newTransformNodeForPerspective || newTransformNodeForScrollTranslation) { OwnPtr<ObjectPaintProperties> updatedPaintProperties = ObjectPaintProperties::create( newTransformNodeForPaintOffsetTranslation.release(), newTransformNodeForTransform.release(), newEffectNode.release(), newTransformNodeForPerspective.release(), newTransformNodeForScrollTranslation.release()); object.setObjectPaintProperties(updatedPaintProperties.release()); } else { object.clearObjectPaintProperties(); } // TODO(trchen): Walk subframes for LayoutFrame. // TODO(trchen): Implement SVG walk. if (object.isSVGRoot()) { return; } for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) { if (child->isText()) continue; walk(toLayoutBoxModelObject(*child), localContext); } }