1/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
4 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
7 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
8 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
9 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
10 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
11 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are
14 * met:
15 *
16 *     * Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *     * Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following disclaimer
20 * in the documentation and/or other materials provided with the
21 * distribution.
22 *     * Neither the name of Google Inc. nor the names of its
23 * contributors may be used to endorse or promote products derived from
24 * this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include "config.h"
40
41#include "core/CSSPropertyNames.h"
42#include "core/CSSValueKeywords.h"
43#include "core/StyleBuilderFunctions.h"
44#include "core/StylePropertyShorthand.h"
45#include "core/css/BasicShapeFunctions.h"
46#include "core/css/CSSAspectRatioValue.h"
47#include "core/css/CSSCursorImageValue.h"
48#include "core/css/CSSFontValue.h"
49#include "core/css/CSSGradientValue.h"
50#include "core/css/CSSGridTemplateAreasValue.h"
51#include "core/css/CSSHelper.h"
52#include "core/css/CSSImageSetValue.h"
53#include "core/css/CSSLineBoxContainValue.h"
54#include "core/css/CSSPrimitiveValueMappings.h"
55#include "core/css/CSSPropertyMetadata.h"
56#include "core/css/Counter.h"
57#include "core/css/Pair.h"
58#include "core/css/StylePropertySet.h"
59#include "core/css/StyleRule.h"
60#include "core/css/resolver/ElementStyleResources.h"
61#include "core/css/resolver/FilterOperationResolver.h"
62#include "core/css/resolver/FontBuilder.h"
63#include "core/css/resolver/StyleBuilder.h"
64#include "core/css/resolver/TransformBuilder.h"
65#include "core/frame/LocalFrame.h"
66#include "core/frame/Settings.h"
67#include "core/rendering/style/CounterContent.h"
68#include "core/rendering/style/QuotesData.h"
69#include "core/rendering/style/RenderStyle.h"
70#include "core/rendering/style/RenderStyleConstants.h"
71#include "core/rendering/style/SVGRenderStyle.h"
72#include "core/rendering/style/StyleGeneratedImage.h"
73#include "platform/fonts/FontDescription.h"
74#include "wtf/MathExtras.h"
75#include "wtf/StdLibExtras.h"
76#include "wtf/Vector.h"
77
78namespace blink {
79
80namespace {
81
82static inline bool isValidVisitedLinkProperty(CSSPropertyID id)
83{
84    switch (id) {
85    case CSSPropertyBackgroundColor:
86    case CSSPropertyBorderLeftColor:
87    case CSSPropertyBorderRightColor:
88    case CSSPropertyBorderTopColor:
89    case CSSPropertyBorderBottomColor:
90    case CSSPropertyColor:
91    case CSSPropertyFill:
92    case CSSPropertyOutlineColor:
93    case CSSPropertyStroke:
94    case CSSPropertyTextDecorationColor:
95    case CSSPropertyWebkitColumnRuleColor:
96    case CSSPropertyWebkitTextEmphasisColor:
97    case CSSPropertyWebkitTextFillColor:
98    case CSSPropertyWebkitTextStrokeColor:
99        return true;
100    default:
101        return false;
102    }
103}
104
105} // namespace
106
107void StyleBuilder::applyProperty(CSSPropertyID id, StyleResolverState& state, CSSValue* value)
108{
109    ASSERT_WITH_MESSAGE(!isExpandedShorthand(id), "Shorthand property id = %d wasn't expanded at parsing time", id);
110
111    bool isInherit = state.parentNode() && value->isInheritedValue();
112    bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue());
113
114    ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
115    ASSERT(!isInherit || (state.parentNode() && state.parentStyle())); // isInherit -> (state.parentNode() && state.parentStyle())
116
117    if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) {
118        // Limit the properties that can be applied to only the ones honored by :visited.
119        return;
120    }
121
122    if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSPropertyMetadata::isInheritedProperty(id))
123        state.parentStyle()->setHasExplicitlyInheritedProperties();
124
125    StyleBuilder::applyProperty(id, state, value, isInitial, isInherit);
126}
127
128void StyleBuilderFunctions::applyInitialCSSPropertyColor(StyleResolverState& state)
129{
130    Color color = RenderStyle::initialColor();
131    if (state.applyPropertyToRegularStyle())
132        state.style()->setColor(color);
133    if (state.applyPropertyToVisitedLinkStyle())
134        state.style()->setVisitedLinkColor(color);
135}
136
137void StyleBuilderFunctions::applyInheritCSSPropertyColor(StyleResolverState& state)
138{
139    Color color = state.parentStyle()->color();
140    if (state.applyPropertyToRegularStyle())
141        state.style()->setColor(color);
142    if (state.applyPropertyToVisitedLinkStyle())
143        state.style()->setVisitedLinkColor(color);
144}
145
146void StyleBuilderFunctions::applyValueCSSPropertyColor(StyleResolverState& state, CSSValue* value)
147{
148    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
149    // As per the spec, 'color: currentColor' is treated as 'color: inherit'
150    if (primitiveValue->getValueID() == CSSValueCurrentcolor) {
151        applyInheritCSSPropertyColor(state);
152        return;
153    }
154
155    if (state.applyPropertyToRegularStyle())
156        state.style()->setColor(StyleBuilderConverter::convertColor(state, value));
157    if (state.applyPropertyToVisitedLinkStyle())
158        state.style()->setVisitedLinkColor(StyleBuilderConverter::convertColor(state, value, true));
159}
160
161void StyleBuilderFunctions::applyInitialCSSPropertyJustifyItems(StyleResolverState& state)
162{
163    state.style()->setJustifyItems(RenderStyle::initialJustifyItems());
164    state.style()->setJustifyItemsOverflowAlignment(RenderStyle::initialJustifyItemsOverflowAlignment());
165    state.style()->setJustifyItemsPositionType(RenderStyle::initialJustifyItemsPositionType());
166}
167
168void StyleBuilderFunctions::applyInheritCSSPropertyJustifyItems(StyleResolverState& state)
169{
170    state.style()->setJustifyItems(state.parentStyle()->justifyItems());
171    state.style()->setJustifyItemsOverflowAlignment(state.parentStyle()->justifyItemsOverflowAlignment());
172    state.style()->setJustifyItemsPositionType(state.parentStyle()->justifyItemsPositionType());
173}
174
175void StyleBuilderFunctions::applyValueCSSPropertyJustifyItems(StyleResolverState& state, CSSValue* value)
176{
177
178    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
179    if (Pair* pairValue = primitiveValue->getPairValue()) {
180        if (pairValue->first()->getValueID() == CSSValueLegacy) {
181            state.style()->setJustifyItemsPositionType(LegacyPosition);
182            state.style()->setJustifyItems(*pairValue->second());
183        } else {
184            state.style()->setJustifyItems(*pairValue->first());
185            state.style()->setJustifyItemsOverflowAlignment(*pairValue->second());
186        }
187    } else {
188        state.style()->setJustifyItems(*primitiveValue);
189    }
190}
191
192void StyleBuilderFunctions::applyInitialCSSPropertyCursor(StyleResolverState& state)
193{
194    state.style()->clearCursorList();
195    state.style()->setCursor(RenderStyle::initialCursor());
196}
197
198void StyleBuilderFunctions::applyInheritCSSPropertyCursor(StyleResolverState& state)
199{
200    state.style()->setCursor(state.parentStyle()->cursor());
201    state.style()->setCursorList(state.parentStyle()->cursors());
202}
203
204void StyleBuilderFunctions::applyValueCSSPropertyCursor(StyleResolverState& state, CSSValue* value)
205{
206    state.style()->clearCursorList();
207    if (value->isValueList()) {
208        CSSValueList* list = toCSSValueList(value);
209        int len = list->length();
210        state.style()->setCursor(CURSOR_AUTO);
211        for (int i = 0; i < len; i++) {
212            CSSValue* item = list->item(i);
213            if (item->isCursorImageValue()) {
214                CSSCursorImageValue* image = toCSSCursorImageValue(item);
215                if (image->updateIfSVGCursorIsUsed(state.element())) // Elements with SVG cursors are not allowed to share style.
216                    state.style()->setUnique();
217                state.style()->addCursor(state.styleImage(CSSPropertyCursor, image), image->hotSpot());
218            } else {
219                state.style()->setCursor(*toCSSPrimitiveValue(item));
220            }
221        }
222    } else {
223        state.style()->setCursor(*toCSSPrimitiveValue(value));
224    }
225}
226
227void StyleBuilderFunctions::applyValueCSSPropertyDirection(StyleResolverState& state, CSSValue* value)
228{
229    state.style()->setDirection(*toCSSPrimitiveValue(value));
230    Element* element = state.element();
231    if (element && element == element->document().documentElement())
232        element->document().setDirectionSetOnDocumentElement(true);
233}
234
235void StyleBuilderFunctions::applyInitialCSSPropertyFontFamily(StyleResolverState& state)
236{
237    state.fontBuilder().setFontFamilyInitial();
238}
239
240void StyleBuilderFunctions::applyInheritCSSPropertyFontFamily(StyleResolverState& state)
241{
242    state.fontBuilder().setFontFamilyInherit(state.parentFontDescription());
243}
244
245void StyleBuilderFunctions::applyValueCSSPropertyFontFamily(StyleResolverState& state, CSSValue* value)
246{
247    state.fontBuilder().setFontFamilyValue(value);
248}
249
250void StyleBuilderFunctions::applyValueCSSPropertyGlyphOrientationVertical(StyleResolverState& state, CSSValue* value)
251{
252    if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueAuto)
253        state.style()->accessSVGStyle().setGlyphOrientationVertical(GO_AUTO);
254    else
255        state.style()->accessSVGStyle().setGlyphOrientationVertical(StyleBuilderConverter::convertGlyphOrientation(state, value));
256}
257
258void StyleBuilderFunctions::applyInitialCSSPropertyGridTemplateAreas(StyleResolverState& state)
259{
260    state.style()->setNamedGridArea(RenderStyle::initialNamedGridArea());
261    state.style()->setNamedGridAreaRowCount(RenderStyle::initialNamedGridAreaCount());
262    state.style()->setNamedGridAreaColumnCount(RenderStyle::initialNamedGridAreaCount());
263}
264
265void StyleBuilderFunctions::applyInheritCSSPropertyGridTemplateAreas(StyleResolverState& state)
266{
267    state.style()->setNamedGridArea(state.parentStyle()->namedGridArea());
268    state.style()->setNamedGridAreaRowCount(state.parentStyle()->namedGridAreaRowCount());
269    state.style()->setNamedGridAreaColumnCount(state.parentStyle()->namedGridAreaColumnCount());
270}
271
272void StyleBuilderFunctions::applyValueCSSPropertyGridTemplateAreas(StyleResolverState& state, CSSValue* value)
273{
274    if (value->isPrimitiveValue()) {
275        // FIXME: Shouldn't we clear the grid-area values
276        ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
277        return;
278    }
279
280    CSSGridTemplateAreasValue* gridTemplateAreasValue = toCSSGridTemplateAreasValue(value);
281    const NamedGridAreaMap& newNamedGridAreas = gridTemplateAreasValue->gridAreaMap();
282
283    NamedGridLinesMap namedGridColumnLines = state.style()->namedGridColumnLines();
284    NamedGridLinesMap namedGridRowLines = state.style()->namedGridRowLines();
285    StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridColumnLines, ForColumns);
286    StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridRowLines, ForRows);
287    state.style()->setNamedGridColumnLines(namedGridColumnLines);
288    state.style()->setNamedGridRowLines(namedGridRowLines);
289
290    state.style()->setNamedGridArea(newNamedGridAreas);
291    state.style()->setNamedGridAreaRowCount(gridTemplateAreasValue->rowCount());
292    state.style()->setNamedGridAreaColumnCount(gridTemplateAreasValue->columnCount());
293}
294
295void StyleBuilderFunctions::applyValueCSSPropertyLineHeight(StyleResolverState& state, CSSValue* value)
296{
297    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
298    Length lineHeight;
299
300    if (primitiveValue->getValueID() == CSSValueNormal) {
301        lineHeight = RenderStyle::initialLineHeight();
302    } else if (primitiveValue->isLength()) {
303        float multiplier = state.style()->effectiveZoom();
304        if (LocalFrame* frame = state.document().frame())
305            multiplier *= frame->textZoomFactor();
306        lineHeight = primitiveValue->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(multiplier));
307    } else if (primitiveValue->isPercentage()) {
308        lineHeight = Length((state.style()->computedFontSize() * primitiveValue->getIntValue()) / 100.0, Fixed);
309    } else if (primitiveValue->isNumber()) {
310        lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
311    } else if (primitiveValue->isCalculated()) {
312        double multiplier = state.style()->effectiveZoom();
313        if (LocalFrame* frame = state.document().frame())
314            multiplier *= frame->textZoomFactor();
315        Length zoomedLength = Length(primitiveValue->cssCalcValue()->toCalcValue(state.cssToLengthConversionData().copyWithAdjustedZoom(multiplier)));
316        lineHeight = Length(valueForLength(zoomedLength, state.style()->fontSize()), Fixed);
317    } else {
318        return;
319    }
320    state.style()->setLineHeight(lineHeight);
321}
322
323void StyleBuilderFunctions::applyValueCSSPropertyListStyleImage(StyleResolverState& state, CSSValue* value)
324{
325    state.style()->setListStyleImage(state.styleImage(CSSPropertyListStyleImage, value));
326}
327
328void StyleBuilderFunctions::applyInitialCSSPropertyOutlineStyle(StyleResolverState& state)
329{
330    state.style()->setOutlineStyleIsAuto(RenderStyle::initialOutlineStyleIsAuto());
331    state.style()->setOutlineStyle(RenderStyle::initialBorderStyle());
332}
333
334void StyleBuilderFunctions::applyInheritCSSPropertyOutlineStyle(StyleResolverState& state)
335{
336    state.style()->setOutlineStyleIsAuto(state.parentStyle()->outlineStyleIsAuto());
337    state.style()->setOutlineStyle(state.parentStyle()->outlineStyle());
338}
339
340void StyleBuilderFunctions::applyValueCSSPropertyOutlineStyle(StyleResolverState& state, CSSValue* value)
341{
342    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
343    state.style()->setOutlineStyleIsAuto(*primitiveValue);
344    state.style()->setOutlineStyle(*primitiveValue);
345}
346
347void StyleBuilderFunctions::applyValueCSSPropertyResize(StyleResolverState& state, CSSValue* value)
348{
349    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
350
351    EResize r = RESIZE_NONE;
352    if (primitiveValue->getValueID() == CSSValueAuto) {
353        if (Settings* settings = state.document().settings())
354            r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
355    } else {
356        r = *primitiveValue;
357    }
358    state.style()->setResize(r);
359}
360
361static Length mmLength(double mm) { return Length(mm * cssPixelsPerMillimeter, Fixed); }
362static Length inchLength(double inch) { return Length(inch * cssPixelsPerInch, Fixed); }
363static bool getPageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height)
364{
365    DEFINE_STATIC_LOCAL(Length, a5Width, (mmLength(148)));
366    DEFINE_STATIC_LOCAL(Length, a5Height, (mmLength(210)));
367    DEFINE_STATIC_LOCAL(Length, a4Width, (mmLength(210)));
368    DEFINE_STATIC_LOCAL(Length, a4Height, (mmLength(297)));
369    DEFINE_STATIC_LOCAL(Length, a3Width, (mmLength(297)));
370    DEFINE_STATIC_LOCAL(Length, a3Height, (mmLength(420)));
371    DEFINE_STATIC_LOCAL(Length, b5Width, (mmLength(176)));
372    DEFINE_STATIC_LOCAL(Length, b5Height, (mmLength(250)));
373    DEFINE_STATIC_LOCAL(Length, b4Width, (mmLength(250)));
374    DEFINE_STATIC_LOCAL(Length, b4Height, (mmLength(353)));
375    DEFINE_STATIC_LOCAL(Length, letterWidth, (inchLength(8.5)));
376    DEFINE_STATIC_LOCAL(Length, letterHeight, (inchLength(11)));
377    DEFINE_STATIC_LOCAL(Length, legalWidth, (inchLength(8.5)));
378    DEFINE_STATIC_LOCAL(Length, legalHeight, (inchLength(14)));
379    DEFINE_STATIC_LOCAL(Length, ledgerWidth, (inchLength(11)));
380    DEFINE_STATIC_LOCAL(Length, ledgerHeight, (inchLength(17)));
381
382    if (!pageSizeName)
383        return false;
384
385    switch (pageSizeName->getValueID()) {
386    case CSSValueA5:
387        width = a5Width;
388        height = a5Height;
389        break;
390    case CSSValueA4:
391        width = a4Width;
392        height = a4Height;
393        break;
394    case CSSValueA3:
395        width = a3Width;
396        height = a3Height;
397        break;
398    case CSSValueB5:
399        width = b5Width;
400        height = b5Height;
401        break;
402    case CSSValueB4:
403        width = b4Width;
404        height = b4Height;
405        break;
406    case CSSValueLetter:
407        width = letterWidth;
408        height = letterHeight;
409        break;
410    case CSSValueLegal:
411        width = legalWidth;
412        height = legalHeight;
413        break;
414    case CSSValueLedger:
415        width = ledgerWidth;
416        height = ledgerHeight;
417        break;
418    default:
419        return false;
420    }
421
422    if (pageOrientation) {
423        switch (pageOrientation->getValueID()) {
424        case CSSValueLandscape:
425            std::swap(width, height);
426            break;
427        case CSSValuePortrait:
428            // Nothing to do.
429            break;
430        default:
431            return false;
432        }
433    }
434    return true;
435}
436
437void StyleBuilderFunctions::applyInitialCSSPropertySize(StyleResolverState&) { }
438void StyleBuilderFunctions::applyInheritCSSPropertySize(StyleResolverState&) { }
439void StyleBuilderFunctions::applyValueCSSPropertySize(StyleResolverState& state, CSSValue* value)
440{
441    state.style()->resetPageSizeType();
442    Length width;
443    Length height;
444    PageSizeType pageSizeType = PAGE_SIZE_AUTO;
445    CSSValueListInspector inspector(value);
446    switch (inspector.length()) {
447    case 2: {
448        // <length>{2} | <page-size> <orientation>
449        if (!inspector.first()->isPrimitiveValue() || !inspector.second()->isPrimitiveValue())
450            return;
451        CSSPrimitiveValue* first = toCSSPrimitiveValue(inspector.first());
452        CSSPrimitiveValue* second = toCSSPrimitiveValue(inspector.second());
453        if (first->isLength()) {
454            // <length>{2}
455            if (!second->isLength())
456                return;
457            width = first->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0));
458            height = second->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0));
459        } else {
460            // <page-size> <orientation>
461            // The value order is guaranteed. See BisonCSSParser::parseSizeParameter.
462            if (!getPageSizeFromName(first, second, width, height))
463                return;
464        }
465        pageSizeType = PAGE_SIZE_RESOLVED;
466        break;
467    }
468    case 1: {
469        // <length> | auto | <page-size> | [ portrait | landscape]
470        if (!inspector.first()->isPrimitiveValue())
471            return;
472        CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inspector.first());
473        if (primitiveValue->isLength()) {
474            // <length>
475            pageSizeType = PAGE_SIZE_RESOLVED;
476            width = height = primitiveValue->computeLength<Length>(state.cssToLengthConversionData().copyWithAdjustedZoom(1.0));
477        } else {
478            switch (primitiveValue->getValueID()) {
479            case 0:
480                return;
481            case CSSValueAuto:
482                pageSizeType = PAGE_SIZE_AUTO;
483                break;
484            case CSSValuePortrait:
485                pageSizeType = PAGE_SIZE_AUTO_PORTRAIT;
486                break;
487            case CSSValueLandscape:
488                pageSizeType = PAGE_SIZE_AUTO_LANDSCAPE;
489                break;
490            default:
491                // <page-size>
492                pageSizeType = PAGE_SIZE_RESOLVED;
493                if (!getPageSizeFromName(primitiveValue, 0, width, height))
494                    return;
495            }
496        }
497        break;
498    }
499    default:
500        return;
501    }
502    state.style()->setPageSizeType(pageSizeType);
503    state.style()->setPageSize(LengthSize(width, height));
504}
505
506void StyleBuilderFunctions::applyValueCSSPropertyTextAlign(StyleResolverState& state, CSSValue* value)
507{
508    if (!value->isPrimitiveValue())
509        return;
510
511    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
512    // FIXME : Per http://www.w3.org/TR/css3-text/#text-align0 can now take <string> but this is not implemented in the
513    // rendering code.
514    if (primitiveValue->isString())
515        return;
516
517    if (primitiveValue->isValueID() && primitiveValue->getValueID() != CSSValueWebkitMatchParent)
518        state.style()->setTextAlign(*primitiveValue);
519    else if (state.parentStyle()->textAlign() == TASTART)
520        state.style()->setTextAlign(state.parentStyle()->isLeftToRightDirection() ? LEFT : RIGHT);
521    else if (state.parentStyle()->textAlign() == TAEND)
522        state.style()->setTextAlign(state.parentStyle()->isLeftToRightDirection() ? RIGHT : LEFT);
523    else
524        state.style()->setTextAlign(state.parentStyle()->textAlign());
525}
526
527void StyleBuilderFunctions::applyInheritCSSPropertyTextIndent(StyleResolverState& state)
528{
529    state.style()->setTextIndent(state.parentStyle()->textIndent());
530    state.style()->setTextIndentLine(state.parentStyle()->textIndentLine());
531    state.style()->setTextIndentType(state.parentStyle()->textIndentType());
532}
533
534void StyleBuilderFunctions::applyInitialCSSPropertyTextIndent(StyleResolverState& state)
535{
536    state.style()->setTextIndent(RenderStyle::initialTextIndent());
537    state.style()->setTextIndentLine(RenderStyle::initialTextIndentLine());
538    state.style()->setTextIndentType(RenderStyle::initialTextIndentType());
539}
540
541void StyleBuilderFunctions::applyValueCSSPropertyTextIndent(StyleResolverState& state, CSSValue* value)
542{
543    if (!value->isValueList())
544        return;
545
546    Length lengthOrPercentageValue;
547    TextIndentLine textIndentLineValue = RenderStyle::initialTextIndentLine();
548    TextIndentType textIndentTypeValue = RenderStyle::initialTextIndentType();
549
550    for (CSSValueListIterator i(value); i.hasMore(); i.advance()) {
551        CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(i.value());
552        if (!primitiveValue->getValueID())
553            lengthOrPercentageValue = primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
554        else if (primitiveValue->getValueID() == CSSValueEachLine)
555            textIndentLineValue = TextIndentEachLine;
556        else if (primitiveValue->getValueID() == CSSValueHanging)
557            textIndentTypeValue = TextIndentHanging;
558        else
559            ASSERT_NOT_REACHED();
560    }
561
562    state.style()->setTextIndent(lengthOrPercentageValue);
563    state.style()->setTextIndentLine(textIndentLineValue);
564    state.style()->setTextIndentType(textIndentTypeValue);
565}
566
567void StyleBuilderFunctions::applyValueCSSPropertyTransform(StyleResolverState& state, CSSValue* value)
568{
569    TransformOperations operations;
570    TransformBuilder::createTransformOperations(value, state.cssToLengthConversionData(), operations);
571    state.style()->setTransform(operations);
572}
573
574void StyleBuilderFunctions::applyInitialCSSPropertyTransformOrigin(StyleResolverState& state)
575{
576    applyInitialCSSPropertyWebkitTransformOriginX(state);
577    applyInitialCSSPropertyWebkitTransformOriginY(state);
578    applyInitialCSSPropertyWebkitTransformOriginZ(state);
579}
580
581void StyleBuilderFunctions::applyInheritCSSPropertyTransformOrigin(StyleResolverState& state)
582{
583    applyInheritCSSPropertyWebkitTransformOriginX(state);
584    applyInheritCSSPropertyWebkitTransformOriginY(state);
585    applyInheritCSSPropertyWebkitTransformOriginZ(state);
586}
587
588void StyleBuilderFunctions::applyValueCSSPropertyTransformOrigin(StyleResolverState& state, CSSValue* value)
589{
590    CSSValueList* list = toCSSValueList(value);
591    ASSERT(list->length() == 3);
592    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(list->item(0));
593    if (primitiveValue->isValueID()) {
594        switch (primitiveValue->getValueID()) {
595        case CSSValueLeft:
596            state.style()->setTransformOriginX(Length(0, Percent));
597            break;
598        case CSSValueRight:
599            state.style()->setTransformOriginX(Length(100, Percent));
600            break;
601        case CSSValueCenter:
602            state.style()->setTransformOriginX(Length(50, Percent));
603            break;
604        default:
605            ASSERT_NOT_REACHED();
606        }
607    } else {
608        state.style()->setTransformOriginX(StyleBuilderConverter::convertLength(state, primitiveValue));
609    }
610
611    primitiveValue = toCSSPrimitiveValue(list->item(1));
612    if (primitiveValue->isValueID()) {
613        switch (primitiveValue->getValueID()) {
614        case CSSValueTop:
615            state.style()->setTransformOriginY(Length(0, Percent));
616            break;
617        case CSSValueBottom:
618            state.style()->setTransformOriginY(Length(100, Percent));
619            break;
620        case CSSValueCenter:
621            state.style()->setTransformOriginY(Length(50, Percent));
622            break;
623        default:
624            ASSERT_NOT_REACHED();
625        }
626    } else {
627        state.style()->setTransformOriginY(StyleBuilderConverter::convertLength(state, primitiveValue));
628    }
629
630    primitiveValue = toCSSPrimitiveValue(list->item(2));
631    state.style()->setTransformOriginZ(StyleBuilderConverter::convertComputedLength<float>(state, primitiveValue));
632}
633
634void StyleBuilderFunctions::applyInitialCSSPropertyPerspectiveOrigin(StyleResolverState& state)
635{
636    applyInitialCSSPropertyWebkitPerspectiveOriginX(state);
637    applyInitialCSSPropertyWebkitPerspectiveOriginY(state);
638}
639
640void StyleBuilderFunctions::applyInheritCSSPropertyPerspectiveOrigin(StyleResolverState& state)
641{
642    applyInheritCSSPropertyWebkitPerspectiveOriginX(state);
643    applyInheritCSSPropertyWebkitPerspectiveOriginY(state);
644}
645
646void StyleBuilderFunctions::applyValueCSSPropertyPerspectiveOrigin(StyleResolverState& state, CSSValue* value)
647{
648    CSSValueList* list = toCSSValueList(value);
649    ASSERT(list->length() == 2);
650    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(list->item(0));
651    if (primitiveValue->isValueID()) {
652        switch (primitiveValue->getValueID()) {
653        case CSSValueLeft:
654            state.style()->setPerspectiveOriginX(Length(0, Percent));
655            break;
656        case CSSValueRight:
657            state.style()->setPerspectiveOriginX(Length(100, Percent));
658            break;
659        case CSSValueCenter:
660            state.style()->setPerspectiveOriginX(Length(50, Percent));
661            break;
662        default:
663            ASSERT_NOT_REACHED();
664        }
665    } else {
666        state.style()->setPerspectiveOriginX(StyleBuilderConverter::convertLength(state, primitiveValue));
667    }
668
669    primitiveValue = toCSSPrimitiveValue(list->item(1));
670    if (primitiveValue->isValueID()) {
671        switch (primitiveValue->getValueID()) {
672        case CSSValueTop:
673            state.style()->setPerspectiveOriginY(Length(0, Percent));
674            break;
675        case CSSValueBottom:
676            state.style()->setPerspectiveOriginY(Length(100, Percent));
677            break;
678        case CSSValueCenter:
679            state.style()->setPerspectiveOriginY(Length(50, Percent));
680            break;
681        default:
682            ASSERT_NOT_REACHED();
683        }
684    } else {
685        state.style()->setPerspectiveOriginY(StyleBuilderConverter::convertLength(state, primitiveValue));
686    }
687}
688
689void StyleBuilderFunctions::applyInheritCSSPropertyVerticalAlign(StyleResolverState& state)
690{
691    EVerticalAlign verticalAlign = state.parentStyle()->verticalAlign();
692    state.style()->setVerticalAlign(verticalAlign);
693    if (verticalAlign == LENGTH)
694        state.style()->setVerticalAlignLength(state.parentStyle()->verticalAlignLength());
695}
696
697void StyleBuilderFunctions::applyValueCSSPropertyVerticalAlign(StyleResolverState& state, CSSValue* value)
698{
699    if (!value->isPrimitiveValue())
700        return;
701
702    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
703
704    if (primitiveValue->getValueID()) {
705        state.style()->setVerticalAlign(*primitiveValue);
706        return;
707    }
708
709    state.style()->setVerticalAlignLength(primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()));
710}
711
712static void resetEffectiveZoom(StyleResolverState& state)
713{
714    // Reset the zoom in effect. This allows the setZoom method to accurately compute a new zoom in effect.
715    state.setEffectiveZoom(state.parentStyle() ? state.parentStyle()->effectiveZoom() : RenderStyle::initialZoom());
716}
717
718void StyleBuilderFunctions::applyInitialCSSPropertyZoom(StyleResolverState& state)
719{
720    resetEffectiveZoom(state);
721    state.setZoom(RenderStyle::initialZoom());
722}
723
724void StyleBuilderFunctions::applyInheritCSSPropertyZoom(StyleResolverState& state)
725{
726    resetEffectiveZoom(state);
727    state.setZoom(state.parentStyle()->zoom());
728}
729
730void StyleBuilderFunctions::applyValueCSSPropertyZoom(StyleResolverState& state, CSSValue* value)
731{
732    ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue());
733    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
734
735    if (primitiveValue->getValueID() == CSSValueNormal) {
736        resetEffectiveZoom(state);
737        state.setZoom(RenderStyle::initialZoom());
738    } else if (primitiveValue->getValueID() == CSSValueReset) {
739        state.setEffectiveZoom(RenderStyle::initialZoom());
740        state.setZoom(RenderStyle::initialZoom());
741    } else if (primitiveValue->getValueID() == CSSValueDocument) {
742        float docZoom = state.rootElementStyle() ? state.rootElementStyle()->zoom() : RenderStyle::initialZoom();
743        state.setEffectiveZoom(docZoom);
744        state.setZoom(docZoom);
745    } else if (primitiveValue->isPercentage()) {
746        resetEffectiveZoom(state);
747        if (float percent = primitiveValue->getFloatValue())
748            state.setZoom(percent / 100.0f);
749    } else if (primitiveValue->isNumber()) {
750        resetEffectiveZoom(state);
751        if (float number = primitiveValue->getFloatValue())
752            state.setZoom(number);
753    }
754}
755
756void StyleBuilderFunctions::applyInitialCSSPropertyWebkitAspectRatio(StyleResolverState& state)
757{
758    state.style()->setHasAspectRatio(RenderStyle::initialHasAspectRatio());
759    state.style()->setAspectRatioDenominator(RenderStyle::initialAspectRatioDenominator());
760    state.style()->setAspectRatioNumerator(RenderStyle::initialAspectRatioNumerator());
761}
762
763void StyleBuilderFunctions::applyInheritCSSPropertyWebkitAspectRatio(StyleResolverState& state)
764{
765    if (!state.parentStyle()->hasAspectRatio())
766        return;
767    state.style()->setHasAspectRatio(true);
768    state.style()->setAspectRatioDenominator(state.parentStyle()->aspectRatioDenominator());
769    state.style()->setAspectRatioNumerator(state.parentStyle()->aspectRatioNumerator());
770}
771
772void StyleBuilderFunctions::applyValueCSSPropertyWebkitAspectRatio(StyleResolverState& state, CSSValue* value)
773{
774    if (!value->isAspectRatioValue()) {
775        state.style()->setHasAspectRatio(false);
776        return;
777    }
778    CSSAspectRatioValue* aspectRatioValue = toCSSAspectRatioValue(value);
779    state.style()->setHasAspectRatio(true);
780    state.style()->setAspectRatioDenominator(aspectRatioValue->denominatorValue());
781    state.style()->setAspectRatioNumerator(aspectRatioValue->numeratorValue());
782}
783
784void StyleBuilderFunctions::applyValueCSSPropertyWebkitBorderImage(StyleResolverState& state, CSSValue* value)
785{
786    NinePieceImage image;
787    state.styleMap().mapNinePieceImage(state.style(), CSSPropertyWebkitBorderImage, value, image);
788    state.style()->setBorderImage(image);
789}
790
791void StyleBuilderFunctions::applyValueCSSPropertyWebkitClipPath(StyleResolverState& state, CSSValue* value)
792{
793    if (value->isPrimitiveValue()) {
794        CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
795        if (primitiveValue->getValueID() == CSSValueNone) {
796            state.style()->setClipPath(nullptr);
797        } else if (primitiveValue->isShape()) {
798            state.style()->setClipPath(ShapeClipPathOperation::create(basicShapeForValue(state, primitiveValue->getShapeValue())));
799        } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_URI) {
800            String cssURLValue = primitiveValue->getStringValue();
801            KURL url = state.document().completeURL(cssURLValue);
802            // FIXME: It doesn't work with forward or external SVG references (see https://bugs.webkit.org/show_bug.cgi?id=90405)
803            state.style()->setClipPath(ReferenceClipPathOperation::create(cssURLValue, AtomicString(url.fragmentIdentifier())));
804        }
805    }
806}
807
808void StyleBuilderFunctions::applyValueCSSPropertyWebkitFilter(StyleResolverState& state, CSSValue* value)
809{
810    FilterOperations operations;
811    if (FilterOperationResolver::createFilterOperations(value, state.cssToLengthConversionData(), operations, state))
812        state.style()->setFilter(operations);
813}
814
815void StyleBuilderFunctions::applyInitialCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state)
816{
817    state.style()->setTextEmphasisFill(RenderStyle::initialTextEmphasisFill());
818    state.style()->setTextEmphasisMark(RenderStyle::initialTextEmphasisMark());
819    state.style()->setTextEmphasisCustomMark(RenderStyle::initialTextEmphasisCustomMark());
820}
821
822void StyleBuilderFunctions::applyInheritCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state)
823{
824    state.style()->setTextEmphasisFill(state.parentStyle()->textEmphasisFill());
825    state.style()->setTextEmphasisMark(state.parentStyle()->textEmphasisMark());
826    state.style()->setTextEmphasisCustomMark(state.parentStyle()->textEmphasisCustomMark());
827}
828
829void StyleBuilderFunctions::applyValueCSSPropertyWebkitTextEmphasisStyle(StyleResolverState& state, CSSValue* value)
830{
831    if (value->isValueList()) {
832        CSSValueList* list = toCSSValueList(value);
833        ASSERT(list->length() == 2);
834        if (list->length() != 2)
835            return;
836        for (unsigned i = 0; i < 2; ++i) {
837            CSSValue* item = list->item(i);
838            if (!item->isPrimitiveValue())
839                continue;
840
841            CSSPrimitiveValue* value = toCSSPrimitiveValue(item);
842            if (value->getValueID() == CSSValueFilled || value->getValueID() == CSSValueOpen)
843                state.style()->setTextEmphasisFill(*value);
844            else
845                state.style()->setTextEmphasisMark(*value);
846        }
847        state.style()->setTextEmphasisCustomMark(nullAtom);
848        return;
849    }
850
851    if (!value->isPrimitiveValue())
852        return;
853    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
854
855    if (primitiveValue->isString()) {
856        state.style()->setTextEmphasisFill(TextEmphasisFillFilled);
857        state.style()->setTextEmphasisMark(TextEmphasisMarkCustom);
858        state.style()->setTextEmphasisCustomMark(AtomicString(primitiveValue->getStringValue()));
859        return;
860    }
861
862    state.style()->setTextEmphasisCustomMark(nullAtom);
863
864    if (primitiveValue->getValueID() == CSSValueFilled || primitiveValue->getValueID() == CSSValueOpen) {
865        state.style()->setTextEmphasisFill(*primitiveValue);
866        state.style()->setTextEmphasisMark(TextEmphasisMarkAuto);
867    } else {
868        state.style()->setTextEmphasisFill(TextEmphasisFillFilled);
869        state.style()->setTextEmphasisMark(*primitiveValue);
870    }
871}
872
873void StyleBuilderFunctions::applyInitialCSSPropertyWillChange(StyleResolverState& state)
874{
875    state.style()->setWillChangeContents(false);
876    state.style()->setWillChangeScrollPosition(false);
877    state.style()->setWillChangeProperties(Vector<CSSPropertyID>());
878    state.style()->setSubtreeWillChangeContents(state.parentStyle()->subtreeWillChangeContents());
879}
880
881void StyleBuilderFunctions::applyInheritCSSPropertyWillChange(StyleResolverState& state)
882{
883    state.style()->setWillChangeContents(state.parentStyle()->willChangeContents());
884    state.style()->setWillChangeScrollPosition(state.parentStyle()->willChangeScrollPosition());
885    state.style()->setWillChangeProperties(state.parentStyle()->willChangeProperties());
886    state.style()->setSubtreeWillChangeContents(state.parentStyle()->subtreeWillChangeContents());
887}
888
889void StyleBuilderFunctions::applyValueCSSPropertyWillChange(StyleResolverState& state, CSSValue* value)
890{
891    ASSERT(value->isValueList());
892    bool willChangeContents = false;
893    bool willChangeScrollPosition = false;
894    Vector<CSSPropertyID> willChangeProperties;
895
896    for (CSSValueListIterator i(value); i.hasMore(); i.advance()) {
897        CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(i.value());
898        if (CSSPropertyID propertyID = primitiveValue->getPropertyID())
899            willChangeProperties.append(propertyID);
900        else if (primitiveValue->getValueID() == CSSValueContents)
901            willChangeContents = true;
902        else if (primitiveValue->getValueID() == CSSValueScrollPosition)
903            willChangeScrollPosition = true;
904        else
905            ASSERT_NOT_REACHED();
906    }
907    state.style()->setWillChangeContents(willChangeContents);
908    state.style()->setWillChangeScrollPosition(willChangeScrollPosition);
909    state.style()->setWillChangeProperties(willChangeProperties);
910    state.style()->setSubtreeWillChangeContents(willChangeContents || state.parentStyle()->subtreeWillChangeContents());
911}
912
913void StyleBuilderFunctions::applyInitialCSSPropertyContent(StyleResolverState& state)
914{
915    state.style()->clearContent();
916}
917
918void StyleBuilderFunctions::applyInheritCSSPropertyContent(StyleResolverState&)
919{
920    // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
921    // note is a reminder that eventually "inherit" needs to be supported.
922}
923
924void StyleBuilderFunctions::applyValueCSSPropertyContent(StyleResolverState& state, CSSValue* value)
925{
926    // list of string, uri, counter, attr, i
927
928    if (!value->isValueList())
929        return;
930
931    bool didSet = false;
932    for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
933        CSSValue* item = i.value();
934        if (item->isImageGeneratorValue()) {
935            if (item->isGradientValue())
936                state.style()->setContent(StyleGeneratedImage::create(toCSSGradientValue(item)->gradientWithStylesResolved(state.document().textLinkColors(), state.style()->color()).get()), didSet);
937            else
938                state.style()->setContent(StyleGeneratedImage::create(toCSSImageGeneratorValue(item)), didSet);
939            didSet = true;
940        } else if (item->isImageSetValue()) {
941            state.style()->setContent(state.elementStyleResources().setOrPendingFromValue(CSSPropertyContent, toCSSImageSetValue(item)), didSet);
942            didSet = true;
943        }
944
945        if (item->isImageValue()) {
946            state.style()->setContent(state.elementStyleResources().cachedOrPendingFromValue(state.document(), CSSPropertyContent, toCSSImageValue(item)), didSet);
947            didSet = true;
948            continue;
949        }
950
951        if (!item->isPrimitiveValue())
952            continue;
953
954        CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item);
955
956        if (contentValue->isString()) {
957            state.style()->setContent(contentValue->getStringValue().impl(), didSet);
958            didSet = true;
959        } else if (contentValue->isAttr()) {
960            // FIXME: Can a namespace be specified for an attr(foo)?
961            if (state.style()->styleType() == NOPSEUDO)
962                state.style()->setUnique();
963            else
964                state.parentStyle()->setUnique();
965            QualifiedName attr(nullAtom, AtomicString(contentValue->getStringValue()), nullAtom);
966            const AtomicString& value = state.element()->getAttribute(attr);
967            state.style()->setContent(value.isNull() ? emptyString() : value.string(), didSet);
968            didSet = true;
969            // register the fact that the attribute value affects the style
970            state.contentAttrValues().append(attr.localName());
971        } else if (contentValue->isCounter()) {
972            Counter* counterValue = contentValue->getCounterValue();
973            EListStyleType listStyleType = NoneListStyle;
974            CSSValueID listStyleIdent = counterValue->listStyleIdent();
975            if (listStyleIdent != CSSValueNone)
976                listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc);
977            OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(AtomicString(counterValue->identifier()), listStyleType, AtomicString(counterValue->separator())));
978            state.style()->setContent(counter.release(), didSet);
979            didSet = true;
980        } else {
981            switch (contentValue->getValueID()) {
982            case CSSValueOpenQuote:
983                state.style()->setContent(OPEN_QUOTE, didSet);
984                didSet = true;
985                break;
986            case CSSValueCloseQuote:
987                state.style()->setContent(CLOSE_QUOTE, didSet);
988                didSet = true;
989                break;
990            case CSSValueNoOpenQuote:
991                state.style()->setContent(NO_OPEN_QUOTE, didSet);
992                didSet = true;
993                break;
994            case CSSValueNoCloseQuote:
995                state.style()->setContent(NO_CLOSE_QUOTE, didSet);
996                didSet = true;
997                break;
998            default:
999                // normal and none do not have any effect.
1000                { }
1001            }
1002        }
1003    }
1004    if (!didSet)
1005        state.style()->clearContent();
1006}
1007
1008void StyleBuilderFunctions::applyInitialCSSPropertyFont(StyleResolverState&)
1009{
1010    ASSERT_NOT_REACHED();
1011}
1012
1013void StyleBuilderFunctions::applyInheritCSSPropertyFont(StyleResolverState&)
1014{
1015    ASSERT_NOT_REACHED();
1016}
1017
1018void StyleBuilderFunctions::applyValueCSSPropertyFont(StyleResolverState& state, CSSValue* value)
1019{
1020    // Only System Font identifiers should come through this method
1021    // all other values should have been handled when the shorthand
1022    // was expanded by the parser.
1023    // FIXME: System Font identifiers should not hijack this
1024    // short-hand CSSProperty like this (crbug.com/353932)
1025    state.style()->setLineHeight(RenderStyle::initialLineHeight());
1026    state.setLineHeightValue(0);
1027    state.fontBuilder().fromSystemFont(toCSSPrimitiveValue(value)->getValueID(), state.style()->effectiveZoom());
1028}
1029
1030void StyleBuilderFunctions::applyValueCSSPropertyWebkitLocale(StyleResolverState& state, CSSValue* value)
1031{
1032    if (!value->isPrimitiveValue())
1033        return;
1034    const CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1035    if (primitiveValue->getValueID() == CSSValueAuto)
1036        state.style()->setLocale(nullAtom);
1037    else
1038        state.style()->setLocale(AtomicString(primitiveValue->getStringValue()));
1039    state.fontBuilder().setScript(state.style()->locale());
1040}
1041
1042void StyleBuilderFunctions::applyInitialCSSPropertyWebkitAppRegion(StyleResolverState&)
1043{
1044}
1045
1046void StyleBuilderFunctions::applyInheritCSSPropertyWebkitAppRegion(StyleResolverState&)
1047{
1048}
1049
1050void StyleBuilderFunctions::applyValueCSSPropertyWebkitAppRegion(StyleResolverState& state, CSSValue* value)
1051{
1052    if (!value->isPrimitiveValue())
1053        return;
1054    const CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1055    if (!primitiveValue->getValueID())
1056        return;
1057    state.style()->setDraggableRegionMode(primitiveValue->getValueID() == CSSValueDrag ? DraggableRegionDrag : DraggableRegionNoDrag);
1058    state.document().setHasAnnotatedRegions(true);
1059}
1060
1061void StyleBuilderFunctions::applyInitialCSSPropertyWebkitPerspective(StyleResolverState& state)
1062{
1063    applyInitialCSSPropertyPerspective(state);
1064}
1065
1066void StyleBuilderFunctions::applyInheritCSSPropertyWebkitPerspective(StyleResolverState& state)
1067{
1068    applyInheritCSSPropertyPerspective(state);
1069}
1070
1071void StyleBuilderFunctions::applyValueCSSPropertyWebkitPerspective(StyleResolverState& state, CSSValue* value)
1072{
1073    if (!value->isPrimitiveValue())
1074        return;
1075    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1076    if (primitiveValue->isNumber()) {
1077        float perspectiveValue = CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX)->computeLength<float>(state.cssToLengthConversionData());
1078        if (perspectiveValue >= 0.0f)
1079            state.style()->setPerspective(perspectiveValue);
1080    } else {
1081        applyValueCSSPropertyPerspective(state, value);
1082    }
1083}
1084
1085void StyleBuilderFunctions::applyValueCSSPropertyPerspective(StyleResolverState& state, CSSValue* value)
1086{
1087    if (!value->isPrimitiveValue())
1088        return;
1089    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1090    if (primitiveValue->getValueID() == CSSValueNone) {
1091        state.style()->setPerspective(0);
1092        return;
1093    }
1094
1095    if (!primitiveValue->isLength())
1096        return;
1097    float perspectiveValue = primitiveValue->computeLength<float>(state.cssToLengthConversionData());
1098    if (perspectiveValue >= 0.0f)
1099        state.style()->setPerspective(perspectiveValue);
1100}
1101
1102void StyleBuilderFunctions::applyValueCSSPropertyWebkitWritingMode(StyleResolverState& state, CSSValue* value)
1103{
1104    if (value->isPrimitiveValue())
1105        state.setWritingMode(*toCSSPrimitiveValue(value));
1106
1107    // FIXME: It is not ok to modify document state while applying style.
1108    if (state.element() && state.element() == state.document().documentElement())
1109        state.document().setWritingModeSetOnDocumentElement(true);
1110}
1111
1112void StyleBuilderFunctions::applyValueCSSPropertyWebkitTextOrientation(StyleResolverState& state, CSSValue* value)
1113{
1114    if (value->isPrimitiveValue())
1115        state.setTextOrientation(*toCSSPrimitiveValue(value));
1116}
1117
1118void StyleBuilderFunctions::applyInheritCSSPropertyBaselineShift(StyleResolverState& state)
1119{
1120    const SVGRenderStyle& parentSvgStyle = state.parentStyle()->svgStyle();
1121    EBaselineShift baselineShift = parentSvgStyle.baselineShift();
1122    SVGRenderStyle& svgStyle = state.style()->accessSVGStyle();
1123    svgStyle.setBaselineShift(baselineShift);
1124    if (baselineShift == BS_LENGTH)
1125        svgStyle.setBaselineShiftValue(parentSvgStyle.baselineShiftValue());
1126}
1127
1128void StyleBuilderFunctions::applyValueCSSPropertyBaselineShift(StyleResolverState& state, CSSValue* value)
1129{
1130    SVGRenderStyle& svgStyle = state.style()->accessSVGStyle();
1131    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
1132    if (!primitiveValue->isValueID()) {
1133        svgStyle.setBaselineShift(BS_LENGTH);
1134        svgStyle.setBaselineShiftValue(SVGLength::fromCSSPrimitiveValue(primitiveValue));
1135        return;
1136    }
1137    switch (primitiveValue->getValueID()) {
1138    case CSSValueBaseline:
1139        svgStyle.setBaselineShift(BS_BASELINE);
1140        return;
1141    case CSSValueSub:
1142        svgStyle.setBaselineShift(BS_SUB);
1143        return;
1144    case CSSValueSuper:
1145        svgStyle.setBaselineShift(BS_SUPER);
1146        return;
1147    default:
1148        ASSERT_NOT_REACHED();
1149    }
1150}
1151
1152void StyleBuilderFunctions::applyValueCSSPropertyGridAutoFlow(StyleResolverState& state, CSSValue* value)
1153{
1154    ASSERT(value->isValueList());
1155    CSSValueList* list = toCSSValueList(value);
1156
1157    CSSPrimitiveValue* first = list->length() >= 1 ? toCSSPrimitiveValue(list->item(0)) : nullptr;
1158
1159    if (!first) {
1160        applyInitialCSSPropertyGridAutoFlow(state);
1161        return;
1162    }
1163
1164    CSSPrimitiveValue* second = list->length() == 2 ? toCSSPrimitiveValue(list->item(1)) : nullptr;
1165
1166    GridAutoFlow autoFlow = RenderStyle::initialGridAutoFlow();
1167    switch (first->getValueID()) {
1168    case CSSValueRow:
1169        if (second) {
1170            if (second->getValueID() == CSSValueDense)
1171                autoFlow = AutoFlowRowDense;
1172            else
1173                autoFlow = AutoFlowStackRow;
1174        } else {
1175            autoFlow = AutoFlowRow;
1176        }
1177        break;
1178    case CSSValueColumn:
1179        if (second) {
1180            if (second->getValueID() == CSSValueDense)
1181                autoFlow = AutoFlowColumnDense;
1182            else
1183                autoFlow = AutoFlowStackColumn;
1184        } else {
1185            autoFlow = AutoFlowColumn;
1186        }
1187        break;
1188    case CSSValueDense:
1189        if (second && second->getValueID() == CSSValueColumn)
1190            autoFlow = AutoFlowColumnDense;
1191        else
1192            autoFlow = AutoFlowRowDense;
1193        break;
1194    case CSSValueStack:
1195        if (second && second->getValueID() == CSSValueColumn)
1196            autoFlow = AutoFlowStackColumn;
1197        else
1198            autoFlow = AutoFlowStackRow;
1199        break;
1200    default:
1201        ASSERT_NOT_REACHED();
1202        break;
1203    }
1204
1205    state.style()->setGridAutoFlow(autoFlow);
1206}
1207
1208} // namespace blink
1209