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 "core/CSSValueKeywords.h"
34#include "core/css/CSSPrimitiveValueMappings.h"
35#include "core/css/CSSToLengthConversionData.h"
36#include "core/css/StylePropertySet.h"
37#include "core/css/StyleRule.h"
38#include "core/dom/Document.h"
39#include "core/dom/NodeRenderStyle.h"
40#include "core/dom/ViewportDescription.h"
41#include "core/frame/FrameView.h"
42
43namespace blink {
44
45DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(ViewportStyleResolver);
46
47ViewportStyleResolver::ViewportStyleResolver(Document* document)
48    : m_document(document)
49    , m_hasAuthorStyle(false)
50{
51    ASSERT(m_document);
52}
53
54void ViewportStyleResolver::collectViewportRules(RuleSet* rules, Origin origin)
55{
56    rules->compactRulesIfNeeded();
57
58    const WillBeHeapVector<RawPtrWillBeMember<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::resolve()
86{
87    if (!m_document)
88        return;
89
90    if (!m_propertySet) {
91        m_document->setViewportDescription(ViewportDescription(ViewportDescription::UserAgentStyleSheet));
92        return;
93    }
94
95    ViewportDescription description(m_hasAuthorStyle ? ViewportDescription::AuthorStyleSheet : ViewportDescription::UserAgentStyleSheet);
96
97    description.userZoom = viewportArgumentValue(CSSPropertyUserZoom);
98    description.zoom = viewportArgumentValue(CSSPropertyZoom);
99    description.minZoom = viewportArgumentValue(CSSPropertyMinZoom);
100    description.maxZoom = viewportArgumentValue(CSSPropertyMaxZoom);
101    description.minWidth = viewportLengthValue(CSSPropertyMinWidth);
102    description.maxWidth = viewportLengthValue(CSSPropertyMaxWidth);
103    description.minHeight = viewportLengthValue(CSSPropertyMinHeight);
104    description.maxHeight = viewportLengthValue(CSSPropertyMaxHeight);
105    description.orientation = viewportArgumentValue(CSSPropertyOrientation);
106
107    m_document->setViewportDescription(description);
108
109    m_propertySet = nullptr;
110    m_hasAuthorStyle = false;
111}
112
113float ViewportStyleResolver::viewportArgumentValue(CSSPropertyID id) const
114{
115    float defaultValue = ViewportDescription::ValueAuto;
116
117    // UserZoom default value is CSSValueZoom, which maps to true, meaning that
118    // yes, it is user scalable. When the value is set to CSSValueFixed, we
119    // return false.
120    if (id == CSSPropertyUserZoom)
121        defaultValue = 1;
122
123    RefPtrWillBeRawPtr<CSSValue> value = m_propertySet->getPropertyCSSValue(id);
124    if (!value || !value->isPrimitiveValue())
125        return defaultValue;
126
127    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value.get());
128
129    if (primitiveValue->isNumber() || primitiveValue->isPx())
130        return primitiveValue->getFloatValue();
131
132    if (primitiveValue->isFontRelativeLength())
133        return primitiveValue->getFloatValue() * m_document->renderStyle()->fontDescription().computedSize();
134
135    if (primitiveValue->isPercentage()) {
136        float percentValue = primitiveValue->getFloatValue() / 100.0f;
137        switch (id) {
138        case CSSPropertyMaxZoom:
139        case CSSPropertyMinZoom:
140        case CSSPropertyZoom:
141            return percentValue;
142        default:
143            ASSERT_NOT_REACHED();
144            break;
145        }
146    }
147
148    switch (primitiveValue->getValueID()) {
149    case CSSValueAuto:
150        return defaultValue;
151    case CSSValueLandscape:
152        return ViewportDescription::ValueLandscape;
153    case CSSValuePortrait:
154        return ViewportDescription::ValuePortrait;
155    case CSSValueZoom:
156        return defaultValue;
157    case CSSValueInternalExtendToZoom:
158        return ViewportDescription::ValueExtendToZoom;
159    case CSSValueFixed:
160        return 0;
161    default:
162        return defaultValue;
163    }
164}
165
166Length ViewportStyleResolver::viewportLengthValue(CSSPropertyID id) const
167{
168    ASSERT(id == CSSPropertyMaxHeight
169        || id == CSSPropertyMinHeight
170        || id == CSSPropertyMaxWidth
171        || id == CSSPropertyMinWidth);
172
173    RefPtrWillBeRawPtr<CSSValue> value = m_propertySet->getPropertyCSSValue(id);
174    if (!value || !value->isPrimitiveValue())
175        return Length(); // auto
176
177    CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value.get());
178
179    if (primitiveValue->getValueID() == CSSValueInternalExtendToZoom)
180        return Length(ExtendToZoom);
181
182    RenderStyle* documentStyle = m_document->renderStyle();
183
184    // If we have viewport units the conversion will mark the document style as having viewport units.
185    bool documentStyleHasViewportUnits = documentStyle->hasViewportUnits();
186    documentStyle->setHasViewportUnits(false);
187
188    FrameView* view = m_document->view();
189    float width = view ? view->width() : 0;
190    float height = view ? view->height() : 0;
191
192    Length result = primitiveValue->convertToLength<AnyConversion>(CSSToLengthConversionData(documentStyle, documentStyle, width, height, 1.0f));
193    if (documentStyle->hasViewportUnits())
194        m_document->setHasViewportUnits();
195    documentStyle->setHasViewportUnits(documentStyleHasViewportUnits);
196
197    return result;
198}
199
200void ViewportStyleResolver::trace(Visitor* visitor)
201{
202    visitor->trace(m_propertySet);
203    visitor->trace(m_document);
204}
205
206} // namespace blink
207