static FloatRect toNormalizedRect(const FloatRect& absoluteRect, const LayoutObject* layoutObject, const LayoutBlock* container) { ASSERT(layoutObject); ASSERT(container || layoutObject->isLayoutView()); if (!container) return FloatRect(); // We want to normalize by the max layout overflow size instead of only the visible bounding box. // Quads and their enclosing bounding boxes need to be used in order to keep results transform-friendly. FloatPoint scrolledOrigin; // For overflow:scroll we need to get where the actual origin is independently of the scroll. if (container->hasOverflowClip()) scrolledOrigin = -IntPoint(container->scrolledContentOffset()); FloatRect overflowRect(scrolledOrigin, FloatSize(container->maxLayoutOverflow())); FloatRect containerRect = container->localToAbsoluteQuad(FloatQuad(overflowRect)).enclosingBoundingBox(); if (containerRect.isEmpty()) return FloatRect(); // Make the coordinates relative to the container enclosing bounding box. // Since we work with rects enclosing quad unions this is still transform-friendly. FloatRect normalizedRect = absoluteRect; normalizedRect.moveBy(-containerRect.location()); // Fixed positions do not make sense in this coordinate system, but need to leave consistent tickmarks. // So, use their position when the view is not scrolled, like an absolute position. if (layoutObject->style()->position() == FixedPosition && container->isLayoutView()) normalizedRect.moveBy(-toLayoutView(container)->frameView()->scrollPosition()); normalizedRect.scale(1 / containerRect.width(), 1 / containerRect.height()); return normalizedRect; }
WebAXObject WebDocument::accessibilityObject() const { const Document* document = constUnwrap<Document>(); AXObjectCacheImpl* cache = toAXObjectCacheImpl(document->axObjectCache()); return cache ? WebAXObject(cache->getOrCreate( toLayoutView(LayoutAPIShim::layoutObjectFrom( document->layoutViewItem())))) : WebAXObject(); }
AXObject* WebPagePopupImpl::rootAXObject() { if (!m_page || !m_page->mainFrame()) return 0; Document* document = toLocalFrame(m_page->mainFrame())->document(); if (!document) return 0; AXObjectCache* cache = document->axObjectCache(); DCHECK(cache); return toAXObjectCacheImpl(cache)->getOrCreate(toLayoutView( LayoutAPIShim::layoutObjectFrom(document->layoutViewItem()))); }
void PaintLayerClipper::calculateRects(const ClipRectsContext& context, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, ClipRect& backgroundRect, ClipRect& foregroundRect, const LayoutPoint* offsetFromRoot) const { bool isClippingRoot = m_layoutObject.layer() == context.rootLayer; if (!isClippingRoot && m_layoutObject.layer()->parent()) { backgroundRect = backgroundClipRect(context); backgroundRect.move(context.subPixelAccumulation); backgroundRect.intersect(paintDirtyRect); } else { backgroundRect = paintDirtyRect; } foregroundRect = backgroundRect; LayoutPoint offset; if (offsetFromRoot) offset = *offsetFromRoot; else m_layoutObject.layer()->convertToLayerCoords(context.rootLayer, offset); layerBounds = LayoutRect(offset, LayoutSize(m_layoutObject.layer()->size())); // Update the clip rects that will be passed to child layers. if (m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) { foregroundRect.intersect(toLayoutBox(m_layoutObject).overflowClipRect(offset, context.scrollbarRelevancy)); if (m_layoutObject.style()->hasBorderRadius()) foregroundRect.setHasRadius(true); // FIXME: Does not do the right thing with columns yet, since we don't yet factor in the // individual column boxes as overflow. // The LayoutView is special since its overflow clipping rect may be larger than its box rect (crbug.com/492871). LayoutRect layerBoundsWithVisualOverflow = m_layoutObject.isLayoutView() ? toLayoutView(m_layoutObject).viewRect() : toLayoutBox(m_layoutObject).visualOverflowRect(); toLayoutBox(m_layoutObject).flipForWritingMode(layerBoundsWithVisualOverflow); // PaintLayer are in physical coordinates, so the overflow has to be flipped. layerBoundsWithVisualOverflow.moveBy(offset); backgroundRect.intersect(layerBoundsWithVisualOverflow); } // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box. if (m_layoutObject.hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. LayoutRect newPosClip = toLayoutBox(m_layoutObject).clipRect(offset); backgroundRect.intersect(newPosClip); backgroundRect.setIsClippedByClipCss(); foregroundRect.intersect(newPosClip); foregroundRect.setIsClippedByClipCss(); } }
void IntersectionObservation::clipToFrameView(IntersectionGeometry& geometry) { Node* rootNode = m_observer->root(); LayoutObject* rootLayoutObject = m_observer->rootLayoutObject(); if (rootLayoutObject->isLayoutView()) { geometry.rootRect = LayoutRect(toLayoutView(rootLayoutObject)->frameView()->visibleContentRect()); m_observer->applyRootMargin(geometry.rootRect); geometry.intersectionRect.intersect(geometry.rootRect); } else { if (rootLayoutObject->isBox()) geometry.rootRect = LayoutRect(toLayoutBox(rootLayoutObject)->absoluteContentBox()); else geometry.rootRect = LayoutRect(rootLayoutObject->absoluteBoundingBoxRect()); m_observer->applyRootMargin(geometry.rootRect); } LayoutPoint scrollPosition(rootNode->document().view()->scrollPosition()); geometry.targetRect.moveBy(-scrollPosition); geometry.intersectionRect.moveBy(-scrollPosition); geometry.rootRect.moveBy(-scrollPosition); }
ClipRect PaintLayerClipper::applyOverflowClipToBackgroundRectWithGeometryMapper( const ClipRectsContext& context, const ClipRect& clip) const { const LayoutObject& layoutObject = *m_layer.layoutObject(); FloatRect clipRect(clip.rect()); if (shouldClipOverflow(context)) { LayoutRect layerBoundsWithVisualOverflow = layoutObject.isLayoutView() ? toLayoutView(layoutObject).viewRect() : toLayoutBox(layoutObject).visualOverflowRect(); toLayoutBox(layoutObject) .flipForWritingMode( // PaintLayer are in physical coordinates, so the overflow has to be // flipped. layerBoundsWithVisualOverflow); mapLocalToRootWithGeometryMapper(context, layerBoundsWithVisualOverflow); clipRect.intersect(FloatRect(layerBoundsWithVisualOverflow)); } return ClipRect(LayoutRect(clipRect)); }
PaintLayerPainter::PaintResult PaintLayerPainter::paintLayer(GraphicsContext& context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { // https://code.google.com/p/chromium/issues/detail?id=343772 DisableCompositingQueryAsserts disabler; if (m_paintLayer.compositingState() != NotComposited) { if (paintingInfo.globalPaintFlags() & GlobalPaintFlattenCompositingLayers) { // FIXME: ok, but what about GlobalPaintFlattenCompositingLayers? That's for printing and drag-image. // FIXME: why isn't the code here global, as opposed to being set on each paintLayer() call? paintFlags |= PaintLayerUncachedClipRects; } } // Non self-painting layers without self-painting descendants don't need to be painted as their // layoutObject() should properly paint itself. if (!m_paintLayer.isSelfPaintingLayer() && !m_paintLayer.hasSelfPaintingLayerDescendant()) return FullyPainted; if (shouldSuppressPaintingLayer(&m_paintLayer)) return FullyPainted; if (m_paintLayer.layoutObject()->isLayoutView() && toLayoutView(m_paintLayer.layoutObject())->frameView()->shouldThrottleRendering()) return FullyPainted; // If this layer is totally invisible then there is nothing to paint. if (!m_paintLayer.layoutObject()->opacity() && !m_paintLayer.layoutObject()->hasBackdropFilter()) return FullyPainted; if (m_paintLayer.paintsWithTransparency(paintingInfo.globalPaintFlags())) paintFlags |= PaintLayerHaveTransparency; LayerFixedPositionRecorder fixedPositionRecorder(context, *m_paintLayer.layoutObject()); // PaintLayerAppliedTransform is used in LayoutReplica, to avoid applying the transform twice. if (m_paintLayer.paintsWithTransform(paintingInfo.globalPaintFlags()) && !(paintFlags & PaintLayerAppliedTransform)) return paintLayerWithTransform(context, paintingInfo, paintFlags); return paintLayerContentsAndReflection(context, paintingInfo, paintFlags); }
PaintLayerPainter::PaintResult PaintLayerPainter::paintLayerContents(GraphicsContext& context, const PaintLayerPaintingInfo& paintingInfoArg, PaintLayerFlags paintFlags, FragmentPolicy fragmentPolicy) { ASSERT(m_paintLayer.isSelfPaintingLayer() || m_paintLayer.hasSelfPaintingLayerDescendant()); ASSERT(!(paintFlags & PaintLayerAppliedTransform)); bool isSelfPaintingLayer = m_paintLayer.isSelfPaintingLayer(); bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars; bool isPaintingScrollingContent = paintFlags & PaintLayerPaintingCompositingScrollingPhase; bool isPaintingCompositedForeground = paintFlags & PaintLayerPaintingCompositingForegroundPhase; bool isPaintingCompositedBackground = paintFlags & PaintLayerPaintingCompositingBackgroundPhase; bool isPaintingOverflowContents = paintFlags & PaintLayerPaintingOverflowContents; // Outline always needs to be painted even if we have no visible content. Also, // the outline is painted in the background phase during composited scrolling. // If it were painted in the foreground phase, it would move with the scrolled // content. When not composited scrolling, the outline is painted in the // foreground phase. Since scrolled contents are moved by paint invalidation in this // case, the outline won't get 'dragged along'. bool shouldPaintSelfOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars && ((isPaintingScrollingContent && isPaintingCompositedBackground) || (!isPaintingScrollingContent && isPaintingCompositedForeground)) && m_paintLayer.layoutObject()->styleRef().hasOutline(); bool shouldPaintContent = m_paintLayer.hasVisibleContent() && isSelfPaintingLayer && !isPaintingOverlayScrollbars; PaintResult result = FullyPainted; if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !m_paintLayer.layoutObject()->isLayoutView() && !m_paintLayer.layoutObject()->isDocumentElement()) return result; if (m_paintLayer.layoutObject()->isLayoutView() && toLayoutView(m_paintLayer.layoutObject())->frameView()->shouldThrottleRendering()) return result; // Ensure our lists are up-to-date. m_paintLayer.stackingNode()->updateLayerListsIfNeeded(); LayoutSize subpixelAccumulation = m_paintLayer.compositingState() == PaintsIntoOwnBacking ? m_paintLayer.subpixelAccumulation() : paintingInfoArg.subPixelAccumulation; ShouldRespectOverflowClip respectOverflowClip = shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()); Optional<SubsequenceRecorder> subsequenceRecorder; if (shouldCreateSubsequence(m_paintLayer, context, paintingInfoArg, paintFlags)) { if (!shouldRepaintSubsequence(m_paintLayer, paintingInfoArg, respectOverflowClip, subpixelAccumulation) && SubsequenceRecorder::useCachedSubsequenceIfPossible(context, m_paintLayer)) return result; subsequenceRecorder.emplace(context, m_paintLayer); } PaintLayerPaintingInfo paintingInfo = paintingInfoArg; LayoutPoint offsetFromRoot; m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); offsetFromRoot.move(subpixelAccumulation); LayoutRect bounds = m_paintLayer.physicalBoundingBox(offsetFromRoot); if (!paintingInfo.paintDirtyRect.contains(bounds)) result = MayBeClippedByPaintDirtyRect; LayoutRect rootRelativeBounds; bool rootRelativeBoundsComputed = false; if (paintingInfo.ancestorHasClipPathClipping && m_paintLayer.layoutObject()->isPositioned()) UseCounter::count(m_paintLayer.layoutObject()->document(), UseCounter::ClipPathOfPositionedElement); // These helpers output clip and compositing operations using a RAII pattern. Stack-allocated-varibles are destructed in the reverse order of construction, // so they are nested properly. ClipPathHelper clipPathHelper(context, m_paintLayer, paintingInfo, rootRelativeBounds, rootRelativeBoundsComputed, offsetFromRoot, paintFlags); Optional<CompositingRecorder> compositingRecorder; // Blending operations must be performed only with the nearest ancestor stacking context. // Note that there is no need to composite if we're painting the root. // FIXME: this should be unified further into PaintLayer::paintsWithTransparency(). bool shouldCompositeForBlendMode = (!m_paintLayer.layoutObject()->isDocumentElement() || m_paintLayer.layoutObject()->isSVGRoot()) && m_paintLayer.stackingNode()->isStackingContext() && m_paintLayer.hasNonIsolatedDescendantWithBlendMode(); if (shouldCompositeForBlendMode || m_paintLayer.paintsWithTransparency(paintingInfo.globalPaintFlags())) { FloatRect compositingBounds = FloatRect(m_paintLayer.paintingExtent(paintingInfo.rootLayer, paintingInfo.subPixelAccumulation, paintingInfo.globalPaintFlags())); compositingRecorder.emplace(context, *m_paintLayer.layoutObject(), WebCoreCompositeToSkiaComposite(CompositeSourceOver, m_paintLayer.layoutObject()->style()->blendMode()), m_paintLayer.layoutObject()->opacity(), &compositingBounds); } PaintLayerPaintingInfo localPaintingInfo(paintingInfo); localPaintingInfo.subPixelAccumulation = subpixelAccumulation; PaintLayerFragments layerFragments; if (shouldPaintContent || shouldPaintSelfOutline || isPaintingOverlayScrollbars) { // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment. ClipRectsCacheSlot cacheSlot = (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects; if (fragmentPolicy == ForceSingleFragment) m_paintLayer.appendSingleFragmentIgnoringPagination(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, localPaintingInfo.subPixelAccumulation); else m_paintLayer.collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, localPaintingInfo.subPixelAccumulation); if (shouldPaintContent) { // TODO(wangxianzhu): This is for old slow scrolling. Implement similar optimization for slimming paint v2. shouldPaintContent = atLeastOneFragmentIntersectsDamageRect(layerFragments, localPaintingInfo, paintFlags, offsetFromRoot); if (!shouldPaintContent) result = MayBeClippedByPaintDirtyRect; } } bool selectionOnly = localPaintingInfo.globalPaintFlags() & GlobalPaintSelectionOnly; { // Begin block for the lifetime of any filter. FilterPainter filterPainter(m_paintLayer, context, offsetFromRoot, layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect, localPaintingInfo, paintFlags, rootRelativeBounds, rootRelativeBoundsComputed); Optional<ScopedPaintChunkProperties> scopedPaintChunkProperties; if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { if (const auto* objectProperties = m_paintLayer.layoutObject()->objectPaintProperties()) { PaintChunkProperties properties(context.paintController().currentPaintChunkProperties()); if (TransformPaintPropertyNode* transform = objectProperties->transformForLayerContents()) properties.transform = transform; if (EffectPaintPropertyNode* effect = objectProperties->effect()) properties.effect = effect; scopedPaintChunkProperties.emplace(context.paintController(), properties); } } bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly; bool shouldPaintNegZOrderList = (isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground); bool shouldPaintOwnContents = isPaintingCompositedForeground && shouldPaintContent; bool shouldPaintNormalFlowAndPosZOrderLists = isPaintingCompositedForeground; bool shouldPaintOverlayScrollbars = isPaintingOverlayScrollbars; if (shouldPaintBackground) { paintBackgroundForFragments(layerFragments, context, paintingInfo.paintDirtyRect, localPaintingInfo, paintFlags); } if (shouldPaintNegZOrderList) { if (paintChildren(NegativeZOrderChildren, context, paintingInfo, paintFlags) == MayBeClippedByPaintDirtyRect) result = MayBeClippedByPaintDirtyRect; } if (shouldPaintOwnContents) { paintForegroundForFragments(layerFragments, context, paintingInfo.paintDirtyRect, localPaintingInfo, selectionOnly, paintFlags); } if (shouldPaintSelfOutline) paintSelfOutlineForFragments(layerFragments, context, localPaintingInfo, paintFlags); if (shouldPaintNormalFlowAndPosZOrderLists) { if (paintChildren(NormalFlowChildren | PositiveZOrderChildren, context, paintingInfo, paintFlags) == MayBeClippedByPaintDirtyRect) result = MayBeClippedByPaintDirtyRect; } if (shouldPaintOverlayScrollbars) paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo, paintFlags); } // FilterPainter block bool shouldPaintMask = (paintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && m_paintLayer.layoutObject()->hasMask() && !selectionOnly; bool shouldPaintClippingMask = (paintFlags & PaintLayerPaintingChildClippingMaskPhase) && shouldPaintContent && !selectionOnly; if (shouldPaintMask) paintMaskForFragments(layerFragments, context, localPaintingInfo, paintFlags); if (shouldPaintClippingMask) { // Paint the border radius mask for the fragments. paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintFlags); } if (subsequenceRecorder) m_paintLayer.setPreviousPaintResult(result); return result; }