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

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

Issue 1180053009: Rewrite nine piece image painting code (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Some more polish Created 5 years, 6 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698