Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: Source/core/paint/BoxPainter.cpp

Issue 550363004: Factor painting code out of RenderBox into a new class called BoxPainter. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | Source/core/rendering/RenderBox.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "config.h"
6 #include "core/paint/BoxPainter.h"
7
8 #include "core/paint/BoxDecorationData.h"
9 #include "core/rendering/PaintInfo.h"
10 #include "core/rendering/RenderBox.h"
11 #include "core/rendering/RenderLayer.h"
12 #include "core/rendering/RenderTable.h"
13 #include "core/rendering/RenderTheme.h"
14 #include "core/rendering/RenderView.h"
15 #include "platform/geometry/LayoutPoint.h"
16 #include "platform/graphics/GraphicsContextStateSaver.h"
17
18 namespace blink {
19
20 void BoxPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
21 {
22 LayoutPoint adjustedPaintOffset = paintOffset + m_renderBox.location();
23 // default implementation. Just pass paint through to the children
24 PaintInfo childInfo(paintInfo);
25 childInfo.updatePaintingRootForChildren(&m_renderBox);
26 for (RenderObject* child = m_renderBox.slowFirstChild(); child; child = chil d->nextSibling())
27 child->paint(childInfo, adjustedPaintOffset);
28 }
29
30 void BoxPainter::paintBoxDecorationBackground(PaintInfo& paintInfo, const Layout Point& paintOffset)
31 {
32 if (!paintInfo.shouldPaintWithinRoot(&m_renderBox))
33 return;
34
35 LayoutRect paintRect = m_renderBox.borderBoxRect();
36 paintRect.moveBy(paintOffset);
37 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect);
38 }
39
40 void BoxPainter::paintBoxDecorationBackgroundWithRect(PaintInfo& paintInfo, cons t LayoutPoint& paintOffset, const LayoutRect& paintRect)
41 {
42 RenderStyle* style = m_renderBox.style();
43 BoxDecorationData boxDecorationData(*style, m_renderBox.canRenderBorderImage (), m_renderBox.backgroundHasOpaqueTopLayer(), paintInfo.context);
44
45 // FIXME: Should eventually give the theme control over whether the box shad ow should paint, since controls could have
46 // custom shadows of their own.
47 if (!m_renderBox.boxShadowShouldBeAppliedToBackground(boxDecorationData.blee dAvoidance()))
48 m_renderBox.paintBoxShadow(paintInfo, paintRect, style, Normal);
49
50 GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
51 if (boxDecorationData.bleedAvoidance() == BackgroundBleedClipBackground) {
52 stateSaver.save();
53 RoundedRect border = style->getRoundedBorderFor(paintRect);
54 paintInfo.context->clipRoundedRect(border);
55 }
56
57 // If we have a native theme appearance, paint that before painting our back ground.
58 // The theme will tell us whether or not we should also paint the CSS backgr ound.
59 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
60 bool themePainted = boxDecorationData.hasAppearance && !RenderTheme::theme() .paint(&m_renderBox, paintInfo, snappedPaintRect);
61 if (!themePainted) {
62 if (boxDecorationData.bleedAvoidance() == BackgroundBleedBackgroundOverB order)
63 m_renderBox.paintBorder(paintInfo, paintRect, style, boxDecorationDa ta.bleedAvoidance());
64
65 paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, boxDecorationData.bleedAvoidance());
66
67 if (boxDecorationData.hasAppearance)
68 RenderTheme::theme().paintDecorations(&m_renderBox, paintInfo, snapp edPaintRect);
69 }
70 m_renderBox.paintBoxShadow(paintInfo, paintRect, style, Inset);
71
72 // The theme will tell us whether or not we should also paint the CSS border .
73 if (boxDecorationData.hasBorder && boxDecorationData.bleedAvoidance() != Bac kgroundBleedBackgroundOverBorder
74 && (!boxDecorationData.hasAppearance || (!themePainted && RenderTheme::t heme().paintBorderOnly(&m_renderBox, paintInfo, snappedPaintRect)))
75 && !(m_renderBox.isTable() && toRenderTable(&m_renderBox)->collapseBorde rs()))
76 m_renderBox.paintBorder(paintInfo, paintRect, style, boxDecorationData.b leedAvoidance());
77 }
78
79 static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
80 {
81 ASSERT(bodyElementRenderer->isBody());
82 // The <body> only paints its background if the root element has defined a b ackground independent of the body,
83 // or if the <body>'s parent is not the document element's renderer (e.g. in side SVG foreignObject).
84 RenderObject* documentElementRenderer = bodyElementRenderer->document().docu mentElement()->renderer();
85 return documentElementRenderer
86 && !documentElementRenderer->hasBackground()
87 && (documentElementRenderer == bodyElementRenderer->parent());
88 }
89
90 void BoxPainter::paintBackground(const PaintInfo& paintInfo, const LayoutRect& p aintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance)
91 {
92 if (m_renderBox.isDocumentElement()) {
93 paintRootBoxFillLayers(paintInfo);
94 return;
95 }
96 if (m_renderBox.isBody() && skipBodyBackground(&m_renderBox))
97 return;
98 if (m_renderBox.boxDecorationBackgroundIsKnownToBeObscured())
99 return;
100 paintFillLayers(paintInfo, backgroundColor, m_renderBox.style()->backgroundL ayers(), paintRect, bleedAvoidance);
101 }
102
103 void BoxPainter::paintRootBoxFillLayers(const PaintInfo& paintInfo)
104 {
105 if (paintInfo.skipRootBackground())
106 return;
107
108 RenderObject* rootBackgroundRenderer = m_renderBox.rendererForRootBackground ();
109
110 const FillLayer& bgLayer = rootBackgroundRenderer->style()->backgroundLayers ();
111 Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundCo lor);
112
113 paintFillLayers(paintInfo, bgColor, bgLayer, m_renderBox.view()->backgroundR ect(&m_renderBox), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRende rer);
114 }
115
116 void BoxPainter::paintFillLayers(const PaintInfo& paintInfo, const Color& c, con st FillLayer& fillLayer, const LayoutRect& rect,
117 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
118 {
119 Vector<const FillLayer*, 8> layers;
120 const FillLayer* curLayer = &fillLayer;
121 bool shouldDrawBackgroundInSeparateBuffer = false;
122 bool isBottomLayerOccluded = false;
123 while (curLayer) {
124 layers.append(curLayer);
125 // Stop traversal when an opaque layer is encountered.
126 // FIXME : It would be possible for the following occlusion culling test to be more aggressive
127 // on layers with no repeat by testing whether the image covers the layo ut rect.
128 // Testing that here would imply duplicating a lot of calculations that are currently done in
129 // RenderBoxModelObject::paintFillLayerExtended. A more efficient soluti on might be to move
130 // the layer recursion into paintFillLayerExtended, or to compute the la yer geometry here
131 // and pass it down.
132
133 if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != We bBlendModeNormal)
134 shouldDrawBackgroundInSeparateBuffer = true;
135
136 // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
137 if (curLayer->clipOccludesNextLayers(curLayer == &fillLayer)
138 && curLayer->hasOpaqueImage(&m_renderBox)
139 && curLayer->image()->canRender(m_renderBox, m_renderBox.style()->ef fectiveZoom())
140 && curLayer->hasRepeatXY()
141 && curLayer->blendMode() == WebBlendModeNormal
142 && !m_renderBox.boxShadowShouldBeAppliedToBackground(bleedAvoidance) )
143 break;
144 curLayer = curLayer->next();
145 }
146
147 if (layers.size() > 0 && (**layers.rbegin()).next())
148 isBottomLayerOccluded = true;
149
150 GraphicsContext* context = paintInfo.context;
151 if (!context)
152 shouldDrawBackgroundInSeparateBuffer = false;
153
154 bool skipBaseColor = false;
155 if (shouldDrawBackgroundInSeparateBuffer) {
156 bool isBaseColorVisible = !isBottomLayerOccluded && c.hasAlpha();
157
158 // Paint the document's base background color outside the transparency l ayer,
159 // so that the background images don't blend with this color: http://crb ug.com/389039.
160 if (isBaseColorVisible && m_renderBox.isDocumentElementWithOpaqueBackgro und()) {
161 m_renderBox.paintRootBackgroundColor(paintInfo, rect, Color());
162 skipBaseColor = true;
163 }
164 context->beginTransparencyLayer(1);
165 }
166
167 Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
168 for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
169 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO bject, skipBaseColor);
170
171 if (shouldDrawBackgroundInSeparateBuffer)
172 context->endLayer();
173 }
174
175 void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, cons t FillLayer& fillLayer, const LayoutRect& rect,
176 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseColor)
177 {
178 m_renderBox.paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoid ance, 0, LayoutSize(), op, backgroundObject, skipBaseColor);
179 }
180
181 void BoxPainter::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
182 {
183 if (!paintInfo.shouldPaintWithinRoot(&m_renderBox) || m_renderBox.style()->v isibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
184 return;
185
186 LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size());
187 paintMaskImages(paintInfo, paintRect);
188 }
189
190 void BoxPainter::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& p aintRect)
191 {
192 // Figure out if we need to push a transparency layer to render our mask.
193 bool pushTransparencyLayer = false;
194 bool compositedMask = m_renderBox.hasLayer() && m_renderBox.layer()->hasComp ositedMask();
195 bool flattenCompositingLayers = m_renderBox.view()->frameView() && m_renderB ox.view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
196 CompositeOperator compositeOp = CompositeSourceOver;
197
198 bool allMaskImagesLoaded = true;
199
200 if (!compositedMask || flattenCompositingLayers) {
201 pushTransparencyLayer = true;
202 StyleImage* maskBoxImage = m_renderBox.style()->maskBoxImage().image();
203 const FillLayer& maskLayers = m_renderBox.style()->maskLayers();
204
205 // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
206 if (maskBoxImage)
207 allMaskImagesLoaded &= maskBoxImage->isLoaded();
208
209 allMaskImagesLoaded &= maskLayers.imagesAreLoaded();
210
211 paintInfo.context->setCompositeOperation(CompositeDestinationIn);
212 paintInfo.context->beginTransparencyLayer(1);
213 compositeOp = CompositeSourceOver;
214 }
215
216 if (allMaskImagesLoaded) {
217 paintFillLayers(paintInfo, Color::transparent, m_renderBox.style()->mask Layers(), paintRect, BackgroundBleedNone, compositeOp);
218 m_renderBox.paintNinePieceImage(paintInfo.context, paintRect, m_renderBo x.style(), m_renderBox.style()->maskBoxImage(), compositeOp);
219 }
220
221 if (pushTransparencyLayer)
222 paintInfo.context->endLayer();
223 }
224
225 void BoxPainter::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& pain tOffset)
226 {
227 if (!paintInfo.shouldPaintWithinRoot(&m_renderBox) || m_renderBox.style()->v isibility() != VISIBLE || paintInfo.phase != PaintPhaseClippingMask)
228 return;
229
230 if (!m_renderBox.layer() || m_renderBox.layer()->compositingState() != Paint sIntoOwnBacking)
231 return;
232
233 // We should never have this state in this function. A layer with a mask
234 // should have always created its own backing if it became composited.
235 ASSERT(m_renderBox.layer()->compositingState() != HasOwnBackingButPaintsInto Ancestor);
236
237 LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size());
238 paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black);
239 }
240
241 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | Source/core/rendering/RenderBox.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698