blob: d9453378aa8f4b6474a5ab672c40fb621fcd6674 [file] [log] [blame]
// 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/BlockPainter.h"
#include "core/editing/Caret.h"
#include "core/editing/FrameSelection.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/page/Page.h"
#include "core/paint/BoxPainter.h"
#include "core/paint/DrawingRecorder.h"
#include "core/paint/InlinePainter.h"
#include "core/paint/LineBoxListPainter.h"
#include "core/rendering/GraphicsContextAnnotator.h"
#include "core/rendering/PaintInfo.h"
#include "core/rendering/RenderBlock.h"
#include "core/rendering/RenderBoxClipper.h"
#include "core/rendering/RenderFlexibleBox.h"
#include "core/rendering/RenderInline.h"
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderView.h"
#include "platform/geometry/LayoutPoint.h"
#include "platform/geometry/LayoutRect.h"
#include "platform/graphics/GraphicsContextCullSaver.h"
#include "platform/graphics/GraphicsContextStateSaver.h"
namespace blink {
void BlockPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderBlock);
LayoutPoint adjustedPaintOffset = paintOffset + m_renderBlock.location();
PaintPhase phase = paintInfo.phase;
LayoutRect overflowBox;
// Check if we need to do anything at all.
// FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView
// paints the root's background.
if (!m_renderBlock.isDocumentElement()) {
overflowBox = overflowRectForPaintRejection();
m_renderBlock.flipForWritingMode(overflowBox);
overflowBox.moveBy(adjustedPaintOffset);
if (!overflowBox.intersects(paintInfo.rect))
return;
}
// There are some cases where not all clipped visual overflow is accounted for.
// FIXME: reduce the number of such cases.
ContentsClipBehavior contentsClipBehavior = ForceContentsClip;
if (m_renderBlock.hasOverflowClip() && !m_renderBlock.hasControlClip() && !(m_renderBlock.shouldPaintSelectionGaps() && phase == PaintPhaseForeground) && !hasCaret())
contentsClipBehavior = SkipContentsClipIfPossible;
{
RenderBoxClipper boxClipper(m_renderBlock, paintInfo, adjustedPaintOffset, contentsClipBehavior);
GraphicsContextCullSaver cullSaver(*paintInfo.context);
// Cull if we have more than one child and we didn't already clip.
bool shouldCull = m_renderBlock.document().settings()->containerCullingEnabled() && !boxClipper.pushedClip() && !m_renderBlock.isDocumentElement()
&& m_renderBlock.firstChild() && m_renderBlock.lastChild() && m_renderBlock.firstChild() != m_renderBlock.lastChild();
if (shouldCull)
cullSaver.cull(overflowBox);
m_renderBlock.paintObject(paintInfo, adjustedPaintOffset);
}
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
// z-index. We paint after we painted the background/border, so that the scrollbars will
// sit above the background/border.
paintOverflowControlsIfNeeded(paintInfo, adjustedPaintOffset);
}
void BlockPainter::paintOverflowControlsIfNeeded(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
PaintPhase phase = paintInfo.phase;
if (m_renderBlock.hasOverflowClip() && m_renderBlock.style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(&m_renderBlock) && !paintInfo.paintRootBackgroundOnly()) {
DrawingRecorder recorder(paintInfo.context, &m_renderBlock, paintInfo.phase, pixelSnappedIntRect(paintOffset, m_renderBlock.visualOverflowRect().size()));
m_renderBlock.layer()->scrollableArea()->paintOverflowControls(paintInfo.context, roundedIntPoint(paintOffset), paintInfo.rect, false /* paintingOverlayControls */);
}
}
void BlockPainter::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
for (RenderBox* child = m_renderBlock.firstChildBox(); child; child = child->nextSiblingBox())
paintChild(child, paintInfo, paintOffset);
}
void BlockPainter::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
LayoutPoint childPoint = m_renderBlock.flipForWritingModeForChild(child, paintOffset);
if (!child->hasSelfPaintingLayer() && !child->isFloating())
child->paint(paintInfo, childPoint);
}
void BlockPainter::paintChildrenOfFlexibleBox(RenderFlexibleBox& renderFlexibleBox, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
for (RenderBox* child = renderFlexibleBox.orderIterator().first(); child; child = renderFlexibleBox.orderIterator().next())
BlockPainter(renderFlexibleBox).paintChildAsInlineBlock(child, paintInfo, paintOffset);
}
void BlockPainter::paintChildAsInlineBlock(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
LayoutPoint childPoint = m_renderBlock.flipForWritingModeForChild(child, paintOffset);
if (!child->hasSelfPaintingLayer() && !child->isFloating())
paintAsInlineBlock(child, paintInfo, childPoint);
}
void BlockPainter::paintInlineBox(InlineBox& inlineBox, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (!paintInfo.shouldPaintWithinRoot(&inlineBox.renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
return;
LayoutPoint childPoint = paintOffset;
if (inlineBox.parent()->renderer().style()->slowIsFlippedBlocksWritingMode()) // Faster than calling containingBlock().
childPoint = inlineBox.renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(inlineBox.renderer()), childPoint);
paintAsInlineBlock(&inlineBox.renderer(), paintInfo, childPoint);
}
void BlockPainter::paintAsInlineBlock(RenderObject* renderer, PaintInfo& paintInfo, const LayoutPoint& childPoint)
{
if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)
return;
// Paint all phases atomically, as though the element established its own
// stacking context. (See Appendix E.2, section 7.2.1.4 on
// inline block/table/replaced elements in the CSS2.1 specification.)
// This is also used by other elements (e.g. flex items and grid items).
bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
PaintInfo info(paintInfo);
info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
renderer->paint(info, childPoint);
if (!preservePhase) {
info.phase = PaintPhaseChildBlockBackgrounds;
renderer->paint(info, childPoint);
info.phase = PaintPhaseFloat;
renderer->paint(info, childPoint);
info.phase = PaintPhaseForeground;
renderer->paint(info, childPoint);
info.phase = PaintPhaseOutline;
renderer->paint(info, childPoint);
}
}
void BlockPainter::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
PaintPhase paintPhase = paintInfo.phase;
// Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
LayoutPoint scrolledOffset = paintOffset;
if (m_renderBlock.hasOverflowClip())
scrolledOffset.move(-m_renderBlock.scrolledContentOffset());
LayoutRect bounds;
if (RuntimeEnabledFeatures::slimmingPaintEnabled()) {
bounds = m_renderBlock.visualOverflowRect();
bounds.moveBy(scrolledOffset);
}
// 1. paint background, borders etc
if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && m_renderBlock.style()->visibility() == VISIBLE) {
if (m_renderBlock.hasBoxDecorationBackground())
m_renderBlock.paintBoxDecorationBackground(paintInfo, paintOffset);
if (m_renderBlock.hasColumns() && !paintInfo.paintRootBackgroundOnly())
paintColumnRules(paintInfo, scrolledOffset);
}
if (paintPhase == PaintPhaseMask && m_renderBlock.style()->visibility() == VISIBLE) {
DrawingRecorder recorder(paintInfo.context, &m_renderBlock, paintPhase, bounds);
m_renderBlock.paintMask(paintInfo, paintOffset);
return;
}
if (paintPhase == PaintPhaseClippingMask && m_renderBlock.style()->visibility() == VISIBLE) {
DrawingRecorder recorder(paintInfo.context, &m_renderBlock, paintPhase, bounds);
m_renderBlock.paintClippingMask(paintInfo, paintOffset);
return;
}
// We're done. We don't bother painting any children.
if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
return;
// 2. paint contents
if (paintPhase != PaintPhaseSelfOutline) {
if (m_renderBlock.hasColumns())
paintColumnContents(paintInfo, scrolledOffset);
else
paintContents(paintInfo, scrolledOffset);
}
// 3. paint selection
// FIXME: Make this work with multi column layouts. For now don't fill gaps.
bool isPrinting = m_renderBlock.document().printing();
if (!isPrinting && !m_renderBlock.hasColumns())
paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
// 4. paint floats.
if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
if (m_renderBlock.hasColumns())
paintColumnContents(paintInfo, scrolledOffset, true);
else
m_renderBlock.paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
}
// 5. paint outline.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && m_renderBlock.style()->hasOutline() && m_renderBlock.style()->visibility() == VISIBLE) {
// Don't paint focus ring for anonymous block continuation because the
// inline element having outline-style:auto paints the whole focus ring.
if (!m_renderBlock.style()->outlineStyleIsAuto() || !m_renderBlock.isAnonymousBlockContinuation())
m_renderBlock.paintOutline(paintInfo, LayoutRect(paintOffset, m_renderBlock.size()));
}
// 6. paint continuation outlines.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines))
paintContinuationOutlines(paintInfo, paintOffset);
// 7. paint caret.
// If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
// then paint the caret.
if (paintPhase == PaintPhaseForeground) {
DrawingRecorder recorder(paintInfo.context, &m_renderBlock, paintPhase, bounds);
paintCarets(paintInfo, paintOffset);
}
}
static inline bool caretBrowsingEnabled(const Frame* frame)
{
Settings* settings = frame->settings();
return settings && settings->caretBrowsingEnabled();
}
static inline bool hasCursorCaret(const FrameSelection& selection, const RenderBlock* block, bool caretBrowsing)
{
return selection.caretRenderer() == block && (selection.hasEditableStyle() || caretBrowsing);
}
static inline bool hasDragCaret(const DragCaretController& dragCaretController, const RenderBlock* block, bool caretBrowsing)
{
return dragCaretController.caretRenderer() == block && (dragCaretController.isContentEditable() || caretBrowsing);
}
void BlockPainter::paintCarets(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
bool caretBrowsing = caretBrowsingEnabled(m_renderBlock.frame());
FrameSelection& selection = m_renderBlock.frame()->selection();
if (hasCursorCaret(selection, &m_renderBlock, caretBrowsing)) {
selection.paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
}
DragCaretController& dragCaretController = m_renderBlock.frame()->page()->dragCaretController();
if (hasDragCaret(dragCaretController, &m_renderBlock, caretBrowsing)) {
dragCaretController.paintDragCaret(m_renderBlock.frame(), paintInfo.context, paintOffset, paintInfo.rect);
}
}
LayoutRect BlockPainter::overflowRectForPaintRejection() const
{
LayoutRect overflowRect = m_renderBlock.visualOverflowRect();
if (!m_renderBlock.hasRenderOverflow() || !m_renderBlock.usesCompositedScrolling())
return overflowRect;
overflowRect.unite(m_renderBlock.layoutOverflowRect());
overflowRect.move(-m_renderBlock.scrolledContentOffset());
return overflowRect;
}
bool BlockPainter::hasCaret() const
{
bool caretBrowsing = caretBrowsingEnabled(m_renderBlock.frame());
return hasCursorCaret(m_renderBlock.frame()->selection(), &m_renderBlock, caretBrowsing)
|| hasDragCaret(m_renderBlock.frame()->page()->dragCaretController(), &m_renderBlock, caretBrowsing);
}
void BlockPainter::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
const Color& ruleColor = m_renderBlock.resolveColor(CSSPropertyWebkitColumnRuleColor);
bool ruleTransparent = m_renderBlock.style()->columnRuleIsTransparent();
EBorderStyle ruleStyle = m_renderBlock.style()->columnRuleStyle();
LayoutUnit ruleThickness = m_renderBlock.style()->columnRuleWidth();
LayoutUnit colGap = m_renderBlock.columnGap();
bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
if (!renderRule)
return;
ColumnInfo* colInfo = m_renderBlock.columnInfo();
unsigned colCount = m_renderBlock.columnCount(colInfo);
bool antialias = BoxPainter::shouldAntialiasLines(paintInfo.context);
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
bool leftToRight = m_renderBlock.style()->isLeftToRightDirection();
LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : m_renderBlock.contentLogicalWidth();
LayoutUnit ruleAdd = m_renderBlock.logicalLeftOffsetForContent();
LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : m_renderBlock.contentLogicalWidth();
LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
BoxSide boxSide = m_renderBlock.isHorizontalWritingMode()
? leftToRight ? BSLeft : BSRight
: leftToRight ? BSTop : BSBottom;
for (unsigned i = 0; i < colCount; i++) {
// Move to the next position.
if (leftToRight) {
ruleLogicalLeft += inlineDirectionSize + colGap / 2;
currLogicalLeftOffset += inlineDirectionSize + colGap;
} else {
ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
currLogicalLeftOffset -= (inlineDirectionSize + colGap);
}
// Now paint the column rule.
if (i < colCount - 1) {
LayoutUnit ruleLeft = m_renderBlock.isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + m_renderBlock.borderLeft() + m_renderBlock.paddingLeft();
LayoutUnit ruleRight = m_renderBlock.isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + m_renderBlock.contentWidth();
LayoutUnit ruleTop = m_renderBlock.isHorizontalWritingMode() ? paintOffset.y() + m_renderBlock.borderTop() + m_renderBlock.paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
LayoutUnit ruleBottom = m_renderBlock.isHorizontalWritingMode() ? ruleTop + m_renderBlock.contentHeight() : ruleTop + ruleThickness;
IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
ObjectPainter::drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
}
ruleLogicalLeft = currLogicalLeftOffset;
}
} else {
bool topToBottom = !m_renderBlock.style()->slowIsFlippedBlocksWritingMode();
LayoutUnit ruleLeft = m_renderBlock.isHorizontalWritingMode()
? m_renderBlock.borderLeft() + m_renderBlock.paddingLeft()
: colGap / 2 - colGap - ruleThickness / 2 + m_renderBlock.borderBefore() + m_renderBlock.paddingBefore();
LayoutUnit ruleWidth = m_renderBlock.isHorizontalWritingMode() ? m_renderBlock.contentWidth() : ruleThickness;
LayoutUnit ruleTop = m_renderBlock.isHorizontalWritingMode()
? colGap / 2 - colGap - ruleThickness / 2 + m_renderBlock.borderBefore() + m_renderBlock.paddingBefore()
: m_renderBlock.borderStart() + m_renderBlock.paddingStart();
LayoutUnit ruleHeight = m_renderBlock.isHorizontalWritingMode() ? ruleThickness : m_renderBlock.contentHeight();
LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
if (!topToBottom) {
if (m_renderBlock.isHorizontalWritingMode())
ruleRect.setY(m_renderBlock.height() - ruleRect.maxY());
else
ruleRect.setX(m_renderBlock.width() - ruleRect.maxX());
}
ruleRect.moveBy(paintOffset);
BoxSide boxSide = m_renderBlock.isHorizontalWritingMode()
? topToBottom ? BSTop : BSBottom
: topToBottom ? BSLeft : BSRight;
LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
if (!m_renderBlock.isHorizontalWritingMode())
step = step.transposedSize();
for (unsigned i = 1; i < colCount; i++) {
ruleRect.move(step);
IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
ObjectPainter::drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
}
}
}
void BlockPainter::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
{
// We need to do multiple passes, breaking up our child painting into strips.
GraphicsContext* context = paintInfo.context;
ColumnInfo* colInfo = m_renderBlock.columnInfo();
unsigned colCount = m_renderBlock.columnCount(colInfo);
if (!colCount)
return;
LayoutUnit currLogicalTopOffset = 0;
LayoutUnit colGap = m_renderBlock.columnGap();
for (unsigned i = 0; i < colCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
LayoutRect colRect = m_renderBlock.columnRectAt(colInfo, i);
m_renderBlock.flipForWritingMode(colRect);
LayoutUnit logicalLeftOffset = (m_renderBlock.isHorizontalWritingMode() ? colRect.x() : colRect.y()) - m_renderBlock.logicalLeftOffsetForContent();
LayoutSize offset = m_renderBlock.isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
if (m_renderBlock.isHorizontalWritingMode())
offset.expand(0, colRect.y() - m_renderBlock.borderTop() - m_renderBlock.paddingTop());
else
offset.expand(colRect.x() - m_renderBlock.borderLeft() - m_renderBlock.paddingLeft(), 0);
}
colRect.moveBy(paintOffset);
PaintInfo info(paintInfo);
info.rect.intersect(enclosingIntRect(colRect));
if (!info.rect.isEmpty()) {
GraphicsContextStateSaver stateSaver(*context);
LayoutRect clipRect(colRect);
if (i < colCount - 1) {
if (m_renderBlock.isHorizontalWritingMode())
clipRect.expand(colGap / 2, 0);
else
clipRect.expand(0, colGap / 2);
}
// Each strip pushes a clip, since column boxes are specified as being
// like overflow:hidden.
// FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
// are clipped according to the 'overflow' property.
context->clip(enclosingIntRect(clipRect));
// Adjust our x and y when painting.
LayoutPoint adjustedPaintOffset = paintOffset + offset;
if (paintingFloats)
m_renderBlock.paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
else
paintContents(info, adjustedPaintOffset);
}
LayoutUnit blockDelta = (m_renderBlock.isHorizontalWritingMode() ? colRect.height() : colRect.width());
if (m_renderBlock.style()->slowIsFlippedBlocksWritingMode())
currLogicalTopOffset += blockDelta;
else
currLogicalTopOffset -= blockDelta;
}
}
void BlockPainter::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
// Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
// It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
// will do a full paint invalidation.
if (m_renderBlock.document().didLayoutWithPendingStylesheets() && !m_renderBlock.isRenderView())
return;
if (m_renderBlock.childrenInline()) {
LineBoxListPainter(*m_renderBlock.lineBoxes()).paint(&m_renderBlock, paintInfo, paintOffset);
} else {
PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
// We don't paint our own background, but we do let the kids paint their backgrounds.
PaintInfo paintInfoForChild(paintInfo);
paintInfoForChild.phase = newPhase;
paintInfoForChild.updatePaintingRootForChildren(&m_renderBlock);
m_renderBlock.paintChildren(paintInfoForChild, paintOffset);
}
}
void BlockPainter::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (m_renderBlock.shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
LayoutUnit lastTop = 0;
LayoutUnit lastLeft = m_renderBlock.logicalLeftSelectionOffset(&m_renderBlock, lastTop);
LayoutUnit lastRight = m_renderBlock.logicalRightSelectionOffset(&m_renderBlock, lastTop);
GraphicsContextStateSaver stateSaver(*paintInfo.context);
LayoutRect gapRectsBounds = m_renderBlock.selectionGaps(&m_renderBlock, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
if (!gapRectsBounds.isEmpty()) {
RenderLayer* layer = m_renderBlock.enclosingLayer();
gapRectsBounds.moveBy(-paintOffset);
if (!m_renderBlock.hasLayer()) {
LayoutRect localBounds(gapRectsBounds);
m_renderBlock.flipForWritingMode(localBounds);
gapRectsBounds = m_renderBlock.localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
if (layer->renderer()->hasOverflowClip())
gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
}
layer->addBlockSelectionGapsBounds(gapRectsBounds);
}
}
}
void BlockPainter::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
{
RenderInline* inlineCont = m_renderBlock.inlineElementContinuation();
if (inlineCont && inlineCont->style()->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
RenderBlock* cb = m_renderBlock.containingBlock();
bool inlineEnclosedInSelfPaintingLayer = false;
for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
if (box->hasSelfPaintingLayer()) {
inlineEnclosedInSelfPaintingLayer = true;
break;
}
}
// Do not add continuations for outline painting by our containing block if we are a relative positioned
// anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on renderers in its continuation table being
// in the same layer.
if (!inlineEnclosedInSelfPaintingLayer && !m_renderBlock.hasLayer())
cb->addContinuationWithOutline(inlineRenderer);
else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && m_renderBlock.hasLayer()))
InlinePainter(*inlineRenderer).paintOutline(info, paintOffset - m_renderBlock.locationOffset() + inlineRenderer->containingBlock()->location());
}
ContinuationOutlineTableMap* table = continuationOutlineTable();
if (table->isEmpty())
return;
OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(&m_renderBlock);
if (!continuations)
return;
LayoutPoint accumulatedPaintOffset = paintOffset;
// Paint each continuation outline.
ListHashSet<RenderInline*>::iterator end = continuations->end();
for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
// Need to add in the coordinates of the intervening blocks.
RenderInline* flow = *it;
RenderBlock* block = flow->containingBlock();
for ( ; block && block != &m_renderBlock; block = block->containingBlock())
accumulatedPaintOffset.moveBy(block->location());
ASSERT(block);
InlinePainter(*flow).paintOutline(info, accumulatedPaintOffset);
}
}
} // namespace blink