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

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

Issue 1145993002: Refactor root element background painting (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix under invalidation (override LayoutView::visualOverflowRect), revise LayoutBoxModelObject::styl… Created 5 years, 6 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
OLDNEW
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/BoxPainter.h" 6 #include "core/paint/BoxPainter.h"
7 7
8 #include "core/HTMLNames.h" 8 #include "core/HTMLNames.h"
9 #include "core/frame/Settings.h" 9 #include "core/frame/Settings.h"
10 #include "core/html/HTMLFrameOwnerElement.h" 10 #include "core/html/HTMLFrameOwnerElement.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 LayoutRect paintRect = m_layoutBox.borderBoxRect(); 54 LayoutRect paintRect = m_layoutBox.borderBoxRect();
55 paintRect.moveBy(paintOffset); 55 paintRect.moveBy(paintOffset);
56 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect); 56 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect);
57 } 57 }
58 58
59 LayoutRect BoxPainter::boundsForDrawingRecorder(const LayoutPoint& paintOffset) 59 LayoutRect BoxPainter::boundsForDrawingRecorder(const LayoutPoint& paintOffset)
60 { 60 {
61 if (!RuntimeEnabledFeatures::slimmingPaintEnabled()) 61 if (!RuntimeEnabledFeatures::slimmingPaintEnabled())
62 return LayoutRect(); 62 return LayoutRect();
63 63
64 // The document element is specified to paint its background infinitely.
65 if (m_layoutBox.isDocumentElement())
66 return rootBackgroundRect();
67
68 // Use the visual overflow rect here, because it will include overflow intro duced by the theme. 64 // Use the visual overflow rect here, because it will include overflow intro duced by the theme.
69 LayoutRect bounds = m_layoutBox.visualOverflowRect(); 65 LayoutRect bounds = m_layoutBox.visualOverflowRect();
70 bounds.moveBy(paintOffset); 66 bounds.moveBy(paintOffset);
71 return LayoutRect(pixelSnappedIntRect(bounds)); 67 return LayoutRect(pixelSnappedIntRect(bounds));
72 } 68 }
73 69
74 LayoutRect BoxPainter::rootBackgroundRect()
75 {
76 LayoutView* layoutView = m_layoutBox.view();
77 LayoutRect result = layoutView->backgroundRect(&m_layoutBox);
78 // In root-layer-scrolls mode, root background is painted in coordinates of the
79 // root scrolling contents layer, so don't need scroll offset adjustment.
80 if (layoutView->hasOverflowClip() && !layoutView->frame()->settings()->rootL ayerScrolls())
81 result.move(-layoutView->scrolledContentOffset());
82 return result;
83 }
84
85 namespace { 70 namespace {
86 71
87 bool bleedAvoidanceIsClipping(BackgroundBleedAvoidance bleedAvoidance) 72 bool bleedAvoidanceIsClipping(BackgroundBleedAvoidance bleedAvoidance)
88 { 73 {
89 return bleedAvoidance == BackgroundBleedClipOnly || bleedAvoidance == Backgr oundBleedClipLayer; 74 return bleedAvoidance == BackgroundBleedClipOnly || bleedAvoidance == Backgr oundBleedClipLayer;
90 } 75 }
91 76
92 } // anonymous namespace 77 } // anonymous namespace
93 78
94 void BoxPainter::paintBoxDecorationBackgroundWithRect(const PaintInfo& paintInfo , const LayoutPoint& paintOffset, const LayoutRect& paintRect) 79 void BoxPainter::paintBoxDecorationBackgroundWithRect(const PaintInfo& paintInfo , const LayoutPoint& paintOffset, const LayoutRect& paintRect)
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 // The theme will tell us whether or not we should also paint the CSS border . 127 // The theme will tell us whether or not we should also paint the CSS border .
143 if (boxDecorationData.hasBorderDecoration && boxDecorationData.bleedAvoidanc e != BackgroundBleedBackgroundOverBorder 128 if (boxDecorationData.hasBorderDecoration && boxDecorationData.bleedAvoidanc e != BackgroundBleedBackgroundOverBorder
144 && (!boxDecorationData.hasAppearance || (!themePainted && LayoutTheme::t heme().painter().paintBorderOnly(&m_layoutBox, paintInfo, snappedPaintRect))) 129 && (!boxDecorationData.hasAppearance || (!themePainted && LayoutTheme::t heme().painter().paintBorderOnly(&m_layoutBox, paintInfo, snappedPaintRect)))
145 && !(m_layoutBox.isTable() && toLayoutTable(&m_layoutBox)->collapseBorde rs())) 130 && !(m_layoutBox.isTable() && toLayoutTable(&m_layoutBox)->collapseBorde rs()))
146 paintBorder(m_layoutBox, paintInfo, paintRect, style, boxDecorationData. bleedAvoidance); 131 paintBorder(m_layoutBox, paintInfo, paintRect, style, boxDecorationData. bleedAvoidance);
147 132
148 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) 133 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer)
149 paintInfo.context->endLayer(); 134 paintInfo.context->endLayer();
150 } 135 }
151 136
152 static bool skipBodyBackground(const LayoutBox* bodyElementLayoutObject)
153 {
154 ASSERT(bodyElementLayoutObject->isBody());
155 // The <body> only paints its background if the root element has defined a b ackground independent of the body,
156 // or if the <body>'s parent is not the document element's layoutObject (e.g . inside SVG foreignObject).
157 LayoutObject* documentElementLayoutObject = bodyElementLayoutObject->documen t().documentElement()->layoutObject();
158 return documentElementLayoutObject
159 && !documentElementLayoutObject->hasBackground()
160 && (documentElementLayoutObject == bodyElementLayoutObject->parent());
161 }
162
163 void BoxPainter::paintBackground(const PaintInfo& paintInfo, const LayoutRect& p aintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance) 137 void BoxPainter::paintBackground(const PaintInfo& paintInfo, const LayoutRect& p aintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance)
164 { 138 {
165 if (m_layoutBox.isDocumentElement()) { 139 if (m_layoutBox.isDocumentElement())
166 paintRootBoxFillLayers(paintInfo);
167 return; 140 return;
168 } 141 if (m_layoutBox.backgroundStolenForBeingBody())
169 if (m_layoutBox.isBody() && skipBodyBackground(&m_layoutBox))
170 return; 142 return;
171 if (m_layoutBox.boxDecorationBackgroundIsKnownToBeObscured()) 143 if (m_layoutBox.boxDecorationBackgroundIsKnownToBeObscured())
172 return; 144 return;
173 paintFillLayers(paintInfo, backgroundColor, m_layoutBox.style()->backgroundL ayers(), paintRect, bleedAvoidance); 145 paintFillLayers(paintInfo, backgroundColor, m_layoutBox.style()->backgroundL ayers(), paintRect, bleedAvoidance);
174 } 146 }
175 147
176 void BoxPainter::paintRootBoxFillLayers(const PaintInfo& paintInfo) 148 static bool isFillLayerOpaque(const FillLayer& layer, const LayoutObject& imageC lient)
177 { 149 {
178 if (paintInfo.skipRootBackground()) 150 return layer.hasOpaqueImage(&imageClient)
179 return; 151 && layer.image()->canRender(imageClient, imageClient.style()->effectiveZ oom())
180 152 && !layer.image()->imageSize(&imageClient, imageClient.style()->effectiv eZoom()).isEmpty()
181 LayoutObject* rootBackgroundLayoutObject = m_layoutBox.layoutObjectForRootBa ckground(); 153 && layer.hasRepeatXY();
182
183 const FillLayer& bgLayer = rootBackgroundLayoutObject->style()->backgroundLa yers();
184 Color bgColor = rootBackgroundLayoutObject->resolveColor(CSSPropertyBackgrou ndColor);
185
186 paintFillLayers(paintInfo, bgColor, bgLayer, rootBackgroundRect(), Backgroun dBleedNone, SkXfermode::kSrcOver_Mode, rootBackgroundLayoutObject);
187 } 154 }
188 155
189 void BoxPainter::paintFillLayers(const PaintInfo& paintInfo, const Color& c, con st FillLayer& fillLayer, const LayoutRect& rect, 156 bool BoxPainter::calculateFillLayerOcclusionCulling(FillLayerOcclusionOutputList &reversedPaintList, const FillLayer& fillLayer)
190 BackgroundBleedAvoidance bleedAvoidance, SkXfermode::Mode op, LayoutObject* backgroundObject)
191 { 157 {
192 Vector<const FillLayer*, 8> layers; 158 bool isNonAssociative = false;
193 const FillLayer* curLayer = &fillLayer; 159 for (auto currentLayer = &fillLayer; currentLayer; currentLayer = currentLay er->next()) {
194 bool shouldDrawBackgroundInSeparateBuffer = false; 160 reversedPaintList.append(currentLayer);
195 bool isBottomLayerOccluded = false;
196 while (curLayer) {
197 layers.append(curLayer);
198 // Stop traversal when an opaque layer is encountered. 161 // Stop traversal when an opaque layer is encountered.
199 // FIXME : It would be possible for the following occlusion culling test to be more aggressive 162 // FIXME : It would be possible for the following occlusion culling test to be more aggressive
200 // on layers with no repeat by testing whether the image covers the layo ut rect. 163 // on layers with no repeat by testing whether the image covers the layo ut rect.
201 // Testing that here would imply duplicating a lot of calculations that are currently done in 164 // Testing that here would imply duplicating a lot of calculations that are currently done in
202 // LayoutBoxModelObject::paintFillLayerExtended. A more efficient soluti on might be to move 165 // LayoutBoxModelObject::paintFillLayerExtended. A more efficient soluti on might be to move
203 // the layer recursion into paintFillLayerExtended, or to compute the la yer geometry here 166 // the layer recursion into paintFillLayerExtended, or to compute the la yer geometry here
204 // and pass it down. 167 // and pass it down.
205 168
206 if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != We bBlendModeNormal) 169 if (currentLayer->composite() != CompositeSourceOver || currentLayer->bl endMode() != WebBlendModeNormal)
207 shouldDrawBackgroundInSeparateBuffer = true; 170 isNonAssociative = true;
208 171
209 if (curLayer->clipOccludesNextLayers() 172 // TODO(trchen): A fill layer cannot paint if the calculated tile size i s empty.
210 && curLayer->hasOpaqueImage(&m_layoutBox) 173 // This occlusion check can be wrong.
211 && curLayer->image()->canRender(m_layoutBox, m_layoutBox.style()->ef fectiveZoom()) 174 if (currentLayer->clipOccludesNextLayers()
212 && curLayer->hasRepeatXY() 175 && isFillLayerOpaque(*currentLayer, m_layoutBox)) {
213 && curLayer->blendMode() == WebBlendModeNormal 176 if (currentLayer->clip() == BorderFillBox)
214 && !m_layoutBox.boxShadowShouldBeAppliedToBackground(bleedAvoidance) ) 177 isNonAssociative = false;
215 break; 178 break;
216 curLayer = curLayer->next(); 179 }
180 }
181 return isNonAssociative;
182 }
183
184 void BoxPainter::paintFillLayers(const PaintInfo& paintInfo, const Color& c, con st FillLayer& fillLayer, const LayoutRect& rect, BackgroundBleedAvoidance bleedA voidance, SkXfermode::Mode op, LayoutObject* backgroundObject)
185 {
186 FillLayerOcclusionOutputList reversedPaintList;
187 bool shouldDrawBackgroundInSeparateBuffer = calculateFillLayerOcclusionCulli ng(reversedPaintList, fillLayer);
188 ASSERT(reversedPaintList.size());
189
190 // If we are responsible to paint box shadow, the bottom layer cannot be ski pped.
191 // TODO(trchen): Box shadow optimization and background color are concepts t hat only
192 // apply to background layers. Ideally we should refactor those out of paint FillLayer.
193 if (m_layoutBox.boxShadowShouldBeAppliedToBackground(bleedAvoidance)) {
chrishtr 2015/06/08 20:30:58 Please do the optimizations for shadow in a new pa
trchen 2015/06/08 22:46:55 Done. The function is still largely refactored, bu
194 const FillLayer* bottomLayer = *reversedPaintList.rbegin();
195 if (bottomLayer->next()) {
196 while (bottomLayer->next())
197 bottomLayer = bottomLayer->next();
198 reversedPaintList.append(bottomLayer);
199 }
217 } 200 }
218 201
219 if (layers.size() > 0 && (**layers.rbegin()).next()) 202 // TODO(trchen): We can optimize out isolation group if we have a non-transp arent
220 isBottomLayerOccluded = true; 203 // background color and the bottom layer encloses all other layers.
221 204
222 GraphicsContext* context = paintInfo.context; 205 GraphicsContext* context = paintInfo.context;
223 if (!context) 206 if (!context)
224 shouldDrawBackgroundInSeparateBuffer = false; 207 shouldDrawBackgroundInSeparateBuffer = false;
225 208
226 bool skipBaseColor = false; 209 if (shouldDrawBackgroundInSeparateBuffer)
227 if (shouldDrawBackgroundInSeparateBuffer) { 210 context->beginLayer();
228 bool isBaseColorVisible = !isBottomLayerOccluded && c.hasAlpha();
229 211
230 // Paint the document's base background color outside the transparency l ayer, 212 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); + +it)
231 // so that the background images don't blend with this color: http://crb ug.com/389039. 213 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO bject);
232 if (isBaseColorVisible && isDocumentElementWithOpaqueBackground(m_layout Box)) {
233 paintRootBackgroundColor(m_layoutBox, paintInfo, rect, Color());
234 skipBaseColor = true;
235 }
236 context->beginLayer();
237 }
238
239 Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
240 for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
241 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO bject, skipBaseColor);
242 214
243 if (shouldDrawBackgroundInSeparateBuffer) 215 if (shouldDrawBackgroundInSeparateBuffer)
244 context->endLayer(); 216 context->endLayer();
245 } 217 }
246 218
247 void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, cons t FillLayer& fillLayer, const LayoutRect& rect, 219 void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, cons t FillLayer& fillLayer, const LayoutRect& rect,
248 BackgroundBleedAvoidance bleedAvoidance, SkXfermode::Mode op, LayoutObject* backgroundObject, bool skipBaseColor) 220 BackgroundBleedAvoidance bleedAvoidance, SkXfermode::Mode op, LayoutObject* backgroundObject)
249 { 221 {
250 BoxPainter::paintFillLayerExtended(m_layoutBox, paintInfo, c, fillLayer, rec t, bleedAvoidance, 0, LayoutSize(), op, backgroundObject, skipBaseColor); 222 BoxPainter::paintFillLayerExtended(m_layoutBox, paintInfo, c, fillLayer, rec t, bleedAvoidance, 0, LayoutSize(), op, backgroundObject);
251 } 223 }
252 224
253 void BoxPainter::applyBoxShadowForBackground(GraphicsContext* context, LayoutObj ect& obj) 225 void BoxPainter::applyBoxShadowForBackground(GraphicsContext* context, LayoutObj ect& obj)
254 { 226 {
255 const ShadowList* shadowList = obj.style()->boxShadow(); 227 const ShadowList* shadowList = obj.style()->boxShadow();
256 ASSERT(shadowList); 228 ASSERT(shadowList);
257 for (size_t i = shadowList->shadows().size(); i--; ) { 229 for (size_t i = shadowList->shadows().size(); i--; ) {
258 const ShadowData& boxShadow = shadowList->shadows()[i]; 230 const ShadowData& boxShadow = shadowList->shadows()[i];
259 if (boxShadow.style() != Normal) 231 if (boxShadow.style() != Normal)
260 continue; 232 continue;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 FloatRoundedRect::Radii insetRadii(backgroundRoundedRect.radii()); 286 FloatRoundedRect::Radii insetRadii(backgroundRoundedRect.radii());
315 insetRadii.shrink(-insets.top(), -insets.bottom(), -insets.left(), -inse ts.right()); 287 insetRadii.shrink(-insets.top(), -insets.bottom(), -insets.left(), -inse ts.right());
316 return FloatRoundedRect(insetRect, insetRadii); 288 return FloatRoundedRect(insetRect, insetRadii);
317 } 289 }
318 if (bleedAvoidance == BackgroundBleedBackgroundOverBorder) 290 if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
319 return obj.style()->getRoundedInnerBorderFor(borderRect, includeLogicalL eftEdge, includeLogicalRightEdge); 291 return obj.style()->getRoundedInnerBorderFor(borderRect, includeLogicalL eftEdge, includeLogicalRightEdge);
320 292
321 return getBackgroundRoundedRect(obj, borderRect, box, boxSize.width(), boxSi ze.height(), includeLogicalLeftEdge, includeLogicalRightEdge); 293 return getBackgroundRoundedRect(obj, borderRect, box, boxSize.width(), boxSi ze.height(), includeLogicalLeftEdge, includeLogicalRightEdge);
322 } 294 }
323 295
324 void BoxPainter::paintFillLayerExtended(LayoutBoxModelObject& obj, const PaintIn fo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutRect& r ect, 296 void BoxPainter::paintFillLayerExtended(LayoutBoxModelObject& obj, const PaintIn fo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutRect& r ect, BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSi ze& boxSize, SkXfermode::Mode op, LayoutObject* backgroundObject)
325 BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSiz e& boxSize, SkXfermode::Mode op, LayoutObject* backgroundObject, bool skipBaseCo lor)
326 { 297 {
327 GraphicsContext* context = paintInfo.context; 298 GraphicsContext* context = paintInfo.context;
328 if (rect.isEmpty()) 299 if (rect.isEmpty())
329 return; 300 return;
330 301
331 bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true; 302 bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true;
332 bool includeRightEdge = box ? box->includeLogicalRightEdge() : true; 303 bool includeRightEdge = box ? box->includeLogicalRightEdge() : true;
333 304
334 bool hasRoundedBorder = obj.style()->hasBorderRadius() && (includeLeftEdge | | includeRightEdge); 305 bool hasRoundedBorder = obj.style()->hasBorderRadius() && (includeLeftEdge | | includeRightEdge);
335 bool clippedWithLocalScrolling = obj.hasOverflowClip() && bgLayer.attachment () == LocalBackgroundAttachment; 306 bool clippedWithLocalScrolling = obj.hasOverflowClip() && bgLayer.attachment () == LocalBackgroundAttachment;
336 bool isBorderFill = bgLayer.clip() == BorderFillBox; 307 bool isBorderFill = bgLayer.clip() == BorderFillBox;
337 bool isDocumentElementLayoutObject = obj.isDocumentElement();
338 bool isBottomLayer = !bgLayer.next(); 308 bool isBottomLayer = !bgLayer.next();
339 309
340 Color bgColor = color; 310 Color bgColor = color;
341 StyleImage* bgImage = bgLayer.image(); 311 StyleImage* bgImage = bgLayer.image();
342 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(obj, obj.sty le()->effectiveZoom());
343 312
344 bool forceBackgroundToWhite = false; 313 bool forceBackgroundToWhite = false;
345 if (obj.document().printing()) { 314 if (obj.document().printing()) {
346 if (obj.style()->printColorAdjust() == PrintColorAdjustEconomy) 315 if (obj.style()->printColorAdjust() == PrintColorAdjustEconomy)
347 forceBackgroundToWhite = true; 316 forceBackgroundToWhite = true;
348 if (obj.document().settings() && obj.document().settings()->shouldPrintB ackgrounds()) 317 if (obj.document().settings() && obj.document().settings()->shouldPrintB ackgrounds())
349 forceBackgroundToWhite = false; 318 forceBackgroundToWhite = false;
350 } 319 }
351 320
352 // When printing backgrounds is disabled or using economy mode, 321 // When printing backgrounds is disabled or using economy mode,
353 // change existing background colors and images to a solid white background. 322 // change existing background colors and images to a solid white background.
354 // If there's no bg color or image, leave it untouched to avoid affecting tr ansparency. 323 // If there's no bg color or image, leave it untouched to avoid affecting tr ansparency.
355 // We don't try to avoid loading the background images, because this style f lag is only set 324 // We don't try to avoid loading the background images, because this style f lag is only set
356 // when printing, and at that point we've already loaded the background imag es anyway. (To avoid 325 // when printing, and at that point we've already loaded the background imag es anyway. (To avoid
357 // loading the background images we'd have to do this check when applying st yles rather than 326 // loading the background images we'd have to do this check when applying st yles rather than
358 // while layout.) 327 // while layout.)
359 if (forceBackgroundToWhite) { 328 if (forceBackgroundToWhite) {
360 // Note that we can't reuse this variable below because the bgColor migh t be changed 329 // Note that we can't reuse this variable below because the bgColor migh t be changed
361 bool shouldPaintBackgroundColor = isBottomLayer && bgColor.alpha(); 330 bool shouldPaintBackgroundColor = isBottomLayer && bgColor.alpha();
362 if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { 331 if (bgImage || shouldPaintBackgroundColor) {
363 bgColor = Color::white; 332 bgColor = Color::white;
364 shouldPaintBackgroundImage = false; 333 bgImage = nullptr;
365 } 334 }
366 } 335 }
367 336
368 bool colorVisible = bgColor.alpha();
369
370 // Fast path for drawing simple color backgrounds. 337 // Fast path for drawing simple color backgrounds.
371 if (!isDocumentElementLayoutObject && !clippedWithLocalScrolling && !shouldP aintBackgroundImage && isBorderFill && isBottomLayer) { 338 if (!clippedWithLocalScrolling && !bgImage && isBorderFill && isBottomLayer) {
372 if (!colorVisible) 339 if (!bgColor.alpha())
373 return; 340 return;
374 341
375 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box); 342 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box);
376 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAp pliedToBackground); 343 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAp pliedToBackground);
377 if (boxShadowShouldBeAppliedToBackground) 344 if (boxShadowShouldBeAppliedToBackground)
378 BoxPainter::applyBoxShadowForBackground(context, obj); 345 BoxPainter::applyBoxShadowForBackground(context, obj);
379 346
380 if (hasRoundedBorder && !bleedAvoidanceIsClipping(bleedAvoidance)) { 347 if (hasRoundedBorder && !bleedAvoidanceIsClipping(bleedAvoidance)) {
381 FloatRoundedRect border = backgroundRoundedRectAdjustedForBleedAvoid ance(obj, rect, 348 FloatRoundedRect border = backgroundRoundedRectAdjustedForBleedAvoid ance(obj, rect,
382 bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge) ; 349 bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge) ;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 439
473 break; 440 break;
474 } 441 }
475 case BorderFillBox: 442 case BorderFillBox:
476 break; 443 break;
477 default: 444 default:
478 ASSERT_NOT_REACHED(); 445 ASSERT_NOT_REACHED();
479 break; 446 break;
480 } 447 }
481 448
449 BackgroundImageGeometry geometry;
450 if (bgImage)
451 calculateBackgroundImageGeometry(obj, paintInfo.paintContainer(), bgLaye r, scrolledPaintRect, geometry, backgroundObject);
452 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(obj, obj.sty le()->effectiveZoom());
453
482 // Paint the color first underneath all images, culled if background image o ccludes it. 454 // Paint the color first underneath all images, culled if background image o ccludes it.
483 // FIXME: In the bgLayer->hasFiniteBounds() case, we could improve the culli ng test 455 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the cu lling test
484 // by verifying whether the background image covers the entire layout rect. 456 // by verifying whether the background image covers the entire painting area .
485 if (isBottomLayer) { 457 if (isBottomLayer) {
486 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); 458 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect));
487 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box); 459 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box);
488 bool isOpaqueRoot = (isDocumentElementLayoutObject && !bgColor.hasAlpha( )) || isDocumentElementWithOpaqueBackground(obj); 460 bool backgroundImageOccludesBackgroundColor = shouldPaintBackgroundImage && isFillLayerOpaque(bgLayer, obj);
489 if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage || !bgLayer.hasOpaqueImage(&obj) || !bgLayer.hasRepeatXY() || (isOpaqueRoot && ! toLayoutBox(&obj)->size().height())) { 461 if (boxShadowShouldBeAppliedToBackground || !backgroundImageOccludesBack groundColor) {
490 if (!RuntimeEnabledFeatures::slimmingPaintEnabled() && !boxShadowSho uldBeAppliedToBackground) 462 if (!RuntimeEnabledFeatures::slimmingPaintEnabled() && !boxShadowSho uldBeAppliedToBackground)
491 backgroundRect.intersect(paintInfo.rect); 463 backgroundRect.intersect(paintInfo.rect);
492 464
493 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShould BeAppliedToBackground); 465 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShould BeAppliedToBackground);
494 if (boxShadowShouldBeAppliedToBackground) 466 if (boxShadowShouldBeAppliedToBackground)
495 BoxPainter::applyBoxShadowForBackground(context, obj); 467 BoxPainter::applyBoxShadowForBackground(context, obj);
496 468
497 if (isOpaqueRoot && !skipBaseColor) { 469 if (bgColor.alpha())
498 paintRootBackgroundColor(obj, paintInfo, rect, bgColor);
499 } else if (bgColor.alpha()) {
500 context->fillRect(backgroundRect, bgColor); 470 context->fillRect(backgroundRect, bgColor);
501 }
502 } 471 }
503 } 472 }
504 473
505 // no progressive loading of the background image 474 // no progressive loading of the background image
506 if (shouldPaintBackgroundImage) { 475 if (shouldPaintBackgroundImage) {
507 BackgroundImageGeometry geometry;
508 calculateBackgroundImageGeometry(obj, paintInfo.paintContainer(), bgLaye r, scrolledPaintRect, geometry, backgroundObject);
509 if (!geometry.destRect().isEmpty()) { 476 if (!geometry.destRect().isEmpty()) {
510 SkXfermode::Mode bgOp = WebCoreCompositeToSkiaComposite(bgLayer.comp osite(), bgLayer.blendMode()); 477 SkXfermode::Mode bgOp = WebCoreCompositeToSkiaComposite(bgLayer.comp osite(), bgLayer.blendMode());
511 // if op != SkXfermode::kSrcOver_Mode, a mask is being painted. 478 // if op != SkXfermode::kSrcOver_Mode, a mask is being painted.
512 SkXfermode::Mode compositeOp = op == SkXfermode::kSrcOver_Mode ? bgO p : op; 479 SkXfermode::Mode compositeOp = op == SkXfermode::kSrcOver_Mode ? bgO p : op;
513 LayoutObject* clientForBackgroundImage = backgroundObject ? backgrou ndObject : &obj; 480 LayoutObject* clientForBackgroundImage = backgroundObject ? backgrou ndObject : &obj;
514 RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geome try.tileSize()); 481 RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geome try.tileSize());
515 InterpolationQuality interpolationQuality = chooseInterpolationQuali ty(*clientForBackgroundImage, context, image.get(), &bgLayer, LayoutSize(geometr y.tileSize())); 482 InterpolationQuality interpolationQuality = chooseInterpolationQuali ty(*clientForBackgroundImage, context, image.get(), &bgLayer, LayoutSize(geometr y.tileSize()));
516 if (bgLayer.maskSourceType() == MaskLuminance) 483 if (bgLayer.maskSourceType() == MaskLuminance)
517 context->setColorFilter(ColorFilterLuminanceToAlpha); 484 context->setColorFilter(ColorFilterLuminanceToAlpha);
518 InterpolationQuality previousInterpolationQuality = context->imageIn terpolationQuality(); 485 InterpolationQuality previousInterpolationQuality = context->imageIn terpolationQuality();
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 return; 567 return;
601 568
602 IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset, m_layoutBox. size())); 569 IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset, m_layoutBox. size()));
603 LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutBox, paintInfo.phase, paintRect); 570 LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutBox, paintInfo.phase, paintRect);
604 if (drawingRecorder.canUseCachedDrawing()) 571 if (drawingRecorder.canUseCachedDrawing())
605 return; 572 return;
606 573
607 paintInfo.context->fillRect(paintRect, Color::black); 574 paintInfo.context->fillRect(paintRect, Color::black);
608 } 575 }
609 576
610 void BoxPainter::paintRootBackgroundColor(LayoutObject& obj, const PaintInfo& pa intInfo, const LayoutRect& rootBackgroundRect, const Color& bgColor)
611 {
612 if (rootBackgroundRect.isEmpty())
613 return;
614
615 ASSERT(obj.isDocumentElement());
616
617 IntRect backgroundRect(pixelSnappedIntRect(rootBackgroundRect));
618 if (!RuntimeEnabledFeatures::slimmingPaintEnabled())
619 backgroundRect.intersect(paintInfo.rect);
620
621 Color baseColor = obj.view()->frameView()->baseBackgroundColor();
622 bool shouldClearDocumentBackground = obj.document().settings() && obj.docume nt().settings()->shouldClearDocumentBackground();
623 SkXfermode::Mode operation = shouldClearDocumentBackground ?
624 SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode;
625
626 GraphicsContext* context = paintInfo.context;
627
628 // If we have an alpha go ahead and blend with the base background color.
629 if (baseColor.alpha()) {
630 if (bgColor.alpha())
631 baseColor = baseColor.blend(bgColor);
632 context->fillRect(backgroundRect, baseColor, operation);
633 } else if (bgColor.alpha()) {
634 context->fillRect(backgroundRect, bgColor, operation);
635 } else if (shouldClearDocumentBackground) {
636 context->clearRect(backgroundRect);
637 }
638 }
639
640 bool BoxPainter::isDocumentElementWithOpaqueBackground(LayoutObject& obj)
641 {
642 if (!obj.isDocumentElement())
643 return false;
644
645 // The background is opaque only if we're the root document, since iframes w ith
646 // no background in the child document should show the parent's background.
647 bool isOpaque = true;
648 Element* ownerElement = obj.document().ownerElement();
649 if (ownerElement) {
650 if (!isHTMLFrameElement(*ownerElement)) {
651 // Locate the <body> element using the DOM. This is easier than tryi ng
652 // to crawl around a layout tree with potential :before/:after conte nt and
653 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
654 // layout object very easily via the DOM.
655 HTMLElement* body = obj.document().body();
656 if (body) {
657 // Can't scroll a frameset document anyway.
658 isOpaque = body->hasTagName(HTMLNames::framesetTag);
659 } else {
660 // FIXME: SVG specific behavior should be in the SVG code.
661 // SVG documents and XML documents with SVG root nodes are trans parent.
662 isOpaque = !obj.document().hasSVGRootNode();
663 }
664 }
665 } else if (obj.view()->frameView()) {
666 isOpaque = !obj.view()->frameView()->isTransparent();
667 }
668
669 return isOpaque;
670 }
671
672 // Return the amount of space to leave between image tiles for the background-re peat: space property. 577 // Return the amount of space to leave between image tiles for the background-re peat: space property.
673 static inline int getSpaceBetweenImageTiles(int areaSize, int tileSize) 578 static inline int getSpaceBetweenImageTiles(int areaSize, int tileSize)
674 { 579 {
675 int numberOfTiles = areaSize / tileSize; 580 int numberOfTiles = areaSize / tileSize;
676 int space = -1; 581 int space = -1;
677 582
678 if (numberOfTiles > 1) { 583 if (numberOfTiles > 1) {
679 // Spec doesn't specify rounding, so use the same method as for backgrou nd-repeat: round. 584 // Spec doesn't specify rounding, so use the same method as for backgrou nd-repeat: round.
680 space = lroundf((areaSize - numberOfTiles * tileSize) / (float)(numberOf Tiles - 1)); 585 space = lroundf((areaSize - numberOfTiles * tileSize) / (float)(numberOf Tiles - 1));
681 } 586 }
682 587
683 return space; 588 return space;
684 } 589 }
685 590
686 void BoxPainter::calculateBackgroundImageGeometry(LayoutBoxModelObject& obj, con st LayoutBoxModelObject* paintContainer, const FillLayer& fillLayer, const Layou tRect& paintRect, 591 void BoxPainter::calculateBackgroundImageGeometry(LayoutBoxModelObject& obj, con st LayoutBoxModelObject* paintContainer, const FillLayer& fillLayer, const Layou tRect& paintRect,
687 BackgroundImageGeometry& geometry, LayoutObject* backgroundObject) 592 BackgroundImageGeometry& geometry, LayoutObject* backgroundObject)
688 { 593 {
689 LayoutUnit left = 0; 594 LayoutUnit left = 0;
690 LayoutUnit top = 0; 595 LayoutUnit top = 0;
691 IntSize positioningAreaSize; 596 IntSize positioningAreaSize;
692 IntRect snappedPaintRect = pixelSnappedIntRect(paintRect); 597 IntRect snappedPaintRect = pixelSnappedIntRect(paintRect);
598 bool isLayoutView = obj.isLayoutView();
599 const LayoutBox* rootBox = nullptr;
600 if (isLayoutView) {
601 rootBox = toLayoutBox(obj.document().documentElement() ? obj.document(). documentElement()->layoutObject() : nullptr);
602 ASSERT(rootBox);
603 }
604 const LayoutBoxModelObject& positioningBox = isLayoutView ? static_cast<cons t LayoutBoxModelObject&>(*rootBox) : obj;
693 605
694 // Determine the background positioning area and set destRect to the backgro und painting area. 606 // Determine the background positioning area and set destRect to the backgro und painting area.
695 // destRect will be adjusted later if the background is non-repeating. 607 // destRect will be adjusted later if the background is non-repeating.
696 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins ide transforms. 608 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins ide transforms.
697 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment; 609 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment;
698 610
699 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) { 611 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) {
700 // As a side effect of an optimization to blit on scroll, we do not hono r the CSS 612 // As a side effect of an optimization to blit on scroll, we do not hono r the CSS
701 // property "background-attachment: fixed" because it may result in rend ering 613 // property "background-attachment: fixed" because it may result in rend ering
702 // artifacts. Note, these artifacts only appear if we are blitting on sc roll of 614 // artifacts. Note, these artifacts only appear if we are blitting on sc roll of
703 // a page that has fixed background images. 615 // a page that has fixed background images.
704 fixedAttachment = false; 616 fixedAttachment = false;
705 } 617 }
706 618
707 if (!fixedAttachment) { 619 if (!fixedAttachment) {
708 geometry.setDestRect(snappedPaintRect); 620 geometry.setDestRect(snappedPaintRect);
709 621
710 LayoutUnit right = 0; 622 LayoutUnit right = 0;
711 LayoutUnit bottom = 0; 623 LayoutUnit bottom = 0;
712 // Scroll and Local. 624 // Scroll and Local.
713 if (fillLayer.origin() != BorderFillBox) { 625 if (fillLayer.origin() != BorderFillBox) {
714 left = obj.borderLeft(); 626 left = positioningBox.borderLeft();
715 right = obj.borderRight(); 627 right = positioningBox.borderRight();
716 top = obj.borderTop(); 628 top = positioningBox.borderTop();
717 bottom = obj.borderBottom(); 629 bottom = positioningBox.borderBottom();
718 if (fillLayer.origin() == ContentFillBox) { 630 if (fillLayer.origin() == ContentFillBox) {
719 left += obj.paddingLeft(); 631 left += positioningBox.paddingLeft();
720 right += obj.paddingRight(); 632 right += positioningBox.paddingRight();
721 top += obj.paddingTop(); 633 top += positioningBox.paddingTop();
722 bottom += obj.paddingBottom(); 634 bottom += positioningBox.paddingBottom();
723 } 635 }
724 } 636 }
725 637
726 // The background of the box generated by the root element covers the en tire canvas including 638 if (isLayoutView) {
727 // its margins. Since those were added in already, we have to factor the m out when computing 639 // The background of the box generated by the root element covers th e entire canvas and will
728 // the background positioning area. 640 // be painted by the view object, but the we should still use the ro ot element box for
729 if (obj.isDocumentElement()) { 641 // positioning.
730 positioningAreaSize = pixelSnappedIntSize(toLayoutBox(&obj)->size() - LayoutSize(left + right, top + bottom), toLayoutBox(&obj)->location()); 642 positioningAreaSize = pixelSnappedIntSize(rootBox->size() - LayoutSi ze(left + right, top + bottom), rootBox->location());
731 // The positioning area is right aligned in paintRect if RightToLeft WritingMode, or left aligned otherwise. 643 // The input paint rect is specified in root element local coordinat e (i.e. a transform
732 if (obj.style()->writingMode() == RightToLeftWritingMode) 644 // is applied on the context for painting), and is expanded to cover the whole canvas.
733 left = paintRect.width() - positioningAreaSize.width() - right - obj.marginRight(); 645 // Since left/top is relative to the paint rect, we need to offset t hem back.
734 else 646 left -= paintRect.x();
735 left += obj.marginLeft(); 647 top -= paintRect.y();
736 top += obj.marginTop();
737 } else { 648 } else {
738 positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutS ize(left + right, top + bottom), paintRect.location()); 649 positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutS ize(left + right, top + bottom), paintRect.location());
739 } 650 }
740 } else { 651 } else {
741 geometry.setHasNonLocalGeometry(); 652 geometry.setHasNonLocalGeometry();
742 653
743 IntRect viewportRect = pixelSnappedIntRect(obj.viewRect()); 654 IntRect viewportRect = pixelSnappedIntRect(obj.viewRect());
744 if (fixedBackgroundPaintsInLocalCoordinates(obj)) 655 if (fixedBackgroundPaintsInLocalCoordinates(obj))
745 viewportRect.setLocation(IntPoint()); 656 viewportRect.setLocation(IntPoint());
746 else if (FrameView* frameView = obj.view()->frameView()) 657 else if (FrameView* frameView = obj.view()->frameView())
747 viewportRect.setLocation(frameView->scrollPosition()); 658 viewportRect.setLocation(frameView->scrollPosition());
748 659
749 if (paintContainer) { 660 if (paintContainer) {
750 IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->l ocalToAbsolute(FloatPoint())); 661 IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->l ocalToAbsolute(FloatPoint()));
751 viewportRect.moveBy(-absoluteContainerOffset); 662 viewportRect.moveBy(-absoluteContainerOffset);
752 } 663 }
753 664
754 geometry.setDestRect(viewportRect); 665 geometry.setDestRect(viewportRect);
755 positioningAreaSize = geometry.destRect().size(); 666 positioningAreaSize = geometry.destRect().size();
756 } 667 }
757 668
758 const LayoutObject* clientForBackgroundImage = backgroundObject ? background Object : &obj; 669 const LayoutObject* clientForBackgroundImage = backgroundObject ? background Object : &obj;
759 IntSize fillTileSize = calculateFillTileSize(obj, fillLayer, positioningArea Size); 670 IntSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, posi tioningAreaSize);
760 fillLayer.image()->setContainerSizeForLayoutObject(clientForBackgroundImage, fillTileSize, obj.style()->effectiveZoom()); 671 fillLayer.image()->setContainerSizeForLayoutObject(clientForBackgroundImage, fillTileSize, obj.style()->effectiveZoom());
761 geometry.setTileSize(fillTileSize); 672 geometry.setTileSize(fillTileSize);
762 673
763 EFillRepeat backgroundRepeatX = fillLayer.repeatX(); 674 EFillRepeat backgroundRepeatX = fillLayer.repeatX();
764 EFillRepeat backgroundRepeatY = fillLayer.repeatY(); 675 EFillRepeat backgroundRepeatY = fillLayer.repeatY();
765 int availableWidth = positioningAreaSize.width() - geometry.tileSize().width (); 676 int availableWidth = positioningAreaSize.width() - geometry.tileSize().width ();
766 int availableHeight = positioningAreaSize.height() - geometry.tileSize().hei ght(); 677 int availableHeight = positioningAreaSize.height() - geometry.tileSize().hei ght();
767 678
768 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit ion(), availableWidth); 679 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit ion(), availableWidth);
769 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fil lTileSize.width() > 0) { 680 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fil lTileSize.width() > 0) {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
847 geometry.clip(snappedPaintRect); 758 geometry.clip(snappedPaintRect);
848 } 759 }
849 760
850 InterpolationQuality BoxPainter::chooseInterpolationQuality(LayoutObject& obj, G raphicsContext* context, Image* image, const void* layer, const LayoutSize& size ) 761 InterpolationQuality BoxPainter::chooseInterpolationQuality(LayoutObject& obj, G raphicsContext* context, Image* image, const void* layer, const LayoutSize& size )
851 { 762 {
852 return ImageQualityController::imageQualityController()->chooseInterpolation Quality(context, &obj, image, layer, size); 763 return ImageQualityController::imageQualityController()->chooseInterpolation Quality(context, &obj, image, layer, size);
853 } 764 }
854 765
855 bool BoxPainter::fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj ) 766 bool BoxPainter::fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj )
856 { 767 {
857 if (!obj.isDocumentElement()) 768 if (!obj.isLayoutView())
858 return false; 769 return false;
859 770
860 if (obj.view()->frameView() && obj.view()->frameView()->paintBehavior() & Pa intBehaviorFlattenCompositingLayers) 771 const LayoutView& view = toLayoutView(obj);
772
773 if (view.frameView() && view.frameView()->paintBehavior() & PaintBehaviorFla ttenCompositingLayers)
861 return false; 774 return false;
862 775
863 DeprecatedPaintLayer* rootLayer = obj.view()->layer(); 776 DeprecatedPaintLayer* rootLayer = view.layer();
864 if (!rootLayer || rootLayer->compositingState() == NotComposited) 777 if (!rootLayer || rootLayer->compositingState() == NotComposited)
865 return false; 778 return false;
866 779
867 return rootLayer->compositedDeprecatedPaintLayerMapping()->backgroundLayerPa intsFixedRootBackground(); 780 return rootLayer->compositedDeprecatedPaintLayerMapping()->backgroundLayerPa intsFixedRootBackground();
868 } 781 }
869 782
870 static inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSize& positioningAreaSize) 783 static inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSize& positioningAreaSize)
871 { 784 {
872 tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tile Size.width().ceil() : tileSize.width().floor()); 785 tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tile Size.width().ceil() : tileSize.width().floor());
873 tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? t ileSize.height().ceil() : tileSize.height().floor()); 786 tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? t ileSize.height().ceil() : tileSize.height().floor());
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
1123 else 1036 else
1124 clippedEdges |= GraphicsContext::BottomEdge; 1037 clippedEdges |= GraphicsContext::BottomEdge;
1125 } 1038 }
1126 // TODO: support non-integer shadows - crbug.com/334828 1039 // TODO: support non-integer shadows - crbug.com/334828
1127 context->drawInnerShadow(border, shadowColor, flooredIntSize(shadowO ffset), shadowBlur, shadowSpread, clippedEdges); 1040 context->drawInnerShadow(border, shadowColor, flooredIntSize(shadowO ffset), shadowBlur, shadowSpread, clippedEdges);
1128 } 1041 }
1129 } 1042 }
1130 } 1043 }
1131 1044
1132 } // namespace blink 1045 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698