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