| 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 |