OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/paint/BoxPainter.h" | 5 #include "core/paint/BoxPainter.h" |
6 | 6 |
7 #include "core/HTMLNames.h" | 7 #include "core/HTMLNames.h" |
8 #include "core/frame/Settings.h" | 8 #include "core/frame/Settings.h" |
9 #include "core/html/HTMLFrameOwnerElement.h" | 9 #include "core/html/HTMLFrameOwnerElement.h" |
10 #include "core/layout/ImageQualityController.h" | 10 #include "core/layout/ImageQualityController.h" |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 child = child->nextSibling()) | 58 child = child->nextSibling()) |
59 child->paint(childInfo, adjustedPaintOffset); | 59 child->paint(childInfo, adjustedPaintOffset); |
60 } | 60 } |
61 | 61 |
62 void BoxPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, | 62 void BoxPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, |
63 const LayoutPoint& paintOffset) { | 63 const LayoutPoint& paintOffset) { |
64 LayoutRect paintRect; | 64 LayoutRect paintRect; |
65 Optional<ScrollRecorder> scrollRecorder; | 65 Optional<ScrollRecorder> scrollRecorder; |
66 if (isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer( | 66 if (isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer( |
67 &m_layoutBox, paintInfo)) { | 67 &m_layoutBox, paintInfo)) { |
68 // For the case where we are painting the background into the scrolling cont
ents layer | 68 // For the case where we are painting the background into the scrolling |
69 // of a composited scroller we need to include the entire overflow rect. | 69 // contents layer of a composited scroller we need to include the entire |
| 70 // overflow rect. |
70 paintRect = m_layoutBox.layoutOverflowRect(); | 71 paintRect = m_layoutBox.layoutOverflowRect(); |
71 scrollRecorder.emplace(paintInfo.context, m_layoutBox, paintInfo.phase, | 72 scrollRecorder.emplace(paintInfo.context, m_layoutBox, paintInfo.phase, |
72 m_layoutBox.scrolledContentOffset()); | 73 m_layoutBox.scrolledContentOffset()); |
73 | 74 |
74 // The background painting code assumes that the borders are part of the pai
ntRect so we | 75 // The background painting code assumes that the borders are part of the |
75 // expand the paintRect by the border size when painting the background into
the | 76 // paintRect so we expand the paintRect by the border size when painting the |
76 // scrolling contents layer. | 77 // background into the scrolling contents layer. |
77 paintRect.expandEdges(LayoutUnit(m_layoutBox.borderTop()), | 78 paintRect.expandEdges(LayoutUnit(m_layoutBox.borderTop()), |
78 LayoutUnit(m_layoutBox.borderRight()), | 79 LayoutUnit(m_layoutBox.borderRight()), |
79 LayoutUnit(m_layoutBox.borderBottom()), | 80 LayoutUnit(m_layoutBox.borderBottom()), |
80 LayoutUnit(m_layoutBox.borderLeft())); | 81 LayoutUnit(m_layoutBox.borderLeft())); |
81 } else { | 82 } else { |
82 paintRect = m_layoutBox.borderBoxRect(); | 83 paintRect = m_layoutBox.borderBoxRect(); |
83 } | 84 } |
84 | 85 |
85 paintRect.moveBy(paintOffset); | 86 paintRect.moveBy(paintOffset); |
86 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect); | 87 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect); |
(...skipping 23 matching lines...) Expand all Loading... |
110 void BoxPainter::paintBoxDecorationBackgroundWithRect( | 111 void BoxPainter::paintBoxDecorationBackgroundWithRect( |
111 const PaintInfo& paintInfo, | 112 const PaintInfo& paintInfo, |
112 const LayoutPoint& paintOffset, | 113 const LayoutPoint& paintOffset, |
113 const LayoutRect& paintRect) { | 114 const LayoutRect& paintRect) { |
114 bool paintingOverflowContents = | 115 bool paintingOverflowContents = |
115 isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer( | 116 isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer( |
116 &m_layoutBox, paintInfo); | 117 &m_layoutBox, paintInfo); |
117 const ComputedStyle& style = m_layoutBox.styleRef(); | 118 const ComputedStyle& style = m_layoutBox.styleRef(); |
118 | 119 |
119 Optional<DisplayItemCacheSkipper> cacheSkipper; | 120 Optional<DisplayItemCacheSkipper> cacheSkipper; |
120 // Disable cache in under-invalidation checking mode for MediaSliderPart becau
se we always paint using the | 121 // Disable cache in under-invalidation checking mode for MediaSliderPart |
121 // latest data (buffered ranges, current time and duration) which may be diffe
rent from the cached data. | 122 // because we always paint using the latest data (buffered ranges, current |
| 123 // time and duration) which may be different from the cached data. |
122 if ((RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled() && | 124 if ((RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled() && |
123 style.appearance() == MediaSliderPart) | 125 style.appearance() == MediaSliderPart) |
124 // We may paint a delayed-invalidation object before it's actually invalid
ated. Note this would be handled for | 126 // We may paint a delayed-invalidation object before it's actually |
125 // us by LayoutObjectDrawingRecorder but we have to use DrawingRecorder as
we may use the scrolling contents | 127 // invalidated. Note this would be handled for us by |
126 // layer as DisplayItemClient below. | 128 // LayoutObjectDrawingRecorder but we have to use DrawingRecorder as we |
| 129 // may use the scrolling contents layer as DisplayItemClient below. |
127 || | 130 || |
128 m_layoutBox.fullPaintInvalidationReason() == | 131 m_layoutBox.fullPaintInvalidationReason() == |
129 PaintInvalidationDelayedFull) { | 132 PaintInvalidationDelayedFull) { |
130 cacheSkipper.emplace(paintInfo.context); | 133 cacheSkipper.emplace(paintInfo.context); |
131 } | 134 } |
132 | 135 |
133 const DisplayItemClient& displayItemClient = | 136 const DisplayItemClient& displayItemClient = |
134 paintingOverflowContents ? static_cast<const DisplayItemClient&>( | 137 paintingOverflowContents ? static_cast<const DisplayItemClient&>( |
135 *m_layoutBox.layer() | 138 *m_layoutBox.layer() |
136 ->compositedLayerMapping() | 139 ->compositedLayerMapping() |
137 ->scrollingContentsLayer()) | 140 ->scrollingContentsLayer()) |
138 : m_layoutBox; | 141 : m_layoutBox; |
139 if (DrawingRecorder::useCachedDrawingIfPossible( | 142 if (DrawingRecorder::useCachedDrawingIfPossible( |
140 paintInfo.context, displayItemClient, | 143 paintInfo.context, displayItemClient, |
141 DisplayItem::kBoxDecorationBackground)) | 144 DisplayItem::kBoxDecorationBackground)) |
142 return; | 145 return; |
143 | 146 |
144 DrawingRecorder recorder( | 147 DrawingRecorder recorder( |
145 paintInfo.context, displayItemClient, | 148 paintInfo.context, displayItemClient, |
146 DisplayItem::kBoxDecorationBackground, | 149 DisplayItem::kBoxDecorationBackground, |
147 FloatRect(boundsForDrawingRecorder(paintInfo, paintOffset))); | 150 FloatRect(boundsForDrawingRecorder(paintInfo, paintOffset))); |
148 BoxDecorationData boxDecorationData(m_layoutBox); | 151 BoxDecorationData boxDecorationData(m_layoutBox); |
149 GraphicsContextStateSaver stateSaver(paintInfo.context, false); | 152 GraphicsContextStateSaver stateSaver(paintInfo.context, false); |
150 | 153 |
151 if (!paintingOverflowContents) { | 154 if (!paintingOverflowContents) { |
152 // FIXME: Should eventually give the theme control over whether the box shad
ow should paint, since controls could have | 155 // FIXME: Should eventually give the theme control over whether the box |
153 // custom shadows of their own. | 156 // shadow should paint, since controls could have custom shadows of their |
| 157 // own. |
154 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground( | 158 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground( |
155 boxDecorationData.bleedAvoidance)) { | 159 boxDecorationData.bleedAvoidance)) { |
156 paintBoxShadow(paintInfo, paintRect, style, Normal); | 160 paintBoxShadow(paintInfo, paintRect, style, Normal); |
157 } | 161 } |
158 | 162 |
159 if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { | 163 if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { |
160 stateSaver.save(); | 164 stateSaver.save(); |
161 FloatRoundedRect border = style.getRoundedBorderFor(paintRect); | 165 FloatRoundedRect border = style.getRoundedBorderFor(paintRect); |
162 paintInfo.context.clipRoundedRect(border); | 166 paintInfo.context.clipRoundedRect(border); |
163 | 167 |
164 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) | 168 if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) |
165 paintInfo.context.beginLayer(); | 169 paintInfo.context.beginLayer(); |
166 } | 170 } |
167 } | 171 } |
168 | 172 |
169 // If we have a native theme appearance, paint that before painting our backgr
ound. | 173 // If we have a native theme appearance, paint that before painting our |
170 // The theme will tell us whether or not we should also paint the CSS backgrou
nd. | 174 // background. The theme will tell us whether or not we should also paint the |
| 175 // CSS background. |
171 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); | 176 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); |
172 ThemePainter& themePainter = LayoutTheme::theme().painter(); | 177 ThemePainter& themePainter = LayoutTheme::theme().painter(); |
173 bool themePainted = | 178 bool themePainted = |
174 boxDecorationData.hasAppearance && | 179 boxDecorationData.hasAppearance && |
175 !themePainter.paint(m_layoutBox, paintInfo, snappedPaintRect); | 180 !themePainter.paint(m_layoutBox, paintInfo, snappedPaintRect); |
176 bool shouldPaintBackground = | 181 bool shouldPaintBackground = |
177 !themePainted && (!paintInfo.skipRootBackground() || | 182 !themePainted && (!paintInfo.skipRootBackground() || |
178 paintInfo.paintContainer() != &m_layoutBox); | 183 paintInfo.paintContainer() != &m_layoutBox); |
179 if (shouldPaintBackground) { | 184 if (shouldPaintBackground) { |
180 paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, | 185 paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, |
181 boxDecorationData.bleedAvoidance); | 186 boxDecorationData.bleedAvoidance); |
182 | 187 |
183 if (boxDecorationData.hasAppearance) | 188 if (boxDecorationData.hasAppearance) |
184 themePainter.paintDecorations(m_layoutBox, paintInfo, snappedPaintRect); | 189 themePainter.paintDecorations(m_layoutBox, paintInfo, snappedPaintRect); |
185 } | 190 } |
186 | 191 |
187 if (!paintingOverflowContents) { | 192 if (!paintingOverflowContents) { |
188 paintBoxShadow(paintInfo, paintRect, style, Inset); | 193 paintBoxShadow(paintInfo, paintRect, style, Inset); |
189 | 194 |
190 // The theme will tell us whether or not we should also paint the CSS border
. | 195 // The theme will tell us whether or not we should also paint the CSS |
| 196 // border. |
191 if (boxDecorationData.hasBorderDecoration && | 197 if (boxDecorationData.hasBorderDecoration && |
192 (!boxDecorationData.hasAppearance || | 198 (!boxDecorationData.hasAppearance || |
193 (!themePainted && | 199 (!themePainted && |
194 LayoutTheme::theme().painter().paintBorderOnly(m_layoutBox, paintInfo, | 200 LayoutTheme::theme().painter().paintBorderOnly(m_layoutBox, paintInfo, |
195 snappedPaintRect))) && | 201 snappedPaintRect))) && |
196 !(m_layoutBox.isTable() && | 202 !(m_layoutBox.isTable() && |
197 toLayoutTable(&m_layoutBox)->collapseBorders())) { | 203 toLayoutTable(&m_layoutBox)->collapseBorders())) { |
198 paintBorder(m_layoutBox, paintInfo, paintRect, style, | 204 paintBorder(m_layoutBox, paintInfo, paintRect, style, |
199 boxDecorationData.bleedAvoidance); | 205 boxDecorationData.bleedAvoidance); |
200 } | 206 } |
(...skipping 19 matching lines...) Expand all Loading... |
220 } | 226 } |
221 | 227 |
222 bool BoxPainter::calculateFillLayerOcclusionCulling( | 228 bool BoxPainter::calculateFillLayerOcclusionCulling( |
223 FillLayerOcclusionOutputList& reversedPaintList, | 229 FillLayerOcclusionOutputList& reversedPaintList, |
224 const FillLayer& fillLayer) { | 230 const FillLayer& fillLayer) { |
225 bool isNonAssociative = false; | 231 bool isNonAssociative = false; |
226 for (auto currentLayer = &fillLayer; currentLayer; | 232 for (auto currentLayer = &fillLayer; currentLayer; |
227 currentLayer = currentLayer->next()) { | 233 currentLayer = currentLayer->next()) { |
228 reversedPaintList.append(currentLayer); | 234 reversedPaintList.append(currentLayer); |
229 // Stop traversal when an opaque layer is encountered. | 235 // Stop traversal when an opaque layer is encountered. |
230 // FIXME : It would be possible for the following occlusion culling test to
be more aggressive | 236 // FIXME : It would be possible for the following occlusion culling test to |
231 // on layers with no repeat by testing whether the image covers the layout r
ect. | 237 // be more aggressive on layers with no repeat by testing whether the image |
232 // Testing that here would imply duplicating a lot of calculations that are
currently done in | 238 // covers the layout rect. Testing that here would imply duplicating a lot |
233 // LayoutBoxModelObject::paintFillLayer. A more efficient solution might be
to move the layer | 239 // of calculations that are currently done in |
234 // recursion into paintFillLayer, or to compute the layer geometry here and
pass it down. | 240 // LayoutBoxModelObject::paintFillLayer. A more efficient solution might be |
| 241 // to move the layer recursion into paintFillLayer, or to compute the layer |
| 242 // geometry here and pass it down. |
235 | 243 |
236 // TODO(trchen): Need to check compositing mode as well. | 244 // TODO(trchen): Need to check compositing mode as well. |
237 if (currentLayer->blendMode() != WebBlendModeNormal) | 245 if (currentLayer->blendMode() != WebBlendModeNormal) |
238 isNonAssociative = true; | 246 isNonAssociative = true; |
239 | 247 |
240 // TODO(trchen): A fill layer cannot paint if the calculated tile size is em
pty. | 248 // TODO(trchen): A fill layer cannot paint if the calculated tile size is |
241 // This occlusion check can be wrong. | 249 // empty. This occlusion check can be wrong. |
242 if (currentLayer->clipOccludesNextLayers() && | 250 if (currentLayer->clipOccludesNextLayers() && |
243 currentLayer->imageOccludesNextLayers(m_layoutBox)) { | 251 currentLayer->imageOccludesNextLayers(m_layoutBox)) { |
244 if (currentLayer->clip() == BorderFillBox) | 252 if (currentLayer->clip() == BorderFillBox) |
245 isNonAssociative = false; | 253 isNonAssociative = false; |
246 break; | 254 break; |
247 } | 255 } |
248 } | 256 } |
249 return isNonAssociative; | 257 return isNonAssociative; |
250 } | 258 } |
251 | 259 |
252 void BoxPainter::paintFillLayers(const PaintInfo& paintInfo, | 260 void BoxPainter::paintFillLayers(const PaintInfo& paintInfo, |
253 const Color& c, | 261 const Color& c, |
254 const FillLayer& fillLayer, | 262 const FillLayer& fillLayer, |
255 const LayoutRect& rect, | 263 const LayoutRect& rect, |
256 BackgroundBleedAvoidance bleedAvoidance, | 264 BackgroundBleedAvoidance bleedAvoidance, |
257 SkXfermode::Mode op, | 265 SkXfermode::Mode op, |
258 const LayoutObject* backgroundObject) { | 266 const LayoutObject* backgroundObject) { |
259 // TODO(trchen): Box shadow optimization and background color are concepts tha
t only | 267 // TODO(trchen): Box shadow optimization and background color are concepts |
260 // apply to background layers. Ideally we should refactor those out of paintFi
llLayer. | 268 // that only apply to background layers. Ideally we should refactor those out |
| 269 // of paintFillLayer. |
261 FillLayerOcclusionOutputList reversedPaintList; | 270 FillLayerOcclusionOutputList reversedPaintList; |
262 bool shouldDrawBackgroundInSeparateBuffer = false; | 271 bool shouldDrawBackgroundInSeparateBuffer = false; |
263 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground(bleedAvoidance)) { | 272 if (!m_layoutBox.boxShadowShouldBeAppliedToBackground(bleedAvoidance)) { |
264 shouldDrawBackgroundInSeparateBuffer = | 273 shouldDrawBackgroundInSeparateBuffer = |
265 calculateFillLayerOcclusionCulling(reversedPaintList, fillLayer); | 274 calculateFillLayerOcclusionCulling(reversedPaintList, fillLayer); |
266 } else { | 275 } else { |
267 // If we are responsible for painting box shadow, don't perform fill layer c
ulling. | 276 // If we are responsible for painting box shadow, don't perform fill layer |
268 // TODO(trchen): In theory we only need to make sure the last layer has bord
er box clipping | 277 // culling. |
269 // and make it paint the box shadow. Investigate optimization opportunity la
ter. | 278 // TODO(trchen): In theory we only need to make sure the last layer has |
| 279 // border box clipping and make it paint the box shadow. Investigate |
| 280 // optimization opportunity later. |
270 for (auto currentLayer = &fillLayer; currentLayer; | 281 for (auto currentLayer = &fillLayer; currentLayer; |
271 currentLayer = currentLayer->next()) { | 282 currentLayer = currentLayer->next()) { |
272 reversedPaintList.append(currentLayer); | 283 reversedPaintList.append(currentLayer); |
273 if (currentLayer->composite() != CompositeSourceOver || | 284 if (currentLayer->composite() != CompositeSourceOver || |
274 currentLayer->blendMode() != WebBlendModeNormal) | 285 currentLayer->blendMode() != WebBlendModeNormal) |
275 shouldDrawBackgroundInSeparateBuffer = true; | 286 shouldDrawBackgroundInSeparateBuffer = true; |
276 } | 287 } |
277 } | 288 } |
278 | 289 |
279 // TODO(trchen): We can optimize out isolation group if we have a non-transpar
ent | 290 // TODO(trchen): We can optimize out isolation group if we have a |
280 // background color and the bottom layer encloses all other layers. | 291 // non-transparent background color and the bottom layer encloses all other |
| 292 // layers. |
281 | 293 |
282 GraphicsContext& context = paintInfo.context; | 294 GraphicsContext& context = paintInfo.context; |
283 | 295 |
284 if (shouldDrawBackgroundInSeparateBuffer) | 296 if (shouldDrawBackgroundInSeparateBuffer) |
285 context.beginLayer(); | 297 context.beginLayer(); |
286 | 298 |
287 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); | 299 for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); |
288 ++it) | 300 ++it) |
289 paintFillLayer(m_layoutBox, paintInfo, c, **it, rect, bleedAvoidance, 0, | 301 paintFillLayer(m_layoutBox, paintInfo, c, **it, rect, bleedAvoidance, 0, |
290 LayoutSize(), op, backgroundObject); | 302 LayoutSize(), op, backgroundObject); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 | 359 |
348 FloatRoundedRect backgroundRoundedRectAdjustedForBleedAvoidance( | 360 FloatRoundedRect backgroundRoundedRectAdjustedForBleedAvoidance( |
349 const LayoutObject& obj, | 361 const LayoutObject& obj, |
350 const LayoutRect& borderRect, | 362 const LayoutRect& borderRect, |
351 BackgroundBleedAvoidance bleedAvoidance, | 363 BackgroundBleedAvoidance bleedAvoidance, |
352 const InlineFlowBox* box, | 364 const InlineFlowBox* box, |
353 const LayoutSize& boxSize, | 365 const LayoutSize& boxSize, |
354 bool includeLogicalLeftEdge, | 366 bool includeLogicalLeftEdge, |
355 bool includeLogicalRightEdge) { | 367 bool includeLogicalRightEdge) { |
356 if (bleedAvoidance == BackgroundBleedShrinkBackground) { | 368 if (bleedAvoidance == BackgroundBleedShrinkBackground) { |
357 // Inset the background rect by a "safe" amount: 1/2 border-width for opaque
border styles, | 369 // Inset the background rect by a "safe" amount: 1/2 border-width for opaque |
358 // 1/6 border-width for double borders. | 370 // border styles, 1/6 border-width for double borders. |
359 | 371 |
360 // TODO(fmalita): we should be able to fold these parameters into BoxBorderI
nfo or | 372 // TODO(fmalita): we should be able to fold these parameters into |
361 // BoxDecorationData and avoid calling getBorderEdgeInfo redundantly here. | 373 // BoxBorderInfo or BoxDecorationData and avoid calling getBorderEdgeInfo |
| 374 // redundantly here. |
362 BorderEdge edges[4]; | 375 BorderEdge edges[4]; |
363 obj.style()->getBorderEdgeInfo(edges, includeLogicalLeftEdge, | 376 obj.style()->getBorderEdgeInfo(edges, includeLogicalLeftEdge, |
364 includeLogicalRightEdge); | 377 includeLogicalRightEdge); |
365 | 378 |
366 // Use the most conservative inset to avoid mixed-style corner issues. | 379 // Use the most conservative inset to avoid mixed-style corner issues. |
367 float fractionalInset = 1.0f / 2; | 380 float fractionalInset = 1.0f / 2; |
368 for (auto& edge : edges) { | 381 for (auto& edge : edges) { |
369 if (edge.borderStyle() == BorderStyleDouble) { | 382 if (edge.borderStyle() == BorderStyleDouble) { |
370 fractionalInset = 1.0f / 6; | 383 fractionalInset = 1.0f / 6; |
371 break; | 384 break; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 color(bgColor), | 418 color(bgColor), |
406 includeLeftEdge(box ? box->includeLogicalLeftEdge() : true), | 419 includeLeftEdge(box ? box->includeLogicalLeftEdge() : true), |
407 includeRightEdge(box ? box->includeLogicalRightEdge() : true), | 420 includeRightEdge(box ? box->includeLogicalRightEdge() : true), |
408 isBottomLayer(!layer.next()), | 421 isBottomLayer(!layer.next()), |
409 isBorderFill(layer.clip() == BorderFillBox), | 422 isBorderFill(layer.clip() == BorderFillBox), |
410 isClippedWithLocalScrolling(obj.hasOverflowClip() && | 423 isClippedWithLocalScrolling(obj.hasOverflowClip() && |
411 layer.attachment() == | 424 layer.attachment() == |
412 LocalBackgroundAttachment) { | 425 LocalBackgroundAttachment) { |
413 // When printing backgrounds is disabled or using economy mode, | 426 // When printing backgrounds is disabled or using economy mode, |
414 // change existing background colors and images to a solid white background. | 427 // change existing background colors and images to a solid white background. |
415 // If there's no bg color or image, leave it untouched to avoid affecting tr
ansparency. | 428 // If there's no bg color or image, leave it untouched to avoid affecting |
416 // We don't try to avoid loading the background images, because this style f
lag is only set | 429 // transparency. We don't try to avoid loading the background images, |
417 // when printing, and at that point we've already loaded the background imag
es anyway. (To avoid | 430 // because this style flag is only set when printing, and at that point |
418 // loading the background images we'd have to do this check when applying st
yles rather than | 431 // we've already loaded the background images anyway. (To avoid loading the |
419 // while layout.) | 432 // background images we'd have to do this check when applying styles rather |
| 433 // than while layout.) |
420 if (BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(obj.styleRef(), | 434 if (BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(obj.styleRef(), |
421 obj.document())) { | 435 obj.document())) { |
422 // Note that we can't reuse this variable below because the bgColor might
be changed | 436 // Note that we can't reuse this variable below because the bgColor might |
| 437 // be changed. |
423 bool shouldPaintBackgroundColor = isBottomLayer && color.alpha(); | 438 bool shouldPaintBackgroundColor = isBottomLayer && color.alpha(); |
424 if (image || shouldPaintBackgroundColor) { | 439 if (image || shouldPaintBackgroundColor) { |
425 color = Color::white; | 440 color = Color::white; |
426 image = nullptr; | 441 image = nullptr; |
427 } | 442 } |
428 } | 443 } |
429 | 444 |
430 const bool hasRoundedBorder = | 445 const bool hasRoundedBorder = |
431 obj.style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge); | 446 obj.style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge); |
432 // BorderFillBox radius clipping is taken care of by BackgroundBleedClip{Onl
y,Layer} | 447 // BorderFillBox radius clipping is taken care of by |
| 448 // BackgroundBleedClip{Only,Layer} |
433 isRoundedFill = hasRoundedBorder && | 449 isRoundedFill = hasRoundedBorder && |
434 !(isBorderFill && bleedAvoidanceIsClipping(bleedAvoidance)); | 450 !(isBorderFill && bleedAvoidanceIsClipping(bleedAvoidance)); |
435 | 451 |
436 shouldPaintImage = image && image->canRender(); | 452 shouldPaintImage = image && image->canRender(); |
437 shouldPaintColor = | 453 shouldPaintColor = |
438 isBottomLayer && color.alpha() && | 454 isBottomLayer && color.alpha() && |
439 (!shouldPaintImage || !layer.imageOccludesNextLayers(obj)); | 455 (!shouldPaintImage || !layer.imageOccludesNextLayers(obj)); |
440 shouldPaintShadow = | 456 shouldPaintShadow = |
441 shouldPaintColor && | 457 shouldPaintColor && |
442 obj.boxShadowShouldBeAppliedToBackground(bleedAvoidance, box); | 458 obj.boxShadowShouldBeAppliedToBackground(bleedAvoidance, box); |
443 } | 459 } |
444 | 460 |
445 // FillLayerInfo is a temporary, stack-allocated container which cannot outliv
e the StyleImage. | 461 // FillLayerInfo is a temporary, stack-allocated container which cannot |
446 // This would normally be a raw pointer, if not for the Oilpan tooling complai
nts. | 462 // outlive the StyleImage. This would normally be a raw pointer, if not for |
| 463 // the Oilpan tooling complaints. |
447 Member<StyleImage> image; | 464 Member<StyleImage> image; |
448 Color color; | 465 Color color; |
449 | 466 |
450 bool includeLeftEdge; | 467 bool includeLeftEdge; |
451 bool includeRightEdge; | 468 bool includeRightEdge; |
452 bool isBottomLayer; | 469 bool isBottomLayer; |
453 bool isBorderFill; | 470 bool isBorderFill; |
454 bool isClippedWithLocalScrolling; | 471 bool isClippedWithLocalScrolling; |
455 bool isRoundedFill; | 472 bool isRoundedFill; |
456 | 473 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 Optional<BackgroundImageGeometry>& geometry) { | 539 Optional<BackgroundImageGeometry>& geometry) { |
523 // Complex cases not handled on the fast path. | 540 // Complex cases not handled on the fast path. |
524 if (!info.isBottomLayer || !info.isBorderFill || | 541 if (!info.isBottomLayer || !info.isBorderFill || |
525 info.isClippedWithLocalScrolling) | 542 info.isClippedWithLocalScrolling) |
526 return false; | 543 return false; |
527 | 544 |
528 // Transparent layer, nothing to paint. | 545 // Transparent layer, nothing to paint. |
529 if (!info.shouldPaintColor && !info.shouldPaintImage) | 546 if (!info.shouldPaintColor && !info.shouldPaintImage) |
530 return true; | 547 return true; |
531 | 548 |
532 // When the layer has an image, figure out whether it is covered by a single t
ile. | 549 // When the layer has an image, figure out whether it is covered by a single |
| 550 // tile. |
533 FloatRect imageTile; | 551 FloatRect imageTile; |
534 if (info.shouldPaintImage) { | 552 if (info.shouldPaintImage) { |
535 DCHECK(!geometry); | 553 DCHECK(!geometry); |
536 geometry.emplace(); | 554 geometry.emplace(); |
537 geometry->calculate(obj, paintInfo.paintContainer(), | 555 geometry->calculate(obj, paintInfo.paintContainer(), |
538 paintInfo.getGlobalPaintFlags(), layer, rect); | 556 paintInfo.getGlobalPaintFlags(), layer, rect); |
539 | 557 |
540 if (!geometry->destRect().isEmpty()) { | 558 if (!geometry->destRect().isEmpty()) { |
541 // The tile is too small. | 559 // The tile is too small. |
542 if (geometry->tileSize().width() < rect.width() || | 560 if (geometry->tileSize().width() < rect.width() || |
543 geometry->tileSize().height() < rect.height()) | 561 geometry->tileSize().height() < rect.height()) |
544 return false; | 562 return false; |
545 | 563 |
546 imageTile = Image::computeTileContaining( | 564 imageTile = Image::computeTileContaining( |
547 FloatPoint(geometry->destRect().location()), | 565 FloatPoint(geometry->destRect().location()), |
548 FloatSize(geometry->tileSize()), FloatPoint(geometry->phase()), | 566 FloatSize(geometry->tileSize()), FloatPoint(geometry->phase()), |
549 FloatSize(geometry->spaceSize())); | 567 FloatSize(geometry->spaceSize())); |
550 | 568 |
551 // The tile is misaligned. | 569 // The tile is misaligned. |
552 if (!imageTile.contains(FloatRect(rect))) | 570 if (!imageTile.contains(FloatRect(rect))) |
553 return false; | 571 return false; |
554 } | 572 } |
555 } | 573 } |
556 | 574 |
557 // At this point we're committed to the fast path: the destination (r)rect fit
s within a single | 575 // At this point we're committed to the fast path: the destination (r)rect |
558 // tile, and we can paint it using direct draw(R)Rect() calls. | 576 // fits within a single tile, and we can paint it using direct draw(R)Rect() |
| 577 // calls. |
559 GraphicsContext& context = paintInfo.context; | 578 GraphicsContext& context = paintInfo.context; |
560 FloatRoundedRect border = | 579 FloatRoundedRect border = |
561 info.isRoundedFill ? backgroundRoundedRectAdjustedForBleedAvoidance( | 580 info.isRoundedFill ? backgroundRoundedRectAdjustedForBleedAvoidance( |
562 obj, rect, bleedAvoidance, box, boxSize, | 581 obj, rect, bleedAvoidance, box, boxSize, |
563 info.includeLeftEdge, info.includeRightEdge) | 582 info.includeLeftEdge, info.includeRightEdge) |
564 : FloatRoundedRect(pixelSnappedIntRect(rect)); | 583 : FloatRoundedRect(pixelSnappedIntRect(rect)); |
565 | 584 |
566 Optional<RoundedInnerRectClipper> clipper; | 585 Optional<RoundedInnerRectClipper> clipper; |
567 if (info.isRoundedFill && !border.isRenderable()) { | 586 if (info.isRoundedFill && !border.isRenderable()) { |
568 // When the rrect is not renderable, we resort to clipping. | 587 // When the rrect is not renderable, we resort to clipping. |
569 // RoundedInnerRectClipper handles this case via discrete, corner-wise clipp
ing. | 588 // RoundedInnerRectClipper handles this case via discrete, corner-wise |
| 589 // clipping. |
570 clipper.emplace(obj, paintInfo, rect, border, ApplyToContext); | 590 clipper.emplace(obj, paintInfo, rect, border, ApplyToContext); |
571 border.setRadii(FloatRoundedRect::Radii()); | 591 border.setRadii(FloatRoundedRect::Radii()); |
572 } | 592 } |
573 | 593 |
574 // Paint the color + shadow if needed. | 594 // Paint the color + shadow if needed. |
575 if (info.shouldPaintColor) { | 595 if (info.shouldPaintColor) { |
576 const ShadowContext shadowContext(context, obj, info.shouldPaintShadow); | 596 const ShadowContext shadowContext(context, obj, info.shouldPaintShadow); |
577 context.fillRoundedRect(border, info.color); | 597 context.fillRoundedRect(border, info.color); |
578 } | 598 } |
579 | 599 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 context, info.isClippedWithLocalScrolling); | 687 context, info.isClippedWithLocalScrolling); |
668 LayoutRect scrolledPaintRect = rect; | 688 LayoutRect scrolledPaintRect = rect; |
669 if (info.isClippedWithLocalScrolling && | 689 if (info.isClippedWithLocalScrolling && |
670 !isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer( | 690 !isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer( |
671 &obj, paintInfo)) { | 691 &obj, paintInfo)) { |
672 // Clip to the overflow area. | 692 // Clip to the overflow area. |
673 const LayoutBox& thisBox = toLayoutBox(obj); | 693 const LayoutBox& thisBox = toLayoutBox(obj); |
674 // TODO(chrishtr): this should be pixel-snapped. | 694 // TODO(chrishtr): this should be pixel-snapped. |
675 context.clip(FloatRect(thisBox.overflowClipRect(rect.location()))); | 695 context.clip(FloatRect(thisBox.overflowClipRect(rect.location()))); |
676 | 696 |
677 // Adjust the paint rect to reflect a scrolled content box with borders at t
he ends. | 697 // Adjust the paint rect to reflect a scrolled content box with borders at |
| 698 // the ends. |
678 IntSize offset = thisBox.scrolledContentOffset(); | 699 IntSize offset = thisBox.scrolledContentOffset(); |
679 scrolledPaintRect.move(-offset); | 700 scrolledPaintRect.move(-offset); |
680 scrolledPaintRect.setWidth(bLeft + thisBox.scrollWidth() + bRight); | 701 scrolledPaintRect.setWidth(bLeft + thisBox.scrollWidth() + bRight); |
681 scrolledPaintRect.setHeight(thisBox.borderTop() + thisBox.scrollHeight() + | 702 scrolledPaintRect.setHeight(thisBox.borderTop() + thisBox.scrollHeight() + |
682 thisBox.borderBottom()); | 703 thisBox.borderBottom()); |
683 } | 704 } |
684 | 705 |
685 GraphicsContextStateSaver backgroundClipStateSaver(context, false); | 706 GraphicsContextStateSaver backgroundClipStateSaver(context, false); |
686 IntRect maskRect; | 707 IntRect maskRect; |
687 | 708 |
(...skipping 15 matching lines...) Expand all Loading... |
703 scrolledPaintRect.height() - obj.borderTop() - obj.borderBottom() - | 724 scrolledPaintRect.height() - obj.borderTop() - obj.borderBottom() - |
704 (includePadding ? obj.paddingTop() + obj.paddingBottom() | 725 (includePadding ? obj.paddingTop() + obj.paddingBottom() |
705 : LayoutUnit())); | 726 : LayoutUnit())); |
706 backgroundClipStateSaver.save(); | 727 backgroundClipStateSaver.save(); |
707 // TODO(chrishtr): this should be pixel-snapped. | 728 // TODO(chrishtr): this should be pixel-snapped. |
708 context.clip(FloatRect(clipRect)); | 729 context.clip(FloatRect(clipRect)); |
709 | 730 |
710 break; | 731 break; |
711 } | 732 } |
712 case TextFillBox: { | 733 case TextFillBox: { |
713 // First figure out how big the mask has to be. It should be no bigger tha
n what we need | 734 // First figure out how big the mask has to be. It should be no bigger |
714 // to actually render, so we should intersect the dirty rect with the bord
er box of the background. | 735 // than what we need to actually render, so we should intersect the dirty |
| 736 // rect with the border box of the background. |
715 maskRect = pixelSnappedIntRect(rect); | 737 maskRect = pixelSnappedIntRect(rect); |
716 | 738 |
717 // We draw the background into a separate layer, to be later masked with y
et another layer | 739 // We draw the background into a separate layer, to be later masked with |
718 // holding the text content. | 740 // yet another layer holding the text content. |
719 backgroundClipStateSaver.save(); | 741 backgroundClipStateSaver.save(); |
720 context.clip(maskRect); | 742 context.clip(maskRect); |
721 context.beginLayer(); | 743 context.beginLayer(); |
722 | 744 |
723 break; | 745 break; |
724 } | 746 } |
725 case BorderFillBox: | 747 case BorderFillBox: |
726 break; | 748 break; |
727 default: | 749 default: |
728 ASSERT_NOT_REACHED(); | 750 ASSERT_NOT_REACHED(); |
729 break; | 751 break; |
730 } | 752 } |
731 | 753 |
732 // Paint the color first underneath all images, culled if background image occ
ludes it. | 754 // Paint the color first underneath all images, culled if background image |
733 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the cull
ing test | 755 // occludes it. |
734 // by verifying whether the background image covers the entire painting area. | 756 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the |
| 757 // culling test by verifying whether the background image covers the entire |
| 758 // painting area. |
735 if (info.isBottomLayer && info.color.alpha()) { | 759 if (info.isBottomLayer && info.color.alpha()) { |
736 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); | 760 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); |
737 if (info.shouldPaintColor || info.shouldPaintShadow) { | 761 if (info.shouldPaintColor || info.shouldPaintShadow) { |
738 const ShadowContext shadowContext(context, obj, info.shouldPaintShadow); | 762 const ShadowContext shadowContext(context, obj, info.shouldPaintShadow); |
739 context.fillRect(backgroundRect, info.color); | 763 context.fillRect(backgroundRect, info.color); |
740 } | 764 } |
741 } | 765 } |
742 | 766 |
743 // no progressive loading of the background image | 767 // no progressive loading of the background image |
744 if (info.shouldPaintImage) { | 768 if (info.shouldPaintImage) { |
(...skipping 18 matching lines...) Expand all Loading... |
763 imageContext.image(), FloatRect(geometry->destRect()), | 787 imageContext.image(), FloatRect(geometry->destRect()), |
764 FloatPoint(geometry->phase()), FloatSize(geometry->tileSize()), | 788 FloatPoint(geometry->phase()), FloatSize(geometry->tileSize()), |
765 imageContext.compositeOp(), FloatSize(geometry->spaceSize())); | 789 imageContext.compositeOp(), FloatSize(geometry->spaceSize())); |
766 } | 790 } |
767 } | 791 } |
768 | 792 |
769 if (bgLayer.clip() == TextFillBox) { | 793 if (bgLayer.clip() == TextFillBox) { |
770 // Create the text mask layer. | 794 // Create the text mask layer. |
771 context.beginLayer(1, SkXfermode::kDstIn_Mode); | 795 context.beginLayer(1, SkXfermode::kDstIn_Mode); |
772 | 796 |
773 // Now draw the text into the mask. We do this by painting using a special p
aint phase that signals to | 797 // Now draw the text into the mask. We do this by painting using a special |
| 798 // paint phase that signals to |
774 // InlineTextBoxes that they should just add their contents to the clip. | 799 // InlineTextBoxes that they should just add their contents to the clip. |
775 PaintInfo info(context, maskRect, PaintPhaseTextClip, | 800 PaintInfo info(context, maskRect, PaintPhaseTextClip, |
776 GlobalPaintNormalPhase, 0); | 801 GlobalPaintNormalPhase, 0); |
777 if (box) { | 802 if (box) { |
778 const RootInlineBox& root = box->root(); | 803 const RootInlineBox& root = box->root(); |
779 box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), | 804 box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), |
780 scrolledPaintRect.y() - box->y()), | 805 scrolledPaintRect.y() - box->y()), |
781 root.lineTop(), root.lineBottom()); | 806 root.lineTop(), root.lineBottom()); |
782 } else { | 807 } else { |
783 // FIXME: this should only have an effect for the line box list within |ob
j|. Change this to create a LineBoxListPainter directly. | 808 // FIXME: this should only have an effect for the line box list within |
| 809 // |obj|. Change this to create a LineBoxListPainter directly. |
784 LayoutSize localOffset = | 810 LayoutSize localOffset = |
785 obj.isBox() ? toLayoutBox(&obj)->locationOffset() : LayoutSize(); | 811 obj.isBox() ? toLayoutBox(&obj)->locationOffset() : LayoutSize(); |
786 obj.paint(info, scrolledPaintRect.location() - localOffset); | 812 obj.paint(info, scrolledPaintRect.location() - localOffset); |
787 } | 813 } |
788 | 814 |
789 context.endLayer(); | 815 context.endLayer(); |
790 context.endLayer(); | 816 context.endLayer(); |
791 } | 817 } |
792 } | 818 } |
793 | 819 |
(...skipping 25 matching lines...) Expand all Loading... |
819 bool flattenCompositingLayers = | 845 bool flattenCompositingLayers = |
820 paintInfo.getGlobalPaintFlags() & GlobalPaintFlattenCompositingLayers; | 846 paintInfo.getGlobalPaintFlags() & GlobalPaintFlattenCompositingLayers; |
821 | 847 |
822 bool allMaskImagesLoaded = true; | 848 bool allMaskImagesLoaded = true; |
823 | 849 |
824 if (!compositedMask || flattenCompositingLayers) { | 850 if (!compositedMask || flattenCompositingLayers) { |
825 pushTransparencyLayer = true; | 851 pushTransparencyLayer = true; |
826 StyleImage* maskBoxImage = m_layoutBox.style()->maskBoxImage().image(); | 852 StyleImage* maskBoxImage = m_layoutBox.style()->maskBoxImage().image(); |
827 const FillLayer& maskLayers = m_layoutBox.style()->maskLayers(); | 853 const FillLayer& maskLayers = m_layoutBox.style()->maskLayers(); |
828 | 854 |
829 // Don't render a masked element until all the mask images have loaded, to p
revent a flash of unmasked content. | 855 // Don't render a masked element until all the mask images have loaded, to |
| 856 // prevent a flash of unmasked content. |
830 if (maskBoxImage) | 857 if (maskBoxImage) |
831 allMaskImagesLoaded &= maskBoxImage->isLoaded(); | 858 allMaskImagesLoaded &= maskBoxImage->isLoaded(); |
832 | 859 |
833 allMaskImagesLoaded &= maskLayers.imagesAreLoaded(); | 860 allMaskImagesLoaded &= maskLayers.imagesAreLoaded(); |
834 | 861 |
835 paintInfo.context.beginLayer(1, SkXfermode::kDstIn_Mode); | 862 paintInfo.context.beginLayer(1, SkXfermode::kDstIn_Mode); |
836 } | 863 } |
837 | 864 |
838 if (allMaskImagesLoaded) { | 865 if (allMaskImagesLoaded) { |
839 paintFillLayers(paintInfo, Color::transparent, | 866 paintFillLayers(paintInfo, Color::transparent, |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 includeLogicalRightEdge); | 932 includeLogicalRightEdge); |
906 borderPainter.paintBorder(info, rect); | 933 borderPainter.paintBorder(info, rect); |
907 } | 934 } |
908 | 935 |
909 void BoxPainter::paintBoxShadow(const PaintInfo& info, | 936 void BoxPainter::paintBoxShadow(const PaintInfo& info, |
910 const LayoutRect& paintRect, | 937 const LayoutRect& paintRect, |
911 const ComputedStyle& style, | 938 const ComputedStyle& style, |
912 ShadowStyle shadowStyle, | 939 ShadowStyle shadowStyle, |
913 bool includeLogicalLeftEdge, | 940 bool includeLogicalLeftEdge, |
914 bool includeLogicalRightEdge) { | 941 bool includeLogicalRightEdge) { |
915 // FIXME: Deal with border-image. Would be great to use border-image as a mask
. | 942 // FIXME: Deal with border-image. Would be great to use border-image as a |
| 943 // mask. |
916 GraphicsContext& context = info.context; | 944 GraphicsContext& context = info.context; |
917 if (!style.boxShadow()) | 945 if (!style.boxShadow()) |
918 return; | 946 return; |
919 FloatRoundedRect border = | 947 FloatRoundedRect border = |
920 (shadowStyle == Inset) | 948 (shadowStyle == Inset) |
921 ? style.getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, | 949 ? style.getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, |
922 includeLogicalRightEdge) | 950 includeLogicalRightEdge) |
923 : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, | 951 : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, |
924 includeLogicalRightEdge); | 952 includeLogicalRightEdge); |
925 | 953 |
(...skipping 30 matching lines...) Expand all Loading... |
956 shadowRect.inflate(shadowBlur + shadowSpread); | 984 shadowRect.inflate(shadowBlur + shadowSpread); |
957 shadowRect.move(shadowOffset); | 985 shadowRect.move(shadowOffset); |
958 | 986 |
959 // Save the state and clip, if not already done. | 987 // Save the state and clip, if not already done. |
960 // The clip does not depend on any shadow-specific properties. | 988 // The clip does not depend on any shadow-specific properties. |
961 if (!stateSaver.saved()) { | 989 if (!stateSaver.saved()) { |
962 stateSaver.save(); | 990 stateSaver.save(); |
963 if (hasBorderRadius) { | 991 if (hasBorderRadius) { |
964 FloatRoundedRect rectToClipOut = border; | 992 FloatRoundedRect rectToClipOut = border; |
965 | 993 |
966 // If the box is opaque, it is unnecessary to clip it out. However, do
ing so saves time | 994 // If the box is opaque, it is unnecessary to clip it out. However, |
967 // when painting the shadow. On the other hand, it introduces subpixel
gaps along the | 995 // doing so saves time when painting the shadow. On the other hand, it |
968 // corners. Those are avoided by insetting the clipping path by one CS
S pixel. | 996 // introduces subpixel gaps along the corners. Those are avoided by |
| 997 // insetting the clipping path by one CSS pixel. |
969 if (hasOpaqueBackground) | 998 if (hasOpaqueBackground) |
970 rectToClipOut.inflateWithRadii(-1); | 999 rectToClipOut.inflateWithRadii(-1); |
971 | 1000 |
972 if (!rectToClipOut.isEmpty()) | 1001 if (!rectToClipOut.isEmpty()) |
973 context.clipOutRoundedRect(rectToClipOut); | 1002 context.clipOutRoundedRect(rectToClipOut); |
974 } else { | 1003 } else { |
975 // This IntRect is correct even with fractional shadows, because it is
used for the rectangle | 1004 // This IntRect is correct even with fractional shadows, because it is |
976 // of the box itself, which is always pixel-aligned. | 1005 // used for the rectangle of the box itself, which is always |
| 1006 // pixel-aligned. |
977 FloatRect rectToClipOut = border.rect(); | 1007 FloatRect rectToClipOut = border.rect(); |
978 | 1008 |
979 // If the box is opaque, it is unnecessary to clip it out. However, do
ing so saves time | 1009 // If the box is opaque, it is unnecessary to clip it out. However, |
980 // when painting the shadow. On the other hand, it introduces subpixel
gaps along the | 1010 // doing so saves time when painting the shadow. On the other hand, it |
981 // edges if they are not pixel-aligned. Those are avoided by insetting
the clipping path | 1011 // introduces subpixel gaps along the edges if they are not |
982 // by one CSS pixel. | 1012 // pixel-aligned. Those are avoided by insetting the clipping path by |
| 1013 // one CSS pixel. |
983 if (hasOpaqueBackground) | 1014 if (hasOpaqueBackground) |
984 rectToClipOut.inflate(-1); | 1015 rectToClipOut.inflate(-1); |
985 | 1016 |
986 if (!rectToClipOut.isEmpty()) | 1017 if (!rectToClipOut.isEmpty()) |
987 context.clipOut(rectToClipOut); | 1018 context.clipOut(rectToClipOut); |
988 } | 1019 } |
989 } | 1020 } |
990 | 1021 |
991 // Draw only the shadow. | 1022 // Draw only the shadow. |
992 context.setShadow(shadowOffset, shadowBlur, shadowColor, | 1023 context.setShadow(shadowOffset, shadowBlur, shadowColor, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1040 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( | 1071 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( |
1041 const ComputedStyle& style, | 1072 const ComputedStyle& style, |
1042 const Document& document) { | 1073 const Document& document) { |
1043 return document.printing() && | 1074 return document.printing() && |
1044 style.getPrintColorAdjust() == PrintColorAdjustEconomy && | 1075 style.getPrintColorAdjust() == PrintColorAdjustEconomy && |
1045 (!document.settings() || | 1076 (!document.settings() || |
1046 !document.settings()->shouldPrintBackgrounds()); | 1077 !document.settings()->shouldPrintBackgrounds()); |
1047 } | 1078 } |
1048 | 1079 |
1049 } // namespace blink | 1080 } // namespace blink |
OLD | NEW |