/*
 * Copyright (C) 2007 Alexey Proskuryakov <ap@nypop.com>.
 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 * Copyright (C) 2009 Jeff Schiller <codedread@gmail.com>
 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "CSSCalculationValue.h"
#include "CSSFontFamily.h"
#include "CSSPrimitiveValue.h"
#include "CSSReflectionDirection.h"
#include "CSSToLengthConversionData.h"
#include "ColorSpace.h"
#include "CSSValueKeywords.h"
#include "FontDescription.h"
#include "GraphicsTypes.h"
#include "ImageOrientation.h"
#include "Length.h"
#include "LineClampValue.h"
#include "Path.h"
#include "RenderStyleConstants.h"
#include "SVGRenderStyleDefs.h"
#include "TextDirection.h"
#include "TextFlags.h"
#include "TextRenderingMode.h"
#include "ThemeTypes.h"
#include "UnicodeBidi.h"
#include "WritingMode.h"
#include <wtf/MathExtras.h>

namespace WebCore {

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(short i)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_NUMBER);
    m_value.num = static_cast<double>(i);
}

template<> inline CSSPrimitiveValue::operator short() const
{
    if (primitiveUnitType() == CSSUnitType::CSS_NUMBER)
        return clampTo<short>(m_value.num);

    ASSERT_NOT_REACHED();
    return 0;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(unsigned short i)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_NUMBER);
    m_value.num = static_cast<double>(i);
}

template<> inline CSSPrimitiveValue::operator unsigned short() const
{
    if (primitiveType() == CSSUnitType::CSS_NUMBER)
        return getValue<unsigned short>();

    ASSERT_NOT_REACHED();
    return 0;
}

template<> inline CSSPrimitiveValue::operator int() const
{
    if (primitiveType() == CSSUnitType::CSS_NUMBER)
        return getValue<int>();

    ASSERT_NOT_REACHED();
    return 0;
}

template<> inline CSSPrimitiveValue::operator unsigned() const
{
    if (primitiveType() == CSSUnitType::CSS_NUMBER)
        return getValue<unsigned>();

    ASSERT_NOT_REACHED();
    return 0;
}


template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(float i)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_NUMBER);
    m_value.num = static_cast<double>(i);
}

template<> inline CSSPrimitiveValue::operator float() const
{
    if (primitiveType() == CSSUnitType::CSS_NUMBER)
        return getValue<float>();

    ASSERT_NOT_REACHED();
    return 0.0f;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(LineClampValue i)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(i.isPercentage() ? CSSUnitType::CSS_PERCENTAGE : CSSUnitType::CSS_NUMBER);
    m_value.num = static_cast<double>(i.value());
}

template<> inline CSSPrimitiveValue::operator LineClampValue() const
{
    if (primitiveUnitType() == CSSUnitType::CSS_NUMBER)
        return LineClampValue(clampTo<int>(m_value.num), LineClampLineCount);

    if (primitiveUnitType() == CSSUnitType::CSS_PERCENTAGE)
        return LineClampValue(clampTo<int>(m_value.num), LineClampPercentage);

    ASSERT_NOT_REACHED();
    return LineClampValue();
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CSSReflectionDirection e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case ReflectionAbove:
        m_value.valueID = CSSValueAbove;
        break;
    case ReflectionBelow:
        m_value.valueID = CSSValueBelow;
        break;
    case ReflectionLeft:
        m_value.valueID = CSSValueLeft;
        break;
    case ReflectionRight:
        m_value.valueID = CSSValueRight;
    }
}

template<> inline CSSPrimitiveValue::operator CSSReflectionDirection() const
{
    switch (m_value.valueID) {
    case CSSValueAbove:
        return ReflectionAbove;
    case CSSValueBelow:
        return ReflectionBelow;
    case CSSValueLeft:
        return ReflectionLeft;
    case CSSValueRight:
        return ReflectionRight;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return ReflectionBelow;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ColumnFill columnFill)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (columnFill) {
    case ColumnFillAuto:
        m_value.valueID = CSSValueAuto;
        break;
    case ColumnFillBalance:
        m_value.valueID = CSSValueBalance;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ColumnFill() const
{
    if (primitiveUnitType() == CSSUnitType::CSS_VALUE_ID) {
        if (m_value.valueID == CSSValueBalance)
            return ColumnFillBalance;
        if (m_value.valueID == CSSValueAuto)
            return ColumnFillAuto;
    }
    ASSERT_NOT_REACHED();
    return ColumnFillBalance;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(ColumnSpan columnSpan)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (columnSpan) {
    case ColumnSpanAll:
        m_value.valueID = CSSValueAll;
        break;
    case ColumnSpanNone:
        m_value.valueID = CSSValueNone;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ColumnSpan() const
{
    // Map 1 to none for compatibility reasons.
    if (primitiveUnitType() == CSSUnitType::CSS_NUMBER && m_value.num == 1)
        return ColumnSpanNone;

    switch (m_value.valueID) {
    case CSSValueAll:
        return ColumnSpanAll;
    case CSSValueNone:
        return ColumnSpanNone;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return ColumnSpanNone;
}


template<> inline CSSPrimitiveValue::CSSPrimitiveValue(PrintColorAdjust value)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (value) {
    case PrintColorAdjustExact:
        m_value.valueID = CSSValueExact;
        break;
    case PrintColorAdjustEconomy:
        m_value.valueID = CSSValueEconomy;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator PrintColorAdjust() const
{
    switch (m_value.valueID) {
    case CSSValueEconomy:
        return PrintColorAdjustEconomy;
    case CSSValueExact:
        return PrintColorAdjustExact;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return PrintColorAdjustEconomy;
}


template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EBorderStyle e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case BNONE:
            m_value.valueID = CSSValueNone;
            break;
        case BHIDDEN:
            m_value.valueID = CSSValueHidden;
            break;
        case INSET:
            m_value.valueID = CSSValueInset;
            break;
        case GROOVE:
            m_value.valueID = CSSValueGroove;
            break;
        case RIDGE:
            m_value.valueID = CSSValueRidge;
            break;
        case OUTSET:
            m_value.valueID = CSSValueOutset;
            break;
        case DOTTED:
            m_value.valueID = CSSValueDotted;
            break;
        case DASHED:
            m_value.valueID = CSSValueDashed;
            break;
        case SOLID:
            m_value.valueID = CSSValueSolid;
            break;
        case DOUBLE:
            m_value.valueID = CSSValueDouble;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EBorderStyle() const
{
    if (m_value.valueID == CSSValueAuto) // Valid for CSS outline-style
        return DOTTED;
    return (EBorderStyle)(m_value.valueID - CSSValueNone);
}

template<> inline CSSPrimitiveValue::operator OutlineIsAuto() const
{
    if (m_value.valueID == CSSValueAuto)
        return AUTO_ON;
    return AUTO_OFF;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CompositeOperator e, CSSPropertyID propertyID)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    if (propertyID == CSSPropertyMaskComposite) {
        switch (e) {
        case CompositeSourceOver:
            m_value.valueID = CSSValueAdd;
            break;
        case CompositeSourceIn:
            m_value.valueID = CSSValueIntersect;
            break;
        case CompositeSourceOut:
            m_value.valueID = CSSValueSubtract;
            break;
        case CompositeXOR:
            m_value.valueID = CSSValueExclude;
            break;
        default:
            ASSERT_NOT_REACHED();
            break;
        }
        return;
    }
    switch (e) {
        case CompositeClear:
            m_value.valueID = CSSValueClear;
            break;
        case CompositeCopy:
            m_value.valueID = CSSValueCopy;
            break;
        case CompositeSourceOver:
            m_value.valueID = CSSValueSourceOver;
            break;
        case CompositeSourceIn:
            m_value.valueID = CSSValueSourceIn;
            break;
        case CompositeSourceOut:
            m_value.valueID = CSSValueSourceOut;
            break;
        case CompositeSourceAtop:
            m_value.valueID = CSSValueSourceAtop;
            break;
        case CompositeDestinationOver:
            m_value.valueID = CSSValueDestinationOver;
            break;
        case CompositeDestinationIn:
            m_value.valueID = CSSValueDestinationIn;
            break;
        case CompositeDestinationOut:
            m_value.valueID = CSSValueDestinationOut;
            break;
        case CompositeDestinationAtop:
            m_value.valueID = CSSValueDestinationAtop;
            break;
        case CompositeXOR:
            m_value.valueID = CSSValueXor;
            break;
        case CompositePlusDarker:
            m_value.valueID = CSSValuePlusDarker;
            break;
        case CompositePlusLighter:
            m_value.valueID = CSSValuePlusLighter;
            break;
        case CompositeDifference:
            ASSERT_NOT_REACHED();
            break;
    }
}

template<> inline CSSPrimitiveValue::operator CompositeOperator() const
{
    switch (m_value.valueID) {
        case CSSValueClear:
            return CompositeClear;
        case CSSValueCopy:
            return CompositeCopy;
        case CSSValueSourceOver:
        case CSSValueAdd:
            return CompositeSourceOver;
        case CSSValueSourceIn:
        case CSSValueIntersect:
            return CompositeSourceIn;
        case CSSValueSourceOut:
        case CSSValueSubtract:
            return CompositeSourceOut;
        case CSSValueSourceAtop:
            return CompositeSourceAtop;
        case CSSValueDestinationOver:
            return CompositeDestinationOver;
        case CSSValueDestinationIn:
            return CompositeDestinationIn;
        case CSSValueDestinationOut:
            return CompositeDestinationOut;
        case CSSValueDestinationAtop:
            return CompositeDestinationAtop;
        case CSSValueXor:
        case CSSValueExclude:
            return CompositeXOR;
        case CSSValuePlusDarker:
            return CompositePlusDarker;
        case CSSValuePlusLighter:
            return CompositePlusLighter;
        default:
            ASSERT_NOT_REACHED();
            return CompositeClear;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ControlPart e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case NoControlPart:
            m_value.valueID = CSSValueNone;
            break;
        case AutoPart:
            m_value.valueID = CSSValueAuto;
            break;
        case CheckboxPart:
            m_value.valueID = CSSValueCheckbox;
            break;
        case RadioPart:
            m_value.valueID = CSSValueRadio;
            break;
        case PushButtonPart:
            m_value.valueID = CSSValuePushButton;
            break;
        case SquareButtonPart:
            m_value.valueID = CSSValueSquareButton;
            break;
        case ButtonPart:
            m_value.valueID = CSSValueButton;
            break;
        case ButtonBevelPart:
            m_value.valueID = CSSValueButtonBevel;
            break;
        case DefaultButtonPart:
            m_value.valueID = CSSValueDefaultButton;
            break;
        case InnerSpinButtonPart:
            m_value.valueID = CSSValueInnerSpinButton;
            break;
        case ListboxPart:
            m_value.valueID = CSSValueListbox;
            break;
        case ListItemPart:
            m_value.valueID = CSSValueListitem;
            break;
        case MediaEnterFullscreenButtonPart:
            m_value.valueID = CSSValueMediaEnterFullscreenButton;
            break;
        case MediaExitFullscreenButtonPart:
            m_value.valueID = CSSValueMediaExitFullscreenButton;
            break;
        case MediaPlayButtonPart:
            m_value.valueID = CSSValueMediaPlayButton;
            break;
        case MediaMuteButtonPart:
            m_value.valueID = CSSValueMediaMuteButton;
            break;
        case MediaSeekBackButtonPart:
            m_value.valueID = CSSValueMediaSeekBackButton;
            break;
        case MediaSeekForwardButtonPart:
            m_value.valueID = CSSValueMediaSeekForwardButton;
            break;
        case MediaRewindButtonPart:
            m_value.valueID = CSSValueMediaRewindButton;
            break;
        case MediaReturnToRealtimeButtonPart:
            m_value.valueID = CSSValueMediaReturnToRealtimeButton;
            break;
        case MediaToggleClosedCaptionsButtonPart:
            m_value.valueID = CSSValueMediaToggleClosedCaptionsButton;
            break;
        case MediaSliderPart:
            m_value.valueID = CSSValueMediaSlider;
            break;
        case MediaSliderThumbPart:
            m_value.valueID = CSSValueMediaSliderthumb;
            break;
        case MediaVolumeSliderContainerPart:
            m_value.valueID = CSSValueMediaVolumeSliderContainer;
            break;
        case MediaVolumeSliderPart:
            m_value.valueID = CSSValueMediaVolumeSlider;
            break;
        case MediaVolumeSliderMuteButtonPart:
            m_value.valueID = CSSValueMediaVolumeSliderMuteButton;
            break;
        case MediaVolumeSliderThumbPart:
            m_value.valueID = CSSValueMediaVolumeSliderthumb;
            break;
        case MediaControlsBackgroundPart:
            m_value.valueID = CSSValueMediaControlsBackground;
            break;
        case MediaControlsFullscreenBackgroundPart:
            m_value.valueID = CSSValueMediaControlsFullscreenBackground;
            break;
        case MediaFullScreenVolumeSliderPart:
            m_value.valueID = CSSValueMediaFullscreenVolumeSlider;
            break;
        case MediaFullScreenVolumeSliderThumbPart:
            m_value.valueID = CSSValueMediaFullscreenVolumeSliderThumb;
            break;
        case MediaCurrentTimePart:
            m_value.valueID = CSSValueMediaCurrentTimeDisplay;
            break;
        case MediaTimeRemainingPart:
            m_value.valueID = CSSValueMediaTimeRemainingDisplay;
            break;
        case MenulistPart:
            m_value.valueID = CSSValueMenulist;
            break;
        case MenulistButtonPart:
            m_value.valueID = CSSValueMenulistButton;
            break;
        case MenulistTextPart:
            m_value.valueID = CSSValueMenulistText;
            break;
        case MenulistTextFieldPart:
            m_value.valueID = CSSValueMenulistTextfield;
            break;
        case MeterPart:
            m_value.valueID = CSSValueMeter;
            break;
        case RelevancyLevelIndicatorPart:
            m_value.valueID = CSSValueRelevancyLevelIndicator;
            break;
        case ContinuousCapacityLevelIndicatorPart:
            m_value.valueID = CSSValueContinuousCapacityLevelIndicator;
            break;
        case DiscreteCapacityLevelIndicatorPart:
            m_value.valueID = CSSValueDiscreteCapacityLevelIndicator;
            break;
        case RatingLevelIndicatorPart:
            m_value.valueID = CSSValueRatingLevelIndicator;
            break;
        case ProgressBarPart:
#if ENABLE(PROGRESS_ELEMENT)
            m_value.valueID = CSSValueProgressBar;
#endif
            break;
        case ProgressBarValuePart:
#if ENABLE(PROGRESS_ELEMENT)
            m_value.valueID = CSSValueProgressBarValue;
#endif
            break;
        case SliderHorizontalPart:
            m_value.valueID = CSSValueSliderHorizontal;
            break;
        case SliderVerticalPart:
            m_value.valueID = CSSValueSliderVertical;
            break;
        case SliderThumbHorizontalPart:
            m_value.valueID = CSSValueSliderthumbHorizontal;
            break;
        case SliderThumbVerticalPart:
            m_value.valueID = CSSValueSliderthumbVertical;
            break;
        case CaretPart:
            m_value.valueID = CSSValueCaret;
            break;
        case SearchFieldPart:
            m_value.valueID = CSSValueSearchfield;
            break;
        case SearchFieldDecorationPart:
            m_value.valueID = CSSValueSearchfieldDecoration;
            break;
        case SearchFieldResultsDecorationPart:
            m_value.valueID = CSSValueSearchfieldResultsDecoration;
            break;
        case SearchFieldResultsButtonPart:
            m_value.valueID = CSSValueSearchfieldResultsButton;
            break;
        case SearchFieldCancelButtonPart:
            m_value.valueID = CSSValueSearchfieldCancelButton;
            break;
        case TextFieldPart:
            m_value.valueID = CSSValueTextfield;
            break;
        case TextAreaPart:
            m_value.valueID = CSSValueTextarea;
            break;
        case CapsLockIndicatorPart:
            m_value.valueID = CSSValueCapsLockIndicator;
            break;
        case InputSpeechButtonPart:
#if ENABLE(INPUT_SPEECH)
            m_value.valueID = CSSValueWebkitInputSpeechButton;
#endif
            break;
#if ENABLE(DATALIST_ELEMENT)
		case ListButtonPart:
			m_value.valueID = CSSValueListButton;
			break;
#endif
    }
}

template<> inline CSSPrimitiveValue::operator ControlPart() const
{
    if (m_value.valueID == CSSValueNone)
        return NoControlPart;

    if (m_value.valueID == CSSValueAuto)
        return AutoPart;

    return ControlPart(m_value.valueID - CSSValueCheckbox + CheckboxPart);
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBackfaceVisibility e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case BackfaceVisibilityVisible:
        m_value.valueID = CSSValueVisible;
        break;
    case BackfaceVisibilityHidden:
        m_value.valueID = CSSValueHidden;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EBackfaceVisibility() const
{
    switch (m_value.valueID) {
    case CSSValueVisible:
        return BackfaceVisibilityVisible;
    case CSSValueHidden:
        return BackfaceVisibilityHidden;
    default:
        ASSERT_NOT_REACHED();
        return BackfaceVisibilityHidden;
    }
}


template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFillAttachment e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case ScrollBackgroundAttachment:
            m_value.valueID = CSSValueScroll;
            break;
        case LocalBackgroundAttachment:
            m_value.valueID = CSSValueLocal;
            break;
        case FixedBackgroundAttachment:
            m_value.valueID = CSSValueFixed;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EFillAttachment() const
{
    switch (m_value.valueID) {
        case CSSValueScroll:
            return ScrollBackgroundAttachment;
        case CSSValueLocal:
            return LocalBackgroundAttachment;
        case CSSValueFixed:
            return FixedBackgroundAttachment;
        default:
            ASSERT_NOT_REACHED();
            return ScrollBackgroundAttachment;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFillBox e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case BorderFillBox:
            m_value.valueID = CSSValueBorderBox;
            break;
        case PaddingFillBox:
            m_value.valueID = CSSValuePaddingBox;
            break;
        case ContentFillBox:
            m_value.valueID = CSSValueContentBox;
            break;
        case TextFillBox:
            m_value.valueID = CSSValueText;
            break;
        case NoClipFillBox:
            m_value.valueID = CSSValueNoClip;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EFillBox() const
{
    switch (m_value.valueID) {
        case CSSValueBorder:
        case CSSValueBorderBox:
            return BorderFillBox;
        case CSSValuePadding:
        case CSSValuePaddingBox:
            return PaddingFillBox;
        case CSSValueContent:
        case CSSValueContentBox:
            return ContentFillBox;
        case CSSValueText:
        case CSSValueWebkitText:
            return TextFillBox;
        case CSSValueNoClip:
            return NoClipFillBox;
        default:
            ASSERT_NOT_REACHED();
            return BorderFillBox;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFillRepeat e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case RepeatFill:
            m_value.valueID = CSSValueRepeat;
            break;
        case NoRepeatFill:
            m_value.valueID = CSSValueNoRepeat;
            break;
        case RoundFill:
            m_value.valueID = CSSValueRound;
            break;
        case SpaceFill:
            m_value.valueID = CSSValueSpace;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EFillRepeat() const
{
    switch (m_value.valueID) {
        case CSSValueRepeat:
            return RepeatFill;
        case CSSValueNoRepeat:
            return NoRepeatFill;
        case CSSValueRound:
            return RoundFill;
        case CSSValueSpace:
            return SpaceFill;
        default:
            ASSERT_NOT_REACHED();
            return RepeatFill;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxPack e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case Start:
        m_value.valueID = CSSValueStart;
        break;
    case Center:
        m_value.valueID = CSSValueCenter;
        break;
    case End:
        m_value.valueID = CSSValueEnd;
        break;
    case Justify:
        m_value.valueID = CSSValueJustify;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EBoxPack() const
{
    switch (m_value.valueID) {
    case CSSValueStart:
        return Start;
    case CSSValueEnd:
        return End;
    case CSSValueCenter:
        return Center;
    case CSSValueJustify:
        return Justify;
    default:
        ASSERT_NOT_REACHED();
        return Justify;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxAlignment e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case BSTRETCH:
            m_value.valueID = CSSValueStretch;
            break;
        case BSTART:
            m_value.valueID = CSSValueStart;
            break;
        case BCENTER:
            m_value.valueID = CSSValueCenter;
            break;
        case BEND:
            m_value.valueID = CSSValueEnd;
            break;
        case BBASELINE:
            m_value.valueID = CSSValueBaseline;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EBoxAlignment() const
{
    switch (m_value.valueID) {
        case CSSValueStretch:
            return BSTRETCH;
        case CSSValueStart:
            return BSTART;
        case CSSValueEnd:
            return BEND;
        case CSSValueCenter:
            return BCENTER;
        case CSSValueBaseline:
            return BBASELINE;
        default:
            ASSERT_NOT_REACHED();
            return BSTRETCH;
    }
}

#if ENABLE(CSS_BOX_DECORATION_BREAK)
template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxDecorationBreak e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case DSLICE:
        m_value.valueID = CSSValueSlice;
        break;
    case DCLONE:
        m_value.valueID = CSSValueClone;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EBoxDecorationBreak() const
{
    switch (m_value.valueID) {
    case CSSValueSlice:
        return DSLICE;
    case CSSValueClone:
        return DCLONE;
    default:
        ASSERT_NOT_REACHED();
        return DSLICE;
    }
}
#endif

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Edge e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case Edge::Top:
        m_value.valueID = CSSValueTop;
        break;
    case Edge::Right:
        m_value.valueID = CSSValueRight;
        break;
    case Edge::Bottom:
        m_value.valueID = CSSValueBottom;
        break;
    case Edge::Left:
        m_value.valueID = CSSValueLeft;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator Edge() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueTop:
        return Edge::Top;
    case CSSValueRight:
        return Edge::Right;
    case CSSValueBottom:
        return Edge::Bottom;
    case CSSValueLeft:
        return Edge::Left;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return Edge::Top;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxSizing e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case BORDER_BOX:
        m_value.valueID = CSSValueBorderBox;
        break;
    case CONTENT_BOX:
        m_value.valueID = CSSValueContentBox;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EBoxSizing() const
{
    switch (m_value.valueID) {
    case CSSValueBorderBox:
        return BORDER_BOX;
    case CSSValueContentBox:
        return CONTENT_BOX;
    default:
        ASSERT_NOT_REACHED();
        return BORDER_BOX;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxDirection e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case BNORMAL:
            m_value.valueID = CSSValueNormal;
            break;
        case BREVERSE:
            m_value.valueID = CSSValueReverse;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EBoxDirection() const
{
    switch (m_value.valueID) {
        case CSSValueNormal:
            return BNORMAL;
        case CSSValueReverse:
            return BREVERSE;
        default:
            ASSERT_NOT_REACHED();
            return BNORMAL;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxLines e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case SINGLE:
            m_value.valueID = CSSValueSingle;
            break;
        case MULTIPLE:
            m_value.valueID = CSSValueMultiple;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EBoxLines() const
{
    switch (m_value.valueID) {
        case CSSValueSingle:
            return SINGLE;
        case CSSValueMultiple:
            return MULTIPLE;
        default:
            ASSERT_NOT_REACHED();
            return SINGLE;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBoxOrient e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case HORIZONTAL:
            m_value.valueID = CSSValueHorizontal;
            break;
        case VERTICAL:
            m_value.valueID = CSSValueVertical;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EBoxOrient() const
{
    switch (m_value.valueID) {
        case CSSValueHorizontal:
        case CSSValueInlineAxis:
            return HORIZONTAL;
        case CSSValueVertical:
        case CSSValueBlockAxis:
            return VERTICAL;
        default:
            ASSERT_NOT_REACHED();
            return HORIZONTAL;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ECaptionSide e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case CAPLEFT:
            m_value.valueID = CSSValueLeft;
            break;
        case CAPRIGHT:
            m_value.valueID = CSSValueRight;
            break;
        case CAPTOP:
            m_value.valueID = CSSValueTop;
            break;
        case CAPBOTTOM:
            m_value.valueID = CSSValueBottom;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator ECaptionSide() const
{
    switch (m_value.valueID) {
        case CSSValueLeft:
            return CAPLEFT;
        case CSSValueRight:
            return CAPRIGHT;
        case CSSValueTop:
            return CAPTOP;
        case CSSValueBottom:
            return CAPBOTTOM;
        default:
            ASSERT_NOT_REACHED();
            return CAPTOP;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(Clear e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case Clear::None:
            m_value.valueID = CSSValueNone;
            break;
        case Clear::Left:
            m_value.valueID = CSSValueLeft;
            break;
        case Clear::Right:
            m_value.valueID = CSSValueRight;
            break;
        case Clear::InlineStart:
            m_value.valueID = CSSValueInlineStart;
            break;
        case Clear::InlineEnd:
            m_value.valueID = CSSValueInlineEnd;
            break;
        case Clear::Both:
            m_value.valueID = CSSValueBoth;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator Clear() const
{
    switch (m_value.valueID) {
        case CSSValueNone:
            return Clear::None;
        case CSSValueLeft:
            return Clear::Left;
        case CSSValueRight:
            return Clear::Right;
        case CSSValueInlineStart:
            return Clear::InlineStart;
        case CSSValueInlineEnd:
            return Clear::InlineEnd;
        case CSSValueBoth:
            return Clear::Both;
        default:
            ASSERT_NOT_REACHED();
            return Clear::None;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ECursor e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case CURSOR_AUTO:
            m_value.valueID = CSSValueAuto;
            break;
        case CURSOR_DEFAULT:
            m_value.valueID = CSSValueDefault;
            break;
        case CURSOR_NONE:
            m_value.valueID = CSSValueNone;
            break;
        case CURSOR_CONTEXT_MENU:
            m_value.valueID = CSSValueContextMenu;
            break;
        case CURSOR_HELP:
            m_value.valueID = CSSValueHelp;
            break;
        case CURSOR_POINTER:
            m_value.valueID = CSSValuePointer;
            break;
        case CURSOR_PROGRESS:
            m_value.valueID = CSSValueProgress;
            break;
        case CURSOR_WAIT:
            m_value.valueID = CSSValueWait;
            break;
        case CURSOR_CELL:
            m_value.valueID = CSSValueCell;
            break;
        case CURSOR_CROSS:
            m_value.valueID = CSSValueCrosshair;
            break;
        case CURSOR_TEXT:
            m_value.valueID = CSSValueText;
            break;
        case CURSOR_VERTICAL_TEXT:
            m_value.valueID = CSSValueVerticalText;
            break;
        case CURSOR_ALIAS:
            m_value.valueID = CSSValueAlias;
            break;
        case CURSOR_COPY:
            m_value.valueID = CSSValueCopy;
            break;
        case CURSOR_MOVE:
            m_value.valueID = CSSValueMove;
            break;
        case CURSOR_NO_DROP:
            m_value.valueID = CSSValueNoDrop;
            break;
        case CURSOR_NOT_ALLOWED:
            m_value.valueID = CSSValueNotAllowed;
            break;
        case CURSOR_GRAB:
            m_value.valueID = CSSValueGrab;
            break;
        case CURSOR_GRABBING:
            m_value.valueID = CSSValueGrabbing;
            break;
        case CURSOR_E_RESIZE:
            m_value.valueID = CSSValueEResize;
            break;
        case CURSOR_N_RESIZE:
            m_value.valueID = CSSValueNResize;
            break;
        case CURSOR_NE_RESIZE:
            m_value.valueID = CSSValueNeResize;
            break;
        case CURSOR_NW_RESIZE:
            m_value.valueID = CSSValueNwResize;
            break;
        case CURSOR_S_RESIZE:
            m_value.valueID = CSSValueSResize;
            break;
        case CURSOR_SE_RESIZE:
            m_value.valueID = CSSValueSeResize;
            break;
        case CURSOR_SW_RESIZE:
            m_value.valueID = CSSValueSwResize;
            break;
        case CURSOR_W_RESIZE:
            m_value.valueID = CSSValueWResize;
            break;
        case CURSOR_EW_RESIZE:
            m_value.valueID = CSSValueEwResize;
            break;
        case CURSOR_NS_RESIZE:
            m_value.valueID = CSSValueNsResize;
            break;
        case CURSOR_NESW_RESIZE:
            m_value.valueID = CSSValueNeswResize;
            break;
        case CURSOR_NWSE_RESIZE:
            m_value.valueID = CSSValueNwseResize;
            break;
        case CURSOR_COL_RESIZE:
            m_value.valueID = CSSValueColResize;
            break;
        case CURSOR_ROW_RESIZE:
            m_value.valueID = CSSValueRowResize;
            break;
        case CURSOR_ALL_SCROLL:
            m_value.valueID = CSSValueAllScroll;
            break;
        case CURSOR_ZOOM_IN:
            m_value.valueID = CSSValueZoomIn;
            break;
        case CURSOR_ZOOM_OUT:
            m_value.valueID = CSSValueZoomOut;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator ECursor() const
{
    ASSERT(isValueID());
    switch (m_value.valueID) {
    case CSSValueCopy:
        return CURSOR_COPY;
    case CSSValueWebkitGrab:
        return CURSOR_GRAB;
    case CSSValueWebkitGrabbing:
        return CURSOR_GRABBING;
    case CSSValueWebkitZoomIn:
        return CURSOR_ZOOM_IN;
    case CSSValueWebkitZoomOut:
        return CURSOR_ZOOM_OUT;
    case CSSValueNone:
        return CURSOR_NONE;
    default:
        return static_cast<ECursor>(m_value.valueID - CSSValueAuto);
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(DisplayType e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case DisplayType::Inline:
            m_value.valueID = CSSValueInline;
            break;
        case DisplayType::Block:
            m_value.valueID = CSSValueBlock;
            break;
        case DisplayType::ListItem:
            m_value.valueID = CSSValueListItem;
            break;
        case DisplayType::Compact:
            m_value.valueID = CSSValueCompact;
            break;
        case DisplayType::InlineBlock:
            m_value.valueID = CSSValueInlineBlock;
            break;
        case DisplayType::Table:
            m_value.valueID = CSSValueTable;
            break;
        case DisplayType::InlineTable:
            m_value.valueID = CSSValueInlineTable;
            break;
        case DisplayType::TableRowGroup:
            m_value.valueID = CSSValueTableRowGroup;
            break;
        case DisplayType::TableHeaderGroup:
            m_value.valueID = CSSValueTableHeaderGroup;
            break;
        case DisplayType::TableFooterGroup:
            m_value.valueID = CSSValueTableFooterGroup;
            break;
        case DisplayType::TableRow:
            m_value.valueID = CSSValueTableRow;
            break;
        case DisplayType::TableColumnGroup:
            m_value.valueID = CSSValueTableColumnGroup;
            break;
        case DisplayType::TableColumn:
            m_value.valueID = CSSValueTableColumn;
            break;
        case DisplayType::TableCell:
            m_value.valueID = CSSValueTableCell;
            break;
        case DisplayType::TableCaption:
            m_value.valueID = CSSValueTableCaption;
            break;
        case DisplayType::Box:
            m_value.valueID = CSSValueWebkitBox;
            break;
        case DisplayType::InlineBox:
            m_value.valueID = CSSValueWebkitInlineBox;
            break;
        case DisplayType::Flex:
		case DisplayType::WebKitFlex:
			m_value.valueID = CSSValueFlex;
			break;
		case DisplayType::InlineFlex:
		case DisplayType::WebKitInlineFlex:
			m_value.valueID = CSSValueInlineFlex;
			break;
        case DisplayType::Grid:
            m_value.valueID = CSSValueGrid;
            break;
        case DisplayType::InlineGrid:
            m_value.valueID = CSSValueInlineGrid;
            break;
        case DisplayType::None:
            m_value.valueID = CSSValueNone;
            break;
        case DisplayType::Contents:
            m_value.valueID = CSSValueContents;
            break;
        case DisplayType::FlowRoot:
            m_value.valueID = CSSValueFlowRoot;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator DisplayType() const
{
    if (m_value.valueID == CSSValueNone)
        return DisplayType::None;

    DisplayType display = static_cast<DisplayType>(m_value.valueID - CSSValueInline);
    ASSERT(display >= DisplayType::Inline && display <= DisplayType::None);
    if (display == DisplayType::WebKitFlex)
		return DisplayType::Flex;
	if (display == DisplayType::WebKitInlineFlex)
		return DisplayType::InlineFlex;
    return display;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EEmptyCell e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case SHOW:
            m_value.valueID = CSSValueShow;
            break;
        case HIDE:
            m_value.valueID = CSSValueHide;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EEmptyCell() const
{
    switch (m_value.valueID) {
        case CSSValueShow:
            return SHOW;
        case CSSValueHide:
            return HIDE;
        default:
            ASSERT_NOT_REACHED();
            return SHOW;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFlexDirection e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case FlowRow:
        m_value.valueID = CSSValueRow;
        break;
    case FlowRowReverse:
        m_value.valueID = CSSValueRowReverse;
        break;
    case FlowColumn:
        m_value.valueID = CSSValueColumn;
        break;
    case FlowColumnReverse:
        m_value.valueID = CSSValueColumnReverse;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EFlexDirection() const
{
    switch (m_value.valueID) {
    case CSSValueRow:
        return FlowRow;
    case CSSValueRowReverse:
        return FlowRowReverse;
    case CSSValueColumn:
        return FlowColumn;
    case CSSValueColumnReverse:
        return FlowColumnReverse;
    default:
        ASSERT_NOT_REACHED();
        return FlowRow;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EAlignContent e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case AlignContentFlexStart:
        m_value.valueID = CSSValueFlexStart;
        break;
    case AlignContentFlexEnd:
        m_value.valueID = CSSValueFlexEnd;
        break;
    case AlignContentCenter:
        m_value.valueID = CSSValueCenter;
        break;
    case AlignContentSpaceBetween:
        m_value.valueID = CSSValueSpaceBetween;
        break;
    case AlignContentSpaceAround:
        m_value.valueID = CSSValueSpaceAround;
        break;
    case AlignContentStretch:
        m_value.valueID = CSSValueStretch;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EAlignContent() const
{
    switch (m_value.valueID) {
    case CSSValueFlexStart:
        return AlignContentFlexStart;
    case CSSValueFlexEnd:
        return AlignContentFlexEnd;
    case CSSValueCenter:
        return AlignContentCenter;
    case CSSValueSpaceBetween:
        return AlignContentSpaceBetween;
    case CSSValueSpaceAround:
        return AlignContentSpaceAround;
    case CSSValueStretch:
        return AlignContentStretch;
    default:
        ASSERT_NOT_REACHED();
        return AlignContentStretch;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EFlexWrap e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case FlexWrapNone:
        m_value.valueID = CSSValueNone;
        break;
    case FlexWrap:
        m_value.valueID = CSSValueWrap;
        break;
    case FlexWrapReverse:
        m_value.valueID = CSSValueWrapReverse;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EFlexWrap() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return FlexWrapNone;
    case CSSValueWrap:
        return FlexWrap;
    case CSSValueWrapReverse:
        return FlexWrapReverse;
    default:
        ASSERT_NOT_REACHED();
        return FlexWrapNone;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(Float e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case Float::None:
            m_value.valueID = CSSValueNone;
            break;
        case Float::Left:
            m_value.valueID = CSSValueLeft;
            break;
        case Float::Right:
            m_value.valueID = CSSValueRight;
            break;
        case Float::InlineStart:
            m_value.valueID = CSSValueInlineStart;
            break;
        case Float::InlineEnd:
            m_value.valueID = CSSValueInlineEnd;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator Float() const
{
    switch (m_value.valueID) {
        case CSSValueLeft:
            return Float::Left;
        case CSSValueRight:
            return Float::Right;
        case CSSValueInlineStart:
            return Float::InlineStart;
        case CSSValueInlineEnd:
            return Float::InlineEnd;
        case CSSValueNone:
        case CSSValueCenter:  // Non-standard CSS value
            return Float::None;
        default:
            ASSERT_NOT_REACHED();
            return Float::None;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineBreak e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case LineBreak::Auto:
        m_value.valueID = CSSValueAuto;
        break;
    case LineBreak::Loose:
        m_value.valueID = CSSValueLoose;
        break;
    case LineBreak::Normal:
        m_value.valueID = CSSValueNormal;
        break;
    case LineBreak::Strict:
        m_value.valueID = CSSValueStrict;
        break;
    case LineBreak::AfterWhiteSpace:
        m_value.valueID = CSSValueAfterWhiteSpace;
        break;
    case LineBreak::Anywhere:
        m_value.valueID = CSSValueAnywhere;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator HangingPunctuation() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueNone:
        return NoHangingPunctuation;
    case CSSValueFirst:
        return FirstHangingPunctuation;
    case CSSValueLast:
        return LastHangingPunctuation;
    case CSSValueAllowEnd:
        return AllowEndHangingPunctuation;
    case CSSValueForceEnd:
        return ForceEndHangingPunctuation;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return NoHangingPunctuation;
}

template<> inline CSSPrimitiveValue::operator LineBreak() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueAuto:
        return LineBreak::Auto;
    case CSSValueLoose:
        return LineBreak::Loose;
    case CSSValueNormal:
        return LineBreak::Normal;
    case CSSValueStrict:
        return LineBreak::Strict;
    case CSSValueAfterWhiteSpace:
        return LineBreak::AfterWhiteSpace;
    case CSSValueAnywhere:
        return LineBreak::Anywhere;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return LineBreak::Auto;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EListStylePosition e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case OUTSIDE:
            m_value.valueID = CSSValueOutside;
            break;
        case INSIDE:
            m_value.valueID = CSSValueInside;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EListStylePosition() const
{
    switch (m_value.valueID) {
    case CSSValueOutside:
        return OUTSIDE;
    case CSSValueInside:
        return INSIDE;
    default:
        ASSERT_NOT_REACHED();
        return OUTSIDE;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EListStyleType e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case Afar:
        m_value.valueID = CSSValueAfar;
        break;
    case Amharic:
        m_value.valueID = CSSValueAmharic;
        break;
    case AmharicAbegede:
        m_value.valueID = CSSValueAmharicAbegede;
        break;
    case ArabicIndic:
        m_value.valueID = CSSValueArabicIndic;
        break;
    case Armenian:
        m_value.valueID = CSSValueArmenian;
        break;
    case Asterisks:
        m_value.valueID = CSSValueAsterisks;
        break;
    case BinaryListStyle:
        m_value.valueID = CSSValueBinary;
        break;
    case Bengali:
        m_value.valueID = CSSValueBengali;
        break;
    case Cambodian:
        m_value.valueID = CSSValueCambodian;
        break;
    case Circle:
        m_value.valueID = CSSValueCircle;
        break;
    case CjkEarthlyBranch:
        m_value.valueID = CSSValueCjkEarthlyBranch;
        break;
    case CjkHeavenlyStem:
        m_value.valueID = CSSValueCjkHeavenlyStem;
        break;
    case CJKIdeographic:
        m_value.valueID = CSSValueCjkIdeographic;
        break;
    case DecimalLeadingZero:
        m_value.valueID = CSSValueDecimalLeadingZero;
        break;
    case DecimalListStyle:
        m_value.valueID = CSSValueDecimal;
        break;
    case Devanagari:
        m_value.valueID = CSSValueDevanagari;
        break;
    case Disc:
        m_value.valueID = CSSValueDisc;
        break;
    case Ethiopic:
        m_value.valueID = CSSValueEthiopic;
        break;
    case EthiopicAbegede:
        m_value.valueID = CSSValueEthiopicAbegede;
        break;
    case EthiopicAbegedeAmEt:
        m_value.valueID = CSSValueEthiopicAbegedeAmEt;
        break;
    case EthiopicAbegedeGez:
        m_value.valueID = CSSValueEthiopicAbegedeGez;
        break;
    case EthiopicAbegedeTiEr:
        m_value.valueID = CSSValueEthiopicAbegedeTiEr;
        break;
    case EthiopicAbegedeTiEt:
        m_value.valueID = CSSValueEthiopicAbegedeTiEt;
        break;
    case EthiopicHalehameAaEr:
        m_value.valueID = CSSValueEthiopicHalehameAaEr;
        break;
    case EthiopicHalehameAaEt:
        m_value.valueID = CSSValueEthiopicHalehameAaEt;
        break;
    case EthiopicHalehameAmEt:
        m_value.valueID = CSSValueEthiopicHalehameAmEt;
        break;
    case EthiopicHalehameGez:
        m_value.valueID = CSSValueEthiopicHalehameGez;
        break;
    case EthiopicHalehameOmEt:
        m_value.valueID = CSSValueEthiopicHalehameOmEt;
        break;
    case EthiopicHalehameSidEt:
        m_value.valueID = CSSValueEthiopicHalehameSidEt;
        break;
    case EthiopicHalehameSoEt:
        m_value.valueID = CSSValueEthiopicHalehameSoEt;
        break;
    case EthiopicHalehameTiEr:
        m_value.valueID = CSSValueEthiopicHalehameTiEr;
        break;
    case EthiopicHalehameTiEt:
        m_value.valueID = CSSValueEthiopicHalehameTiEt;
        break;
    case EthiopicHalehameTig:
        m_value.valueID = CSSValueEthiopicHalehameTig;
        break;
    case Footnotes:
        m_value.valueID = CSSValueFootnotes;
        break;
    case Georgian:
        m_value.valueID = CSSValueGeorgian;
        break;
    case Gujarati:
        m_value.valueID = CSSValueGujarati;
        break;
    case Gurmukhi:
        m_value.valueID = CSSValueGurmukhi;
        break;
    case Hangul:
        m_value.valueID = CSSValueHangul;
        break;
    case HangulConsonant:
        m_value.valueID = CSSValueHangulConsonant;
        break;
    case Hebrew:
        m_value.valueID = CSSValueHebrew;
        break;
    case Hiragana:
        m_value.valueID = CSSValueHiragana;
        break;
    case HiraganaIroha:
        m_value.valueID = CSSValueHiraganaIroha;
        break;
    case Kannada:
        m_value.valueID = CSSValueKannada;
        break;
    case Katakana:
        m_value.valueID = CSSValueKatakana;
        break;
    case KatakanaIroha:
        m_value.valueID = CSSValueKatakanaIroha;
        break;
    case Khmer:
        m_value.valueID = CSSValueKhmer;
        break;
    case Lao:
        m_value.valueID = CSSValueLao;
        break;
    case LowerAlpha:
        m_value.valueID = CSSValueLowerAlpha;
        break;
    case LowerArmenian:
        m_value.valueID = CSSValueLowerArmenian;
        break;
    case LowerGreek:
        m_value.valueID = CSSValueLowerGreek;
        break;
    case LowerHexadecimal:
        m_value.valueID = CSSValueLowerHexadecimal;
        break;
    case LowerLatin:
        m_value.valueID = CSSValueLowerLatin;
        break;
    case LowerNorwegian:
        m_value.valueID = CSSValueLowerNorwegian;
        break;
    case LowerRoman:
        m_value.valueID = CSSValueLowerRoman;
        break;
    case Malayalam:
        m_value.valueID = CSSValueMalayalam;
        break;
    case Mongolian:
        m_value.valueID = CSSValueMongolian;
        break;
    case Myanmar:
        m_value.valueID = CSSValueMyanmar;
        break;
    case NoneListStyle:
        m_value.valueID = CSSValueNone;
        break;
    case Octal:
        m_value.valueID = CSSValueOctal;
        break;
    case Oriya:
        m_value.valueID = CSSValueOriya;
        break;
    case Oromo:
        m_value.valueID = CSSValueOromo;
        break;
    case Persian:
        m_value.valueID = CSSValuePersian;
        break;
    case Sidama:
        m_value.valueID = CSSValueSidama;
        break;
    case Somali:
        m_value.valueID = CSSValueSomali;
        break;
    case Square:
        m_value.valueID = CSSValueSquare;
        break;
    case Telugu:
        m_value.valueID = CSSValueTelugu;
        break;
    case Thai:
        m_value.valueID = CSSValueThai;
        break;
    case Tibetan:
        m_value.valueID = CSSValueTibetan;
        break;
    case Tigre:
        m_value.valueID = CSSValueTigre;
        break;
    case TigrinyaEr:
        m_value.valueID = CSSValueTigrinyaEr;
        break;
    case TigrinyaErAbegede:
        m_value.valueID = CSSValueTigrinyaErAbegede;
        break;
    case TigrinyaEt:
        m_value.valueID = CSSValueTigrinyaEt;
        break;
    case TigrinyaEtAbegede:
        m_value.valueID = CSSValueTigrinyaEtAbegede;
        break;
    case UpperAlpha:
        m_value.valueID = CSSValueUpperAlpha;
        break;
    case UpperArmenian:
        m_value.valueID = CSSValueUpperArmenian;
        break;
    case UpperGreek:
        m_value.valueID = CSSValueUpperGreek;
        break;
    case UpperHexadecimal:
        m_value.valueID = CSSValueUpperHexadecimal;
        break;
    case UpperLatin:
        m_value.valueID = CSSValueUpperLatin;
        break;
    case UpperNorwegian:
        m_value.valueID = CSSValueUpperNorwegian;
        break;
    case UpperRoman:
        m_value.valueID = CSSValueUpperRoman;
        break;
    case Urdu:
        m_value.valueID = CSSValueUrdu;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EListStyleType() const
{
    switch (m_value.valueID) {
        case CSSValueNone:
            return NoneListStyle;
        default:
            return static_cast<EListStyleType>(m_value.valueID - CSSValueDisc);
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(MarqueeBehavior e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case MarqueeBehavior::None:
        m_value.valueID = CSSValueNone;
        break;
    case MarqueeBehavior::Scroll:
        m_value.valueID = CSSValueScroll;
        break;
    case MarqueeBehavior::Slide:
        m_value.valueID = CSSValueSlide;
        break;
    case MarqueeBehavior::Alternate:
        m_value.valueID = CSSValueAlternate;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator MarqueeBehavior() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueNone:
        return MarqueeBehavior::None;
    case CSSValueScroll:
        return MarqueeBehavior::Scroll;
    case CSSValueSlide:
        return MarqueeBehavior::Slide;
    case CSSValueAlternate:
        return MarqueeBehavior::Alternate;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return MarqueeBehavior::None;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(MarqueeDirection direction)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (direction) {
    case MarqueeDirection::Forward:
        m_value.valueID = CSSValueForwards;
        break;
    case MarqueeDirection::Backward:
        m_value.valueID = CSSValueBackwards;
        break;
    case MarqueeDirection::Auto:
        m_value.valueID = CSSValueAuto;
        break;
    case MarqueeDirection::Up:
        m_value.valueID = CSSValueUp;
        break;
    case MarqueeDirection::Down:
        m_value.valueID = CSSValueDown;
        break;
    case MarqueeDirection::Left:
        m_value.valueID = CSSValueLeft;
        break;
    case MarqueeDirection::Right:
        m_value.valueID = CSSValueRight;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator MarqueeDirection() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueForwards:
        return MarqueeDirection::Forward;
    case CSSValueBackwards:
        return MarqueeDirection::Backward;
    case CSSValueAuto:
        return MarqueeDirection::Auto;
    case CSSValueAhead:
    case CSSValueUp: // We don't support vertical languages, so AHEAD just maps to UP.
        return MarqueeDirection::Up;
    case CSSValueReverse:
    case CSSValueDown: // REVERSE just maps to DOWN, since we don't do vertical text.
        return MarqueeDirection::Down;
    case CSSValueLeft:
        return MarqueeDirection::Left;
    case CSSValueRight:
        return MarqueeDirection::Right;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return MarqueeDirection::Auto;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ENBSPMode e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case NBNORMAL:
            m_value.valueID = CSSValueNormal;
            break;
        case SPACE:
            m_value.valueID = CSSValueSpace;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator ENBSPMode() const
{
    switch (m_value.valueID) {
        case CSSValueSpace:
            return SPACE;
        case CSSValueNormal:
            return NBNORMAL;
        default:
            ASSERT_NOT_REACHED();
            return NBNORMAL;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(Overflow e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case Overflow::Visible:
            m_value.valueID = CSSValueVisible;
            break;
        case Overflow::Hidden:
            m_value.valueID = CSSValueHidden;
            break;
        case Overflow::Scroll:
            m_value.valueID = CSSValueScroll;
            break;
        case Overflow::Auto:
            m_value.valueID = CSSValueAuto;
            break;
        case Overflow::PagedX:
            m_value.valueID = CSSValueWebkitPagedX;
            break;
        case Overflow::PagedY:
            m_value.valueID = CSSValueWebkitPagedY;
            break;
        case Overflow::Clip:
            m_value.valueID = CSSValueClip;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator Overflow() const
{
    switch (m_value.valueID) {
        case CSSValueVisible:
            return Overflow::Visible;
        case CSSValueHidden:
            return Overflow::Hidden;
        case CSSValueScroll:
            return Overflow::Scroll;
        case CSSValueOverlay:
        case CSSValueAuto:
            return Overflow::Auto;
        case CSSValueWebkitPagedX:
            return Overflow::PagedX;
        case CSSValueWebkitPagedY:
            return Overflow::PagedY;
        case CSSValueClip:
            return Overflow::Clip;
        default:
            ASSERT_NOT_REACHED();
            return Overflow::Visible;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(BreakBetween e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case AutoBreakBetween:
        m_value.valueID = CSSValueAuto;
        break;
    case AvoidBreakBetween:
        m_value.valueID = CSSValueAvoid;
        break;
    case AvoidColumnBreakBetween:
        m_value.valueID = CSSValueAvoidColumn;
        break;
    case AvoidPageBreakBetween:
        m_value.valueID = CSSValueAvoidPage;
        break;
    case ColumnBreakBetween:
        m_value.valueID = CSSValueColumn;
        break;
    case PageBreakBetween:
        m_value.valueID = CSSValuePage;
        break;
    case LeftPageBreakBetween:
        m_value.valueID = CSSValueLeft;
        break;
    case RightPageBreakBetween:
        m_value.valueID = CSSValueRight;
        break;
    case RectoPageBreakBetween:
        m_value.valueID = CSSValueRecto;
        break;
    case VersoPageBreakBetween:
        m_value.valueID = CSSValueVerso;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator BreakBetween() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueAuto:
        return AutoBreakBetween;
    case CSSValueAvoid:
        return AvoidBreakBetween;
    case CSSValueAvoidColumn:
        return AvoidColumnBreakBetween;
    case CSSValueAvoidPage:
        return AvoidPageBreakBetween;
    case CSSValueColumn:
        return ColumnBreakBetween;
    case CSSValuePage:
        return PageBreakBetween;
    case CSSValueLeft:
        return LeftPageBreakBetween;
    case CSSValueRight:
        return RightPageBreakBetween;
    case CSSValueRecto:
        return RectoPageBreakBetween;
    case CSSValueVerso:
        return VersoPageBreakBetween;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return AutoBreakBetween;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(BreakInside e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case AutoBreakInside:
        m_value.valueID = CSSValueAuto;
        break;
    case AvoidBreakInside:
        m_value.valueID = CSSValueAvoid;
        break;
    case AvoidColumnBreakInside:
        m_value.valueID = CSSValueAvoidColumn;
        break;
    case AvoidPageBreakInside:
        m_value.valueID = CSSValueAvoidPage;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator BreakInside() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueAuto:
        return AutoBreakInside;
    case CSSValueAvoid:
        return AvoidBreakInside;
    case CSSValueAvoidColumn:
        return AvoidColumnBreakInside;
    case CSSValueAvoidPage:
        return AvoidPageBreakInside;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return AutoBreakInside;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(PositionType e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case PositionType::Static:
            m_value.valueID = CSSValueStatic;
            break;
        case PositionType::Relative:
            m_value.valueID = CSSValueRelative;
            break;
        case PositionType::Absolute:
            m_value.valueID = CSSValueAbsolute;
            break;
        case PositionType::Fixed:
            m_value.valueID = CSSValueFixed;
            break;
        case PositionType::Sticky:
            m_value.valueID = CSSValueSticky;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator PositionType() const
{
    switch (m_value.valueID) {
        case CSSValueStatic:
            return PositionType::Static;
        case CSSValueRelative:
            return PositionType::Relative;
        case CSSValueAbsolute:
            return PositionType::Absolute;
        case CSSValueFixed:
            return PositionType::Fixed;
        case CSSValueSticky:
            return PositionType::Sticky;
        default:
            ASSERT_NOT_REACHED();
            return PositionType::Static;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EResize e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case RESIZE_BOTH:
            m_value.valueID = CSSValueBoth;
            break;
        case RESIZE_HORIZONTAL:
            m_value.valueID = CSSValueHorizontal;
            break;
        case RESIZE_VERTICAL:
            m_value.valueID = CSSValueVertical;
            break;
        case RESIZE_NONE:
            m_value.valueID = CSSValueNone;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EResize() const
{
    switch (m_value.valueID) {
        case CSSValueBoth:
            return RESIZE_BOTH;
        case CSSValueHorizontal:
            return RESIZE_HORIZONTAL;
        case CSSValueVertical:
            return RESIZE_VERTICAL;
        case CSSValueAuto:
            ASSERT_NOT_REACHED(); // Depends on settings, thus should be handled by the caller.
            return RESIZE_NONE;
        case CSSValueNone:
            return RESIZE_NONE;
        default:
            ASSERT_NOT_REACHED();
            return RESIZE_NONE;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETableLayout e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case TAUTO:
            m_value.valueID = CSSValueAuto;
            break;
        case TFIXED:
            m_value.valueID = CSSValueFixed;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator ETableLayout() const
{
    switch (m_value.valueID) {
        case CSSValueFixed:
            return TFIXED;
        case CSSValueAuto:
            return TAUTO;
        default:
            ASSERT_NOT_REACHED();
            return TAUTO;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(TextAlignMode e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case TextAlignMode::Start:
        m_value.valueID = CSSValueStart;
        break;
    case TextAlignMode::End:
        m_value.valueID = CSSValueEnd;
        break;
    case TextAlignMode::Left:
        m_value.valueID = CSSValueLeft;
        break;
    case TextAlignMode::Right:
        m_value.valueID = CSSValueRight;
        break;
    case TextAlignMode::Center:
        m_value.valueID = CSSValueCenter;
        break;
    case TextAlignMode::Justify:
        m_value.valueID = CSSValueJustify;
        break;
    case TextAlignMode::WebKitLeft:
        m_value.valueID = CSSValueWebkitLeft;
        break;
    case TextAlignMode::WebKitRight:
        m_value.valueID = CSSValueWebkitRight;
        break;
    case TextAlignMode::WebKitCenter:
        m_value.valueID = CSSValueWebkitCenter;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextAlignMode() const
{
    switch (m_value.valueID) {
    case CSSValueWebkitAuto: // Legacy -webkit-auto. Eqiuvalent to start.
    case CSSValueStart:
        return TextAlignMode::Start;
    case CSSValueEnd:
        return TextAlignMode::End;
    default:
        return static_cast<TextAlignMode>(m_value.valueID - CSSValueLeft);
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextAlignLast e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_IDENT);
    switch (e) {
    case TextAlignLastStart:
        m_value.valueID = CSSValueStart;
        break;
    case TextAlignLastEnd:
        m_value.valueID = CSSValueEnd;
        break;
    case TextAlignLastLeft:
        m_value.valueID = CSSValueLeft;
        break;
    case TextAlignLastRight:
        m_value.valueID = CSSValueRight;
        break;
    case TextAlignLastCenter:
        m_value.valueID = CSSValueCenter;
        break;
    case TextAlignLastJustify:
        m_value.valueID = CSSValueJustify;
        break;
    case TextAlignLastAuto:
        m_value.valueID = CSSValueAuto;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextAlignLast() const
{
    switch (m_value.valueID) {
    case CSSValueAuto:
        return TextAlignLastAuto;
    case CSSValueStart:
        return TextAlignLastStart;
    case CSSValueEnd:
        return TextAlignLastEnd;
    case CSSValueLeft:
        return TextAlignLastLeft;
    case CSSValueRight:
        return TextAlignLastRight;
    case CSSValueCenter:
        return TextAlignLastCenter;
    case CSSValueJustify:
        return TextAlignLastJustify;
    }

    ASSERT_NOT_REACHED();
    return TextAlignLastAuto;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextJustify e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_IDENT);
    switch (e) {
    case TextJustifyAuto:
        m_value.valueID = CSSValueAuto;
        break;
    case TextJustifyNone:
        m_value.valueID = CSSValueNone;
        break;
    case TextJustifyInterWord:
        m_value.valueID = CSSValueInterWord;
        break;
    case TextJustifyDistribute:
        m_value.valueID = CSSValueDistribute;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextJustify() const
{
    switch (m_value.valueID) {
    case CSSValueAuto:
        return TextJustifyAuto;
    case CSSValueNone:
        return TextJustifyNone;
    case CSSValueInterWord:
        return TextJustifyInterWord;
    case CSSValueDistribute:
        return TextJustifyDistribute;
    }

    ASSERT_NOT_REACHED();
    return TextJustifyAuto;
}

template<> inline CSSPrimitiveValue::operator TextDecoration() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return TextDecorationNone;
    case CSSValueUnderline:
        return TextDecorationUnderline;
    case CSSValueOverline:
        return TextDecorationOverline;
    case CSSValueLineThrough:
        return TextDecorationLineThrough;
    case CSSValueBlink:
        return TextDecorationBlink;
    default:
        ASSERT_NOT_REACHED();
        return TextDecorationNone;
    }
}

template<> inline CSSPrimitiveValue::operator TextDecorationStyle() const
{
    switch (m_value.valueID) {
    case CSSValueSolid:
        return TextDecorationStyleSolid;
    case CSSValueDouble:
        return TextDecorationStyleDouble;
    case CSSValueDotted:
        return TextDecorationStyleDotted;
    case CSSValueDashed:
        return TextDecorationStyleDashed;
    case CSSValueWavy:
        return TextDecorationStyleWavy;
    }

    ASSERT_NOT_REACHED();
    return TextDecorationStyleSolid;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextUnderlinePosition position)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_IDENT);
    switch (position) {
    case TextUnderlinePosition::Auto:
        m_value.valueID = CSSValueAuto;
        break;
    case TextUnderlinePosition::Under:
        m_value.valueID = CSSValueUnder;
        break;
    case TextUnderlinePosition::FromFont:
        m_value.valueID = CSSValueFromFont;
        break;
    }

    // FIXME: Implement support for 'under left' and 'under right' values.
}

template<> inline CSSPrimitiveValue::operator TextUnderlinePosition() const
{
    switch (m_value.valueID) {
    case CSSValueAuto:
        return TextUnderlinePosition::Auto;
    case CSSValueUnder:
        return TextUnderlinePosition::Under;
    case CSSValueFromFont:
        return TextUnderlinePosition::FromFont;
    default:
    	break;
    }

    // FIXME: Implement support for 'under left' and 'under right' values.
    ASSERT_NOT_REACHED();
    return TextUnderlinePosition::Auto;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETextSecurity e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case TSNONE:
            m_value.valueID = CSSValueNone;
            break;
        case TSDISC:
            m_value.valueID = CSSValueDisc;
            break;
        case TSCIRCLE:
            m_value.valueID = CSSValueCircle;
            break;
        case TSSQUARE:
            m_value.valueID = CSSValueSquare;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator ETextSecurity() const
{
    switch (m_value.valueID) {
        case CSSValueNone:
            return TSNONE;
        case CSSValueDisc:
            return TSDISC;
        case CSSValueCircle:
            return TSCIRCLE;
        case CSSValueSquare:
            return TSSQUARE;
        default:
            ASSERT_NOT_REACHED();
            return TSNONE;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ETextTransform e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case CAPITALIZE:
            m_value.valueID = CSSValueCapitalize;
            break;
        case UPPERCASE:
            m_value.valueID = CSSValueUppercase;
            break;
        case LOWERCASE:
            m_value.valueID = CSSValueLowercase;
            break;
        case TTNONE:
            m_value.valueID = CSSValueNone;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator ETextTransform() const
{
    switch (m_value.valueID) {
        case CSSValueCapitalize:
            return CAPITALIZE;
        case CSSValueUppercase:
            return UPPERCASE;
        case CSSValueLowercase:
            return LOWERCASE;
        case CSSValueNone:
            return TTNONE;
        default:
            ASSERT_NOT_REACHED();
            return TTNONE;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUnicodeBidi e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_IDENT);
    switch (e) {
    case UBNormal:
        m_value.valueID = CSSValueNormal;
        break;
    case Embed:
        m_value.valueID = CSSValueEmbed;
        break;
    case Override:
        m_value.valueID = CSSValueBidiOverride;
        break;
    case Isolate:
        m_value.valueID = CSSValueIsolate;
        break;
    case IsolateOverride:
        m_value.valueID = CSSValueIsolateOverride;
        break;
    case Plaintext:
        m_value.valueID = CSSValuePlaintext;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EUnicodeBidi() const
{
    switch (m_value.valueID) {
    case CSSValueNormal:
        return UBNormal;
    case CSSValueEmbed:
        return Embed;
    case CSSValueBidiOverride:
        return Override;
    case CSSValueIsolate:
    case CSSValueWebkitIsolate:
        return Isolate;
    case CSSValueIsolateOverride:
    case CSSValueWebkitIsolateOverride:
        return IsolateOverride;
    case CSSValuePlaintext:
    case CSSValueWebkitPlaintext:
        return Plaintext;
    default:
        ASSERT_NOT_REACHED();
        return UBNormal;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUserDrag e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case DRAG_AUTO:
            m_value.valueID = CSSValueAuto;
            break;
        case DRAG_NONE:
            m_value.valueID = CSSValueNone;
            break;
        case DRAG_ELEMENT:
            m_value.valueID = CSSValueElement;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EUserDrag() const
{
    switch (m_value.valueID) {
        case CSSValueAuto:
            return DRAG_AUTO;
        case CSSValueNone:
            return DRAG_NONE;
        case CSSValueElement:
            return DRAG_ELEMENT;
        default:
            ASSERT_NOT_REACHED();
            return DRAG_AUTO;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUserModify e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case READ_ONLY:
            m_value.valueID = CSSValueReadOnly;
            break;
        case READ_WRITE:
            m_value.valueID = CSSValueReadWrite;
            break;
        case READ_WRITE_PLAINTEXT_ONLY:
            m_value.valueID = CSSValueReadWritePlaintextOnly;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EUserModify() const
{
    switch (m_value.valueID) {
    case CSSValueReadOnly:
        return READ_ONLY;
    case CSSValueReadWrite:
        return READ_WRITE;
    case CSSValueReadWritePlaintextOnly:
        return READ_WRITE_PLAINTEXT_ONLY;
    default:
        ASSERT_NOT_REACHED();
        return READ_ONLY;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EUserSelect e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case SELECT_NONE:
            m_value.valueID = CSSValueNone;
            break;
        case SELECT_TEXT:
            m_value.valueID = CSSValueText;
            break;
        case SELECT_ALL:
            m_value.valueID = CSSValueAll;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EUserSelect() const
{
    switch (m_value.valueID) {
        case CSSValueAuto:
            return SELECT_TEXT;
        case CSSValueNone:
            return SELECT_NONE;
        case CSSValueText:
            return SELECT_TEXT;
        case CSSValueAll:
            return SELECT_ALL;
        default:
            ASSERT_NOT_REACHED();
            return SELECT_TEXT;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EVerticalAlign a)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (a) {
    case TOP:
        m_value.valueID = CSSValueTop;
        break;
    case BOTTOM:
        m_value.valueID = CSSValueBottom;
        break;
    case MIDDLE:
        m_value.valueID = CSSValueMiddle;
        break;
    case BASELINE:
        m_value.valueID = CSSValueBaseline;
        break;
    case TEXT_BOTTOM:
        m_value.valueID = CSSValueTextBottom;
        break;
    case TEXT_TOP:
        m_value.valueID = CSSValueTextTop;
        break;
    case SUB:
        m_value.valueID = CSSValueSub;
        break;
    case SUPER:
        m_value.valueID = CSSValueSuper;
        break;
    case BASELINE_MIDDLE:
        m_value.valueID = CSSValueWebkitBaselineMiddle;
        break;
    case LENGTH:
        m_value.valueID = CSSValueInvalid;
    }
}

template<> inline CSSPrimitiveValue::operator EVerticalAlign() const
{
    switch (m_value.valueID) {
    case CSSValueTop:
        return TOP;
    case CSSValueBottom:
        return BOTTOM;
    case CSSValueMiddle:
        return MIDDLE;
    case CSSValueBaseline:
        return BASELINE;
    case CSSValueTextBottom:
        return TEXT_BOTTOM;
    case CSSValueTextTop:
        return TEXT_TOP;
    case CSSValueSub:
        return SUB;
    case CSSValueSuper:
        return SUPER;
    case CSSValueWebkitBaselineMiddle:
        return BASELINE_MIDDLE;
    default:
        ASSERT_NOT_REACHED();
        return TOP;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EVisibility e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case VISIBLE:
            m_value.valueID = CSSValueVisible;
            break;
        case HIDDEN:
            m_value.valueID = CSSValueHidden;
            break;
        case COLLAPSE:
            m_value.valueID = CSSValueCollapse;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EVisibility() const
{
    switch (m_value.valueID) {
        case CSSValueHidden:
            return HIDDEN;
        case CSSValueVisible:
            return VISIBLE;
        case CSSValueCollapse:
            return COLLAPSE;
        default:
            ASSERT_NOT_REACHED();
            return VISIBLE;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(WhiteSpace e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case WhiteSpace::Normal:
            m_value.valueID = CSSValueNormal;
            break;
        case WhiteSpace::Pre:
            m_value.valueID = CSSValuePre;
            break;
        case WhiteSpace::PreWrap:
            m_value.valueID = CSSValuePreWrap;
            break;
        case WhiteSpace::PreLine:
            m_value.valueID = CSSValuePreLine;
            break;
        case WhiteSpace::NoWrap:
            m_value.valueID = CSSValueNowrap;
            break;
        case WhiteSpace::KHTMLNoWrap:
            m_value.valueID = CSSValueWebkitNowrap;
            break;
        case WhiteSpace::BreakSpaces:
            m_value.valueID = CSSValueBreakSpaces;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator WhiteSpace() const
{
    switch (m_value.valueID) {
        case CSSValueWebkitNowrap:
            return WhiteSpace::KHTMLNoWrap;
        case CSSValueNowrap:
            return WhiteSpace::NoWrap;
        case CSSValuePre:
            return WhiteSpace::Pre;
        case CSSValuePreWrap:
            return WhiteSpace::PreWrap;
        case CSSValuePreLine:
            return WhiteSpace::PreLine;
        case CSSValueNormal:
            return WhiteSpace::Normal;
        case CSSValueBreakSpaces:
            return WhiteSpace::BreakSpaces;
        default:
            ASSERT_NOT_REACHED();
            return WhiteSpace::Normal;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(WordBreak e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case WordBreak::Normal:
            m_value.valueID = CSSValueNormal;
            break;
        case WordBreak::BreakAll:
            m_value.valueID = CSSValueBreakAll;
            break;
        case WordBreak::KeepAll:
            m_value.valueID = CSSValueKeepAll;
            break;
        case WordBreak::BreakWord:
            m_value.valueID = CSSValueBreakWord;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator WordBreak() const
{
    switch (m_value.valueID) {
        case CSSValueBreakAll:
            return WordBreak::BreakAll;
        case CSSValueKeepAll:
            return WordBreak::KeepAll;
        case CSSValueBreakWord:
            return WordBreak::BreakWord;
        case CSSValueNormal:
            return WordBreak::Normal;
        default:
        ASSERT_NOT_REACHED();
        return WordBreak::Normal;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(OverflowWrap e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case OverflowWrap::Normal:
            m_value.valueID = CSSValueNormal;
            break;
        case OverflowWrap::Anywhere:
            m_value.valueID = CSSValueAnywhere;
            break;
        case OverflowWrap::BreakWord:
            m_value.valueID = CSSValueBreakWord;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator OverflowWrap() const
{
    switch (m_value.valueID) {
        case CSSValueBreakWord:
            return OverflowWrap::BreakWord;
        case CSSValueAnywhere:
            return OverflowWrap::Anywhere;
        case CSSValueNormal:
            return OverflowWrap::Normal;
        default:
            ASSERT_NOT_REACHED();
            return OverflowWrap::Normal;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(TextDirection e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case LTR:
            m_value.valueID = CSSValueLtr;
            break;
        case RTL:
            m_value.valueID = CSSValueRtl;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator TextDirection() const
{
    switch (m_value.valueID) {
        case CSSValueLtr:
            return LTR;
        case CSSValueRtl:
            return RTL;
        default:
            ASSERT_NOT_REACHED();
            return LTR;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(WritingMode e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case TopToBottomWritingMode:
        m_value.valueID = CSSValueHorizontalTb;
        break;
    case RightToLeftWritingMode:
        m_value.valueID = CSSValueVerticalRl;
        break;
    case LeftToRightWritingMode:
        m_value.valueID = CSSValueVerticalLr;
        break;
    case BottomToTopWritingMode:
        m_value.valueID = CSSValueHorizontalBt;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator WritingMode() const
{
    switch (m_value.valueID) {
    case CSSValueHorizontalTb:
    case CSSValueLrTb:
    case CSSValueRl:
    case CSSValueRlTb:
        return TopToBottomWritingMode;
    case CSSValueVerticalRl:
    case CSSValueTb:
    case CSSValueTbRl:
        return RightToLeftWritingMode;
    case CSSValueVerticalLr:
        return LeftToRightWritingMode;
    case CSSValueHorizontalBt:
        return BottomToTopWritingMode;
    default:
        ASSERT_NOT_REACHED();
        return TopToBottomWritingMode;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextCombine e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case TextCombineNone:
        m_value.valueID = CSSValueNone;
        break;
    case TextCombineHorizontal:
        m_value.valueID = CSSValueHorizontal;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextCombine() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return TextCombineNone;
    case CSSValueHorizontal:
        return TextCombineHorizontal;
    default:
        ASSERT_NOT_REACHED();
        return TextCombineNone;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(RubyPosition position)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (position) {
    case RubyPositionBefore:
        m_value.valueID = CSSValueBefore;
        break;
    case RubyPositionAfter:
        m_value.valueID = CSSValueAfter;
        break;
    case RubyPositionInterCharacter:
        m_value.valueID = CSSValueInterCharacter;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator RubyPosition() const
{
    switch (m_value.valueID) {
    case CSSValueBefore:
        return RubyPositionBefore;
    case CSSValueAfter:
        return RubyPositionAfter;
    case CSSValueInterCharacter:
        return RubyPositionInterCharacter;
    }

    ASSERT_NOT_REACHED();
    return RubyPositionBefore;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(TextOverflow overflow)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (overflow) {
    case TextOverflowClip:
        m_value.valueID = CSSValueClip;
        break;
    case TextOverflowEllipsis:
        m_value.valueID = CSSValueEllipsis;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextOverflow() const
{
    switch (m_value.valueID) {
    case CSSValueClip:
        return TextOverflowClip;
    case CSSValueEllipsis:
        return TextOverflowEllipsis;
    default:
        ASSERT_NOT_REACHED();
        return TextOverflowClip;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextEmphasisFill fill)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (fill) {
    case TextEmphasisFillFilled:
        m_value.valueID = CSSValueFilled;
        break;
    case TextEmphasisFillOpen:
        m_value.valueID = CSSValueOpen;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextEmphasisFill() const
{
    switch (m_value.valueID) {
    case CSSValueFilled:
        return TextEmphasisFillFilled;
    case CSSValueOpen:
        return TextEmphasisFillOpen;
    default:
        ASSERT_NOT_REACHED();
        return TextEmphasisFillFilled;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextEmphasisMark mark)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (mark) {
    case TextEmphasisMarkDot:
        m_value.valueID = CSSValueDot;
        break;
    case TextEmphasisMarkCircle:
        m_value.valueID = CSSValueCircle;
        break;
    case TextEmphasisMarkDoubleCircle:
        m_value.valueID = CSSValueDoubleCircle;
        break;
    case TextEmphasisMarkTriangle:
        m_value.valueID = CSSValueTriangle;
        break;
    case TextEmphasisMarkSesame:
        m_value.valueID = CSSValueSesame;
        break;
    case TextEmphasisMarkNone:
    case TextEmphasisMarkAuto:
    case TextEmphasisMarkCustom:
        ASSERT_NOT_REACHED();
        m_value.valueID = CSSValueNone;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextEmphasisMark() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return TextEmphasisMarkNone;
    case CSSValueDot:
        return TextEmphasisMarkDot;
    case CSSValueCircle:
        return TextEmphasisMarkCircle;
    case CSSValueDoubleCircle:
        return TextEmphasisMarkDoubleCircle;
    case CSSValueTriangle:
        return TextEmphasisMarkTriangle;
    case CSSValueSesame:
        return TextEmphasisMarkSesame;
    default:
        ASSERT_NOT_REACHED();
        return TextEmphasisMarkNone;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(TextOrientation e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case TextOrientation::Sideways:
        m_value.valueID = CSSValueSideways;
        break;
    case TextOrientation::SidewaysRight:
        m_value.valueID = CSSValueSidewaysRight;
        break;
    case TextOrientation::Mixed:
        m_value.valueID = CSSValueMixed;
        break;
    case TextOrientation::Upright:
        m_value.valueID = CSSValueUpright;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TextOrientation() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueSideways:
        return TextOrientation::Sideways;
    case CSSValueSidewaysRight:
        return TextOrientation::SidewaysRight;
    case CSSValueVerticalRight:
        return TextOrientation::Mixed;
    case CSSValueMixed:
        return TextOrientation::Mixed;
    case CSSValueUpright:
        return TextOrientation::Upright;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return TextOrientation::Mixed;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EPointerEvents e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case PE_NONE:
            m_value.valueID = CSSValueNone;
            break;
        case PE_STROKE:
            m_value.valueID = CSSValueStroke;
            break;
        case PE_FILL:
            m_value.valueID = CSSValueFill;
            break;
        case PE_PAINTED:
            m_value.valueID = CSSValuePainted;
            break;
        case PE_VISIBLE:
            m_value.valueID = CSSValueVisible;
            break;
        case PE_VISIBLE_STROKE:
            m_value.valueID = CSSValueVisibleStroke;
            break;
        case PE_VISIBLE_FILL:
            m_value.valueID = CSSValueVisibleFill;
            break;
        case PE_VISIBLE_PAINTED:
            m_value.valueID = CSSValueVisiblePainted;
            break;
        case PE_AUTO:
            m_value.valueID = CSSValueAuto;
            break;
        case PE_ALL:
            m_value.valueID = CSSValueAll;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EPointerEvents() const
{
    switch (m_value.valueID) {
        case CSSValueAll:
            return PE_ALL;
        case CSSValueAuto:
            return PE_AUTO;
        case CSSValueNone:
            return PE_NONE;
        case CSSValueVisiblePainted:
            return PE_VISIBLE_PAINTED;
        case CSSValueVisibleFill:
            return PE_VISIBLE_FILL;
        case CSSValueVisibleStroke:
            return PE_VISIBLE_STROKE;
        case CSSValueVisible:
            return PE_VISIBLE;
        case CSSValuePainted:
            return PE_PAINTED;
        case CSSValueFill:
            return PE_FILL;
        case CSSValueStroke:
            return PE_STROKE;
        default:
            ASSERT_NOT_REACHED();
            return PE_ALL;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Kerning kerning)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (kerning) {
    case Kerning::Auto:
        m_value.valueID = CSSValueAuto;
        return;
    case Kerning::Normal:
        m_value.valueID = CSSValueNormal;
        return;
    case Kerning::NoShift:
        m_value.valueID = CSSValueNone;
        return;
    }

    ASSERT_NOT_REACHED();
    m_value.valueID = CSSValueAuto;
}

template<> inline CSSPrimitiveValue::operator Kerning() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueAuto:
        return Kerning::Auto;
    case CSSValueNormal:
        return Kerning::Normal;
    case CSSValueNone:
        return Kerning::NoShift;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return Kerning::Auto;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ObjectFit fit)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (fit) {
    case ObjectFitFill:
        m_value.valueID = CSSValueFill;
        break;
    case ObjectFitContain:
        m_value.valueID = CSSValueContain;
        break;
    case ObjectFitCover:
        m_value.valueID = CSSValueCover;
        break;
    case ObjectFitNone:
        m_value.valueID = CSSValueNone;
        break;
    case ObjectFitScaleDown:
        m_value.valueID = CSSValueScaleDown;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ObjectFit() const
{
    switch (m_value.valueID) {
    case CSSValueFill:
        return ObjectFitFill;
    case CSSValueContain:
        return ObjectFitContain;
    case CSSValueCover:
        return ObjectFitCover;
    case CSSValueNone:
        return ObjectFitNone;
    case CSSValueScaleDown:
        return ObjectFitScaleDown;
    default:
        ASSERT_NOT_REACHED();
        return ObjectFitFill;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontSmoothingMode smoothing)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (smoothing) {
    case AutoSmoothing:
        m_value.valueID = CSSValueAuto;
        return;
    case NoSmoothing:
        m_value.valueID = CSSValueNone;
        return;
    case Antialiased:
        m_value.valueID = CSSValueAntialiased;
        return;
    case SubpixelAntialiased:
        m_value.valueID = CSSValueSubpixelAntialiased;
        return;
    }

    ASSERT_NOT_REACHED();
    m_value.valueID = CSSValueAuto;
}

template<> inline CSSPrimitiveValue::operator FontSmoothingMode() const
{
    switch (m_value.valueID) {
    case CSSValueAuto:
        return AutoSmoothing;
    case CSSValueNone:
        return NoSmoothing;
    case CSSValueAntialiased:
        return Antialiased;
    case CSSValueSubpixelAntialiased:
        return SubpixelAntialiased;
    }

    ASSERT_NOT_REACHED();
    return AutoSmoothing;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(FontSmallCaps smallCaps)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (smallCaps) {
    case FontSmallCapsOff:
        m_value.valueID = CSSValueNormal;
        return;
    case FontSmallCapsOn:
        m_value.valueID = CSSValueSmallCaps;
        return;
    }

    ASSERT_NOT_REACHED();
    m_value.valueID = CSSValueNormal;
}

template<> inline CSSPrimitiveValue::operator FontSmallCaps() const
{
    switch (m_value.valueID) {
    case CSSValueSmallCaps:
        return FontSmallCapsOn;
    case CSSValueNormal:
        return FontSmallCapsOff;
    }
    ASSERT_NOT_REACHED();
    return FontSmallCapsOff;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(TextRenderingMode e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case AutoTextRendering:
            m_value.valueID = CSSValueAuto;
            break;
        case OptimizeSpeed:
            m_value.valueID = CSSValueOptimizeSpeed;
            break;
        case OptimizeLegibility:
            m_value.valueID = CSSValueOptimizeLegibility;
            break;
        case GeometricPrecision:
            m_value.valueID = CSSValueGeometricPrecision;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator TextRenderingMode() const
{
    switch (m_value.valueID) {
        case CSSValueAuto:
            return AutoTextRendering;
        case CSSValueOptimizeSpeed:
            return OptimizeSpeed;
        case CSSValueOptimizeLegibility:
            return OptimizeLegibility;
        case CSSValueGeometricPrecision:
            return GeometricPrecision;
        default:
            ASSERT_NOT_REACHED();
            return AutoTextRendering;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(Hyphens hyphens)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (hyphens) {
    case HyphensNone:
        m_value.valueID = CSSValueNone;
        break;
    case HyphensManual:
        m_value.valueID = CSSValueManual;
        break;
    case HyphensAuto:
        m_value.valueID = CSSValueAuto;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator Hyphens() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return HyphensNone;
    case CSSValueManual:
        return HyphensManual;
    case CSSValueAuto:
        return HyphensAuto;
    default:
        ASSERT_NOT_REACHED();
        return HyphensAuto;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(LineSnap gridSnap)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (gridSnap) {
    case LineSnapNone:
        m_value.valueID = CSSValueNone;
        break;
    case LineSnapBaseline:
        m_value.valueID = CSSValueBaseline;
        break;
    case LineSnapContain:
        m_value.valueID = CSSValueContain;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator LineSnap() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return LineSnapNone;
    case CSSValueBaseline:
        return LineSnapBaseline;
    case CSSValueContain:
        return LineSnapContain;
    default:
        ASSERT_NOT_REACHED();
        return LineSnapNone;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(LineAlign lineAlign)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (lineAlign) {
    case LineAlignNone:
        m_value.valueID = CSSValueNone;
        break;
    case LineAlignEdges:
        m_value.valueID = CSSValueEdges;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator LineAlign() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return LineAlignNone;
    case CSSValueEdges:
        return LineAlignEdges;
    default:
        ASSERT_NOT_REACHED();
        return LineAlignNone;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ESpeak e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case SpeakNone:
        m_value.valueID = CSSValueNone;
        break;
    case SpeakNormal:
        m_value.valueID = CSSValueNormal;
        break;
    case SpeakSpellOut:
        m_value.valueID = CSSValueSpellOut;
        break;
    case SpeakDigits:
        m_value.valueID = CSSValueDigits;
        break;
    case SpeakLiteralPunctuation:
        m_value.valueID = CSSValueLiteralPunctuation;
        break;
    case SpeakNoPunctuation:
        m_value.valueID = CSSValueNoPunctuation;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator Order() const
{
    switch (m_value.valueID) {
    case CSSValueLogical:
        return LogicalOrder;
    case CSSValueVisual:
        return VisualOrder;
    default:
        ASSERT_NOT_REACHED();
        return LogicalOrder;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(Order e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case LogicalOrder:
        m_value.valueID = CSSValueLogical;
        break;
    case VisualOrder:
        m_value.valueID = CSSValueVisual;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ESpeak() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return SpeakNone;
    case CSSValueNormal:
        return SpeakNormal;
    case CSSValueSpellOut:
        return SpeakSpellOut;
    case CSSValueDigits:
        return SpeakDigits;
    case CSSValueLiteralPunctuation:
        return SpeakLiteralPunctuation;
    case CSSValueNoPunctuation:
        return SpeakNoPunctuation;
    default:
        ASSERT_NOT_REACHED();
        return SpeakNormal;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(BlendMode blendMode)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_IDENT);
    switch (blendMode) {
    case BlendModeNormal:
        m_value.valueID = CSSValueNormal;
        break;
    case BlendModeMultiply:
        m_value.valueID = CSSValueMultiply;
        break;
    case BlendModeScreen:
        m_value.valueID = CSSValueScreen;
        break;
    case BlendModeOverlay:
        m_value.valueID = CSSValueOverlay;
        break;
    case BlendModeDarken:
        m_value.valueID = CSSValueDarken;
        break;
    case BlendModeLighten:
        m_value.valueID = CSSValueLighten;
        break;
    case BlendModeColorDodge:
        m_value.valueID = CSSValueColorDodge;
        break;
    case BlendModeColorBurn:
        m_value.valueID = CSSValueColorBurn;
        break;
    case BlendModeHardLight:
        m_value.valueID = CSSValueHardLight;
        break;
    case BlendModeSoftLight:
        m_value.valueID = CSSValueSoftLight;
        break;
    case BlendModeDifference:
        m_value.valueID = CSSValueDifference;
        break;
    case BlendModeExclusion:
        m_value.valueID = CSSValueExclusion;
        break;
    case BlendModeHue:
        m_value.valueID = CSSValueHue;
        break;
    case BlendModeSaturation:
        m_value.valueID = CSSValueSaturation;
        break;
    case BlendModeColor:
        m_value.valueID = CSSValueColor;
        break;
    case BlendModeLuminosity:
        m_value.valueID = CSSValueLuminosity;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator BlendMode() const
{
    switch (m_value.valueID) {
    case CSSValueNormal:
        return BlendModeNormal;
    case CSSValueMultiply:
        return BlendModeMultiply;
    case CSSValueScreen:
        return BlendModeScreen;
    case CSSValueOverlay:
        return BlendModeOverlay;
    case CSSValueDarken:
        return BlendModeDarken;
    case CSSValueLighten:
        return BlendModeLighten;
    case CSSValueColorDodge:
        return BlendModeColorDodge;
    case CSSValueColorBurn:
        return BlendModeColorBurn;
    case CSSValueHardLight:
        return BlendModeHardLight;
    case CSSValueSoftLight:
        return BlendModeSoftLight;
    case CSSValueDifference:
        return BlendModeDifference;
    case CSSValueExclusion:
        return BlendModeExclusion;
    case CSSValueHue:
        return BlendModeHue;
    case CSSValueSaturation:
        return BlendModeSaturation;
    case CSSValueColor:
        return BlendModeColor;
    case CSSValueLuminosity:
        return BlendModeLuminosity;
    default:
        ASSERT_NOT_REACHED();
        return BlendModeNormal;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Isolation isolation)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (isolation) {
    case IsolationAuto:
        m_value.valueID = CSSValueAuto;
        break;
    case IsolationIsolate:
        m_value.valueID = CSSValueIsolate;
        break;
    default:
        ASSERT_NOT_REACHED();
    }
}

template<> inline CSSPrimitiveValue::operator Isolation() const
{
    ASSERT(isValueID());
    switch (m_value.valueID) {
    case CSSValueAuto:
        return IsolationAuto;
    case CSSValueIsolate:
        return IsolationIsolate;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return IsolationAuto;
}

#if ENABLE(SVG)

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(LineCap e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case ButtCap:
            m_value.valueID = CSSValueButt;
            break;
        case RoundCap:
            m_value.valueID = CSSValueRound;
            break;
        case SquareCap:
            m_value.valueID = CSSValueSquare;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator LineCap() const
{
    switch (m_value.valueID) {
        case CSSValueButt:
            return ButtCap;
        case CSSValueRound:
            return RoundCap;
        case CSSValueSquare:
            return SquareCap;
        default:
            ASSERT_NOT_REACHED();
            return ButtCap;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(LineJoin e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case MiterJoin:
            m_value.valueID = CSSValueMiter;
            break;
        case RoundJoin:
            m_value.valueID = CSSValueRound;
            break;
        case BevelJoin:
            m_value.valueID = CSSValueBevel;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator LineJoin() const
{
    switch (m_value.valueID) {
        case CSSValueMiter:
            return MiterJoin;
        case CSSValueRound:
            return RoundJoin;
        case CSSValueBevel:
            return BevelJoin;
        default:
            ASSERT_NOT_REACHED();
            return MiterJoin;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(WindRule e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case RULE_NONZERO:
            m_value.valueID = CSSValueNonzero;
            break;
        case RULE_EVENODD:
            m_value.valueID = CSSValueEvenodd;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator WindRule() const
{
    switch (m_value.valueID) {
        case CSSValueNonzero:
            return RULE_NONZERO;
        case CSSValueEvenodd:
            return RULE_EVENODD;
        default:
            ASSERT_NOT_REACHED();
            return RULE_NONZERO;
    }
}


template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EAlignmentBaseline e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case AB_BASELINE:
            m_value.valueID = CSSValueBaseline;
            break;
        case AB_BEFORE_EDGE:
            m_value.valueID = CSSValueBeforeEdge;
            break;
        case AB_TEXT_BEFORE_EDGE:
            m_value.valueID = CSSValueTextBeforeEdge;
            break;
        case AB_MIDDLE:
            m_value.valueID = CSSValueMiddle;
            break;
        case AB_CENTRAL:
            m_value.valueID = CSSValueCentral;
            break;
        case AB_AFTER_EDGE:
            m_value.valueID = CSSValueAfterEdge;
            break;
        case AB_TEXT_AFTER_EDGE:
            m_value.valueID = CSSValueTextAfterEdge;
            break;
        case AB_IDEOGRAPHIC:
            m_value.valueID = CSSValueIdeographic;
            break;
        case AB_ALPHABETIC:
            m_value.valueID = CSSValueAlphabetic;
            break;
        case AB_HANGING:
            m_value.valueID = CSSValueHanging;
            break;
        case AB_MATHEMATICAL:
            m_value.valueID = CSSValueMathematical;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EAlignmentBaseline() const
{
    switch (m_value.valueID) {
        case CSSValueBaseline:
            return AB_BASELINE;
        case CSSValueBeforeEdge:
            return AB_BEFORE_EDGE;
        case CSSValueTextBeforeEdge:
            return AB_TEXT_BEFORE_EDGE;
        case CSSValueMiddle:
            return AB_MIDDLE;
        case CSSValueCentral:
            return AB_CENTRAL;
        case CSSValueAfterEdge:
            return AB_AFTER_EDGE;
        case CSSValueTextAfterEdge:
            return AB_TEXT_AFTER_EDGE;
        case CSSValueIdeographic:
            return AB_IDEOGRAPHIC;
        case CSSValueAlphabetic:
            return AB_ALPHABETIC;
        case CSSValueHanging:
            return AB_HANGING;
        case CSSValueMathematical:
            return AB_MATHEMATICAL;
        default:
            ASSERT_NOT_REACHED();
            return AB_BASELINE;
    }
}

#endif

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EBorderCollapse e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case BSEPARATE:
        m_value.valueID = CSSValueSeparate;
        break;
    case BCOLLAPSE:
        m_value.valueID = CSSValueCollapse;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EBorderCollapse() const
{
    switch (m_value.valueID) {
    case CSSValueSeparate:
        return BSEPARATE;
    case CSSValueCollapse:
        return BCOLLAPSE;
    default:
        ASSERT_NOT_REACHED();
        return BSEPARATE;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EImageRendering e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case ImageRenderingAuto:
        m_value.valueID = CSSValueAuto;
        break;
    case ImageRenderingOptimizeSpeed:
        m_value.valueID = CSSValueOptimizeSpeed;
        break;
    case ImageRenderingOptimizeQuality:
        m_value.valueID = CSSValueOptimizeQuality;
        break;
    case ImageRenderingOptimizeContrast:
        m_value.valueID = CSSValueWebkitOptimizeContrast;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EImageRendering() const
{
    switch (m_value.valueID) {
    case CSSValueAuto:
        return ImageRenderingAuto;
    case CSSValueOptimizeSpeed:
        return ImageRenderingOptimizeSpeed;
    case CSSValueOptimizeQuality:
        return ImageRenderingOptimizeQuality;
    case CSSValueWebkitOptimizeContrast:
        return ImageRenderingOptimizeContrast;
    default:
        ASSERT_NOT_REACHED();
        return ImageRenderingAuto;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(ETransformStyle3D e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case TransformStyle3DFlat:
        m_value.valueID = CSSValueFlat;
        break;
    case TransformStyle3DPreserve3D:
        m_value.valueID = CSSValuePreserve3d;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ETransformStyle3D() const
{
    switch (m_value.valueID) {
    case CSSValueFlat:
        return TransformStyle3DFlat;
    case CSSValuePreserve3d:
        return TransformStyle3DPreserve3D;
    default:
        ASSERT_NOT_REACHED();
        return TransformStyle3DFlat;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TransformBox box)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (box) {
    case TransformBox::StrokeBox:
        m_value.valueID = CSSValueStrokeBox;
        break;
    case TransformBox::ContentBox:
        m_value.valueID = CSSValueContentBox;
        break;
    case TransformBox::BorderBox:
        m_value.valueID = CSSValueBorderBox;
        break;
    case TransformBox::FillBox:
        m_value.valueID = CSSValueFillBox;
        break;
    case TransformBox::ViewBox:
        m_value.valueID = CSSValueViewBox;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator TransformBox() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueStrokeBox:
        return TransformBox::StrokeBox;
    case CSSValueContentBox:
        return TransformBox::ContentBox;
    case CSSValueBorderBox:
        return TransformBox::BorderBox;
    case CSSValueFillBox:
        return TransformBox::FillBox;
    case CSSValueViewBox:
        return TransformBox::ViewBox;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return TransformBox::BorderBox;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(ColumnAxis e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case HorizontalColumnAxis:
        m_value.valueID = CSSValueHorizontal;
        break;
    case VerticalColumnAxis:
        m_value.valueID = CSSValueVertical;
        break;
    case AutoColumnAxis:
        m_value.valueID = CSSValueAuto;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ColumnAxis() const
{
    switch (m_value.valueID) {
    case CSSValueHorizontal:
        return HorizontalColumnAxis;
    case CSSValueVertical:
        return VerticalColumnAxis;
    case CSSValueAuto:
        return AutoColumnAxis;
    default:
        ASSERT_NOT_REACHED();
        return AutoColumnAxis;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(ColumnProgression e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case NormalColumnProgression:
        m_value.valueID = CSSValueNormal;
        break;
    case ReverseColumnProgression:
        m_value.valueID = CSSValueReverse;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ColumnProgression() const
{
    switch (m_value.valueID) {
    case CSSValueNormal:
        return NormalColumnProgression;
    case CSSValueReverse:
        return ReverseColumnProgression;
    default:
        ASSERT_NOT_REACHED();
        return NormalColumnProgression;
    }
}

enum LengthConversion {
    AnyConversion = ~0,
    FixedIntegerConversion = 1 << 0,
    FixedFloatConversion = 1 << 1,
    AutoConversion = 1 << 2,
    PercentConversion = 1 << 3,
    CalculatedConversion = 1 << 4
};

inline bool CSSPrimitiveValue::convertingToLengthRequiresNonNullStyle(int lengthConversion) const
{
	// This matches the implementation in CSSPrimitiveValue::computeLengthDouble().
    //
    // FIXME: We should probably make CSSPrimitiveValue::computeLengthDouble and
    // CSSPrimitiveValue::computeNonCalcLengthDouble (which has the style assertion)
    // return std::optional<double> instead of having this check here.
    switch (primitiveUnitType()) {
    case CSSUnitType::CSS_EMS:
    case CSSUnitType::CSS_EXS:
    case CSSUnitType::CSS_CHS:
    case CSSUnitType::CSS_IC:
    case CSSUnitType::CSS_LHS:
        return lengthConversion & (FixedIntegerConversion | FixedFloatConversion);
    case CSSUnitType::CSS_CALC:
		return m_value.calc->convertingToLengthRequiresNonNullStyle(lengthConversion);
	default:
        return false;
    }
}

template<int supported> ALWAYS_INLINE Length CSSPrimitiveValue::convertToLength(const CSSToLengthConversionData& conversionData) const
{
    ASSERT(!hasVariableReference());
    if (convertingToLengthRequiresNonNullStyle(supported) && !conversionData.style())
        return Length(LengthType::Undefined);
    if ((supported & FixedIntegerConversion) && isLength())
        return computeLength<Length>(conversionData);
    if ((supported & FixedFloatConversion) && isLength())
        return Length(computeLength<double>(conversionData), LengthType::Fixed);
    if ((supported & PercentConversion) && isPercentage())
        return Length(doubleValue(), LengthType::Percent);
    if ((supported & AutoConversion) && getValueID() == CSSValueAuto)
        return Length(LengthType::Auto);
    if ((supported & CalculatedConversion) && isCalculated())
        return Length(cssCalcValue()->createCalculationValue(conversionData));
    return Length(LengthType::Undefined);
}

#if ENABLE(SVG)

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBufferedRendering e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case BR_AUTO:
        m_value.valueID = CSSValueAuto;
        break;
    case BR_DYNAMIC:
        m_value.valueID = CSSValueDynamic;
        break;
    case BR_STATIC:
        m_value.valueID = CSSValueStatic;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EBufferedRendering() const
{
    switch (m_value.valueID) {
    case CSSValueAuto:
        return BR_AUTO;
    case CSSValueDynamic:
        return BR_DYNAMIC;
    case CSSValueStatic:
        return BR_STATIC;
    }

    ASSERT_NOT_REACHED();
    return BR_AUTO;
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EColorInterpolation e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case CI_AUTO:
            m_value.valueID = CSSValueAuto;
            break;
        case CI_SRGB:
            m_value.valueID = CSSValueSRGB;
            break;
        case CI_LINEARRGB:
            m_value.valueID = CSSValueLinearRGB;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EColorInterpolation() const
{
    switch (m_value.valueID) {
        case CSSValueSRGB:
            return CI_SRGB;
        case CSSValueLinearRGB:
            return CI_LINEARRGB;
        case CSSValueAuto:
            return CI_AUTO;
        default:
            ASSERT_NOT_REACHED();
            return CI_AUTO;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EColorRendering e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case CR_AUTO:
            m_value.valueID = CSSValueAuto;
            break;
        case CR_OPTIMIZESPEED:
            m_value.valueID = CSSValueOptimizeSpeed;
            break;
        case CR_OPTIMIZEQUALITY:
            m_value.valueID = CSSValueOptimizeQuality;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EColorRendering() const
{
    switch (m_value.valueID) {
        case CSSValueOptimizeSpeed:
            return CR_OPTIMIZESPEED;
        case CSSValueOptimizeQuality:
            return CR_OPTIMIZEQUALITY;
        case CSSValueAuto:
            return CR_AUTO;
        default:
            ASSERT_NOT_REACHED();
            return CR_AUTO;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EDominantBaseline e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case DB_AUTO:
            m_value.valueID = CSSValueAuto;
            break;
        case DB_USE_SCRIPT:
            m_value.valueID = CSSValueUseScript;
            break;
        case DB_NO_CHANGE:
            m_value.valueID = CSSValueNoChange;
            break;
        case DB_RESET_SIZE:
            m_value.valueID = CSSValueResetSize;
            break;
        case DB_CENTRAL:
            m_value.valueID = CSSValueCentral;
            break;
        case DB_MIDDLE:
            m_value.valueID = CSSValueMiddle;
            break;
        case DB_TEXT_BEFORE_EDGE:
            m_value.valueID = CSSValueTextBeforeEdge;
            break;
        case DB_TEXT_AFTER_EDGE:
            m_value.valueID = CSSValueTextAfterEdge;
            break;
        case DB_IDEOGRAPHIC:
            m_value.valueID = CSSValueIdeographic;
            break;
        case DB_ALPHABETIC:
            m_value.valueID = CSSValueAlphabetic;
            break;
        case DB_HANGING:
            m_value.valueID = CSSValueHanging;
            break;
        case DB_MATHEMATICAL:
            m_value.valueID = CSSValueMathematical;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator EDominantBaseline() const
{
    switch (m_value.valueID) {
        case CSSValueAuto:
            return DB_AUTO;
        case CSSValueUseScript:
            return DB_USE_SCRIPT;
        case CSSValueNoChange:
            return DB_NO_CHANGE;
        case CSSValueResetSize:
            return DB_RESET_SIZE;
        case CSSValueIdeographic:
            return DB_IDEOGRAPHIC;
        case CSSValueAlphabetic:
            return DB_ALPHABETIC;
        case CSSValueHanging:
            return DB_HANGING;
        case CSSValueMathematical:
            return DB_MATHEMATICAL;
        case CSSValueCentral:
            return DB_CENTRAL;
        case CSSValueMiddle:
            return DB_MIDDLE;
        case CSSValueTextAfterEdge:
            return DB_TEXT_AFTER_EDGE;
        case CSSValueTextBeforeEdge:
            return DB_TEXT_BEFORE_EDGE;
        default:
            ASSERT_NOT_REACHED();
            return DB_AUTO;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EShapeRendering e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case SR_AUTO:
        m_value.valueID = CSSValueAuto;
        break;
    case SR_OPTIMIZESPEED:
        m_value.valueID = CSSValueOptimizeSpeed;
        break;
    case SR_CRISPEDGES:
        m_value.valueID = CSSValueCrispedges;
        break;
    case SR_GEOMETRICPRECISION:
        m_value.valueID = CSSValueGeometricPrecision;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EShapeRendering() const
{
    switch (m_value.valueID) {
    case CSSValueAuto:
        return SR_AUTO;
    case CSSValueOptimizeSpeed:
        return SR_OPTIMIZESPEED;
    case CSSValueCrispedges:
        return SR_CRISPEDGES;
    case CSSValueGeometricPrecision:
        return SR_GEOMETRICPRECISION;
    default:
        ASSERT_NOT_REACHED();
        return SR_AUTO;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(ETextAnchor e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
        case TA_START:
            m_value.valueID = CSSValueStart;
            break;
        case TA_MIDDLE:
            m_value.valueID = CSSValueMiddle;
            break;
        case TA_END:
            m_value.valueID = CSSValueEnd;
            break;
    }
}

template<> inline CSSPrimitiveValue::operator ETextAnchor() const
{
    switch (m_value.valueID) {
        case CSSValueStart:
            return TA_START;
        case CSSValueMiddle:
            return TA_MIDDLE;
        case CSSValueEnd:
            return TA_END;
        default:
            ASSERT_NOT_REACHED();
            return TA_START;
    }
}

template<> ALWAYS_INLINE CSSPrimitiveValue::CSSPrimitiveValue(EVectorEffect e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case VE_NONE:
        m_value.valueID = CSSValueNone;
        break;
    case VE_NON_SCALING_STROKE:
        m_value.valueID = CSSValueNonScalingStroke;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EVectorEffect() const
{
    switch (m_value.valueID) {
    case CSSValueNone:
        return VE_NONE;
    case CSSValueNonScalingStroke:
        return VE_NON_SCALING_STROKE;
    default:
        ASSERT_NOT_REACHED();
        return VE_NONE;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EMaskType e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (e) {
    case MT_LUMINANCE:
        m_value.valueID = CSSValueLuminance;
        break;
    case MT_ALPHA:
        m_value.valueID = CSSValueAlpha;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator EMaskType() const
{
    switch (m_value.valueID) {
    case CSSValueLuminance:
        return MT_LUMINANCE;
    case CSSValueAlpha:
        return MT_ALPHA;
    }

    ASSERT_NOT_REACHED();
    return MT_LUMINANCE;
}

#endif // ENABLE(SVG)

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ImageOrientation::Orientation e)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_DEG);
    switch (e) {
    case ImageOrientation::OriginTopLeft:
        m_value.num = 0;
        break;
    case ImageOrientation::OriginRightTop:
        m_value.num = 90;
        break;
    case ImageOrientation::OriginBottomRight:
        m_value.num = 180;
        break;
    case ImageOrientation::OriginLeftBottom:
        m_value.num = 270;
        break;
    case ImageOrientation::OriginTopRight:
    case ImageOrientation::OriginLeftTop:
    case ImageOrientation::OriginBottomLeft:
    case ImageOrientation::OriginRightBottom:
        ASSERT_NOT_REACHED();
    }
}

template<> inline CSSPrimitiveValue::operator ImageOrientation::Orientation() const
{
    ASSERT(isAngle());
    double quarters = 4 * doubleValue(CSSUnitType::CSS_TURN);
    int orientation = 3 & static_cast<int>(quarters < 0 ? floor(quarters) : ceil(quarters));
    switch (orientation) {
    case 0:
        return ImageOrientation::OriginTopLeft;
    case 1:
        return ImageOrientation::OriginRightTop;
    case 2:
        return ImageOrientation::OriginBottomRight;
    case 3:
        return ImageOrientation::OriginLeftBottom;
    default:
        ASSERT_NOT_REACHED();
        return ImageOrientation::OriginTopLeft;
    }
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CSSBoxType cssBox)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (cssBox) {
    case CSSBoxType::MarginBox:
        m_value.valueID = CSSValueMarginBox;
        break;
    case CSSBoxType::BorderBox:
        m_value.valueID = CSSValueBorderBox;
        break;
    case CSSBoxType::PaddingBox:
        m_value.valueID = CSSValuePaddingBox;
        break;
    case CSSBoxType::ContentBox:
        m_value.valueID = CSSValueContentBox;
        break;
    case CSSBoxType::FillBox:
        m_value.valueID = CSSValueFillBox;
        break;
    case CSSBoxType::StrokeBox:
        m_value.valueID = CSSValueStrokeBox;
        break;
    case CSSBoxType::ViewBox:
        m_value.valueID = CSSValueViewBox;
        break;
    case CSSBoxType::BoxMissing:
        ASSERT_NOT_REACHED();
        m_value.valueID = CSSValueNone;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator CSSBoxType() const
{
    switch (getValueID()) {
    case CSSValueMarginBox:
        return CSSBoxType::MarginBox;
    case CSSValueBorderBox:
        return CSSBoxType::BorderBox;
    case CSSValuePaddingBox:
        return CSSBoxType::PaddingBox;
    case CSSValueContentBox:
        return CSSBoxType::ContentBox;
    // The following are used in an SVG context.
    case CSSValueFillBox:
        return CSSBoxType::FillBox;
    case CSSValueStrokeBox:
        return CSSBoxType::StrokeBox;
    case CSSValueViewBox:
        return CSSBoxType::ViewBox;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return CSSBoxType::BoxMissing;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ItemPosition itemPosition)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (itemPosition) {
    case ItemPositionLegacy:
        m_value.valueID = CSSValueLegacy;
        break;
    case ItemPositionAuto:
        m_value.valueID = CSSValueAuto;
        break;
    case ItemPositionNormal:
        m_value.valueID = CSSValueNormal;
        break;
    case ItemPositionStretch:
        m_value.valueID = CSSValueStretch;
        break;
    case ItemPositionBaseline:
        m_value.valueID = CSSValueBaseline;
        break;
    case ItemPositionLastBaseline:
        m_value.valueID = CSSValueLastBaseline;
        break;
    case ItemPositionCenter:
        m_value.valueID = CSSValueCenter;
        break;
    case ItemPositionStart:
        m_value.valueID = CSSValueStart;
        break;
    case ItemPositionEnd:
        m_value.valueID = CSSValueEnd;
        break;
    case ItemPositionSelfStart:
        m_value.valueID = CSSValueSelfStart;
        break;
    case ItemPositionSelfEnd:
        m_value.valueID = CSSValueSelfEnd;
        break;
    case ItemPositionFlexStart:
        m_value.valueID = CSSValueFlexStart;
        break;
    case ItemPositionFlexEnd:
        m_value.valueID = CSSValueFlexEnd;
        break;
    case ItemPositionLeft:
        m_value.valueID = CSSValueLeft;
        break;
    case ItemPositionRight:
        m_value.valueID = CSSValueRight;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ItemPosition() const
{
    switch (m_value.valueID) {
    case CSSValueLegacy:
        return ItemPositionLegacy;
    case CSSValueAuto:
        return ItemPositionAuto;
    case CSSValueNormal:
        return ItemPositionNormal;
    case CSSValueStretch:
        return ItemPositionStretch;
    case CSSValueBaseline:
        return ItemPositionBaseline;
    case CSSValueFirstBaseline:
        return ItemPositionBaseline;
    case CSSValueLastBaseline:
        return ItemPositionLastBaseline;
    case CSSValueCenter:
        return ItemPositionCenter;
    case CSSValueStart:
        return ItemPositionStart;
    case CSSValueEnd:
        return ItemPositionEnd;
    case CSSValueSelfStart:
        return ItemPositionSelfStart;
    case CSSValueSelfEnd:
        return ItemPositionSelfEnd;
    case CSSValueFlexStart:
        return ItemPositionFlexStart;
    case CSSValueFlexEnd:
        return ItemPositionFlexEnd;
    case CSSValueLeft:
        return ItemPositionLeft;
    case CSSValueRight:
        return ItemPositionRight;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return ItemPositionAuto;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(OverflowAlignment overflowAlignment)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (overflowAlignment) {
    case OverflowAlignmentDefault:
        m_value.valueID = CSSValueDefault;
        break;
    case OverflowAlignmentUnsafe:
        m_value.valueID = CSSValueUnsafe;
        break;
    case OverflowAlignmentSafe:
        m_value.valueID = CSSValueSafe;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator OverflowAlignment() const
{
    switch (m_value.valueID) {
    case CSSValueUnsafe:
        return OverflowAlignmentUnsafe;
    case CSSValueSafe:
        return OverflowAlignmentSafe;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return OverflowAlignmentUnsafe;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ContentPosition contentPosition)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (contentPosition) {
    case ContentPositionNormal:
        m_value.valueID = CSSValueNormal;
        break;
    case ContentPositionBaseline:
        m_value.valueID = CSSValueBaseline;
        break;
    case ContentPositionLastBaseline:
        m_value.valueID = CSSValueLastBaseline;
        break;
    case ContentPositionCenter:
        m_value.valueID = CSSValueCenter;
        break;
    case ContentPositionStart:
        m_value.valueID = CSSValueStart;
        break;
    case ContentPositionEnd:
        m_value.valueID = CSSValueEnd;
        break;
    case ContentPositionFlexStart:
        m_value.valueID = CSSValueFlexStart;
        break;
    case ContentPositionFlexEnd:
        m_value.valueID = CSSValueFlexEnd;
        break;
    case ContentPositionLeft:
        m_value.valueID = CSSValueLeft;
        break;
    case ContentPositionRight:
        m_value.valueID = CSSValueRight;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ContentPosition() const
{
    switch (m_value.valueID) {
    case CSSValueNormal:
        return ContentPositionNormal;
    case CSSValueBaseline:
        return ContentPositionBaseline;
    case CSSValueFirstBaseline:
        return ContentPositionBaseline;
    case CSSValueLastBaseline:
        return ContentPositionLastBaseline;
    case CSSValueCenter:
        return ContentPositionCenter;
    case CSSValueStart:
        return ContentPositionStart;
    case CSSValueEnd:
        return ContentPositionEnd;
    case CSSValueFlexStart:
        return ContentPositionFlexStart;
    case CSSValueFlexEnd:
        return ContentPositionFlexEnd;
    case CSSValueLeft:
        return ContentPositionLeft;
    case CSSValueRight:
        return ContentPositionRight;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return ContentPositionNormal;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(ContentDistributionType contentDistribution)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (contentDistribution) {
    case ContentDistributionDefault:
        m_value.valueID = CSSValueDefault;
        break;
    case ContentDistributionSpaceBetween:
        m_value.valueID = CSSValueSpaceBetween;
        break;
    case ContentDistributionSpaceAround:
        m_value.valueID = CSSValueSpaceAround;
        break;
    case ContentDistributionSpaceEvenly:
        m_value.valueID = CSSValueSpaceEvenly;
        break;
    case ContentDistributionStretch:
        m_value.valueID = CSSValueStretch;
        break;
    }
}

template<> inline CSSPrimitiveValue::operator ContentDistributionType() const
{
    switch (m_value.valueID) {
    case CSSValueSpaceBetween:
        return ContentDistributionSpaceBetween;
    case CSSValueSpaceAround:
        return ContentDistributionSpaceAround;
    case CSSValueSpaceEvenly:
        return ContentDistributionSpaceEvenly;
    case CSSValueStretch:
        return ContentDistributionStretch;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return ContentDistributionStretch;
}

template<> inline CSSPrimitiveValue::operator TextZoom() const
{
    ASSERT(isValueID());

    switch (m_value.valueID) {
    case CSSValueNormal:
        return TextZoomNormal;
    case CSSValueReset:
        return TextZoomReset;
    default:
        break;
    }

    ASSERT_NOT_REACHED();
    return TextZoomNormal;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(TextZoom textZoom)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (textZoom) {
    case TextZoomNormal:
        m_value.valueID = CSSValueNormal;
        return;
    case TextZoomReset:
        m_value.valueID = CSSValueReset;
        return;
    }

    ASSERT_NOT_REACHED();
    m_value.valueID = CSSValueNormal;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(CSSFontFamily fontFamily)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_FONT_FAMILY);
    m_value.fontFamily = new CSSFontFamily(fontFamily);
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontLoadingBehavior behavior)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (behavior) {
    case FontLoadingBehavior::Auto:
        m_value.valueID = CSSValueAuto;
        break;
    case FontLoadingBehavior::Block:
        m_value.valueID = CSSValueBlock;
        break;
    case FontLoadingBehavior::Swap:
        m_value.valueID = CSSValueSwap;
        break;
    case FontLoadingBehavior::Fallback:
        m_value.valueID = CSSValueFallback;
        break;
    case FontLoadingBehavior::Optional:
        m_value.valueID = CSSValueOptional;
        break;
    default:
        ASSERT_NOT_REACHED();
        break;
    }
}

template<> inline CSSPrimitiveValue::operator FontLoadingBehavior() const
{
    ASSERT(isValueID());
    switch (m_value.valueID) {
    case CSSValueAuto:
        return FontLoadingBehavior::Auto;
    case CSSValueBlock:
        return FontLoadingBehavior::Block;
    case CSSValueSwap:
        return FontLoadingBehavior::Swap;
    case CSSValueFallback:
        return FontLoadingBehavior::Fallback;
    case CSSValueOptional:
        return FontLoadingBehavior::Optional;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return FontLoadingBehavior::Auto;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantPosition position)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (position) {
    case FontVariantPosition::Normal:
        m_value.valueID = CSSValueNormal;
        break;
    case FontVariantPosition::Subscript:
        m_value.valueID = CSSValueSub;
        break;
    case FontVariantPosition::Superscript:
        m_value.valueID = CSSValueSuper;
        break;
    default:
        ASSERT_NOT_REACHED();
        break;
    }
}

template<> inline CSSPrimitiveValue::operator FontVariantPosition() const
{
    ASSERT(isValueID());
    switch (m_value.valueID) {
    case CSSValueNormal:
        return FontVariantPosition::Normal;
    case CSSValueSub:
        return FontVariantPosition::Subscript;
    case CSSValueSuper:
        return FontVariantPosition::Superscript;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return FontVariantPosition::Normal;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantCaps caps)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (caps) {
    case FontVariantCaps::Normal:
        m_value.valueID = CSSValueNormal;
        break;
    case FontVariantCaps::Small:
        m_value.valueID = CSSValueSmallCaps;
        break;
    case FontVariantCaps::AllSmall:
        m_value.valueID = CSSValueAllSmallCaps;
        break;
    case FontVariantCaps::Petite:
        m_value.valueID = CSSValuePetiteCaps;
        break;
    case FontVariantCaps::AllPetite:
        m_value.valueID = CSSValueAllPetiteCaps;
        break;
    case FontVariantCaps::Unicase:
        m_value.valueID = CSSValueUnicase;
        break;
    case FontVariantCaps::Titling:
        m_value.valueID = CSSValueTitlingCaps;
        break;
    default:
        ASSERT_NOT_REACHED();
        break;
    }
}

template<> inline CSSPrimitiveValue::operator FontVariantCaps() const
{
    ASSERT(isValueID());
    switch (m_value.valueID) {
    case CSSValueNormal:
        return FontVariantCaps::Normal;
    case CSSValueSmallCaps:
        return FontVariantCaps::Small;
    case CSSValueAllSmallCaps:
        return FontVariantCaps::AllSmall;
    case CSSValuePetiteCaps:
        return FontVariantCaps::Petite;
    case CSSValueAllPetiteCaps:
        return FontVariantCaps::AllPetite;
    case CSSValueUnicase:
        return FontVariantCaps::Unicase;
    case CSSValueTitlingCaps:
        return FontVariantCaps::Titling;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return FontVariantCaps::Normal;
}

template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontVariantAlternates alternates)
    : CSSValue(PrimitiveClass)
{
    setPrimitiveUnitType(CSSUnitType::CSS_VALUE_ID);
    switch (alternates) {
    case FontVariantAlternates::Normal:
        m_value.valueID = CSSValueNormal;
        break;
    case FontVariantAlternates::HistoricalForms:
        m_value.valueID = CSSValueHistoricalForms;
        break;
    default:
        ASSERT_NOT_REACHED();
        break;
    }
}

template<> inline CSSPrimitiveValue::operator FontVariantAlternates() const
{
    ASSERT(isValueID());
    switch (m_value.valueID) {
    case CSSValueNormal:
        return FontVariantAlternates::Normal;
    case CSSValueHistoricalForms:
        return FontVariantAlternates::HistoricalForms;
    default:
        break;
    }
    ASSERT_NOT_REACHED();
    return FontVariantAlternates::Normal;
}

}
