PaintInvalidationState::PaintInvalidationState(const LayoutView& layoutView, Vector<LayoutObject*>& pendingDelayedPaintInvalidations, PaintInvalidationState* ownerPaintInvalidationState) : m_clipped(false) , m_cachedOffsetsEnabled(true) , m_forcedSubtreeInvalidationWithinContainer(false) , m_forcedSubtreeInvalidationRectUpdateWithinContainer(false) , m_viewClippingAndScrollOffsetDisabled(false) , m_paintInvalidationContainer(layoutView.containerForPaintInvalidation()) , m_pendingDelayedPaintInvalidations(pendingDelayedPaintInvalidations) , m_enclosingSelfPaintingLayer(*layoutView.layer()) { bool establishesPaintInvalidationContainer = layoutView == m_paintInvalidationContainer; if (!establishesPaintInvalidationContainer) { if ((ownerPaintInvalidationState && !ownerPaintInvalidationState->m_cachedOffsetsEnabled) || !layoutView.supportsPaintInvalidationStateCachedOffsets()) { m_cachedOffsetsEnabled = false; return; } if (ownerPaintInvalidationState && ownerPaintInvalidationState->m_forcedSubtreeInvalidationWithinContainer) m_forcedSubtreeInvalidationWithinContainer = true; FloatPoint point = layoutView.localToAncestorPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); m_paintOffset = LayoutSize(point.x(), point.y()); } m_clipRect = layoutView.viewRect(); m_clipRect.move(m_paintOffset); m_clipped = true; }
void ScrollableAreaPainter::paintOverflowControls( GraphicsContext& context, const IntPoint& paintOffset, const CullRect& cullRect, bool paintingOverlayControls) { // Don't do anything if we have no overflow. if (!getScrollableArea().box().hasOverflowClip()) return; IntPoint adjustedPaintOffset = paintOffset; if (paintingOverlayControls) adjustedPaintOffset = getScrollableArea().cachedOverlayScrollbarOffset(); CullRect adjustedCullRect(cullRect, -adjustedPaintOffset); // 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 will be false, and we should just tell the // root layer that there are overlay scrollbars that need to be painted. That // will cause the second pass through the layer tree to run, and we'll paint // the scrollbars then. In the meantime, cache tx and ty so that the second // pass doesn't need to re-enter the LayoutTree to get it right. if (getScrollableArea().hasOverlayScrollbars() && !paintingOverlayControls) { getScrollableArea().setCachedOverlayScrollbarOffset(paintOffset); // It's not necessary to do the second pass if the scrollbars paint into // layers. if ((getScrollableArea().horizontalScrollbar() && getScrollableArea().layerForHorizontalScrollbar()) || (getScrollableArea().verticalScrollbar() && getScrollableArea().layerForVerticalScrollbar())) return; if (!overflowControlsIntersectRect(adjustedCullRect)) return; LayoutView* layoutView = getScrollableArea().box().view(); PaintLayer* paintingRoot = getScrollableArea().layer()->enclosingLayerWithCompositedLayerMapping( IncludeSelf); if (!paintingRoot) paintingRoot = layoutView->layer(); paintingRoot->setContainsDirtyOverlayScrollbars(true); return; } // This check is required to avoid painting custom CSS scrollbars twice. if (paintingOverlayControls && !getScrollableArea().hasOverlayScrollbars()) return; { Optional<ScopedPaintChunkProperties> scopedTransformProperty; if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { const auto* objectProperties = getScrollableArea().box().paintProperties(); if (objectProperties && objectProperties->scrollbarPaintOffset()) { PaintChunkProperties properties( context.getPaintController().currentPaintChunkProperties()); properties.transform = objectProperties->scrollbarPaintOffset(); scopedTransformProperty.emplace( context.getPaintController(), getScrollableArea().box(), DisplayItem::kScrollOverflowControls, properties); } } if (getScrollableArea().horizontalScrollbar() && !getScrollableArea().layerForHorizontalScrollbar()) { TransformRecorder translateRecorder( context, *getScrollableArea().horizontalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); getScrollableArea().horizontalScrollbar()->paint(context, adjustedCullRect); } if (getScrollableArea().verticalScrollbar() && !getScrollableArea().layerForVerticalScrollbar()) { TransformRecorder translateRecorder( context, *getScrollableArea().verticalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); getScrollableArea().verticalScrollbar()->paint(context, adjustedCullRect); } } if (getScrollableArea().layerForScrollCorner()) return; // 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. paintScrollCorner(context, adjustedPaintOffset, cullRect); // Paint our resizer last, since it sits on top of the scroll corner. paintResizer(context, adjustedPaintOffset, cullRect); }
void FramePainter::paintContents(GraphicsContext& context, const GlobalPaintFlags globalPaintFlags, const IntRect& rect) { Document* document = frameView().frame().document(); #ifndef NDEBUG bool fillWithRed; if (document->printing()) fillWithRed = false; // Printing, don't fill with red (can't remember why). else if (frameView().frame().owner()) fillWithRed = false; // Subframe, don't fill with red. else if (frameView().isTransparent()) fillWithRed = false; // Transparent, don't fill with red. else if (globalPaintFlags & GlobalPaintSelectionOnly) fillWithRed = false; // Selections are transparent, don't fill with red. else fillWithRed = true; if (fillWithRed && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, *frameView().layoutView(), DisplayItem::DebugRedFill, LayoutPoint())) { IntRect contentRect(IntPoint(), frameView().contentsSize()); LayoutObjectDrawingRecorder drawingRecorder(context, *frameView().layoutView(), DisplayItem::DebugRedFill, contentRect, LayoutPoint()); } #endif LayoutView* layoutView = frameView().layoutView(); if (!layoutView) { WTF_LOG_ERROR("called FramePainter::paint with nil layoutObject"); return; } if (!frameView().shouldThrottleRendering()) { RELEASE_ASSERT(!frameView().needsLayout()); ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean); } TRACE_EVENT1("devtools.timeline", "Paint", "data", InspectorPaintEvent::data(layoutView, LayoutRect(rect), 0)); bool isTopLevelPainter = !s_inPaintContents; s_inPaintContents = true; FontCachePurgePreventer fontCachePurgePreventer; // TODO(jchaffraix): GlobalPaintFlags should be const during a paint // phase. Thus we should set this flag upfront (crbug.com/510280). GlobalPaintFlags localPaintFlags = globalPaintFlags; if (document->printing()) localPaintFlags |= GlobalPaintFlattenCompositingLayers | GlobalPaintPrinting; PaintLayer* rootLayer = layoutView->layer(); #if ENABLE(ASSERT) if (!frameView().shouldThrottleRendering()) layoutView->assertSubtreeIsLaidOut(); LayoutObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->layoutObject()); #endif PaintLayerPainter layerPainter(*rootLayer); float deviceScaleFactor = blink::deviceScaleFactor(rootLayer->layoutObject()->frame()); context.setDeviceScaleFactor(deviceScaleFactor); layerPainter.paint(context, LayoutRect(rect), localPaintFlags); if (rootLayer->containsDirtyOverlayScrollbars()) layerPainter.paintOverlayScrollbars(context, LayoutRect(rect), localPaintFlags); // Regions may have changed as a result of the visibility/z-index of element changing. if (document->annotatedRegionsDirty()) frameView().updateDocumentAnnotatedRegions(); if (isTopLevelPainter) { // Everything that happens after paintContents completions is considered // to be part of the next frame. memoryCache()->updateFramePaintTimestamp(); s_inPaintContents = false; } InspectorInstrumentation::didPaint(layoutView, 0, context, LayoutRect(rect)); }
void ScrollableAreaPainter::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) { // Don't do anything if we have no overflow. if (!m_scrollableArea.box().hasOverflowClip()) return; IntPoint adjustedPaintOffset = paintOffset; if (paintingOverlayControls) adjustedPaintOffset = m_scrollableArea.cachedOverlayScrollbarOffset(); IntRect localDamageRect = damageRect; localDamageRect.moveBy(-adjustedPaintOffset); // 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 // will be false, and we should just tell the root layer that there are overlay scrollbars // that need to be painted. That will cause the second pass through the layer tree to run, // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the // second pass doesn't need to re-enter the LayoutTree to get it right. if (m_scrollableArea.hasOverlayScrollbars() && !paintingOverlayControls) { m_scrollableArea.setCachedOverlayScrollbarOffset(paintOffset); // It's not necessary to do the second pass if the scrollbars paint into layers. if ((m_scrollableArea.horizontalScrollbar() && m_scrollableArea.layerForHorizontalScrollbar()) || (m_scrollableArea.verticalScrollbar() && m_scrollableArea.layerForVerticalScrollbar())) return; if (!overflowControlsIntersectRect(localDamageRect)) return; LayoutView* layoutView = m_scrollableArea.box().view(); DeprecatedPaintLayer* paintingRoot = m_scrollableArea.layer()->enclosingLayerWithCompositedDeprecatedPaintLayerMapping(IncludeSelf); if (!paintingRoot) paintingRoot = layoutView->layer(); paintingRoot->setContainsDirtyOverlayScrollbars(true); return; } // This check is required to avoid painting custom CSS scrollbars twice. if (paintingOverlayControls && !m_scrollableArea.hasOverlayScrollbars()) return; { if (m_scrollableArea.horizontalScrollbar() && !m_scrollableArea.layerForHorizontalScrollbar()) { TransformRecorder translateRecorder(*context, *m_scrollableArea.horizontalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); m_scrollableArea.horizontalScrollbar()->paint(context, localDamageRect); } if (m_scrollableArea.verticalScrollbar() && !m_scrollableArea.layerForVerticalScrollbar()) { TransformRecorder translateRecorder(*context, *m_scrollableArea.verticalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); m_scrollableArea.verticalScrollbar()->paint(context, localDamageRect); } } if (m_scrollableArea.layerForScrollCorner()) return; // 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. paintScrollCorner(context, adjustedPaintOffset, damageRect); // Paint our resizer last, since it sits on top of the scroll corner. paintResizer(context, adjustedPaintOffset, damageRect); }
void FramePainter::paintContents(GraphicsContext* context, const IntRect& rect) { Document* document = m_frameView.frame().document(); #ifndef NDEBUG bool fillWithRed; if (document->printing()) fillWithRed = false; // Printing, don't fill with red (can't remember why). else if (m_frameView.frame().owner()) fillWithRed = false; // Subframe, don't fill with red. else if (m_frameView.isTransparent()) fillWithRed = false; // Transparent, don't fill with red. else if (m_frameView.paintBehavior() & PaintBehaviorSelectionOnly) fillWithRed = false; // Selections are transparent, don't fill with red. else if (m_frameView.nodeToDraw()) fillWithRed = false; // Element images are transparent, don't fill with red. else fillWithRed = true; if (fillWithRed) { IntRect contentRect(IntPoint(), m_frameView.contentsSize()); DrawingRecorder drawingRecorder(*context, *m_frameView.layoutView(), DisplayItem::DebugRedFill, contentRect); if (!drawingRecorder.canUseCachedDrawing()) context->fillRect(contentRect, Color(0xFF, 0, 0)); } #endif LayoutView* layoutView = m_frameView.layoutView(); if (!layoutView) { WTF_LOG_ERROR("called FramePainter::paint with nil renderer"); return; } RELEASE_ASSERT(!m_frameView.needsLayout()); ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Paint", "data", InspectorPaintEvent::data(layoutView, LayoutRect(rect), 0)); bool isTopLevelPainter = !s_inPaintContents; s_inPaintContents = true; FontCachePurgePreventer fontCachePurgePreventer; PaintBehavior oldPaintBehavior = m_frameView.paintBehavior(); if (FrameView* parentView = m_frameView.parentFrameView()) { if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers) m_frameView.setPaintBehavior(m_frameView.paintBehavior() | PaintBehaviorFlattenCompositingLayers); } if (m_frameView.paintBehavior() == PaintBehaviorNormal) document->markers().invalidateRenderedRectsForMarkersInRect(LayoutRect(rect)); if (document->printing()) m_frameView.setPaintBehavior(m_frameView.paintBehavior() | PaintBehaviorFlattenCompositingLayers); ASSERT(!m_frameView.isPainting()); m_frameView.setIsPainting(true); // m_frameView.nodeToDraw() is used to draw only one element (and its descendants) LayoutObject* renderer = m_frameView.nodeToDraw() ? m_frameView.nodeToDraw()->layoutObject() : 0; DeprecatedPaintLayer* rootLayer = layoutView->layer(); #if ENABLE(ASSERT) layoutView->assertSubtreeIsLaidOut(); LayoutObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->layoutObject()); #endif DeprecatedPaintLayerPainter layerPainter(*rootLayer); float deviceScaleFactor = blink::deviceScaleFactor(rootLayer->layoutObject()->frame()); context->setDeviceScaleFactor(deviceScaleFactor); layerPainter.paint(context, LayoutRect(rect), m_frameView.paintBehavior(), renderer); if (rootLayer->containsDirtyOverlayScrollbars()) layerPainter.paintOverlayScrollbars(context, LayoutRect(rect), m_frameView.paintBehavior(), renderer); m_frameView.setIsPainting(false); m_frameView.setPaintBehavior(oldPaintBehavior); m_frameView.setLastPaintTime(currentTime()); // Regions may have changed as a result of the visibility/z-index of element changing. if (document->annotatedRegionsDirty()) m_frameView.updateAnnotatedRegions(); if (isTopLevelPainter) { // Everything that happens after paintContents completions is considered // to be part of the next frame. memoryCache()->updateFramePaintTimestamp(); s_inPaintContents = false; } InspectorInstrumentation::didPaint(layoutView, 0, context, LayoutRect(rect)); }