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 |