| 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/BackgroundImageGeometry.h" | 6 #include "core/paint/BackgroundImageGeometry.h" |
| 7 | 7 |
| 8 #include "core/frame/FrameView.h" | 8 #include "core/frame/FrameView.h" |
| 9 #include "core/layout/LayoutBox.h" | 9 #include "core/layout/LayoutBox.h" |
| 10 #include "core/layout/LayoutBoxModelObject.h" | 10 #include "core/layout/LayoutBoxModelObject.h" |
| 11 #include "core/layout/LayoutView.h" | 11 #include "core/layout/LayoutView.h" |
| 12 #include "core/layout/compositing/CompositedLayerMapping.h" | 12 #include "core/layout/compositing/CompositedLayerMapping.h" |
| 13 #include "core/paint/PaintLayer.h" | 13 #include "core/paint/PaintLayer.h" |
| 14 #include "platform/LayoutUnit.h" | 14 #include "platform/LayoutUnit.h" |
| 15 #include "platform/geometry/LayoutRect.h" | 15 #include "platform/geometry/LayoutRect.h" |
| 16 | 16 |
| 17 namespace blink { | 17 namespace blink { |
| 18 | 18 |
| 19 namespace { | 19 namespace { |
| 20 | 20 |
| 21 inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSiz
e& positioningAreaSize) | |
| 22 { | |
| 23 tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tile
Size.width().ceil() : tileSize.width().floor()); | |
| 24 tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? t
ileSize.height().ceil() : tileSize.height().floor()); | |
| 25 } | |
| 26 | |
| 27 // Return the amount of space to leave between image tiles for the background-re
peat: space property. | 21 // Return the amount of space to leave between image tiles for the background-re
peat: space property. |
| 28 inline int getSpaceBetweenImageTiles(int areaSize, int tileSize) | 22 inline LayoutUnit getSpaceBetweenImageTiles(LayoutUnit areaSize, LayoutUnit tile
Size) |
| 29 { | 23 { |
| 30 int numberOfTiles = areaSize / tileSize; | 24 int numberOfTiles = areaSize / tileSize; |
| 31 int space = -1; | 25 LayoutUnit space = -1; |
| 32 | 26 |
| 33 if (numberOfTiles > 1) { | 27 if (numberOfTiles > 1) { |
| 34 // Spec doesn't specify rounding, so use the same method as for backgrou
nd-repeat: round. | 28 // Spec doesn't specify rounding, so use the same method as for backgrou
nd-repeat: round. |
| 35 space = lroundf((areaSize - numberOfTiles * tileSize) / (float)(numberOf
Tiles - 1)); | 29 space = (areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1); |
| 36 } | 30 } |
| 37 | 31 |
| 38 return space; | 32 return space; |
| 39 } | 33 } |
| 40 | 34 |
| 41 bool fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj, const Glob
alPaintFlags globalPaintFlags) | 35 bool fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj, const Glob
alPaintFlags globalPaintFlags) |
| 42 { | 36 { |
| 43 if (!obj.isLayoutView()) | 37 if (!obj.isLayoutView()) |
| 44 return false; | 38 return false; |
| 45 | 39 |
| 46 const LayoutView& view = toLayoutView(obj); | 40 const LayoutView& view = toLayoutView(obj); |
| 47 | 41 |
| 48 if (globalPaintFlags & GlobalPaintFlattenCompositingLayers) | 42 if (globalPaintFlags & GlobalPaintFlattenCompositingLayers) |
| 49 return false; | 43 return false; |
| 50 | 44 |
| 51 PaintLayer* rootLayer = view.layer(); | 45 PaintLayer* rootLayer = view.layer(); |
| 52 if (!rootLayer || rootLayer->compositingState() == NotComposited) | 46 if (!rootLayer || rootLayer->compositingState() == NotComposited) |
| 53 return false; | 47 return false; |
| 54 | 48 |
| 55 return rootLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBa
ckground(); | 49 return rootLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBa
ckground(); |
| 56 } | 50 } |
| 57 | 51 |
| 58 IntSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer&
fillLayer, const IntSize& positioningAreaSize) | 52 LayoutSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLaye
r& fillLayer, const LayoutSize& positioningAreaSize) |
| 59 { | 53 { |
| 60 StyleImage* image = fillLayer.image(); | 54 StyleImage* image = fillLayer.image(); |
| 61 EFillSizeType type = fillLayer.size().type; | 55 EFillSizeType type = fillLayer.size().type; |
| 62 | 56 |
| 63 IntSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, po
sitioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom); | 57 LayoutSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image,
positioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom); |
| 64 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal
eFactor()); | 58 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal
eFactor()); |
| 65 switch (type) { | 59 switch (type) { |
| 66 case SizeLength: { | 60 case SizeLength: { |
| 67 LayoutSize tileSize(positioningAreaSize); | 61 LayoutSize tileSize(positioningAreaSize); |
| 68 | 62 |
| 69 Length layerWidth = fillLayer.size().size.width(); | 63 Length layerWidth = fillLayer.size().size.width(); |
| 70 Length layerHeight = fillLayer.size().size.height(); | 64 Length layerHeight = fillLayer.size().size.height(); |
| 71 | 65 |
| 72 if (layerWidth.isFixed()) | 66 if (layerWidth.isFixed()) |
| 73 tileSize.setWidth(layerWidth.value()); | 67 tileSize.setWidth(layerWidth.value()); |
| 74 else if (layerWidth.hasPercent()) | 68 else if (layerWidth.hasPercent()) |
| 75 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.wid
th())); | 69 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.wid
th())); |
| 76 | 70 |
| 77 if (layerHeight.isFixed()) | 71 if (layerHeight.isFixed()) |
| 78 tileSize.setHeight(layerHeight.value()); | 72 tileSize.setHeight(layerHeight.value()); |
| 79 else if (layerHeight.hasPercent()) | 73 else if (layerHeight.hasPercent()) |
| 80 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.h
eight())); | 74 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.h
eight())); |
| 81 | 75 |
| 82 applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize); | |
| 83 | |
| 84 // If one of the values is auto we have to use the appropriate | 76 // If one of the values is auto we have to use the appropriate |
| 85 // scale to maintain our aspect ratio. | 77 // scale to maintain our aspect ratio. |
| 86 if (layerWidth.isAuto() && !layerHeight.isAuto()) { | 78 if (layerWidth.isAuto() && !layerHeight.isAuto()) { |
| 87 if (imageIntrinsicSize.height()) { | 79 if (imageIntrinsicSize.height()) { |
| 88 LayoutUnit adjustedWidth = imageIntrinsicSize.width() * tileSize
.height() / imageIntrinsicSize.height(); | 80 LayoutUnit adjustedWidth = imageIntrinsicSize.width() * tileSize
.height() / imageIntrinsicSize.height(); |
| 89 if (imageIntrinsicSize.width() >= 1 && adjustedWidth < 1) | 81 if (imageIntrinsicSize.width() >= 1 && adjustedWidth < 1) |
| 90 adjustedWidth = 1; | 82 adjustedWidth = 1; |
| 91 tileSize.setWidth(adjustedWidth); | 83 tileSize.setWidth(adjustedWidth); |
| 92 } | 84 } |
| 93 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) { | 85 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) { |
| 94 if (imageIntrinsicSize.width()) { | 86 if (imageIntrinsicSize.width()) { |
| 95 LayoutUnit adjustedHeight = imageIntrinsicSize.height() * tileSi
ze.width() / imageIntrinsicSize.width(); | 87 LayoutUnit adjustedHeight = imageIntrinsicSize.height() * tileSi
ze.width() / imageIntrinsicSize.width(); |
| 96 if (imageIntrinsicSize.height() >= 1 && adjustedHeight < 1) | 88 if (imageIntrinsicSize.height() >= 1 && adjustedHeight < 1) |
| 97 adjustedHeight = 1; | 89 adjustedHeight = 1; |
| 98 tileSize.setHeight(adjustedHeight); | 90 tileSize.setHeight(adjustedHeight); |
| 99 } | 91 } |
| 100 } else if (layerWidth.isAuto() && layerHeight.isAuto()) { | 92 } else if (layerWidth.isAuto() && layerHeight.isAuto()) { |
| 101 // If both width and height are auto, use the image's intrinsic size
. | 93 // If both width and height are auto, use the image's intrinsic size
. |
| 102 tileSize = LayoutSize(imageIntrinsicSize); | 94 tileSize = imageIntrinsicSize; |
| 103 } | 95 } |
| 104 | 96 |
| 105 tileSize.clampNegativeToZero(); | 97 tileSize.clampNegativeToZero(); |
| 106 return flooredIntSize(tileSize); | 98 return tileSize; |
| 107 } | 99 } |
| 108 case SizeNone: { | 100 case SizeNone: { |
| 109 // If both values are 'auto' then the intrinsic width and/or height of t
he image should be used, if any. | 101 // If both values are 'auto' then the intrinsic width and/or height of t
he image should be used, if any. |
| 110 if (!imageIntrinsicSize.isEmpty()) | 102 if (!imageIntrinsicSize.isEmpty()) |
| 111 return imageIntrinsicSize; | 103 return imageIntrinsicSize; |
| 112 | 104 |
| 113 // If the image has neither an intrinsic width nor an intrinsic height,
its size is determined as for 'contain'. | 105 // If the image has neither an intrinsic width nor an intrinsic height,
its size is determined as for 'contain'. |
| 114 type = Contain; | 106 type = Contain; |
| 115 } | 107 } |
| 116 case Contain: | 108 case Contain: |
| 117 case Cover: { | 109 case Cover: { |
| 118 float horizontalScaleFactor = imageIntrinsicSize.width() | 110 float horizontalScaleFactor = imageIntrinsicSize.width() |
| 119 ? static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSi
ze.width() : 1; | 111 ? positioningAreaSize.width().toFloat() / imageIntrinsicSize.width()
: 1; |
| 120 float verticalScaleFactor = imageIntrinsicSize.height() | 112 float verticalScaleFactor = imageIntrinsicSize.height() |
| 121 ? static_cast<float>(positioningAreaSize.height()) / imageIntrinsicS
ize.height() : 1; | 113 ? positioningAreaSize.height().toFloat() / imageIntrinsicSize.height
() : 1; |
| 122 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, ve
rticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor); | 114 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, ve
rticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor); |
| 123 return IntSize(std::max(1l, lround(imageIntrinsicSize.width() * scaleFac
tor)), std::max(1l, lround(imageIntrinsicSize.height() * scaleFactor))); | 115 return LayoutSize(std::max<LayoutUnit>(1, imageIntrinsicSize.width() * s
caleFactor), std::max<LayoutUnit>(1, imageIntrinsicSize.height() * scaleFactor))
; |
| 124 } | 116 } |
| 125 } | 117 } |
| 126 | 118 |
| 127 ASSERT_NOT_REACHED(); | 119 ASSERT_NOT_REACHED(); |
| 128 return IntSize(); | 120 return LayoutSize(); |
| 129 } | 121 } |
| 130 | 122 |
| 131 IntPoint accumulatedScrollOffset(const LayoutBoxModelObject& object, const Layou
tBoxModelObject* container) | 123 IntPoint accumulatedScrollOffset(const LayoutBoxModelObject& object, const Layou
tBoxModelObject* container) |
| 132 { | 124 { |
| 133 const LayoutBlock* block = object.isLayoutBlock() ? toLayoutBlock(&object) :
object.containingBlock(); | 125 const LayoutBlock* block = object.isLayoutBlock() ? toLayoutBlock(&object) :
object.containingBlock(); |
| 134 IntPoint result; | 126 IntPoint result; |
| 135 while (block) { | 127 while (block) { |
| 136 if (block->hasOverflowClip()) | 128 if (block->hasOverflowClip()) |
| 137 result += block->scrolledContentOffset(); | 129 result += block->scrolledContentOffset(); |
| 138 if (block == container) | 130 if (block == container) |
| 139 break; | 131 break; |
| 140 block = block->containingBlock(); | 132 block = block->containingBlock(); |
| 141 } | 133 } |
| 142 return result; | 134 return result; |
| 143 } | 135 } |
| 144 | 136 |
| 145 } // anonymous namespace | 137 } // anonymous namespace |
| 146 | 138 |
| 147 void BackgroundImageGeometry::setNoRepeatX(int xOffset) | 139 void BackgroundImageGeometry::setNoRepeatX(LayoutUnit xOffset) |
| 148 { | 140 { |
| 149 m_destRect.move(std::max(xOffset, 0), 0); | 141 m_destRect.move(std::max(xOffset, LayoutUnit()), LayoutUnit()); |
| 150 m_phase.setX(-std::min(xOffset, 0)); | 142 m_phase.setX(-std::min(xOffset, LayoutUnit())); |
| 151 m_destRect.setWidth(m_tileSize.width() + std::min(xOffset, 0)); | 143 m_destRect.setWidth(m_tileSize.width() + std::min(xOffset, LayoutUnit())); |
| 152 } | 144 } |
| 153 | 145 |
| 154 void BackgroundImageGeometry::setNoRepeatY(int yOffset) | 146 void BackgroundImageGeometry::setNoRepeatY(LayoutUnit yOffset) |
| 155 { | 147 { |
| 156 m_destRect.move(0, std::max(yOffset, 0)); | 148 m_destRect.move(LayoutUnit(), std::max(yOffset, LayoutUnit())); |
| 157 m_phase.setY(-std::min(yOffset, 0)); | 149 m_phase.setY(-std::min(yOffset, LayoutUnit())); |
| 158 m_destRect.setHeight(m_tileSize.height() + std::min(yOffset, 0)); | 150 m_destRect.setHeight(m_tileSize.height() + std::min(yOffset, LayoutUnit())); |
| 159 } | 151 } |
| 160 | 152 |
| 161 void BackgroundImageGeometry::useFixedAttachment(const IntPoint& attachmentPoint
) | 153 void BackgroundImageGeometry::useFixedAttachment(const LayoutPoint& attachmentPo
int) |
| 162 { | 154 { |
| 163 IntPoint alignedPoint = attachmentPoint; | 155 LayoutPoint alignedPoint = attachmentPoint; |
| 164 m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), 0), std::max(aligne
dPoint.y() - m_destRect.y(), 0)); | 156 m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), LayoutUnit()), std:
:max(alignedPoint.y() - m_destRect.y(), LayoutUnit())); |
| 165 } | 157 } |
| 166 | 158 |
| 167 void BackgroundImageGeometry::clip(const IntRect& clipRect) | 159 void BackgroundImageGeometry::clip(const LayoutRect& clipRect) |
| 168 { | 160 { |
| 169 m_destRect.intersect(clipRect); | 161 m_destRect.intersect(clipRect); |
| 170 } | 162 } |
| 171 | 163 |
| 164 // When we match the destination rect in a dimension, we snap the same way. Othe
rwise |
| 165 // we floor to avoid growing our tile size. Often these tiles are from a sprite
map, |
| 166 // and bleeding adjactent sprites is visually worse than clipping the intenteded
one. |
| 167 static LayoutSize applySubPixelHeuristicToImageSize(const LayoutSize& size, cons
t LayoutRect& destination) |
| 168 { |
| 169 LayoutSize snappedSize = LayoutSize( |
| 170 size.width() == destination.width() ? destination.pixelSnappedWidth() :
size.width().floor(), |
| 171 size.height() == destination.height() ? destination.pixelSnappedHeight()
: size.height().floor()); |
| 172 return snappedSize; |
| 173 } |
| 174 |
| 175 void BackgroundImageGeometry::pixelSnapGeometry() |
| 176 { |
| 177 setTileSize(applySubPixelHeuristicToImageSize(m_tileSize, m_destRect)); |
| 178 setImageContainerSize(applySubPixelHeuristicToImageSize(m_imageContainerSize
, m_destRect)); |
| 179 setSpaceSize(LayoutSize(roundedIntSize(m_repeatSpacing))); |
| 180 setDestRect(LayoutRect(pixelSnappedIntRect(m_destRect))); |
| 181 setPhase(LayoutPoint(flooredIntPoint(m_phase))); |
| 182 } |
| 183 |
| 172 void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
ayoutBoxModelObject* paintContainer, | 184 void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
ayoutBoxModelObject* paintContainer, |
| 173 const GlobalPaintFlags globalPaintFlags, const FillLayer& fillLayer, const L
ayoutRect& paintRect) | 185 const GlobalPaintFlags globalPaintFlags, const FillLayer& fillLayer, const L
ayoutRect& paintRect) |
| 174 { | 186 { |
| 175 LayoutUnit left = 0; | 187 LayoutUnit left; |
| 176 LayoutUnit top = 0; | 188 LayoutUnit top; |
| 177 IntSize positioningAreaSize; | 189 LayoutSize positioningAreaSize; |
| 178 IntRect snappedPaintRect = pixelSnappedIntRect(paintRect); | |
| 179 bool isLayoutView = obj.isLayoutView(); | 190 bool isLayoutView = obj.isLayoutView(); |
| 180 const LayoutBox* rootBox = nullptr; | 191 const LayoutBox* rootBox = nullptr; |
| 181 if (isLayoutView) { | 192 if (isLayoutView) { |
| 182 // It is only possible reach here when root element has a box. | 193 // It is only possible reach here when root element has a box. |
| 183 Element* documentElement = obj.document().documentElement(); | 194 Element* documentElement = obj.document().documentElement(); |
| 184 ASSERT(documentElement); | 195 ASSERT(documentElement); |
| 185 ASSERT(documentElement->layoutObject()); | 196 ASSERT(documentElement->layoutObject()); |
| 186 ASSERT(documentElement->layoutObject()->isBox()); | 197 ASSERT(documentElement->layoutObject()->isBox()); |
| 187 rootBox = toLayoutBox(documentElement->layoutObject()); | 198 rootBox = toLayoutBox(documentElement->layoutObject()); |
| 188 } | 199 } |
| 189 const LayoutBoxModelObject& positioningBox = isLayoutView ? static_cast<cons
t LayoutBoxModelObject&>(*rootBox) : obj; | 200 const LayoutBoxModelObject& positioningBox = isLayoutView ? static_cast<cons
t LayoutBoxModelObject&>(*rootBox) : obj; |
| 190 | 201 |
| 191 // Determine the background positioning area and set destRect to the backgro
und painting area. | 202 // Determine the background positioning area and set destRect to the backgro
und painting area. |
| 192 // destRect will be adjusted later if the background is non-repeating. | 203 // destRect will be adjusted later if the background is non-repeating. |
| 193 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins
ide transforms. | 204 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins
ide transforms. |
| 194 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment; | 205 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment; |
| 195 | 206 |
| 196 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) { | 207 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) { |
| 197 // As a side effect of an optimization to blit on scroll, we do not hono
r the CSS | 208 // As a side effect of an optimization to blit on scroll, we do not hono
r the CSS |
| 198 // property "background-attachment: fixed" because it may result in rend
ering | 209 // property "background-attachment: fixed" because it may result in rend
ering |
| 199 // artifacts. Note, these artifacts only appear if we are blitting on sc
roll of | 210 // artifacts. Note, these artifacts only appear if we are blitting on sc
roll of |
| 200 // a page that has fixed background images. | 211 // a page that has fixed background images. |
| 201 fixedAttachment = false; | 212 fixedAttachment = false; |
| 202 } | 213 } |
| 203 | 214 |
| 204 if (!fixedAttachment) { | 215 if (!fixedAttachment) { |
| 205 setDestRect(snappedPaintRect); | 216 setDestRect(paintRect); |
| 206 | 217 |
| 207 LayoutUnit right = 0; | 218 LayoutUnit right; |
| 208 LayoutUnit bottom = 0; | 219 LayoutUnit bottom; |
| 209 // Scroll and Local. | 220 // Scroll and Local. |
| 210 if (fillLayer.origin() != BorderFillBox) { | 221 if (fillLayer.origin() != BorderFillBox) { |
| 211 left = positioningBox.borderLeft(); | 222 left = positioningBox.borderLeft(); |
| 212 right = positioningBox.borderRight(); | 223 right = positioningBox.borderRight(); |
| 213 top = positioningBox.borderTop(); | 224 top = positioningBox.borderTop(); |
| 214 bottom = positioningBox.borderBottom(); | 225 bottom = positioningBox.borderBottom(); |
| 215 if (fillLayer.origin() == ContentFillBox) { | 226 if (fillLayer.origin() == ContentFillBox) { |
| 216 left += positioningBox.paddingLeft(); | 227 left += positioningBox.paddingLeft(); |
| 217 right += positioningBox.paddingRight(); | 228 right += positioningBox.paddingRight(); |
| 218 top += positioningBox.paddingTop(); | 229 top += positioningBox.paddingTop(); |
| 219 bottom += positioningBox.paddingBottom(); | 230 bottom += positioningBox.paddingBottom(); |
| 220 } | 231 } |
| 221 } | 232 } |
| 222 | 233 |
| 223 if (isLayoutView) { | 234 if (isLayoutView) { |
| 224 // The background of the box generated by the root element covers th
e entire canvas and will | 235 // The background of the box generated by the root element covers th
e entire canvas and will |
| 225 // be painted by the view object, but the we should still use the ro
ot element box for | 236 // be painted by the view object, but the we should still use the ro
ot element box for |
| 226 // positioning. | 237 // positioning. |
| 227 positioningAreaSize = pixelSnappedIntSize(rootBox->size() - LayoutSi
ze(left + right, top + bottom), rootBox->location()); | 238 positioningAreaSize = rootBox->size() - LayoutSize(left + right, top
+ bottom), rootBox->location(); |
| 228 // The input paint rect is specified in root element local coordinat
e (i.e. a transform | 239 // The input paint rect is specified in root element local coordinat
e (i.e. a transform |
| 229 // is applied on the context for painting), and is expanded to cover
the whole canvas. | 240 // is applied on the context for painting), and is expanded to cover
the whole canvas. |
| 230 // Since left/top is relative to the paint rect, we need to offset t
hem back. | 241 // Since left/top is relative to the paint rect, we need to offset t
hem back. |
| 231 left -= paintRect.x(); | 242 left -= paintRect.x(); |
| 232 top -= paintRect.y(); | 243 top -= paintRect.y(); |
| 233 } else { | 244 } else { |
| 234 positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutS
ize(left + right, top + bottom), paintRect.location()); | 245 positioningAreaSize = paintRect.size() - LayoutSize(left + right, to
p + bottom); |
| 235 } | 246 } |
| 236 } else { | 247 } else { |
| 237 setHasNonLocalGeometry(); | 248 setHasNonLocalGeometry(); |
| 238 | 249 |
| 239 IntRect viewportRect = pixelSnappedIntRect(obj.viewRect()); | 250 LayoutRect viewportRect = obj.viewRect(); |
| 240 if (fixedBackgroundPaintsInLocalCoordinates(obj, globalPaintFlags)) { | 251 if (fixedBackgroundPaintsInLocalCoordinates(obj, globalPaintFlags)) { |
| 241 viewportRect.setLocation(IntPoint()); | 252 viewportRect.setLocation(LayoutPoint()); |
| 242 } else { | 253 } else { |
| 243 if (FrameView* frameView = obj.view()->frameView()) | 254 if (FrameView* frameView = obj.view()->frameView()) |
| 244 viewportRect.setLocation(frameView->scrollPosition()); | 255 viewportRect.setLocation(frameView->scrollPosition()); |
| 245 // Compensate the translations created by ScrollRecorders. | 256 // Compensate the translations created by ScrollRecorders. |
| 246 // TODO(trchen): Fix this for SP phase 2. crbug.com/529963. | 257 // TODO(trchen): Fix this for SP phase 2. crbug.com/529963. |
| 247 viewportRect.moveBy(accumulatedScrollOffset(obj, paintContainer)); | 258 viewportRect.moveBy(accumulatedScrollOffset(obj, paintContainer)); |
| 248 } | 259 } |
| 249 | 260 |
| 250 if (paintContainer) { | 261 if (paintContainer) |
| 251 IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->l
ocalToAbsolute(FloatPoint())); | 262 viewportRect.moveBy(LayoutPoint(-paintContainer->localToAbsolute(Flo
atPoint()))); |
| 252 viewportRect.moveBy(-absoluteContainerOffset); | |
| 253 } | |
| 254 | 263 |
| 255 setDestRect(viewportRect); | 264 setDestRect(viewportRect); |
| 256 positioningAreaSize = destRect().size(); | 265 positioningAreaSize = destRect().size(); |
| 257 } | 266 } |
| 258 | 267 |
| 259 IntSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, posi
tioningAreaSize); | 268 LayoutSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, p
ositioningAreaSize); |
| 260 setTileSize(fillTileSize); | 269 setTileSize(fillTileSize); |
| 261 setImageContainerSize(fillTileSize); | 270 setImageContainerSize(fillTileSize); |
| 262 | 271 |
| 263 EFillRepeat backgroundRepeatX = fillLayer.repeatX(); | 272 EFillRepeat backgroundRepeatX = fillLayer.repeatX(); |
| 264 EFillRepeat backgroundRepeatY = fillLayer.repeatY(); | 273 EFillRepeat backgroundRepeatY = fillLayer.repeatY(); |
| 265 int availableWidth = positioningAreaSize.width() - tileSize().width(); | 274 LayoutUnit availableWidth = positioningAreaSize.width() - tileSize().width()
; |
| 266 int availableHeight = positioningAreaSize.height() - tileSize().height(); | 275 LayoutUnit availableHeight = positioningAreaSize.height() - tileSize().heigh
t(); |
| 267 | 276 |
| 268 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit
ion(), availableWidth); | 277 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit
ion(), availableWidth); |
| 269 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fil
lTileSize.width() > 0) { | 278 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > LayoutUn
it() && fillTileSize.width() > LayoutUnit()) { |
| 270 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.width() /
fillTileSize.width())); | 279 int nrTiles = std::max(1, roundToInt(positioningAreaSize.width() / fillT
ileSize.width())); |
| 271 | 280 |
| 272 // Round tile size per css3-background spec. | 281 fillTileSize.setWidth(positioningAreaSize.width() / nrTiles); |
| 273 fillTileSize.setWidth(lroundf(positioningAreaSize.width() / (float)nrTil
es)); | |
| 274 | 282 |
| 275 // Maintain aspect ratio if background-size: auto is set | 283 // Maintain aspect ratio if background-size: auto is set |
| 276 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun
dFill) { | 284 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun
dFill) { |
| 277 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w
idth() / (nrTiles * fillTileSize.width())); | 285 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w
idth() / (nrTiles * fillTileSize.width())); |
| 278 } | 286 } |
| 279 | 287 |
| 280 setTileSize(fillTileSize); | 288 setTileSize(fillTileSize); |
| 281 setPhaseX(tileSize().width() ? tileSize().width() - roundToInt(computedX
Position + left) % tileSize().width() : 0); | 289 setImageContainerSize(fillTileSize); |
| 282 setSpaceSize(IntSize()); | 290 setPhaseX(tileSize().width() ? tileSize().width() - fmodf((computedXPosi
tion + left), tileSize().width()) : 0.0f); |
| 291 setSpaceSize(LayoutSize()); |
| 283 } | 292 } |
| 284 | 293 |
| 285 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit
ion(), availableHeight); | 294 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit
ion(), availableHeight); |
| 286 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fi
llTileSize.height() > 0) { | 295 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > LayoutU
nit() && fillTileSize.height() > LayoutUnit()) { |
| 287 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.height()
/ fillTileSize.height())); | 296 int nrTiles = std::max(1, roundToInt(positioningAreaSize.height() / fill
TileSize.height())); |
| 288 | 297 |
| 289 // Round tile size per css3-background spec. | 298 fillTileSize.setHeight(positioningAreaSize.height() / nrTiles); |
| 290 fillTileSize.setHeight(lroundf(positioningAreaSize.height() / (float)nrT
iles)); | |
| 291 | 299 |
| 292 // Maintain aspect ratio if background-size: auto is set | 300 // Maintain aspect ratio if background-size: auto is set |
| 293 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round
Fill) { | 301 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round
Fill) { |
| 294 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei
ght() / (nrTiles * fillTileSize.height())); | 302 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei
ght() / (nrTiles * fillTileSize.height())); |
| 295 } | 303 } |
| 296 | 304 |
| 297 setTileSize(fillTileSize); | 305 setTileSize(fillTileSize); |
| 298 setPhaseY(tileSize().height() ? tileSize().height() - roundToInt(compute
dYPosition + top) % tileSize().height() : 0); | 306 setImageContainerSize(fillTileSize); |
| 299 setSpaceSize(IntSize()); | 307 setPhaseY(tileSize().height() ? tileSize().height() - fmodf((computedYPo
sition + top), tileSize().height()) : 0.0f); |
| 308 setSpaceSize(LayoutSize()); |
| 300 } | 309 } |
| 301 | 310 |
| 302 if (backgroundRepeatX == RepeatFill) { | 311 if (backgroundRepeatX == RepeatFill) { |
| 303 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; | 312 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; |
| 304 setPhaseX(tileSize().width() ? tileSize().width() - roundToInt(xOffset +
left) % tileSize().width() : 0); | 313 setPhaseX(tileSize().width() ? tileSize().width() - fmodf((xOffset + lef
t), tileSize().width()) : 0.0f); |
| 305 setSpaceSize(IntSize()); | 314 setSpaceSize(LayoutSize()); |
| 306 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) { | 315 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > LayoutUn
it()) { |
| 307 int space = getSpaceBetweenImageTiles(positioningAreaSize.width(), tileS
ize().width()); | 316 LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.width()
, tileSize().width()); |
| 308 int actualWidth = tileSize().width() + space; | 317 LayoutUnit actualWidth = tileSize().width() + space; |
| 309 | 318 |
| 310 if (space >= 0) { | 319 if (space >= LayoutUnit()) { |
| 311 computedXPosition = roundedMinimumValueForLength(Length(), available
Width); | 320 computedXPosition = roundedMinimumValueForLength(Length(), available
Width); |
| 312 setSpaceSize(IntSize(space, 0)); | 321 setSpaceSize(LayoutSize(space, LayoutUnit())); |
| 313 setPhaseX(actualWidth ? actualWidth - roundToInt(computedXPosition +
left) % actualWidth : 0); | 322 setPhaseX(actualWidth ? actualWidth - fmodf((computedXPosition + lef
t), actualWidth) : 0.0f); |
| 314 } else { | 323 } else { |
| 315 backgroundRepeatX = NoRepeatFill; | 324 backgroundRepeatX = NoRepeatFill; |
| 316 } | 325 } |
| 317 } | 326 } |
| 318 if (backgroundRepeatX == NoRepeatFill) { | 327 if (backgroundRepeatX == NoRepeatFill) { |
| 319 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; | 328 LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availa
bleWidth - computedXPosition : computedXPosition; |
| 320 setNoRepeatX(left + xOffset); | 329 setNoRepeatX(left + xOffset); |
| 321 setSpaceSize(IntSize(0, spaceSize().height())); | 330 setSpaceSize(LayoutSize(LayoutUnit(), spaceSize().height())); |
| 322 } | 331 } |
| 323 | 332 |
| 324 if (backgroundRepeatY == RepeatFill) { | 333 if (backgroundRepeatY == RepeatFill) { |
| 325 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; | 334 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; |
| 326 setPhaseY(tileSize().height() ? tileSize().height() - roundToInt(yOffset
+ top) % tileSize().height() : 0); | 335 setPhaseY(tileSize().height() ? tileSize().height() - fmodf((yOffset + t
op), tileSize().height()) : 0.0f); |
| 327 setSpaceSize(IntSize(spaceSize().width(), 0)); | 336 setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit())); |
| 328 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) { | 337 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > LayoutU
nit()) { |
| 329 int space = getSpaceBetweenImageTiles(positioningAreaSize.height(), tile
Size().height()); | 338 LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.height(
), tileSize().height()); |
| 330 int actualHeight = tileSize().height() + space; | 339 LayoutUnit actualHeight = tileSize().height() + space; |
| 331 | 340 |
| 332 if (space >= 0) { | 341 if (space >= LayoutUnit()) { |
| 333 computedYPosition = roundedMinimumValueForLength(Length(), available
Height); | 342 computedYPosition = roundedMinimumValueForLength(Length(), available
Height); |
| 334 setSpaceSize(IntSize(spaceSize().width(), space)); | 343 setSpaceSize(LayoutSize(spaceSize().width(), space)); |
| 335 setPhaseY(actualHeight ? actualHeight - roundToInt(computedYPosition
+ top) % actualHeight : 0); | 344 setPhaseY(actualHeight ? actualHeight - fmodf((computedYPosition + t
op), actualHeight) : 0.0f); |
| 336 } else { | 345 } else { |
| 337 backgroundRepeatY = NoRepeatFill; | 346 backgroundRepeatY = NoRepeatFill; |
| 338 } | 347 } |
| 339 } | 348 } |
| 340 if (backgroundRepeatY == NoRepeatFill) { | 349 if (backgroundRepeatY == NoRepeatFill) { |
| 341 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; | 350 LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? avail
ableHeight - computedYPosition : computedYPosition; |
| 342 setNoRepeatY(top + yOffset); | 351 setNoRepeatY(top + yOffset); |
| 343 setSpaceSize(IntSize(spaceSize().width(), 0)); | 352 setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit())); |
| 344 } | 353 } |
| 345 | 354 |
| 346 if (fixedAttachment) | 355 if (fixedAttachment) |
| 347 useFixedAttachment(snappedPaintRect.location()); | 356 useFixedAttachment(paintRect.location()); |
| 348 | 357 |
| 349 clip(snappedPaintRect); | 358 clip(paintRect); |
| 359 pixelSnapGeometry(); |
| 350 } | 360 } |
| 351 | 361 |
| 352 } // namespace blink | 362 } // namespace blink |
| OLD | NEW |