Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: Source/core/paint/BackgroundImageGeometry.cpp

Issue 1300103003: Refactor code for calculating background image geometry (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/paint/BackgroundImageGeometry.h ('k') | Source/core/paint/BoxPainter.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/layout/LayoutBox.h"
9 #include "core/layout/LayoutBoxModelObject.h"
10 #include "core/layout/LayoutView.h"
11 #include "core/layout/compositing/CompositedDeprecatedPaintLayerMapping.h"
12 #include "core/paint/DeprecatedPaintLayer.h"
13 #include "platform/LayoutUnit.h"
14 #include "platform/geometry/LayoutRect.h"
15
8 namespace blink { 16 namespace blink {
9 17
18 namespace {
19
20 inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSiz e& positioningAreaSize)
21 {
22 tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tile Size.width().ceil() : tileSize.width().floor());
23 tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? t ileSize.height().ceil() : tileSize.height().floor());
24 }
25
26 // Return the amount of space to leave between image tiles for the background-re peat: space property.
27 inline int getSpaceBetweenImageTiles(int areaSize, int tileSize)
28 {
29 int numberOfTiles = areaSize / tileSize;
30 int space = -1;
31
32 if (numberOfTiles > 1) {
33 // Spec doesn't specify rounding, so use the same method as for backgrou nd-repeat: round.
34 space = lroundf((areaSize - numberOfTiles * tileSize) / (float)(numberOf Tiles - 1));
35 }
36
37 return space;
38 }
39
40 bool fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj, const Glob alPaintFlags globalPaintFlags)
41 {
42 if (!obj.isLayoutView())
43 return false;
44
45 const LayoutView& view = toLayoutView(obj);
46
47 if (globalPaintFlags & GlobalPaintFlattenCompositingLayers)
48 return false;
49
50 DeprecatedPaintLayer* rootLayer = view.layer();
51 if (!rootLayer || rootLayer->compositingState() == NotComposited)
52 return false;
53
54 return rootLayer->compositedDeprecatedPaintLayerMapping()->backgroundLayerPa intsFixedRootBackground();
55 }
56
57 IntSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer& fillLayer, const IntSize& positioningAreaSize)
58 {
59 StyleImage* image = fillLayer.image();
60 EFillSizeType type = fillLayer.size().type;
61
62 IntSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, po sitioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom);
63 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal eFactor());
64 switch (type) {
65 case SizeLength: {
66 LayoutSize tileSize(positioningAreaSize);
67
68 Length layerWidth = fillLayer.size().size.width();
69 Length layerHeight = fillLayer.size().size.height();
70
71 if (layerWidth.isFixed())
72 tileSize.setWidth(layerWidth.value());
73 else if (layerWidth.hasPercent())
74 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.wid th()));
75
76 if (layerHeight.isFixed())
77 tileSize.setHeight(layerHeight.value());
78 else if (layerHeight.hasPercent())
79 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.h eight()));
80
81 applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize);
82
83 // If one of the values is auto we have to use the appropriate
84 // scale to maintain our aspect ratio.
85 if (layerWidth.isAuto() && !layerHeight.isAuto()) {
86 if (imageIntrinsicSize.height()) {
87 LayoutUnit adjustedWidth = imageIntrinsicSize.width() * tileSize .height() / imageIntrinsicSize.height();
88 if (imageIntrinsicSize.width() >= 1 && adjustedWidth < 1)
89 adjustedWidth = 1;
90 tileSize.setWidth(adjustedWidth);
91 }
92 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) {
93 if (imageIntrinsicSize.width()) {
94 LayoutUnit adjustedHeight = imageIntrinsicSize.height() * tileSi ze.width() / imageIntrinsicSize.width();
95 if (imageIntrinsicSize.height() >= 1 && adjustedHeight < 1)
96 adjustedHeight = 1;
97 tileSize.setHeight(adjustedHeight);
98 }
99 } else if (layerWidth.isAuto() && layerHeight.isAuto()) {
100 // If both width and height are auto, use the image's intrinsic size .
101 tileSize = LayoutSize(imageIntrinsicSize);
102 }
103
104 tileSize.clampNegativeToZero();
105 return flooredIntSize(tileSize);
106 }
107 case SizeNone: {
108 // If both values are 'auto' then the intrinsic width and/or height of t he image should be used, if any.
109 if (!imageIntrinsicSize.isEmpty())
110 return imageIntrinsicSize;
111
112 // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'.
113 type = Contain;
114 }
115 case Contain:
116 case Cover: {
117 float horizontalScaleFactor = imageIntrinsicSize.width()
118 ? static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSi ze.width() : 1;
119 float verticalScaleFactor = imageIntrinsicSize.height()
120 ? static_cast<float>(positioningAreaSize.height()) / imageIntrinsicS ize.height() : 1;
121 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, ve rticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor);
122 return IntSize(std::max(1l, lround(imageIntrinsicSize.width() * scaleFac tor)), std::max(1l, lround(imageIntrinsicSize.height() * scaleFactor)));
123 }
124 }
125
126 ASSERT_NOT_REACHED();
127 return IntSize();
128 }
129
130 } // anonymous namespace
131
10 void BackgroundImageGeometry::setNoRepeatX(int xOffset) 132 void BackgroundImageGeometry::setNoRepeatX(int xOffset)
11 { 133 {
12 m_destRect.move(std::max(xOffset, 0), 0); 134 m_destRect.move(std::max(xOffset, 0), 0);
13 m_phase.setX(-std::min(xOffset, 0)); 135 m_phase.setX(-std::min(xOffset, 0));
14 m_destRect.setWidth(m_tileSize.width() + std::min(xOffset, 0)); 136 m_destRect.setWidth(m_tileSize.width() + std::min(xOffset, 0));
15 } 137 }
138
16 void BackgroundImageGeometry::setNoRepeatY(int yOffset) 139 void BackgroundImageGeometry::setNoRepeatY(int yOffset)
17 { 140 {
18 m_destRect.move(0, std::max(yOffset, 0)); 141 m_destRect.move(0, std::max(yOffset, 0));
19 m_phase.setY(-std::min(yOffset, 0)); 142 m_phase.setY(-std::min(yOffset, 0));
20 m_destRect.setHeight(m_tileSize.height() + std::min(yOffset, 0)); 143 m_destRect.setHeight(m_tileSize.height() + std::min(yOffset, 0));
21 } 144 }
22 145
23 void BackgroundImageGeometry::useFixedAttachment(const IntPoint& attachmentPoint ) 146 void BackgroundImageGeometry::useFixedAttachment(const IntPoint& attachmentPoint )
24 { 147 {
25 IntPoint alignedPoint = attachmentPoint; 148 IntPoint alignedPoint = attachmentPoint;
26 m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), 0), std::max(aligne dPoint.y() - m_destRect.y(), 0)); 149 m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), 0), std::max(aligne dPoint.y() - m_destRect.y(), 0));
27 } 150 }
28 151
29 void BackgroundImageGeometry::clip(const IntRect& clipRect) 152 void BackgroundImageGeometry::clip(const IntRect& clipRect)
30 { 153 {
31 m_destRect.intersect(clipRect); 154 m_destRect.intersect(clipRect);
32 } 155 }
33 156
157 void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L ayoutBoxModelObject* paintContainer,
158 const GlobalPaintFlags globalPaintFlags, const FillLayer& fillLayer, const L ayoutRect& paintRect,
159 LayoutObject* backgroundObject)
160 {
161 LayoutUnit left = 0;
162 LayoutUnit top = 0;
163 IntSize positioningAreaSize;
164 IntRect snappedPaintRect = pixelSnappedIntRect(paintRect);
165 bool isLayoutView = obj.isLayoutView();
166 const LayoutBox* rootBox = nullptr;
167 if (isLayoutView) {
168 // It is only possible reach here when root element has a box.
169 Element* documentElement = obj.document().documentElement();
170 ASSERT(documentElement);
171 ASSERT(documentElement->layoutObject());
172 ASSERT(documentElement->layoutObject()->isBox());
173 rootBox = toLayoutBox(documentElement->layoutObject());
174 }
175 const LayoutBoxModelObject& positioningBox = isLayoutView ? static_cast<cons t LayoutBoxModelObject&>(*rootBox) : obj;
176
177 // Determine the background positioning area and set destRect to the backgro und painting area.
178 // destRect will be adjusted later if the background is non-repeating.
179 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins ide transforms.
180 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment;
181
182 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) {
183 // As a side effect of an optimization to blit on scroll, we do not hono r the CSS
184 // property "background-attachment: fixed" because it may result in rend ering
185 // artifacts. Note, these artifacts only appear if we are blitting on sc roll of
186 // a page that has fixed background images.
187 fixedAttachment = false;
188 }
189
190 if (!fixedAttachment) {
191 setDestRect(snappedPaintRect);
192
193 LayoutUnit right = 0;
194 LayoutUnit bottom = 0;
195 // Scroll and Local.
196 if (fillLayer.origin() != BorderFillBox) {
197 left = positioningBox.borderLeft();
198 right = positioningBox.borderRight();
199 top = positioningBox.borderTop();
200 bottom = positioningBox.borderBottom();
201 if (fillLayer.origin() == ContentFillBox) {
202 left += positioningBox.paddingLeft();
203 right += positioningBox.paddingRight();
204 top += positioningBox.paddingTop();
205 bottom += positioningBox.paddingBottom();
206 }
207 }
208
209 if (isLayoutView) {
210 // The background of the box generated by the root element covers th e entire canvas and will
211 // be painted by the view object, but the we should still use the ro ot element box for
212 // positioning.
213 positioningAreaSize = pixelSnappedIntSize(rootBox->size() - LayoutSi ze(left + right, top + bottom), rootBox->location());
214 // The input paint rect is specified in root element local coordinat e (i.e. a transform
215 // is applied on the context for painting), and is expanded to cover the whole canvas.
216 // Since left/top is relative to the paint rect, we need to offset t hem back.
217 left -= paintRect.x();
218 top -= paintRect.y();
219 } else {
220 positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutS ize(left + right, top + bottom), paintRect.location());
221 }
222 } else {
223 setHasNonLocalGeometry();
224
225 IntRect viewportRect = pixelSnappedIntRect(obj.viewRect());
226 if (fixedBackgroundPaintsInLocalCoordinates(obj, globalPaintFlags))
227 viewportRect.setLocation(IntPoint());
228 else if (FrameView* frameView = obj.view()->frameView())
229 viewportRect.setLocation(frameView->scrollPosition());
230
231 if (paintContainer) {
232 IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->l ocalToAbsolute(FloatPoint()));
233 viewportRect.moveBy(-absoluteContainerOffset);
234 }
235
236 setDestRect(viewportRect);
237 positioningAreaSize = destRect().size();
238 }
239
240 const LayoutObject* clientForBackgroundImage = backgroundObject ? background Object : &obj;
241 IntSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, posi tioningAreaSize);
242 fillLayer.image()->setContainerSizeForLayoutObject(clientForBackgroundImage, fillTileSize, obj.style()->effectiveZoom());
243 setTileSize(fillTileSize);
244
245 EFillRepeat backgroundRepeatX = fillLayer.repeatX();
246 EFillRepeat backgroundRepeatY = fillLayer.repeatY();
247 int availableWidth = positioningAreaSize.width() - tileSize().width();
248 int availableHeight = positioningAreaSize.height() - tileSize().height();
249
250 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit ion(), availableWidth);
251 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fil lTileSize.width() > 0) {
252 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.width() / fillTileSize.width()));
253
254 // Round tile size per css3-background spec.
255 fillTileSize.setWidth(lroundf(positioningAreaSize.width() / (float)nrTil es));
256
257 // Maintain aspect ratio if background-size: auto is set
258 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun dFill) {
259 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w idth() / (nrTiles * fillTileSize.width()));
260 }
261
262 setTileSize(fillTileSize);
263 setPhaseX(tileSize().width() ? tileSize().width() - roundToInt(computedX Position + left) % tileSize().width() : 0);
264 setSpaceSize(IntSize());
265 }
266
267 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit ion(), availableHeight);
268 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fi llTileSize.height() > 0) {
269 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.height() / fillTileSize.height()));
270
271 // Round tile size per css3-background spec.
272 fillTileSize.setHeight(lroundf(positioningAreaSize.height() / (float)nrT iles));
273
274 // Maintain aspect ratio if background-size: auto is set
275 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round Fill) {
276 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei ght() / (nrTiles * fillTileSize.height()));
277 }
278
279 setTileSize(fillTileSize);
280 setPhaseY(tileSize().height() ? tileSize().height() - roundToInt(compute dYPosition + top) % tileSize().height() : 0);
281 setSpaceSize(IntSize());
282 }
283
284 if (backgroundRepeatX == RepeatFill) {
285 int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidt h - computedXPosition : computedXPosition;
286 setPhaseX(tileSize().width() ? tileSize().width() - roundToInt(xOffset + left) % tileSize().width() : 0);
287 setSpaceSize(IntSize());
288 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) {
289 int space = getSpaceBetweenImageTiles(positioningAreaSize.width(), tileS ize().width());
290 int actualWidth = tileSize().width() + space;
291
292 if (space >= 0) {
293 computedXPosition = roundedMinimumValueForLength(Length(), available Width);
294 setSpaceSize(IntSize(space, 0));
295 setPhaseX(actualWidth ? actualWidth - roundToInt(computedXPosition + left) % actualWidth : 0);
296 } else {
297 backgroundRepeatX = NoRepeatFill;
298 }
299 }
300 if (backgroundRepeatX == NoRepeatFill) {
301 int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidt h - computedXPosition : computedXPosition;
302 setNoRepeatX(left + xOffset);
303 setSpaceSize(IntSize(0, spaceSize().height()));
304 }
305
306 if (backgroundRepeatY == RepeatFill) {
307 int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHei ght - computedYPosition : computedYPosition;
308 setPhaseY(tileSize().height() ? tileSize().height() - roundToInt(yOffset + top) % tileSize().height() : 0);
309 setSpaceSize(IntSize(spaceSize().width(), 0));
310 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) {
311 int space = getSpaceBetweenImageTiles(positioningAreaSize.height(), tile Size().height());
312 int actualHeight = tileSize().height() + space;
313
314 if (space >= 0) {
315 computedYPosition = roundedMinimumValueForLength(Length(), available Height);
316 setSpaceSize(IntSize(spaceSize().width(), space));
317 setPhaseY(actualHeight ? actualHeight - roundToInt(computedYPosition + top) % actualHeight : 0);
318 } else {
319 backgroundRepeatY = NoRepeatFill;
320 }
321 }
322 if (backgroundRepeatY == NoRepeatFill) {
323 int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHei ght - computedYPosition : computedYPosition;
324 setNoRepeatY(top + yOffset);
325 setSpaceSize(IntSize(spaceSize().width(), 0));
326 }
327
328 if (fixedAttachment)
329 useFixedAttachment(snappedPaintRect.location());
330
331 clip(snappedPaintRect);
332 }
333
34 } // namespace blink 334 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/paint/BackgroundImageGeometry.h ('k') | Source/core/paint/BoxPainter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698