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
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintChildren(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintChild(RenderBox * child,PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintChildrenOfFlexibleBox(RenderFlexibleBox & renderFlexibleBox,PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintChildAsInlineBlock(RenderBox * child,PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintInlineBox(InlineBox & inlineBox,PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintAsInlineBlock(RenderObject * renderer,PaintInfo & paintInfo,const LayoutPoint & childPoint)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
paintObject(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
caretBrowsingEnabled(const Frame * frame)212 static inline bool caretBrowsingEnabled(const Frame* frame)
213 {
214 Settings* settings = frame->settings();
215 return settings && settings->caretBrowsingEnabled();
216 }
217
hasCursorCaret(const FrameSelection & selection,const RenderBlock * block,bool caretBrowsing)218 static inline bool hasCursorCaret(const FrameSelection& selection, const RenderBlock* block, bool caretBrowsing)
219 {
220 return selection.caretRenderer() == block && (selection.hasEditableStyle() || caretBrowsing);
221 }
222
hasDragCaret(const DragCaretController & dragCaretController,const RenderBlock * block,bool caretBrowsing)223 static inline bool hasDragCaret(const DragCaretController& dragCaretController, const RenderBlock* block, bool caretBrowsing)
224 {
225 return dragCaretController.caretRenderer() == block && (dragCaretController.isContentEditable() || caretBrowsing);
226 }
227
paintCarets(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
overflowRectForPaintRejection() const243 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
hasCaret() const254 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
paintColumnRules(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintColumnContents(PaintInfo & paintInfo,const LayoutPoint & paintOffset,bool paintingFloats)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
paintContents(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintSelection(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
paintContinuationOutlines(PaintInfo & info,const LayoutPoint & paintOffset)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