Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / paint / NinePieceImageGrid.cpp
blobb59320dcaa719ad9b4f8285df0a6cdf38b6fd002
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.
5 #include "config.h"
6 #include "core/paint/NinePieceImageGrid.h"
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"
14 namespace blink {
16 static LayoutUnit computeEdgeWidth(const BorderImageLength& borderSlice, int borderSide, const LayoutUnit& imageSide,
17 const LayoutUnit& boxExtent)
19 if (borderSlice.isNumber())
20 return borderSlice.number() * borderSide;
21 if (borderSlice.length().isAuto())
22 return imageSide;
23 return valueForLength(borderSlice.length(), boxExtent);
26 static int computeEdgeSlice(const Length& slice, LayoutUnit maximum)
28 return std::min<int>(maximum, valueForLength(slice, maximum));
31 NinePieceImageGrid::NinePieceImageGrid(const NinePieceImage& ninePieceImage, IntSize 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())
39 StyleImage* styleImage = ninePieceImage.image();
40 ASSERT(styleImage);
42 float imageScaleFactor = styleImage->imageScaleFactor();
43 m_top.slice = computeEdgeSlice(ninePieceImage.imageSlices().top(), imageSize.height()) * imageScaleFactor;
44 m_right.slice = computeEdgeSlice(ninePieceImage.imageSlices().right(), imageSize.width()) * imageScaleFactor;
45 m_bottom.slice = computeEdgeSlice(ninePieceImage.imageSlices().bottom(), imageSize.height()) * imageScaleFactor;
46 m_left.slice = computeEdgeSlice(ninePieceImage.imageSlices().left(), imageSize.width()) * imageScaleFactor;
48 m_top.width = computeEdgeWidth(ninePieceImage.borderSlices().top(), borderWidths.top(), m_top.slice,
49 borderImageArea.height());
50 m_right.width = computeEdgeWidth(ninePieceImage.borderSlices().right(), borderWidths.right(), m_right.slice,
51 borderImageArea.width());
52 m_bottom.width = computeEdgeWidth(ninePieceImage.borderSlices().bottom(), borderWidths.bottom(), m_bottom.slice,
53 borderImageArea.height());
54 m_left.width = computeEdgeWidth(ninePieceImage.borderSlices().left(), borderWidths.left(), m_left.slice,
55 borderImageArea.width());
57 // The spec says: Given Lwidth as the width of the border image area, Lheight as its height, and Wside as the border
58 // image width offset for the side, let f = min(Lwidth/(Wleft+Wright), Lheight/(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() / borderSideWidth,
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;
72 // Given a rectangle, construct a subrectangle using offset, width and height. Negative 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)
76 float baseX = rect.x();
77 if (offsetX < 0)
78 baseX = rect.maxX();
80 float baseY = rect.y();
81 if (offsetY < 0)
82 baseY = rect.maxY();
84 return FloatRect(baseX + offsetX, baseY + offsetY, width, height);
87 static FloatRect subrect(IntSize size, float offsetX, float offsetY, float width, float height)
89 return subrect(IntRect(IntPoint(), size), offsetX, offsetY, width, height);
92 static inline void setCornerPiece(NinePieceImageGrid::NinePieceDrawInfo& drawInfo, bool isDrawable,
93 const FloatRect& source, const FloatRect& destination)
95 drawInfo.isDrawable = isDrawable;
96 if (drawInfo.isDrawable) {
97 drawInfo.source = source;
98 drawInfo.destination = destination;
102 void NinePieceImageGrid::setDrawInfoCorner(NinePieceDrawInfo& drawInfo, NinePiece piece) const
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.slice),
113 subrect(m_borderImageArea, 0, -m_bottom.width, m_left.width, m_bottom.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.width));
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;
131 static inline void setHorizontalEdge(NinePieceImageGrid::NinePieceDrawInfo& drawInfo,
132 const NinePieceImageGrid::Edge& edge, const FloatRect& source, const FloatRect& destination,
133 Image::TileRule tileRule)
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 };
144 static inline void setVerticalEdge(NinePieceImageGrid::NinePieceDrawInfo& drawInfo,
145 const NinePieceImageGrid::Edge& edge, const FloatRect& source, const FloatRect& destination,
146 Image::TileRule tileRule)
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 };
157 void NinePieceImageGrid::setDrawInfoEdge(NinePieceDrawInfo& drawInfo, NinePiece piece) const
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.width + m_right.width, m_top.width + m_bottom.width);
162 switch (piece) {
163 case LeftPiece:
164 setVerticalEdge(drawInfo, m_left,
165 subrect(m_imageSize, 0, m_top.slice, m_left.slice, edgeSourceSize.height()),
166 subrect(m_borderImageArea, 0, m_top.width, m_left.width, edgeDestinationSize.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, edgeSourceSize.height()),
172 subrect(m_borderImageArea, -m_right.width, m_top.width, m_right.width, 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.width(), 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.width(), m_bottom.slice),
184 subrect(m_borderImageArea, m_left.width, -m_bottom.width, edgeDestinationSize.width(), m_bottom.width),
185 m_horizontalTileRule);
186 break;
187 default:
188 ASSERT_NOT_REACHED();
189 break;
193 void NinePieceImageGrid::setDrawInfoMiddle(NinePieceDrawInfo& drawInfo) const
195 IntSize sourceSize = m_imageSize - IntSize(m_left.slice + m_right.slice, m_top.slice + m_bottom.slice);
196 IntSize destinationSize =
197 m_borderImageArea.size() - IntSize(m_left.width + m_right.width, m_top.width + m_bottom.width);
199 drawInfo.isDrawable = m_fill && !sourceSize.isEmpty() && !destinationSize.isEmpty();
200 if (!drawInfo.isDrawable)
201 return;
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());
207 FloatSize middleScaleFactor(1, 1);
209 if (m_top.isDrawable())
210 middleScaleFactor.setWidth(m_top.scale());
211 else if (m_bottom.isDrawable())
212 middleScaleFactor.setWidth(m_bottom.scale());
214 if (m_left.isDrawable())
215 middleScaleFactor.setHeight(m_left.scale());
216 else if (m_right.isDrawable())
217 middleScaleFactor.setHeight(m_right.scale());
219 if (!sourceSize.isEmpty()) {
220 // For "stretch" rules, just override the scale factor and replace. We only have to do this for the center tile,
221 // since sides don't even use the scale factor unless they have a rule other than "stretch". The middle however
222 // can have "stretch" specified in one axis but not the other, so we have to correct the scale here.
223 if (m_horizontalTileRule == (Image::TileRule)StretchImageRule)
224 middleScaleFactor.setWidth((float) destinationSize.width() / sourceSize.width());
226 if (m_verticalTileRule == (Image::TileRule)StretchImageRule)
227 middleScaleFactor.setHeight((float) destinationSize.height() / sourceSize.height());
230 drawInfo.tileScale = middleScaleFactor;
231 drawInfo.tileRule = { m_horizontalTileRule, m_verticalTileRule };
234 NinePieceImageGrid::NinePieceDrawInfo NinePieceImageGrid::getNinePieceDrawInfo(NinePiece piece) const
236 NinePieceDrawInfo drawInfo;
237 drawInfo.isCornerPiece =
238 piece == TopLeftPiece || piece == TopRightPiece || piece == BottomLeftPiece || piece == BottomRightPiece;
240 if (drawInfo.isCornerPiece)
241 setDrawInfoCorner(drawInfo, piece);
242 else if (piece != MiddlePiece)
243 setDrawInfoEdge(drawInfo, piece);
244 else
245 setDrawInfoMiddle(drawInfo);
247 return drawInfo;
250 } // namespace blink