| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/paint/InlineFlowBoxPainter.h" | 5 #include "core/paint/InlineFlowBoxPainter.h" |
| 6 | 6 |
| 7 #include "core/layout/api/LineLayoutAPIShim.h" | 7 #include "core/layout/api/LineLayoutAPIShim.h" |
| 8 #include "core/layout/line/RootInlineBox.h" | 8 #include "core/layout/line/RootInlineBox.h" |
| 9 #include "core/paint/BoxPainter.h" | 9 #include "core/paint/BoxPainter.h" |
| 10 #include "core/paint/PaintInfo.h" | 10 #include "core/paint/PaintInfo.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 !curr->boxModelObject().hasSelfPaintingLayer()) | 55 !curr->boxModelObject().hasSelfPaintingLayer()) |
| 56 curr->paint(childInfo, paintOffset, lineTop, lineBottom); | 56 curr->paint(childInfo, paintOffset, lineTop, lineBottom); |
| 57 } | 57 } |
| 58 } | 58 } |
| 59 | 59 |
| 60 void InlineFlowBoxPainter::paintFillLayers(const PaintInfo& paintInfo, | 60 void InlineFlowBoxPainter::paintFillLayers(const PaintInfo& paintInfo, |
| 61 const Color& c, | 61 const Color& c, |
| 62 const FillLayer& fillLayer, | 62 const FillLayer& fillLayer, |
| 63 const LayoutRect& rect, | 63 const LayoutRect& rect, |
| 64 SkXfermode::Mode op) { | 64 SkXfermode::Mode op) { |
| 65 // FIXME: This should be a for loop or similar. It's a little non-trivial to d
o so, however, since the layers need to be | 65 // FIXME: This should be a for loop or similar. It's a little non-trivial to |
| 66 // painted in reverse order. | 66 // do so, however, since the layers need to be painted in reverse order. |
| 67 if (fillLayer.next()) | 67 if (fillLayer.next()) |
| 68 paintFillLayers(paintInfo, c, *fillLayer.next(), rect, op); | 68 paintFillLayers(paintInfo, c, *fillLayer.next(), rect, op); |
| 69 paintFillLayer(paintInfo, c, fillLayer, rect, op); | 69 paintFillLayer(paintInfo, c, fillLayer, rect, op); |
| 70 } | 70 } |
| 71 | 71 |
| 72 void InlineFlowBoxPainter::paintFillLayer(const PaintInfo& paintInfo, | 72 void InlineFlowBoxPainter::paintFillLayer(const PaintInfo& paintInfo, |
| 73 const Color& c, | 73 const Color& c, |
| 74 const FillLayer& fillLayer, | 74 const FillLayer& fillLayer, |
| 75 const LayoutRect& rect, | 75 const LayoutRect& rect, |
| 76 SkXfermode::Mode op) { | 76 SkXfermode::Mode op) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 } | 110 } |
| 111 | 111 |
| 112 void InlineFlowBoxPainter::paintBoxShadow(const PaintInfo& info, | 112 void InlineFlowBoxPainter::paintBoxShadow(const PaintInfo& info, |
| 113 const ComputedStyle& s, | 113 const ComputedStyle& s, |
| 114 ShadowStyle shadowStyle, | 114 ShadowStyle shadowStyle, |
| 115 const LayoutRect& paintRect) { | 115 const LayoutRect& paintRect) { |
| 116 if ((!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) || | 116 if ((!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) || |
| 117 !m_inlineFlowBox.parent()) { | 117 !m_inlineFlowBox.parent()) { |
| 118 BoxPainter::paintBoxShadow(info, paintRect, s, shadowStyle); | 118 BoxPainter::paintBoxShadow(info, paintRect, s, shadowStyle); |
| 119 } else { | 119 } else { |
| 120 // FIXME: We can do better here in the multi-line case. We want to push a cl
ip so that the shadow doesn't | 120 // FIXME: We can do better here in the multi-line case. We want to push a |
| 121 // protrude incorrectly at the edges, and we want to possibly include shadow
s cast from the previous/following lines | 121 // clip so that the shadow doesn't protrude incorrectly at the edges, and we |
| 122 // want to possibly include shadows cast from the previous/following lines |
| 122 BoxPainter::paintBoxShadow(info, paintRect, s, shadowStyle, | 123 BoxPainter::paintBoxShadow(info, paintRect, s, shadowStyle, |
| 123 m_inlineFlowBox.includeLogicalLeftEdge(), | 124 m_inlineFlowBox.includeLogicalLeftEdge(), |
| 124 m_inlineFlowBox.includeLogicalRightEdge()); | 125 m_inlineFlowBox.includeLogicalRightEdge()); |
| 125 } | 126 } |
| 126 } | 127 } |
| 127 | 128 |
| 128 static LayoutRect clipRectForNinePieceImageStrip(const InlineFlowBox& box, | 129 static LayoutRect clipRectForNinePieceImageStrip(const InlineFlowBox& box, |
| 129 const NinePieceImage& image, | 130 const NinePieceImage& image, |
| 130 const LayoutRect& paintRect) { | 131 const LayoutRect& paintRect) { |
| 131 LayoutRect clipRect(paintRect); | 132 LayoutRect clipRect(paintRect); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 152 } | 153 } |
| 153 return clipRect; | 154 return clipRect; |
| 154 } | 155 } |
| 155 | 156 |
| 156 LayoutRect InlineFlowBoxPainter::paintRectForImageStrip( | 157 LayoutRect InlineFlowBoxPainter::paintRectForImageStrip( |
| 157 const LayoutPoint& paintOffset, | 158 const LayoutPoint& paintOffset, |
| 158 const LayoutSize& frameSize, | 159 const LayoutSize& frameSize, |
| 159 TextDirection direction) const { | 160 TextDirection direction) const { |
| 160 // We have a fill/border/mask image that spans multiple lines. | 161 // We have a fill/border/mask image that spans multiple lines. |
| 161 // We need to adjust the offset by the width of all previous lines. | 162 // We need to adjust the offset by the width of all previous lines. |
| 162 // Think of background painting on inlines as though you had one long line, a
single continuous | 163 // Think of background painting on inlines as though you had one long line, a |
| 163 // strip. Even though that strip has been broken up across multiple lines, you
still paint it | 164 // single continuous strip. Even though that strip has been broken up across |
| 164 // as though you had one single line. This means each line has to pick up the
background where | 165 // multiple lines, you still paint it as though you had one single line. This |
| 165 // the previous line left off. | 166 // means each line has to pick up the background where the previous line left |
| 167 // off. |
| 166 LayoutUnit logicalOffsetOnLine; | 168 LayoutUnit logicalOffsetOnLine; |
| 167 LayoutUnit totalLogicalWidth; | 169 LayoutUnit totalLogicalWidth; |
| 168 if (direction == LTR) { | 170 if (direction == LTR) { |
| 169 for (const InlineFlowBox* curr = m_inlineFlowBox.prevLineBox(); curr; | 171 for (const InlineFlowBox* curr = m_inlineFlowBox.prevLineBox(); curr; |
| 170 curr = curr->prevLineBox()) | 172 curr = curr->prevLineBox()) |
| 171 logicalOffsetOnLine += curr->logicalWidth(); | 173 logicalOffsetOnLine += curr->logicalWidth(); |
| 172 totalLogicalWidth = logicalOffsetOnLine; | 174 totalLogicalWidth = logicalOffsetOnLine; |
| 173 for (const InlineFlowBox* curr = &m_inlineFlowBox; curr; | 175 for (const InlineFlowBox* curr = &m_inlineFlowBox; curr; |
| 174 curr = curr->nextLineBox()) | 176 curr = curr->nextLineBox()) |
| 175 totalLogicalWidth += curr->logicalWidth(); | 177 totalLogicalWidth += curr->logicalWidth(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 201 adjustedClipRect = pixelSnappedIntRect(adjustedFrameRect); | 203 adjustedClipRect = pixelSnappedIntRect(adjustedFrameRect); |
| 202 if (m_inlineFlowBox.parent() && | 204 if (m_inlineFlowBox.parent() && |
| 203 m_inlineFlowBox.getLineLayoutItem().style()->hasBorderDecoration()) { | 205 m_inlineFlowBox.getLineLayoutItem().style()->hasBorderDecoration()) { |
| 204 const NinePieceImage& borderImage = | 206 const NinePieceImage& borderImage = |
| 205 m_inlineFlowBox.getLineLayoutItem().style()->borderImage(); | 207 m_inlineFlowBox.getLineLayoutItem().style()->borderImage(); |
| 206 StyleImage* borderImageSource = borderImage.image(); | 208 StyleImage* borderImageSource = borderImage.image(); |
| 207 bool hasBorderImage = borderImageSource && borderImageSource->canRender(); | 209 bool hasBorderImage = borderImageSource && borderImageSource->canRender(); |
| 208 if (hasBorderImage && !borderImageSource->isLoaded()) | 210 if (hasBorderImage && !borderImageSource->isLoaded()) |
| 209 return DontPaintBorders; | 211 return DontPaintBorders; |
| 210 | 212 |
| 211 // The simple case is where we either have no border image or we are the onl
y box for this object. | 213 // The simple case is where we either have no border image or we are the |
| 212 // In those cases only a single call to draw is required. | 214 // only box for this object. In those cases only a single call to draw is |
| 215 // required. |
| 213 if (!hasBorderImage || | 216 if (!hasBorderImage || |
| 214 (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox())) | 217 (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox())) |
| 215 return PaintBordersWithoutClip; | 218 return PaintBordersWithoutClip; |
| 216 | 219 |
| 217 // We have a border image that spans multiple lines. | 220 // We have a border image that spans multiple lines. |
| 218 adjustedClipRect = pixelSnappedIntRect(clipRectForNinePieceImageStrip( | 221 adjustedClipRect = pixelSnappedIntRect(clipRectForNinePieceImageStrip( |
| 219 m_inlineFlowBox, borderImage, adjustedFrameRect)); | 222 m_inlineFlowBox, borderImage, adjustedFrameRect)); |
| 220 return PaintBordersWithClip; | 223 return PaintBordersWithClip; |
| 221 } | 224 } |
| 222 return DontPaintBorders; | 225 return DontPaintBorders; |
| 223 } | 226 } |
| 224 | 227 |
| 225 void InlineFlowBoxPainter::paintBoxDecorationBackground( | 228 void InlineFlowBoxPainter::paintBoxDecorationBackground( |
| 226 const PaintInfo& paintInfo, | 229 const PaintInfo& paintInfo, |
| 227 const LayoutPoint& paintOffset, | 230 const LayoutPoint& paintOffset, |
| 228 const LayoutRect& cullRect) { | 231 const LayoutRect& cullRect) { |
| 229 ASSERT(paintInfo.phase == PaintPhaseForeground); | 232 ASSERT(paintInfo.phase == PaintPhaseForeground); |
| 230 if (m_inlineFlowBox.getLineLayoutItem().style()->visibility() != | 233 if (m_inlineFlowBox.getLineLayoutItem().style()->visibility() != |
| 231 EVisibility::Visible) | 234 EVisibility::Visible) |
| 232 return; | 235 return; |
| 233 | 236 |
| 234 // You can use p::first-line to specify a background. If so, the root line box
es for | 237 // You can use p::first-line to specify a background. If so, the root line |
| 235 // a line may actually have to paint a background. | 238 // boxes for a line may actually have to paint a background. |
| 236 LayoutObject* inlineFlowBoxLayoutObject = | 239 LayoutObject* inlineFlowBoxLayoutObject = |
| 237 LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.getLineLayoutItem()); | 240 LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.getLineLayoutItem()); |
| 238 const ComputedStyle* styleToUse = m_inlineFlowBox.getLineLayoutItem().style( | 241 const ComputedStyle* styleToUse = m_inlineFlowBox.getLineLayoutItem().style( |
| 239 m_inlineFlowBox.isFirstLineStyle()); | 242 m_inlineFlowBox.isFirstLineStyle()); |
| 240 bool shouldPaintBoxDecorationBackground; | 243 bool shouldPaintBoxDecorationBackground; |
| 241 if (m_inlineFlowBox.parent()) | 244 if (m_inlineFlowBox.parent()) |
| 242 shouldPaintBoxDecorationBackground = | 245 shouldPaintBoxDecorationBackground = |
| 243 inlineFlowBoxLayoutObject->hasBoxDecorationBackground(); | 246 inlineFlowBoxLayoutObject->hasBoxDecorationBackground(); |
| 244 else | 247 else |
| 245 shouldPaintBoxDecorationBackground = | 248 shouldPaintBoxDecorationBackground = |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 BoxPainter::paintBorder( | 293 BoxPainter::paintBorder( |
| 291 *toLayoutBoxModelObject(LineLayoutAPIShim::layoutObjectFrom( | 294 *toLayoutBoxModelObject(LineLayoutAPIShim::layoutObjectFrom( |
| 292 m_inlineFlowBox.boxModelObject())), | 295 m_inlineFlowBox.boxModelObject())), |
| 293 paintInfo, adjustedFrameRect, | 296 paintInfo, adjustedFrameRect, |
| 294 m_inlineFlowBox.getLineLayoutItem().styleRef( | 297 m_inlineFlowBox.getLineLayoutItem().styleRef( |
| 295 m_inlineFlowBox.isFirstLineStyle()), | 298 m_inlineFlowBox.isFirstLineStyle()), |
| 296 BackgroundBleedNone, m_inlineFlowBox.includeLogicalLeftEdge(), | 299 BackgroundBleedNone, m_inlineFlowBox.includeLogicalLeftEdge(), |
| 297 m_inlineFlowBox.includeLogicalRightEdge()); | 300 m_inlineFlowBox.includeLogicalRightEdge()); |
| 298 break; | 301 break; |
| 299 case PaintBordersWithClip: | 302 case PaintBordersWithClip: |
| 300 // FIXME: What the heck do we do with RTL here? The math we're using is ob
viously not right, | 303 // FIXME: What the heck do we do with RTL here? The math we're using is |
| 301 // but it isn't even clear how this should work at all. | 304 // obviously not right, but it isn't even clear how this should work at |
| 305 // all. |
| 302 LayoutRect imageStripPaintRect = | 306 LayoutRect imageStripPaintRect = |
| 303 paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); | 307 paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); |
| 304 GraphicsContextStateSaver stateSaver(paintInfo.context); | 308 GraphicsContextStateSaver stateSaver(paintInfo.context); |
| 305 paintInfo.context.clip(adjustedClipRect); | 309 paintInfo.context.clip(adjustedClipRect); |
| 306 BoxPainter::paintBorder( | 310 BoxPainter::paintBorder( |
| 307 *toLayoutBoxModelObject(LineLayoutAPIShim::layoutObjectFrom( | 311 *toLayoutBoxModelObject(LineLayoutAPIShim::layoutObjectFrom( |
| 308 m_inlineFlowBox.boxModelObject())), | 312 m_inlineFlowBox.boxModelObject())), |
| 309 paintInfo, imageStripPaintRect, | 313 paintInfo, imageStripPaintRect, |
| 310 m_inlineFlowBox.getLineLayoutItem().styleRef( | 314 m_inlineFlowBox.getLineLayoutItem().styleRef( |
| 311 m_inlineFlowBox.isFirstLineStyle())); | 315 m_inlineFlowBox.isFirstLineStyle())); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 if (!compositedMask || flattenCompositingLayers) { | 347 if (!compositedMask || flattenCompositingLayers) { |
| 344 if ((maskBoxImage && | 348 if ((maskBoxImage && |
| 345 m_inlineFlowBox.getLineLayoutItem() | 349 m_inlineFlowBox.getLineLayoutItem() |
| 346 .style() | 350 .style() |
| 347 ->maskLayers() | 351 ->maskLayers() |
| 348 .hasImage()) || | 352 .hasImage()) || |
| 349 m_inlineFlowBox.getLineLayoutItem().style()->maskLayers().next()) { | 353 m_inlineFlowBox.getLineLayoutItem().style()->maskLayers().next()) { |
| 350 pushTransparencyLayer = true; | 354 pushTransparencyLayer = true; |
| 351 paintInfo.context.beginLayer(1.0f, SkXfermode::kDstIn_Mode); | 355 paintInfo.context.beginLayer(1.0f, SkXfermode::kDstIn_Mode); |
| 352 } else { | 356 } else { |
| 353 // TODO(fmalita): passing a dst-in xfer mode down to paintFillLayers/paint
NinePieceImage | 357 // TODO(fmalita): passing a dst-in xfer mode down to |
| 354 // seems dangerous: it is only correct if applied atomically (single dra
w call). While | 358 // paintFillLayers/paintNinePieceImage seems dangerous: it is only correct |
| 355 // the heuristic above presumably ensures that is the case, this approac
h seems super | 359 // if applied atomically (single draw call). While the heuristic above |
| 356 // fragile. We should investigate dropping this optimization in favour o
f the more | 360 // presumably ensures that is the case, this approach seems super fragile. |
| 357 // robust layer branch above. | 361 // We should investigate dropping this optimization in favour of the more |
| 362 // robust layer branch above. |
| 358 compositeOp = SkXfermode::kDstIn_Mode; | 363 compositeOp = SkXfermode::kDstIn_Mode; |
| 359 } | 364 } |
| 360 } | 365 } |
| 361 | 366 |
| 362 LayoutRect paintRect = LayoutRect(adjustedPaintOffset, frameRect.size()); | 367 LayoutRect paintRect = LayoutRect(adjustedPaintOffset, frameRect.size()); |
| 363 paintFillLayers(paintInfo, Color::transparent, | 368 paintFillLayers(paintInfo, Color::transparent, |
| 364 m_inlineFlowBox.getLineLayoutItem().style()->maskLayers(), | 369 m_inlineFlowBox.getLineLayoutItem().style()->maskLayers(), |
| 365 paintRect, compositeOp); | 370 paintRect, compositeOp); |
| 366 | 371 |
| 367 bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(); | 372 bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(); |
| 368 if (!hasBoxImage || !maskBoxImage->isLoaded()) { | 373 if (!hasBoxImage || !maskBoxImage->isLoaded()) { |
| 369 if (pushTransparencyLayer) | 374 if (pushTransparencyLayer) |
| 370 paintInfo.context.endLayer(); | 375 paintInfo.context.endLayer(); |
| 371 return; // Don't paint anything while we wait for the image to load. | 376 return; // Don't paint anything while we wait for the image to load. |
| 372 } | 377 } |
| 373 | 378 |
| 374 LayoutBoxModelObject* boxModel = toLayoutBoxModelObject( | 379 LayoutBoxModelObject* boxModel = toLayoutBoxModelObject( |
| 375 LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.boxModelObject())); | 380 LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.boxModelObject())); |
| 376 // The simple case is where we are the only box for this object. In those | 381 // The simple case is where we are the only box for this object. In those |
| 377 // cases only a single call to draw is required. | 382 // cases only a single call to draw is required. |
| 378 if (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) { | 383 if (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) { |
| 379 BoxPainter::paintNinePieceImage( | 384 BoxPainter::paintNinePieceImage( |
| 380 *boxModel, paintInfo.context, paintRect, | 385 *boxModel, paintInfo.context, paintRect, |
| 381 m_inlineFlowBox.getLineLayoutItem().styleRef(), maskNinePieceImage, | 386 m_inlineFlowBox.getLineLayoutItem().styleRef(), maskNinePieceImage, |
| 382 compositeOp); | 387 compositeOp); |
| 383 } else { | 388 } else { |
| 384 // We have a mask image that spans multiple lines. | 389 // We have a mask image that spans multiple lines. |
| 385 // FIXME: What the heck do we do with RTL here? The math we're using is obvi
ously not right, | 390 // FIXME: What the heck do we do with RTL here? The math we're using is |
| 386 // but it isn't even clear how this should work at all. | 391 // obviously not right, but it isn't even clear how this should work at all. |
| 387 LayoutRect imageStripPaintRect = | 392 LayoutRect imageStripPaintRect = |
| 388 paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); | 393 paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); |
| 389 FloatRect clipRect(clipRectForNinePieceImageStrip( | 394 FloatRect clipRect(clipRectForNinePieceImageStrip( |
| 390 m_inlineFlowBox, maskNinePieceImage, paintRect)); | 395 m_inlineFlowBox, maskNinePieceImage, paintRect)); |
| 391 GraphicsContextStateSaver stateSaver(paintInfo.context); | 396 GraphicsContextStateSaver stateSaver(paintInfo.context); |
| 392 // TODO(chrishtr): this should be pixel-snapped. | 397 // TODO(chrishtr): this should be pixel-snapped. |
| 393 paintInfo.context.clip(clipRect); | 398 paintInfo.context.clip(clipRect); |
| 394 BoxPainter::paintNinePieceImage( | 399 BoxPainter::paintNinePieceImage( |
| 395 *boxModel, paintInfo.context, imageStripPaintRect, | 400 *boxModel, paintInfo.context, imageStripPaintRect, |
| 396 m_inlineFlowBox.getLineLayoutItem().styleRef(), maskNinePieceImage, | 401 m_inlineFlowBox.getLineLayoutItem().styleRef(), maskNinePieceImage, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 425 rect.setHeight(logicalHeight); | 430 rect.setHeight(logicalHeight); |
| 426 } else { | 431 } else { |
| 427 rect.setX(logicalTop); | 432 rect.setX(logicalTop); |
| 428 rect.setWidth(logicalHeight); | 433 rect.setWidth(logicalHeight); |
| 429 } | 434 } |
| 430 } | 435 } |
| 431 return rect; | 436 return rect; |
| 432 } | 437 } |
| 433 | 438 |
| 434 } // namespace blink | 439 } // namespace blink |
| OLD | NEW |