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

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

Powered by Google App Engine
This is Rietveld 408576698