1/*
2 * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 *    copyright notice, this list of conditions and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 *    copyright notice, this list of conditions and the following
13 *    disclaimer in the documentation and/or other materials
14 *    provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "core/css/resolver/ViewportStyleResolver.h"
32
33#include "CSSValueKeywords.h"
34#include "core/css/CSSToLengthConversionData.h"
35#include "core/css/StylePropertySet.h"
36#include "core/css/StyleRule.h"
37#include "core/dom/Document.h"
38#include "core/dom/NodeRenderStyle.h"
39#include "core/dom/ViewportDescription.h"
40
41namespace WebCore {
42
43ViewportStyleResolver::ViewportStyleResolver(Document* document)
44    : m_document(document),
45    m_hasAuthorStyle(false)
46{
47    ASSERT(m_document);
48}
49
50ViewportStyleResolver::~ViewportStyleResolver()
51{
52}
53
54void ViewportStyleResolver::collectViewportRules(RuleSet* rules, Origin origin)
55{
56    rules->compactRulesIfNeeded();
57
58    const Vector<StyleRuleViewport*>& viewportRules = rules->viewportRules();
59    for (size_t i = 0; i < viewportRules.size(); ++i)
60        addViewportRule(viewportRules[i], origin);
61}
62
63void ViewportStyleResolver::addViewportRule(StyleRuleViewport* viewportRule, Origin origin)
64{
65    StylePropertySet* propertySet = viewportRule->mutableProperties();
66
67    unsigned propertyCount = propertySet->propertyCount();
68    if (!propertyCount)
69        return;
70
71    if (origin == AuthorOrigin)
72        m_hasAuthorStyle = true;
73
74    if (!m_propertySet) {
75        m_propertySet = propertySet->mutableCopy();
76        return;
77    }
78
79    // We cannot use mergeAndOverrideOnConflict() here because it doesn't
80    // respect the !important declaration (but addParsedProperty() does).
81    for (unsigned i = 0; i < propertyCount; ++i)
82        m_propertySet->addParsedProperty(propertySet->propertyAt(i).toCSSProperty());
83}
84
85void ViewportStyleResolver::clearDocument()
86{
87    m_document = 0;
88}
89
90void ViewportStyleResolver::resolve()
91{
92    if (!m_document)
93        return;
94
95    if (!m_propertySet || (!m_hasAuthorStyle && m_document->hasLegacyViewportTag())) {
96        ASSERT(!m_hasAuthorStyle);
97        m_propertySet = 0;
98        m_document->setViewportDescription(ViewportDescription());
99        return;
100    }
101
102    ViewportDescription description(m_hasAuthorStyle ? ViewportDescription::AuthorStyleSheet : ViewportDescription::UserAgentStyleSheet);
103
104    description.userZoom = viewportArgumentValue(CSSPropertyUserZoom);
105    description.zoom = viewportArgumentValue(CSSPropertyZoom);
106    description.minZoom = viewportArgumentValue(CSSPropertyMinZoom);
107    description.maxZoom = viewportArgumentValue(CSSPropertyMaxZoom);
108    description.minWidth = viewportLengthValue(CSSPropertyMinWidth);
109    description.maxWidth = viewportLengthValue(CSSPropertyMaxWidth);
110    description.minHeight = viewportLengthValue(CSSPropertyMinHeight);
111    description.maxHeight = viewportLengthValue(CSSPropertyMaxHeight);
112    description.orientation = viewportArgumentValue(CSSPropertyOrientation);
113
114    m_document->setViewportDescription(description);
115
116    m_propertySet = 0;
117    m_hasAuthorStyle = false;
118}
119
120float ViewportStyleResolver::viewportArgumentValue(CSSPropertyID id) const
121{
122    float defaultValue = ViewportDescription::ValueAuto;
123
124    // UserZoom default value is CSSValueZoom, which maps to true, meaning that
125    // yes, it is user scalable. When the value is set to CSSValueFixed, we
126    // return false.
127    if (id == CSSPropertyUserZoom)
128        defaultValue = 1;
129
130    RefPtr<CSSValue> value = m_propertySet->getPropertyCSSValue(id);
131    if (!value || !value->isPrimitiveValue())
132        return defaultValue;
133
134    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value.get());
135
136    if (primitiveValue->isNumber() || primitiveValue->isPx())
137        return primitiveValue->getFloatValue();
138
139    if (primitiveValue->isFontRelativeLength())
140        return primitiveValue->getFloatValue() * m_document->renderStyle()->fontDescription().computedSize();
141
142    if (primitiveValue->isPercentage()) {
143        float percentValue = primitiveValue->getFloatValue() / 100.0f;
144        switch (id) {
145        case CSSPropertyMaxZoom:
146        case CSSPropertyMinZoom:
147        case CSSPropertyZoom:
148            return percentValue;
149        default:
150            ASSERT_NOT_REACHED();
151            break;
152        }
153    }
154
155    switch (primitiveValue->getValueID()) {
156    case CSSValueAuto:
157        return defaultValue;
158    case CSSValueLandscape:
159        return ViewportDescription::ValueLandscape;
160    case CSSValuePortrait:
161        return ViewportDescription::ValuePortrait;
162    case CSSValueZoom:
163        return defaultValue;
164    case CSSValueInternalExtendToZoom:
165        return ViewportDescription::ValueExtendToZoom;
166    case CSSValueFixed:
167        return 0;
168    default:
169        return defaultValue;
170    }
171}
172
173Length ViewportStyleResolver::viewportLengthValue(CSSPropertyID id) const
174{
175    ASSERT(id == CSSPropertyMaxHeight
176        || id == CSSPropertyMinHeight
177        || id == CSSPropertyMaxWidth
178        || id == CSSPropertyMinWidth);
179
180    RefPtr<CSSValue> value = m_propertySet->getPropertyCSSValue(id);
181    if (!value || !value->isPrimitiveValue())
182        return Length(); // auto
183
184    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value.get());
185
186    if (primitiveValue->isLength())
187        return primitiveValue->computeLength<Length>(CSSToLengthConversionData(m_document->renderStyle(), m_document->renderStyle(), 1.0f));
188
189    if (primitiveValue->isViewportPercentageLength())
190        return primitiveValue->viewportPercentageLength();
191
192    if (primitiveValue->isPercentage())
193        return Length(primitiveValue->getFloatValue(), Percent);
194
195    switch (primitiveValue->getValueID()) {
196    case CSSValueInternalExtendToZoom:
197        return Length(ExtendToZoom);
198    case CSSValueAuto:
199        return Length();
200    default:
201        // Unrecognized keyword.
202        ASSERT_NOT_REACHED();
203        return Length(0, Fixed);
204    }
205}
206
207} // namespace WebCore
208