| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/paint/ViewPainter.h" | 6 #include "core/paint/ViewPainter.h" |
| 7 | 7 |
| 8 #include "core/frame/FrameView.h" | 8 #include "core/frame/FrameView.h" |
| 9 #include "core/frame/Settings.h" |
| 9 #include "core/layout/LayoutBox.h" | 10 #include "core/layout/LayoutBox.h" |
| 10 #include "core/layout/LayoutView.h" | 11 #include "core/layout/LayoutView.h" |
| 11 #include "core/paint/BlockPainter.h" | 12 #include "core/paint/BlockPainter.h" |
| 13 #include "core/paint/BoxPainter.h" |
| 14 #include "core/paint/DeprecatedPaintLayer.h" |
| 12 #include "core/paint/LayoutObjectDrawingRecorder.h" | 15 #include "core/paint/LayoutObjectDrawingRecorder.h" |
| 13 #include "core/paint/PaintInfo.h" | 16 #include "core/paint/PaintInfo.h" |
| 14 #include "platform/RuntimeEnabledFeatures.h" | 17 #include "platform/RuntimeEnabledFeatures.h" |
| 15 | 18 |
| 16 namespace blink { | 19 namespace blink { |
| 17 | 20 |
| 18 void ViewPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffs
et) | 21 void ViewPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffs
et) |
| 19 { | 22 { |
| 20 // If we ever require layout but receive a paint anyway, something has gone
horribly wrong. | 23 // If we ever require layout but receive a paint anyway, something has gone
horribly wrong. |
| 21 ASSERT(!m_layoutView.needsLayout()); | 24 ASSERT(!m_layoutView.needsLayout()); |
| 22 // LayoutViews should never be called to paint with an offset not on device
pixels. | 25 // LayoutViews should never be called to paint with an offset not on device
pixels. |
| 23 ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffse
t); | 26 ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffse
t); |
| 24 | 27 |
| 25 m_layoutView.paintObject(paintInfo, paintOffset); | 28 m_layoutView.paintObject(paintInfo, paintOffset); |
| 26 BlockPainter(m_layoutView).paintOverflowControlsIfNeeded(paintInfo, paintOff
set); | 29 BlockPainter(m_layoutView).paintOverflowControlsIfNeeded(paintInfo, paintOff
set); |
| 27 } | 30 } |
| 28 | 31 |
| 29 static inline bool layoutObjectObscuresBackground(LayoutBox* rootBox) | |
| 30 { | |
| 31 ASSERT(rootBox); | |
| 32 const ComputedStyle& style = rootBox->styleRef(); | |
| 33 if (style.visibility() != VISIBLE | |
| 34 || style.opacity() != 1 | |
| 35 || style.hasFilter() | |
| 36 || style.hasTransform()) | |
| 37 return false; | |
| 38 | |
| 39 if (rootBox->compositingState() == PaintsIntoOwnBacking) | |
| 40 return false; | |
| 41 | |
| 42 const LayoutObject* rootLayoutObject = rootBox->layoutObjectForRootBackgroun
d(); | |
| 43 if (rootLayoutObject->style()->backgroundClip() == TextFillBox) | |
| 44 return false; | |
| 45 | |
| 46 return true; | |
| 47 } | |
| 48 | |
| 49 void ViewPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo) | 32 void ViewPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo) |
| 50 { | 33 { |
| 51 if (m_layoutView.document().ownerElement() || !m_layoutView.view()) | |
| 52 return; | |
| 53 | |
| 54 if (paintInfo.skipRootBackground()) | 34 if (paintInfo.skipRootBackground()) |
| 55 return; | 35 return; |
| 56 | 36 |
| 57 bool shouldPaintBackground = true; | 37 // This function overrides background painting for the LayoutView. |
| 58 Node* documentElement = m_layoutView.document().documentElement(); | 38 // View background painting is special in the following ways: |
| 59 if (LayoutBox* rootBox = documentElement ? toLayoutBox(documentElement->layo
utObject()) : 0) | 39 // 1. The view paints background for the root element, the background positi
oning respects |
| 60 shouldPaintBackground = !rootFillsViewportBackground(rootBox) || !layout
ObjectObscuresBackground(rootBox); | 40 // the positioning and transformation of the root element. |
| 41 // 2. CSS background-clip is ignored, the background layers always expand to
cover the whole |
| 42 // canvas. None of the stacking context effects (except transformation) o
n the root element |
| 43 // affects the background. |
| 44 // 3. The main frame is also responsible for painting the user-agent-defined
base background |
| 45 // color. Conceptually it should be painted by the embedder but painting
it here allows |
| 46 // culling and pre-blending optimization when possible. |
| 61 | 47 |
| 62 // If painting will entirely fill the view, no need to fill the background. | 48 GraphicsContext& context = *paintInfo.context; |
| 63 if (!shouldPaintBackground) | 49 IntRect documentRect = m_layoutView.unscaledDocumentRect(); |
| 50 const Document& document = m_layoutView.document(); |
| 51 const FrameView& frameView = *m_layoutView.frameView(); |
| 52 bool isMainFrame = !document.ownerElement(); |
| 53 bool paintsBaseBackground = isMainFrame && !frameView.isTransparent(); |
| 54 bool shouldClearCanvas = paintsBaseBackground && (document.settings() && doc
ument.settings()->shouldClearDocumentBackground()); |
| 55 Color baseBackgroundColor = paintsBaseBackground ? frameView.baseBackgroundC
olor() : Color(); |
| 56 const LayoutObject* rootObject = document.documentElement() ? document.docum
entElement()->layoutObject() : nullptr; |
| 57 |
| 58 LayoutObjectDrawingRecorder recorder(context, m_layoutView, DisplayItem::Box
DecorationBackground, documentRect); |
| 59 if (recorder.canUseCachedDrawing()) |
| 64 return; | 60 return; |
| 65 | 61 |
| 66 // This code typically only executes if the root element's visibility has be
en set to hidden, | 62 // Compute the enclosing rect of the view, in root element space. |
| 67 // if there is a transform on the <html>, or if there is a page scale factor
less than 1. | 63 // |
| 68 // Only fill with the base background color (typically white) if we're the r
oot document, | 64 // For background colors we can simply paint the document rect in the defaul
t space. |
| 69 // since iframes/frames with no background in the child document should show
the parent's background. | 65 // However for background image, the root element transform applies. The str
ategy is to apply |
| 70 if (!m_layoutView.frameView()->isTransparent()) { | 66 // root element transform on the context and issue draw commands in the loca
l space, therefore |
| 71 LayoutRect paintRect(paintInfo.rect); | 67 // we need to apply inverse transform on the document rect to get to the roo
t element space. |
| 72 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) | 68 bool backgroundRenderable = true; |
| 73 paintRect = m_layoutView.viewRect(); | 69 TransformationMatrix transform; |
| 70 IntRect paintRect = documentRect; |
| 71 if (!rootObject || !rootObject->isBox()) { |
| 72 backgroundRenderable = false; |
| 73 } else if (rootObject->hasLayer()) { |
| 74 const DeprecatedPaintLayer& rootLayer = *toLayoutBoxModelObject(rootObje
ct)->layer(); |
| 75 LayoutPoint offset; |
| 76 rootLayer.convertToLayerCoords(nullptr, offset); |
| 77 transform.translate(offset.x(), offset.y()); |
| 78 transform.multiply(rootLayer.renderableTransform(paintInfo.paintBehavior
)); |
| 74 | 79 |
| 75 LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutView, D
isplayItem::BoxDecorationBackground, m_layoutView.viewRect()); | 80 if (!transform.isInvertible()) { |
| 76 if (!recorder.canUseCachedDrawing()) { | 81 backgroundRenderable = false; |
| 77 Color baseColor = m_layoutView.frameView()->baseBackgroundColor(); | 82 } else { |
| 78 paintInfo.context->fillRect(paintRect, baseColor, baseColor.alpha()
? | 83 bool isClamped; |
| 79 SkXfermode::kSrc_Mode : SkXfermode::kClear_Mode); | 84 paintRect = transform.inverse().projectQuad(FloatQuad(documentRect),
&isClamped).enclosingBoundingBox(); |
| 85 backgroundRenderable = !isClamped; |
| 80 } | 86 } |
| 81 } | 87 } |
| 82 } | |
| 83 | 88 |
| 84 bool ViewPainter::rootFillsViewportBackground(LayoutBox* rootBox) const | 89 if (!backgroundRenderable) { |
| 85 { | 90 if (baseBackgroundColor.alpha()) |
| 86 ASSERT(rootBox); | 91 context.fillRect(documentRect, baseBackgroundColor, shouldClearCanva
s ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode); |
| 87 // CSS Boxes always fill the viewport background (see paintRootBoxFillLayers
) | 92 else if (shouldClearCanvas) |
| 88 if (!rootBox->isSVG()) | 93 context.fillRect(documentRect, Color(), SkXfermode::kClear_Mode); |
| 89 return true; | 94 return; |
| 95 } |
| 90 | 96 |
| 91 return rootBox->frameRect().contains(m_layoutView.frameRect()); | 97 BoxPainter::FillLayerOcclusionOutputList reversedPaintList; |
| 98 bool shouldDrawBackgroundInSeparateBuffer = BoxPainter(m_layoutView).calcula
teFillLayerOcclusionCulling(reversedPaintList, m_layoutView.style()->backgroundL
ayers()); |
| 99 ASSERT(reversedPaintList.size()); |
| 100 Color rootBackgroundColor = m_layoutView.style()->visitedDependentColor(CSSP
ropertyBackgroundColor); |
| 101 |
| 102 // If the root background color is opaque, isolation group can be skipped be
cause the canvas |
| 103 // will be cleared by root background color. |
| 104 if (!rootBackgroundColor.hasAlpha()) |
| 105 shouldDrawBackgroundInSeparateBuffer = false; |
| 106 |
| 107 // We are going to clear the canvas with transparent pixels, isolation group
can be skipped. |
| 108 if (!baseBackgroundColor.alpha() && shouldClearCanvas) |
| 109 shouldDrawBackgroundInSeparateBuffer = false; |
| 110 |
| 111 if (shouldDrawBackgroundInSeparateBuffer) { |
| 112 if (baseBackgroundColor.alpha()) |
| 113 context.fillRect(documentRect, baseBackgroundColor, shouldClearCanva
s ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode); |
| 114 context.beginLayer(); |
| 115 } |
| 116 |
| 117 Color combinedBackgroundColor = shouldDrawBackgroundInSeparateBuffer ? rootB
ackgroundColor : baseBackgroundColor.blend(rootBackgroundColor); |
| 118 if (combinedBackgroundColor.alpha()) |
| 119 context.fillRect(documentRect, combinedBackgroundColor, (shouldDrawBackg
roundInSeparateBuffer || shouldClearCanvas) ? SkXfermode::kSrc_Mode : SkXfermode
::kSrcOver_Mode); |
| 120 else if (shouldClearCanvas && !shouldDrawBackgroundInSeparateBuffer) |
| 121 context.fillRect(documentRect, Color(), SkXfermode::kClear_Mode); |
| 122 |
| 123 context.save(); |
| 124 // TODO(trchen): We should be able to handle 3D-transformed root |
| 125 // background with slimming paint by using transform display items. |
| 126 context.concatCTM(transform.toAffineTransform()); |
| 127 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); +
+it) { |
| 128 ASSERT((*it)->clip() == BorderFillBox); |
| 129 BoxPainter::paintFillLayerExtended(m_layoutView, paintInfo, Color(), **i
t, LayoutRect(paintRect), BackgroundBleedNone); |
| 130 } |
| 131 context.restore(); |
| 132 |
| 133 if (shouldDrawBackgroundInSeparateBuffer) |
| 134 context.endLayer(); |
| 92 } | 135 } |
| 93 | 136 |
| 94 } // namespace blink | 137 } // namespace blink |
| OLD | NEW |