Index: Source/core/rendering/RenderBox.cpp |
diff --git a/Source/core/rendering/RenderBox.cpp b/Source/core/rendering/RenderBox.cpp |
index b806e2cf2df5a3e0ef3cacef92aae2d3646e6ae2..7fafa29ea302ac3326f9d2db3e4c2a0254b92f57 100644 |
--- a/Source/core/rendering/RenderBox.cpp |
+++ b/Source/core/rendering/RenderBox.cpp |
@@ -40,6 +40,7 @@ |
#include "core/page/AutoscrollController.h" |
#include "core/page/EventHandler.h" |
#include "core/page/Page.h" |
+#include "core/paint/BoxPainter.h" |
#include "core/rendering/HitTestResult.h" |
#include "core/rendering/PaintInfo.h" |
#include "core/rendering/RenderDeprecatedFlexibleBox.h" |
@@ -51,13 +52,11 @@ |
#include "core/rendering/RenderListBox.h" |
#include "core/rendering/RenderListMarker.h" |
#include "core/rendering/RenderTableCell.h" |
-#include "core/rendering/RenderTheme.h" |
#include "core/rendering/RenderView.h" |
#include "core/rendering/compositing/RenderLayerCompositor.h" |
#include "platform/LengthFunctions.h" |
#include "platform/geometry/FloatQuad.h" |
#include "platform/geometry/TransformState.h" |
-#include "platform/graphics/GraphicsContextStateSaver.h" |
#include <algorithm> |
#include <math.h> |
@@ -1076,123 +1075,17 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result |
return false; |
} |
-// --------------------- painting stuff ------------------------------- |
- |
void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) |
{ |
- LayoutPoint adjustedPaintOffset = paintOffset + location(); |
- // default implementation. Just pass paint through to the children |
- PaintInfo childInfo(paintInfo); |
- childInfo.updatePaintingRootForChildren(this); |
- for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) |
- child->paint(childInfo, adjustedPaintOffset); |
-} |
- |
-void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo) |
-{ |
- if (paintInfo.skipRootBackground()) |
- return; |
- |
- RenderObject* rootBackgroundRenderer = rendererForRootBackground(); |
- |
- const FillLayer& bgLayer = rootBackgroundRenderer->style()->backgroundLayers(); |
- Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundColor); |
- |
- paintFillLayers(paintInfo, bgColor, bgLayer, view()->backgroundRect(this), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer); |
+ BoxPainter(*this).paint(paintInfo, paintOffset); |
} |
-BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext* context, const BoxDecorationData& boxDecorationData) const |
-{ |
- if (!boxDecorationData.hasBackground || !boxDecorationData.hasBorder || !style()->hasBorderRadius() || canRenderBorderImage()) |
- return BackgroundBleedNone; |
- |
- // FIXME: See crbug.com/382491. getCTM does not accurately reflect the scale at the time content is |
- // rasterized, and should not be relied on to make decisions about bleeding. |
- AffineTransform ctm = context->getCTM(); |
- FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale())); |
- |
- // Because RoundedRect uses IntRect internally the inset applied by the |
- // BackgroundBleedShrinkBackground strategy cannot be less than one integer |
- // layout coordinate, even with subpixel layout enabled. To take that into |
- // account, we clamp the contextScaling to 1.0 for the following test so |
- // that borderObscuresBackgroundEdge can only return true if the border |
- // widths are greater than 2 in both layout coordinates and screen |
- // coordinates. |
- // This precaution will become obsolete if RoundedRect is ever promoted to |
- // a sub-pixel representation. |
- if (contextScaling.width() > 1) |
- contextScaling.setWidth(1); |
- if (contextScaling.height() > 1) |
- contextScaling.setHeight(1); |
- |
- if (borderObscuresBackgroundEdge(contextScaling)) |
- return BackgroundBleedShrinkBackground; |
- if (!boxDecorationData.hasAppearance && borderObscuresBackground() && backgroundHasOpaqueTopLayer()) |
- return BackgroundBleedBackgroundOverBorder; |
- |
- return BackgroundBleedClipBackground; |
-} |
void RenderBox::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset) |
{ |
- if (!paintInfo.shouldPaintWithinRoot(this)) |
- return; |
- |
- LayoutRect paintRect = borderBoxRect(); |
- paintRect.moveBy(paintOffset); |
- paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect); |
+ BoxPainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset); |
} |
-void RenderBox::paintBoxDecorationBackgroundWithRect(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& paintRect) |
-{ |
- RenderStyle* style = this->style(); |
- BoxDecorationData boxDecorationData(*style); |
- BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context, boxDecorationData); |
- |
- // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have |
- // custom shadows of their own. |
- if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance)) |
- paintBoxShadow(paintInfo, paintRect, style, Normal); |
- |
- GraphicsContextStateSaver stateSaver(*paintInfo.context, false); |
- if (bleedAvoidance == BackgroundBleedClipBackground) { |
- stateSaver.save(); |
- RoundedRect border = style->getRoundedBorderFor(paintRect); |
- paintInfo.context->clipRoundedRect(border); |
- } |
- |
- // If we have a native theme appearance, paint that before painting our background. |
- // The theme will tell us whether or not we should also paint the CSS background. |
- IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); |
- bool themePainted = boxDecorationData.hasAppearance && !RenderTheme::theme().paint(this, paintInfo, snappedPaintRect); |
- if (!themePainted) { |
- if (bleedAvoidance == BackgroundBleedBackgroundOverBorder) |
- paintBorder(paintInfo, paintRect, style, bleedAvoidance); |
- |
- paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, bleedAvoidance); |
- |
- if (boxDecorationData.hasAppearance) |
- RenderTheme::theme().paintDecorations(this, paintInfo, snappedPaintRect); |
- } |
- paintBoxShadow(paintInfo, paintRect, style, Inset); |
- |
- // The theme will tell us whether or not we should also paint the CSS border. |
- if (boxDecorationData.hasBorder && bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!boxDecorationData.hasAppearance || (!themePainted && RenderTheme::theme().paintBorderOnly(this, paintInfo, snappedPaintRect))) && !(isTable() && toRenderTable(this)->collapseBorders())) |
- paintBorder(paintInfo, paintRect, style, bleedAvoidance); |
-} |
- |
-void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance) |
-{ |
- if (isDocumentElement()) { |
- paintRootBoxFillLayers(paintInfo); |
- return; |
- } |
- if (isBody() && skipBodyBackground(this)) |
- return; |
- if (boxDecorationBackgroundIsKnownToBeObscured()) |
- return; |
- paintFillLayers(paintInfo, backgroundColor, style()->backgroundLayers(), paintRect, bleedAvoidance); |
-} |
bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const |
{ |
@@ -1356,122 +1249,12 @@ bool RenderBox::backgroundHasOpaqueTopLayer() const |
void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) |
{ |
- if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) |
- return; |
- |
- LayoutRect paintRect = LayoutRect(paintOffset, size()); |
- paintMaskImages(paintInfo, paintRect); |
+ BoxPainter(*this).paintMask(paintInfo, paintOffset); |
} |
void RenderBox::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) |
{ |
- if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseClippingMask) |
- return; |
- |
- if (!layer() || layer()->compositingState() != PaintsIntoOwnBacking) |
- return; |
- |
- // We should never have this state in this function. A layer with a mask |
- // should have always created its own backing if it became composited. |
- ASSERT(layer()->compositingState() != HasOwnBackingButPaintsIntoAncestor); |
- |
- LayoutRect paintRect = LayoutRect(paintOffset, size()); |
- paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black); |
-} |
- |
-void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect) |
-{ |
- // Figure out if we need to push a transparency layer to render our mask. |
- bool pushTransparencyLayer = false; |
- bool compositedMask = hasLayer() && layer()->hasCompositedMask(); |
- bool flattenCompositingLayers = view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers; |
- CompositeOperator compositeOp = CompositeSourceOver; |
- |
- bool allMaskImagesLoaded = true; |
- |
- if (!compositedMask || flattenCompositingLayers) { |
- pushTransparencyLayer = true; |
- StyleImage* maskBoxImage = style()->maskBoxImage().image(); |
- const FillLayer& maskLayers = style()->maskLayers(); |
- |
- // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content. |
- if (maskBoxImage) |
- allMaskImagesLoaded &= maskBoxImage->isLoaded(); |
- |
- allMaskImagesLoaded &= maskLayers.imagesAreLoaded(); |
- |
- paintInfo.context->setCompositeOperation(CompositeDestinationIn); |
- paintInfo.context->beginTransparencyLayer(1); |
- compositeOp = CompositeSourceOver; |
- } |
- |
- if (allMaskImagesLoaded) { |
- paintFillLayers(paintInfo, Color::transparent, style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp); |
- paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp); |
- } |
- |
- if (pushTransparencyLayer) |
- paintInfo.context->endLayer(); |
-} |
- |
-void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect, |
- BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject) |
-{ |
- Vector<const FillLayer*, 8> layers; |
- const FillLayer* curLayer = &fillLayer; |
- bool shouldDrawBackgroundInSeparateBuffer = false; |
- bool isBottomLayerOccluded = false; |
- while (curLayer) { |
- layers.append(curLayer); |
- // Stop traversal when an opaque layer is encountered. |
- // FIXME : It would be possible for the following occlusion culling test to be more aggressive |
- // on layers with no repeat by testing whether the image covers the layout rect. |
- // Testing that here would imply duplicating a lot of calculations that are currently done in |
- // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move |
- // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here |
- // and pass it down. |
- |
- if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != WebBlendModeNormal) |
- shouldDrawBackgroundInSeparateBuffer = true; |
- |
- // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting. |
- if (curLayer->clipOccludesNextLayers(curLayer == &fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(*this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == WebBlendModeNormal && !boxShadowShouldBeAppliedToBackground(bleedAvoidance)) |
- break; |
- curLayer = curLayer->next(); |
- } |
- |
- if (layers.size() > 0 && (**layers.rbegin()).next()) |
- isBottomLayerOccluded = true; |
- |
- GraphicsContext* context = paintInfo.context; |
- if (!context) |
- shouldDrawBackgroundInSeparateBuffer = false; |
- |
- bool skipBaseColor = false; |
- if (shouldDrawBackgroundInSeparateBuffer) { |
- bool isBaseColorVisible = !isBottomLayerOccluded && c.hasAlpha(); |
- |
- // Paint the document's base background color outside the transparency layer, |
- // so that the background images don't blend with this color: http://crbug.com/389039. |
- if (isBaseColorVisible && isDocumentElementWithOpaqueBackground()) { |
- paintRootBackgroundColor(paintInfo, rect, Color()); |
- skipBaseColor = true; |
- } |
- context->beginTransparencyLayer(1); |
- } |
- |
- Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend(); |
- for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it) |
- paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundObject, skipBaseColor); |
- |
- if (shouldDrawBackgroundInSeparateBuffer) |
- context->endLayer(); |
-} |
- |
-void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect, |
- BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseColor) |
-{ |
- paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject, skipBaseColor); |
+ BoxPainter(*this).paintClippingMask(paintInfo, paintOffset); |
} |
void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) |
@@ -4743,13 +4526,4 @@ LayoutSize RenderBox::computePreviousBorderBoxSize(const LayoutSize& previousBou |
return previousBoundsSize; |
} |
-RenderBox::BoxDecorationData::BoxDecorationData(const RenderStyle& style) |
-{ |
- backgroundColor = style.visitedDependentColor(CSSPropertyBackgroundColor); |
- hasBackground = backgroundColor.alpha() || style.hasBackgroundImage(); |
- ASSERT(hasBackground == style.hasBackground()); |
- hasBorder = style.hasBorder(); |
- hasAppearance = style.hasAppearance(); |
-} |
- |
} // namespace blink |