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