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

Side by Side Diff: Source/core/paint/BlockPainter.cpp

Issue 569683004: Factor painting code from RenderBlock into BlockPainter. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Finish. 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/rendering/GraphicsContextAnnotator.h"
15 #include "core/rendering/PaintInfo.h"
16 #include "core/rendering/RenderBlock.h"
17 #include "core/rendering/RenderLayer.h"
18 #include "platform/geometry/LayoutPoint.h"
19 #include "platform/geometry/LayoutRect.h"
20 #include "platform/graphics/GraphicsContextCullSaver.h"
21 #include "platform/graphics/GraphicsContextStateSaver.h"
22
23 namespace blink {
24
25 void BlockPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
26 {
27 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderBlock);
28
29 LayoutPoint adjustedPaintOffset = paintOffset + m_renderBlock.location();
30
31 PaintPhase phase = paintInfo.phase;
32
33 LayoutRect overflowBox;
34 // Check if we need to do anything at all.
35 // FIXME: Could eliminate the isDocumentElement() check if we fix background painting so that the RenderView
36 // paints the root's background.
37 if (!m_renderBlock.isDocumentElement()) {
38 overflowBox = overflowRectForPaintRejection();
39 m_renderBlock.flipForWritingMode(overflowBox);
40 overflowBox.moveBy(adjustedPaintOffset);
41 if (!overflowBox.intersects(paintInfo.rect))
42 return;
43 }
44
45 // There are some cases where not all clipped visual overflow is accounted f or.
46 // FIXME: reduce the number of such cases.
47 ContentsClipBehavior contentsClipBehavior = ForceContentsClip;
48 if (m_renderBlock.hasOverflowClip() && !m_renderBlock.hasControlClip() && !( m_renderBlock.shouldPaintSelectionGaps() && phase == PaintPhaseForeground) && !h asCaret())
49 contentsClipBehavior = SkipContentsClipIfPossible;
50
51 bool pushedClip = m_renderBlock.pushContentsClip(paintInfo, adjustedPaintOff set, contentsClipBehavior);
52 {
53 GraphicsContextCullSaver cullSaver(*paintInfo.context);
54 // Cull if we have more than one child and we didn't already clip.
55 bool shouldCull = m_renderBlock.document().settings()->containerCullingE nabled() && !pushedClip && !m_renderBlock.isDocumentElement()
56 && m_renderBlock.firstChild() && m_renderBlock.lastChild() && m_rend erBlock.firstChild() != m_renderBlock.lastChild();
57 if (shouldCull)
58 cullSaver.cull(overflowBox);
59
60 m_renderBlock.paintObject(paintInfo, adjustedPaintOffset);
Stephen Chennney 2014/09/15 20:18:05 FIXME on all the refs like this so that we catch t
chrishtr 2014/09/15 20:52:08 This one is due to a virtual method on RenderBlock
61 }
62 if (pushedClip)
63 m_renderBlock.popContentsClip(paintInfo, phase, adjustedPaintOffset);
Stephen Chennney 2014/09/15 20:18:05 Can we move popContentsClip too?
chrishtr 2014/09/15 20:52:08 This one is harder, since popContentsClip is on Re
64
65 // Our scrollbar widgets paint exactly when we tell them to, so that they wo rk properly with
66 // z-index. We paint after we painted the background/border, so that the scr ollbars will
67 // sit above the background/border.
68 if (m_renderBlock.hasOverflowClip() && m_renderBlock.style()->visibility() = = VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBloc kBackground) && paintInfo.shouldPaintWithinRoot(&m_renderBlock) && !paintInfo.pa intRootBackgroundOnly())
69 m_renderBlock.layer()->scrollableArea()->paintOverflowControls(paintInfo .context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect, false /* paintin gOverlayControls */);
70 }
71
72 void BlockPainter::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOff set)
73 {
74 PaintPhase paintPhase = paintInfo.phase;
75
76 // Adjust our painting position if we're inside a scrolled layer (e.g., an o verflow:auto div).
77 LayoutPoint scrolledOffset = paintOffset;
78 if (m_renderBlock.hasOverflowClip())
79 scrolledOffset.move(-m_renderBlock.scrolledContentOffset());
80
81 // 1. paint background, borders etc
82 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChil dBlockBackground) && m_renderBlock.style()->visibility() == VISIBLE) {
83 if (m_renderBlock.hasBoxDecorationBackground())
84 m_renderBlock.paintBoxDecorationBackground(paintInfo, paintOffset);
85 if (m_renderBlock.hasColumns() && !paintInfo.paintRootBackgroundOnly())
86 paintColumnRules(paintInfo, scrolledOffset);
87 }
88
89 if (paintPhase == PaintPhaseMask && m_renderBlock.style()->visibility() == V ISIBLE) {
90 m_renderBlock.paintMask(paintInfo, paintOffset);
Stephen Chennney 2014/09/15 20:18:05 Whenever I see a m_renderBlock.paintBlah, I presum
chrishtr 2014/09/15 20:52:08 Added the rest of the methods. But paintMask is vi
91 return;
92 }
93
94 if (paintPhase == PaintPhaseClippingMask && m_renderBlock.style()->visibilit y() == VISIBLE) {
95 m_renderBlock.paintClippingMask(paintInfo, paintOffset);
96 return;
97 }
98
99 // We're done. We don't bother painting any children.
100 if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackground Only())
101 return;
102
103 // 2. paint contents
104 if (paintPhase != PaintPhaseSelfOutline) {
105 if (m_renderBlock.hasColumns())
106 paintColumnContents(paintInfo, scrolledOffset);
107 else
108 paintContents(paintInfo, scrolledOffset);
109 }
110
111 // 3. paint selection
112 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
113 bool isPrinting = m_renderBlock.document().printing();
114 if (!isPrinting && !m_renderBlock.hasColumns())
115 m_renderBlock.paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
116
117 // 4. paint floats.
118 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || pa intPhase == PaintPhaseTextClip) {
119 if (m_renderBlock.hasColumns())
120 paintColumnContents(paintInfo, scrolledOffset, true);
121 else
122 m_renderBlock.paintFloats(paintInfo, scrolledOffset, paintPhase == P aintPhaseSelection || paintPhase == PaintPhaseTextClip);
123 }
124
125 // 5. paint outline.
126 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && m_renderBlock.style()->hasOutline() && m_renderBlock.style()->visibility() = = VISIBLE) {
127 // Don't paint focus ring for anonymous block continuation because the
128 // inline element having outline-style:auto paints the whole focus ring.
129 if (!m_renderBlock.style()->outlineStyleIsAuto() || !m_renderBlock.isAno nymousBlockContinuation())
130 m_renderBlock.paintOutline(paintInfo, LayoutRect(paintOffset, m_rend erBlock.size()));
131 }
132
133 // 6. paint continuation outlines.
134 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutline s))
135 m_renderBlock.paintContinuationOutlines(paintInfo, paintOffset);
136
137 // 7. paint caret.
138 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
139 // then paint the caret.
140 if (paintPhase == PaintPhaseForeground)
141 paintCarets(paintInfo, paintOffset);
142 }
143
144 static inline bool caretBrowsingEnabled(const Frame* frame)
145 {
146 Settings* settings = frame->settings();
147 return settings && settings->caretBrowsingEnabled();
148 }
149
150 static inline bool hasCursorCaret(const FrameSelection& selection, const RenderB lock* block, bool caretBrowsing)
151 {
152 return selection.caretRenderer() == block && (selection.hasEditableStyle() | | caretBrowsing);
153 }
154
155 static inline bool hasDragCaret(const DragCaretController& dragCaretController, const RenderBlock* block, bool caretBrowsing)
156 {
157 return dragCaretController.caretRenderer() == block && (dragCaretController. isContentEditable() || caretBrowsing);
158 }
159
160 void BlockPainter::paintCarets(PaintInfo& paintInfo, const LayoutPoint& paintOff set)
161 {
162 bool caretBrowsing = caretBrowsingEnabled(m_renderBlock.frame());
163
164 FrameSelection& selection = m_renderBlock.frame()->selection();
165 if (hasCursorCaret(selection, &m_renderBlock, caretBrowsing)) {
166 selection.paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
167 }
168
169 DragCaretController& dragCaretController = m_renderBlock.frame()->page()->dr agCaretController();
170 if (hasDragCaret(dragCaretController, &m_renderBlock, caretBrowsing)) {
171 dragCaretController.paintDragCaret(m_renderBlock.frame(), paintInfo.cont ext, paintOffset, paintInfo.rect);
172 }
173 }
174
175 LayoutRect BlockPainter::overflowRectForPaintRejection() const
176 {
177 LayoutRect overflowRect = m_renderBlock.visualOverflowRect();
178 if (!m_renderBlock.hasRenderOverflow() || !m_renderBlock.usesCompositedScrol ling())
179 return overflowRect;
180
181 overflowRect.unite(m_renderBlock.layoutOverflowRect());
182 overflowRect.move(-m_renderBlock.scrolledContentOffset());
183 return overflowRect;
184 }
185
186 bool BlockPainter::hasCaret() const
187 {
188 bool caretBrowsing = caretBrowsingEnabled(m_renderBlock.frame());
189 return hasCursorCaret(m_renderBlock.frame()->selection(), &m_renderBlock, ca retBrowsing)
190 || hasDragCaret(m_renderBlock.frame()->page()->dragCaretController(), &m _renderBlock, caretBrowsing);
191 }
192
193 void BlockPainter::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pai ntOffset)
194 {
195 const Color& ruleColor = m_renderBlock.resolveColor(CSSPropertyWebkitColumnR uleColor);
196 bool ruleTransparent = m_renderBlock.style()->columnRuleIsTransparent();
197 EBorderStyle ruleStyle = m_renderBlock.style()->columnRuleStyle();
198 LayoutUnit ruleThickness = m_renderBlock.style()->columnRuleWidth();
199 LayoutUnit colGap = m_renderBlock.columnGap();
200 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
201 if (!renderRule)
202 return;
203
204 ColumnInfo* colInfo = m_renderBlock.columnInfo();
205 unsigned colCount = m_renderBlock.columnCount(colInfo);
206
207 bool antialias = BoxPainter::shouldAntialiasLines(paintInfo.context);
208
209 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
210 bool leftToRight = m_renderBlock.style()->isLeftToRightDirection();
211 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : m_render Block.contentLogicalWidth();
212 LayoutUnit ruleAdd = m_renderBlock.logicalLeftOffsetForContent();
213 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : m_renderBlock. contentLogicalWidth();
214 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
215 BoxSide boxSide = m_renderBlock.isHorizontalWritingMode()
216 ? leftToRight ? BSLeft : BSRight
217 : leftToRight ? BSTop : BSBottom;
218
219 for (unsigned i = 0; i < colCount; i++) {
220 // Move to the next position.
221 if (leftToRight) {
222 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
223 currLogicalLeftOffset += inlineDirectionSize + colGap;
224 } else {
225 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
226 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
227 }
228
229 // Now paint the column rule.
230 if (i < colCount - 1) {
231 LayoutUnit ruleLeft = m_renderBlock.isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x( ) + m_renderBlock.borderLeft() + m_renderBlock.paddingLeft();
232 LayoutUnit ruleRight = m_renderBlock.isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + m_renderBlock.contentWidth();
233 LayoutUnit ruleTop = m_renderBlock.isHorizontalWritingMode() ? p aintOffset.y() + m_renderBlock.borderTop() + m_renderBlock.paddingTop() : paintO ffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
234 LayoutUnit ruleBottom = m_renderBlock.isHorizontalWritingMode() ? ruleTop + m_renderBlock.contentHeight() : ruleTop + ruleThickness;
235 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(rule Left, ruleTop, ruleRight, ruleBottom);
236 m_renderBlock.drawLineForBoxSide(paintInfo.context, pixelSnapped RuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappe dRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
237 }
238
239 ruleLogicalLeft = currLogicalLeftOffset;
240 }
241 } else {
242 bool topToBottom = !m_renderBlock.style()->isFlippedBlocksWritingMode();
243 LayoutUnit ruleLeft = m_renderBlock.isHorizontalWritingMode()
244 ? m_renderBlock.borderLeft() + m_renderBlock.paddingLeft()
245 : colGap / 2 - colGap - ruleThickness / 2 + m_renderBlock.borderBefo re() + m_renderBlock.paddingBefore();
246 LayoutUnit ruleWidth = m_renderBlock.isHorizontalWritingMode() ? m_rende rBlock.contentWidth() : ruleThickness;
247 LayoutUnit ruleTop = m_renderBlock.isHorizontalWritingMode()
248 ? colGap / 2 - colGap - ruleThickness / 2 + m_renderBlock.borderBefo re() + m_renderBlock.paddingBefore()
249 : m_renderBlock.borderStart() + m_renderBlock.paddingStart();
250 LayoutUnit ruleHeight = m_renderBlock.isHorizontalWritingMode() ? ruleTh ickness : m_renderBlock.contentHeight();
251 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
252
253 if (!topToBottom) {
254 if (m_renderBlock.isHorizontalWritingMode())
255 ruleRect.setY(m_renderBlock.height() - ruleRect.maxY());
256 else
257 ruleRect.setX(m_renderBlock.width() - ruleRect.maxX());
258 }
259
260 ruleRect.moveBy(paintOffset);
261
262 BoxSide boxSide = m_renderBlock.isHorizontalWritingMode()
263 ? topToBottom ? BSTop : BSBottom
264 : topToBottom ? BSLeft : BSRight;
265
266 LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(co lInfo->columnHeight() + colGap));
267 if (!m_renderBlock.isHorizontalWritingMode())
268 step = step.transposedSize();
269
270 for (unsigned i = 1; i < colCount; i++) {
271 ruleRect.move(step);
272 IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
273 m_renderBlock.drawLineForBoxSide(paintInfo.context, pixelSnappedRule Rect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRul eRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
274 }
275 }
276 }
277
278 void BlockPainter::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
279 {
280 // We need to do multiple passes, breaking up our child painting into strips .
281 GraphicsContext* context = paintInfo.context;
282 ColumnInfo* colInfo = m_renderBlock.columnInfo();
283 unsigned colCount = m_renderBlock.columnCount(colInfo);
284 if (!colCount)
285 return;
286 LayoutUnit currLogicalTopOffset = 0;
287 LayoutUnit colGap = m_renderBlock.columnGap();
288 for (unsigned i = 0; i < colCount; i++) {
289 // For each rect, we clip to the rect, and then we adjust our coords.
290 LayoutRect colRect = m_renderBlock.columnRectAt(colInfo, i);
291 m_renderBlock.flipForWritingMode(colRect);
292 LayoutUnit logicalLeftOffset = (m_renderBlock.isHorizontalWritingMode() ? colRect.x() : colRect.y()) - m_renderBlock.logicalLeftOffsetForContent();
293 LayoutSize offset = m_renderBlock.isHorizontalWritingMode() ? LayoutSize (logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, log icalLeftOffset);
294 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
295 if (m_renderBlock.isHorizontalWritingMode())
296 offset.expand(0, colRect.y() - m_renderBlock.borderTop() - m_ren derBlock.paddingTop());
297 else
298 offset.expand(colRect.x() - m_renderBlock.borderLeft() - m_rende rBlock.paddingLeft(), 0);
299 }
300 colRect.moveBy(paintOffset);
301 PaintInfo info(paintInfo);
302 info.rect.intersect(enclosingIntRect(colRect));
303
304 if (!info.rect.isEmpty()) {
305 GraphicsContextStateSaver stateSaver(*context);
306 LayoutRect clipRect(colRect);
307
308 if (i < colCount - 1) {
309 if (m_renderBlock.isHorizontalWritingMode())
310 clipRect.expand(colGap / 2, 0);
311 else
312 clipRect.expand(0, colGap / 2);
313 }
314 // Each strip pushes a clip, since column boxes are specified as bei ng
315 // like overflow:hidden.
316 // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
317 // are clipped according to the 'overflow' property.
318 context->clip(enclosingIntRect(clipRect));
319
320 // Adjust our x and y when painting.
321 LayoutPoint adjustedPaintOffset = paintOffset + offset;
322 if (paintingFloats)
323 m_renderBlock.paintFloats(info, adjustedPaintOffset, paintInfo.p hase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
324 else
325 paintContents(info, adjustedPaintOffset);
326 }
327
328 LayoutUnit blockDelta = (m_renderBlock.isHorizontalWritingMode() ? colRe ct.height() : colRect.width());
329 if (m_renderBlock.style()->isFlippedBlocksWritingMode())
330 currLogicalTopOffset += blockDelta;
331 else
332 currLogicalTopOffset -= blockDelta;
333 }
334 }
335
336 void BlockPainter::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintO ffset)
337 {
338 // Avoid painting descendants of the root element when stylesheets haven't l oaded. This eliminates FOUC.
339 // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
340 // will do a full paint invalidation.
341 if (m_renderBlock.document().didLayoutWithPendingStylesheets() && !m_renderB lock.isRenderView())
342 return;
343
344 if (m_renderBlock.childrenInline()) {
345 m_renderBlock.lineBoxes()->paint(&m_renderBlock, paintInfo, paintOffset) ;
346 } else {
347 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? Pai ntPhaseOutline : paintInfo.phase;
348 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChi ldBlockBackground : newPhase;
349
350 // We don't paint our own background, but we do let the kids paint their backgrounds.
351 PaintInfo paintInfoForChild(paintInfo);
352 paintInfoForChild.phase = newPhase;
353 paintInfoForChild.updatePaintingRootForChildren(&m_renderBlock);
354 m_renderBlock.paintChildren(paintInfoForChild, paintOffset);
355 }
356 }
357
358 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698