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

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: Address review comments 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
« no previous file with comments | « Source/core/paint/NinePieceImageGrid.h ('k') | Source/core/paint/NinePieceImageGridTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Given a rectangle, construct a subrectangle using offset, width and height. N egative offsets are relative to the
73 // extent of the given rectangle.
74 static FloatRect subrect(IntRect rect, float offsetX, float offsetY, float width , float height)
75 {
76 float baseX = rect.x();
77 if (offsetX < 0)
78 baseX = rect.maxX();
79
80 float baseY = rect.y();
81 if (offsetY < 0)
82 baseY = rect.maxY();
83
84 return FloatRect(baseX + offsetX, baseY + offsetY, width, height);
85 }
86
87 static FloatRect subrect(IntSize size, float offsetX, float offsetY, float width , float height)
88 {
89 return subrect(IntRect(IntPoint(), size), offsetX, offsetY, width, height);
90 }
91
92 static inline void setCornerPiece(NinePieceImageGrid::NinePieceDrawInfo& drawInf o, bool isDrawable,
93 const FloatRect& source, const FloatRect& destination)
94 {
95 drawInfo.isDrawable = isDrawable;
96 if (drawInfo.isDrawable) {
97 drawInfo.source = source;
98 drawInfo.destination = destination;
99 }
100 }
101
102 void NinePieceImageGrid::setDrawInfoCorner(NinePieceDrawInfo& drawInfo, NinePiec e piece) const
103 {
104 switch (piece) {
105 case TopLeftPiece:
106 setCornerPiece(drawInfo, m_top.isDrawable() && m_left.isDrawable(),
107 subrect(m_imageSize, 0, 0, m_left.slice, m_top.slice),
108 subrect(m_borderImageArea, 0, 0, m_left.width, m_top.width));
109 break;
110 case BottomLeftPiece:
111 setCornerPiece(drawInfo, m_bottom.isDrawable() && m_left.isDrawable(),
112 subrect(m_imageSize, 0, -m_bottom.slice, m_left.slice, m_bottom.slic e),
113 subrect(m_borderImageArea, 0, -m_bottom.width, m_left.width, m_botto m.width));
114 break;
115 case TopRightPiece:
116 setCornerPiece(drawInfo, m_top.isDrawable() && m_right.isDrawable(),
117 subrect(m_imageSize, -m_right.slice, 0, m_right.slice, m_top.slice),
118 subrect(m_borderImageArea, -m_right.width, 0, m_right.width, m_top.w idth));
119 break;
120 case BottomRightPiece:
121 setCornerPiece(drawInfo, m_bottom.isDrawable() && m_right.isDrawable(),
122 subrect(m_imageSize, -m_right.slice, -m_bottom.slice, m_right.slice, m_bottom.slice),
123 subrect(m_borderImageArea, -m_right.width, -m_bottom.width, m_right. width, m_bottom.width));
124 break;
125 default:
126 ASSERT_NOT_REACHED();
127 break;
128 }
129 }
130
131 static inline void setHorizontalEdge(NinePieceImageGrid::NinePieceDrawInfo& draw Info,
132 const NinePieceImageGrid::Edge& edge, const FloatRect& source, const FloatRe ct& destination,
133 Image::TileRule tileRule)
134 {
135 drawInfo.isDrawable = edge.isDrawable() && source.width() > 0;
136 if (drawInfo.isDrawable) {
137 drawInfo.source = source;
138 drawInfo.destination = destination;
139 drawInfo.tileScale = FloatSize(edge.scale(), edge.scale());
140 drawInfo.tileRule = { tileRule, Image::StretchTile };
141 }
142 }
143
144 static inline void setVerticalEdge(NinePieceImageGrid::NinePieceDrawInfo& drawIn fo,
145 const NinePieceImageGrid::Edge& edge, const FloatRect& source, const FloatRe ct& destination,
146 Image::TileRule tileRule)
147 {
148 drawInfo.isDrawable = edge.isDrawable() && source.height() > 0;
149 if (drawInfo.isDrawable) {
150 drawInfo.source = source;
151 drawInfo.destination = destination;
152 drawInfo.tileScale = FloatSize(edge.scale(), edge.scale());
153 drawInfo.tileRule = { Image::StretchTile, tileRule };
154 }
155 }
156
157 void NinePieceImageGrid::setDrawInfoEdge(NinePieceDrawInfo& drawInfo, NinePiece piece) const
158 {
159 IntSize edgeSourceSize = m_imageSize - IntSize(m_left.slice + m_right.slice, m_top.slice + m_bottom.slice);
160 IntSize edgeDestinationSize = m_borderImageArea.size() - IntSize(m_left.widt h + m_right.width, m_top.width + m_bottom.width);
161
162 switch (piece) {
163 case LeftPiece:
164 setVerticalEdge(drawInfo, m_left,
165 subrect(m_imageSize, 0, m_top.slice, m_left.slice, edgeSourceSize.he ight()),
166 subrect(m_borderImageArea, 0, m_top.width, m_left.width, edgeDestina tionSize.height()),
167 m_verticalTileRule);
168 break;
169 case RightPiece:
170 setVerticalEdge(drawInfo, m_right,
171 subrect(m_imageSize, -m_right.slice, m_top.slice, m_right.slice, edg eSourceSize.height()),
172 subrect(m_borderImageArea, -m_right.width, m_top.width, m_right.widt h, edgeDestinationSize.height()),
173 m_verticalTileRule);
174 break;
175 case TopPiece:
176 setHorizontalEdge(drawInfo, m_top,
177 subrect(m_imageSize, m_left.slice, 0, edgeSourceSize.width(), m_top. slice),
178 subrect(m_borderImageArea, m_left.width, 0, edgeDestinationSize.widt h(), m_top.width),
179 m_horizontalTileRule);
180 break;
181 case BottomPiece:
182 setHorizontalEdge(drawInfo, m_bottom,
183 subrect(m_imageSize, m_left.slice, -m_bottom.slice, edgeSourceSize.w idth(), m_bottom.slice),
184 subrect(m_borderImageArea, m_left.width, -m_bottom.width, edgeDestin ationSize.width(), m_bottom.width),
185 m_horizontalTileRule);
186 break;
187 default:
188 ASSERT_NOT_REACHED();
189 break;
190 }
191 }
192
193 void NinePieceImageGrid::setDrawInfoMiddle(NinePieceDrawInfo& drawInfo) const
194 {
195 IntSize sourceSize = m_imageSize - IntSize(m_left.slice + m_right.slice, m_t op.slice + m_bottom.slice);
196 IntSize destinationSize =
197 m_borderImageArea.size() - IntSize(m_left.width + m_right.width, m_top.w idth + m_bottom.width);
198
199 drawInfo.isDrawable = m_fill && !sourceSize.isEmpty() && !destinationSize.is Empty();
200 if (!drawInfo.isDrawable)
201 return;
202
203 drawInfo.source = subrect(m_imageSize, m_left.slice, m_top.slice, sourceSize .width(), sourceSize.height());
204 drawInfo.destination = subrect(m_borderImageArea, m_left.width, m_top.width,
205 destinationSize.width(), destinationSize.height());
206
207 FloatSize middleScaleFactor(1, 1);
208
209 if (m_top.isDrawable())
210 middleScaleFactor.setWidth(m_top.scale());
211 else if (m_bottom.isDrawable())
212 middleScaleFactor.setWidth(m_bottom.scale());
213
214 if (m_left.isDrawable())
215 middleScaleFactor.setHeight(m_left.scale());
216 else if (m_right.isDrawable())
217 middleScaleFactor.setHeight(m_right.scale());
218
219 if (!sourceSize.isEmpty()) {
220 // For "stretch" rules, just override the scale factor and replace. We o nly have to do this for the center tile,
221 // since sides don't even use the scale factor unless they have a rule o ther than "stretch". The middle however
222 // can have "stretch" specified in one axis but not the other, so we hav e to correct the scale here.
223 if (m_horizontalTileRule == (Image::TileRule)StretchImageRule)
224 middleScaleFactor.setWidth((float) destinationSize.width() / sourceS ize.width());
225
226 if (m_verticalTileRule == (Image::TileRule)StretchImageRule)
227 middleScaleFactor.setHeight((float) destinationSize.height() / sourc eSize.height());
228 }
229
230 drawInfo.tileScale = middleScaleFactor;
231 drawInfo.tileRule = { m_horizontalTileRule, m_verticalTileRule };
232 }
233
234 NinePieceImageGrid::NinePieceDrawInfo NinePieceImageGrid::getNinePieceDrawInfo(N inePiece piece) const
235 {
236 NinePieceDrawInfo drawInfo;
237 drawInfo.isCornerPiece =
238 piece == TopLeftPiece || piece == TopRightPiece || piece == BottomLeftPi ece || piece == BottomRightPiece;
239
240 if (drawInfo.isCornerPiece)
241 setDrawInfoCorner(drawInfo, piece);
242 else if (piece != MiddlePiece)
243 setDrawInfoEdge(drawInfo, piece);
244 else
245 setDrawInfoMiddle(drawInfo);
246
247 return drawInfo;
248 }
249
250 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/paint/NinePieceImageGrid.h ('k') | Source/core/paint/NinePieceImageGridTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698