12949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project/*
22949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * CSS Media Query Evaluator
32949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project *
42949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>.
52949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project *
62949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * Redistribution and use in source and binary forms, with or without
72949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * modification, are permitted provided that the following conditions
82949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * are met:
92949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
102949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
112949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
122949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
132949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project *    documentation and/or other materials provided with the distribution.
142949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project *
152949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
162949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
182949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
192949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
202949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
212949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
222949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
232949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
252949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project */
272949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
282949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "config.h"
292949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaQueryEvaluator.h"
302949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
312949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "Chrome.h"
322949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "ChromeClient.h"
332949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "CSSPrimitiveValue.h"
342949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "CSSStyleSelector.h"
352949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "CSSValueList.h"
362949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "FloatRect.h"
372949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "Frame.h"
382949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "FrameView.h"
392949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "IntRect.h"
402949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaFeatureNames.h"
412949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaList.h"
422949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaQuery.h"
432949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaQueryExp.h"
442949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "NodeRenderStyle.h"
452949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "Page.h"
462949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "RenderView.h"
472949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "RenderStyle.h"
482949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "PlatformScreen.h"
492949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include <wtf/HashMap.h>
502949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
512949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#if ENABLE(3D_RENDERING) && USE(ACCELERATED_COMPOSITING)
522949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "RenderLayerCompositor.h"
532949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#endif
542949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
552949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectnamespace WebCore {
562949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
572949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectusing namespace MediaFeatureNames;
582949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
592949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectenum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
602949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
612949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projecttypedef bool (*EvalFunc)(CSSValue*, RenderStyle*, Frame*, MediaFeaturePrefix);
622949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projecttypedef HashMap<AtomicStringImpl*, EvalFunc> FunctionMap;
632949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectstatic FunctionMap* gFunctionMap;
642949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
652949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project/*
662949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * FIXME: following media features are not implemented: color_index, scan, resolution
672949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project *
682949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * color_index, min-color-index, max_color_index: It's unknown how to retrieve
692949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * the information if the display mode is indexed
702949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * scan: The "scan" media feature describes the scanning process of
712949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * tv output devices. It's unknown how to retrieve this information from
722949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * the platform
732949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * resolution, min-resolution, max-resolution: css parser doesn't seem to
742949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * support CSS_DIMENSION
752949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project */
762949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
772949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
782949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    : m_frame(0)
792949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_style(0)
802949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_expResult(mediaFeatureResult)
812949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{
822949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project}
832949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
842949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator:: MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult)
852949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    : m_mediaType(acceptedMediaType)
862949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_frame(0)
872949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_style(0)
882949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_expResult(mediaFeatureResult)
892949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{
902949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project}
912949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
922949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator:: MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult)
932949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    : m_mediaType(acceptedMediaType)
942949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_frame(0)
952949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_style(0)
962949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_expResult(mediaFeatureResult)
972949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{
982949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project}
992949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
1002949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator:: MediaQueryEvaluator(const String& acceptedMediaType, Frame* frame, RenderStyle* style)
1012949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    : m_mediaType(acceptedMediaType)
1022949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_frame(frame)
1032949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_style(style)
1042949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    , m_expResult(false) // doesn't matter when we have m_frame and m_style
1052949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{
1062949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project}
1072949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
1082949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator::~MediaQueryEvaluator()
1092949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{
1102949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project}
1112949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
1122949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectbool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const
1132949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{
1142949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    return mediaTypeToMatch.isEmpty()
1152949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project        || equalIgnoringCase(mediaTypeToMatch, "all")
1162949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project        || equalIgnoringCase(mediaTypeToMatch, m_mediaType);
1172949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project}
1182949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
1192949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectbool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const
1202949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{
1212949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    // Like mediaTypeMatch, but without the special cases for "" and "all".
1222949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    ASSERT(mediaTypeToMatch);
1232949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    ASSERT(mediaTypeToMatch[0] != '\0');
1242949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    ASSERT(!equalIgnoringCase(mediaTypeToMatch, String("all")));
1252949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project    return equalIgnoringCase(mediaTypeToMatch, m_mediaType);
1262949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project}
1272949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project
128static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
129{
130    return r == MediaQuery::Not ? !value : value;
131}
132
133bool MediaQueryEvaluator::eval(const MediaList* mediaList, CSSStyleSelector* styleSelector) const
134{
135    if (!mediaList)
136        return true;
137
138    const Vector<MediaQuery*>& queries = mediaList->mediaQueries();
139    if (!queries.size())
140        return true; // empty query list evaluates to true
141
142    // iterate over queries, stop if any of them eval to true (OR semantics)
143    bool result = false;
144    for (size_t i = 0; i < queries.size() && !result; ++i) {
145        MediaQuery* query = queries.at(i);
146
147        if (query->ignored())
148            continue;
149
150        if (mediaTypeMatch(query->mediaType())) {
151            const Vector<OwnPtr<MediaQueryExp> >* exps = query->expressions();
152            // iterate through expressions, stop if any of them eval to false
153            // (AND semantics)
154            size_t j = 0;
155            for (; j < exps->size(); ++j) {
156                bool exprResult = eval(exps->at(j).get());
157                if (styleSelector && exps->at(j)->isViewportDependent())
158                    styleSelector->addViewportDependentMediaQueryResult(exps->at(j).get(), exprResult);
159                if (!exprResult)
160                    break;
161            }
162
163            // assume true if we are at the end of the list,
164            // otherwise assume false
165            result = applyRestrictor(query->restrictor(), exps->size() == j);
166        } else
167            result = applyRestrictor(query->restrictor(), false);
168    }
169
170    return result;
171}
172
173static bool parseAspectRatio(CSSValue* value, int& h, int& v)
174{
175    if (value->isValueList()) {
176        CSSValueList* valueList = static_cast<CSSValueList*>(value);
177        if (valueList->length() == 3) {
178            CSSValue* i0 = valueList->itemWithoutBoundsCheck(0);
179            CSSValue* i1 = valueList->itemWithoutBoundsCheck(1);
180            CSSValue* i2 = valueList->itemWithoutBoundsCheck(2);
181            if (i0->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i0)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER
182                && i1->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i1)->primitiveType() == CSSPrimitiveValue::CSS_STRING
183                && i2->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i2)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) {
184                String str = static_cast<CSSPrimitiveValue*>(i1)->getStringValue();
185                if (!str.isNull() && str.length() == 1 && str[0] == '/') {
186                    h = static_cast<CSSPrimitiveValue*>(i0)->getIntValue(CSSPrimitiveValue::CSS_NUMBER);
187                    v = static_cast<CSSPrimitiveValue*>(i2)->getIntValue(CSSPrimitiveValue::CSS_NUMBER);
188                    return true;
189                }
190            }
191        }
192    }
193    return false;
194}
195
196template<typename T>
197bool compareValue(T a, T b, MediaFeaturePrefix op)
198{
199    switch (op) {
200    case MinPrefix:
201        return a >= b;
202    case MaxPrefix:
203        return a <= b;
204    case NoPrefix:
205        return a == b;
206    }
207    return false;
208}
209
210static bool numberValue(CSSValue* value, float& result)
211{
212    if (value->isPrimitiveValue()
213        && static_cast<CSSPrimitiveValue*>(value)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) {
214        result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER);
215        return true;
216    }
217    return false;
218}
219
220static bool colorMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
221{
222    int bitsPerComponent = screenDepthPerComponent(frame->page()->mainFrame()->view());
223    float number;
224    if (value)
225        return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op);
226
227    return bitsPerComponent != 0;
228}
229
230static bool monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
231{
232    if (!screenIsMonochrome(frame->page()->mainFrame()->view())) {
233        if (value) {
234            float number;
235            return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
236        }
237        return false;
238    }
239
240    return colorMediaFeatureEval(value, style, frame, op);
241}
242
243static bool orientationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix)
244{
245    // A missing parameter should fail
246    if (!value)
247        return false;
248
249    FrameView* view = frame->view();
250    int width = view->layoutWidth();
251    int height = view->layoutHeight();
252    if (width > height) // Square viewport is portrait
253        return "landscape" == static_cast<CSSPrimitiveValue*>(value)->getStringValue();
254    return "portrait" == static_cast<CSSPrimitiveValue*>(value)->getStringValue();
255}
256
257static bool aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
258{
259    if (value) {
260        FrameView* view = frame->view();
261        int width = view->layoutWidth();
262        int height = view->layoutHeight();
263        int h = 0;
264        int v = 0;
265        if (parseAspectRatio(value, h, v))
266            return v != 0 && compareValue(width * v, height * h, op);
267        return false;
268    }
269
270    // ({,min-,max-}aspect-ratio)
271    // assume if we have a device, its aspect ratio is non-zero
272    return true;
273}
274
275static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
276{
277    if (value) {
278        FloatRect sg = screenRect(frame->page()->mainFrame()->view());
279        int h = 0;
280        int v = 0;
281        if (parseAspectRatio(value, h, v))
282            return v != 0  && compareValue(static_cast<int>(sg.width()) * v, static_cast<int>(sg.height()) * h, op);
283        return false;
284    }
285
286    // ({,min-,max-}device-aspect-ratio)
287    // assume if we have a device, its aspect ratio is non-zero
288    return true;
289}
290
291static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
292{
293    if (value)
294        return value->isPrimitiveValue() && compareValue(frame->page()->chrome()->scaleFactor(), static_cast<CSSPrimitiveValue*>(value)->getFloatValue(), op);
295
296    return frame->page()->chrome()->scaleFactor() != 0;
297}
298
299static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
300{
301    // if output device is bitmap, grid: 0 == true
302    // assume we have bitmap device
303    float number;
304    if (value && numberValue(value, number))
305        return compareValue(static_cast<int>(number), 0, op);
306    return false;
307}
308
309static bool device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
310{
311    if (value) {
312        FloatRect sg = screenRect(frame->page()->mainFrame()->view());
313        RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle();
314        return value->isPrimitiveValue() && compareValue(static_cast<int>(sg.height()), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op);
315    }
316    // ({,min-,max-}device-height)
317    // assume if we have a device, assume non-zero
318    return true;
319}
320
321static bool device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
322{
323    if (value) {
324        FloatRect sg = screenRect(frame->page()->mainFrame()->view());
325        RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle();
326        return value->isPrimitiveValue() && compareValue(static_cast<int>(sg.width()), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op);
327    }
328    // ({,min-,max-}device-width)
329    // assume if we have a device, assume non-zero
330    return true;
331}
332
333static bool heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
334{
335    FrameView* view = frame->view();
336    RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle();
337
338    if (value)
339        return value->isPrimitiveValue() && compareValue(view->layoutHeight(), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op);
340
341    return view->layoutHeight() != 0;
342}
343
344static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
345{
346    FrameView* view = frame->view();
347    RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle();
348
349    if (value)
350        return value->isPrimitiveValue() && compareValue(view->layoutWidth(), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op);
351
352    return view->layoutWidth() != 0;
353}
354
355// rest of the functions are trampolines which set the prefix according to the media feature expression used
356
357static bool min_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
358{
359    return colorMediaFeatureEval(value, style, frame, MinPrefix);
360}
361
362static bool max_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
363{
364    return colorMediaFeatureEval(value, style, frame, MaxPrefix);
365}
366
367static bool min_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
368{
369    return monochromeMediaFeatureEval(value, style, frame, MinPrefix);
370}
371
372static bool max_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
373{
374    return monochromeMediaFeatureEval(value, style, frame, MaxPrefix);
375}
376
377static bool min_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
378{
379    return aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix);
380}
381
382static bool max_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
383{
384    return aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix);
385}
386
387static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
388{
389    return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix);
390}
391
392static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
393{
394    return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix);
395}
396
397static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
398{
399    return device_pixel_ratioMediaFeatureEval(value, style, frame, MinPrefix);
400}
401
402static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
403{
404    return device_pixel_ratioMediaFeatureEval(value, style, frame, MaxPrefix);
405}
406
407static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
408{
409    return heightMediaFeatureEval(value, style, frame, MinPrefix);
410}
411
412static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
413{
414    return heightMediaFeatureEval(value, style, frame, MaxPrefix);
415}
416
417static bool min_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
418{
419    return widthMediaFeatureEval(value, style, frame, MinPrefix);
420}
421
422static bool max_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
423{
424    return widthMediaFeatureEval(value, style, frame, MaxPrefix);
425}
426
427static bool min_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
428{
429    return device_heightMediaFeatureEval(value, style, frame, MinPrefix);
430}
431
432static bool max_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
433{
434    return device_heightMediaFeatureEval(value, style, frame, MaxPrefix);
435}
436
437static bool min_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
438{
439    return device_widthMediaFeatureEval(value, style, frame, MinPrefix);
440}
441
442static bool max_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
443{
444    return device_widthMediaFeatureEval(value, style, frame, MaxPrefix);
445}
446
447static bool animationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
448{
449    if (value) {
450        float number;
451        return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
452    }
453    return true;
454}
455
456static bool transitionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
457{
458    if (value) {
459        float number;
460        return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
461    }
462    return true;
463}
464
465static bool transform_2dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
466{
467    if (value) {
468        float number;
469        return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
470    }
471    return true;
472}
473
474static bool transform_3dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
475{
476    bool returnValueIfNoParameter;
477    int have3dRendering;
478
479#if ENABLE(3D_RENDERING)
480    bool threeDEnabled = false;
481#if USE(ACCELERATED_COMPOSITING)
482    if (RenderView* view = frame->contentRenderer())
483        threeDEnabled = view->compositor()->canRender3DTransforms();
484#endif
485
486    returnValueIfNoParameter = threeDEnabled;
487    have3dRendering = threeDEnabled ? 1 : 0;
488#else
489    UNUSED_PARAM(frame);
490    returnValueIfNoParameter = false;
491    have3dRendering = 0;
492#endif
493
494    if (value) {
495        float number;
496        return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op);
497    }
498    return returnValueIfNoParameter;
499}
500
501static bool view_modeMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
502{
503    UNUSED_PARAM(op);
504    if (!value)
505        return true;
506    return Page::stringToViewMode(static_cast<CSSPrimitiveValue*>(value)->getStringValue()) == frame->page()->viewMode();
507}
508
509static void createFunctionMap()
510{
511    // Create the table.
512    gFunctionMap = new FunctionMap;
513#define ADD_TO_FUNCTIONMAP(name, str)  \
514    gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval);
515    CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP);
516#undef ADD_TO_FUNCTIONMAP
517}
518
519bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const
520{
521    if (!m_frame || !m_style)
522        return m_expResult;
523
524    if (!expr->isValid())
525        return false;
526
527    if (!gFunctionMap)
528        createFunctionMap();
529
530    // call the media feature evaluation function. Assume no prefix
531    // and let trampoline functions override the prefix if prefix is
532    // used
533    EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl());
534    if (func)
535        return func(expr->value(), m_style, m_frame, NoPrefix);
536
537    return false;
538}
539
540} // namespace
541