dadc1ec303a7ca5137b07683f4f382574e585638
[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/BasicShapeFunctions.h"
31 #include "core/css/CSSFontFeatureValue.h"
32 #include "core/css/CSSFunctionValue.h"
33 #include "core/css/CSSGridLineNamesValue.h"
34 #include "core/css/CSSPrimitiveValueMappings.h"
35 #include "core/css/CSSReflectValue.h"
36 #include "core/css/CSSShadowValue.h"
37 #include "core/css/Pair.h"
38 #include "core/css/Rect.h"
39 #include "core/svg/SVGURIReference.h"
40
41 namespace blink {
42
43 namespace {
44
45 static GridLength convertGridTrackBreadth(const StyleResolverState& state, CSSPrimitiveValue* primitiveValue)
46 {
47     if (primitiveValue->getValueID() == CSSValueMinContent)
48         return Length(MinContent);
49
50     if (primitiveValue->getValueID() == CSSValueMaxContent)
51         return Length(MaxContent);
52
53     // Fractional unit.
54     if (primitiveValue->isFlex())
55         return GridLength(primitiveValue->getDoubleValue());
56
57     return primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
58 }
59
60 } // namespace
61
62 PassRefPtr<StyleReflection> StyleBuilderConverter::convertBoxReflect(StyleResolverState& state, CSSValue* value)
63 {
64     if (value->isPrimitiveValue()) {
65         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
66         return RenderStyle::initialBoxReflect();
67     }
68
69     CSSReflectValue* reflectValue = toCSSReflectValue(value);
70     RefPtr<StyleReflection> reflection = StyleReflection::create();
71     reflection->setDirection(*reflectValue->direction());
72     if (reflectValue->offset())
73         reflection->setOffset(reflectValue->offset()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()));
74     NinePieceImage mask;
75     mask.setMaskDefaults();
76     state.styleMap().mapNinePieceImage(state.style(), CSSPropertyWebkitBoxReflect, reflectValue->mask(), mask);
77     reflection->setMask(mask);
78
79     return reflection.release();
80 }
81
82 Color StyleBuilderConverter::convertColor(StyleResolverState& state, CSSValue* value, bool forVisitedLink)
83 {
84     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
85     return state.document().textLinkColors().colorFromPrimitiveValue(primitiveValue, state.style()->color(), forVisitedLink);
86 }
87
88 AtomicString StyleBuilderConverter::convertFragmentIdentifier(StyleResolverState& state, CSSValue* value)
89 {
90     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
91     if (primitiveValue->isURI())
92         return SVGURIReference::fragmentIdentifierFromIRIString(primitiveValue->getStringValue(), state.element()->treeScope());
93     return nullAtom;
94 }
95
96 LengthBox StyleBuilderConverter::convertClip(StyleResolverState& state, CSSValue* value)
97 {
98     Rect* rect = toCSSPrimitiveValue(value)->getRectValue();
99
100     return LengthBox(convertLengthOrAuto(state, rect->top()),
101         convertLengthOrAuto(state, rect->right()),
102         convertLengthOrAuto(state, rect->bottom()),
103         convertLengthOrAuto(state, rect->left()));
104 }
105
106 static FontDescription::GenericFamilyType convertGenericFamily(CSSValueID valueID)
107 {
108     switch (valueID) {
109     case CSSValueWebkitBody:
110         return FontDescription::StandardFamily;
111     case CSSValueSerif:
112         return FontDescription::SerifFamily;
113     case CSSValueSansSerif:
114         return FontDescription::SansSerifFamily;
115     case CSSValueCursive:
116         return FontDescription::CursiveFamily;
117     case CSSValueFantasy:
118         return FontDescription::FantasyFamily;
119     case CSSValueMonospace:
120         return FontDescription::MonospaceFamily;
121     case CSSValueWebkitPictograph:
122         return FontDescription::PictographFamily;
123     default:
124         return FontDescription::NoFamily;
125     }
126 }
127
128 static bool convertFontFamilyName(StyleResolverState& state, CSSPrimitiveValue* primitiveValue,
129     FontDescription::GenericFamilyType& genericFamily, AtomicString& familyName)
130 {
131     if (primitiveValue->isString()) {
132         genericFamily = FontDescription::NoFamily;
133         familyName = AtomicString(primitiveValue->getStringValue());
134     } else if (state.document().settings()) {
135         genericFamily = convertGenericFamily(primitiveValue->getValueID());
136         familyName = state.fontBuilder().genericFontFamilyName(genericFamily);
137     }
138
139     return !familyName.isEmpty();
140 }
141
142 FontDescription::FamilyDescription StyleBuilderConverter::convertFontFamily(StyleResolverState& state, CSSValue* value)
143 {
144     ASSERT(value->isValueList());
145
146     FontDescription::FamilyDescription desc(FontDescription::NoFamily);
147     FontFamily* currFamily = nullptr;
148
149     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
150         CSSValue* item = i.value();
151         if (!item->isPrimitiveValue())
152             continue;
153
154         FontDescription::GenericFamilyType genericFamily = FontDescription::NoFamily;
155         AtomicString familyName;
156
157         if (!convertFontFamilyName(state, toCSSPrimitiveValue(item), genericFamily, familyName))
158             continue;
159
160         if (!currFamily) {
161             currFamily = &desc.family;
162         } else {
163             RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create();
164             currFamily->appendFamily(newFamily);
165             currFamily = newFamily.get();
166         }
167
168         currFamily->setFamily(familyName);
169
170         if (genericFamily != FontDescription::NoFamily)
171             desc.genericFamily = genericFamily;
172     }
173
174     return desc;
175 }
176
177 PassRefPtr<FontFeatureSettings> StyleBuilderConverter::convertFontFeatureSettings(StyleResolverState& state, CSSValue* value)
178 {
179     if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal)
180         return FontBuilder::initialFeatureSettings();
181
182     CSSValueList* list = toCSSValueList(value);
183     RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create();
184     int len = list->length();
185     for (int i = 0; i < len; ++i) {
186         CSSFontFeatureValue* feature = toCSSFontFeatureValue(list->item(i));
187         settings->append(FontFeature(feature->tag(), feature->value()));
188     }
189     return settings;
190 }
191
192 class RedirectSetHasViewportUnits {
193 public:
194     RedirectSetHasViewportUnits(RenderStyle* from, RenderStyle* to)
195         : m_from(from), m_to(to), m_hadViewportUnits(from->hasViewportUnits())
196     {
197         from->setHasViewportUnits(false);
198     }
199     ~RedirectSetHasViewportUnits()
200     {
201         m_to->setHasViewportUnits(m_from->hasViewportUnits());
202         m_from->setHasViewportUnits(m_hadViewportUnits);
203     }
204 private:
205     RenderStyle* m_from;
206     RenderStyle* m_to;
207     bool m_hadViewportUnits;
208 };
209
210 static float computeFontSize(StyleResolverState& state, CSSPrimitiveValue* primitiveValue, const FontDescription::Size& parentSize)
211 {
212     RedirectSetHasViewportUnits redirect(state.parentStyle(), state.style());
213
214     CSSToLengthConversionData conversionData(state.parentStyle(), state.rootElementStyle(), state.document().renderView(), 1.0f, true);
215     if (primitiveValue->isLength())
216         return primitiveValue->computeLength<float>(conversionData);
217     if (primitiveValue->isCalculatedPercentageWithLength())
218         return primitiveValue->cssCalcValue()->toCalcValue(conversionData)->evaluate(parentSize.value);
219
220     ASSERT_NOT_REACHED();
221     return 0;
222 }
223
224 FontDescription::Size StyleBuilderConverter::convertFontSize(StyleResolverState& state, CSSValue* value)
225 {
226     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
227
228     FontDescription::Size parentSize(0, 0.0f, false);
229
230     // FIXME: Find out when parentStyle could be 0?
231     if (state.parentStyle())
232         parentSize = state.parentFontDescription().size();
233
234     if (CSSValueID valueID = primitiveValue->getValueID()) {
235         switch (valueID) {
236         case CSSValueXxSmall:
237         case CSSValueXSmall:
238         case CSSValueSmall:
239         case CSSValueMedium:
240         case CSSValueLarge:
241         case CSSValueXLarge:
242         case CSSValueXxLarge:
243         case CSSValueWebkitXxxLarge:
244             return FontDescription::Size(FontSize::keywordSize(valueID), 0.0f, false);
245         case CSSValueLarger:
246             return FontDescription::largerSize(parentSize);
247         case CSSValueSmaller:
248             return FontDescription::smallerSize(parentSize);
249         default:
250             ASSERT_NOT_REACHED();
251             return FontBuilder::initialSize();
252         }
253     }
254
255     bool parentIsAbsoluteSize = state.parentFontDescription().isAbsoluteSize();
256
257     if (primitiveValue->isPercentage())
258         return FontDescription::Size(0, (primitiveValue->getFloatValue() * parentSize.value / 100.0f), parentIsAbsoluteSize);
259
260     return FontDescription::Size(0, computeFontSize(state, primitiveValue, parentSize), parentIsAbsoluteSize || !primitiveValue->isFontRelativeLength());
261 }
262
263 FontWeight StyleBuilderConverter::convertFontWeight(StyleResolverState& state, CSSValue* value)
264 {
265     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
266     switch (primitiveValue->getValueID()) {
267     case CSSValueBolder:
268         return FontDescription::bolderWeight(state.parentStyle()->fontDescription().weight());
269     case CSSValueLighter:
270         return FontDescription::lighterWeight(state.parentStyle()->fontDescription().weight());
271     default:
272         return *primitiveValue;
273     }
274 }
275
276 FontDescription::VariantLigatures StyleBuilderConverter::convertFontVariantLigatures(StyleResolverState&, CSSValue* value)
277 {
278     if (value->isValueList()) {
279         FontDescription::VariantLigatures ligatures;
280         CSSValueList* valueList = toCSSValueList(value);
281         for (size_t i = 0; i < valueList->length(); ++i) {
282             CSSValue* item = valueList->item(i);
283             CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item);
284             switch (primitiveValue->getValueID()) {
285             case CSSValueNoCommonLigatures:
286                 ligatures.common = FontDescription::DisabledLigaturesState;
287                 break;
288             case CSSValueCommonLigatures:
289                 ligatures.common = FontDescription::EnabledLigaturesState;
290                 break;
291             case CSSValueNoDiscretionaryLigatures:
292                 ligatures.discretionary = FontDescription::DisabledLigaturesState;
293                 break;
294             case CSSValueDiscretionaryLigatures:
295                 ligatures.discretionary = FontDescription::EnabledLigaturesState;
296                 break;
297             case CSSValueNoHistoricalLigatures:
298                 ligatures.historical = FontDescription::DisabledLigaturesState;
299                 break;
300             case CSSValueHistoricalLigatures:
301                 ligatures.historical = FontDescription::EnabledLigaturesState;
302                 break;
303             case CSSValueNoContextual:
304                 ligatures.contextual = FontDescription::DisabledLigaturesState;
305                 break;
306             case CSSValueContextual:
307                 ligatures.contextual = FontDescription::EnabledLigaturesState;
308                 break;
309             default:
310                 ASSERT_NOT_REACHED();
311                 break;
312             }
313         }
314         return ligatures;
315     }
316
317     ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue());
318     ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal);
319     return FontDescription::VariantLigatures();
320 }
321
322 EGlyphOrientation StyleBuilderConverter::convertGlyphOrientation(StyleResolverState&, CSSValue* value)
323 {
324     if (!value->isPrimitiveValue())
325         return GO_0DEG;
326
327     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
328     if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_DEG)
329         return GO_0DEG;
330
331     float angle = fabsf(fmodf(primitiveValue->getFloatValue(), 360.0f));
332
333     if (angle <= 45.0f || angle > 315.0f)
334         return GO_0DEG;
335     if (angle > 45.0f && angle <= 135.0f)
336         return GO_90DEG;
337     if (angle > 135.0f && angle <= 225.0f)
338         return GO_180DEG;
339     return GO_270DEG;
340 }
341
342 GridAutoFlow StyleBuilderConverter::convertGridAutoFlow(StyleResolverState&, CSSValue* value)
343 {
344     CSSValueList* list = toCSSValueList(value);
345
346     ASSERT(list->length() >= 1);
347     CSSPrimitiveValue* first = toCSSPrimitiveValue(list->item(0));
348     CSSPrimitiveValue* second = list->length() == 2 ? toCSSPrimitiveValue(list->item(1)) : nullptr;
349
350     switch (first->getValueID()) {
351     case CSSValueRow:
352         if (second) {
353             if (second->getValueID() == CSSValueDense)
354                 return AutoFlowRowDense;
355             return AutoFlowStackRow;
356         }
357         return AutoFlowRow;
358     case CSSValueColumn:
359         if (second) {
360             if (second->getValueID() == CSSValueDense)
361                 return AutoFlowColumnDense;
362             return AutoFlowStackColumn;
363         }
364         return AutoFlowColumn;
365     case CSSValueDense:
366         if (second && second->getValueID() == CSSValueColumn)
367             return AutoFlowColumnDense;
368         return AutoFlowRowDense;
369     case CSSValueStack:
370         if (second && second->getValueID() == CSSValueColumn)
371             return AutoFlowStackColumn;
372         return AutoFlowStackRow;
373     default:
374         ASSERT_NOT_REACHED();
375         return RenderStyle::initialGridAutoFlow();
376     }
377 }
378
379 GridPosition StyleBuilderConverter::convertGridPosition(StyleResolverState&, CSSValue* value)
380 {
381     // We accept the specification's grammar:
382     // 'auto' | [ <integer> || <custom-ident> ] | [ span && [ <integer> || <custom-ident> ] ] | <custom-ident>
383
384     GridPosition position;
385
386     if (value->isPrimitiveValue()) {
387         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
388         // We translate <custom-ident> to <string> during parsing as it
389         // makes handling it more simple.
390         if (primitiveValue->isString()) {
391             position.setNamedGridArea(primitiveValue->getStringValue());
392             return position;
393         }
394
395         ASSERT(primitiveValue->getValueID() == CSSValueAuto);
396         return position;
397     }
398
399     CSSValueList* values = toCSSValueList(value);
400     ASSERT(values->length());
401
402     bool isSpanPosition = false;
403     // The specification makes the <integer> optional, in which case it default to '1'.
404     int gridLineNumber = 1;
405     String gridLineName;
406
407     CSSValueListIterator it = values;
408     CSSPrimitiveValue* currentValue = toCSSPrimitiveValue(it.value());
409     if (currentValue->getValueID() == CSSValueSpan) {
410         isSpanPosition = true;
411         it.advance();
412         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
413     }
414
415     if (currentValue && currentValue->isNumber()) {
416         gridLineNumber = currentValue->getIntValue();
417         it.advance();
418         currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0;
419     }
420
421     if (currentValue && currentValue->isString()) {
422         gridLineName = currentValue->getStringValue();
423         it.advance();
424     }
425
426     ASSERT(!it.hasMore());
427     if (isSpanPosition)
428         position.setSpanPosition(gridLineNumber, gridLineName);
429     else
430         position.setExplicitPosition(gridLineNumber, gridLineName);
431
432     return position;
433 }
434
435 GridTrackSize StyleBuilderConverter::convertGridTrackSize(StyleResolverState& state, CSSValue* value)
436 {
437     if (value->isPrimitiveValue())
438         return GridTrackSize(convertGridTrackBreadth(state, toCSSPrimitiveValue(value)));
439
440     CSSFunctionValue* minmaxFunction = toCSSFunctionValue(value);
441     CSSValueList* arguments = minmaxFunction->arguments();
442     ASSERT_WITH_SECURITY_IMPLICATION(arguments->length() == 2);
443     GridLength minTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->item(0))));
444     GridLength maxTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->item(1))));
445     return GridTrackSize(minTrackBreadth, maxTrackBreadth);
446 }
447
448 bool StyleBuilderConverter::convertGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines, StyleResolverState& state)
449 {
450     // Handle 'none'.
451     if (value->isPrimitiveValue()) {
452         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
453         return primitiveValue->getValueID() == CSSValueNone;
454     }
455
456     if (!value->isValueList())
457         return false;
458
459     size_t currentNamedGridLine = 0;
460     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
461         CSSValue* currValue = i.value();
462         if (currValue->isGridLineNamesValue()) {
463             CSSGridLineNamesValue* lineNamesValue = toCSSGridLineNamesValue(currValue);
464             for (CSSValueListIterator j = lineNamesValue; j.hasMore(); j.advance()) {
465                 String namedGridLine = toCSSPrimitiveValue(j.value())->getStringValue();
466                 NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<size_t>());
467                 result.storedValue->value.append(currentNamedGridLine);
468                 OrderedNamedGridLines::AddResult orderedInsertionResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
469                 orderedInsertionResult.storedValue->value.append(namedGridLine);
470             }
471             continue;
472         }
473
474         ++currentNamedGridLine;
475         trackSizes.append(convertGridTrackSize(state, currValue));
476     }
477
478     // The parser should have rejected any <track-list> without any <track-size> as
479     // this is not conformant to the syntax.
480     ASSERT(!trackSizes.isEmpty());
481     return true;
482 }
483
484 void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
485 {
486     for (const auto& namedGridAreaEntry : namedGridAreas) {
487         GridSpan areaSpan = direction == ForRows ? namedGridAreaEntry.value.rows : namedGridAreaEntry.value.columns;
488         {
489             NamedGridLinesMap::AddResult startResult = namedGridLines.add(namedGridAreaEntry.key + "-start", Vector<size_t>());
490             startResult.storedValue->value.append(areaSpan.resolvedInitialPosition.toInt());
491             std::sort(startResult.storedValue->value.begin(), startResult.storedValue->value.end());
492         }
493         {
494             NamedGridLinesMap::AddResult endResult = namedGridLines.add(namedGridAreaEntry.key + "-end", Vector<size_t>());
495             endResult.storedValue->value.append(areaSpan.resolvedFinalPosition.toInt() + 1);
496             std::sort(endResult.storedValue->value.begin(), endResult.storedValue->value.end());
497         }
498     }
499 }
500
501 Length StyleBuilderConverter::convertLength(StyleResolverState& state, CSSValue* value)
502 {
503     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
504     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
505     result.setQuirk(primitiveValue->isQuirkValue());
506     return result;
507 }
508
509 Length StyleBuilderConverter::convertLengthOrAuto(StyleResolverState& state, CSSValue* value)
510 {
511     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
512     Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData());
513     result.setQuirk(primitiveValue->isQuirkValue());
514     return result;
515 }
516
517 Length StyleBuilderConverter::convertLengthSizing(StyleResolverState& state, CSSValue* value)
518 {
519     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
520     switch (primitiveValue->getValueID()) {
521     case CSSValueInvalid:
522         return convertLength(state, value);
523     case CSSValueIntrinsic:
524         return Length(Intrinsic);
525     case CSSValueMinIntrinsic:
526         return Length(MinIntrinsic);
527     case CSSValueWebkitMinContent:
528         return Length(MinContent);
529     case CSSValueWebkitMaxContent:
530         return Length(MaxContent);
531     case CSSValueWebkitFillAvailable:
532         return Length(FillAvailable);
533     case CSSValueWebkitFitContent:
534         return Length(FitContent);
535     case CSSValueAuto:
536         return Length(Auto);
537     default:
538         ASSERT_NOT_REACHED();
539         return Length();
540     }
541 }
542
543 Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolverState& state, CSSValue* value)
544 {
545     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
546     if (primitiveValue->getValueID() == CSSValueNone)
547         return Length(MaxSizeNone);
548     return convertLengthSizing(state, value);
549 }
550
551 LengthPoint StyleBuilderConverter::convertLengthPoint(StyleResolverState& state, CSSValue* value)
552 {
553     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
554     Pair* pair = primitiveValue->getPairValue();
555     Length x = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
556     Length y = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
557     return LengthPoint(x, y);
558 }
559
560 LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolverState&, CSSValue* value)
561 {
562     if (value->isPrimitiveValue()) {
563         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
564         return LineBoxContainNone;
565     }
566
567     return toCSSLineBoxContainValue(value)->value();
568 }
569
570 float StyleBuilderConverter::convertNumberOrPercentage(StyleResolverState& state, CSSValue* value)
571 {
572     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
573     ASSERT(primitiveValue->isNumber() || primitiveValue->isPercentage());
574     if (primitiveValue->isNumber())
575         return primitiveValue->getFloatValue();
576     return primitiveValue->getFloatValue() / 100.0f;
577 }
578
579 static float convertPerspectiveLength(StyleResolverState& state, CSSPrimitiveValue* primitiveValue)
580 {
581     return std::max(primitiveValue->computeLength<float>(state.cssToLengthConversionData()), 0.0f);
582 }
583
584 float StyleBuilderConverter::convertPerspective(StyleResolverState& state, CSSValue* value)
585 {
586     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
587
588     if (primitiveValue->getValueID() == CSSValueNone)
589         return RenderStyle::initialPerspective();
590
591     // CSSPropertyWebkitPerspective accepts unitless numbers.
592     if (primitiveValue->isNumber()) {
593         RefPtrWillBeRawPtr<CSSPrimitiveValue> px = CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX);
594         return convertPerspectiveLength(state, px.get());
595     }
596
597     return convertPerspectiveLength(state, primitiveValue);
598 }
599
600 template <CSSValueID cssValueFor0, CSSValueID cssValueFor100>
601 static Length convertOriginLength(StyleResolverState& state, CSSPrimitiveValue* primitiveValue)
602 {
603     if (primitiveValue->isValueID()) {
604         switch (primitiveValue->getValueID()) {
605         case cssValueFor0:
606             return Length(0, Percent);
607         case cssValueFor100:
608             return Length(100, Percent);
609         case CSSValueCenter:
610             return Length(50, Percent);
611         default:
612             ASSERT_NOT_REACHED();
613         }
614     }
615
616     return StyleBuilderConverter::convertLength(state, primitiveValue);
617 }
618
619 LengthPoint StyleBuilderConverter::convertPerspectiveOrigin(StyleResolverState& state, CSSValue* value)
620 {
621     CSSValueList* list = toCSSValueList(value);
622     ASSERT(list->length() == 2);
623
624     CSSPrimitiveValue* primitiveValueX = toCSSPrimitiveValue(list->item(0));
625     CSSPrimitiveValue* primitiveValueY = toCSSPrimitiveValue(list->item(1));
626
627     return LengthPoint(
628         convertOriginLength<CSSValueLeft, CSSValueRight>(state, primitiveValueX),
629         convertOriginLength<CSSValueTop, CSSValueBottom>(state, primitiveValueY)
630     );
631 }
632
633 EPaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolverState&, CSSValue* cssPaintOrder)
634 {
635     if (cssPaintOrder->isValueList()) {
636         int paintOrder = 0;
637         const CSSValueList& list = *toCSSValueList(cssPaintOrder);
638         for (size_t i = 0; i < list.length(); ++i) {
639             EPaintOrderType paintOrderType = PT_NONE;
640             switch (toCSSPrimitiveValue(list.item(i))->getValueID()) {
641             case CSSValueFill:
642                 paintOrderType = PT_FILL;
643                 break;
644             case CSSValueStroke:
645                 paintOrderType = PT_STROKE;
646                 break;
647             case CSSValueMarkers:
648                 paintOrderType = PT_MARKERS;
649                 break;
650             default:
651                 ASSERT_NOT_REACHED();
652                 break;
653             }
654
655             paintOrder |= (paintOrderType << kPaintOrderBitwidth*i);
656         }
657         return (EPaintOrder)paintOrder;
658     }
659
660     return PO_NORMAL;
661 }
662
663 PassRefPtr<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolverState&, CSSValue* value)
664 {
665     if (value->isValueList()) {
666         CSSValueList* list = toCSSValueList(value);
667         RefPtr<QuotesData> quotes = QuotesData::create();
668         for (size_t i = 0; i < list->length(); i += 2) {
669             CSSValue* first = list->item(i);
670             CSSValue* second = list->item(i + 1);
671             String startQuote = toCSSPrimitiveValue(first)->getStringValue();
672             String endQuote = toCSSPrimitiveValue(second)->getStringValue();
673             quotes->addPair(std::make_pair(startQuote, endQuote));
674         }
675         return quotes.release();
676     }
677     // FIXME: We should assert we're a primitive value with valueID = CSSValueNone
678     return QuotesData::create();
679 }
680
681 LengthSize StyleBuilderConverter::convertRadius(StyleResolverState& state, CSSValue* value)
682 {
683     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
684     Pair* pair = primitiveValue->getPairValue();
685     Length radiusWidth = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
686     Length radiusHeight = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
687     float width = radiusWidth.value();
688     float height = radiusHeight.value();
689     ASSERT(width >= 0 && height >= 0);
690     if (width <= 0 || height <= 0)
691         return LengthSize(Length(0, Fixed), Length(0, Fixed));
692     return LengthSize(radiusWidth, radiusHeight);
693 }
694
695 PassRefPtr<ShadowList> StyleBuilderConverter::convertShadow(StyleResolverState& state, CSSValue* value)
696 {
697     if (value->isPrimitiveValue()) {
698         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
699         return PassRefPtr<ShadowList>();
700     }
701
702     const CSSValueList* valueList = toCSSValueList(value);
703     size_t shadowCount = valueList->length();
704     ShadowDataVector shadows;
705     for (size_t i = 0; i < shadowCount; ++i) {
706         const CSSShadowValue* item = toCSSShadowValue(valueList->item(i));
707         float x = item->x->computeLength<float>(state.cssToLengthConversionData());
708         float y = item->y->computeLength<float>(state.cssToLengthConversionData());
709         float blur = item->blur ? item->blur->computeLength<float>(state.cssToLengthConversionData()) : 0;
710         float spread = item->spread ? item->spread->computeLength<float>(state.cssToLengthConversionData()) : 0;
711         ShadowStyle shadowStyle = item->style && item->style->getValueID() == CSSValueInset ? Inset : Normal;
712         Color color;
713         if (item->color)
714             color = convertColor(state, item->color.get());
715         else
716             color = state.style()->color();
717         shadows.append(ShadowData(FloatPoint(x, y), blur, spread, shadowStyle, color));
718     }
719     return ShadowList::adopt(shadows);
720 }
721
722 PassRefPtr<ShapeValue> StyleBuilderConverter::convertShapeValue(StyleResolverState& state, CSSValue* value)
723 {
724     if (value->isPrimitiveValue()) {
725         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
726         return nullptr;
727     }
728
729     if (value->isImageValue() || value->isImageGeneratorValue() || value->isImageSetValue())
730         return ShapeValue::createImageValue(state.styleImage(CSSPropertyShapeOutside, value));
731
732     RefPtr<BasicShape> shape;
733     CSSBoxType cssBox = BoxMissing;
734     CSSValueList* valueList = toCSSValueList(value);
735     for (unsigned i = 0; i < valueList->length(); ++i) {
736         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(valueList->item(i));
737         if (primitiveValue->isShape())
738             shape = basicShapeForValue(state, primitiveValue->getShapeValue());
739         else
740             cssBox = CSSBoxType(*primitiveValue);
741     }
742
743     if (shape)
744         return ShapeValue::createShapeValue(shape.release(), cssBox);
745
746     ASSERT(cssBox != BoxMissing);
747     return ShapeValue::createBoxShapeValue(cssBox);
748 }
749
750 float StyleBuilderConverter::convertSpacing(StyleResolverState& state, CSSValue* value)
751 {
752     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
753     if (primitiveValue->getValueID() == CSSValueNormal)
754         return 0;
755     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
756 }
757
758 PassRefPtr<SVGLengthList> StyleBuilderConverter::convertStrokeDasharray(StyleResolverState&, CSSValue* value)
759 {
760     if (!value->isValueList()) {
761         return SVGRenderStyle::initialStrokeDashArray();
762     }
763
764     CSSValueList* dashes = toCSSValueList(value);
765
766     RefPtr<SVGLengthList> array = SVGLengthList::create();
767     size_t length = dashes->length();
768     for (size_t i = 0; i < length; ++i) {
769         CSSValue* currValue = dashes->item(i);
770         if (!currValue->isPrimitiveValue())
771             continue;
772
773         CSSPrimitiveValue* dash = toCSSPrimitiveValue(dashes->item(i));
774         array->append(SVGLength::fromCSSPrimitiveValue(dash));
775     }
776
777     return array.release();
778 }
779
780 StyleColor StyleBuilderConverter::convertStyleColor(StyleResolverState& state, CSSValue* value, bool forVisitedLink)
781 {
782     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
783     if (primitiveValue->getValueID() == CSSValueCurrentcolor)
784         return StyleColor::currentColor();
785     return state.document().textLinkColors().colorFromPrimitiveValue(primitiveValue, Color(), forVisitedLink);
786 }
787
788 Color StyleBuilderConverter::convertSVGColor(StyleResolverState& state, CSSValue* value)
789 {
790     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
791     if (primitiveValue->isRGBColor())
792         return primitiveValue->getRGBA32Value();
793     ASSERT(primitiveValue->getValueID() == CSSValueCurrentcolor);
794     return state.style()->color();
795 }
796
797 PassRefPtr<SVGLength> StyleBuilderConverter::convertSVGLength(StyleResolverState&, CSSValue* value)
798 {
799     return SVGLength::fromCSSPrimitiveValue(toCSSPrimitiveValue(value));
800 }
801
802 float StyleBuilderConverter::convertTextStrokeWidth(StyleResolverState& state, CSSValue* value)
803 {
804     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
805     if (primitiveValue->getValueID()) {
806         float multiplier = convertLineWidth<float>(state, value);
807         return CSSPrimitiveValue::create(multiplier / 48, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.cssToLengthConversionData());
808     }
809     return primitiveValue->computeLength<float>(state.cssToLengthConversionData());
810 }
811
812 TransformOrigin StyleBuilderConverter::convertTransformOrigin(StyleResolverState& state, CSSValue* value)
813 {
814     CSSValueList* list = toCSSValueList(value);
815     ASSERT(list->length() == 3);
816
817     CSSPrimitiveValue* primitiveValueX = toCSSPrimitiveValue(list->item(0));
818     CSSPrimitiveValue* primitiveValueY = toCSSPrimitiveValue(list->item(1));
819     CSSPrimitiveValue* primitiveValueZ = toCSSPrimitiveValue(list->item(2));
820
821     return TransformOrigin(
822         convertOriginLength<CSSValueLeft, CSSValueRight>(state, primitiveValueX),
823         convertOriginLength<CSSValueTop, CSSValueBottom>(state, primitiveValueY),
824         StyleBuilderConverter::convertComputedLength<float>(state, primitiveValueZ)
825     );
826 }
827
828 } // namespace blink