Unreviewed, rolling out r191902.
[WebKit-https.git] / Source / WebCore / css / MediaQueryEvaluator.cpp
1 /*
2  * CSS Media Query Evaluator
3  *
4  * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>.
5  * Copyright (C) 2013 Apple Inc. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 APPLE INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, 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 THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "MediaQueryEvaluator.h"
31
32 #include "CSSAspectRatioValue.h"
33 #include "CSSPrimitiveValue.h"
34 #include "CSSToLengthConversionData.h"
35 #include "CSSValueKeywords.h"
36 #include "CSSValueList.h"
37 #include "FloatRect.h"
38 #include "FrameView.h"
39 #include "IntRect.h"
40 #include "MainFrame.h"
41 #include "MediaFeatureNames.h"
42 #include "MediaList.h"
43 #include "MediaQuery.h"
44 #include "MediaQueryExp.h"
45 #include "NodeRenderStyle.h"
46 #include "Page.h"
47 #include "PlatformScreen.h"
48 #include "RenderStyle.h"
49 #include "RenderView.h"
50 #include "Screen.h"
51 #include "Settings.h"
52 #include "StyleResolver.h"
53 #include <wtf/HashMap.h>
54
55 #if ENABLE(3D_TRANSFORMS)
56 #include "RenderLayerCompositor.h"
57 #endif
58
59 #if PLATFORM(IOS)
60 #include "WebCoreSystemInterface.h"
61 #endif
62
63 namespace WebCore {
64
65 using namespace MediaFeatureNames;
66
67 enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
68
69 typedef bool (*EvalFunc)(CSSValue*, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix);
70 typedef HashMap<AtomicStringImpl*, EvalFunc> FunctionMap;
71 static FunctionMap* gFunctionMap;
72
73 /*
74  * FIXME: following media features are not implemented: scan
75  *
76  * scan: The "scan" media feature describes the scanning process of
77  * tv output devices. It's unknown how to retrieve this information from
78  * the platform
79  */
80
81 MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
82     : m_frame(0)
83     , m_style(0)
84     , m_expResult(mediaFeatureResult)
85 {
86 }
87
88 MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult)
89     : m_mediaType(acceptedMediaType)
90     , m_frame(0)
91     , m_style(0)
92     , m_expResult(mediaFeatureResult)
93 {
94 }
95
96 MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, Frame* frame, RenderStyle* style)
97     : m_mediaType(acceptedMediaType)
98     , m_frame(frame)
99     , m_style(style)
100     , m_expResult(false) // doesn't matter when we have m_frame and m_style
101 {
102 }
103
104 MediaQueryEvaluator::~MediaQueryEvaluator()
105 {
106 }
107
108 bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const
109 {
110     return mediaTypeToMatch.isEmpty()
111         || equalIgnoringCase(mediaTypeToMatch, "all")
112         || equalIgnoringCase(mediaTypeToMatch, m_mediaType);
113 }
114
115 bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const
116 {
117     // Like mediaTypeMatch, but without the special cases for "" and "all".
118     ASSERT(mediaTypeToMatch);
119     ASSERT(mediaTypeToMatch[0] != '\0');
120     ASSERT(!equalIgnoringCase(mediaTypeToMatch, String("all")));
121     return equalIgnoringCase(mediaTypeToMatch, m_mediaType);
122 }
123
124 static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
125 {
126     return r == MediaQuery::Not ? !value : value;
127 }
128
129 bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, StyleResolver* styleResolver) const
130 {
131     if (!querySet)
132         return true;
133
134     auto& queries = querySet->queryVector();
135     if (!queries.size())
136         return true; // empty query list evaluates to true
137
138     // iterate over queries, stop if any of them eval to true (OR semantics)
139     bool result = false;
140     for (size_t i = 0; i < queries.size() && !result; ++i) {
141         MediaQuery* query = queries[i].get();
142
143         if (query->ignored())
144             continue;
145
146         if (mediaTypeMatch(query->mediaType())) {
147             auto& expressions = query->expressions();
148             // iterate through expressions, stop if any of them eval to false
149             // (AND semantics)
150             size_t j = 0;
151             for (; j < expressions.size(); ++j) {
152                 bool exprResult = eval(expressions.at(j).get());
153                 if (styleResolver && expressions.at(j)->isViewportDependent())
154                     styleResolver->addViewportDependentMediaQueryResult(expressions.at(j).get(), exprResult);
155                 if (!exprResult)
156                     break;
157             }
158
159             // assume true if we are at the end of the list,
160             // otherwise assume false
161             result = applyRestrictor(query->restrictor(), expressions.size() == j);
162         } else
163             result = applyRestrictor(query->restrictor(), false);
164     }
165
166     return result;
167 }
168
169 template<typename T>
170 bool compareValue(T a, T b, MediaFeaturePrefix op)
171 {
172     switch (op) {
173     case MinPrefix:
174         return a >= b;
175     case MaxPrefix:
176         return a <= b;
177     case NoPrefix:
178         return a == b;
179     }
180     return false;
181 }
182
183 static bool compareAspectRatioValue(CSSValue* value, int width, int height, MediaFeaturePrefix op)
184 {
185     if (is<CSSAspectRatioValue>(*value)) {
186         CSSAspectRatioValue& aspectRatio = downcast<CSSAspectRatioValue>(*value);
187         return compareValue(width * static_cast<int>(aspectRatio.denominatorValue()), height * static_cast<int>(aspectRatio.numeratorValue()), op);
188     }
189
190     return false;
191 }
192
193 static bool numberValue(CSSValue* value, float& result)
194 {
195     if (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).isNumber()) {
196         result = downcast<CSSPrimitiveValue>(*value).getFloatValue(CSSPrimitiveValue::CSS_NUMBER);
197         return true;
198     }
199     return false;
200 }
201
202 static bool colorMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix op)
203 {
204     int bitsPerComponent = screenDepthPerComponent(frame->page()->mainFrame().view());
205     float number;
206     if (value)
207         return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op);
208
209     return bitsPerComponent != 0;
210 }
211
212 static bool color_indexMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix op)
213 {
214     // FIXME: It's unknown how to retrieve the information if the display mode is indexed
215     // Assume we don't support indexed display.
216     if (!value)
217         return false;
218
219     float number;
220     return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
221 }
222
223 static bool monochromeMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix op)
224 {
225     if (!screenIsMonochrome(frame->page()->mainFrame().view())) {
226         if (value) {
227             float number;
228             return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
229         }
230         return false;
231     }
232
233     return colorMediaFeatureEval(value, conversionData, frame, op);
234 }
235
236 static bool inverted_colorsMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix)
237 {
238     bool isInverted = screenHasInvertedColors();
239
240     if (!value)
241         return isInverted;
242
243     const CSSValueID id = downcast<CSSPrimitiveValue>(*value).getValueID();
244     return (isInverted && id == CSSValueInverted) || (!isInverted && id == CSSValueNone);
245 }
246
247 static bool orientationMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix)
248 {
249     FrameView* view = frame->view();
250     if (!view)
251         return false;
252
253     int width = view->layoutWidth();
254     int height = view->layoutHeight();
255     if (is<CSSPrimitiveValue>(value)) {
256         const CSSValueID id = downcast<CSSPrimitiveValue>(*value).getValueID();
257         if (width > height) // Square viewport is portrait.
258             return CSSValueLandscape == id;
259         return CSSValuePortrait == id;
260     }
261
262     // Expression (orientation) evaluates to true if width and height >= 0.
263     return height >= 0 && width >= 0;
264 }
265
266 static bool aspect_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix op)
267 {
268     FrameView* view = frame->view();
269     if (!view)
270         return true;
271
272     if (value)
273         return compareAspectRatioValue(value, view->layoutWidth(), view->layoutHeight(), op);
274
275     // ({,min-,max-}aspect-ratio)
276     // assume if we have a device, its aspect ratio is non-zero
277     return true;
278 }
279
280 static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix op)
281 {
282     if (value) {
283         FloatRect sg = screenRect(frame->page()->mainFrame().view());
284         return compareAspectRatioValue(value, static_cast<int>(sg.width()), static_cast<int>(sg.height()), op);
285     }
286
287     // ({,min-,max-}device-aspect-ratio)
288     // assume if we have a device, its aspect ratio is non-zero
289     return true;
290 }
291
292 static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op)
293 {
294     // FIXME: Possible handle other media types than 'screen' and 'print'.
295     FrameView* view = frame->view();
296     if (!view)
297         return false;
298
299     float deviceScaleFactor = 0;
300     // This checks the actual media type applied to the document, and we know
301     // this method only got called if this media type matches the one defined
302     // in the query. Thus, if if the document's media type is "print", the
303     // media type of the query will either be "print" or "all".
304     String mediaType = view->mediaType();
305     if (equalIgnoringCase(mediaType, "screen"))
306         deviceScaleFactor = frame->page()->deviceScaleFactor();
307     else if (equalIgnoringCase(mediaType, "print")) {
308         // The resolution of images while printing should not depend on the dpi
309         // of the screen. Until we support proper ways of querying this info
310         // we use 300px which is considered minimum for current printers.
311         deviceScaleFactor = 3.125; // 300dpi / 96dpi;
312     }
313
314     if (!value)
315         return !!deviceScaleFactor;
316
317     if (!is<CSSPrimitiveValue>(*value))
318         return false;
319
320     CSSPrimitiveValue& resolution = downcast<CSSPrimitiveValue>(*value);
321     return compareValue(deviceScaleFactor, resolution.isNumber() ? resolution.getFloatValue() : resolution.getFloatValue(CSSPrimitiveValue::CSS_DPPX), op);
322 }
323
324 static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix op)
325 {
326     return (!value || downcast<CSSPrimitiveValue>(*value).isNumber()) && evalResolution(value, frame, op);
327 }
328
329 static bool resolutionMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix op)
330 {
331 #if ENABLE(RESOLUTION_MEDIA_QUERY)
332     return (!value || downcast<CSSPrimitiveValue>(*value).isResolution()) && evalResolution(value, frame, op);
333 #else
334     UNUSED_PARAM(value);
335     UNUSED_PARAM(frame);
336     UNUSED_PARAM(op);
337     return false;
338 #endif
339 }
340
341 static bool gridMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix op)
342 {
343     // if output device is bitmap, grid: 0 == true
344     // assume we have bitmap device
345     float number;
346     if (value && numberValue(value, number))
347         return compareValue(static_cast<int>(number), 0, op);
348     return false;
349 }
350
351 static bool computeLength(CSSValue* value, bool strict, const CSSToLengthConversionData& conversionData, int& result)
352 {
353     if (!is<CSSPrimitiveValue>(*value))
354         return false;
355
356     CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(*value);
357
358     if (primitiveValue.isNumber()) {
359         result = primitiveValue.getIntValue();
360         return !strict || !result;
361     }
362
363     if (primitiveValue.isLength()) {
364         result = primitiveValue.computeLength<int>(conversionData);
365         return true;
366     }
367
368     return false;
369 }
370
371 static bool device_heightMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix op)
372 {
373     if (value) {
374         FloatRect sg = screenRect(frame->page()->mainFrame().view());
375         int length;
376         long height = sg.height();
377         return computeLength(value, !frame->document()->inQuirksMode(), conversionData, length) && compareValue(static_cast<int>(height), length, op);
378     }
379     // ({,min-,max-}device-height)
380     // assume if we have a device, assume non-zero
381     return true;
382 }
383
384 static bool device_widthMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix op)
385 {
386     if (value) {
387         FloatRect sg = screenRect(frame->page()->mainFrame().view());
388         int length;
389         long width = sg.width();
390         return computeLength(value, !frame->document()->inQuirksMode(), conversionData, length) && compareValue(static_cast<int>(width), length, op);
391     }
392     // ({,min-,max-}device-width)
393     // assume if we have a device, assume non-zero
394     return true;
395 }
396
397 static bool heightMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix op)
398 {
399     FrameView* view = frame->view();
400     if (!view)
401         return false;
402
403     if (value) {
404         int height = view->layoutHeight();
405         if (RenderView* renderView = frame->document()->renderView())
406             height = adjustForAbsoluteZoom(height, *renderView);
407         int length;
408         return computeLength(value, !frame->document()->inQuirksMode(), conversionData, length) && compareValue(height, length, op);
409     }
410
411     return view->layoutHeight() != 0;
412 }
413
414 static bool widthMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix op)
415 {
416     FrameView* view = frame->view();
417     if (!view)
418         return false;
419
420     if (value) {
421         int width = view->layoutWidth();
422         if (RenderView* renderView = frame->document()->renderView())
423             width = adjustForAbsoluteZoom(width, *renderView);
424         int length;
425         return computeLength(value, !frame->document()->inQuirksMode(), conversionData, length) && compareValue(width, length, op);
426     }
427
428     return view->layoutWidth() != 0;
429 }
430
431 // rest of the functions are trampolines which set the prefix according to the media feature expression used
432
433 static bool min_colorMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
434 {
435     return colorMediaFeatureEval(value, conversionData, frame, MinPrefix);
436 }
437
438 static bool max_colorMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
439 {
440     return colorMediaFeatureEval(value, conversionData, frame, MaxPrefix);
441 }
442
443 static bool min_color_indexMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
444 {
445     return color_indexMediaFeatureEval(value, conversionData, frame, MinPrefix);
446 }
447
448 static bool max_color_indexMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
449 {
450     return color_indexMediaFeatureEval(value, conversionData, frame, MaxPrefix);
451 }
452
453 static bool min_monochromeMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
454 {
455     return monochromeMediaFeatureEval(value, conversionData, frame, MinPrefix);
456 }
457
458 static bool max_monochromeMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
459 {
460     return monochromeMediaFeatureEval(value, conversionData, frame, MaxPrefix);
461 }
462
463 static bool min_aspect_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
464 {
465     return aspect_ratioMediaFeatureEval(value, conversionData, frame, MinPrefix);
466 }
467
468 static bool max_aspect_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
469 {
470     return aspect_ratioMediaFeatureEval(value, conversionData, frame, MaxPrefix);
471 }
472
473 static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
474 {
475     return device_aspect_ratioMediaFeatureEval(value, conversionData, frame, MinPrefix);
476 }
477
478 static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
479 {
480     return device_aspect_ratioMediaFeatureEval(value, conversionData, frame, MaxPrefix);
481 }
482
483 static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
484 {
485     return device_pixel_ratioMediaFeatureEval(value, conversionData, frame, MinPrefix);
486 }
487
488 static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
489 {
490     return device_pixel_ratioMediaFeatureEval(value, conversionData, frame, MaxPrefix);
491 }
492
493 static bool min_heightMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
494 {
495     return heightMediaFeatureEval(value, conversionData, frame, MinPrefix);
496 }
497
498 static bool max_heightMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
499 {
500     return heightMediaFeatureEval(value, conversionData, frame, MaxPrefix);
501 }
502
503 static bool min_widthMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
504 {
505     return widthMediaFeatureEval(value, conversionData, frame, MinPrefix);
506 }
507
508 static bool max_widthMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
509 {
510     return widthMediaFeatureEval(value, conversionData, frame, MaxPrefix);
511 }
512
513 static bool min_device_heightMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
514 {
515     return device_heightMediaFeatureEval(value, conversionData, frame, MinPrefix);
516 }
517
518 static bool max_device_heightMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
519 {
520     return device_heightMediaFeatureEval(value, conversionData, frame, MaxPrefix);
521 }
522
523 static bool min_device_widthMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
524 {
525     return device_widthMediaFeatureEval(value, conversionData, frame, MinPrefix);
526 }
527
528 static bool max_device_widthMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
529 {
530     return device_widthMediaFeatureEval(value, conversionData, frame, MaxPrefix);
531 }
532
533 static bool min_resolutionMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
534 {
535     return resolutionMediaFeatureEval(value, conversionData, frame, MinPrefix);
536 }
537
538 static bool max_resolutionMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame* frame, MediaFeaturePrefix)
539 {
540     return resolutionMediaFeatureEval(value, conversionData, frame, MaxPrefix);
541 }
542
543 static bool animationMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix op)
544 {
545     if (value) {
546         float number;
547         return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
548     }
549     return true;
550 }
551
552 static bool transitionMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix op)
553 {
554     if (value) {
555         float number;
556         return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
557     }
558     return true;
559 }
560
561 static bool transform_2dMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix op)
562 {
563     if (value) {
564         float number;
565         return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
566     }
567     return true;
568 }
569
570 static bool transform_3dMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix op)
571 {
572     bool returnValueIfNoParameter;
573     int have3dRendering;
574
575 #if ENABLE(3D_TRANSFORMS)
576     bool threeDEnabled = false;
577     if (RenderView* view = frame->contentRenderer())
578         threeDEnabled = view->compositor().canRender3DTransforms();
579
580     returnValueIfNoParameter = threeDEnabled;
581     have3dRendering = threeDEnabled ? 1 : 0;
582 #else
583     UNUSED_PARAM(frame);
584     returnValueIfNoParameter = false;
585     have3dRendering = 0;
586 #endif
587
588     if (value) {
589         float number;
590         return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op);
591     }
592     return returnValueIfNoParameter;
593 }
594
595 #if ENABLE(VIEW_MODE_CSS_MEDIA)
596 static bool view_modeMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix op)
597 {
598     UNUSED_PARAM(op);
599     if (!value)
600         return true;
601
602     const int viewModeCSSKeywordID = downcast<CSSPrimitiveValue>(*value).getValueID();
603     const Page::ViewMode viewMode = frame->page()->viewMode();
604     bool result = false;
605     switch (viewMode) {
606     case Page::ViewModeWindowed:
607         result = viewModeCSSKeywordID == CSSValueWindowed;
608         break;
609     case Page::ViewModeFloating:
610         result = viewModeCSSKeywordID == CSSValueFloating;
611         break;
612     case Page::ViewModeFullscreen:
613         result = viewModeCSSKeywordID == CSSValueFullscreen;
614         break;
615     case Page::ViewModeMaximized:
616         result = viewModeCSSKeywordID == CSSValueMaximized;
617         break;
618     case Page::ViewModeMinimized:
619         result = viewModeCSSKeywordID == CSSValueMinimized;
620         break;
621     default:
622         result = false;
623         break;
624     }
625
626     return result;
627 }
628 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
629
630 // FIXME: Find a better place for this function. Maybe ChromeClient?
631 static inline bool isRunningOnIPhoneOrIPod()
632 {
633 #if PLATFORM(IOS)
634     static wkDeviceClass deviceClass = iosDeviceClass();
635     return deviceClass == wkDeviceClassiPhone || deviceClass == wkDeviceClassiPod;
636 #else
637     return false;
638 #endif
639 }
640
641 static bool video_playable_inlineMediaFeatureEval(CSSValue*, const CSSToLengthConversionData&, Frame* frame, MediaFeaturePrefix)
642 {
643     return !isRunningOnIPhoneOrIPod() || frame->settings().allowsInlineMediaPlayback();
644 }
645
646 static bool hoverMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix)
647 {
648     if (!is<CSSPrimitiveValue>(value)) {
649 #if ENABLE(TOUCH_EVENTS)
650         return false;
651 #else
652         return true;
653 #endif
654     }
655
656     int hoverCSSKeywordID = downcast<CSSPrimitiveValue>(*value).getValueID();
657 #if ENABLE(TOUCH_EVENTS)
658     return hoverCSSKeywordID == CSSValueNone;
659 #else
660     return hoverCSSKeywordID == CSSValueHover;
661 #endif
662 }
663
664 static bool any_hoverMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame* frame, MediaFeaturePrefix prefix)
665 {
666     return hoverMediaFeatureEval(value, cssToLengthConversionData, frame, prefix);
667 }
668
669 static bool pointerMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData&, Frame*, MediaFeaturePrefix)
670 {
671     if (!is<CSSPrimitiveValue>(value))
672         return true;
673
674     int pointerCSSKeywordID = downcast<CSSPrimitiveValue>(*value).getValueID();
675 #if ENABLE(TOUCH_EVENTS)
676     return pointerCSSKeywordID == CSSValueCoarse;
677 #else
678     return pointerCSSKeywordID == CSSValueFine;
679 #endif
680 }
681
682 static bool any_pointerMediaFeatureEval(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame* frame, MediaFeaturePrefix prefix)
683 {
684     return pointerMediaFeatureEval(value, cssToLengthConversionData, frame, prefix);
685 }
686
687 // FIXME: Remove unnecessary '&' from the following 'ADD_TO_FUNCTIONMAP' definition
688 // once we switch to a non-broken Visual Studio compiler.  https://bugs.webkit.org/show_bug.cgi?id=121235
689 static void createFunctionMap()
690 {
691     // Create the table.
692     gFunctionMap = new FunctionMap;
693 #define ADD_TO_FUNCTIONMAP(name, str)  \
694     gFunctionMap->set(name##MediaFeature.impl(), &name##MediaFeatureEval);
695     CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP);
696 #undef ADD_TO_FUNCTIONMAP
697 }
698
699 bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const
700 {
701     if (!m_frame || !m_frame->view() || !m_style)
702         return m_expResult;
703
704     if (!expr->isValid())
705         return false;
706
707     if (!gFunctionMap)
708         createFunctionMap();
709
710     // call the media feature evaluation function. Assume no prefix
711     // and let trampoline functions override the prefix if prefix is
712     // used
713     EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl());
714     if (func) {
715         CSSToLengthConversionData conversionData(m_style.get(),
716             m_frame->document()->documentElement()->renderStyle(),
717             m_frame->document()->renderView(), 1, false);
718         return func(expr->value(), conversionData, m_frame, NoPrefix);
719     }
720
721     return false;
722 }
723
724 } // namespace