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
40namespace blink {
41
42namespace {
43
44static 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
61PassRefPtr<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
81Color 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
87AtomicString 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
95LengthBox 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
105PassRefPtr<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
120class RedirectSetHasViewportUnits {
121public:
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    }
132private:
133    RenderStyle* m_from;
134    RenderStyle* m_to;
135    bool m_hadViewportUnits;
136};
137
138static 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
152FontDescription::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
191FontWeight 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
204FontDescription::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
250EGlyphOrientation 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
270GridPosition 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
326GridTrackSize 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
339bool 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
375void 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
393Length 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
401Length 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
409Length 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
435Length 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
443LengthPoint 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
452LineBoxContain 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
462float 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
471EPaintOrder 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
503PassRefPtr<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
521LengthSize 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
535PassRefPtr<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
562float 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
570PassRefPtr<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
592StyleColor 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
600Color 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
609PassRefPtr<SVGLength> StyleBuilderConverter::convertSVGLength(StyleResolverState&, CSSValue* value)
610{
611    return SVGLength::fromCSSPrimitiveValue(toCSSPrimitiveValue(value));
612}
613
614float 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