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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 5
0
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));
}