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 "config.h" | 5 #include "config.h" |
6 #include "core/paint/BoxPainter.h" | 6 #include "core/paint/BoxPainter.h" |
7 | 7 |
8 #include "core/HTMLNames.h" | 8 #include "core/HTMLNames.h" |
9 #include "core/frame/Settings.h" | 9 #include "core/frame/Settings.h" |
10 #include "core/html/HTMLFrameOwnerElement.h" | 10 #include "core/html/HTMLFrameOwnerElement.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 } // anonymous namespace | 74 } // anonymous namespace |
75 | 75 |
76 void BoxPainter::paintBoxDecorationBackgroundWithRect(const PaintInfo& paintInfo
, const LayoutPoint& paintOffset, const LayoutRect& paintRect) | 76 void BoxPainter::paintBoxDecorationBackgroundWithRect(const PaintInfo& paintInfo
, const LayoutPoint& paintOffset, const LayoutRect& paintRect) |
77 { | 77 { |
78 const ComputedStyle& style = m_layoutBox.styleRef(); | 78 const ComputedStyle& style = m_layoutBox.styleRef(); |
79 | 79 |
80 // FIXME: For now we don't have notification on media buffered range change
from media player | 80 // FIXME: For now we don't have notification on media buffered range change
from media player |
81 // and miss paint invalidation on buffered range change. crbug.com/484288. | 81 // and miss paint invalidation on buffered range change. crbug.com/484288. |
82 Optional<DisplayItemCacheSkipper> cacheSkipper; | 82 Optional<DisplayItemCacheSkipper> cacheSkipper; |
83 if (style.appearance() == MediaSliderPart) | 83 if (style.appearance() == MediaSliderPart) |
84 cacheSkipper.emplace(*paintInfo.context); | 84 cacheSkipper.emplace(paintInfo.context); |
85 | 85 |
86 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.conte
xt, m_layoutBox, DisplayItem::BoxDecorationBackground, paintOffset)) | 86 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.contex
t, m_layoutBox, DisplayItem::BoxDecorationBackground, paintOffset)) |
87 return; | 87 return; |
88 | 88 |
89 LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutBox, Displa
yItem::BoxDecorationBackground, boundsForDrawingRecorder(paintOffset), paintOffs
et); | 89 LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutBox, Display
Item::BoxDecorationBackground, boundsForDrawingRecorder(paintOffset), paintOffse
t); |
90 | 90 |
91 BoxDecorationData boxDecorationData(m_layoutBox); | 91 BoxDecorationData boxDecorationData(m_layoutBox); |
92 | 92 |
93 // FIXME: Should eventually give the theme control over whether the box shad
ow should paint, since controls could have | 93 // FIXME: Should eventually give the theme control over whether the box shad
ow should paint, since controls could have |
94 // custom shadows of their own. | 94 // custom shadows of their own. |
95 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground(boxDecorationData.blee
dAvoidance)) | 95 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground(boxDecorationData.blee
dAvoidance)) |
96 paintBoxShadow(paintInfo, paintRect, style, Normal); | 96 paintBoxShadow(paintInfo, paintRect, style, Normal); |
97 | 97 |
98 GraphicsContextStateSaver stateSaver(*paintInfo.context, false); | 98 GraphicsContextStateSaver stateSaver(paintInfo.context, false); |
99 if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { | 99 if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { |
100 | 100 |
101 stateSaver.save(); | 101 stateSaver.save(); |
102 FloatRoundedRect border = style.getRoundedBorderFor(paintRect); | 102 FloatRoundedRect border = style.getRoundedBorderFor(paintRect); |
103 paintInfo.context->clipRoundedRect(border); | 103 paintInfo.context.clipRoundedRect(border); |
104 | 104 |
105 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) | 105 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) |
106 paintInfo.context->beginLayer(); | 106 paintInfo.context.beginLayer(); |
107 } | 107 } |
108 | 108 |
109 // If we have a native theme appearance, paint that before painting our back
ground. | 109 // If we have a native theme appearance, paint that before painting our back
ground. |
110 // The theme will tell us whether or not we should also paint the CSS backgr
ound. | 110 // The theme will tell us whether or not we should also paint the CSS backgr
ound. |
111 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); | 111 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); |
112 ThemePainter& themePainter = LayoutTheme::theme().painter(); | 112 ThemePainter& themePainter = LayoutTheme::theme().painter(); |
113 bool themePainted = boxDecorationData.hasAppearance && !themePainter.paint(m
_layoutBox, paintInfo, snappedPaintRect); | 113 bool themePainted = boxDecorationData.hasAppearance && !themePainter.paint(m
_layoutBox, paintInfo, snappedPaintRect); |
114 if (!themePainted) { | 114 if (!themePainted) { |
115 paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor,
boxDecorationData.bleedAvoidance); | 115 paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor,
boxDecorationData.bleedAvoidance); |
116 | 116 |
117 if (boxDecorationData.hasAppearance) | 117 if (boxDecorationData.hasAppearance) |
118 themePainter.paintDecorations(m_layoutBox, paintInfo, snappedPaintRe
ct); | 118 themePainter.paintDecorations(m_layoutBox, paintInfo, snappedPaintRe
ct); |
119 } | 119 } |
120 paintBoxShadow(paintInfo, paintRect, style, Inset); | 120 paintBoxShadow(paintInfo, paintRect, style, Inset); |
121 | 121 |
122 // The theme will tell us whether or not we should also paint the CSS border
. | 122 // The theme will tell us whether or not we should also paint the CSS border
. |
123 if (boxDecorationData.hasBorderDecoration | 123 if (boxDecorationData.hasBorderDecoration |
124 && (!boxDecorationData.hasAppearance || (!themePainted && LayoutTheme::t
heme().painter().paintBorderOnly(m_layoutBox, paintInfo, snappedPaintRect))) | 124 && (!boxDecorationData.hasAppearance || (!themePainted && LayoutTheme::t
heme().painter().paintBorderOnly(m_layoutBox, paintInfo, snappedPaintRect))) |
125 && !(m_layoutBox.isTable() && toLayoutTable(&m_layoutBox)->collapseBorde
rs())) | 125 && !(m_layoutBox.isTable() && toLayoutTable(&m_layoutBox)->collapseBorde
rs())) |
126 paintBorder(m_layoutBox, paintInfo, paintRect, style, boxDecorationData.
bleedAvoidance); | 126 paintBorder(m_layoutBox, paintInfo, paintRect, style, boxDecorationData.
bleedAvoidance); |
127 | 127 |
128 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) | 128 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) |
129 paintInfo.context->endLayer(); | 129 paintInfo.context.endLayer(); |
130 } | 130 } |
131 | 131 |
132 void BoxPainter::paintBackground(const PaintInfo& paintInfo, const LayoutRect& p
aintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance) | 132 void BoxPainter::paintBackground(const PaintInfo& paintInfo, const LayoutRect& p
aintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance) |
133 { | 133 { |
134 if (m_layoutBox.isDocumentElement()) | 134 if (m_layoutBox.isDocumentElement()) |
135 return; | 135 return; |
136 if (m_layoutBox.backgroundStolenForBeingBody()) | 136 if (m_layoutBox.backgroundStolenForBeingBody()) |
137 return; | 137 return; |
138 if (m_layoutBox.boxDecorationBackgroundIsKnownToBeObscured()) | 138 if (m_layoutBox.boxDecorationBackgroundIsKnownToBeObscured()) |
139 return; | 139 return; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 for (auto currentLayer = &fillLayer; currentLayer; currentLayer = curren
tLayer->next()) { | 192 for (auto currentLayer = &fillLayer; currentLayer; currentLayer = curren
tLayer->next()) { |
193 reversedPaintList.append(currentLayer); | 193 reversedPaintList.append(currentLayer); |
194 if (currentLayer->composite() != CompositeSourceOver || currentLayer
->blendMode() != WebBlendModeNormal) | 194 if (currentLayer->composite() != CompositeSourceOver || currentLayer
->blendMode() != WebBlendModeNormal) |
195 shouldDrawBackgroundInSeparateBuffer = true; | 195 shouldDrawBackgroundInSeparateBuffer = true; |
196 } | 196 } |
197 } | 197 } |
198 | 198 |
199 // TODO(trchen): We can optimize out isolation group if we have a non-transp
arent | 199 // TODO(trchen): We can optimize out isolation group if we have a non-transp
arent |
200 // background color and the bottom layer encloses all other layers. | 200 // background color and the bottom layer encloses all other layers. |
201 | 201 |
202 GraphicsContext* context = paintInfo.context; | 202 GraphicsContext& context = paintInfo.context; |
203 if (!context) | |
204 shouldDrawBackgroundInSeparateBuffer = false; | |
205 | 203 |
206 if (shouldDrawBackgroundInSeparateBuffer) | 204 if (shouldDrawBackgroundInSeparateBuffer) |
207 context->beginLayer(); | 205 context.beginLayer(); |
208 | 206 |
209 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); +
+it) | 207 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); +
+it) |
210 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO
bject); | 208 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO
bject); |
211 | 209 |
212 if (shouldDrawBackgroundInSeparateBuffer) | 210 if (shouldDrawBackgroundInSeparateBuffer) |
213 context->endLayer(); | 211 context.endLayer(); |
214 } | 212 } |
215 | 213 |
216 void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, cons
t FillLayer& fillLayer, const LayoutRect& rect, | 214 void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, cons
t FillLayer& fillLayer, const LayoutRect& rect, |
217 BackgroundBleedAvoidance bleedAvoidance, SkXfermode::Mode op, const LayoutOb
ject* backgroundObject) | 215 BackgroundBleedAvoidance bleedAvoidance, SkXfermode::Mode op, const LayoutOb
ject* backgroundObject) |
218 { | 216 { |
219 BoxPainter::paintFillLayerExtended(m_layoutBox, paintInfo, c, fillLayer, rec
t, bleedAvoidance, 0, LayoutSize(), op, backgroundObject); | 217 BoxPainter::paintFillLayerExtended(m_layoutBox, paintInfo, c, fillLayer, rec
t, bleedAvoidance, 0, LayoutSize(), op, backgroundObject); |
220 } | 218 } |
221 | 219 |
222 void BoxPainter::applyBoxShadowForBackground(GraphicsContext* context, const Lay
outObject& obj) | 220 void BoxPainter::applyBoxShadowForBackground(GraphicsContext& context, const Lay
outObject& obj) |
223 { | 221 { |
224 const ShadowList* shadowList = obj.style()->boxShadow(); | 222 const ShadowList* shadowList = obj.style()->boxShadow(); |
225 ASSERT(shadowList); | 223 ASSERT(shadowList); |
226 for (size_t i = shadowList->shadows().size(); i--; ) { | 224 for (size_t i = shadowList->shadows().size(); i--; ) { |
227 const ShadowData& boxShadow = shadowList->shadows()[i]; | 225 const ShadowData& boxShadow = shadowList->shadows()[i]; |
228 if (boxShadow.style() != Normal) | 226 if (boxShadow.style() != Normal) |
229 continue; | 227 continue; |
230 FloatSize shadowOffset(boxShadow.x(), boxShadow.y()); | 228 FloatSize shadowOffset(boxShadow.x(), boxShadow.y()); |
231 context->setShadow(shadowOffset, boxShadow.blur(), | 229 context.setShadow(shadowOffset, boxShadow.blur(), |
232 boxShadow.color().resolve(obj.resolveColor(CSSPropertyColor)), | 230 boxShadow.color().resolve(obj.resolveColor(CSSPropertyColor)), |
233 DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::Shad
owIgnoresAlpha); | 231 DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::Shad
owIgnoresAlpha); |
234 return; | 232 return; |
235 } | 233 } |
236 } | 234 } |
237 | 235 |
238 FloatRoundedRect BoxPainter::getBackgroundRoundedRect(const LayoutObject& obj, c
onst LayoutRect& borderRect, | 236 FloatRoundedRect BoxPainter::getBackgroundRoundedRect(const LayoutObject& obj, c
onst LayoutRect& borderRect, |
239 const InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHei
ght, | 237 const InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHei
ght, |
240 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) | 238 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) |
241 { | 239 { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 FloatRoundedRect::Radii insetRadii(backgroundRoundedRect.radii()); | 281 FloatRoundedRect::Radii insetRadii(backgroundRoundedRect.radii()); |
284 insetRadii.shrink(-insets.top(), -insets.bottom(), -insets.left(), -inse
ts.right()); | 282 insetRadii.shrink(-insets.top(), -insets.bottom(), -insets.left(), -inse
ts.right()); |
285 return FloatRoundedRect(insetRect, insetRadii); | 283 return FloatRoundedRect(insetRect, insetRadii); |
286 } | 284 } |
287 | 285 |
288 return getBackgroundRoundedRect(obj, borderRect, box, boxSize.width(), boxSi
ze.height(), includeLogicalLeftEdge, includeLogicalRightEdge); | 286 return getBackgroundRoundedRect(obj, borderRect, box, boxSize.width(), boxSi
ze.height(), includeLogicalLeftEdge, includeLogicalRightEdge); |
289 } | 287 } |
290 | 288 |
291 void BoxPainter::paintFillLayerExtended(const LayoutBoxModelObject& obj, const P
aintInfo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutR
ect& rect, BackgroundBleedAvoidance bleedAvoidance, const InlineFlowBox* box, co
nst LayoutSize& boxSize, SkXfermode::Mode op, const LayoutObject* backgroundObje
ct) | 289 void BoxPainter::paintFillLayerExtended(const LayoutBoxModelObject& obj, const P
aintInfo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutR
ect& rect, BackgroundBleedAvoidance bleedAvoidance, const InlineFlowBox* box, co
nst LayoutSize& boxSize, SkXfermode::Mode op, const LayoutObject* backgroundObje
ct) |
292 { | 290 { |
293 GraphicsContext* context = paintInfo.context; | 291 GraphicsContext& context = paintInfo.context; |
294 if (rect.isEmpty()) | 292 if (rect.isEmpty()) |
295 return; | 293 return; |
296 | 294 |
297 bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true; | 295 bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true; |
298 bool includeRightEdge = box ? box->includeLogicalRightEdge() : true; | 296 bool includeRightEdge = box ? box->includeLogicalRightEdge() : true; |
299 | 297 |
300 bool hasRoundedBorder = obj.style()->hasBorderRadius() && (includeLeftEdge |
| includeRightEdge); | 298 bool hasRoundedBorder = obj.style()->hasBorderRadius() && (includeLeftEdge |
| includeRightEdge); |
301 bool clippedWithLocalScrolling = obj.hasOverflowClip() && bgLayer.attachment
() == LocalBackgroundAttachment; | 299 bool clippedWithLocalScrolling = obj.hasOverflowClip() && bgLayer.attachment
() == LocalBackgroundAttachment; |
302 bool isBorderFill = bgLayer.clip() == BorderFillBox; | 300 bool isBorderFill = bgLayer.clip() == BorderFillBox; |
303 bool isBottomLayer = !bgLayer.next(); | 301 bool isBottomLayer = !bgLayer.next(); |
(...skipping 18 matching lines...) Expand all Loading... |
322 bgImage = nullptr; | 320 bgImage = nullptr; |
323 } | 321 } |
324 } | 322 } |
325 | 323 |
326 // Fast path for drawing simple color backgrounds. | 324 // Fast path for drawing simple color backgrounds. |
327 if (!clippedWithLocalScrolling && !bgImage && isBorderFill && isBottomLayer)
{ | 325 if (!clippedWithLocalScrolling && !bgImage && isBorderFill && isBottomLayer)
{ |
328 if (!bgColor.alpha()) | 326 if (!bgColor.alpha()) |
329 return; | 327 return; |
330 | 328 |
331 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied
ToBackground(bleedAvoidance, box); | 329 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied
ToBackground(bleedAvoidance, box); |
332 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAp
pliedToBackground); | 330 GraphicsContextStateSaver shadowStateSaver(context, boxShadowShouldBeApp
liedToBackground); |
333 if (boxShadowShouldBeAppliedToBackground) | 331 if (boxShadowShouldBeAppliedToBackground) |
334 BoxPainter::applyBoxShadowForBackground(context, obj); | 332 BoxPainter::applyBoxShadowForBackground(context, obj); |
335 | 333 |
336 if (hasRoundedBorder && !bleedAvoidanceIsClipping(bleedAvoidance)) { | 334 if (hasRoundedBorder && !bleedAvoidanceIsClipping(bleedAvoidance)) { |
337 FloatRoundedRect border = backgroundRoundedRectAdjustedForBleedAvoid
ance(obj, rect, | 335 FloatRoundedRect border = backgroundRoundedRectAdjustedForBleedAvoid
ance(obj, rect, |
338 bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge)
; | 336 bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge)
; |
339 | 337 |
340 if (border.isRenderable()) { | 338 if (border.isRenderable()) { |
341 context->fillRoundedRect(border, bgColor); | 339 context.fillRoundedRect(border, bgColor); |
342 } else { | 340 } else { |
343 RoundedInnerRectClipper clipper(obj, paintInfo, rect, border, Ap
plyToContext); | 341 RoundedInnerRectClipper clipper(obj, paintInfo, rect, border, Ap
plyToContext); |
344 context->fillRect(border.rect(), bgColor); | 342 context.fillRect(border.rect(), bgColor); |
345 } | 343 } |
346 } else { | 344 } else { |
347 context->fillRect(pixelSnappedIntRect(rect), bgColor); | 345 context.fillRect(pixelSnappedIntRect(rect), bgColor); |
348 } | 346 } |
349 | 347 |
350 return; | 348 return; |
351 } | 349 } |
352 | 350 |
353 // BorderFillBox radius clipping is taken care of by BackgroundBleedClip{Onl
y,Layer} | 351 // BorderFillBox radius clipping is taken care of by BackgroundBleedClip{Onl
y,Layer} |
354 bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidan
ceIsClipping(bleedAvoidance)); | 352 bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidan
ceIsClipping(bleedAvoidance)); |
355 Optional<RoundedInnerRectClipper> clipToBorder; | 353 Optional<RoundedInnerRectClipper> clipToBorder; |
356 if (clipToBorderRadius) { | 354 if (clipToBorderRadius) { |
357 FloatRoundedRect border = isBorderFill | 355 FloatRoundedRect border = isBorderFill |
(...skipping 14 matching lines...) Expand all Loading... |
372 } | 370 } |
373 | 371 |
374 clipToBorder.emplace(obj, paintInfo, rect, border, ApplyToContext); | 372 clipToBorder.emplace(obj, paintInfo, rect, border, ApplyToContext); |
375 } | 373 } |
376 | 374 |
377 int bLeft = includeLeftEdge ? obj.borderLeft() : 0; | 375 int bLeft = includeLeftEdge ? obj.borderLeft() : 0; |
378 int bRight = includeRightEdge ? obj.borderRight() : 0; | 376 int bRight = includeRightEdge ? obj.borderRight() : 0; |
379 LayoutUnit pLeft = includeLeftEdge ? obj.paddingLeft() : LayoutUnit(); | 377 LayoutUnit pLeft = includeLeftEdge ? obj.paddingLeft() : LayoutUnit(); |
380 LayoutUnit pRight = includeRightEdge ? obj.paddingRight() : LayoutUnit(); | 378 LayoutUnit pRight = includeRightEdge ? obj.paddingRight() : LayoutUnit(); |
381 | 379 |
382 GraphicsContextStateSaver clipWithScrollingStateSaver(*context, clippedWithL
ocalScrolling); | 380 GraphicsContextStateSaver clipWithScrollingStateSaver(context, clippedWithLo
calScrolling); |
383 LayoutRect scrolledPaintRect = rect; | 381 LayoutRect scrolledPaintRect = rect; |
384 if (clippedWithLocalScrolling) { | 382 if (clippedWithLocalScrolling) { |
385 // Clip to the overflow area. | 383 // Clip to the overflow area. |
386 const LayoutBox& thisBox = toLayoutBox(obj); | 384 const LayoutBox& thisBox = toLayoutBox(obj); |
387 // TODO(chrishtr): this should be pixel-snapped. | 385 // TODO(chrishtr): this should be pixel-snapped. |
388 context->clip(FloatRect(thisBox.overflowClipRect(rect.location()))); | 386 context.clip(FloatRect(thisBox.overflowClipRect(rect.location()))); |
389 | 387 |
390 // Adjust the paint rect to reflect a scrolled content box with borders
at the ends. | 388 // Adjust the paint rect to reflect a scrolled content box with borders
at the ends. |
391 IntSize offset = thisBox.scrolledContentOffset(); | 389 IntSize offset = thisBox.scrolledContentOffset(); |
392 scrolledPaintRect.move(-offset); | 390 scrolledPaintRect.move(-offset); |
393 scrolledPaintRect.setWidth(bLeft + thisBox.scrollWidth() + bRight); | 391 scrolledPaintRect.setWidth(bLeft + thisBox.scrollWidth() + bRight); |
394 scrolledPaintRect.setHeight(thisBox.borderTop() + thisBox.scrollHeight()
+ thisBox.borderBottom()); | 392 scrolledPaintRect.setHeight(thisBox.borderTop() + thisBox.scrollHeight()
+ thisBox.borderBottom()); |
395 } | 393 } |
396 | 394 |
397 GraphicsContextStateSaver backgroundClipStateSaver(*context, false); | 395 GraphicsContextStateSaver backgroundClipStateSaver(context, false); |
398 IntRect maskRect; | 396 IntRect maskRect; |
399 | 397 |
400 switch (bgLayer.clip()) { | 398 switch (bgLayer.clip()) { |
401 case PaddingFillBox: | 399 case PaddingFillBox: |
402 case ContentFillBox: { | 400 case ContentFillBox: { |
403 if (clipToBorderRadius) | 401 if (clipToBorderRadius) |
404 break; | 402 break; |
405 | 403 |
406 // Clip to the padding or content boxes as necessary. | 404 // Clip to the padding or content boxes as necessary. |
407 bool includePadding = bgLayer.clip() == ContentFillBox; | 405 bool includePadding = bgLayer.clip() == ContentFillBox; |
408 LayoutRect clipRect(scrolledPaintRect.x() + bLeft + (includePadding ? pL
eft : LayoutUnit()), | 406 LayoutRect clipRect(scrolledPaintRect.x() + bLeft + (includePadding ? pL
eft : LayoutUnit()), |
409 scrolledPaintRect.y() + obj.borderTop() + (includePadding ? obj.padd
ingTop() : LayoutUnit()), | 407 scrolledPaintRect.y() + obj.borderTop() + (includePadding ? obj.padd
ingTop() : LayoutUnit()), |
410 scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft
+ pRight : LayoutUnit()), | 408 scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft
+ pRight : LayoutUnit()), |
411 scrolledPaintRect.height() - obj.borderTop() - obj.borderBottom() -
(includePadding ? obj.paddingTop() + obj.paddingBottom() : LayoutUnit())); | 409 scrolledPaintRect.height() - obj.borderTop() - obj.borderBottom() -
(includePadding ? obj.paddingTop() + obj.paddingBottom() : LayoutUnit())); |
412 backgroundClipStateSaver.save(); | 410 backgroundClipStateSaver.save(); |
413 // TODO(chrishtr): this should be pixel-snapped. | 411 // TODO(chrishtr): this should be pixel-snapped. |
414 context->clip(FloatRect(clipRect)); | 412 context.clip(FloatRect(clipRect)); |
415 | 413 |
416 break; | 414 break; |
417 } | 415 } |
418 case TextFillBox: { | 416 case TextFillBox: { |
419 // First figure out how big the mask has to be. It should be no bigger t
han what we need | 417 // First figure out how big the mask has to be. It should be no bigger t
han what we need |
420 // to actually render, so we should intersect the dirty rect with the bo
rder box of the background. | 418 // to actually render, so we should intersect the dirty rect with the bo
rder box of the background. |
421 maskRect = pixelSnappedIntRect(rect); | 419 maskRect = pixelSnappedIntRect(rect); |
422 | 420 |
423 // We draw the background into a separate layer, to be later masked with
yet another layer | 421 // We draw the background into a separate layer, to be later masked with
yet another layer |
424 // holding the text content. | 422 // holding the text content. |
425 backgroundClipStateSaver.save(); | 423 backgroundClipStateSaver.save(); |
426 context->clip(maskRect); | 424 context.clip(maskRect); |
427 context->beginLayer(); | 425 context.beginLayer(); |
428 | 426 |
429 break; | 427 break; |
430 } | 428 } |
431 case BorderFillBox: | 429 case BorderFillBox: |
432 break; | 430 break; |
433 default: | 431 default: |
434 ASSERT_NOT_REACHED(); | 432 ASSERT_NOT_REACHED(); |
435 break; | 433 break; |
436 } | 434 } |
437 | 435 |
438 BackgroundImageGeometry geometry; | 436 BackgroundImageGeometry geometry; |
439 if (bgImage) | 437 if (bgImage) |
440 geometry.calculate(obj, paintInfo.paintContainer(), paintInfo.globalPain
tFlags(), bgLayer, scrolledPaintRect); | 438 geometry.calculate(obj, paintInfo.paintContainer(), paintInfo.globalPain
tFlags(), bgLayer, scrolledPaintRect); |
441 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(); | 439 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(); |
442 | 440 |
443 // Paint the color first underneath all images, culled if background image o
ccludes it. | 441 // Paint the color first underneath all images, culled if background image o
ccludes it. |
444 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the cu
lling test | 442 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the cu
lling test |
445 // by verifying whether the background image covers the entire painting area
. | 443 // by verifying whether the background image covers the entire painting area
. |
446 if (isBottomLayer) { | 444 if (isBottomLayer) { |
447 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); | 445 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); |
448 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied
ToBackground(bleedAvoidance, box); | 446 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied
ToBackground(bleedAvoidance, box); |
449 bool backgroundImageOccludesBackgroundColor = shouldPaintBackgroundImage
&& isFillLayerOpaque(bgLayer, obj); | 447 bool backgroundImageOccludesBackgroundColor = shouldPaintBackgroundImage
&& isFillLayerOpaque(bgLayer, obj); |
450 if (boxShadowShouldBeAppliedToBackground || !backgroundImageOccludesBack
groundColor) { | 448 if (boxShadowShouldBeAppliedToBackground || !backgroundImageOccludesBack
groundColor) { |
451 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShould
BeAppliedToBackground); | 449 GraphicsContextStateSaver shadowStateSaver(context, boxShadowShouldB
eAppliedToBackground); |
452 if (boxShadowShouldBeAppliedToBackground) | 450 if (boxShadowShouldBeAppliedToBackground) |
453 BoxPainter::applyBoxShadowForBackground(context, obj); | 451 BoxPainter::applyBoxShadowForBackground(context, obj); |
454 | 452 |
455 if (bgColor.alpha()) | 453 if (bgColor.alpha()) |
456 context->fillRect(backgroundRect, bgColor); | 454 context.fillRect(backgroundRect, bgColor); |
457 } | 455 } |
458 } | 456 } |
459 | 457 |
460 // no progressive loading of the background image | 458 // no progressive loading of the background image |
461 if (shouldPaintBackgroundImage) { | 459 if (shouldPaintBackgroundImage) { |
462 if (!geometry.destRect().isEmpty()) { | 460 if (!geometry.destRect().isEmpty()) { |
463 SkXfermode::Mode bgOp = WebCoreCompositeToSkiaComposite(bgLayer.comp
osite(), bgLayer.blendMode()); | 461 SkXfermode::Mode bgOp = WebCoreCompositeToSkiaComposite(bgLayer.comp
osite(), bgLayer.blendMode()); |
464 // if op != SkXfermode::kSrcOver_Mode, a mask is being painted. | 462 // if op != SkXfermode::kSrcOver_Mode, a mask is being painted. |
465 SkXfermode::Mode compositeOp = op == SkXfermode::kSrcOver_Mode ? bgO
p : op; | 463 SkXfermode::Mode compositeOp = op == SkXfermode::kSrcOver_Mode ? bgO
p : op; |
466 const LayoutObject* clientForBackgroundImage = backgroundObject ? ba
ckgroundObject : &obj; | 464 const LayoutObject* clientForBackgroundImage = backgroundObject ? ba
ckgroundObject : &obj; |
467 RefPtr<Image> image = bgImage->image(clientForBackgroundImage, floor
edIntSize(geometry.imageContainerSize()), obj.style()->effectiveZoom()); | 465 RefPtr<Image> image = bgImage->image(clientForBackgroundImage, floor
edIntSize(geometry.imageContainerSize()), obj.style()->effectiveZoom()); |
468 InterpolationQuality interpolationQuality = chooseInterpolationQuali
ty(*clientForBackgroundImage, context, image.get(), &bgLayer, LayoutSize(geometr
y.tileSize())); | 466 InterpolationQuality interpolationQuality = chooseInterpolationQuali
ty(*clientForBackgroundImage, image.get(), &bgLayer, LayoutSize(geometry.tileSiz
e())); |
469 if (bgLayer.maskSourceType() == MaskLuminance) | 467 if (bgLayer.maskSourceType() == MaskLuminance) |
470 context->setColorFilter(ColorFilterLuminanceToAlpha); | 468 context.setColorFilter(ColorFilterLuminanceToAlpha); |
471 InterpolationQuality previousInterpolationQuality = context->imageIn
terpolationQuality(); | 469 InterpolationQuality previousInterpolationQuality = context.imageInt
erpolationQuality(); |
472 context->setImageInterpolationQuality(interpolationQuality); | 470 context.setImageInterpolationQuality(interpolationQuality); |
473 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintI
mage", "data", InspectorPaintImageEvent::data(obj, *bgImage)); | 471 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintI
mage", "data", InspectorPaintImageEvent::data(obj, *bgImage)); |
474 context->drawTiledImage(image.get(), FloatRect(geometry.destRect()),
FloatPoint(geometry.phase()), FloatSize(geometry.tileSize()), | 472 context.drawTiledImage(image.get(), FloatRect(geometry.destRect()),
FloatPoint(geometry.phase()), FloatSize(geometry.tileSize()), |
475 compositeOp, FloatSize(geometry.spaceSize())); | 473 compositeOp, FloatSize(geometry.spaceSize())); |
476 context->setImageInterpolationQuality(previousInterpolationQuality); | 474 context.setImageInterpolationQuality(previousInterpolationQuality); |
477 } | 475 } |
478 } | 476 } |
479 | 477 |
480 if (bgLayer.clip() == TextFillBox) { | 478 if (bgLayer.clip() == TextFillBox) { |
481 // Create the text mask layer. | 479 // Create the text mask layer. |
482 context->beginLayer(1, SkXfermode::kDstIn_Mode); | 480 context.beginLayer(1, SkXfermode::kDstIn_Mode); |
483 | 481 |
484 // Now draw the text into the mask. We do this by painting using a speci
al paint phase that signals to | 482 // Now draw the text into the mask. We do this by painting using a speci
al paint phase that signals to |
485 // InlineTextBoxes that they should just add their contents to the clip. | 483 // InlineTextBoxes that they should just add their contents to the clip. |
486 PaintInfo info(context, maskRect, PaintPhaseTextClip, GlobalPaintNormalP
hase, 0); | 484 PaintInfo info(context, maskRect, PaintPhaseTextClip, GlobalPaintNormalP
hase, 0); |
487 if (box) { | 485 if (box) { |
488 const RootInlineBox& root = box->root(); | 486 const RootInlineBox& root = box->root(); |
489 box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrol
ledPaintRect.y() - box->y()), root.lineTop(), root.lineBottom()); | 487 box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrol
ledPaintRect.y() - box->y()), root.lineTop(), root.lineBottom()); |
490 } else { | 488 } else { |
491 // FIXME: this should only have an effect for the line box list with
in |obj|. Change this to create a LineBoxListPainter directly. | 489 // FIXME: this should only have an effect for the line box list with
in |obj|. Change this to create a LineBoxListPainter directly. |
492 LayoutSize localOffset = obj.isBox() ? toLayoutBox(&obj)->locationOf
fset() : LayoutSize(); | 490 LayoutSize localOffset = obj.isBox() ? toLayoutBox(&obj)->locationOf
fset() : LayoutSize(); |
493 obj.paint(info, scrolledPaintRect.location() - localOffset); | 491 obj.paint(info, scrolledPaintRect.location() - localOffset); |
494 } | 492 } |
495 | 493 |
496 context->endLayer(); | 494 context.endLayer(); |
497 context->endLayer(); | 495 context.endLayer(); |
498 } | 496 } |
499 } | 497 } |
500 | 498 |
501 void BoxPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintO
ffset) | 499 void BoxPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintO
ffset) |
502 { | 500 { |
503 if (!paintInfo.shouldPaintWithinRoot(&m_layoutBox) || m_layoutBox.style()->v
isibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) | 501 if (!paintInfo.shouldPaintWithinRoot(&m_layoutBox) || m_layoutBox.style()->v
isibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) |
504 return; | 502 return; |
505 | 503 |
506 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.conte
xt, m_layoutBox, paintInfo.phase, paintOffset)) | 504 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.contex
t, m_layoutBox, paintInfo.phase, paintOffset)) |
507 return; | 505 return; |
508 | 506 |
509 LayoutRect visualOverflowRect(m_layoutBox.visualOverflowRect()); | 507 LayoutRect visualOverflowRect(m_layoutBox.visualOverflowRect()); |
510 visualOverflowRect.moveBy(paintOffset); | 508 visualOverflowRect.moveBy(paintOffset); |
511 | 509 |
512 LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutBox, paintI
nfo.phase, visualOverflowRect, paintOffset); | 510 LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutBox, paintIn
fo.phase, visualOverflowRect, paintOffset); |
513 LayoutRect paintRect = LayoutRect(paintOffset, m_layoutBox.size()); | 511 LayoutRect paintRect = LayoutRect(paintOffset, m_layoutBox.size()); |
514 paintMaskImages(paintInfo, paintRect); | 512 paintMaskImages(paintInfo, paintRect); |
515 } | 513 } |
516 | 514 |
517 void BoxPainter::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& p
aintRect) | 515 void BoxPainter::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& p
aintRect) |
518 { | 516 { |
519 // Figure out if we need to push a transparency layer to render our mask. | 517 // Figure out if we need to push a transparency layer to render our mask. |
520 bool pushTransparencyLayer = false; | 518 bool pushTransparencyLayer = false; |
521 bool compositedMask = m_layoutBox.hasLayer() && m_layoutBox.layer()->hasComp
ositedMask(); | 519 bool compositedMask = m_layoutBox.hasLayer() && m_layoutBox.layer()->hasComp
ositedMask(); |
522 bool flattenCompositingLayers = paintInfo.globalPaintFlags() & GlobalPaintFl
attenCompositingLayers; | 520 bool flattenCompositingLayers = paintInfo.globalPaintFlags() & GlobalPaintFl
attenCompositingLayers; |
523 | 521 |
524 bool allMaskImagesLoaded = true; | 522 bool allMaskImagesLoaded = true; |
525 | 523 |
526 if (!compositedMask || flattenCompositingLayers) { | 524 if (!compositedMask || flattenCompositingLayers) { |
527 pushTransparencyLayer = true; | 525 pushTransparencyLayer = true; |
528 StyleImage* maskBoxImage = m_layoutBox.style()->maskBoxImage().image(); | 526 StyleImage* maskBoxImage = m_layoutBox.style()->maskBoxImage().image(); |
529 const FillLayer& maskLayers = m_layoutBox.style()->maskLayers(); | 527 const FillLayer& maskLayers = m_layoutBox.style()->maskLayers(); |
530 | 528 |
531 // Don't render a masked element until all the mask images have loaded,
to prevent a flash of unmasked content. | 529 // Don't render a masked element until all the mask images have loaded,
to prevent a flash of unmasked content. |
532 if (maskBoxImage) | 530 if (maskBoxImage) |
533 allMaskImagesLoaded &= maskBoxImage->isLoaded(); | 531 allMaskImagesLoaded &= maskBoxImage->isLoaded(); |
534 | 532 |
535 allMaskImagesLoaded &= maskLayers.imagesAreLoaded(); | 533 allMaskImagesLoaded &= maskLayers.imagesAreLoaded(); |
536 | 534 |
537 paintInfo.context->beginLayer(1, SkXfermode::kDstIn_Mode); | 535 paintInfo.context.beginLayer(1, SkXfermode::kDstIn_Mode); |
538 } | 536 } |
539 | 537 |
540 if (allMaskImagesLoaded) { | 538 if (allMaskImagesLoaded) { |
541 paintFillLayers(paintInfo, Color::transparent, m_layoutBox.style()->mask
Layers(), paintRect); | 539 paintFillLayers(paintInfo, Color::transparent, m_layoutBox.style()->mask
Layers(), paintRect); |
542 paintNinePieceImage(m_layoutBox, paintInfo.context, paintRect, m_layoutB
ox.styleRef(), m_layoutBox.style()->maskBoxImage()); | 540 paintNinePieceImage(m_layoutBox, paintInfo.context, paintRect, m_layoutB
ox.styleRef(), m_layoutBox.style()->maskBoxImage()); |
543 } | 541 } |
544 | 542 |
545 if (pushTransparencyLayer) | 543 if (pushTransparencyLayer) |
546 paintInfo.context->endLayer(); | 544 paintInfo.context.endLayer(); |
547 } | 545 } |
548 | 546 |
549 void BoxPainter::paintClippingMask(const PaintInfo& paintInfo, const LayoutPoint
& paintOffset) | 547 void BoxPainter::paintClippingMask(const PaintInfo& paintInfo, const LayoutPoint
& paintOffset) |
550 { | 548 { |
551 ASSERT(paintInfo.phase == PaintPhaseClippingMask); | 549 ASSERT(paintInfo.phase == PaintPhaseClippingMask); |
552 | 550 |
553 if (!paintInfo.shouldPaintWithinRoot(&m_layoutBox) || m_layoutBox.style()->v
isibility() != VISIBLE) | 551 if (!paintInfo.shouldPaintWithinRoot(&m_layoutBox) || m_layoutBox.style()->v
isibility() != VISIBLE) |
554 return; | 552 return; |
555 | 553 |
556 if (!m_layoutBox.layer() || m_layoutBox.layer()->compositingState() != Paint
sIntoOwnBacking) | 554 if (!m_layoutBox.layer() || m_layoutBox.layer()->compositingState() != Paint
sIntoOwnBacking) |
557 return; | 555 return; |
558 | 556 |
559 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.conte
xt, m_layoutBox, paintInfo.phase, paintOffset)) | 557 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.contex
t, m_layoutBox, paintInfo.phase, paintOffset)) |
560 return; | 558 return; |
561 | 559 |
562 IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset, m_layoutBox.
size())); | 560 IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset, m_layoutBox.
size())); |
563 LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutBox,
paintInfo.phase, paintRect, paintOffset); | 561 LayoutObjectDrawingRecorder drawingRecorder(paintInfo.context, m_layoutBox,
paintInfo.phase, paintRect, paintOffset); |
564 paintInfo.context->fillRect(paintRect, Color::black); | 562 paintInfo.context.fillRect(paintRect, Color::black); |
565 } | 563 } |
566 | 564 |
567 InterpolationQuality BoxPainter::chooseInterpolationQuality(const LayoutObject&
obj, GraphicsContext* context, Image* image, const void* layer, const LayoutSize
& size) | 565 InterpolationQuality BoxPainter::chooseInterpolationQuality(const LayoutObject&
obj, Image* image, const void* layer, const LayoutSize& size) |
568 { | 566 { |
569 return ImageQualityController::imageQualityController()->chooseInterpolation
Quality(context, &obj, image, layer, size); | 567 return ImageQualityController::imageQualityController()->chooseInterpolation
Quality(obj, image, layer, size); |
570 } | 568 } |
571 | 569 |
572 bool BoxPainter::paintNinePieceImage(const LayoutBoxModelObject& obj, GraphicsCo
ntext* graphicsContext, const LayoutRect& rect, const ComputedStyle& style, cons
t NinePieceImage& ninePieceImage, SkXfermode::Mode op) | 570 bool BoxPainter::paintNinePieceImage(const LayoutBoxModelObject& obj, GraphicsCo
ntext& graphicsContext, const LayoutRect& rect, const ComputedStyle& style, cons
t NinePieceImage& ninePieceImage, SkXfermode::Mode op) |
573 { | 571 { |
574 NinePieceImagePainter ninePieceImagePainter(obj); | 572 NinePieceImagePainter ninePieceImagePainter(obj); |
575 return ninePieceImagePainter.paint(graphicsContext, rect, style, ninePieceIm
age, op); | 573 return ninePieceImagePainter.paint(graphicsContext, rect, style, ninePieceIm
age, op); |
576 } | 574 } |
577 | 575 |
578 void BoxPainter::paintBorder(const LayoutBoxModelObject& obj, const PaintInfo& i
nfo, | 576 void BoxPainter::paintBorder(const LayoutBoxModelObject& obj, const PaintInfo& i
nfo, |
579 const LayoutRect& rect, const ComputedStyle& style, BackgroundBleedAvoidance
bleedAvoidance, | 577 const LayoutRect& rect, const ComputedStyle& style, BackgroundBleedAvoidance
bleedAvoidance, |
580 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) | 578 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) |
581 { | 579 { |
582 // border-image is not affected by border-radius. | 580 // border-image is not affected by border-radius. |
583 if (paintNinePieceImage(obj, info.context, rect, style, style.borderImage())
) | 581 if (paintNinePieceImage(obj, info.context, rect, style, style.borderImage())
) |
584 return; | 582 return; |
585 | 583 |
586 const BoxBorderPainter borderPainter(rect, style, bleedAvoidance, | 584 const BoxBorderPainter borderPainter(rect, style, bleedAvoidance, |
587 includeLogicalLeftEdge, includeLogicalRightEdge); | 585 includeLogicalLeftEdge, includeLogicalRightEdge); |
588 borderPainter.paintBorder(info, rect); | 586 borderPainter.paintBorder(info, rect); |
589 } | 587 } |
590 | 588 |
591 void BoxPainter::paintBoxShadow(const PaintInfo& info, const LayoutRect& paintRe
ct, const ComputedStyle& style, ShadowStyle shadowStyle, bool includeLogicalLeft
Edge, bool includeLogicalRightEdge) | 589 void BoxPainter::paintBoxShadow(const PaintInfo& info, const LayoutRect& paintRe
ct, const ComputedStyle& style, ShadowStyle shadowStyle, bool includeLogicalLeft
Edge, bool includeLogicalRightEdge) |
592 { | 590 { |
593 // FIXME: Deal with border-image. Would be great to use border-image as a ma
sk. | 591 // FIXME: Deal with border-image. Would be great to use border-image as a ma
sk. |
594 GraphicsContext* context = info.context; | 592 GraphicsContext& context = info.context; |
595 if (!style.boxShadow()) | 593 if (!style.boxShadow()) |
596 return; | 594 return; |
597 FloatRoundedRect border = (shadowStyle == Inset) ? style.getRoundedInnerBord
erFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge) | 595 FloatRoundedRect border = (shadowStyle == Inset) ? style.getRoundedInnerBord
erFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge) |
598 : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLo
gicalRightEdge); | 596 : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLo
gicalRightEdge); |
599 | 597 |
600 bool hasBorderRadius = style.hasBorderRadius(); | 598 bool hasBorderRadius = style.hasBorderRadius(); |
601 bool isHorizontal = style.isHorizontalWritingMode(); | 599 bool isHorizontal = style.isHorizontalWritingMode(); |
602 bool hasOpaqueBackground = style.visitedDependentColor(CSSPropertyBackground
Color).alpha() == 255; | 600 bool hasOpaqueBackground = style.visitedDependentColor(CSSPropertyBackground
Color).alpha() == 255; |
603 | 601 |
604 GraphicsContextStateSaver stateSaver(*context, false); | 602 GraphicsContextStateSaver stateSaver(context, false); |
605 | 603 |
606 const ShadowList* shadowList = style.boxShadow(); | 604 const ShadowList* shadowList = style.boxShadow(); |
607 for (size_t i = shadowList->shadows().size(); i--; ) { | 605 for (size_t i = shadowList->shadows().size(); i--; ) { |
608 const ShadowData& shadow = shadowList->shadows()[i]; | 606 const ShadowData& shadow = shadowList->shadows()[i]; |
609 if (shadow.style() != shadowStyle) | 607 if (shadow.style() != shadowStyle) |
610 continue; | 608 continue; |
611 | 609 |
612 FloatSize shadowOffset(shadow.x(), shadow.y()); | 610 FloatSize shadowOffset(shadow.x(), shadow.y()); |
613 float shadowBlur = shadow.blur(); | 611 float shadowBlur = shadow.blur(); |
614 float shadowSpread = shadow.spread(); | 612 float shadowSpread = shadow.spread(); |
(...skipping 20 matching lines...) Expand all Loading... |
635 if (hasBorderRadius) { | 633 if (hasBorderRadius) { |
636 FloatRoundedRect rectToClipOut = border; | 634 FloatRoundedRect rectToClipOut = border; |
637 | 635 |
638 // If the box is opaque, it is unnecessary to clip it out. H
owever, doing so saves time | 636 // If the box is opaque, it is unnecessary to clip it out. H
owever, doing so saves time |
639 // when painting the shadow. On the other hand, it introduce
s subpixel gaps along the | 637 // when painting the shadow. On the other hand, it introduce
s subpixel gaps along the |
640 // corners. Those are avoided by insetting the clipping path
by one CSS pixel. | 638 // corners. Those are avoided by insetting the clipping path
by one CSS pixel. |
641 if (hasOpaqueBackground) | 639 if (hasOpaqueBackground) |
642 rectToClipOut.inflateWithRadii(-1); | 640 rectToClipOut.inflateWithRadii(-1); |
643 | 641 |
644 if (!rectToClipOut.isEmpty()) | 642 if (!rectToClipOut.isEmpty()) |
645 context->clipOutRoundedRect(rectToClipOut); | 643 context.clipOutRoundedRect(rectToClipOut); |
646 } else { | 644 } else { |
647 // This IntRect is correct even with fractional shadows, bec
ause it is used for the rectangle | 645 // This IntRect is correct even with fractional shadows, bec
ause it is used for the rectangle |
648 // of the box itself, which is always pixel-aligned. | 646 // of the box itself, which is always pixel-aligned. |
649 FloatRect rectToClipOut = border.rect(); | 647 FloatRect rectToClipOut = border.rect(); |
650 | 648 |
651 // If the box is opaque, it is unnecessary to clip it out. H
owever, doing so saves time | 649 // If the box is opaque, it is unnecessary to clip it out. H
owever, doing so saves time |
652 // when painting the shadow. On the other hand, it introduce
s subpixel gaps along the | 650 // when painting the shadow. On the other hand, it introduce
s subpixel gaps along the |
653 // edges if they are not pixel-aligned. Those are avoided by
insetting the clipping path | 651 // edges if they are not pixel-aligned. Those are avoided by
insetting the clipping path |
654 // by one CSS pixel. | 652 // by one CSS pixel. |
655 if (hasOpaqueBackground) | 653 if (hasOpaqueBackground) |
656 rectToClipOut.inflate(-1); | 654 rectToClipOut.inflate(-1); |
657 | 655 |
658 if (!rectToClipOut.isEmpty()) | 656 if (!rectToClipOut.isEmpty()) |
659 context->clipOut(rectToClipOut); | 657 context.clipOut(rectToClipOut); |
660 } | 658 } |
661 } | 659 } |
662 | 660 |
663 // Draw only the shadow. | 661 // Draw only the shadow. |
664 context->setShadow(shadowOffset, shadowBlur, shadowColor, DrawLooper
Builder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha, DrawSh
adowOnly); | 662 context.setShadow(shadowOffset, shadowBlur, shadowColor, DrawLooperB
uilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha, DrawSha
dowOnly); |
665 | 663 |
666 if (hasBorderRadius) { | 664 if (hasBorderRadius) { |
667 FloatRoundedRect influenceRect(pixelSnappedIntRect(LayoutRect(sh
adowRect)), border.radii()); | 665 FloatRoundedRect influenceRect(pixelSnappedIntRect(LayoutRect(sh
adowRect)), border.radii()); |
668 float changeAmount = 2 * shadowBlur + shadowSpread; | 666 float changeAmount = 2 * shadowBlur + shadowSpread; |
669 if (changeAmount >= 0) | 667 if (changeAmount >= 0) |
670 influenceRect.expandRadii(changeAmount); | 668 influenceRect.expandRadii(changeAmount); |
671 else | 669 else |
672 influenceRect.shrinkRadii(-changeAmount); | 670 influenceRect.shrinkRadii(-changeAmount); |
673 | 671 |
674 FloatRoundedRect roundedFillRect = border; | 672 FloatRoundedRect roundedFillRect = border; |
675 roundedFillRect.inflate(shadowSpread); | 673 roundedFillRect.inflate(shadowSpread); |
676 | 674 |
677 if (shadowSpread >= 0) | 675 if (shadowSpread >= 0) |
678 roundedFillRect.expandRadii(shadowSpread); | 676 roundedFillRect.expandRadii(shadowSpread); |
679 else | 677 else |
680 roundedFillRect.shrinkRadii(-shadowSpread); | 678 roundedFillRect.shrinkRadii(-shadowSpread); |
681 if (!roundedFillRect.isRenderable()) | 679 if (!roundedFillRect.isRenderable()) |
682 roundedFillRect.adjustRadii(); | 680 roundedFillRect.adjustRadii(); |
683 roundedFillRect.constrainRadii(); | 681 roundedFillRect.constrainRadii(); |
684 context->fillRoundedRect(roundedFillRect, Color::black); | 682 context.fillRoundedRect(roundedFillRect, Color::black); |
685 } else { | 683 } else { |
686 context->fillRect(fillRect, Color::black); | 684 context.fillRect(fillRect, Color::black); |
687 } | 685 } |
688 } else { | 686 } else { |
689 // The inset shadow case. | 687 // The inset shadow case. |
690 GraphicsContext::Edges clippedEdges = GraphicsContext::NoEdge; | 688 GraphicsContext::Edges clippedEdges = GraphicsContext::NoEdge; |
691 if (!includeLogicalLeftEdge) { | 689 if (!includeLogicalLeftEdge) { |
692 if (isHorizontal) | 690 if (isHorizontal) |
693 clippedEdges |= GraphicsContext::LeftEdge; | 691 clippedEdges |= GraphicsContext::LeftEdge; |
694 else | 692 else |
695 clippedEdges |= GraphicsContext::TopEdge; | 693 clippedEdges |= GraphicsContext::TopEdge; |
696 } | 694 } |
697 if (!includeLogicalRightEdge) { | 695 if (!includeLogicalRightEdge) { |
698 if (isHorizontal) | 696 if (isHorizontal) |
699 clippedEdges |= GraphicsContext::RightEdge; | 697 clippedEdges |= GraphicsContext::RightEdge; |
700 else | 698 else |
701 clippedEdges |= GraphicsContext::BottomEdge; | 699 clippedEdges |= GraphicsContext::BottomEdge; |
702 } | 700 } |
703 context->drawInnerShadow(border, shadowColor, shadowOffset, shadowBl
ur, shadowSpread, clippedEdges); | 701 context.drawInnerShadow(border, shadowColor, shadowOffset, shadowBlu
r, shadowSpread, clippedEdges); |
704 } | 702 } |
705 } | 703 } |
706 } | 704 } |
707 | 705 |
708 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(const ComputedStyle&
style, const Document& document) | 706 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(const ComputedStyle&
style, const Document& document) |
709 { | 707 { |
710 return document.printing() && style.printColorAdjust() == PrintColorAdjustEc
onomy | 708 return document.printing() && style.printColorAdjust() == PrintColorAdjustEc
onomy |
711 && (!document.settings() || !document.settings()->shouldPrintBackgrounds
()); | 709 && (!document.settings() || !document.settings()->shouldPrintBackgrounds
()); |
712 } | 710 } |
713 | 711 |
714 } // namespace blink | 712 } // namespace blink |
OLD | NEW |