| OLD | NEW |
| 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 "core/paint/BoxPainter.h" | 5 #include "core/paint/BoxPainter.h" |
| 6 | 6 |
| 7 #include "core/HTMLNames.h" | 7 #include "core/HTMLNames.h" |
| 8 #include "core/frame/Settings.h" | 8 #include "core/frame/Settings.h" |
| 9 #include "core/html/HTMLFrameOwnerElement.h" | 9 #include "core/html/HTMLFrameOwnerElement.h" |
| 10 #include "core/layout/ImageQualityController.h" | 10 #include "core/layout/ImageQualityController.h" |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 paintInfo.context, displayItemClient, | 185 paintInfo.context, displayItemClient, |
| 186 DisplayItem::kBoxDecorationBackground, | 186 DisplayItem::kBoxDecorationBackground, |
| 187 FloatRect(boundsForDrawingRecorder(paintInfo, paintOffset))); | 187 FloatRect(boundsForDrawingRecorder(paintInfo, paintOffset))); |
| 188 BoxDecorationData boxDecorationData(m_layoutBox); | 188 BoxDecorationData boxDecorationData(m_layoutBox); |
| 189 GraphicsContextStateSaver stateSaver(paintInfo.context, false); | 189 GraphicsContextStateSaver stateSaver(paintInfo.context, false); |
| 190 | 190 |
| 191 if (!paintingOverflowContents) { | 191 if (!paintingOverflowContents) { |
| 192 // FIXME: Should eventually give the theme control over whether the box | 192 // FIXME: Should eventually give the theme control over whether the box |
| 193 // shadow should paint, since controls could have custom shadows of their | 193 // shadow should paint, since controls could have custom shadows of their |
| 194 // own. | 194 // own. |
| 195 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground( | 195 paintBoxShadow(paintInfo, paintRect, style, Normal); |
| 196 boxDecorationData.bleedAvoidance)) { | |
| 197 paintBoxShadow(paintInfo, paintRect, style, Normal); | |
| 198 } | |
| 199 | 196 |
| 200 if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { | 197 if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { |
| 201 stateSaver.save(); | 198 stateSaver.save(); |
| 202 FloatRoundedRect border = style.getRoundedBorderFor(paintRect); | 199 FloatRoundedRect border = style.getRoundedBorderFor(paintRect); |
| 203 paintInfo.context.clipRoundedRect(border); | 200 paintInfo.context.clipRoundedRect(border); |
| 204 | 201 |
| 205 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) | 202 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) |
| 206 paintInfo.context.beginLayer(); | 203 paintInfo.context.beginLayer(); |
| 207 } | 204 } |
| 208 } | 205 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 return isNonAssociative; | 291 return isNonAssociative; |
| 295 } | 292 } |
| 296 | 293 |
| 297 void BoxPainter::paintFillLayers(const PaintInfo& paintInfo, | 294 void BoxPainter::paintFillLayers(const PaintInfo& paintInfo, |
| 298 const Color& c, | 295 const Color& c, |
| 299 const FillLayer& fillLayer, | 296 const FillLayer& fillLayer, |
| 300 const LayoutRect& rect, | 297 const LayoutRect& rect, |
| 301 BackgroundBleedAvoidance bleedAvoidance, | 298 BackgroundBleedAvoidance bleedAvoidance, |
| 302 SkBlendMode op, | 299 SkBlendMode op, |
| 303 const LayoutObject* backgroundObject) { | 300 const LayoutObject* backgroundObject) { |
| 304 // TODO(trchen): Box shadow optimization and background color are concepts | |
| 305 // that only apply to background layers. Ideally we should refactor those out | |
| 306 // of paintFillLayer. | |
| 307 FillLayerOcclusionOutputList reversedPaintList; | 301 FillLayerOcclusionOutputList reversedPaintList; |
| 308 bool shouldDrawBackgroundInSeparateBuffer = false; | 302 bool shouldDrawBackgroundInSeparateBuffer = |
| 309 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground(bleedAvoidance)) { | 303 calculateFillLayerOcclusionCulling(reversedPaintList, fillLayer); |
| 310 shouldDrawBackgroundInSeparateBuffer = | |
| 311 calculateFillLayerOcclusionCulling(reversedPaintList, fillLayer); | |
| 312 } else { | |
| 313 // If we are responsible for painting box shadow, don't perform fill layer | |
| 314 // culling. | |
| 315 // TODO(trchen): In theory we only need to make sure the last layer has | |
| 316 // border box clipping and make it paint the box shadow. Investigate | |
| 317 // optimization opportunity later. | |
| 318 for (auto currentLayer = &fillLayer; currentLayer; | |
| 319 currentLayer = currentLayer->next()) { | |
| 320 reversedPaintList.append(currentLayer); | |
| 321 if (currentLayer->composite() != CompositeSourceOver || | |
| 322 currentLayer->blendMode() != WebBlendModeNormal) | |
| 323 shouldDrawBackgroundInSeparateBuffer = true; | |
| 324 } | |
| 325 } | |
| 326 | 304 |
| 327 // TODO(trchen): We can optimize out isolation group if we have a | 305 // TODO(trchen): We can optimize out isolation group if we have a |
| 328 // non-transparent background color and the bottom layer encloses all other | 306 // non-transparent background color and the bottom layer encloses all other |
| 329 // layers. | 307 // layers. |
| 330 | 308 |
| 331 GraphicsContext& context = paintInfo.context; | 309 GraphicsContext& context = paintInfo.context; |
| 332 | 310 |
| 333 if (shouldDrawBackgroundInSeparateBuffer) | 311 if (shouldDrawBackgroundInSeparateBuffer) |
| 334 context.beginLayer(); | 312 context.beginLayer(); |
| 335 | 313 |
| 336 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); | 314 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); |
| 337 ++it) | 315 ++it) |
| 338 paintFillLayer(m_layoutBox, paintInfo, c, **it, rect, bleedAvoidance, 0, | 316 paintFillLayer(m_layoutBox, paintInfo, c, **it, rect, bleedAvoidance, 0, |
| 339 LayoutSize(), op, backgroundObject); | 317 LayoutSize(), op, backgroundObject); |
| 340 | 318 |
| 341 if (shouldDrawBackgroundInSeparateBuffer) | 319 if (shouldDrawBackgroundInSeparateBuffer) |
| 342 context.endLayer(); | 320 context.endLayer(); |
| 343 } | 321 } |
| 344 | 322 |
| 345 namespace { | 323 namespace { |
| 346 | 324 |
| 347 // RAII shadow helper. | |
| 348 class ShadowContext { | |
| 349 STACK_ALLOCATED(); | |
| 350 | |
| 351 public: | |
| 352 ShadowContext(GraphicsContext& context, | |
| 353 const LayoutObject& obj, | |
| 354 bool applyShadow) | |
| 355 : m_saver(context, applyShadow) { | |
| 356 if (!applyShadow) | |
| 357 return; | |
| 358 | |
| 359 const ShadowList* shadowList = obj.style()->boxShadow(); | |
| 360 DCHECK(shadowList); | |
| 361 for (size_t i = shadowList->shadows().size(); i--;) { | |
| 362 const ShadowData& boxShadow = shadowList->shadows()[i]; | |
| 363 if (boxShadow.style() != Normal) | |
| 364 continue; | |
| 365 FloatSize shadowOffset(boxShadow.x(), boxShadow.y()); | |
| 366 context.setShadow( | |
| 367 shadowOffset, boxShadow.blur(), | |
| 368 boxShadow.color().resolve(obj.resolveColor(CSSPropertyColor)), | |
| 369 DrawLooperBuilder::ShadowRespectsTransforms, | |
| 370 DrawLooperBuilder::ShadowIgnoresAlpha); | |
| 371 break; | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 private: | |
| 376 GraphicsContextStateSaver m_saver; | |
| 377 }; | |
| 378 | |
| 379 FloatRoundedRect getBackgroundRoundedRect(const LayoutObject& obj, | 325 FloatRoundedRect getBackgroundRoundedRect(const LayoutObject& obj, |
| 380 const LayoutRect& borderRect, | 326 const LayoutRect& borderRect, |
| 381 const InlineFlowBox* box, | 327 const InlineFlowBox* box, |
| 382 LayoutUnit inlineBoxWidth, | 328 LayoutUnit inlineBoxWidth, |
| 383 LayoutUnit inlineBoxHeight, | 329 LayoutUnit inlineBoxHeight, |
| 384 bool includeLogicalLeftEdge, | 330 bool includeLogicalLeftEdge, |
| 385 bool includeLogicalRightEdge) { | 331 bool includeLogicalRightEdge) { |
| 386 FloatRoundedRect border = obj.style()->getRoundedBorderFor( | 332 FloatRoundedRect border = obj.style()->getRoundedBorderFor( |
| 387 borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); | 333 borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); |
| 388 if (box && (box->nextLineBox() || box->prevLineBox())) { | 334 if (box && (box->nextLineBox() || box->prevLineBox())) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 obj.style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge); | 429 obj.style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge); |
| 484 // BorderFillBox radius clipping is taken care of by | 430 // BorderFillBox radius clipping is taken care of by |
| 485 // BackgroundBleedClip{Only,Layer} | 431 // BackgroundBleedClip{Only,Layer} |
| 486 isRoundedFill = hasRoundedBorder && | 432 isRoundedFill = hasRoundedBorder && |
| 487 !(isBorderFill && bleedAvoidanceIsClipping(bleedAvoidance)); | 433 !(isBorderFill && bleedAvoidanceIsClipping(bleedAvoidance)); |
| 488 | 434 |
| 489 shouldPaintImage = image && image->canRender(); | 435 shouldPaintImage = image && image->canRender(); |
| 490 shouldPaintColor = | 436 shouldPaintColor = |
| 491 isBottomLayer && color.alpha() && | 437 isBottomLayer && color.alpha() && |
| 492 (!shouldPaintImage || !layer.imageOccludesNextLayers(obj)); | 438 (!shouldPaintImage || !layer.imageOccludesNextLayers(obj)); |
| 493 shouldPaintShadow = | |
| 494 shouldPaintColor && | |
| 495 obj.boxShadowShouldBeAppliedToBackground(bleedAvoidance, box); | |
| 496 } | 439 } |
| 497 | 440 |
| 498 // FillLayerInfo is a temporary, stack-allocated container which cannot | 441 // FillLayerInfo is a temporary, stack-allocated container which cannot |
| 499 // outlive the StyleImage. This would normally be a raw pointer, if not for | 442 // outlive the StyleImage. This would normally be a raw pointer, if not for |
| 500 // the Oilpan tooling complaints. | 443 // the Oilpan tooling complaints. |
| 501 Member<StyleImage> image; | 444 Member<StyleImage> image; |
| 502 Color color; | 445 Color color; |
| 503 | 446 |
| 504 bool includeLeftEdge; | 447 bool includeLeftEdge; |
| 505 bool includeRightEdge; | 448 bool includeRightEdge; |
| 506 bool isBottomLayer; | 449 bool isBottomLayer; |
| 507 bool isBorderFill; | 450 bool isBorderFill; |
| 508 bool isClippedWithLocalScrolling; | 451 bool isClippedWithLocalScrolling; |
| 509 bool isRoundedFill; | 452 bool isRoundedFill; |
| 510 | 453 |
| 511 bool shouldPaintImage; | 454 bool shouldPaintImage; |
| 512 bool shouldPaintColor; | 455 bool shouldPaintColor; |
| 513 bool shouldPaintShadow; | |
| 514 }; | 456 }; |
| 515 | 457 |
| 516 // RAII image paint helper. | 458 // RAII image paint helper. |
| 517 class ImagePaintContext { | 459 class ImagePaintContext { |
| 518 STACK_ALLOCATED(); | 460 STACK_ALLOCATED(); |
| 519 | 461 |
| 520 public: | 462 public: |
| 521 ImagePaintContext(const LayoutBoxModelObject& obj, | 463 ImagePaintContext(const LayoutBoxModelObject& obj, |
| 522 GraphicsContext& context, | 464 GraphicsContext& context, |
| 523 const FillLayer& layer, | 465 const FillLayer& layer, |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 | 563 |
| 622 Optional<RoundedInnerRectClipper> clipper; | 564 Optional<RoundedInnerRectClipper> clipper; |
| 623 if (info.isRoundedFill && !border.isRenderable()) { | 565 if (info.isRoundedFill && !border.isRenderable()) { |
| 624 // When the rrect is not renderable, we resort to clipping. | 566 // When the rrect is not renderable, we resort to clipping. |
| 625 // RoundedInnerRectClipper handles this case via discrete, corner-wise | 567 // RoundedInnerRectClipper handles this case via discrete, corner-wise |
| 626 // clipping. | 568 // clipping. |
| 627 clipper.emplace(obj, paintInfo, rect, border, ApplyToContext); | 569 clipper.emplace(obj, paintInfo, rect, border, ApplyToContext); |
| 628 border.setRadii(FloatRoundedRect::Radii()); | 570 border.setRadii(FloatRoundedRect::Radii()); |
| 629 } | 571 } |
| 630 | 572 |
| 631 // Paint the color + shadow if needed. | 573 // Paint the color if needed. |
| 632 if (info.shouldPaintColor) { | 574 if (info.shouldPaintColor) |
| 633 const ShadowContext shadowContext(context, obj, info.shouldPaintShadow); | |
| 634 context.fillRoundedRect(border, info.color); | 575 context.fillRoundedRect(border, info.color); |
| 635 } | |
| 636 | 576 |
| 637 // Paint the image + shadow if needed. | 577 // Paint the image if needed. |
| 638 if (!info.shouldPaintImage || imageTile.isEmpty()) | 578 if (!info.shouldPaintImage || imageTile.isEmpty()) |
| 639 return true; | 579 return true; |
| 640 | 580 |
| 641 const ImagePaintContext imageContext(obj, context, layer, *info.image, op, | 581 const ImagePaintContext imageContext(obj, context, layer, *info.image, op, |
| 642 backgroundObject, geometry->tileSize()); | 582 backgroundObject, geometry->tileSize()); |
| 643 if (!imageContext.image()) | 583 if (!imageContext.image()) |
| 644 return true; | 584 return true; |
| 645 | 585 |
| 646 const FloatSize intrinsicTileSize = | 586 const FloatSize intrinsicTileSize = |
| 647 imageContext.image()->hasRelativeSize() | 587 imageContext.image()->hasRelativeSize() |
| 648 ? imageTile.size() | 588 ? imageTile.size() |
| 649 : FloatSize(imageContext.image()->size()); | 589 : FloatSize(imageContext.image()->size()); |
| 650 const FloatRect srcRect = | 590 const FloatRect srcRect = |
| 651 Image::computeSubsetForTile(imageTile, border.rect(), intrinsicTileSize); | 591 Image::computeSubsetForTile(imageTile, border.rect(), intrinsicTileSize); |
| 652 | 592 |
| 653 // The shadow may have been applied with the color fill. | |
| 654 const ShadowContext shadowContext( | |
| 655 context, obj, info.shouldPaintShadow && !info.shouldPaintColor); | |
| 656 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", | 593 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", |
| 657 "data", InspectorPaintImageEvent::data(obj, *info.image)); | 594 "data", InspectorPaintImageEvent::data(obj, *info.image)); |
| 658 context.drawImageRRect(imageContext.image(), border, srcRect, | 595 context.drawImageRRect(imageContext.image(), border, srcRect, |
| 659 imageContext.compositeOp()); | 596 imageContext.compositeOp()); |
| 660 | 597 |
| 661 updatePreferredRasterBoundsFromImage(srcRect, border.rect(), obj); | 598 updatePreferredRasterBoundsFromImage(srcRect, border.rect(), obj); |
| 662 | 599 |
| 663 return true; | 600 return true; |
| 664 } | 601 } |
| 665 | 602 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 default: | 725 default: |
| 789 ASSERT_NOT_REACHED(); | 726 ASSERT_NOT_REACHED(); |
| 790 break; | 727 break; |
| 791 } | 728 } |
| 792 | 729 |
| 793 // Paint the color first underneath all images, culled if background image | 730 // Paint the color first underneath all images, culled if background image |
| 794 // occludes it. | 731 // occludes it. |
| 795 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the | 732 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the |
| 796 // culling test by verifying whether the background image covers the entire | 733 // culling test by verifying whether the background image covers the entire |
| 797 // painting area. | 734 // painting area. |
| 798 if (info.isBottomLayer && info.color.alpha()) { | 735 if (info.isBottomLayer && info.color.alpha() && info.shouldPaintColor) { |
| 799 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); | 736 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); |
| 800 if (info.shouldPaintColor || info.shouldPaintShadow) { | 737 context.fillRect(backgroundRect, info.color); |
| 801 const ShadowContext shadowContext(context, obj, info.shouldPaintShadow); | |
| 802 context.fillRect(backgroundRect, info.color); | |
| 803 } | |
| 804 } | 738 } |
| 805 | 739 |
| 806 // no progressive loading of the background image | 740 // no progressive loading of the background image |
| 807 if (info.shouldPaintImage) { | 741 if (info.shouldPaintImage) { |
| 808 if (!geometry) { | 742 if (!geometry) { |
| 809 geometry.emplace(); | 743 geometry.emplace(); |
| 810 geometry->calculate(obj, paintInfo.paintContainer(), | 744 geometry->calculate(obj, paintInfo.paintContainer(), |
| 811 paintInfo.getGlobalPaintFlags(), bgLayer, | 745 paintInfo.getGlobalPaintFlags(), bgLayer, |
| 812 scrolledPaintRect); | 746 scrolledPaintRect); |
| 813 } else { | 747 } else { |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1110 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( | 1044 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( |
| 1111 const ComputedStyle& style, | 1045 const ComputedStyle& style, |
| 1112 const Document& document) { | 1046 const Document& document) { |
| 1113 return document.printing() && | 1047 return document.printing() && |
| 1114 style.getPrintColorAdjust() == PrintColorAdjustEconomy && | 1048 style.getPrintColorAdjust() == PrintColorAdjustEconomy && |
| 1115 (!document.settings() || | 1049 (!document.settings() || |
| 1116 !document.settings()->shouldPrintBackgrounds()); | 1050 !document.settings()->shouldPrintBackgrounds()); |
| 1117 } | 1051 } |
| 1118 | 1052 |
| 1119 } // namespace blink | 1053 } // namespace blink |
| OLD | NEW |