Home | History | Annotate | Download | only in resolver
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  *     * Redistributions of source code must retain the above copyright
      5  * notice, this list of conditions and the following disclaimer.
      6  *     * Redistributions in binary form must reproduce the above
      7  * copyright notice, this list of conditions and the following disclaimer
      8  * in the documentation and/or other materials provided with the
      9  * distribution.
     10  *     * Neither the name of Google Inc. nor the names of its
     11  * contributors may be used to endorse or promote products derived from
     12  * this software without specific prior written permission.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/css/resolver/StyleBuilderConverter.h"
     29 
     30 #include "core/css/CSSFunctionValue.h"
     31 #include "core/css/CSSGridLineNamesValue.h"
     32 #include "core/css/CSSPrimitiveValueMappings.h"
     33 #include "core/css/CSSReflectValue.h"
     34 #include "core/css/CSSShadowValue.h"
     35 #include "core/css/Pair.h"
     36 #include "core/svg/SVGURIReference.h"
     37 
     38 namespace WebCore {
     39 
     40 namespace {
     41 
     42 static GridLength convertGridTrackBreadth(const StyleResolverState& state, CSSPrimitiveValue* primitiveValue)
     43 {
     44     if (primitiveValue->getValueID() == CSSValueMinContent)
     45         return Length(MinContent);
     46 
     47     if (primitiveValue->getValueID() == CSSValueMaxContent)
     48         return Length(MaxContent);
     49 
     50     // Fractional unit.
     51     if (primitiveValue->isFlex())
     52         return GridLength(primitiveValue->getDoubleValue());
     53 
     54     return primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
     55 }
     56 
     57 } // namespace
     58 
     59 PassRefPtr<StyleReflection> StyleBuilderConverter::convertBoxReflect(StyleResolverState& state, CSSValue* value)
     60 {
     61     if (value->isPrimitiveValue()) {
     62         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
     63         return RenderStyle::initialBoxReflect();
     64     }
     65 
     66     CSSReflectValue* reflectValue = toCSSReflectValue(value);
     67     RefPtr<StyleReflection> reflection = StyleReflection::create();
     68     reflection->setDirection(*reflectValue->direction());
     69     if (reflectValue->offset())
     70         reflection->setOffset(reflectValue->offset()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()));
     71     NinePieceImage mask;
     72     mask.setMaskDefaults();
     73     state.styleMap().mapNinePieceImage(state.style(), CSSPropertyWebkitBoxReflect, reflectValue->mask(), mask);
     74     reflection->setMask(mask);
     75 
     76     return reflection.release();
     77 }
     78 
     79 AtomicString StyleBuilderConverter::convertFragmentIdentifier(StyleResolverState& state, CSSValue* value)
     80 {
     81     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
     82     if (primitiveValue->isURI())
     83         return SVGURIReference::fragmentIdentifierFromIRIString(primitiveValue->getStringValue(), state.element()->treeScope());
     84     return nullAtom;
     85 }
     86 
     87 EGlyphOrientation StyleBuilderConverter::convertGlyphOrientation(StyleResolverState&, CSSValue* value)
     88 {
     89     if (!value->isPrimitiveValue())
     90         return GO_0DEG;
     91 
     92     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
     93     if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_DEG)
     94         return GO_0DEG;
     95 
     96     float angle = fabsf(fmodf(primitiveValue->getFloatValue(), 360.0f));
     97 
     98     if (angle <= 45.0f || angle > 315.0f)
     99         return GO_0DEG;
    100     if (angle > 45.0f && angle <= 135.0f)
    101         return GO_90DEG;
    102     if (angle > 135.0f && angle <= 225.0f)
    103         return GO_180DEG;
    104     return GO_270DEG;
    105 }
    106 
    107 GridPosition StyleBuilderConverter::convertGridPosition(StyleResolverState&, CSSValue* value)
    108 {
    109     // We accept the specification's grammar:
    110     // 'auto' | [ <integer> || <custom-ident> ] | [ span && [ <integer> || <custom-ident> ] ] | <custom-ident>
    111 
    112     GridPosition position;
    113 
    114     if (value->isPrimitiveValue()) {
    115         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    116         // We translate <custom-ident> to <string> during parsing as it
    117         // makes handling it more simple.
    118         if (primitiveValue->isString()) {
    119             position.setNamedGridArea(primitiveValue->getStringValue());
    120             return position;
    121         }
    122 
    123         ASSERT(primitiveValue->getValueID() == CSSValueAuto);
    124         return position;
    125     }
    126 
    127     CSSValueList* values = toCSSValueList(value);
    128     ASSERT(values->length());
    129 
    130     bool isSpanPosition = false;
    131     // The specification makes the <integer> optional, in which case it default to '1'.
    132     int gridLineNumber = 1;
    133     String gridLineName;
    134 
    135     CSSValueListIterator it = values;
    136     CSSPrimitiveValue* currentValue = toCSSPrimitiveValue(it.value());
    137     if (currentValue->getValueID() == CSSValueSpan) {
    138         isSpanPosition = true;
    139         it.advance();
    140         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
    141     }
    142 
    143     if (currentValue && currentValue->isNumber()) {
    144         gridLineNumber = currentValue->getIntValue();
    145         it.advance();
    146         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
    147     }
    148 
    149     if (currentValue && currentValue->isString()) {
    150         gridLineName = currentValue->getStringValue();
    151         it.advance();
    152     }
    153 
    154     ASSERT(!it.hasMore());
    155     if (isSpanPosition)
    156         position.setSpanPosition(gridLineNumber, gridLineName);
    157     else
    158         position.setExplicitPosition(gridLineNumber, gridLineName);
    159 
    160     return position;
    161 }
    162 
    163 GridTrackSize StyleBuilderConverter::convertGridTrackSize(StyleResolverState& state, CSSValue* value)
    164 {
    165     if (value->isPrimitiveValue())
    166         return GridTrackSize(convertGridTrackBreadth(state, toCSSPrimitiveValue(value)));
    167 
    168     CSSFunctionValue* minmaxFunction = toCSSFunctionValue(value);
    169     CSSValueList* arguments = minmaxFunction->arguments();
    170     ASSERT_WITH_SECURITY_IMPLICATION(arguments->length() == 2);
    171     GridLength minTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->itemWithoutBoundsCheck(0))));
    172     GridLength maxTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->itemWithoutBoundsCheck(1))));
    173     return GridTrackSize(minTrackBreadth, maxTrackBreadth);
    174 }
    175 
    176 bool StyleBuilderConverter::convertGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines, StyleResolverState& state)
    177 {
    178     // Handle 'none'.
    179     if (value->isPrimitiveValue()) {
    180         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    181         return primitiveValue->getValueID() == CSSValueNone;
    182     }
    183 
    184     if (!value->isValueList())
    185         return false;
    186 
    187     size_t currentNamedGridLine = 0;
    188     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
    189         CSSValue* currValue = i.value();
    190         if (currValue->isGridLineNamesValue()) {
    191             CSSGridLineNamesValue* lineNamesValue = toCSSGridLineNamesValue(currValue);
    192             for (CSSValueListIterator j = lineNamesValue; j.hasMore(); j.advance()) {
    193                 String namedGridLine = toCSSPrimitiveValue(j.value())->getStringValue();
    194                 NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<size_t>());
    195                 result.storedValue->value.append(currentNamedGridLine);
    196                 OrderedNamedGridLines::AddResult orderedInsertionResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
    197                 orderedInsertionResult.storedValue->value.append(namedGridLine);
    198             }
    199             continue;
    200         }
    201 
    202         ++currentNamedGridLine;
    203         trackSizes.append(convertGridTrackSize(state, currValue));
    204     }
    205 
    206     // The parser should have rejected any <track-list> without any <track-size> as
    207     // this is not conformant to the syntax.
    208     ASSERT(!trackSizes.isEmpty());
    209     return true;
    210 }
    211 
    212 void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
    213 {
    214     NamedGridAreaMap::const_iterator end = namedGridAreas.end();
    215     for (NamedGridAreaMap::const_iterator it = namedGridAreas.begin(); it != end; ++it) {
    216         GridSpan areaSpan = direction == ForRows ? it->value.rows : it->value.columns;
    217         {
    218             NamedGridLinesMap::AddResult startResult = namedGridLines.add(it->key + "-start", Vector<size_t>());
    219             startResult.storedValue->value.append(areaSpan.resolvedInitialPosition.toInt());
    220             std::sort(startResult.storedValue->value.begin(), startResult.storedValue->value.end());
    221         }
    222         {
    223             NamedGridLinesMap::AddResult endResult = namedGridLines.add(it->key + "-end", Vector<size_t>());
    224             endResult.storedValue->value.append(areaSpan.resolvedFinalPosition.toInt() + 1);
    225             std::sort(endResult.storedValue->value.begin(), endResult.storedValue->value.end());
    226         }
    227     }
    228 }
    229 
    230 Length StyleBuilderConverter::convertLength(StyleResolverState& state, CSSValue* value)
    231 {
    232     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    233     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    234     result.setQuirk(primitiveValue->isQuirkValue());
    235     return result;
    236 }
    237 
    238 Length StyleBuilderConverter::convertLengthOrAuto(StyleResolverState& state, CSSValue* value)
    239 {
    240     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    241     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
    242     result.setQuirk(primitiveValue->isQuirkValue());
    243     return result;
    244 }
    245 
    246 Length StyleBuilderConverter::convertLengthSizing(StyleResolverState& state, CSSValue* value)
    247 {
    248     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    249     switch (primitiveValue->getValueID()) {
    250     case CSSValueInvalid:
    251         return convertLength(state, value);
    252     case CSSValueIntrinsic:
    253         return Length(Intrinsic);
    254     case CSSValueMinIntrinsic:
    255         return Length(MinIntrinsic);
    256     case CSSValueWebkitMinContent:
    257         return Length(MinContent);
    258     case CSSValueWebkitMaxContent:
    259         return Length(MaxContent);
    260     case CSSValueWebkitFillAvailable:
    261         return Length(FillAvailable);
    262     case CSSValueWebkitFitContent:
    263         return Length(FitContent);
    264     case CSSValueAuto:
    265         return Length(Auto);
    266     default:
    267         ASSERT_NOT_REACHED();
    268         return Length();
    269     }
    270 }
    271 
    272 Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolverState& state, CSSValue* value)
    273 {
    274     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    275     if (primitiveValue->getValueID() == CSSValueNone)
    276         return Length(Undefined);
    277     return convertLengthSizing(state, value);
    278 }
    279 
    280 LengthPoint StyleBuilderConverter::convertLengthPoint(StyleResolverState& state, CSSValue* value)
    281 {
    282     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    283     Pair* pair = primitiveValue->getPairValue();
    284     Length x = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    285     Length y = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    286     return LengthPoint(x, y);
    287 }
    288 
    289 LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolverState&, CSSValue* value)
    290 {
    291     if (value->isPrimitiveValue()) {
    292         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
    293         return LineBoxContainNone;
    294     }
    295 
    296     return toCSSLineBoxContainValue(value)->value();
    297 }
    298 
    299 float StyleBuilderConverter::convertNumberOrPercentage(StyleResolverState& state, CSSValue* value)
    300 {
    301     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    302     ASSERT(primitiveValue->isNumber() || primitiveValue->isPercentage());
    303     if (primitiveValue->isNumber())
    304         return primitiveValue->getFloatValue();
    305     return primitiveValue->getFloatValue() / 100.0f;
    306 }
    307 
    308 EPaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolverState&, CSSValue* cssPaintOrder)
    309 {
    310     if (cssPaintOrder->isValueList()) {
    311         int paintOrder = 0;
    312         CSSValueListInspector iter(cssPaintOrder);
    313         for (size_t i = 0; i < iter.length(); i++) {
    314             CSSPrimitiveValue* value = toCSSPrimitiveValue(iter.item(i));
    315 
    316             EPaintOrderType paintOrderType = PT_NONE;
    317             switch (value->getValueID()) {
    318             case CSSValueFill:
    319                 paintOrderType = PT_FILL;
    320                 break;
    321             case CSSValueStroke:
    322                 paintOrderType = PT_STROKE;
    323                 break;
    324             case CSSValueMarkers:
    325                 paintOrderType = PT_MARKERS;
    326                 break;
    327             default:
    328                 ASSERT_NOT_REACHED();
    329                 break;
    330             }
    331 
    332             paintOrder |= (paintOrderType << kPaintOrderBitwidth*i);
    333         }
    334         return (EPaintOrder)paintOrder;
    335     }
    336 
    337     return PO_NORMAL;
    338 }
    339 
    340 PassRefPtr<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolverState&, CSSValue* value)
    341 {
    342     if (value->isValueList()) {
    343         CSSValueList* list = toCSSValueList(value);
    344         RefPtr<QuotesData> quotes = QuotesData::create();
    345         for (size_t i = 0; i < list->length(); i += 2) {
    346             CSSValue* first = list->itemWithoutBoundsCheck(i);
    347             // item() returns null if out of bounds so this is safe.
    348             CSSValue* second = list->item(i + 1);
    349             if (!second)
    350                 continue;
    351             String startQuote = toCSSPrimitiveValue(first)->getStringValue();
    352             String endQuote = toCSSPrimitiveValue(second)->getStringValue();
    353             quotes->addPair(std::make_pair(startQuote, endQuote));
    354         }
    355         return quotes.release();
    356     }
    357     // FIXME: We should assert we're a primitive value with valueID = CSSValueNone
    358     return QuotesData::create();
    359 }
    360 
    361 LengthSize StyleBuilderConverter::convertRadius(StyleResolverState& state, CSSValue* value)
    362 {
    363     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    364     Pair* pair = primitiveValue->getPairValue();
    365     Length radiusWidth = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    366     Length radiusHeight = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    367     float width = radiusWidth.value();
    368     float height = radiusHeight.value();
    369     ASSERT(width >= 0 && height >= 0);
    370     if (width <= 0 || height <= 0)
    371         return LengthSize(Length(0, Fixed), Length(0, Fixed));
    372     return LengthSize(radiusWidth, radiusHeight);
    373 }
    374 
    375 PassRefPtr<ShadowList> StyleBuilderConverter::convertShadow(StyleResolverState& state, CSSValue* value)
    376 {
    377     if (value->isPrimitiveValue()) {
    378         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
    379         return PassRefPtr<ShadowList>();
    380     }
    381 
    382     const CSSValueList* valueList = toCSSValueList(value);
    383     size_t shadowCount = valueList->length();
    384     ShadowDataVector shadows;
    385     for (size_t i = 0; i < shadowCount; ++i) {
    386         const CSSShadowValue* item = toCSSShadowValue(valueList->item(i));
    387         float x = item->x->computeLength<float>(state.cssToLengthConversionData());
    388         float y = item->y->computeLength<float>(state.cssToLengthConversionData());
    389         float blur = item->blur ? item->blur->computeLength<float>(state.cssToLengthConversionData()) : 0;
    390         float spread = item->spread ? item->spread->computeLength<float>(state.cssToLengthConversionData()) : 0;
    391         ShadowStyle shadowStyle = item->style && item->style->getValueID() == CSSValueInset ? Inset : Normal;
    392         Color color;
    393         if (item->color)
    394             color = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color());
    395         else
    396             color = state.style()->color();
    397         shadows.append(ShadowData(FloatPoint(x, y), blur, spread, shadowStyle, color));
    398     }
    399     return ShadowList::adopt(shadows);
    400 }
    401 
    402 float StyleBuilderConverter::convertSpacing(StyleResolverState& state, CSSValue* value)
    403 {
    404     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    405     if (primitiveValue->getValueID() == CSSValueNormal)
    406         return 0;
    407     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
    408 }
    409 
    410 PassRefPtr<SVGLengthList> StyleBuilderConverter::convertStrokeDasharray(StyleResolverState&, CSSValue* value)
    411 {
    412     if (!value->isValueList()) {
    413         return SVGRenderStyle::initialStrokeDashArray();
    414     }
    415 
    416     CSSValueList* dashes = toCSSValueList(value);
    417 
    418     RefPtr<SVGLengthList> array = SVGLengthList::create();
    419     size_t length = dashes->length();
    420     for (size_t i = 0; i < length; ++i) {
    421         CSSValue* currValue = dashes->itemWithoutBoundsCheck(i);
    422         if (!currValue->isPrimitiveValue())
    423             continue;
    424 
    425         CSSPrimitiveValue* dash = toCSSPrimitiveValue(dashes->itemWithoutBoundsCheck(i));
    426         array->append(SVGLength::fromCSSPrimitiveValue(dash));
    427     }
    428 
    429     return array.release();
    430 }
    431 
    432 Color StyleBuilderConverter::convertSVGColor(StyleResolverState& state, CSSValue* value)
    433 {
    434     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    435     if (primitiveValue->isRGBColor())
    436         return primitiveValue->getRGBA32Value();
    437     ASSERT(primitiveValue->getValueID() == CSSValueCurrentcolor);
    438     return state.style()->color();
    439 }
    440 
    441 PassRefPtr<SVGLength> StyleBuilderConverter::convertSVGLength(StyleResolverState&, CSSValue* value)
    442 {
    443     return SVGLength::fromCSSPrimitiveValue(toCSSPrimitiveValue(value));
    444 }
    445 
    446 float StyleBuilderConverter::convertTextStrokeWidth(StyleResolverState& state, CSSValue* value)
    447 {
    448     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    449     if (primitiveValue->getValueID()) {
    450         float multiplier = convertLineWidth<float>(state, value);
    451         return CSSPrimitiveValue::create(multiplier / 48, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.cssToLengthConversionData());
    452     }
    453     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
    454 }
    455 
    456 } // namespace WebCore
    457