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/BackgroundImageGeometry.h" | 5 #include "core/paint/BackgroundImageGeometry.h" |
6 | 6 |
7 #include "core/frame/FrameView.h" | 7 #include "core/frame/FrameView.h" |
8 #include "core/layout/LayoutBox.h" | 8 #include "core/layout/LayoutBox.h" |
9 #include "core/layout/LayoutBoxModelObject.h" | 9 #include "core/layout/LayoutBoxModelObject.h" |
10 #include "core/layout/LayoutView.h" | 10 #include "core/layout/LayoutView.h" |
11 #include "core/layout/compositing/CompositedLayerMapping.h" | 11 #include "core/layout/compositing/CompositedLayerMapping.h" |
12 #include "core/paint/PaintLayer.h" | 12 #include "core/paint/PaintLayer.h" |
13 #include "platform/LayoutUnit.h" | 13 #include "platform/LayoutUnit.h" |
14 #include "platform/geometry/LayoutRect.h" | 14 #include "platform/geometry/LayoutRect.h" |
15 | 15 |
16 namespace blink { | 16 namespace blink { |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 // Return the amount of space to leave between image tiles for the background-re
peat: space property. | 20 // Return the amount of space to leave between image tiles for the background-re
peat: space property. |
21 inline LayoutUnit getSpaceBetweenImageTiles(LayoutUnit areaSize, LayoutUnit tile
Size) | 21 inline LayoutUnit getSpaceBetweenImageTiles(LayoutUnit areaSize, LayoutUnit tile
Size) |
22 { | 22 { |
23 int numberOfTiles = areaSize / tileSize; | 23 int numberOfTiles = areaSize / tileSize; |
24 LayoutUnit space = -1; | 24 LayoutUnit space(-1); |
25 | 25 |
26 if (numberOfTiles > 1) { | 26 if (numberOfTiles > 1) { |
27 // Spec doesn't specify rounding, so use the same method as for backgrou
nd-repeat: round. | 27 // Spec doesn't specify rounding, so use the same method as for backgrou
nd-repeat: round. |
28 space = (areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1); | 28 space = (areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1); |
29 } | 29 } |
30 | 30 |
31 return space; | 31 return space; |
32 } | 32 } |
33 | 33 |
34 bool fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj, const Glob
alPaintFlags globalPaintFlags) | 34 bool fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj, const Glob
alPaintFlags globalPaintFlags) |
(...skipping 21 matching lines...) Expand all Loading... |
56 LayoutSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image,
positioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom); | 56 LayoutSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image,
positioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom); |
57 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal
eFactor()); | 57 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal
eFactor()); |
58 switch (type) { | 58 switch (type) { |
59 case SizeLength: { | 59 case SizeLength: { |
60 LayoutSize tileSize(positioningAreaSize); | 60 LayoutSize tileSize(positioningAreaSize); |
61 | 61 |
62 Length layerWidth = fillLayer.size().size.width(); | 62 Length layerWidth = fillLayer.size().size.width(); |
63 Length layerHeight = fillLayer.size().size.height(); | 63 Length layerHeight = fillLayer.size().size.height(); |
64 | 64 |
65 if (layerWidth.isFixed()) | 65 if (layerWidth.isFixed()) |
66 tileSize.setWidth(layerWidth.value()); | 66 tileSize.setWidth(LayoutUnit(layerWidth.value())); |
67 else if (layerWidth.hasPercent()) | 67 else if (layerWidth.hasPercent()) |
68 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.wid
th())); | 68 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.wid
th())); |
69 | 69 |
70 if (layerHeight.isFixed()) | 70 if (layerHeight.isFixed()) |
71 tileSize.setHeight(layerHeight.value()); | 71 tileSize.setHeight(LayoutUnit(layerHeight.value())); |
72 else if (layerHeight.hasPercent()) | 72 else if (layerHeight.hasPercent()) |
73 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.h
eight())); | 73 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.h
eight())); |
74 | 74 |
75 // If one of the values is auto we have to use the appropriate | 75 // If one of the values is auto we have to use the appropriate |
76 // scale to maintain our aspect ratio. | 76 // scale to maintain our aspect ratio. |
77 if (layerWidth.isAuto() && !layerHeight.isAuto()) { | 77 if (layerWidth.isAuto() && !layerHeight.isAuto()) { |
78 if (imageIntrinsicSize.height()) { | 78 if (imageIntrinsicSize.height()) { |
79 LayoutUnit adjustedWidth = imageIntrinsicSize.width() * tileSize
.height() / imageIntrinsicSize.height(); | 79 LayoutUnit adjustedWidth = imageIntrinsicSize.width() * tileSize
.height() / imageIntrinsicSize.height(); |
80 if (imageIntrinsicSize.width() >= 1 && adjustedWidth < 1) | 80 if (imageIntrinsicSize.width() >= 1 && adjustedWidth < 1) |
81 adjustedWidth = 1; | 81 adjustedWidth = LayoutUnit(1); |
82 tileSize.setWidth(adjustedWidth); | 82 tileSize.setWidth(adjustedWidth); |
83 } | 83 } |
84 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) { | 84 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) { |
85 if (imageIntrinsicSize.width()) { | 85 if (imageIntrinsicSize.width()) { |
86 LayoutUnit adjustedHeight = imageIntrinsicSize.height() * tileSi
ze.width() / imageIntrinsicSize.width(); | 86 LayoutUnit adjustedHeight = imageIntrinsicSize.height() * tileSi
ze.width() / imageIntrinsicSize.width(); |
87 if (imageIntrinsicSize.height() >= 1 && adjustedHeight < 1) | 87 if (imageIntrinsicSize.height() >= 1 && adjustedHeight < 1) |
88 adjustedHeight = 1; | 88 adjustedHeight = LayoutUnit(1); |
89 tileSize.setHeight(adjustedHeight); | 89 tileSize.setHeight(adjustedHeight); |
90 } | 90 } |
91 } else if (layerWidth.isAuto() && layerHeight.isAuto()) { | 91 } else if (layerWidth.isAuto() && layerHeight.isAuto()) { |
92 // If both width and height are auto, use the image's intrinsic size
. | 92 // If both width and height are auto, use the image's intrinsic size
. |
93 tileSize = imageIntrinsicSize; | 93 tileSize = imageIntrinsicSize; |
94 } | 94 } |
95 | 95 |
96 tileSize.clampNegativeToZero(); | 96 tileSize.clampNegativeToZero(); |
97 return tileSize; | 97 return tileSize; |
98 } | 98 } |
99 case SizeNone: { | 99 case SizeNone: { |
100 // If both values are 'auto' then the intrinsic width and/or height of t
he image should be used, if any. | 100 // If both values are 'auto' then the intrinsic width and/or height of t
he image should be used, if any. |
101 if (!imageIntrinsicSize.isEmpty()) | 101 if (!imageIntrinsicSize.isEmpty()) |
102 return imageIntrinsicSize; | 102 return imageIntrinsicSize; |
103 | 103 |
104 // If the image has neither an intrinsic width nor an intrinsic height,
its size is determined as for 'contain'. | 104 // If the image has neither an intrinsic width nor an intrinsic height,
its size is determined as for 'contain'. |
105 type = Contain; | 105 type = Contain; |
106 } | 106 } |
107 case Contain: | 107 case Contain: |
108 case Cover: { | 108 case Cover: { |
109 float horizontalScaleFactor = imageIntrinsicSize.width() | 109 float horizontalScaleFactor = imageIntrinsicSize.width() |
110 ? positioningAreaSize.width().toFloat() / imageIntrinsicSize.width()
: 1; | 110 ? positioningAreaSize.width().toFloat() / imageIntrinsicSize.width()
: 1.0f; |
111 float verticalScaleFactor = imageIntrinsicSize.height() | 111 float verticalScaleFactor = imageIntrinsicSize.height() |
112 ? positioningAreaSize.height().toFloat() / imageIntrinsicSize.height
() : 1; | 112 ? positioningAreaSize.height().toFloat() / imageIntrinsicSize.height
() : 1.0f; |
113 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, ve
rticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor); | 113 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, ve
rticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor); |
114 return LayoutSize(std::max<LayoutUnit>(1, imageIntrinsicSize.width() * s
caleFactor), std::max<LayoutUnit>(1, imageIntrinsicSize.height() * scaleFactor))
; | 114 return LayoutSize(std::max(1.0f, imageIntrinsicSize.width() * scaleFacto
r), |
| 115 std::max(1.0f, imageIntrinsicSize.height() * scaleFactor)); |
115 } | 116 } |
116 } | 117 } |
117 | 118 |
118 ASSERT_NOT_REACHED(); | 119 ASSERT_NOT_REACHED(); |
119 return LayoutSize(); | 120 return LayoutSize(); |
120 } | 121 } |
121 | 122 |
122 IntPoint accumulatedScrollOffsetForFixedBackground(const LayoutBoxModelObject& o
bject, const LayoutBoxModelObject* container) | 123 IntPoint accumulatedScrollOffsetForFixedBackground(const LayoutBoxModelObject& o
bject, const LayoutBoxModelObject* container) |
123 { | 124 { |
124 IntPoint result; | 125 IntPoint result; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 fixedAttachment = false; | 215 fixedAttachment = false; |
215 } | 216 } |
216 | 217 |
217 if (!fixedAttachment) { | 218 if (!fixedAttachment) { |
218 setDestRect(paintRect); | 219 setDestRect(paintRect); |
219 | 220 |
220 LayoutUnit right; | 221 LayoutUnit right; |
221 LayoutUnit bottom; | 222 LayoutUnit bottom; |
222 // Scroll and Local. | 223 // Scroll and Local. |
223 if (fillLayer.origin() != BorderFillBox) { | 224 if (fillLayer.origin() != BorderFillBox) { |
224 left = positioningBox.borderLeft(); | 225 left = LayoutUnit(positioningBox.borderLeft()); |
225 right = positioningBox.borderRight(); | 226 right = LayoutUnit(positioningBox.borderRight()); |
226 top = positioningBox.borderTop(); | 227 top = LayoutUnit(positioningBox.borderTop()); |
227 bottom = positioningBox.borderBottom(); | 228 bottom = LayoutUnit(positioningBox.borderBottom()); |
228 if (fillLayer.origin() == ContentFillBox) { | 229 if (fillLayer.origin() == ContentFillBox) { |
229 left += positioningBox.paddingLeft(); | 230 left += positioningBox.paddingLeft(); |
230 right += positioningBox.paddingRight(); | 231 right += positioningBox.paddingRight(); |
231 top += positioningBox.paddingTop(); | 232 top += positioningBox.paddingTop(); |
232 bottom += positioningBox.paddingBottom(); | 233 bottom += positioningBox.paddingBottom(); |
233 } | 234 } |
234 } | 235 } |
235 | 236 |
236 if (isLayoutView) { | 237 if (isLayoutView) { |
237 // The background of the box generated by the root element covers th
e entire canvas and will | 238 // The background of the box generated by the root element covers th
e entire canvas and will |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 | 287 |
287 fillTileSize.setWidth(positioningAreaSize.width() / nrTiles); | 288 fillTileSize.setWidth(positioningAreaSize.width() / nrTiles); |
288 | 289 |
289 // Maintain aspect ratio if background-size: auto is set | 290 // Maintain aspect ratio if background-size: auto is set |
290 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun
dFill) { | 291 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun
dFill) { |
291 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w
idth() / (nrTiles * fillTileSize.width())); | 292 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w
idth() / (nrTiles * fillTileSize.width())); |
292 } | 293 } |
293 | 294 |
294 setTileSize(fillTileSize); | 295 setTileSize(fillTileSize); |
295 setImageContainerSize(fillTileSize); | 296 setImageContainerSize(fillTileSize); |
296 setPhaseX(tileSize().width() ? tileSize().width() - fmodf((computedXPosi
tion + left), tileSize().width()) : 0.0f); | 297 setPhaseX(tileSize().width() ? LayoutUnit(tileSize().width() - fmodf((co
mputedXPosition + left), tileSize().width())) |
| 298 : LayoutUnit()); |
297 setSpaceSize(LayoutSize()); | 299 setSpaceSize(LayoutSize()); |
298 } | 300 } |
299 | 301 |
300 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit
ion(), availableHeight); | 302 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit
ion(), availableHeight); |
301 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > LayoutU
nit() && fillTileSize.height() > LayoutUnit()) { | 303 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > LayoutU
nit() && fillTileSize.height() > LayoutUnit()) { |
302 int nrTiles = std::max(1, roundToInt(positioningAreaSize.height() / fill
TileSize.height())); | 304 int nrTiles = std::max(1, roundToInt(positioningAreaSize.height() / fill
TileSize.height())); |
303 | 305 |
304 fillTileSize.setHeight(positioningAreaSize.height() / nrTiles); | 306 fillTileSize.setHeight(positioningAreaSize.height() / nrTiles); |
305 | 307 |
306 // Maintain aspect ratio if background-size: auto is set | 308 // Maintain aspect ratio if background-size: auto is set |
307 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round
Fill) { | 309 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round
Fill) { |
308 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei
ght() / (nrTiles * fillTileSize.height())); | 310 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei
ght() / (nrTiles * fillTileSize.height())); |
309 } | 311 } |
310 | 312 |
311 setTileSize(fillTileSize); | 313 setTileSize(fillTileSize); |
312 setImageContainerSize(fillTileSize); | 314 setImageContainerSize(fillTileSize); |
313 setPhaseY(tileSize().height() ? tileSize().height() - fmodf((computedYPo
sition + top), tileSize().height()) : 0.0f); | 315 setPhaseY(tileSize().height() ? LayoutUnit(tileSize().height() - fmodf((
computedYPosition + top), tileSize().height())) |
| 316 : LayoutUnit()); |
314 setSpaceSize(LayoutSize()); | 317 setSpaceSize(LayoutSize()); |
315 } | 318 } |
316 | 319 |
317 if (backgroundRepeatX == RepeatFill) { | 320 if (backgroundRepeatX == RepeatFill) { |
318 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; | 321 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; |
319 setPhaseX(tileSize().width() ? tileSize().width() - fmodf((xOffset + lef
t), tileSize().width()) : 0.0f); | 322 setPhaseX(tileSize().width() ? LayoutUnit(tileSize().width() - fmodf((xO
ffset + left), tileSize().width())) |
| 323 : LayoutUnit()); |
320 setSpaceSize(LayoutSize()); | 324 setSpaceSize(LayoutSize()); |
321 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > LayoutUn
it()) { | 325 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > LayoutUn
it()) { |
322 LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.width()
, tileSize().width()); | 326 LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.width()
, tileSize().width()); |
323 LayoutUnit actualWidth = tileSize().width() + space; | 327 LayoutUnit actualWidth = tileSize().width() + space; |
324 | 328 |
325 if (space >= LayoutUnit()) { | 329 if (space >= LayoutUnit()) { |
326 computedXPosition = roundedMinimumValueForLength(Length(), available
Width); | 330 computedXPosition = roundedMinimumValueForLength(Length(), available
Width); |
327 setSpaceSize(LayoutSize(space, LayoutUnit())); | 331 setSpaceSize(LayoutSize(space, LayoutUnit())); |
328 setPhaseX(actualWidth ? actualWidth - fmodf((computedXPosition + lef
t), actualWidth) : 0.0f); | 332 setPhaseX(actualWidth ? LayoutUnit(actualWidth - fmodf((computedXPos
ition + left), actualWidth)) : LayoutUnit()); |
329 } else { | 333 } else { |
330 backgroundRepeatX = NoRepeatFill; | 334 backgroundRepeatX = NoRepeatFill; |
331 } | 335 } |
332 } | 336 } |
333 if (backgroundRepeatX == NoRepeatFill) { | 337 if (backgroundRepeatX == NoRepeatFill) { |
334 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; | 338 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; |
335 setNoRepeatX(left + xOffset); | 339 setNoRepeatX(left + xOffset); |
336 setSpaceSize(LayoutSize(LayoutUnit(), spaceSize().height())); | 340 setSpaceSize(LayoutSize(LayoutUnit(), spaceSize().height())); |
337 } | 341 } |
338 | 342 |
339 if (backgroundRepeatY == RepeatFill) { | 343 if (backgroundRepeatY == RepeatFill) { |
340 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; | 344 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; |
341 setPhaseY(tileSize().height() ? tileSize().height() - fmodf((yOffset + t
op), tileSize().height()) : 0.0f); | 345 setPhaseY(tileSize().height() ? LayoutUnit(tileSize().height() - fmodf((
yOffset + top), tileSize().height())) |
| 346 : LayoutUnit()); |
342 setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit())); | 347 setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit())); |
343 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > LayoutU
nit()) { | 348 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > LayoutU
nit()) { |
344 LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.height(
), tileSize().height()); | 349 LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.height(
), tileSize().height()); |
345 LayoutUnit actualHeight = tileSize().height() + space; | 350 LayoutUnit actualHeight = tileSize().height() + space; |
346 | 351 |
347 if (space >= LayoutUnit()) { | 352 if (space >= LayoutUnit()) { |
348 computedYPosition = roundedMinimumValueForLength(Length(), available
Height); | 353 computedYPosition = roundedMinimumValueForLength(Length(), available
Height); |
349 setSpaceSize(LayoutSize(spaceSize().width(), space)); | 354 setSpaceSize(LayoutSize(spaceSize().width(), space)); |
350 setPhaseY(actualHeight ? actualHeight - fmodf((computedYPosition + t
op), actualHeight) : 0.0f); | 355 setPhaseY(actualHeight ? LayoutUnit(actualHeight - fmodf((computedYP
osition + top), actualHeight)) : LayoutUnit()); |
351 } else { | 356 } else { |
352 backgroundRepeatY = NoRepeatFill; | 357 backgroundRepeatY = NoRepeatFill; |
353 } | 358 } |
354 } | 359 } |
355 if (backgroundRepeatY == NoRepeatFill) { | 360 if (backgroundRepeatY == NoRepeatFill) { |
356 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; | 361 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; |
357 setNoRepeatY(top + yOffset); | 362 setNoRepeatY(top + yOffset); |
358 setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit())); | 363 setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit())); |
359 } | 364 } |
360 | 365 |
361 if (fixedAttachment) | 366 if (fixedAttachment) |
362 useFixedAttachment(paintRect.location()); | 367 useFixedAttachment(paintRect.location()); |
363 | 368 |
364 clip(paintRect); | 369 clip(paintRect); |
365 pixelSnapGeometry(); | 370 pixelSnapGeometry(); |
366 } | 371 } |
367 | 372 |
368 } // namespace blink | 373 } // namespace blink |
OLD | NEW |