bool LinkHighlightImpl::computeHighlightLayerPathAndPosition(const LayoutBoxModelObject& paintInvalidationContainer) { if (!m_node || !m_node->layoutObject() || !m_currentGraphicsLayer) return false; // FIXME: This is defensive code to avoid crashes such as those described in // crbug.com/440887. This should be cleaned up once we fix the root cause of // of the paint invalidation container not being composited. if (!paintInvalidationContainer.layer()->compositedLayerMapping() && !paintInvalidationContainer.layer()->groupedMapping()) return false; // Get quads for node in absolute coordinates. Vector<FloatQuad> quads; computeQuads(*m_node, quads); DCHECK(quads.size()); Path newPath; for (size_t quadIndex = 0; quadIndex < quads.size(); ++quadIndex) { FloatQuad absoluteQuad = quads[quadIndex]; // Scrolling content layers have the same offset from layout object as the non-scrolling layers. Thus we need // to adjust for their scroll offset. if (m_isScrollingGraphicsLayer) { DoubleSize adjustedScrollOffset = paintInvalidationContainer.layer()->getScrollableArea()->adjustedScrollOffset(); absoluteQuad.move(adjustedScrollOffset.width(), adjustedScrollOffset.height()); } // Transform node quads in target absolute coords to local coordinates in the compositor layer. FloatQuad transformedQuad; convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->layoutObject(), paintInvalidationContainer, transformedQuad); // FIXME: for now, we'll only use rounded paths if we have a single node quad. The reason for this is that // we may sometimes get a chain of adjacent boxes (e.g. for text nodes) which end up looking like sausage // links: these should ideally be merged into a single rect before creating the path, but that's // another CL. if (quads.size() == 1 && transformedQuad.isRectilinear() && !m_owningWebViewImpl->settingsImpl()->mockGestureTapHighlightsEnabled()) { FloatSize rectRoundingRadii(3, 3); newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRadii); } else { addQuadToPath(transformedQuad, newPath); } } FloatRect boundingRect = newPath.boundingRect(); newPath.translate(-toFloatSize(boundingRect.location())); bool pathHasChanged = !(newPath == m_path); if (pathHasChanged) { m_path = newPath; m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size()); } m_contentLayer->layer()->setPosition(boundingRect.location()); return pathHasChanged; }
static void checkIsClippingStackingContextAndContainer(LayoutBoxModelObject& obj) { EXPECT_TRUE(obj.canContainFixedPositionObjects()); EXPECT_TRUE(obj.hasClipRelatedProperty()); EXPECT_TRUE(obj.style()->containsPaint()); // TODO(leviw): Ideally, we wouldn't require a paint layer to handle the clipping // and stacking performed by paint containment. ASSERT(obj.layer()); PaintLayer* layer = obj.layer(); EXPECT_TRUE(layer->stackingNode() && layer->stackingNode()->isStackingContext()); }
static PassRefPtr<TransformPaintPropertyNode> createPaintOffsetTranslationIfNeeded(const LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context) { // TODO(trchen): Eliminate PaintLayer dependency. bool shouldCreatePaintOffsetTranslationNode = object.layer() && object.layer()->paintsWithTransform(GlobalPaintNormalPhase); if (context.paintOffset == LayoutPoint() || !shouldCreatePaintOffsetTranslationNode) return nullptr; RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = TransformPaintPropertyNode::create( TransformationMatrix().translate(context.paintOffset.x(), context.paintOffset.y()), FloatPoint3D(), context.currentTransform); context.currentTransform = newTransformNodeForPaintOffsetTranslation.get(); context.paintOffset = LayoutPoint(); return newTransformNodeForPaintOffsetTranslation.release(); }
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. }
void LinkHighlightImpl::attachLinkHighlightToCompositingLayer(const LayoutBoxModelObject& paintInvalidationContainer) { GraphicsLayer* newGraphicsLayer = paintInvalidationContainer.layer()->graphicsLayerBacking(); m_isScrollingGraphicsLayer = false; // FIXME: There should always be a GraphicsLayer. See crbug.com/431961. if (paintInvalidationContainer.layer()->needsCompositedScrolling() && m_node->layoutObject() != &paintInvalidationContainer) { newGraphicsLayer = paintInvalidationContainer.layer()->graphicsLayerBackingForScrolling(); m_isScrollingGraphicsLayer = true; } if (!newGraphicsLayer) return; m_clipLayer->setTransform(SkMatrix44(SkMatrix44::kIdentity_Constructor)); if (m_currentGraphicsLayer != newGraphicsLayer) { if (m_currentGraphicsLayer) clearGraphicsLayerLinkHighlightPointer(); m_currentGraphicsLayer = newGraphicsLayer; m_currentGraphicsLayer->addLinkHighlight(this); } }
LayerClipRecorder::LayerClipRecorder(GraphicsContext& graphicsContext, const LayoutBoxModelObject& layoutObject, DisplayItem::Type clipType, const ClipRect& clipRect, const PaintLayerPaintingInfo* localPaintingInfo, const LayoutPoint& fragmentOffset, PaintLayerFlags paintFlags, BorderRadiusClippingRule rule) : m_graphicsContext(graphicsContext) , m_layoutObject(layoutObject) , m_clipType(clipType) { IntRect snappedClipRect = pixelSnappedIntRect(clipRect.rect()); Vector<FloatRoundedRect> roundedRects; if (localPaintingInfo && clipRect.hasRadius()) { collectRoundedRectClips(*layoutObject.layer(), *localPaintingInfo, graphicsContext, fragmentOffset, paintFlags, rule, roundedRects); } m_graphicsContext.paintController().createAndAppend<ClipDisplayItem>(layoutObject, m_clipType, snappedClipRect, roundedRects); }
static PassRefPtr<TransformPaintPropertyNode> createScrollTranslationIfNeeded(const LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context) { if (!object.hasOverflowClip()) return nullptr; PaintLayer* layer = object.layer(); ASSERT(layer); DoubleSize scrollOffset = layer->scrollableArea()->scrollOffset(); if (scrollOffset.isZero() && !layer->scrollsOverflow()) return nullptr; RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = TransformPaintPropertyNode::create( TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.height()), FloatPoint3D(), context.currentTransform); context.currentTransform = newTransformNodeForScrollTranslation.get(); return newTransformNodeForScrollTranslation.release(); }