Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / paint / ViewPainter.cpp
blob9feee6fa57d7bd0a78e304e8956ec46f9fbcef80
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.
5 #include "config.h"
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"
19 namespace blink {
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))
35 return;
37 if (paintInfo.skipRootBackground())
38 return;
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()))
53 return;
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);
73 return;
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();
89 LayoutPoint offset;
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;
96 } else {
97 bool isClamped;
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);
108 return;
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);
142 } else {
143 context.save();
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);
148 context.restore();
152 if (shouldDrawBackgroundInSeparateBuffer)
153 context.endLayer();
156 } // namespace blink