1 /* 2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials 14 * provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "core/css/BasicShapeFunctions.h" 32 33 #include "core/css/CSSBasicShapes.h" 34 #include "core/css/CSSPrimitiveValueMappings.h" 35 #include "core/css/CSSValuePool.h" 36 #include "core/css/Pair.h" 37 #include "core/css/resolver/StyleResolverState.h" 38 #include "core/rendering/style/BasicShapes.h" 39 #include "core/rendering/style/RenderStyle.h" 40 41 namespace WebCore { 42 43 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueForCenterCoordinate(CSSValuePool& pool, const RenderStyle& style, const BasicShapeCenterCoordinate& center, EBoxOrient orientation) 44 { 45 if (center.direction() == BasicShapeCenterCoordinate::TopLeft) 46 return pool.createValue(center.length(), style); 47 48 CSSValueID keyword = orientation == HORIZONTAL ? CSSValueRight : CSSValueBottom; 49 50 return pool.createValue(Pair::create(pool.createIdentifierValue(keyword), pool.createValue(center.length(), style), Pair::DropIdenticalValues)); 51 } 52 53 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> basicShapeRadiusToCSSValue(CSSValuePool& pool, const RenderStyle& style, const BasicShapeRadius& radius) 54 { 55 switch (radius.type()) { 56 case BasicShapeRadius::Value: 57 return pool.createValue(radius.value(), style); 58 case BasicShapeRadius::ClosestSide: 59 return pool.createIdentifierValue(CSSValueClosestSide); 60 case BasicShapeRadius::FarthestSide: 61 return pool.createIdentifierValue(CSSValueFarthestSide); 62 } 63 64 ASSERT_NOT_REACHED(); 65 return nullptr; 66 } 67 68 PassRefPtrWillBeRawPtr<CSSValue> valueForBasicShape(const RenderStyle& style, const BasicShape* basicShape) 69 { 70 CSSValuePool& pool = cssValuePool(); 71 72 RefPtrWillBeRawPtr<CSSBasicShape> basicShapeValue = nullptr; 73 switch (basicShape->type()) { 74 case BasicShape::BasicShapeCircleType: { 75 const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); 76 RefPtrWillBeRawPtr<CSSBasicShapeCircle> circleValue = CSSBasicShapeCircle::create(); 77 78 circleValue->setCenterX(valueForCenterCoordinate(pool, style, circle->centerX(), HORIZONTAL)); 79 circleValue->setCenterY(valueForCenterCoordinate(pool, style, circle->centerY(), VERTICAL)); 80 circleValue->setRadius(basicShapeRadiusToCSSValue(pool, style, circle->radius())); 81 basicShapeValue = circleValue.release(); 82 break; 83 } 84 case BasicShape::BasicShapeEllipseType: { 85 const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape); 86 RefPtrWillBeRawPtr<CSSBasicShapeEllipse> ellipseValue = CSSBasicShapeEllipse::create(); 87 88 ellipseValue->setCenterX(valueForCenterCoordinate(pool, style, ellipse->centerX(), HORIZONTAL)); 89 ellipseValue->setCenterY(valueForCenterCoordinate(pool, style, ellipse->centerY(), VERTICAL)); 90 ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(pool, style, ellipse->radiusX())); 91 ellipseValue->setRadiusY(basicShapeRadiusToCSSValue(pool, style, ellipse->radiusY())); 92 basicShapeValue = ellipseValue.release(); 93 break; 94 } 95 case BasicShape::BasicShapePolygonType: { 96 const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape); 97 RefPtrWillBeRawPtr<CSSBasicShapePolygon> polygonValue = CSSBasicShapePolygon::create(); 98 99 polygonValue->setWindRule(polygon->windRule()); 100 const Vector<Length>& values = polygon->values(); 101 for (unsigned i = 0; i < values.size(); i += 2) 102 polygonValue->appendPoint(pool.createValue(values.at(i), style), pool.createValue(values.at(i + 1), style)); 103 104 basicShapeValue = polygonValue.release(); 105 break; 106 } 107 case BasicShape::BasicShapeInsetType: { 108 const BasicShapeInset* inset = static_cast<const BasicShapeInset*>(basicShape); 109 RefPtrWillBeRawPtr<CSSBasicShapeInset> insetValue = CSSBasicShapeInset::create(); 110 111 insetValue->setTop(pool.createValue(inset->top(), style)); 112 insetValue->setRight(pool.createValue(inset->right(), style)); 113 insetValue->setBottom(pool.createValue(inset->bottom(), style)); 114 insetValue->setLeft(pool.createValue(inset->left(), style)); 115 116 insetValue->setTopLeftRadius(CSSPrimitiveValue::create(inset->topLeftRadius(), style)); 117 insetValue->setTopRightRadius(CSSPrimitiveValue::create(inset->topRightRadius(), style)); 118 insetValue->setBottomRightRadius(CSSPrimitiveValue::create(inset->bottomRightRadius(), style)); 119 insetValue->setBottomLeftRadius(CSSPrimitiveValue::create(inset->bottomLeftRadius(), style)); 120 121 basicShapeValue = insetValue.release(); 122 break; 123 } 124 default: 125 break; 126 } 127 128 return pool.createValue(basicShapeValue.release()); 129 } 130 131 static Length convertToLength(const StyleResolverState& state, CSSPrimitiveValue* value) 132 { 133 if (!value) 134 return Length(0, Fixed); 135 return value->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()); 136 } 137 138 static LengthSize convertToLengthSize(const StyleResolverState& state, CSSPrimitiveValue* value) 139 { 140 if (!value) 141 return LengthSize(Length(0, Fixed), Length(0, Fixed)); 142 143 Pair* pair = value->getPairValue(); 144 return LengthSize(convertToLength(state, pair->first()), convertToLength(state, pair->second())); 145 } 146 147 static BasicShapeCenterCoordinate convertToCenterCoordinate(const StyleResolverState& state, CSSPrimitiveValue* value) 148 { 149 BasicShapeCenterCoordinate::Direction direction; 150 Length offset = Length(0, Fixed); 151 152 CSSValueID keyword = CSSValueTop; 153 if (!value) { 154 keyword = CSSValueCenter; 155 } else if (value->isValueID()) { 156 keyword = value->getValueID(); 157 } else if (Pair* pair = value->getPairValue()) { 158 keyword = pair->first()->getValueID(); 159 offset = convertToLength(state, pair->second()); 160 } else { 161 offset = convertToLength(state, value); 162 } 163 164 switch (keyword) { 165 case CSSValueTop: 166 case CSSValueLeft: 167 direction = BasicShapeCenterCoordinate::TopLeft; 168 break; 169 case CSSValueRight: 170 case CSSValueBottom: 171 direction = BasicShapeCenterCoordinate::BottomRight; 172 break; 173 case CSSValueCenter: 174 direction = BasicShapeCenterCoordinate::TopLeft; 175 offset = Length(50, Percent); 176 break; 177 default: 178 ASSERT_NOT_REACHED(); 179 direction = BasicShapeCenterCoordinate::TopLeft; 180 break; 181 } 182 183 return BasicShapeCenterCoordinate(direction, offset); 184 } 185 186 static BasicShapeRadius cssValueToBasicShapeRadius(const StyleResolverState& state, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> radius) 187 { 188 if (!radius) 189 return BasicShapeRadius(BasicShapeRadius::ClosestSide); 190 191 if (radius->isValueID()) { 192 switch (radius->getValueID()) { 193 case CSSValueClosestSide: 194 return BasicShapeRadius(BasicShapeRadius::ClosestSide); 195 case CSSValueFarthestSide: 196 return BasicShapeRadius(BasicShapeRadius::FarthestSide); 197 default: 198 ASSERT_NOT_REACHED(); 199 break; 200 } 201 } 202 203 return BasicShapeRadius(convertToLength(state, radius.get())); 204 } 205 206 PassRefPtr<BasicShape> basicShapeForValue(const StyleResolverState& state, const CSSBasicShape* basicShapeValue) 207 { 208 RefPtr<BasicShape> basicShape; 209 210 switch (basicShapeValue->type()) { 211 case CSSBasicShape::CSSBasicShapeCircleType: { 212 const CSSBasicShapeCircle* circleValue = static_cast<const CSSBasicShapeCircle *>(basicShapeValue); 213 RefPtr<BasicShapeCircle> circle = BasicShapeCircle::create(); 214 215 circle->setCenterX(convertToCenterCoordinate(state, circleValue->centerX())); 216 circle->setCenterY(convertToCenterCoordinate(state, circleValue->centerY())); 217 circle->setRadius(cssValueToBasicShapeRadius(state, circleValue->radius())); 218 219 basicShape = circle.release(); 220 break; 221 } 222 case CSSBasicShape::CSSBasicShapeEllipseType: { 223 const CSSBasicShapeEllipse* ellipseValue = static_cast<const CSSBasicShapeEllipse *>(basicShapeValue); 224 RefPtr<BasicShapeEllipse> ellipse = BasicShapeEllipse::create(); 225 226 ellipse->setCenterX(convertToCenterCoordinate(state, ellipseValue->centerX())); 227 ellipse->setCenterY(convertToCenterCoordinate(state, ellipseValue->centerY())); 228 ellipse->setRadiusX(cssValueToBasicShapeRadius(state, ellipseValue->radiusX())); 229 ellipse->setRadiusY(cssValueToBasicShapeRadius(state, ellipseValue->radiusY())); 230 231 basicShape = ellipse.release(); 232 break; 233 } 234 case CSSBasicShape::CSSBasicShapePolygonType: { 235 const CSSBasicShapePolygon* polygonValue = static_cast<const CSSBasicShapePolygon *>(basicShapeValue); 236 RefPtr<BasicShapePolygon> polygon = BasicShapePolygon::create(); 237 238 polygon->setWindRule(polygonValue->windRule()); 239 const WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue> >& values = polygonValue->values(); 240 for (unsigned i = 0; i < values.size(); i += 2) 241 polygon->appendPoint(convertToLength(state, values.at(i).get()), convertToLength(state, values.at(i + 1).get())); 242 243 basicShape = polygon.release(); 244 break; 245 } 246 case CSSBasicShape::CSSBasicShapeInsetType: { 247 const CSSBasicShapeInset* rectValue = static_cast<const CSSBasicShapeInset* >(basicShapeValue); 248 RefPtr<BasicShapeInset> rect = BasicShapeInset::create(); 249 250 rect->setTop(convertToLength(state, rectValue->top())); 251 rect->setRight(convertToLength(state, rectValue->right())); 252 rect->setBottom(convertToLength(state, rectValue->bottom())); 253 rect->setLeft(convertToLength(state, rectValue->left())); 254 255 rect->setTopLeftRadius(convertToLengthSize(state, rectValue->topLeftRadius())); 256 rect->setTopRightRadius(convertToLengthSize(state, rectValue->topRightRadius())); 257 rect->setBottomRightRadius(convertToLengthSize(state, rectValue->bottomRightRadius())); 258 rect->setBottomLeftRadius(convertToLengthSize(state, rectValue->bottomLeftRadius())); 259 260 basicShape = rect.release(); 261 break; 262 } 263 default: 264 break; 265 } 266 267 return basicShape.release(); 268 } 269 270 FloatPoint floatPointForCenterCoordinate(const BasicShapeCenterCoordinate& centerX, const BasicShapeCenterCoordinate& centerY, FloatSize boxSize) 271 { 272 FloatPoint p; 273 float offset = floatValueForLength(centerX.length(), boxSize.width()); 274 p.setX(centerX.direction() == BasicShapeCenterCoordinate::TopLeft ? offset : boxSize.width() - offset); 275 offset = floatValueForLength(centerY.length(), boxSize.height()); 276 p.setY(centerY.direction() == BasicShapeCenterCoordinate::TopLeft ? offset : boxSize.height() - offset); 277 return p; 278 } 279 280 } 281