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/CSSFontFeatureValue.h"
     31 #include "core/css/CSSFunctionValue.h"
     32 #include "core/css/CSSGridLineNamesValue.h"
     33 #include "core/css/CSSPrimitiveValueMappings.h"
     34 #include "core/css/CSSReflectValue.h"
     35 #include "core/css/CSSShadowValue.h"
     36 #include "core/css/Pair.h"
     37 #include "core/css/Rect.h"
     38 #include "core/svg/SVGURIReference.h"
     39 
     40 namespace blink {
     41 
     42 namespace {
     43 
     44 static GridLength convertGridTrackBreadth(const StyleResolverState& state, CSSPrimitiveValue* primitiveValue)
     45 {
     46     if (primitiveValue->getValueID() == CSSValueMinContent)
     47         return Length(MinContent);
     48 
     49     if (primitiveValue->getValueID() == CSSValueMaxContent)
     50         return Length(MaxContent);
     51 
     52     // Fractional unit.
     53     if (primitiveValue->isFlex())
     54         return GridLength(primitiveValue->getDoubleValue());
     55 
     56     return primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
     57 }
     58 
     59 } // namespace
     60 
     61 PassRefPtr<StyleReflection> StyleBuilderConverter::convertBoxReflect(StyleResolverState& state, CSSValue* value)
     62 {
     63     if (value->isPrimitiveValue()) {
     64         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
     65         return RenderStyle::initialBoxReflect();
     66     }
     67 
     68     CSSReflectValue* reflectValue = toCSSReflectValue(value);
     69     RefPtr<StyleReflection> reflection = StyleReflection::create();
     70     reflection->setDirection(*reflectValue->direction());
     71     if (reflectValue->offset())
     72         reflection->setOffset(reflectValue->offset()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()));
     73     NinePieceImage mask;
     74     mask.setMaskDefaults();
     75     state.styleMap().mapNinePieceImage(state.style(), CSSPropertyWebkitBoxReflect, reflectValue->mask(), mask);
     76     reflection->setMask(mask);
     77 
     78     return reflection.release();
     79 }
     80 
     81 Color StyleBuilderConverter::convertColor(StyleResolverState& state, CSSValue* value, bool forVisitedLink)
     82 {
     83     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
     84     return state.document().textLinkColors().colorFromPrimitiveValue(primitiveValue, state.style()->color(), forVisitedLink);
     85 }
     86 
     87 AtomicString StyleBuilderConverter::convertFragmentIdentifier(StyleResolverState& state, CSSValue* value)
     88 {
     89     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
     90     if (primitiveValue->isURI())
     91         return SVGURIReference::fragmentIdentifierFromIRIString(primitiveValue->getStringValue(), state.element()->treeScope());
     92     return nullAtom;
     93 }
     94 
     95 LengthBox StyleBuilderConverter::convertClip(StyleResolverState& state, CSSValue* value)
     96 {
     97     Rect* rect = toCSSPrimitiveValue(value)->getRectValue();
     98 
     99     return LengthBox(convertLengthOrAuto(state, rect->top()),
    100         convertLengthOrAuto(state, rect->right()),
    101         convertLengthOrAuto(state, rect->bottom()),
    102         convertLengthOrAuto(state, rect->left()));
    103 }
    104 
    105 PassRefPtr<FontFeatureSettings> StyleBuilderConverter::convertFontFeatureSettings(StyleResolverState& state, CSSValue* value)
    106 {
    107     if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal)
    108         return FontBuilder::initialFeatureSettings();
    109 
    110     CSSValueList* list = toCSSValueList(value);
    111     RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create();
    112     int len = list->length();
    113     for (int i = 0; i < len; ++i) {
    114         CSSFontFeatureValue* feature = toCSSFontFeatureValue(list->item(i));
    115         settings->append(FontFeature(feature->tag(), feature->value()));
    116     }
    117     return settings;
    118 }
    119 
    120 class RedirectSetHasViewportUnits {
    121 public:
    122     RedirectSetHasViewportUnits(RenderStyle* from, RenderStyle* to)
    123         : m_from(from), m_to(to), m_hadViewportUnits(from->hasViewportUnits())
    124     {
    125         from->setHasViewportUnits(false);
    126     }
    127     ~RedirectSetHasViewportUnits()
    128     {
    129         m_to->setHasViewportUnits(m_from->hasViewportUnits());
    130         m_from->setHasViewportUnits(m_hadViewportUnits);
    131     }
    132 private:
    133     RenderStyle* m_from;
    134     RenderStyle* m_to;
    135     bool m_hadViewportUnits;
    136 };
    137 
    138 static float computeFontSize(StyleResolverState& state, CSSPrimitiveValue* primitiveValue, const FontDescription::Size& parentSize)
    139 {
    140     RedirectSetHasViewportUnits redirect(state.parentStyle(), state.style());
    141 
    142     CSSToLengthConversionData conversionData(state.parentStyle(), state.rootElementStyle(), state.document().renderView(), 1.0f, true);
    143     if (primitiveValue->isLength())
    144         return primitiveValue->computeLength<float>(conversionData);
    145     if (primitiveValue->isCalculatedPercentageWithLength())
    146         return primitiveValue->cssCalcValue()->toCalcValue(conversionData)->evaluate(parentSize.value);
    147 
    148     ASSERT_NOT_REACHED();
    149     return 0;
    150 }
    151 
    152 FontDescription::Size StyleBuilderConverter::convertFontSize(StyleResolverState& state, CSSValue* value)
    153 {
    154     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    155 
    156     FontDescription::Size parentSize(0, 0.0f, false);
    157 
    158     // FIXME: Find out when parentStyle could be 0?
    159     if (state.parentStyle())
    160         parentSize = state.parentFontDescription().size();
    161 
    162     if (CSSValueID valueID = primitiveValue->getValueID()) {
    163         switch (valueID) {
    164         case CSSValueXxSmall:
    165         case CSSValueXSmall:
    166         case CSSValueSmall:
    167         case CSSValueMedium:
    168         case CSSValueLarge:
    169         case CSSValueXLarge:
    170         case CSSValueXxLarge:
    171         case CSSValueWebkitXxxLarge:
    172             return FontDescription::Size(FontSize::keywordSize(valueID), 0.0f, false);
    173         case CSSValueLarger:
    174             return FontDescription::largerSize(parentSize);
    175         case CSSValueSmaller:
    176             return FontDescription::smallerSize(parentSize);
    177         default:
    178             ASSERT_NOT_REACHED();
    179             return FontBuilder::initialSize();
    180         }
    181     }
    182 
    183     bool parentIsAbsoluteSize = state.parentFontDescription().isAbsoluteSize();
    184 
    185     if (primitiveValue->isPercentage())
    186         return FontDescription::Size(0, (primitiveValue->getFloatValue() * parentSize.value / 100.0f), parentIsAbsoluteSize);
    187 
    188     return FontDescription::Size(0, computeFontSize(state, primitiveValue, parentSize), parentIsAbsoluteSize || !primitiveValue->isFontRelativeLength());
    189 }
    190 
    191 FontWeight StyleBuilderConverter::convertFontWeight(StyleResolverState& state, CSSValue* value)
    192 {
    193     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    194     switch (primitiveValue->getValueID()) {
    195     case CSSValueBolder:
    196         return FontDescription::bolderWeight(state.parentStyle()->fontDescription().weight());
    197     case CSSValueLighter:
    198         return FontDescription::lighterWeight(state.parentStyle()->fontDescription().weight());
    199     default:
    200         return *primitiveValue;
    201     }
    202 }
    203 
    204 FontDescription::VariantLigatures StyleBuilderConverter::convertFontVariantLigatures(StyleResolverState&, CSSValue* value)
    205 {
    206     if (value->isValueList()) {
    207         FontDescription::VariantLigatures ligatures;
    208         CSSValueList* valueList = toCSSValueList(value);
    209         for (size_t i = 0; i < valueList->length(); ++i) {
    210             CSSValue* item = valueList->item(i);
    211             CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item);
    212             switch (primitiveValue->getValueID()) {
    213             case CSSValueNoCommonLigatures:
    214                 ligatures.common = FontDescription::DisabledLigaturesState;
    215                 break;
    216             case CSSValueCommonLigatures:
    217                 ligatures.common = FontDescription::EnabledLigaturesState;
    218                 break;
    219             case CSSValueNoDiscretionaryLigatures:
    220                 ligatures.discretionary = FontDescription::DisabledLigaturesState;
    221                 break;
    222             case CSSValueDiscretionaryLigatures:
    223                 ligatures.discretionary = FontDescription::EnabledLigaturesState;
    224                 break;
    225             case CSSValueNoHistoricalLigatures:
    226                 ligatures.historical = FontDescription::DisabledLigaturesState;
    227                 break;
    228             case CSSValueHistoricalLigatures:
    229                 ligatures.historical = FontDescription::EnabledLigaturesState;
    230                 break;
    231             case CSSValueNoContextual:
    232                 ligatures.contextual = FontDescription::DisabledLigaturesState;
    233                 break;
    234             case CSSValueContextual:
    235                 ligatures.contextual = FontDescription::EnabledLigaturesState;
    236                 break;
    237             default:
    238                 ASSERT_NOT_REACHED();
    239                 break;
    240             }
    241         }
    242         return ligatures;
    243     }
    244 
    245     ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue());
    246     ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal);
    247     return FontDescription::VariantLigatures();
    248 }
    249 
    250 EGlyphOrientation StyleBuilderConverter::convertGlyphOrientation(StyleResolverState&, CSSValue* value)
    251 {
    252     if (!value->isPrimitiveValue())
    253         return GO_0DEG;
    254 
    255     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    256     if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_DEG)
    257         return GO_0DEG;
    258 
    259     float angle = fabsf(fmodf(primitiveValue->getFloatValue(), 360.0f));
    260 
    261     if (angle <= 45.0f || angle > 315.0f)
    262         return GO_0DEG;
    263     if (angle > 45.0f && angle <= 135.0f)
    264         return GO_90DEG;
    265     if (angle > 135.0f && angle <= 225.0f)
    266         return GO_180DEG;
    267     return GO_270DEG;
    268 }
    269 
    270 GridPosition StyleBuilderConverter::convertGridPosition(StyleResolverState&, CSSValue* value)
    271 {
    272     // We accept the specification's grammar:
    273     // 'auto' | [ <integer> || <custom-ident> ] | [ span && [ <integer> || <custom-ident> ] ] | <custom-ident>
    274 
    275     GridPosition position;
    276 
    277     if (value->isPrimitiveValue()) {
    278         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    279         // We translate <custom-ident> to <string> during parsing as it
    280         // makes handling it more simple.
    281         if (primitiveValue->isString()) {
    282             position.setNamedGridArea(primitiveValue->getStringValue());
    283             return position;
    284         }
    285 
    286         ASSERT(primitiveValue->getValueID() == CSSValueAuto);
    287         return position;
    288     }
    289 
    290     CSSValueList* values = toCSSValueList(value);
    291     ASSERT(values->length());
    292 
    293     bool isSpanPosition = false;
    294     // The specification makes the <integer> optional, in which case it default to '1'.
    295     int gridLineNumber = 1;
    296     String gridLineName;
    297 
    298     CSSValueListIterator it = values;
    299     CSSPrimitiveValue* currentValue = toCSSPrimitiveValue(it.value());
    300     if (currentValue->getValueID() == CSSValueSpan) {
    301         isSpanPosition = true;
    302         it.advance();
    303         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
    304     }
    305 
    306     if (currentValue && currentValue->isNumber()) {
    307         gridLineNumber = currentValue->getIntValue();
    308         it.advance();
    309         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
    310     }
    311 
    312     if (currentValue && currentValue->isString()) {
    313         gridLineName = currentValue->getStringValue();
    314         it.advance();
    315     }
    316 
    317     ASSERT(!it.hasMore());
    318     if (isSpanPosition)
    319         position.setSpanPosition(gridLineNumber, gridLineName);
    320     else
    321         position.setExplicitPosition(gridLineNumber, gridLineName);
    322 
    323     return position;
    324 }
    325 
    326 GridTrackSize StyleBuilderConverter::convertGridTrackSize(StyleResolverState& state, CSSValue* value)
    327 {
    328     if (value->isPrimitiveValue())
    329         return GridTrackSize(convertGridTrackBreadth(state, toCSSPrimitiveValue(value)));
    330 
    331     CSSFunctionValue* minmaxFunction = toCSSFunctionValue(value);
    332     CSSValueList* arguments = minmaxFunction->arguments();
    333     ASSERT_WITH_SECURITY_IMPLICATION(arguments->length() == 2);
    334     GridLength minTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->item(0))));
    335     GridLength maxTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->item(1))));
    336     return GridTrackSize(minTrackBreadth, maxTrackBreadth);
    337 }
    338 
    339 bool StyleBuilderConverter::convertGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines, StyleResolverState& state)
    340 {
    341     // Handle 'none'.
    342     if (value->isPrimitiveValue()) {
    343         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    344         return primitiveValue->getValueID() == CSSValueNone;
    345     }
    346 
    347     if (!value->isValueList())
    348         return false;
    349 
    350     size_t currentNamedGridLine = 0;
    351     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
    352         CSSValue* currValue = i.value();
    353         if (currValue->isGridLineNamesValue()) {
    354             CSSGridLineNamesValue* lineNamesValue = toCSSGridLineNamesValue(currValue);
    355             for (CSSValueListIterator j = lineNamesValue; j.hasMore(); j.advance()) {
    356                 String namedGridLine = toCSSPrimitiveValue(j.value())->getStringValue();
    357                 NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<size_t>());
    358                 result.storedValue->value.append(currentNamedGridLine);
    359                 OrderedNamedGridLines::AddResult orderedInsertionResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
    360                 orderedInsertionResult.storedValue->value.append(namedGridLine);
    361             }
    362             continue;
    363         }
    364 
    365         ++currentNamedGridLine;
    366         trackSizes.append(convertGridTrackSize(state, currValue));
    367     }
    368 
    369     // The parser should have rejected any <track-list> without any <track-size> as
    370     // this is not conformant to the syntax.
    371     ASSERT(!trackSizes.isEmpty());
    372     return true;
    373 }
    374 
    375 void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
    376 {
    377     NamedGridAreaMap::const_iterator end = namedGridAreas.end();
    378     for (NamedGridAreaMap::const_iterator it = namedGridAreas.begin(); it != end; ++it) {
    379         GridSpan areaSpan = direction == ForRows ? it->value.rows : it->value.columns;
    380         {
    381             NamedGridLinesMap::AddResult startResult = namedGridLines.add(it->key + "-start", Vector<size_t>());
    382             startResult.storedValue->value.append(areaSpan.resolvedInitialPosition.toInt());
    383             std::sort(startResult.storedValue->value.begin(), startResult.storedValue->value.end());
    384         }
    385         {
    386             NamedGridLinesMap::AddResult endResult = namedGridLines.add(it->key + "-end", Vector<size_t>());
    387             endResult.storedValue->value.append(areaSpan.resolvedFinalPosition.toInt() + 1);
    388             std::sort(endResult.storedValue->value.begin(), endResult.storedValue->value.end());
    389         }
    390     }
    391 }
    392 
    393 Length StyleBuilderConverter::convertLength(StyleResolverState& state, CSSValue* value)
    394 {
    395     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    396     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    397     result.setQuirk(primitiveValue->isQuirkValue());
    398     return result;
    399 }
    400 
    401 Length StyleBuilderConverter::convertLengthOrAuto(StyleResolverState& state, CSSValue* value)
    402 {
    403     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    404     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
    405     result.setQuirk(primitiveValue->isQuirkValue());
    406     return result;
    407 }
    408 
    409 Length StyleBuilderConverter::convertLengthSizing(StyleResolverState& state, CSSValue* value)
    410 {
    411     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    412     switch (primitiveValue->getValueID()) {
    413     case CSSValueInvalid:
    414         return convertLength(state, value);
    415     case CSSValueIntrinsic:
    416         return Length(Intrinsic);
    417     case CSSValueMinIntrinsic:
    418         return Length(MinIntrinsic);
    419     case CSSValueWebkitMinContent:
    420         return Length(MinContent);
    421     case CSSValueWebkitMaxContent:
    422         return Length(MaxContent);
    423     case CSSValueWebkitFillAvailable:
    424         return Length(FillAvailable);
    425     case CSSValueWebkitFitContent:
    426         return Length(FitContent);
    427     case CSSValueAuto:
    428         return Length(Auto);
    429     default:
    430         ASSERT_NOT_REACHED();
    431         return Length();
    432     }
    433 }
    434 
    435 Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolverState& state, CSSValue* value)
    436 {
    437     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    438     if (primitiveValue->getValueID() == CSSValueNone)
    439         return Length(MaxSizeNone);
    440     return convertLengthSizing(state, value);
    441 }
    442 
    443 LengthPoint StyleBuilderConverter::convertLengthPoint(StyleResolverState& state, CSSValue* value)
    444 {
    445     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    446     Pair* pair = primitiveValue->getPairValue();
    447     Length x = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    448     Length y = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    449     return LengthPoint(x, y);
    450 }
    451 
    452 LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolverState&, CSSValue* value)
    453 {
    454     if (value->isPrimitiveValue()) {
    455         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
    456         return LineBoxContainNone;
    457     }
    458 
    459     return toCSSLineBoxContainValue(value)->value();
    460 }
    461 
    462 float StyleBuilderConverter::convertNumberOrPercentage(StyleResolverState& state, CSSValue* value)
    463 {
    464     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    465     ASSERT(primitiveValue->isNumber() || primitiveValue->isPercentage());
    466     if (primitiveValue->isNumber())
    467         return primitiveValue->getFloatValue();
    468     return primitiveValue->getFloatValue() / 100.0f;
    469 }
    470 
    471 EPaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolverState&, CSSValue* cssPaintOrder)
    472 {
    473     if (cssPaintOrder->isValueList()) {
    474         int paintOrder = 0;
    475         CSSValueListInspector iter(cssPaintOrder);
    476         for (size_t i = 0; i < iter.length(); i++) {
    477             CSSPrimitiveValue* value = toCSSPrimitiveValue(iter.item(i));
    478 
    479             EPaintOrderType paintOrderType = PT_NONE;
    480             switch (value->getValueID()) {
    481             case CSSValueFill:
    482                 paintOrderType = PT_FILL;
    483                 break;
    484             case CSSValueStroke:
    485                 paintOrderType = PT_STROKE;
    486                 break;
    487             case CSSValueMarkers:
    488                 paintOrderType = PT_MARKERS;
    489                 break;
    490             default:
    491                 ASSERT_NOT_REACHED();
    492                 break;
    493             }
    494 
    495             paintOrder |= (paintOrderType << kPaintOrderBitwidth*i);
    496         }
    497         return (EPaintOrder)paintOrder;
    498     }
    499 
    500     return PO_NORMAL;
    501 }
    502 
    503 PassRefPtr<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolverState&, CSSValue* value)
    504 {
    505     if (value->isValueList()) {
    506         CSSValueList* list = toCSSValueList(value);
    507         RefPtr<QuotesData> quotes = QuotesData::create();
    508         for (size_t i = 0; i < list->length(); i += 2) {
    509             CSSValue* first = list->item(i);
    510             CSSValue* second = list->item(i + 1);
    511             String startQuote = toCSSPrimitiveValue(first)->getStringValue();
    512             String endQuote = toCSSPrimitiveValue(second)->getStringValue();
    513             quotes->addPair(std::make_pair(startQuote, endQuote));
    514         }
    515         return quotes.release();
    516     }
    517     // FIXME: We should assert we're a primitive value with valueID = CSSValueNone
    518     return QuotesData::create();
    519 }
    520 
    521 LengthSize StyleBuilderConverter::convertRadius(StyleResolverState& state, CSSValue* value)
    522 {
    523     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    524     Pair* pair = primitiveValue->getPairValue();
    525     Length radiusWidth = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    526     Length radiusHeight = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
    527     float width = radiusWidth.value();
    528     float height = radiusHeight.value();
    529     ASSERT(width >= 0 && height >= 0);
    530     if (width <= 0 || height <= 0)
    531         return LengthSize(Length(0, Fixed), Length(0, Fixed));
    532     return LengthSize(radiusWidth, radiusHeight);
    533 }
    534 
    535 PassRefPtr<ShadowList> StyleBuilderConverter::convertShadow(StyleResolverState& state, CSSValue* value)
    536 {
    537     if (value->isPrimitiveValue()) {
    538         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
    539         return PassRefPtr<ShadowList>();
    540     }
    541 
    542     const CSSValueList* valueList = toCSSValueList(value);
    543     size_t shadowCount = valueList->length();
    544     ShadowDataVector shadows;
    545     for (size_t i = 0; i < shadowCount; ++i) {
    546         const CSSShadowValue* item = toCSSShadowValue(valueList->item(i));
    547         float x = item->x->computeLength<float>(state.cssToLengthConversionData());
    548         float y = item->y->computeLength<float>(state.cssToLengthConversionData());
    549         float blur = item->blur ? item->blur->computeLength<float>(state.cssToLengthConversionData()) : 0;
    550         float spread = item->spread ? item->spread->computeLength<float>(state.cssToLengthConversionData()) : 0;
    551         ShadowStyle shadowStyle = item->style && item->style->getValueID() == CSSValueInset ? Inset : Normal;
    552         Color color;
    553         if (item->color)
    554             color = convertColor(state, item->color.get());
    555         else
    556             color = state.style()->color();
    557         shadows.append(ShadowData(FloatPoint(x, y), blur, spread, shadowStyle, color));
    558     }
    559     return ShadowList::adopt(shadows);
    560 }
    561 
    562 float StyleBuilderConverter::convertSpacing(StyleResolverState& state, CSSValue* value)
    563 {
    564     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    565     if (primitiveValue->getValueID() == CSSValueNormal)
    566         return 0;
    567     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
    568 }
    569 
    570 PassRefPtr<SVGLengthList> StyleBuilderConverter::convertStrokeDasharray(StyleResolverState&, CSSValue* value)
    571 {
    572     if (!value->isValueList()) {
    573         return SVGRenderStyle::initialStrokeDashArray();
    574     }
    575 
    576     CSSValueList* dashes = toCSSValueList(value);
    577 
    578     RefPtr<SVGLengthList> array = SVGLengthList::create();
    579     size_t length = dashes->length();
    580     for (size_t i = 0; i < length; ++i) {
    581         CSSValue* currValue = dashes->item(i);
    582         if (!currValue->isPrimitiveValue())
    583             continue;
    584 
    585         CSSPrimitiveValue* dash = toCSSPrimitiveValue(dashes->item(i));
    586         array->append(SVGLength::fromCSSPrimitiveValue(dash));
    587     }
    588 
    589     return array.release();
    590 }
    591 
    592 StyleColor StyleBuilderConverter::convertStyleColor(StyleResolverState& state, CSSValue* value, bool forVisitedLink)
    593 {
    594     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    595     if (primitiveValue->getValueID() == CSSValueCurrentcolor)
    596         return StyleColor::currentColor();
    597     return state.document().textLinkColors().colorFromPrimitiveValue(primitiveValue, Color(), forVisitedLink);
    598 }
    599 
    600 Color StyleBuilderConverter::convertSVGColor(StyleResolverState& state, CSSValue* value)
    601 {
    602     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    603     if (primitiveValue->isRGBColor())
    604         return primitiveValue->getRGBA32Value();
    605     ASSERT(primitiveValue->getValueID() == CSSValueCurrentcolor);
    606     return state.style()->color();
    607 }
    608 
    609 PassRefPtr<SVGLength> StyleBuilderConverter::convertSVGLength(StyleResolverState&, CSSValue* value)
    610 {
    611     return SVGLength::fromCSSPrimitiveValue(toCSSPrimitiveValue(value));
    612 }
    613 
    614 float StyleBuilderConverter::convertTextStrokeWidth(StyleResolverState& state, CSSValue* value)
    615 {
    616     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    617     if (primitiveValue->getValueID()) {
    618         float multiplier = convertLineWidth<float>(state, value);
    619         return CSSPrimitiveValue::create(multiplier / 48, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.cssToLengthConversionData());
    620     }
    621     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
    622 }
    623 
    624 } // namespace blink
    625