Chromium Code Reviews| 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 |