OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "config.h" | |
6 #include "core/paint/NinePieceImageGrid.h" | |
7 | |
8 #include "core/style/ComputedStyle.h" | |
9 #include "core/style/NinePieceImage.h" | |
10 #include "platform/LengthFunctions.h" | |
11 #include "platform/geometry/FloatSize.h" | |
12 #include "platform/geometry/IntSize.h" | |
13 | |
14 namespace blink { | |
15 | |
16 static LayoutUnit computeEdgeWidth(const BorderImageLength& borderSlice, int bor derSide, const LayoutUnit& imageSide, | |
17 const LayoutUnit& boxExtent) | |
18 { | |
19 if (borderSlice.isNumber()) | |
20 return borderSlice.number() * borderSide; | |
21 if (borderSlice.length().isAuto()) | |
22 return imageSide; | |
23 return valueForLength(borderSlice.length(), boxExtent); | |
24 } | |
25 | |
26 static int computeEdgeSlice(const Length& slice, LayoutUnit maximum) | |
27 { | |
28 return std::min<int>(maximum, valueForLength(slice, maximum)); | |
29 } | |
30 | |
31 NinePieceImageGrid::NinePieceImageGrid(const NinePieceImage& ninePieceImage, Int Size imageSize, IntRect borderImageArea, | |
32 const IntRectOutsets& borderWidths) | |
33 : m_borderImageArea(borderImageArea) | |
34 , m_imageSize(imageSize) | |
35 , m_horizontalTileRule((Image::TileRule)ninePieceImage.horizontalRule()) | |
36 , m_verticalTileRule((Image::TileRule)ninePieceImage.verticalRule()) | |
37 , m_fill(ninePieceImage.fill()) | |
38 { | |
39 StyleImage* styleImage = ninePieceImage.image(); | |
40 ASSERT(styleImage); | |
41 | |
42 float imageScaleFactor = styleImage->imageScaleFactor(); | |
43 m_top.slice = computeEdgeSlice(ninePieceImage.imageSlices().top(), imageSize .height()) * imageScaleFactor; | |
44 m_right.slice = computeEdgeSlice(ninePieceImage.imageSlices().right(), image Size.width()) * imageScaleFactor; | |
45 m_bottom.slice = computeEdgeSlice(ninePieceImage.imageSlices().bottom(), ima geSize.height()) * imageScaleFactor; | |
46 m_left.slice = computeEdgeSlice(ninePieceImage.imageSlices().left(), imageSi ze.width()) * imageScaleFactor; | |
47 | |
48 m_top.width = computeEdgeWidth(ninePieceImage.borderSlices().top(), borderWi dths.top(), m_top.slice, | |
49 borderImageArea.height()); | |
50 m_right.width = computeEdgeWidth(ninePieceImage.borderSlices().right(), bord erWidths.right(), m_right.slice, | |
51 borderImageArea.width()); | |
52 m_bottom.width = computeEdgeWidth(ninePieceImage.borderSlices().bottom(), bo rderWidths.bottom(), m_bottom.slice, | |
53 borderImageArea.height()); | |
54 m_left.width = computeEdgeWidth(ninePieceImage.borderSlices().left(), border Widths.left(), m_left.slice, | |
55 borderImageArea.width()); | |
56 | |
57 // The spec says: Given Lwidth as the width of the border image area, Lheigh t as its height, and Wside as the border | |
58 // image width offset for the side, let f = min(Lwidth/(Wleft+Wright), Lheig ht/(Wtop+Wbottom)). If f < 1, then all W | |
59 // are reduced by multiplying them by f. | |
60 int borderSideWidth = std::max(1, m_left.width + m_right.width); | |
61 int borderSideHeight = std::max(1, m_top.width + m_bottom.width); | |
62 float borderSideScaleFactor = std::min((float)borderImageArea.width() / bord erSideWidth, | |
63 (float)borderImageArea.height() / borderSideHeight); | |
64 if (borderSideScaleFactor < 1) { | |
65 m_top.width *= borderSideScaleFactor; | |
66 m_right.width *= borderSideScaleFactor; | |
67 m_bottom.width *= borderSideScaleFactor; | |
68 m_left.width *= borderSideScaleFactor; | |
69 } | |
70 } | |
71 | |
72 static FloatRect subrect(IntRect rect, float offsetX, float offsetY, float width , float height) | |
fs
2015/06/24 13:19:10
Maybe a short comment on the behavior of this func
davve
2015/06/24 13:35:25
Done.
| |
73 { | |
74 float baseX = rect.x(); | |
75 if (offsetX < 0) | |
76 baseX = rect.maxX(); | |
77 | |
78 float baseY = rect.y(); | |
79 if (offsetY < 0) | |
80 baseY = rect.maxY(); | |
81 | |
82 return FloatRect(baseX + offsetX, baseY + offsetY, width, height); | |
83 } | |
84 | |
85 static FloatRect subrect(IntSize size, float offsetX, float offsetY, float width , float height) | |
86 { | |
87 return subrect(IntRect(IntPoint(), size), offsetX, offsetY, width, height); | |
88 } | |
89 | |
90 static inline void setCornerPiece(NinePieceImageGrid::NinePieceDrawInfo& drawInf o, bool isDrawable, | |
91 const FloatRect& source, const FloatRect& destination) | |
92 { | |
93 drawInfo.isDrawable = isDrawable; | |
94 if (drawInfo.isDrawable) { | |
95 drawInfo.source = source; | |
96 drawInfo.destination = destination; | |
97 } | |
98 } | |
99 | |
100 void NinePieceImageGrid::setDrawInfoCorner(NinePieceDrawInfo& drawInfo, NinePiec e piece) const | |
101 { | |
102 switch (piece) { | |
103 case TopLeftPiece: | |
104 setCornerPiece(drawInfo, m_top.draw() && m_left.draw(), | |
105 subrect(m_imageSize, 0, 0, m_left.slice, m_top.slice), | |
106 subrect(m_borderImageArea, 0, 0, m_left.width, m_top.width)); | |
107 break; | |
108 case BottomLeftPiece: | |
109 setCornerPiece(drawInfo, m_bottom.draw() && m_left.draw(), | |
110 subrect(m_imageSize, 0, -m_bottom.slice, m_left.slice, m_bottom.slic e), | |
111 subrect(m_borderImageArea, 0, -m_bottom.width, m_left.width, m_botto m.width)); | |
112 break; | |
113 case TopRightPiece: | |
114 setCornerPiece(drawInfo, m_top.draw() && m_right.draw(), | |
115 subrect(m_imageSize, -m_right.slice, 0, m_right.slice, m_top.slice), | |
116 subrect(m_borderImageArea, -m_right.width, 0, m_right.width, m_top.w idth)); | |
117 break; | |
118 case BottomRightPiece: | |
119 setCornerPiece(drawInfo, m_bottom.draw() && m_right.draw(), | |
120 subrect(m_imageSize, -m_right.slice, -m_bottom.slice, m_right.slice, m_bottom.slice), | |
121 subrect(m_borderImageArea, -m_right.width, -m_bottom.width, m_right. width, m_bottom.width)); | |
122 break; | |
123 default: | |
124 ASSERT_NOT_REACHED(); | |
125 break; | |
126 } | |
127 } | |
128 | |
129 static inline void setHorizontalEdge(NinePieceImageGrid::NinePieceDrawInfo& draw Info, | |
130 const NinePieceImageGrid::Edge& edge, const FloatRect& source, const FloatRe ct& destination, | |
131 Image::TileRule tileRule) | |
132 { | |
133 drawInfo.isDrawable = edge.draw() && source.width() > 0; | |
134 if (drawInfo.isDrawable) { | |
135 drawInfo.source = source; | |
136 drawInfo.destination = destination; | |
137 drawInfo.tileScale = FloatSize(edge.scale(), edge.scale()); | |
138 drawInfo.tileRule = { tileRule, Image::StretchTile }; | |
139 } | |
140 } | |
141 | |
142 static inline void setVerticalEdge(NinePieceImageGrid::NinePieceDrawInfo& drawIn fo, | |
143 const NinePieceImageGrid::Edge& edge, const FloatRect& source, const FloatRe ct& destination, | |
144 Image::TileRule tileRule) | |
145 { | |
146 drawInfo.isDrawable = edge.draw() && source.height() > 0; | |
147 if (drawInfo.isDrawable) { | |
148 drawInfo.source = source; | |
149 drawInfo.destination = destination; | |
150 drawInfo.tileScale = FloatSize(edge.scale(), edge.scale()); | |
151 drawInfo.tileRule = { Image::StretchTile, tileRule }; | |
152 } | |
153 } | |
154 | |
155 static IntSize subsize(const IntSize& size, int horizontalInset, int verticalIns et) | |
fs
2015/06/24 13:19:10
I think there's an operator overload for this (if
davve
2015/06/24 13:35:25
Nice, I like the operator overload.
| |
156 { | |
157 return IntSize(size.width() - horizontalInset, size.height() - verticalInset ); | |
158 } | |
159 | |
160 void NinePieceImageGrid::setDrawInfoEdge(NinePieceDrawInfo& drawInfo, NinePiece piece) const | |
161 { | |
162 IntSize edgeSourceSize = subsize(m_imageSize, m_left.slice + m_right.slice, m_top.slice + m_bottom.slice); | |
163 IntSize edgeDestinationSize = | |
164 subsize(m_borderImageArea.size(), m_left.width + m_right.width, m_top.wi dth + m_bottom.width); | |
165 | |
166 switch (piece) { | |
167 case LeftPiece: | |
168 setVerticalEdge(drawInfo, m_left, | |
169 subrect(m_imageSize, 0, m_top.slice, m_left.slice, edgeSourceSize.he ight()), | |
170 subrect(m_borderImageArea, 0, m_top.width, m_left.width, edgeDestina tionSize.height()), | |
171 m_verticalTileRule); | |
172 break; | |
173 case RightPiece: | |
174 setVerticalEdge(drawInfo, m_right, | |
175 subrect(m_imageSize, -m_right.slice, m_top.slice, m_right.slice, edg eSourceSize.height()), | |
176 subrect(m_borderImageArea, -m_right.width, m_top.width, m_right.widt h, edgeDestinationSize.height()), | |
177 m_verticalTileRule); | |
178 break; | |
179 case TopPiece: | |
180 setHorizontalEdge(drawInfo, m_top, | |
181 subrect(m_imageSize, m_left.slice, 0, edgeSourceSize.width(), m_top. slice), | |
182 subrect(m_borderImageArea, m_left.width, 0, edgeDestinationSize.widt h(), m_top.width), | |
183 m_horizontalTileRule); | |
184 break; | |
185 case BottomPiece: | |
186 setHorizontalEdge(drawInfo, m_bottom, | |
187 subrect(m_imageSize, m_left.slice, -m_bottom.slice, edgeSourceSize.w idth(), m_bottom.slice), | |
188 subrect(m_borderImageArea, m_left.width, -m_bottom.width, edgeDestin ationSize.width(), m_bottom.width), | |
189 m_horizontalTileRule); | |
190 break; | |
191 default: | |
192 ASSERT_NOT_REACHED(); | |
193 break; | |
194 } | |
195 } | |
196 | |
197 void NinePieceImageGrid::setDrawInfoMiddle(NinePieceDrawInfo& drawInfo) const | |
198 { | |
199 IntSize sourceSize = subsize(m_imageSize, m_left.slice + m_right.slice, m_to p.slice + m_bottom.slice); | |
200 IntSize destinationSize = | |
201 subsize(m_borderImageArea.size(), m_left.width + m_right.width, m_top.wi dth + m_bottom.width); | |
202 | |
203 drawInfo.isDrawable = m_fill && !sourceSize.isEmpty() && !destinationSize.is Empty(); | |
204 if (!drawInfo.isDrawable) | |
205 return; | |
206 | |
207 drawInfo.source = subrect(m_imageSize, m_left.slice, m_top.slice, sourceSize .width(), sourceSize.height()); | |
208 drawInfo.destination = subrect(m_borderImageArea, m_left.width, m_top.width, | |
209 destinationSize.width(), destinationSize.height()); | |
210 | |
211 FloatSize middleScaleFactor(1, 1); | |
212 | |
213 if (m_top.draw()) | |
214 middleScaleFactor.setWidth(m_top.scale()); | |
215 else if (m_bottom.draw()) | |
216 middleScaleFactor.setWidth(m_bottom.scale()); | |
217 | |
218 if (m_left.draw()) | |
219 middleScaleFactor.setHeight(m_left.scale()); | |
220 else if (m_right.draw()) | |
221 middleScaleFactor.setHeight(m_right.scale()); | |
222 | |
223 if (!sourceSize.isEmpty()) { | |
224 // For "stretch" rules, just override the scale factor and replace. We o nly have to do this for the center tile, | |
225 // since sides don't even use the scale factor unless they have a rule o ther than "stretch". The middle however | |
226 // can have "stretch" specified in one axis but not the other, so we hav e to correct the scale here. | |
227 if (m_horizontalTileRule == (Image::TileRule)StretchImageRule) | |
228 middleScaleFactor.setWidth((float) destinationSize.width() / sourceS ize.width()); | |
229 | |
230 if (m_verticalTileRule == (Image::TileRule)StretchImageRule) | |
231 middleScaleFactor.setHeight((float) destinationSize.height() / sourc eSize.height()); | |
232 } | |
233 | |
234 drawInfo.tileScale = middleScaleFactor; | |
235 drawInfo.tileRule = { m_horizontalTileRule, m_verticalTileRule }; | |
236 } | |
237 | |
238 NinePieceImageGrid::NinePieceDrawInfo NinePieceImageGrid::getNinePieceDrawInfo(N inePiece piece) const | |
239 { | |
240 NinePieceDrawInfo drawInfo; | |
241 drawInfo.isCornerPiece = | |
242 piece == TopLeftPiece || piece == TopRightPiece || piece == BottomLeftPi ece || piece == BottomRightPiece; | |
243 | |
244 if (drawInfo.isCornerPiece) | |
245 setDrawInfoCorner(drawInfo, piece); | |
246 else if (piece != MiddlePiece) | |
247 setDrawInfoEdge(drawInfo, piece); | |
248 else | |
249 setDrawInfoMiddle(drawInfo); | |
250 | |
251 return drawInfo; | |
252 } | |
253 | |
254 } // namespace blink | |
OLD | NEW |