https://bugs.webkit.org/show_bug.cgi?id=78728
In some cases, when there is only one normal box shadow, and the box has an opaque background,
it is possible to draw the box shadow by having the background cast it directly. This appears
to be faster than the generic code path that uses a separate drawing pass to cast the shadow,
clipping out the border box and the shadow-casting box.
Reviewed by Dave Hyatt.
No new tests, because behavior is unchanged.
* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::paintBoxDecorations): Changed to not paint normal box shadows if
they are going to be cast by the background.
* rendering/RenderBox.cpp:
(WebCore::RenderBox::paintBoxDecorations): Ditto.
* rendering/RenderBox.h: Made determineBackgroundBleedAvoidance() protected.
* rendering/RenderBoxModelObject.cpp:
(WebCore::applyBoxShadowForBackground): Added this helper function, which applies the first
normal shadow from the given RenderStyle to the given GraphicsContext.
(WebCore::RenderBoxModelObject::paintFillLayerExtended): Added calls to
applyBoxShadowForBackground() before drawing the background color when needed.
(WebCore::RenderBoxModelObject::boxShadowShouldBeAppliedToBackground): Added. Returns true
in some of the cases where the box shadow can be cast by the background directly.
* rendering/RenderBoxModelObject.h:
* rendering/RenderFieldset.cpp:
(WebCore::RenderFieldset::paintBoxDecorations): Changed to not paint normal box shadows if
they are going to be cast by the background.
* rendering/RenderTable.cpp:
(WebCore::RenderTable::paintBoxDecorations): Ditto.
* rendering/RenderTableCell.cpp:
(WebCore::RenderTableCell::boxShadowShouldBeAppliedToBackground): Added this override that
always returns false, because table cells sometimes apply a clip before drawing the background.
* rendering/RenderTableCell.h:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@107836
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-02-15 Dan Bernstein <mitz@apple.com>
+
+ <rdar://problem/10870238> Box shadow drawing takes an unnecessarily slow code path in some single-shadow, opaque-background cases
+ https://bugs.webkit.org/show_bug.cgi?id=78728
+
+ In some cases, when there is only one normal box shadow, and the box has an opaque background,
+ it is possible to draw the box shadow by having the background cast it directly. This appears
+ to be faster than the generic code path that uses a separate drawing pass to cast the shadow,
+ clipping out the border box and the shadow-casting box.
+
+ Reviewed by Dave Hyatt.
+
+ No new tests, because behavior is unchanged.
+
+ * rendering/InlineFlowBox.cpp:
+ (WebCore::InlineFlowBox::paintBoxDecorations): Changed to not paint normal box shadows if
+ they are going to be cast by the background.
+ * rendering/RenderBox.cpp:
+ (WebCore::RenderBox::paintBoxDecorations): Ditto.
+ * rendering/RenderBox.h: Made determineBackgroundBleedAvoidance() protected.
+ * rendering/RenderBoxModelObject.cpp:
+ (WebCore::applyBoxShadowForBackground): Added this helper function, which applies the first
+ normal shadow from the given RenderStyle to the given GraphicsContext.
+ (WebCore::RenderBoxModelObject::paintFillLayerExtended): Added calls to
+ applyBoxShadowForBackground() before drawing the background color when needed.
+ (WebCore::RenderBoxModelObject::boxShadowShouldBeAppliedToBackground): Added. Returns true
+ in some of the cases where the box shadow can be cast by the background directly.
+ * rendering/RenderBoxModelObject.h:
+ * rendering/RenderFieldset.cpp:
+ (WebCore::RenderFieldset::paintBoxDecorations): Changed to not paint normal box shadows if
+ they are going to be cast by the background.
+ * rendering/RenderTable.cpp:
+ (WebCore::RenderTable::paintBoxDecorations): Ditto.
+ * rendering/RenderTableCell.cpp:
+ (WebCore::RenderTableCell::boxShadowShouldBeAppliedToBackground): Added this override that
+ always returns false, because table cells sometimes apply a clip before drawing the background.
+ * rendering/RenderTableCell.h:
+
2012-02-15 Ojan Vafai <ojan@chromium.org>
getComputedStyle of flex-item-align:auto should resolve to it's parent's flex-align value
if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) {
LayoutRect paintRect = LayoutRect(adjustedPaintoffset, frameRect.size());
// Shadow comes first and is behind the background and border.
- paintBoxShadow(paintInfo, styleToUse, Normal, paintRect);
+ if (!boxModelObject()->boxShadowShouldBeAppliedToBackground(BackgroundBleedNone))
+ paintBoxShadow(paintInfo, styleToUse, Normal, paintRect);
Color c = styleToUse->visitedDependentColor(CSSPropertyBackgroundColor);
paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), paintRect);
// balloon layout is an example of this).
borderFitAdjust(paintRect);
+ BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
+
// FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
// custom shadows of their own.
- paintBoxShadow(paintInfo, paintRect, style(), Normal);
-
- BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
+ if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
+ paintBoxShadow(paintInfo, paintRect, style(), Normal);
GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
void paintMaskImages(const PaintInfo&, const LayoutRect&);
+ BackgroundBleedAvoidance determineBackgroundBleedAvoidance(GraphicsContext*) const;
+
#if PLATFORM(MAC)
void paintCustomHighlight(const LayoutPoint&, const AtomicString& type, bool behindText);
#endif
// These include tables, positioned objects, floats and flexible boxes.
virtual void computePreferredLogicalWidths() { setPreferredLogicalWidthsDirty(false); }
- BackgroundBleedAvoidance determineBackgroundBleedAvoidance(GraphicsContext*) const;
-
private:
// The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent).
LayoutRect m_frameRect;
return adjustedRect;
}
+static void applyBoxShadowForBackground(GraphicsContext* context, RenderStyle* style)
+{
+ const ShadowData* boxShadow = style->boxShadow();
+ while (boxShadow->style() != Normal)
+ boxShadow = boxShadow->next();
+
+ FloatSize shadowOffset(boxShadow->x(), boxShadow->y());
+ if (!boxShadow->isWebkitBoxShadow())
+ context->setShadow(shadowOffset, boxShadow->blur(), boxShadow->color(), style->colorSpace());
+ else
+ context->setLegacyShadow(shadowOffset, boxShadow->blur(), boxShadow->color(), style->colorSpace());
+}
+
void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& color, const FillLayer* bgLayer, const LayoutRect& rect,
BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, CompositeOperator op, RenderObject* backgroundObject)
{
if (!colorVisible)
return;
+ bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(bleedAvoidance);
+ GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAppliedToBackground);
+ if (boxShadowShouldBeAppliedToBackground)
+ applyBoxShadowForBackground(context, style());
+
if (hasRoundedBorder && bleedAvoidance != BackgroundBleedUseTransparencyLayer) {
RoundedRect border = getBackgroundRoundedRect(backgroundRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance), box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge);
context->fillRoundedRect(border, bgColor, style()->colorSpace());
// Paint the color first underneath all images.
if (!bgLayer->next()) {
IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect));
- backgroundRect.intersect(paintInfo.rect);
+ bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(bleedAvoidance);
+ if (!boxShadowShouldBeAppliedToBackground)
+ backgroundRect.intersect(paintInfo.rect);
+
// If we have an alpha and we are painting the root element, go ahead and blend with the base background color.
Color baseColor;
bool shouldClearBackground = false;
shouldClearBackground = true;
}
+ GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAppliedToBackground);
+ if (boxShadowShouldBeAppliedToBackground)
+ applyBoxShadowForBackground(context, style());
+
if (baseColor.alpha()) {
if (bgColor.alpha())
baseColor = baseColor.blend(bgColor);
return true;
}
+bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance bleedAvoidance) const
+{
+ if (bleedAvoidance != BackgroundBleedNone)
+ return false;
+
+ if (style()->hasAppearance())
+ return false;
+
+ const ShadowData* boxShadow = style()->boxShadow();
+ bool hasOneNormalBoxShadow = false;
+ for (const ShadowData* currentShadow = boxShadow; currentShadow; currentShadow = currentShadow->next()) {
+ if (currentShadow->style() != Normal)
+ continue;
+ if (hasOneNormalBoxShadow)
+ return false;
+ hasOneNormalBoxShadow = true;
+ }
+
+ if (!hasOneNormalBoxShadow)
+ return false;
+
+ Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
+ if (!backgroundColor.isValid() || backgroundColor.alpha() < 255)
+ return false;
+
+ const FillLayer* lastBackgroundLayer = style()->backgroundLayers();
+ for (const FillLayer* next = lastBackgroundLayer->next(); next; )
+ lastBackgroundLayer = next;
+
+ if (lastBackgroundLayer->clip() != BorderFillBox)
+ return false;
+
+ if (hasOverflowClip() && lastBackgroundLayer->attachment() == LocalBackgroundAttachment)
+ return false;
+
+ return true;
+}
+
static inline LayoutRect areaCastingShadowInHole(const LayoutRect& holeRect, int shadowBlur, int shadowSpread, const LayoutSize& shadowOffset)
{
LayoutRect bounds(holeRect);
void paintBoxShadow(const PaintInfo&, const LayoutRect&, const RenderStyle*, ShadowStyle, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true);
void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance, InlineFlowBox* = 0, const LayoutSize& = LayoutSize(), CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0);
+ virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance) const;
+
// Overridden by subclasses to determine line height and baseline position.
virtual LayoutUnit lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const = 0;
virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const = 0;
paintRect.setWidth(paintRect.width() - xOff);
paintRect.setX(paintRect.x() + xOff);
}
-
- paintBoxShadow(paintInfo, paintRect, style(), Normal);
+
+ if (!boxShadowShouldBeAppliedToBackground(determineBackgroundBleedAvoidance(paintInfo.context)))
+ paintBoxShadow(paintInfo, paintRect, style(), Normal);
paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect);
paintBoxShadow(paintInfo, paintRect, style(), Inset);
LayoutRect rect(paintOffset, size());
subtractCaptionRect(rect);
- paintBoxShadow(paintInfo, rect, style(), Normal);
+ if (!boxShadowShouldBeAppliedToBackground(determineBackgroundBleedAvoidance(paintInfo.context)))
+ paintBoxShadow(paintInfo, rect, style(), Normal);
paintBackground(paintInfo, rect);
paintBoxShadow(paintInfo, rect, style(), Inset);
paintMaskImages(paintInfo, LayoutRect(paintOffset, size()));
}
+bool RenderTableCell::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance) const
+{
+ return false;
+}
+
void RenderTableCell::scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged)
{
LayoutUnit scrollbarHeight = scrollbarLogicalHeight();
virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
virtual void paintMask(PaintInfo&, const LayoutPoint&);
+ virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance) const OVERRIDE;
+
virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&) const;
virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const;
virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect&, bool fixed = false) const;