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
3 // found in the LICENSE file.
6 #include "core/paint/ViewPainter.h"
8 #include "core/frame/FrameView.h"
9 #include "core/frame/Settings.h"
10 #include "core/layout/LayoutBox.h"
11 #include "core/layout/LayoutView.h"
12 #include "core/paint/BlockPainter.h"
13 #include "core/paint/BoxPainter.h"
14 #include "core/paint/DeprecatedPaintLayer.h"
15 #include "core/paint/LayoutObjectDrawingRecorder.h"
16 #include "core/paint/PaintInfo.h"
17 #include "platform/RuntimeEnabledFeatures.h"
21 void ViewPainter::paint(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
23 // If we ever require layout but receive a paint anyway, something has gone horribly wrong.
24 ASSERT(!m_layoutView
.needsLayout());
25 // LayoutViews should never be called to paint with an offset not on device pixels.
26 ASSERT(LayoutPoint(IntPoint(paintOffset
.x(), paintOffset
.y())) == paintOffset
);
28 m_layoutView
.paintObject(paintInfo
, paintOffset
);
29 BlockPainter(m_layoutView
).paintOverflowControlsIfNeeded(paintInfo
, paintOffset
);
32 void ViewPainter::paintBoxDecorationBackground(const PaintInfo
& paintInfo
)
34 if (!paintInfo
.shouldPaintWithinRoot(&m_layoutView
))
37 if (paintInfo
.skipRootBackground())
40 // This function overrides background painting for the LayoutView.
41 // View background painting is special in the following ways:
42 // 1. The view paints background for the root element, the background positioning respects
43 // the positioning and transformation of the root element.
44 // 2. CSS background-clip is ignored, the background layers always expand to cover the whole
45 // canvas. None of the stacking context effects (except transformation) on the root element
46 // affects the background.
47 // 3. The main frame is also responsible for painting the user-agent-defined base background
48 // color. Conceptually it should be painted by the embedder but painting it here allows
49 // culling and pre-blending optimization when possible.
51 GraphicsContext
& context
= *paintInfo
.context
;
52 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context
, m_layoutView
, DisplayItem::BoxDecorationBackground
, LayoutPoint()))
55 IntRect documentRect
= m_layoutView
.unscaledDocumentRect();
56 const Document
& document
= m_layoutView
.document();
57 const FrameView
& frameView
= *m_layoutView
.frameView();
58 bool isMainFrame
= !document
.ownerElement();
59 bool paintsBaseBackground
= isMainFrame
&& !frameView
.isTransparent();
60 bool shouldClearCanvas
= paintsBaseBackground
&& (document
.settings() && document
.settings()->shouldClearDocumentBackground());
61 Color baseBackgroundColor
= paintsBaseBackground
? frameView
.baseBackgroundColor() : Color();
62 Color rootBackgroundColor
= m_layoutView
.style()->visitedDependentColor(CSSPropertyBackgroundColor
);
63 const LayoutObject
* rootObject
= document
.documentElement() ? document
.documentElement()->layoutObject() : nullptr;
65 LayoutObjectDrawingRecorder
recorder(context
, m_layoutView
, DisplayItem::BoxDecorationBackground
, documentRect
, LayoutPoint());
67 // Special handling for print economy mode.
68 bool forceBackgroundToWhite
= BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(m_layoutView
.styleRef(), document
);
69 if (forceBackgroundToWhite
) {
70 // If for any reason the view background is not transparent, paint white instead, otherwise keep transparent as is.
71 if (paintsBaseBackground
|| rootBackgroundColor
.alpha() || m_layoutView
.style()->backgroundLayers().image())
72 context
.fillRect(documentRect
, Color::white
, SkXfermode::kSrc_Mode
);
76 // Compute the enclosing rect of the view, in root element space.
78 // For background colors we can simply paint the document rect in the default space.
79 // However for background image, the root element transform applies. The strategy is to apply
80 // root element transform on the context and issue draw commands in the local space, therefore
81 // we need to apply inverse transform on the document rect to get to the root element space.
82 bool backgroundRenderable
= true;
83 TransformationMatrix transform
;
84 IntRect paintRect
= documentRect
;
85 if (!rootObject
|| !rootObject
->isBox()) {
86 backgroundRenderable
= false;
87 } else if (rootObject
->hasLayer()) {
88 const DeprecatedPaintLayer
& rootLayer
= *toLayoutBoxModelObject(rootObject
)->layer();
90 rootLayer
.convertToLayerCoords(nullptr, offset
);
91 transform
.translate(offset
.x(), offset
.y());
92 transform
.multiply(rootLayer
.renderableTransform(paintInfo
.globalPaintFlags()));
94 if (!transform
.isInvertible()) {
95 backgroundRenderable
= false;
98 paintRect
= transform
.inverse().projectQuad(FloatQuad(documentRect
), &isClamped
).enclosingBoundingBox();
99 backgroundRenderable
= !isClamped
;
103 if (!backgroundRenderable
) {
104 if (baseBackgroundColor
.alpha())
105 context
.fillRect(documentRect
, baseBackgroundColor
, shouldClearCanvas
? SkXfermode::kSrc_Mode
: SkXfermode::kSrcOver_Mode
);
106 else if (shouldClearCanvas
)
107 context
.fillRect(documentRect
, Color(), SkXfermode::kClear_Mode
);
111 BoxPainter::FillLayerOcclusionOutputList reversedPaintList
;
112 bool shouldDrawBackgroundInSeparateBuffer
= BoxPainter(m_layoutView
).calculateFillLayerOcclusionCulling(reversedPaintList
, m_layoutView
.style()->backgroundLayers());
113 ASSERT(reversedPaintList
.size());
115 // If the root background color is opaque, isolation group can be skipped because the canvas
116 // will be cleared by root background color.
117 if (!rootBackgroundColor
.hasAlpha())
118 shouldDrawBackgroundInSeparateBuffer
= false;
120 // We are going to clear the canvas with transparent pixels, isolation group can be skipped.
121 if (!baseBackgroundColor
.alpha() && shouldClearCanvas
)
122 shouldDrawBackgroundInSeparateBuffer
= false;
124 if (shouldDrawBackgroundInSeparateBuffer
) {
125 if (baseBackgroundColor
.alpha())
126 context
.fillRect(documentRect
, baseBackgroundColor
, shouldClearCanvas
? SkXfermode::kSrc_Mode
: SkXfermode::kSrcOver_Mode
);
127 context
.beginLayer();
130 Color combinedBackgroundColor
= shouldDrawBackgroundInSeparateBuffer
? rootBackgroundColor
: baseBackgroundColor
.blend(rootBackgroundColor
);
131 if (combinedBackgroundColor
.alpha())
132 context
.fillRect(documentRect
, combinedBackgroundColor
, (shouldDrawBackgroundInSeparateBuffer
|| shouldClearCanvas
) ? SkXfermode::kSrc_Mode
: SkXfermode::kSrcOver_Mode
);
133 else if (shouldClearCanvas
&& !shouldDrawBackgroundInSeparateBuffer
)
134 context
.fillRect(documentRect
, Color(), SkXfermode::kClear_Mode
);
136 for (auto it
= reversedPaintList
.rbegin(); it
!= reversedPaintList
.rend(); ++it
) {
137 ASSERT((*it
)->clip() == BorderFillBox
);
139 bool shouldPaintInViewportSpace
= (*it
)->attachment() == FixedBackgroundAttachment
;
140 if (shouldPaintInViewportSpace
) {
141 BoxPainter::paintFillLayerExtended(m_layoutView
, paintInfo
, Color(), **it
, LayoutRect::infiniteRect(), BackgroundBleedNone
);
144 // TODO(trchen): We should be able to handle 3D-transformed root
145 // background with slimming paint by using transform display items.
146 context
.concatCTM(transform
.toAffineTransform());
147 BoxPainter::paintFillLayerExtended(m_layoutView
, paintInfo
, Color(), **it
, LayoutRect(paintRect
), BackgroundBleedNone
);
152 if (shouldDrawBackgroundInSeparateBuffer
)