Home | History | Annotate | Download | only in paint
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/paint/BlockPainter.h"
      7 
      8 #include "core/editing/Caret.h"
      9 #include "core/editing/FrameSelection.h"
     10 #include "core/frame/LocalFrame.h"
     11 #include "core/frame/Settings.h"
     12 #include "core/page/Page.h"
     13 #include "core/paint/BoxPainter.h"
     14 #include "core/paint/InlinePainter.h"
     15 #include "core/paint/LineBoxListPainter.h"
     16 #include "core/rendering/GraphicsContextAnnotator.h"
     17 #include "core/rendering/PaintInfo.h"
     18 #include "core/rendering/RenderBlock.h"
     19 #include "core/rendering/RenderFlexibleBox.h"
     20 #include "core/rendering/RenderInline.h"
     21 #include "core/rendering/RenderLayer.h"
     22 #include "platform/geometry/LayoutPoint.h"
     23 #include "platform/geometry/LayoutRect.h"
     24 #include "platform/graphics/GraphicsContextCullSaver.h"
     25 #include "platform/graphics/GraphicsContextStateSaver.h"
     26 
     27 namespace blink {
     28 
     29 void BlockPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
     30 {
     31     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderBlock);
     32 
     33     LayoutPoint adjustedPaintOffset = paintOffset + m_renderBlock.location();
     34 
     35     PaintPhase phase = paintInfo.phase;
     36 
     37     LayoutRect overflowBox;
     38     // Check if we need to do anything at all.
     39     // FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView
     40     // paints the root's background.
     41     if (!m_renderBlock.isDocumentElement()) {
     42         overflowBox = overflowRectForPaintRejection();
     43         m_renderBlock.flipForWritingMode(overflowBox);
     44         overflowBox.moveBy(adjustedPaintOffset);
     45         if (!overflowBox.intersects(paintInfo.rect))
     46             return;
     47     }
     48 
     49     // There are some cases where not all clipped visual overflow is accounted for.
     50     // FIXME: reduce the number of such cases.
     51     ContentsClipBehavior contentsClipBehavior = ForceContentsClip;
     52     if (m_renderBlock.hasOverflowClip() && !m_renderBlock.hasControlClip() && !(m_renderBlock.shouldPaintSelectionGaps() && phase == PaintPhaseForeground) && !hasCaret())
     53         contentsClipBehavior = SkipContentsClipIfPossible;
     54 
     55     bool pushedClip = m_renderBlock.pushContentsClip(paintInfo, adjustedPaintOffset, contentsClipBehavior);
     56     {
     57         GraphicsContextCullSaver cullSaver(*paintInfo.context);
     58         // Cull if we have more than one child and we didn't already clip.
     59         bool shouldCull = m_renderBlock.document().settings()->containerCullingEnabled() && !pushedClip && !m_renderBlock.isDocumentElement()
     60             && m_renderBlock.firstChild() && m_renderBlock.lastChild() && m_renderBlock.firstChild() != m_renderBlock.lastChild();
     61         if (shouldCull)
     62             cullSaver.cull(overflowBox);
     63 
     64         m_renderBlock.paintObject(paintInfo, adjustedPaintOffset);
     65     }
     66     // FIXME: move popContentsClip out of RenderBox.
     67     if (pushedClip)
     68         m_renderBlock.popContentsClip(paintInfo, phase, adjustedPaintOffset);
     69 
     70     // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
     71     // z-index. We paint after we painted the background/border, so that the scrollbars will
     72     // sit above the background/border.
     73     if (m_renderBlock.hasOverflowClip() && m_renderBlock.style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(&m_renderBlock) && !paintInfo.paintRootBackgroundOnly())
     74         m_renderBlock.layer()->scrollableArea()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect, false /* paintingOverlayControls */);
     75 }
     76 
     77 void BlockPainter::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
     78 {
     79     for (RenderBox* child = m_renderBlock.firstChildBox(); child; child = child->nextSiblingBox())
     80         paintChild(child, paintInfo, paintOffset);
     81 }
     82 
     83 void BlockPainter::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
     84 {
     85     LayoutPoint childPoint = m_renderBlock.flipForWritingModeForChild(child, paintOffset);
     86     if (!child->hasSelfPaintingLayer() && !child->isFloating())
     87         child->paint(paintInfo, childPoint);
     88 }
     89 
     90 void BlockPainter::paintChildrenOfFlexibleBox(RenderFlexibleBox& renderFlexibleBox, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
     91 {
     92     for (RenderBox* child = renderFlexibleBox.orderIterator().first(); child; child = renderFlexibleBox.orderIterator().next())
     93         BlockPainter(renderFlexibleBox).paintChildAsInlineBlock(child, paintInfo, paintOffset);
     94 }
     95 
     96 void BlockPainter::paintChildAsInlineBlock(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
     97 {
     98     LayoutPoint childPoint = m_renderBlock.flipForWritingModeForChild(child, paintOffset);
     99     if (!child->hasSelfPaintingLayer() && !child->isFloating())
    100         paintAsInlineBlock(child, paintInfo, childPoint);
    101 }
    102 
    103 void BlockPainter::paintInlineBox(InlineBox& inlineBox, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    104 {
    105     if (!paintInfo.shouldPaintWithinRoot(&inlineBox.renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
    106         return;
    107 
    108     LayoutPoint childPoint = paintOffset;
    109     if (inlineBox.parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
    110         childPoint = inlineBox.renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(inlineBox.renderer()), childPoint);
    111 
    112     paintAsInlineBlock(&inlineBox.renderer(), paintInfo, childPoint);
    113 }
    114 
    115 void BlockPainter::paintAsInlineBlock(RenderObject* renderer, PaintInfo& paintInfo, const LayoutPoint& childPoint)
    116 {
    117     if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)
    118         return;
    119 
    120     // Paint all phases atomically, as though the element established its own
    121     // stacking context.  (See Appendix E.2, section 7.2.1.4 on
    122     // inline block/table/replaced elements in the CSS2.1 specification.)
    123     // This is also used by other elements (e.g. flex items and grid items).
    124     bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
    125     PaintInfo info(paintInfo);
    126     info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
    127     renderer->paint(info, childPoint);
    128     if (!preservePhase) {
    129         info.phase = PaintPhaseChildBlockBackgrounds;
    130         renderer->paint(info, childPoint);
    131         info.phase = PaintPhaseFloat;
    132         renderer->paint(info, childPoint);
    133         info.phase = PaintPhaseForeground;
    134         renderer->paint(info, childPoint);
    135         info.phase = PaintPhaseOutline;
    136         renderer->paint(info, childPoint);
    137     }
    138 }
    139 
    140 void BlockPainter::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    141 {
    142     PaintPhase paintPhase = paintInfo.phase;
    143 
    144     // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
    145     LayoutPoint scrolledOffset = paintOffset;
    146     if (m_renderBlock.hasOverflowClip())
    147         scrolledOffset.move(-m_renderBlock.scrolledContentOffset());
    148 
    149     // 1. paint background, borders etc
    150     if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && m_renderBlock.style()->visibility() == VISIBLE) {
    151         if (m_renderBlock.hasBoxDecorationBackground())
    152             m_renderBlock.paintBoxDecorationBackground(paintInfo, paintOffset);
    153         if (m_renderBlock.hasColumns() && !paintInfo.paintRootBackgroundOnly())
    154             paintColumnRules(paintInfo, scrolledOffset);
    155     }
    156 
    157     if (paintPhase == PaintPhaseMask && m_renderBlock.style()->visibility() == VISIBLE) {
    158         m_renderBlock.paintMask(paintInfo, paintOffset);
    159         return;
    160     }
    161 
    162     if (paintPhase == PaintPhaseClippingMask && m_renderBlock.style()->visibility() == VISIBLE) {
    163         m_renderBlock.paintClippingMask(paintInfo, paintOffset);
    164         return;
    165     }
    166 
    167     // We're done. We don't bother painting any children.
    168     if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
    169         return;
    170 
    171     // 2. paint contents
    172     if (paintPhase != PaintPhaseSelfOutline) {
    173         if (m_renderBlock.hasColumns())
    174             paintColumnContents(paintInfo, scrolledOffset);
    175         else
    176             paintContents(paintInfo, scrolledOffset);
    177     }
    178 
    179     // 3. paint selection
    180     // FIXME: Make this work with multi column layouts. For now don't fill gaps.
    181     bool isPrinting = m_renderBlock.document().printing();
    182     if (!isPrinting && !m_renderBlock.hasColumns())
    183         paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
    184 
    185     // 4. paint floats.
    186     if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
    187         if (m_renderBlock.hasColumns())
    188             paintColumnContents(paintInfo, scrolledOffset, true);
    189         else
    190             m_renderBlock.paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
    191     }
    192 
    193     // 5. paint outline.
    194     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && m_renderBlock.style()->hasOutline() && m_renderBlock.style()->visibility() == VISIBLE) {
    195         // Don't paint focus ring for anonymous block continuation because the
    196         // inline element having outline-style:auto paints the whole focus ring.
    197         if (!m_renderBlock.style()->outlineStyleIsAuto() || !m_renderBlock.isAnonymousBlockContinuation())
    198             m_renderBlock.paintOutline(paintInfo, LayoutRect(paintOffset, m_renderBlock.size()));
    199     }
    200 
    201     // 6. paint continuation outlines.
    202     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines))
    203         paintContinuationOutlines(paintInfo, paintOffset);
    204 
    205     // 7. paint caret.
    206     // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
    207     // then paint the caret.
    208     if (paintPhase == PaintPhaseForeground)
    209         paintCarets(paintInfo, paintOffset);
    210 }
    211 
    212 static inline bool caretBrowsingEnabled(const Frame* frame)
    213 {
    214     Settings* settings = frame->settings();
    215     return settings && settings->caretBrowsingEnabled();
    216 }
    217 
    218 static inline bool hasCursorCaret(const FrameSelection& selection, const RenderBlock* block, bool caretBrowsing)
    219 {
    220     return selection.caretRenderer() == block && (selection.hasEditableStyle() || caretBrowsing);
    221 }
    222 
    223 static inline bool hasDragCaret(const DragCaretController& dragCaretController, const RenderBlock* block, bool caretBrowsing)
    224 {
    225     return dragCaretController.caretRenderer() == block && (dragCaretController.isContentEditable() || caretBrowsing);
    226 }
    227 
    228 void BlockPainter::paintCarets(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    229 {
    230     bool caretBrowsing = caretBrowsingEnabled(m_renderBlock.frame());
    231 
    232     FrameSelection& selection = m_renderBlock.frame()->selection();
    233     if (hasCursorCaret(selection, &m_renderBlock, caretBrowsing)) {
    234         selection.paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
    235     }
    236 
    237     DragCaretController& dragCaretController = m_renderBlock.frame()->page()->dragCaretController();
    238     if (hasDragCaret(dragCaretController, &m_renderBlock, caretBrowsing)) {
    239         dragCaretController.paintDragCaret(m_renderBlock.frame(), paintInfo.context, paintOffset, paintInfo.rect);
    240     }
    241 }
    242 
    243 LayoutRect BlockPainter::overflowRectForPaintRejection() const
    244 {
    245     LayoutRect overflowRect = m_renderBlock.visualOverflowRect();
    246     if (!m_renderBlock.hasRenderOverflow() || !m_renderBlock.usesCompositedScrolling())
    247         return overflowRect;
    248 
    249     overflowRect.unite(m_renderBlock.layoutOverflowRect());
    250     overflowRect.move(-m_renderBlock.scrolledContentOffset());
    251     return overflowRect;
    252 }
    253 
    254 bool BlockPainter::hasCaret() const
    255 {
    256     bool caretBrowsing = caretBrowsingEnabled(m_renderBlock.frame());
    257     return hasCursorCaret(m_renderBlock.frame()->selection(), &m_renderBlock, caretBrowsing)
    258         || hasDragCaret(m_renderBlock.frame()->page()->dragCaretController(), &m_renderBlock, caretBrowsing);
    259 }
    260 
    261 void BlockPainter::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    262 {
    263     const Color& ruleColor = m_renderBlock.resolveColor(CSSPropertyWebkitColumnRuleColor);
    264     bool ruleTransparent = m_renderBlock.style()->columnRuleIsTransparent();
    265     EBorderStyle ruleStyle = m_renderBlock.style()->columnRuleStyle();
    266     LayoutUnit ruleThickness = m_renderBlock.style()->columnRuleWidth();
    267     LayoutUnit colGap = m_renderBlock.columnGap();
    268     bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
    269     if (!renderRule)
    270         return;
    271 
    272     ColumnInfo* colInfo = m_renderBlock.columnInfo();
    273     unsigned colCount = m_renderBlock.columnCount(colInfo);
    274 
    275     bool antialias = BoxPainter::shouldAntialiasLines(paintInfo.context);
    276 
    277     if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
    278         bool leftToRight = m_renderBlock.style()->isLeftToRightDirection();
    279         LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : m_renderBlock.contentLogicalWidth();
    280         LayoutUnit ruleAdd = m_renderBlock.logicalLeftOffsetForContent();
    281         LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : m_renderBlock.contentLogicalWidth();
    282         LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
    283         BoxSide boxSide = m_renderBlock.isHorizontalWritingMode()
    284             ? leftToRight ? BSLeft : BSRight
    285             : leftToRight ? BSTop : BSBottom;
    286 
    287         for (unsigned i = 0; i < colCount; i++) {
    288             // Move to the next position.
    289             if (leftToRight) {
    290                 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
    291                 currLogicalLeftOffset += inlineDirectionSize + colGap;
    292             } else {
    293                 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
    294                 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
    295             }
    296 
    297             // Now paint the column rule.
    298             if (i < colCount - 1) {
    299                 LayoutUnit ruleLeft = m_renderBlock.isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + m_renderBlock.borderLeft() + m_renderBlock.paddingLeft();
    300                 LayoutUnit ruleRight = m_renderBlock.isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + m_renderBlock.contentWidth();
    301                 LayoutUnit ruleTop = m_renderBlock.isHorizontalWritingMode() ? paintOffset.y() + m_renderBlock.borderTop() + m_renderBlock.paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
    302                 LayoutUnit ruleBottom = m_renderBlock.isHorizontalWritingMode() ? ruleTop + m_renderBlock.contentHeight() : ruleTop + ruleThickness;
    303                 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
    304                 ObjectPainter::drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
    305             }
    306 
    307             ruleLogicalLeft = currLogicalLeftOffset;
    308         }
    309     } else {
    310         bool topToBottom = !m_renderBlock.style()->isFlippedBlocksWritingMode();
    311         LayoutUnit ruleLeft = m_renderBlock.isHorizontalWritingMode()
    312             ? m_renderBlock.borderLeft() + m_renderBlock.paddingLeft()
    313             : colGap / 2 - colGap - ruleThickness / 2 + m_renderBlock.borderBefore() + m_renderBlock.paddingBefore();
    314         LayoutUnit ruleWidth = m_renderBlock.isHorizontalWritingMode() ? m_renderBlock.contentWidth() : ruleThickness;
    315         LayoutUnit ruleTop = m_renderBlock.isHorizontalWritingMode()
    316             ? colGap / 2 - colGap - ruleThickness / 2 + m_renderBlock.borderBefore() + m_renderBlock.paddingBefore()
    317             : m_renderBlock.borderStart() + m_renderBlock.paddingStart();
    318         LayoutUnit ruleHeight = m_renderBlock.isHorizontalWritingMode() ? ruleThickness : m_renderBlock.contentHeight();
    319         LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
    320 
    321         if (!topToBottom) {
    322             if (m_renderBlock.isHorizontalWritingMode())
    323                 ruleRect.setY(m_renderBlock.height() - ruleRect.maxY());
    324             else
    325                 ruleRect.setX(m_renderBlock.width() - ruleRect.maxX());
    326         }
    327 
    328         ruleRect.moveBy(paintOffset);
    329 
    330         BoxSide boxSide = m_renderBlock.isHorizontalWritingMode()
    331             ? topToBottom ? BSTop : BSBottom
    332             : topToBottom ? BSLeft : BSRight;
    333 
    334         LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
    335         if (!m_renderBlock.isHorizontalWritingMode())
    336             step = step.transposedSize();
    337 
    338         for (unsigned i = 1; i < colCount; i++) {
    339             ruleRect.move(step);
    340             IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
    341             ObjectPainter::drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
    342         }
    343     }
    344 }
    345 
    346 void BlockPainter::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
    347 {
    348     // We need to do multiple passes, breaking up our child painting into strips.
    349     GraphicsContext* context = paintInfo.context;
    350     ColumnInfo* colInfo = m_renderBlock.columnInfo();
    351     unsigned colCount = m_renderBlock.columnCount(colInfo);
    352     if (!colCount)
    353         return;
    354     LayoutUnit currLogicalTopOffset = 0;
    355     LayoutUnit colGap = m_renderBlock.columnGap();
    356     for (unsigned i = 0; i < colCount; i++) {
    357         // For each rect, we clip to the rect, and then we adjust our coords.
    358         LayoutRect colRect = m_renderBlock.columnRectAt(colInfo, i);
    359         m_renderBlock.flipForWritingMode(colRect);
    360         LayoutUnit logicalLeftOffset = (m_renderBlock.isHorizontalWritingMode() ? colRect.x() : colRect.y()) - m_renderBlock.logicalLeftOffsetForContent();
    361         LayoutSize offset = m_renderBlock.isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
    362         if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
    363             if (m_renderBlock.isHorizontalWritingMode())
    364                 offset.expand(0, colRect.y() - m_renderBlock.borderTop() - m_renderBlock.paddingTop());
    365             else
    366                 offset.expand(colRect.x() - m_renderBlock.borderLeft() - m_renderBlock.paddingLeft(), 0);
    367         }
    368         colRect.moveBy(paintOffset);
    369         PaintInfo info(paintInfo);
    370         info.rect.intersect(enclosingIntRect(colRect));
    371 
    372         if (!info.rect.isEmpty()) {
    373             GraphicsContextStateSaver stateSaver(*context);
    374             LayoutRect clipRect(colRect);
    375 
    376             if (i < colCount - 1) {
    377                 if (m_renderBlock.isHorizontalWritingMode())
    378                     clipRect.expand(colGap / 2, 0);
    379                 else
    380                     clipRect.expand(0, colGap / 2);
    381             }
    382             // Each strip pushes a clip, since column boxes are specified as being
    383             // like overflow:hidden.
    384             // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
    385             // are clipped according to the 'overflow' property.
    386             context->clip(enclosingIntRect(clipRect));
    387 
    388             // Adjust our x and y when painting.
    389             LayoutPoint adjustedPaintOffset = paintOffset + offset;
    390             if (paintingFloats)
    391                 m_renderBlock.paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
    392             else
    393                 paintContents(info, adjustedPaintOffset);
    394         }
    395 
    396         LayoutUnit blockDelta = (m_renderBlock.isHorizontalWritingMode() ? colRect.height() : colRect.width());
    397         if (m_renderBlock.style()->isFlippedBlocksWritingMode())
    398             currLogicalTopOffset += blockDelta;
    399         else
    400             currLogicalTopOffset -= blockDelta;
    401     }
    402 }
    403 
    404 void BlockPainter::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    405 {
    406     // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
    407     // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
    408     // will do a full paint invalidation.
    409     if (m_renderBlock.document().didLayoutWithPendingStylesheets() && !m_renderBlock.isRenderView())
    410         return;
    411 
    412     if (m_renderBlock.childrenInline()) {
    413         LineBoxListPainter(*m_renderBlock.lineBoxes()).paint(&m_renderBlock, paintInfo, paintOffset);
    414     } else {
    415         PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
    416         newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
    417 
    418         // We don't paint our own background, but we do let the kids paint their backgrounds.
    419         PaintInfo paintInfoForChild(paintInfo);
    420         paintInfoForChild.phase = newPhase;
    421         paintInfoForChild.updatePaintingRootForChildren(&m_renderBlock);
    422         m_renderBlock.paintChildren(paintInfoForChild, paintOffset);
    423     }
    424 }
    425 
    426 void BlockPainter::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    427 {
    428     if (m_renderBlock.shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
    429         LayoutUnit lastTop = 0;
    430         LayoutUnit lastLeft = m_renderBlock.logicalLeftSelectionOffset(&m_renderBlock, lastTop);
    431         LayoutUnit lastRight = m_renderBlock.logicalRightSelectionOffset(&m_renderBlock, lastTop);
    432         GraphicsContextStateSaver stateSaver(*paintInfo.context);
    433 
    434         LayoutRect gapRectsBounds = m_renderBlock.selectionGaps(&m_renderBlock, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
    435         if (!gapRectsBounds.isEmpty()) {
    436             RenderLayer* layer = m_renderBlock.enclosingLayer();
    437             gapRectsBounds.moveBy(-paintOffset);
    438             if (!m_renderBlock.hasLayer()) {
    439                 LayoutRect localBounds(gapRectsBounds);
    440                 m_renderBlock.flipForWritingMode(localBounds);
    441                 gapRectsBounds = m_renderBlock.localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
    442                 if (layer->renderer()->hasOverflowClip())
    443                     gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
    444             }
    445             layer->addBlockSelectionGapsBounds(gapRectsBounds);
    446         }
    447     }
    448 }
    449 
    450 void BlockPainter::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
    451 {
    452     RenderInline* inlineCont = m_renderBlock.inlineElementContinuation();
    453     if (inlineCont && inlineCont->style()->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
    454         RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
    455         RenderBlock* cb = m_renderBlock.containingBlock();
    456 
    457         bool inlineEnclosedInSelfPaintingLayer = false;
    458         for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
    459             if (box->hasSelfPaintingLayer()) {
    460                 inlineEnclosedInSelfPaintingLayer = true;
    461                 break;
    462             }
    463         }
    464 
    465         // Do not add continuations for outline painting by our containing block if we are a relative positioned
    466         // 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
    467         // in the same layer.
    468         if (!inlineEnclosedInSelfPaintingLayer && !m_renderBlock.hasLayer())
    469             cb->addContinuationWithOutline(inlineRenderer);
    470         else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && m_renderBlock.hasLayer()))
    471             InlinePainter(*inlineRenderer).paintOutline(info, paintOffset - m_renderBlock.locationOffset() + inlineRenderer->containingBlock()->location());
    472     }
    473 
    474     ContinuationOutlineTableMap* table = continuationOutlineTable();
    475     if (table->isEmpty())
    476         return;
    477 
    478     OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(&m_renderBlock);
    479     if (!continuations)
    480         return;
    481 
    482     LayoutPoint accumulatedPaintOffset = paintOffset;
    483     // Paint each continuation outline.
    484     ListHashSet<RenderInline*>::iterator end = continuations->end();
    485     for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
    486         // Need to add in the coordinates of the intervening blocks.
    487         RenderInline* flow = *it;
    488         RenderBlock* block = flow->containingBlock();
    489         for ( ; block && block != &m_renderBlock; block = block->containingBlock())
    490             accumulatedPaintOffset.moveBy(block->location());
    491         ASSERT(block);
    492         InlinePainter(*flow).paintOutline(info, accumulatedPaintOffset);
    493     }
    494 }
    495 
    496 
    497 } // namespace blink
    498