Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1013)

Unified Diff: Source/core/paint/BoxPainter.cpp

Issue 550363004: Factor painting code out of RenderBox into a new class called BoxPainter. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | Source/core/rendering/RenderBox.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/paint/BoxPainter.cpp
diff --git a/Source/core/paint/BoxPainter.cpp b/Source/core/paint/BoxPainter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..684e70fba3c259d815c22e3b588e37f092ba9a78
--- /dev/null
+++ b/Source/core/paint/BoxPainter.cpp
@@ -0,0 +1,241 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/paint/BoxPainter.h"
+
+#include "core/paint/BoxDecorationData.h"
+#include "core/rendering/PaintInfo.h"
+#include "core/rendering/RenderBox.h"
+#include "core/rendering/RenderLayer.h"
+#include "core/rendering/RenderTable.h"
+#include "core/rendering/RenderTheme.h"
+#include "core/rendering/RenderView.h"
+#include "platform/geometry/LayoutPoint.h"
+#include "platform/graphics/GraphicsContextStateSaver.h"
+
+namespace blink {
+
+void BoxPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+ LayoutPoint adjustedPaintOffset = paintOffset + m_renderBox.location();
+ // default implementation. Just pass paint through to the children
+ PaintInfo childInfo(paintInfo);
+ childInfo.updatePaintingRootForChildren(&m_renderBox);
+ for (RenderObject* child = m_renderBox.slowFirstChild(); child; child = child->nextSibling())
+ child->paint(childInfo, adjustedPaintOffset);
+}
+
+void BoxPainter::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+ if (!paintInfo.shouldPaintWithinRoot(&m_renderBox))
+ return;
+
+ LayoutRect paintRect = m_renderBox.borderBoxRect();
+ paintRect.moveBy(paintOffset);
+ paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect);
+}
+
+void BoxPainter::paintBoxDecorationBackgroundWithRect(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& paintRect)
+{
+ RenderStyle* style = m_renderBox.style();
+ BoxDecorationData boxDecorationData(*style, m_renderBox.canRenderBorderImage(), m_renderBox.backgroundHasOpaqueTopLayer(), 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.
+ if (!m_renderBox.boxShadowShouldBeAppliedToBackground(boxDecorationData.bleedAvoidance()))
+ m_renderBox.paintBoxShadow(paintInfo, paintRect, style, Normal);
+
+ GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
+ if (boxDecorationData.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(&m_renderBox, paintInfo, snappedPaintRect);
+ if (!themePainted) {
+ if (boxDecorationData.bleedAvoidance() == BackgroundBleedBackgroundOverBorder)
+ m_renderBox.paintBorder(paintInfo, paintRect, style, boxDecorationData.bleedAvoidance());
+
+ paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, boxDecorationData.bleedAvoidance());
+
+ if (boxDecorationData.hasAppearance)
+ RenderTheme::theme().paintDecorations(&m_renderBox, paintInfo, snappedPaintRect);
+ }
+ m_renderBox.paintBoxShadow(paintInfo, paintRect, style, Inset);
+
+ // The theme will tell us whether or not we should also paint the CSS border.
+ if (boxDecorationData.hasBorder && boxDecorationData.bleedAvoidance() != BackgroundBleedBackgroundOverBorder
+ && (!boxDecorationData.hasAppearance || (!themePainted && RenderTheme::theme().paintBorderOnly(&m_renderBox, paintInfo, snappedPaintRect)))
+ && !(m_renderBox.isTable() && toRenderTable(&m_renderBox)->collapseBorders()))
+ m_renderBox.paintBorder(paintInfo, paintRect, style, boxDecorationData.bleedAvoidance());
+}
+
+static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
+{
+ ASSERT(bodyElementRenderer->isBody());
+ // The <body> only paints its background if the root element has defined a background independent of the body,
+ // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
+ RenderObject* documentElementRenderer = bodyElementRenderer->document().documentElement()->renderer();
+ return documentElementRenderer
+ && !documentElementRenderer->hasBackground()
+ && (documentElementRenderer == bodyElementRenderer->parent());
+}
+
+void BoxPainter::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance)
+{
+ if (m_renderBox.isDocumentElement()) {
+ paintRootBoxFillLayers(paintInfo);
+ return;
+ }
+ if (m_renderBox.isBody() && skipBodyBackground(&m_renderBox))
+ return;
+ if (m_renderBox.boxDecorationBackgroundIsKnownToBeObscured())
+ return;
+ paintFillLayers(paintInfo, backgroundColor, m_renderBox.style()->backgroundLayers(), paintRect, bleedAvoidance);
+}
+
+void BoxPainter::paintRootBoxFillLayers(const PaintInfo& paintInfo)
+{
+ if (paintInfo.skipRootBackground())
+ return;
+
+ RenderObject* rootBackgroundRenderer = m_renderBox.rendererForRootBackground();
+
+ const FillLayer& bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
+ Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundColor);
+
+ paintFillLayers(paintInfo, bgColor, bgLayer, m_renderBox.view()->backgroundRect(&m_renderBox), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
+}
+
+void BoxPainter::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(&m_renderBox)
+ && curLayer->image()->canRender(m_renderBox, m_renderBox.style()->effectiveZoom())
+ && curLayer->hasRepeatXY()
+ && curLayer->blendMode() == WebBlendModeNormal
+ && !m_renderBox.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 && m_renderBox.isDocumentElementWithOpaqueBackground()) {
+ m_renderBox.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 BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect,
+ BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseColor)
+{
+ m_renderBox.paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject, skipBaseColor);
+}
+
+void BoxPainter::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+ if (!paintInfo.shouldPaintWithinRoot(&m_renderBox) || m_renderBox.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
+ return;
+
+ LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size());
+ paintMaskImages(paintInfo, paintRect);
+}
+
+void BoxPainter::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 = m_renderBox.hasLayer() && m_renderBox.layer()->hasCompositedMask();
+ bool flattenCompositingLayers = m_renderBox.view()->frameView() && m_renderBox.view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
+ CompositeOperator compositeOp = CompositeSourceOver;
+
+ bool allMaskImagesLoaded = true;
+
+ if (!compositedMask || flattenCompositingLayers) {
+ pushTransparencyLayer = true;
+ StyleImage* maskBoxImage = m_renderBox.style()->maskBoxImage().image();
+ const FillLayer& maskLayers = m_renderBox.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, m_renderBox.style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
+ m_renderBox.paintNinePieceImage(paintInfo.context, paintRect, m_renderBox.style(), m_renderBox.style()->maskBoxImage(), compositeOp);
+ }
+
+ if (pushTransparencyLayer)
+ paintInfo.context->endLayer();
+}
+
+void BoxPainter::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+ if (!paintInfo.shouldPaintWithinRoot(&m_renderBox) || m_renderBox.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseClippingMask)
+ return;
+
+ if (!m_renderBox.layer() || m_renderBox.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(m_renderBox.layer()->compositingState() != HasOwnBackingButPaintsIntoAncestor);
+
+ LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size());
+ paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black);
+}
+
+} // namespace blink
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | Source/core/rendering/RenderBox.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698