Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / resolver / StyleBuilderConverter.cpp
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