- Revision
- 91628
- Author
- simon.fra...@apple.com
- Date
- 2011-07-22 17:39:54 -0700 (Fri, 22 Jul 2011)
Log Message
2011-07-22 Simon Fraser <simon.fra...@apple.com>
Avoiding painting backgrounds if they are fully obscures by an object's foreground
https://bugs.webkit.org/show_bug.cgi?id=65030
Reviewed by Dan Bernstein.
Some pages use animated loading GIFs as the background of <img>,
but WebKit keeps animating these after the <img> has loaded.
Thwart this by avoiding the painting of such backgrounds, if we can
determine that they are completely obscured by the border and content
of the element.
* platform/graphics/BitmapImage.h:
(WebCore::BitmapImage::currentFrameHasAlpha): Utility method, since currentFrame()
is protected.
* rendering/RenderBox.cpp:
(WebCore::RenderBox::paintBoxDecorations): Call paintBackground().
(WebCore::RenderBox::paintBackground): New wrapper for the paintFillLayers() which
paints the background layers, plus some code we call in a couple of places. This
checks the new backgroundIsObscured() method before doing any painting.
* rendering/RenderBox.h:
(WebCore::RenderBox::backgroundIsObscured): New virtual method that determines
whether any of the background is visible.
* rendering/RenderBoxModelObject.h:
* rendering/RenderBoxModelObject.cpp:
(WebCore::BorderEdge::obscuresBackground): Returns true if this edge will
entirely hide the background under it.
(WebCore::RenderBoxModelObject::borderObscuresBackground): Determine whether
the border hides the background.
* rendering/RenderImage.cpp:
(WebCore::RenderImage::backgroundIsObscured): Override the RenderBox method
and return true if the image is a loaded, opaque bitmap image, and the background
won't show in the border or padding areas.
* rendering/RenderImage.h:
* rendering/RenderTable.cpp:
(WebCore::RenderTable::paintBoxDecorations): Use paintBackground().
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (91627 => 91628)
--- trunk/Source/WebCore/ChangeLog 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/ChangeLog 2011-07-23 00:39:54 UTC (rev 91628)
@@ -1,3 +1,42 @@
+2011-07-22 Simon Fraser <simon.fra...@apple.com>
+
+ Avoiding painting backgrounds if they are fully obscures by an object's foreground
+ https://bugs.webkit.org/show_bug.cgi?id=65030
+
+ Reviewed by Dan Bernstein.
+
+ Some pages use animated loading GIFs as the background of <img>,
+ but WebKit keeps animating these after the <img> has loaded.
+
+ Thwart this by avoiding the painting of such backgrounds, if we can
+ determine that they are completely obscured by the border and content
+ of the element.
+
+ * platform/graphics/BitmapImage.h:
+ (WebCore::BitmapImage::currentFrameHasAlpha): Utility method, since currentFrame()
+ is protected.
+ * rendering/RenderBox.cpp:
+ (WebCore::RenderBox::paintBoxDecorations): Call paintBackground().
+ (WebCore::RenderBox::paintBackground): New wrapper for the paintFillLayers() which
+ paints the background layers, plus some code we call in a couple of places. This
+ checks the new backgroundIsObscured() method before doing any painting.
+ * rendering/RenderBox.h:
+ (WebCore::RenderBox::backgroundIsObscured): New virtual method that determines
+ whether any of the background is visible.
+ * rendering/RenderBoxModelObject.h:
+ * rendering/RenderBoxModelObject.cpp:
+ (WebCore::BorderEdge::obscuresBackground): Returns true if this edge will
+ entirely hide the background under it.
+ (WebCore::RenderBoxModelObject::borderObscuresBackground): Determine whether
+ the border hides the background.
+ * rendering/RenderImage.cpp:
+ (WebCore::RenderImage::backgroundIsObscured): Override the RenderBox method
+ and return true if the image is a loaded, opaque bitmap image, and the background
+ won't show in the border or padding areas.
+ * rendering/RenderImage.h:
+ * rendering/RenderTable.cpp:
+ (WebCore::RenderTable::paintBoxDecorations): Use paintBackground().
+
2011-07-22 Kenneth Russell <k...@google.com>
HTMLImageElement::crossOrigin is hard to use because of caching
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (91627 => 91628)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.h 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h 2011-07-23 00:39:54 UTC (rev 91628)
@@ -158,7 +158,8 @@
#endif
virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); }
- bool frameHasAlphaAtIndex(size_t);
+ bool frameHasAlphaAtIndex(size_t);
+ bool currentFrameHasAlpha() { return frameHasAlphaAtIndex(currentFrame()); }
#if !ASSERT_DISABLED
bool notSolidColor()
Modified: trunk/Source/WebCore/rendering/RenderBox.cpp (91627 => 91628)
--- trunk/Source/WebCore/rendering/RenderBox.cpp 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBox.cpp 2011-07-23 00:39:54 UTC (rev 91628)
@@ -862,13 +862,8 @@
// The theme will tell us whether or not we should also paint the CSS background.
bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, paintRect);
if (!themePainted) {
- if (isRoot())
- paintRootBoxFillLayers(paintInfo);
- else if (!isBody() || document()->documentElement()->renderer()->hasBackground()) {
- // The <body> only paints its background if the root element has defined a background
- // independent of the body.
- paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
- }
+ paintBackground(paintInfo, paintRect, bleedAvoidance);
+
if (style()->hasAppearance())
theme()->paintDecorations(this, paintInfo, paintRect);
}
@@ -882,6 +877,18 @@
paintInfo.context->endTransparencyLayer();
}
+void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
+{
+ if (isRoot())
+ paintRootBoxFillLayers(paintInfo);
+ else if (!isBody() || document()->documentElement()->renderer()->hasBackground()) {
+ // The <body> only paints its background if the root element has defined a background
+ // independent of the body.
+ if (!backgroundIsObscured())
+ paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
+ }
+}
+
void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
Modified: trunk/Source/WebCore/rendering/RenderBox.h (91627 => 91628)
--- trunk/Source/WebCore/rendering/RenderBox.h 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBox.h 2011-07-23 00:39:54 UTC (rev 91628)
@@ -417,6 +417,9 @@
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
virtual void updateBoxModelInfoFromStyle();
+ virtual bool backgroundIsObscured() const { return false; }
+ void paintBackground(const PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone);
+
void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance, CompositeOperator, RenderObject* backgroundObject);
void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0);
Modified: trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp (91627 => 91628)
--- trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp 2011-07-23 00:39:54 UTC (rev 91628)
@@ -1095,7 +1095,17 @@
return true;
}
+ bool obscuresBackground() const
+ {
+ if (!isPresent || isTransparent || color.hasAlpha() || style == BHIDDEN)
+ return false;
+ if (style == DOTTED || style == DASHED || style == DOUBLE)
+ return false;
+
+ return true;
+ }
+
int usedWidth() const { return isPresent ? width : 0; }
void getDoubleBorderStripeWidths(int& outerWidth, int& innerWidth) const
@@ -2145,6 +2155,27 @@
return true;
}
+bool RenderBoxModelObject::borderObscuresBackground() const
+{
+ if (!style()->hasBorder())
+ return false;
+
+ // Bail if we have any border-image for now. We could look at the image alpha to improve this.
+ if (style()->borderImage().image())
+ return false;
+
+ BorderEdge edges[4];
+ getBorderEdgeInfo(edges);
+
+ for (int i = BSTop; i <= BSLeft; ++i) {
+ const BorderEdge& currEdge = edges[i];
+ if (!currEdge.obscuresBackground())
+ return false;
+ }
+
+ return true;
+}
+
static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset)
{
IntRect bounds(holeRect);
Modified: trunk/Source/WebCore/rendering/RenderBoxModelObject.h (91627 => 91628)
--- trunk/Source/WebCore/rendering/RenderBoxModelObject.h 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBoxModelObject.h 2011-07-23 00:39:54 UTC (rev 91628)
@@ -183,6 +183,7 @@
void calculateBackgroundImageGeometry(const FillLayer*, const IntRect& paintRect, BackgroundImageGeometry&);
void getBorderEdgeInfo(class BorderEdge[], bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const;
bool borderObscuresBackgroundEdge(const FloatSize& contextScale) const;
+ bool borderObscuresBackground() const;
bool shouldPaintAtLowQuality(GraphicsContext*, Image*, const void*, const IntSize&);
Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (91627 => 91628)
--- trunk/Source/WebCore/rendering/RenderImage.cpp 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp 2011-07-23 00:39:54 UTC (rev 91628)
@@ -27,6 +27,7 @@
#include "config.h"
#include "RenderImage.h"
+#include "BitmapImage.h"
#include "FontCache.h"
#include "Frame.h"
#include "FrameSelection.h"
@@ -387,6 +388,36 @@
context->drawImage(m_imageResource->image(rect.width(), rect.height()).get(), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling);
}
+bool RenderImage::backgroundIsObscured() const
+{
+ if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
+ return false;
+
+ if (m_imageResource->cachedImage() && !m_imageResource->cachedImage()->isLoaded())
+ return false;
+
+ EFillBox backgroundClip = style()->backgroundClip();
+
+ // Background paints under borders.
+ if (backgroundClip == BorderFillBox && style()->hasBorder() && !borderObscuresBackground())
+ return false;
+
+ // Background shows in padding area.
+ if ((backgroundClip == BorderFillBox || backgroundClip == PaddingFillBox) && style()->hasPadding())
+ return false;
+
+ // Check for bitmap image with alpha.
+ Image* image = m_imageResource->image().get();
+ if (!image || !image->isBitmapImage())
+ return false;
+
+ BitmapImage* bitmapImage = static_cast<BitmapImage*>(image);
+ if (bitmapImage->currentFrameHasAlpha())
+ return false;
+
+ return true;
+}
+
int RenderImage::minimumReplacedHeight() const
{
return m_imageResource->errorOccurred() ? intrinsicSize().height() : 0;
Modified: trunk/Source/WebCore/rendering/RenderImage.h (91627 => 91628)
--- trunk/Source/WebCore/rendering/RenderImage.h 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderImage.h 2011-07-23 00:39:54 UTC (rev 91628)
@@ -78,6 +78,8 @@
virtual void paintReplaced(PaintInfo&, const IntPoint&);
+ virtual bool backgroundIsObscured() const;
+
virtual int minimumReplacedHeight() const;
virtual void notifyFinished(CachedResource*);
Modified: trunk/Source/WebCore/rendering/RenderTable.cpp (91627 => 91628)
--- trunk/Source/WebCore/rendering/RenderTable.cpp 2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderTable.cpp 2011-07-23 00:39:54 UTC (rev 91628)
@@ -558,14 +558,7 @@
subtractCaptionRect(rect);
paintBoxShadow(paintInfo.context, rect, style(), Normal);
-
- if (isRoot())
- paintRootBoxFillLayers(paintInfo);
- else if (!isBody() || document()->documentElement()->renderer()->hasBackground())
- // The <body> only paints its background if the root element has defined a background
- // independent of the body.
- paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), rect);
-
+ paintBackground(paintInfo, rect);
paintBoxShadow(paintInfo.context, rect, style(), Inset);
if (style()->hasBorder() && !collapseBorders())