Changeset 83422 in webkit
- Timestamp:
- Apr 10, 2011 9:51:42 PM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r83419 r83422 1 2011-04-10 Simon Fraser <simon.fraser@apple.com> 2 3 Reviewed by Ariya Hidayat. 4 5 Allow ShadowBlur to re-use the last buffer if it already contains the correct shadow 6 https://bugs.webkit.org/show_bug.cgi?id=58161 7 8 ShadowBlur already has a singleton scratch buffer that is re-used 9 between shadows. Enhance use of this scratch buffer to avoid drawing 10 and blurring the shadow if the results will match what is already 11 in the buffer. 12 13 Cleaned up ShadowBlur code to remove beginShadowLayer() and endShadowLayer(), 14 which ended up with little reusable code after adding the re-use logic. 15 16 * platform/graphics/FloatRect.cpp: 17 (WebCore::enclosingIntRect): Replace safeFloatToInt() with the existing 18 clampToInteger() from MathExtras.h 19 20 * platform/graphics/FloatSize.h: 21 (WebCore::expandedIntSize): New method to safely ceil() the size. 22 23 * platform/graphics/RoundedIntRect.h: 24 Add operator== for Radii and RoundedIntRect. 25 26 * platform/graphics/ShadowBlur.cpp: 27 (WebCore::ScratchBuffer::ScratchBuffer): 28 (WebCore::ScratchBuffer::setLastShadowValues): 29 (WebCore::ScratchBuffer::setLastInsetShadowValues): 30 (WebCore::ScratchBuffer::matchesLastShadow): 31 (WebCore::ScratchBuffer::matchesLastInsetShadow): 32 (WebCore::ScratchBuffer::clearScratchBuffer): 33 Have the scratch buffer remember what shadow parameters were used 34 to render the buffer contents. 35 36 (WebCore::ShadowBlur::drawShadowBuffer): 37 Renamed from endShadowLayer(), and only contains the drawing 38 logic now. 39 40 (WebCore::ShadowBlur::drawRectShadow): 41 Promote some code from beginShadowLayer(). 42 43 (WebCore::ShadowBlur::drawInsetShadow): 44 Promote some code from beginShadowLayer(). 45 46 (WebCore::ShadowBlur::drawRectShadowWithoutTiling): 47 (WebCore::ShadowBlur::drawInsetShadowWithoutTiling): 48 (WebCore::ShadowBlur::drawInsetShadowWithTiling): 49 (WebCore::ShadowBlur::drawRectShadowWithTiling): 50 These methods now check to see if the buffer already matches 51 their required parameters, and avoid work if it does. 52 53 (WebCore::ShadowBlur::blurShadowBuffer): 54 Factored some code into this new method. 55 56 (WebCore::ShadowBlur::blurAndColorShadowBuffer): 57 Minor refactoring. 58 59 * platform/graphics/ShadowBlur.h: 60 1 61 2011-04-10 Geoffrey Garen <ggaren@apple.com> 2 62 -
trunk/Source/WebCore/platform/graphics/FloatRect.cpp
r83075 r83422 31 31 #include "IntRect.h" 32 32 #include <algorithm> 33 #include <limits>34 33 #include <math.h> 34 #include <wtf/MathExtras.h> 35 35 36 36 using std::max; … … 183 183 } 184 184 185 static inline int safeFloatToInt(float x)186 {187 static const int s_intMax = std::numeric_limits<int>::max();188 static const int s_intMin = std::numeric_limits<int>::min();189 190 if (x >= static_cast<float>(s_intMax))191 return s_intMax;192 if (x < static_cast<float>(s_intMin))193 return s_intMin;194 return static_cast<int>(x);195 }196 197 185 IntRect enclosingIntRect(const FloatRect& rect) 198 186 { … … 201 189 float width = ceilf(rect.maxX()) - left; 202 190 float height = ceilf(rect.maxY()) - top; 203 return IntRect( safeFloatToInt(left), safeFloatToInt(top),204 safeFloatToInt(width), safeFloatToInt(height));191 return IntRect(clampToInteger(left), clampToInteger(top), 192 clampToInteger(width), clampToInteger(height)); 205 193 } 206 194 -
trunk/Source/WebCore/platform/graphics/FloatSize.h
r66560 r83422 149 149 } 150 150 151 inline IntSize expandedIntSize(const FloatSize& p) 152 { 153 return IntSize(clampToInteger(ceilf(p.width())), clampToInteger(ceilf(p.height()))); 154 } 155 151 156 } // namespace WebCore 152 157 -
trunk/Source/WebCore/platform/graphics/RoundedIntRect.h
r76083 r83422 99 99 }; 100 100 101 inline bool operator==(const RoundedIntRect::Radii& a, const RoundedIntRect::Radii& b) 102 { 103 return a.topLeft() == b.topLeft() && a.topRight() == b.topRight() && a.bottomLeft() == b.bottomLeft() && a.bottomRight() == b.bottomRight(); 104 } 105 106 inline bool operator==(const RoundedIntRect& a, const RoundedIntRect& b) 107 { 108 return a.rect() == b.rect() && a.radii() == b.radii(); 109 } 110 111 101 112 } // namespace WebCore 102 113 -
trunk/Source/WebCore/platform/graphics/ShadowBlur.cpp
r83358 r83422 55 55 ScratchBuffer() 56 56 : m_purgeTimer(this, &ScratchBuffer::timerFired) 57 , m_lastRadius(0) 58 , m_lastWasInset(false) 57 59 #if !ASSERT_DISABLED 58 60 , m_bufferInUse(false) … … 78 80 } 79 81 82 void setLastShadowValues(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) 83 { 84 m_lastWasInset = false; 85 m_lastRadius = radius; 86 m_lastColor = color; 87 m_lastColorSpace = colorSpace; 88 m_lastShadowRect = shadowRect; 89 m_lastRadii = radii; 90 } 91 92 void setLastInsetShadowValues(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& bounds, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) 93 { 94 m_lastWasInset = true; 95 m_lastInsetBounds = bounds; 96 m_lastRadius = radius; 97 m_lastColor = color; 98 m_lastColorSpace = colorSpace; 99 m_lastShadowRect = shadowRect; 100 m_lastRadii = radii; 101 } 102 103 bool matchesLastShadow(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) const 104 { 105 if (m_lastWasInset) 106 return false; 107 return m_lastRadius == radius && m_lastColor == color && m_lastColorSpace == colorSpace && shadowRect == m_lastShadowRect && radii == m_lastRadii; 108 } 109 110 bool matchesLastInsetShadow(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& bounds, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) const 111 { 112 if (!m_lastWasInset) 113 return false; 114 return m_lastRadius == radius && m_lastColor == color && m_lastColorSpace == colorSpace && m_lastInsetBounds == bounds && shadowRect == m_lastShadowRect && radii == m_lastRadii; 115 } 116 80 117 void scheduleScratchBufferPurge() 81 118 { … … 101 138 { 102 139 m_imageBuffer = 0; 140 m_lastRadius = 0; 103 141 } 104 142 105 143 OwnPtr<ImageBuffer> m_imageBuffer; 106 144 Timer<ScratchBuffer> m_purgeTimer; 145 146 FloatRect m_lastInsetBounds; 147 FloatRect m_lastShadowRect; 148 RoundedIntRect::Radii m_lastRadii; 149 Color m_lastColor; 150 ColorSpace m_lastColorSpace; 151 float m_lastRadius; 152 bool m_lastWasInset; 153 107 154 #if !ASSERT_DISABLED 108 155 bool m_bufferInUse; … … 350 397 } 351 398 352 GraphicsContext* ShadowBlur::beginShadowLayer(GraphicsContext* graphicsContext, const IntRect& layerRect) 353 { 354 adjustBlurRadius(graphicsContext); 355 356 // Don't paint if we are totally outside the clip region. 357 if (layerRect.isEmpty()) 358 return 0; 359 360 m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); 361 GraphicsContext* layerContext = m_layerImage->context(); 362 363 layerContext->save(); // Balanced by restore() in endShadowLayer(). 364 365 // Always clear the surface first. FIXME: we could avoid the clear on first allocation. 366 // Add a pixel to avoid later edge aliasing when rotated. 367 layerContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); 368 layerContext->translate(m_layerContextTranslation); 369 370 return layerContext; 371 } 372 373 void ShadowBlur::endShadowLayer(GraphicsContext* graphicsContext) 399 void ShadowBlur::drawShadowBuffer(GraphicsContext* graphicsContext) 374 400 { 375 401 if (!m_layerImage) 376 402 return; 377 378 m_layerImage->context()->restore();379 380 if (m_type == BlurShadow) {381 IntRect blurRect = enclosingIntRect(FloatRect(FloatPoint(), m_layerSize));382 RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect);383 blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4);384 m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint());385 }386 403 387 404 graphicsContext->save(); … … 400 417 401 418 graphicsContext->restore(); 402 403 m_layerImage = 0;404 405 // Schedule a purge of the scratch buffer. We do not need to destroy the surface.406 ScratchBuffer::shared().scheduleScratchBufferPurge();407 419 } 408 420 … … 436 448 return; 437 449 450 adjustBlurRadius(graphicsContext); 451 438 452 // drawRectShadowWithTiling does not work with rotations. 439 453 // https://bugs.webkit.org/show_bug.cgi?id=45042 … … 460 474 return; 461 475 476 adjustBlurRadius(graphicsContext); 477 462 478 // drawInsetShadowWithTiling does not work with rotations. 463 479 // https://bugs.webkit.org/show_bug.cgi?id=45042 … … 480 496 void ShadowBlur::drawRectShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& shadowedRect, const RoundedIntRect::Radii& radii, const IntRect& layerRect) 481 497 { 482 GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); 483 if (!shadowContext) 484 return; 485 486 Path path; 487 path.addRoundedRect(shadowedRect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); 488 489 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 490 shadowContext->fillPath(path); 491 492 endShadowLayer(graphicsContext); 498 m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); 499 if (!m_layerImage) 500 return; 501 502 FloatRect bufferRelativeShadowedRect = shadowedRect; 503 bufferRelativeShadowedRect.move(m_layerContextTranslation); 504 if (!ScratchBuffer::shared().matchesLastShadow(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeShadowedRect, radii)) { 505 GraphicsContext* shadowContext = m_layerImage->context(); 506 shadowContext->save(); 507 508 // Add a pixel to avoid later edge aliasing when rotated. 509 shadowContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); 510 shadowContext->translate(m_layerContextTranslation); 511 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 512 if (radii.isZero()) 513 shadowContext->fillRect(shadowedRect); 514 else { 515 Path path; 516 path.addRoundedRect(shadowedRect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); 517 shadowContext->fillPath(path); 518 } 519 520 blurShadowBuffer(expandedIntSize(m_layerSize)); 521 522 shadowContext->restore(); 523 524 ScratchBuffer::shared().setLastShadowValues(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeShadowedRect, radii); 525 } 526 527 drawShadowBuffer(graphicsContext); 528 m_layerImage = 0; 529 ScratchBuffer::shared().scheduleScratchBufferPurge(); 493 530 } 494 531 495 532 void ShadowBlur::drawInsetShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& rect, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii, const IntRect& layerRect) 496 533 { 497 GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); 498 if (!shadowContext) 499 return; 500 501 Path path; 502 path.addRect(rect); 503 path.addRoundedRect(holeRect, holeRadii.topLeft(), holeRadii.topRight(), holeRadii.bottomLeft(), holeRadii.bottomRight()); 504 505 shadowContext->setFillRule(RULE_EVENODD); 506 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 507 shadowContext->fillPath(path); 508 509 endShadowLayer(graphicsContext); 534 m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); 535 if (!m_layerImage) 536 return; 537 538 FloatRect bufferRelativeRect = rect; 539 bufferRelativeRect.move(m_layerContextTranslation); 540 541 FloatRect bufferRelativeHoleRect = holeRect; 542 bufferRelativeHoleRect.move(m_layerContextTranslation); 543 544 if (!ScratchBuffer::shared().matchesLastInsetShadow(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeRect, bufferRelativeHoleRect, holeRadii)) { 545 GraphicsContext* shadowContext = m_layerImage->context(); 546 shadowContext->save(); 547 548 // Add a pixel to avoid later edge aliasing when rotated. 549 shadowContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); 550 shadowContext->translate(m_layerContextTranslation); 551 552 Path path; 553 path.addRect(rect); 554 if (holeRadii.isZero()) 555 path.addRect(holeRect); 556 else 557 path.addRoundedRect(holeRect, holeRadii.topLeft(), holeRadii.topRight(), holeRadii.bottomLeft(), holeRadii.bottomRight()); 558 559 shadowContext->setFillRule(RULE_EVENODD); 560 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 561 shadowContext->fillPath(path); 562 563 blurShadowBuffer(expandedIntSize(m_layerSize)); 564 565 shadowContext->restore(); 566 567 ScratchBuffer::shared().setLastInsetShadowValues(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeRect, bufferRelativeHoleRect, holeRadii); 568 } 569 570 drawShadowBuffer(graphicsContext); 571 m_layerImage = 0; 572 ScratchBuffer::shared().scheduleScratchBufferPurge(); 510 573 } 511 574 … … 551 614 552 615 m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); 616 if (!m_layerImage) 617 return; 553 618 554 619 // Draw the rectangle with hole. 555 620 FloatRect templateBounds(0, 0, templateSize.width(), templateSize.height()); 556 621 FloatRect templateHole = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); 557 Path path; 558 path.addRect(templateBounds); 559 path.addRoundedRect(templateHole, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); 560 561 // Draw shadow into a new ImageBuffer. 562 GraphicsContext* shadowContext = m_layerImage->context(); 563 shadowContext->save(); 564 shadowContext->clearRect(templateBounds); 565 shadowContext->setFillRule(RULE_EVENODD); 566 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 567 shadowContext->fillPath(path); 568 blurAndColorShadowBuffer(templateSize); 569 shadowContext->restore(); 622 623 if (!ScratchBuffer::shared().matchesLastInsetShadow(m_blurRadius, m_color, m_colorSpace, templateBounds, templateHole, radii)) { 624 // Draw shadow into a new ImageBuffer. 625 GraphicsContext* shadowContext = m_layerImage->context(); 626 shadowContext->save(); 627 shadowContext->clearRect(templateBounds); 628 shadowContext->setFillRule(RULE_EVENODD); 629 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 630 631 Path path; 632 path.addRect(templateBounds); 633 if (radii.isZero()) 634 path.addRect(templateHole); 635 else 636 path.addRoundedRect(templateHole, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); 637 638 shadowContext->fillPath(path); 639 640 blurAndColorShadowBuffer(templateSize); 641 shadowContext->restore(); 642 643 ScratchBuffer::shared().setLastInsetShadowValues(m_blurRadius, m_color, m_colorSpace, templateBounds, templateHole, radii); 644 } 570 645 571 646 FloatRect boundingRect = rect; … … 593 668 594 669 m_layerImage = 0; 595 // Schedule a purge of the scratch buffer.596 670 ScratchBuffer::shared().scheduleScratchBufferPurge(); 597 671 } … … 606 680 607 681 m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); 608 609 // Draw the rectangle. 682 if (!m_layerImage) 683 return; 684 610 685 FloatRect templateShadow = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); 611 Path path; 612 path.addRoundedRect(templateShadow, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); 613 614 // Draw shadow into the ImageBuffer. 615 GraphicsContext* shadowContext = m_layerImage->context(); 616 shadowContext->save(); 617 shadowContext->clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); 618 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 619 shadowContext->fillPath(path); 620 blurAndColorShadowBuffer(templateSize); 621 shadowContext->restore(); 686 687 if (!ScratchBuffer::shared().matchesLastShadow(m_blurRadius, m_color, m_colorSpace, templateShadow, radii)) { 688 // Draw shadow into the ImageBuffer. 689 GraphicsContext* shadowContext = m_layerImage->context(); 690 shadowContext->save(); 691 shadowContext->clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); 692 shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); 693 694 if (radii.isZero()) 695 shadowContext->fillRect(templateShadow); 696 else { 697 Path path; 698 path.addRoundedRect(templateShadow, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); 699 shadowContext->fillPath(path); 700 } 701 702 blurAndColorShadowBuffer(templateSize); 703 shadowContext->restore(); 704 705 ScratchBuffer::shared().setLastShadowValues(m_blurRadius, m_color, m_colorSpace, templateShadow, radii); 706 } 622 707 623 708 FloatRect shadowBounds = shadowedRect; … … 630 715 631 716 m_layerImage = 0; 632 // Schedule a purge of the scratch buffer.633 717 ScratchBuffer::shared().scheduleScratchBufferPurge(); 634 718 } … … 708 792 709 793 794 void ShadowBlur::blurShadowBuffer(const IntSize& templateSize) 795 { 796 if (m_type != BlurShadow) 797 return; 798 799 IntRect blurRect(IntPoint(), templateSize); 800 RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); 801 blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); 802 m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); 803 } 804 710 805 void ShadowBlur::blurAndColorShadowBuffer(const IntSize& templateSize) 711 806 { 712 { 713 IntRect blurRect(IntPoint(), templateSize); 714 RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); 715 blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); 716 m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); 717 } 807 blurShadowBuffer(templateSize); 718 808 719 809 // Mask the image with the shadow color. -
trunk/Source/WebCore/platform/graphics/ShadowBlur.h
r78062 r83422 54 54 55 55 private: 56 GraphicsContext* beginShadowLayer(GraphicsContext*, const IntRect& layerRect); 57 void endShadowLayer(GraphicsContext*); 56 void drawShadowBuffer(GraphicsContext*); 58 57 59 58 void adjustBlurRadius(GraphicsContext*); … … 76 75 void drawLayerPieces(GraphicsContext*, const FloatRect& shadowBounds, const RoundedIntRect::Radii&, float roundedRadius, const IntSize& templateSize, ShadowDirection); 77 76 77 void blurShadowBuffer(const IntSize& templateSize); 78 78 void blurAndColorShadowBuffer(const IntSize& templateSize); 79 79
Note: See TracChangeset
for help on using the changeset viewer.