| /* | 
 |  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * | 
 |  * 1. Redistributions of source code must retain the above | 
 |  *    copyright notice, this list of conditions and the following | 
 |  *    disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above | 
 |  *    copyright notice, this list of conditions and the following | 
 |  *    disclaimer in the documentation and/or other materials | 
 |  *    provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY | 
 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 |  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE | 
 |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | 
 |  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | 
 |  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | 
 |  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
 |  * SUCH DAMAGE. | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 | #include "BasicShapeFunctions.h" | 
 |  | 
 | #include "BasicShapes.h" | 
 | #include "CSSBasicShapes.h" | 
 | #include "CSSPrimitiveValueMappings.h" | 
 | #include "CSSValuePool.h" | 
 | #include "Pair.h" | 
 | #include "RenderStyle.h" | 
 | #include "SVGPathByteStream.h" | 
 |  | 
 | namespace WebCore { | 
 |  | 
 | static Ref<CSSPrimitiveValue> valueForCenterCoordinate(CSSValuePool& pool, const RenderStyle& style, const BasicShapeCenterCoordinate& center, BoxOrient orientation) | 
 | { | 
 |     if (center.direction() == BasicShapeCenterCoordinate::TopLeft) | 
 |         return pool.createValue(center.length(), style); | 
 |  | 
 |     CSSValueID keyword = orientation == BoxOrient::Horizontal ? CSSValueRight : CSSValueBottom; | 
 |  | 
 |     return pool.createValue(Pair::create(pool.createIdentifierValue(keyword), pool.createValue(center.length(), style))); | 
 | } | 
 |  | 
 | static Ref<CSSPrimitiveValue> basicShapeRadiusToCSSValue(const RenderStyle& style, CSSValuePool& pool, const BasicShapeRadius& radius) | 
 | { | 
 |     switch (radius.type()) { | 
 |     case BasicShapeRadius::Value: | 
 |         return pool.createValue(radius.value(), style); | 
 |     case BasicShapeRadius::ClosestSide: | 
 |         return pool.createIdentifierValue(CSSValueClosestSide); | 
 |     case BasicShapeRadius::FarthestSide: | 
 |         return pool.createIdentifierValue(CSSValueFarthestSide); | 
 |     } | 
 |  | 
 |     ASSERT_NOT_REACHED(); | 
 |     return pool.createIdentifierValue(CSSValueClosestSide); | 
 | } | 
 |  | 
 | Ref<CSSPrimitiveValue> valueForBasicShape(const RenderStyle& style, const BasicShape& basicShape) | 
 | { | 
 |     auto& cssValuePool = CSSValuePool::singleton(); | 
 |  | 
 |     RefPtr<CSSBasicShape> basicShapeValue; | 
 |     switch (basicShape.type()) { | 
 |     case BasicShape::Type::Circle: { | 
 |         auto& circle = downcast<BasicShapeCircle>(basicShape); | 
 |         auto circleValue = CSSBasicShapeCircle::create(); | 
 |  | 
 |         circleValue->setCenterX(valueForCenterCoordinate(cssValuePool, style, circle.centerX(), BoxOrient::Horizontal)); | 
 |         circleValue->setCenterY(valueForCenterCoordinate(cssValuePool, style, circle.centerY(), BoxOrient::Vertical)); | 
 |         circleValue->setRadius(basicShapeRadiusToCSSValue(style, cssValuePool, circle.radius())); | 
 |  | 
 |         basicShapeValue = WTFMove(circleValue); | 
 |         break; | 
 |     } | 
 |     case BasicShape::Type::Ellipse: { | 
 |         auto& ellipse = downcast<BasicShapeEllipse>(basicShape); | 
 |         auto ellipseValue = CSSBasicShapeEllipse::create(); | 
 |  | 
 |         ellipseValue->setCenterX(valueForCenterCoordinate(cssValuePool, style, ellipse.centerX(), BoxOrient::Horizontal)); | 
 |         ellipseValue->setCenterY(valueForCenterCoordinate(cssValuePool, style, ellipse.centerY(), BoxOrient::Vertical)); | 
 |         ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(style, cssValuePool, ellipse.radiusX())); | 
 |         ellipseValue->setRadiusY(basicShapeRadiusToCSSValue(style, cssValuePool, ellipse.radiusY())); | 
 |  | 
 |         basicShapeValue = WTFMove(ellipseValue); | 
 |         break; | 
 |     } | 
 |     case BasicShape::Type::Polygon: { | 
 |         auto& polygon = downcast<BasicShapePolygon>(basicShape); | 
 |         auto polygonValue = CSSBasicShapePolygon::create(); | 
 |  | 
 |         polygonValue->setWindRule(polygon.windRule()); | 
 |         const Vector<Length>& values = polygon.values(); | 
 |         for (unsigned i = 0; i < values.size(); i += 2) | 
 |             polygonValue->appendPoint(cssValuePool.createValue(values.at(i), style), cssValuePool.createValue(values.at(i + 1), style)); | 
 |  | 
 |         basicShapeValue = WTFMove(polygonValue); | 
 |         break; | 
 |     } | 
 |     case BasicShape::Type::Path: { | 
 |         auto& pathShape = downcast<BasicShapePath>(basicShape); | 
 |         auto pathShapeValue = CSSBasicShapePath::create(pathShape.pathData()->copy()); | 
 |         pathShapeValue->setWindRule(pathShape.windRule()); | 
 |  | 
 |         basicShapeValue = WTFMove(pathShapeValue); | 
 |         break; | 
 |     } | 
 |     case BasicShape::Type::Inset: { | 
 |         auto& inset = downcast<BasicShapeInset>(basicShape); | 
 |         auto insetValue = CSSBasicShapeInset::create(); | 
 |  | 
 |         insetValue->setTop(cssValuePool.createValue(inset.top(), style)); | 
 |         insetValue->setRight(cssValuePool.createValue(inset.right(), style)); | 
 |         insetValue->setBottom(cssValuePool.createValue(inset.bottom(), style)); | 
 |         insetValue->setLeft(cssValuePool.createValue(inset.left(), style)); | 
 |  | 
 |         insetValue->setTopLeftRadius(cssValuePool.createValue(inset.topLeftRadius(), style)); | 
 |         insetValue->setTopRightRadius(cssValuePool.createValue(inset.topRightRadius(), style)); | 
 |         insetValue->setBottomRightRadius(cssValuePool.createValue(inset.bottomRightRadius(), style)); | 
 |         insetValue->setBottomLeftRadius(cssValuePool.createValue(inset.bottomLeftRadius(), style)); | 
 |  | 
 |         basicShapeValue = WTFMove(insetValue); | 
 |         break; | 
 |     } | 
 |     } | 
 |  | 
 |     return cssValuePool.createValue(basicShapeValue.releaseNonNull()); | 
 | } | 
 |  | 
 | static Length convertToLength(const CSSToLengthConversionData& conversionData, const CSSPrimitiveValue* value) | 
 | { | 
 |     return value->convertToLength<FixedIntegerConversion | FixedFloatConversion | PercentConversion | CalculatedConversion>(conversionData); | 
 | } | 
 |  | 
 | static LengthSize convertToLengthSize(const CSSToLengthConversionData& conversionData, const CSSPrimitiveValue* value) | 
 | { | 
 |     if (!value) | 
 |         return { { 0, LengthType::Fixed }, { 0, LengthType::Fixed } }; | 
 |  | 
 |     auto& pair = *value->pairValue(); | 
 |     return { convertToLength(conversionData, pair.first()), convertToLength(conversionData, pair.second()) }; | 
 | } | 
 |  | 
 | static BasicShapeCenterCoordinate convertToCenterCoordinate(const CSSToLengthConversionData& conversionData, CSSPrimitiveValue* value) | 
 | { | 
 |     CSSValueID keyword = CSSValueTop; | 
 |     Length offset { 0, LengthType::Fixed }; | 
 |     if (!value) | 
 |         keyword = CSSValueCenter; | 
 |     else if (value->isValueID()) | 
 |         keyword = value->valueID(); | 
 |     else if (Pair* pair = value->pairValue()) { | 
 |         keyword = pair->first()->valueID(); | 
 |         offset = convertToLength(conversionData, pair->second()); | 
 |     } else | 
 |         offset = convertToLength(conversionData, value); | 
 |  | 
 |     BasicShapeCenterCoordinate::Direction direction; | 
 |     switch (keyword) { | 
 |     case CSSValueTop: | 
 |     case CSSValueLeft: | 
 |         direction = BasicShapeCenterCoordinate::TopLeft; | 
 |         break; | 
 |     case CSSValueRight: | 
 |     case CSSValueBottom: | 
 |         direction = BasicShapeCenterCoordinate::BottomRight; | 
 |         break; | 
 |     case CSSValueCenter: | 
 |         direction = BasicShapeCenterCoordinate::TopLeft; | 
 |         offset = Length(50, LengthType::Percent); | 
 |         break; | 
 |     default: | 
 |         ASSERT_NOT_REACHED(); | 
 |         direction = BasicShapeCenterCoordinate::TopLeft; | 
 |         break; | 
 |     } | 
 |  | 
 |     return BasicShapeCenterCoordinate(direction, offset); | 
 | } | 
 |  | 
 | static BasicShapeRadius cssValueToBasicShapeRadius(const CSSToLengthConversionData& conversionData, CSSPrimitiveValue* radius) | 
 | { | 
 |     if (!radius) | 
 |         return BasicShapeRadius(BasicShapeRadius::ClosestSide); | 
 |  | 
 |     if (radius->isValueID()) { | 
 |         switch (radius->valueID()) { | 
 |         case CSSValueClosestSide: | 
 |             return BasicShapeRadius(BasicShapeRadius::ClosestSide); | 
 |         case CSSValueFarthestSide: | 
 |             return BasicShapeRadius(BasicShapeRadius::FarthestSide); | 
 |         default: | 
 |             ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |     } | 
 |  | 
 |     return BasicShapeRadius(convertToLength(conversionData, radius)); | 
 | } | 
 |  | 
 | Ref<BasicShape> basicShapeForValue(const CSSToLengthConversionData& conversionData, const CSSBasicShape& basicShapeValue, float zoom) | 
 | { | 
 |     RefPtr<BasicShape> basicShape; | 
 |  | 
 |     switch (basicShapeValue.type()) { | 
 |     case CSSBasicShape::CSSBasicShapeCircleType: { | 
 |         auto& circleValue = downcast<CSSBasicShapeCircle>(basicShapeValue); | 
 |         auto circle = BasicShapeCircle::create(); | 
 |  | 
 |         circle->setCenterX(convertToCenterCoordinate(conversionData, circleValue.centerX())); | 
 |         circle->setCenterY(convertToCenterCoordinate(conversionData, circleValue.centerY())); | 
 |         circle->setRadius(cssValueToBasicShapeRadius(conversionData, circleValue.radius())); | 
 |  | 
 |         basicShape = WTFMove(circle); | 
 |         break; | 
 |     } | 
 |     case CSSBasicShape::CSSBasicShapeEllipseType: { | 
 |         auto& ellipseValue = downcast<CSSBasicShapeEllipse>(basicShapeValue); | 
 |         auto ellipse = BasicShapeEllipse::create(); | 
 |  | 
 |         ellipse->setCenterX(convertToCenterCoordinate(conversionData, ellipseValue.centerX())); | 
 |         ellipse->setCenterY(convertToCenterCoordinate(conversionData, ellipseValue.centerY())); | 
 |  | 
 |         ellipse->setRadiusX(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusX())); | 
 |         ellipse->setRadiusY(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusY())); | 
 |  | 
 |         basicShape = WTFMove(ellipse); | 
 |         break; | 
 |     } | 
 |     case CSSBasicShape::CSSBasicShapePolygonType: { | 
 |         auto& polygonValue = downcast<CSSBasicShapePolygon>(basicShapeValue); | 
 |         auto polygon = BasicShapePolygon::create(); | 
 |  | 
 |         polygon->setWindRule(polygonValue.windRule()); | 
 |         auto& values = polygonValue.values(); | 
 |         for (unsigned i = 0; i < values.size(); i += 2) | 
 |             polygon->appendPoint(convertToLength(conversionData, values[i].ptr()), convertToLength(conversionData, values[i + 1].ptr())); | 
 |  | 
 |         basicShape = WTFMove(polygon); | 
 |         break; | 
 |     } | 
 |     case CSSBasicShape::CSSBasicShapeInsetType: { | 
 |         auto& rectValue = downcast<CSSBasicShapeInset>(basicShapeValue); | 
 |         auto rect = BasicShapeInset::create(); | 
 |  | 
 |         rect->setTop(convertToLength(conversionData, rectValue.top())); | 
 |         rect->setRight(convertToLength(conversionData, rectValue.right())); | 
 |         rect->setBottom(convertToLength(conversionData, rectValue.bottom())); | 
 |         rect->setLeft(convertToLength(conversionData, rectValue.left())); | 
 |  | 
 |         rect->setTopLeftRadius(convertToLengthSize(conversionData, rectValue.topLeftRadius())); | 
 |         rect->setTopRightRadius(convertToLengthSize(conversionData, rectValue.topRightRadius())); | 
 |         rect->setBottomRightRadius(convertToLengthSize(conversionData, rectValue.bottomRightRadius())); | 
 |         rect->setBottomLeftRadius(convertToLengthSize(conversionData, rectValue.bottomLeftRadius())); | 
 |  | 
 |         basicShape = WTFMove(rect); | 
 |         break; | 
 |     } | 
 |     case CSSBasicShape::CSSBasicShapePathType: { | 
 |         auto& pathValue = downcast<CSSBasicShapePath>(basicShapeValue); | 
 |         auto path = BasicShapePath::create(pathValue.pathData().copy()); | 
 |         path->setWindRule(pathValue.windRule()); | 
 |         path->setZoom(zoom); | 
 |  | 
 |         basicShape = WTFMove(path); | 
 |         break; | 
 |     } | 
 |     } | 
 |  | 
 |     return basicShape.releaseNonNull(); | 
 | } | 
 |  | 
 | float floatValueForCenterCoordinate(const BasicShapeCenterCoordinate& center, float boxDimension) | 
 | { | 
 |     float offset = floatValueForLength(center.length(), boxDimension); | 
 |     if (center.direction() == BasicShapeCenterCoordinate::TopLeft) | 
 |         return offset; | 
 |     return boxDimension - offset; | 
 | } | 
 |  | 
 | } |