void ViewPainter::paintBoxDecorationBackground(PaintInfo& paintInfo) { if (m_renderView.document().ownerElement() || !m_renderView.view()) return; if (paintInfo.skipRootBackground()) return; bool shouldPaintBackground = true; Node* documentElement = m_renderView.document().documentElement(); if (RenderBox* rootBox = documentElement ? toRenderBox(documentElement->renderer()) : 0) shouldPaintBackground = !rootFillsViewportBackground(rootBox) || !rendererObscuresBackground(rootBox); // If painting will entirely fill the view, no need to fill the background. if (!shouldPaintBackground) return; // This code typically only executes if the root element's visibility has been set to hidden, // if there is a transform on the <html>, or if there is a page scale factor less than 1. // Only fill with the base background color (typically white) if we're the root document, // since iframes/frames with no background in the child document should show the parent's background. if (!m_renderView.frameView()->isTransparent()) { Color baseColor = m_renderView.frameView()->baseBackgroundColor(); if (baseColor.alpha()) { CompositeOperator previousOperator = paintInfo.context->compositeOperation(); paintInfo.context->setCompositeOperation(CompositeCopy); paintInfo.context->fillRect(paintInfo.rect, baseColor); paintInfo.context->setCompositeOperation(previousOperator); } else { paintInfo.context->clearRect(paintInfo.rect); } } }
void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) { // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers, // layers with reflections, or transformed layers. // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside // a transform, transparency layer, etc. Element* elt; for (elt = document().ownerElement(); view() && elt && elt->renderer(); elt = elt->document().ownerElement()) { RenderLayer* layer = elt->renderer()->enclosingLayer(); if (layer->cannotBlitToWindow()) { frameView()->setCannotBlitToWindow(); break; } if (layer->enclosingCompositingLayerForRepaint()) { frameView()->setCannotBlitToWindow(); break; } } if (document().ownerElement() || !view()) return; if (paintInfo.skipRootBackground()) return; bool shouldPaintBackground = true; Node* documentElement = document().documentElement(); if (RenderBox* rootBox = documentElement ? toRenderBox(documentElement->renderer()) : 0) shouldPaintBackground = !rootFillsViewportBackground(rootBox) || !rendererObscuresBackground(rootBox); // If painting will entirely fill the view, no need to fill the background. if (!shouldPaintBackground) return; // This code typically only executes if the root element's visibility has been set to hidden, // if there is a transform on the <html>, or if there is a page scale factor less than 1. // Only fill with the base background color (typically white) if we're the root document, // since iframes/frames with no background in the child document should show the parent's background. if (frameView()->isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. frameView()->setCannotBlitToWindow(); // The parent must show behind the child. else { Color baseColor = frameView()->baseBackgroundColor(); if (baseColor.alpha()) { CompositeOperator previousOperator = paintInfo.context->compositeOperation(); paintInfo.context->setCompositeOperation(CompositeCopy); paintInfo.context->fillRect(paintInfo.rect, baseColor); paintInfo.context->setCompositeOperation(previousOperator); } else { paintInfo.context->clearRect(paintInfo.rect); } } }
void ViewPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo) { if (paintInfo.skipRootBackground()) return; // This function overrides background painting for the LayoutView. // View background painting is special in the following ways: // 1. The view paints background for the root element, the background positioning respects // the positioning and transformation of the root element. // 2. CSS background-clip is ignored, the background layers always expand to cover the whole // canvas. None of the stacking context effects (except transformation) on the root element // affects the background. // 3. The main frame is also responsible for painting the user-agent-defined base background // color. Conceptually it should be painted by the embedder but painting it here allows // culling and pre-blending optimization when possible. GraphicsContext& context = paintInfo.context; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, m_layoutView, DisplayItem::DocumentBackground, LayoutPoint())) return; // The background fill rect is the size of the LayoutView's main GraphicsLayer. IntRect backgroundRect = pixelSnappedIntRect(m_layoutView.layer()->boundingBoxForCompositing()); const Document& document = m_layoutView.document(); const FrameView& frameView = *m_layoutView.frameView(); bool isMainFrame = !document.ownerElement(); bool paintsBaseBackground = isMainFrame && !frameView.isTransparent(); bool shouldClearCanvas = paintsBaseBackground && (document.settings() && document.settings()->shouldClearDocumentBackground()); Color baseBackgroundColor = paintsBaseBackground ? frameView.baseBackgroundColor() : Color(); Color rootBackgroundColor = m_layoutView.style()->visitedDependentColor(CSSPropertyBackgroundColor); const LayoutObject* rootObject = document.documentElement() ? document.documentElement()->layoutObject() : nullptr; LayoutObjectDrawingRecorder recorder(context, m_layoutView, DisplayItem::DocumentBackground, backgroundRect, LayoutPoint()); // Special handling for print economy mode. bool forceBackgroundToWhite = BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(m_layoutView.styleRef(), document); if (forceBackgroundToWhite) { // If for any reason the view background is not transparent, paint white instead, otherwise keep transparent as is. if (paintsBaseBackground || rootBackgroundColor.alpha() || m_layoutView.style()->backgroundLayers().image()) context.fillRect(backgroundRect, Color::white, SkXfermode::kSrc_Mode); return; } // Compute the enclosing rect of the view, in root element space. // // For background colors we can simply paint the document rect in the default space. // However for background image, the root element transform applies. The strategy is to apply // root element transform on the context and issue draw commands in the local space, therefore // we need to apply inverse transform on the document rect to get to the root element space. bool backgroundRenderable = true; TransformationMatrix transform; IntRect paintRect = backgroundRect; if (!rootObject || !rootObject->isBox()) { backgroundRenderable = false; } else if (rootObject->hasLayer()) { const PaintLayer& rootLayer = *toLayoutBoxModelObject(rootObject)->layer(); LayoutPoint offset; rootLayer.convertToLayerCoords(nullptr, offset); transform.translate(offset.x(), offset.y()); transform.multiply(rootLayer.renderableTransform(paintInfo.globalPaintFlags())); if (!transform.isInvertible()) { backgroundRenderable = false; } else { bool isClamped; paintRect = transform.inverse().projectQuad(FloatQuad(backgroundRect), &isClamped).enclosingBoundingBox(); backgroundRenderable = !isClamped; } } if (!backgroundRenderable) { if (baseBackgroundColor.alpha()) context.fillRect(backgroundRect, baseBackgroundColor, shouldClearCanvas ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode); else if (shouldClearCanvas) context.fillRect(backgroundRect, Color(), SkXfermode::kClear_Mode); return; } BoxPainter::FillLayerOcclusionOutputList reversedPaintList; bool shouldDrawBackgroundInSeparateBuffer = BoxPainter(m_layoutView).calculateFillLayerOcclusionCulling(reversedPaintList, m_layoutView.style()->backgroundLayers()); ASSERT(reversedPaintList.size()); // If the root background color is opaque, isolation group can be skipped because the canvas // will be cleared by root background color. if (!rootBackgroundColor.hasAlpha()) shouldDrawBackgroundInSeparateBuffer = false; // We are going to clear the canvas with transparent pixels, isolation group can be skipped. if (!baseBackgroundColor.alpha() && shouldClearCanvas) shouldDrawBackgroundInSeparateBuffer = false; if (shouldDrawBackgroundInSeparateBuffer) { if (baseBackgroundColor.alpha()) context.fillRect(backgroundRect, baseBackgroundColor, shouldClearCanvas ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode); context.beginLayer(); } Color combinedBackgroundColor = shouldDrawBackgroundInSeparateBuffer ? rootBackgroundColor : baseBackgroundColor.blend(rootBackgroundColor); if (combinedBackgroundColor.alpha()) { if (!combinedBackgroundColor.hasAlpha() && RuntimeEnabledFeatures::slimmingPaintV2Enabled()) recorder.setKnownToBeOpaque(); context.fillRect(backgroundRect, combinedBackgroundColor, (shouldDrawBackgroundInSeparateBuffer || shouldClearCanvas) ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode); } else if (shouldClearCanvas && !shouldDrawBackgroundInSeparateBuffer) { context.fillRect(backgroundRect, Color(), SkXfermode::kClear_Mode); } for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); ++it) { ASSERT((*it)->clip() == BorderFillBox); bool shouldPaintInViewportSpace = (*it)->attachment() == FixedBackgroundAttachment; if (shouldPaintInViewportSpace) { BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(LayoutRect::infiniteIntRect()), BackgroundBleedNone); } else { context.save(); // TODO(trchen): We should be able to handle 3D-transformed root // background with slimming paint by using transform display items. context.concatCTM(transform.toAffineTransform()); BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(paintRect), BackgroundBleedNone); context.restore(); } } if (shouldDrawBackgroundInSeparateBuffer) context.endLayer(); }
void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) { if (!paintInfo.shouldPaintWithinRoot(*this)) return; // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers, // layers with reflections, or transformed layers. // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside // a transform, transparency layer, etc. Element* elt; for (elt = document().ownerElement(); elt && elt->renderer(); elt = elt->document().ownerElement()) { RenderLayer* layer = elt->renderer()->enclosingLayer(); if (layer->cannotBlitToWindow()) { frameView().setCannotBlitToWindow(); break; } #if USE(ACCELERATED_COMPOSITING) if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) { if (!compositingLayer->backing()->paintsIntoWindow()) { frameView().setCannotBlitToWindow(); break; } } #endif } if (document().ownerElement()) return; if (paintInfo.skipRootBackground()) return; bool rootFillsViewport = false; bool rootObscuresBackground = false; Element* documentElement = document().documentElement(); if (RenderElement* rootRenderer = documentElement ? documentElement->renderer() : 0) { // The document element's renderer is currently forced to be a block, but may not always be. RenderBox* rootBox = rootRenderer->isBox() ? toRenderBox(rootRenderer) : 0; rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height(); rootObscuresBackground = rendererObscuresBackground(rootRenderer); } Page* page = document().page(); float pageScaleFactor = page ? page->pageScaleFactor() : 1; // If painting will entirely fill the view, no need to fill the background. if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1) return; // This code typically only executes if the root element's visibility has been set to hidden, // if there is a transform on the <html>, or if there is a page scale factor less than 1. // Only fill with the base background color (typically white) if we're the root document, // since iframes/frames with no background in the child document should show the parent's background. if (frameView().isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. frameView().setCannotBlitToWindow(); // The parent must show behind the child. else { Color baseColor = frameView().baseBackgroundColor(); if (baseColor.alpha()) { CompositeOperator previousOperator = paintInfo.context->compositeOperation(); paintInfo.context->setCompositeOperation(CompositeCopy); paintInfo.context->fillRect(paintInfo.rect, baseColor, style()->colorSpace()); paintInfo.context->setCompositeOperation(previousOperator); } else paintInfo.context->clearRect(paintInfo.rect); } }