Home | History | Annotate | Download | only in css
      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