51a484090713c2c6d3413ab404e1e0cd227137a3
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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  * Copyright (C) 2013 Intel Corporation. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "core/css/MediaQueryEvaluator.h"
32
33 #include "core/CSSValueKeywords.h"
34 #include "core/MediaFeatureNames.h"
35 #include "core/MediaFeatures.h"
36 #include "core/MediaTypeNames.h"
37 #include "core/css/CSSAspectRatioValue.h"
38 #include "core/css/CSSHelper.h"
39 #include "core/css/CSSPrimitiveValue.h"
40 #include "core/css/CSSToLengthConversionData.h"
41 #include "core/css/MediaList.h"
42 #include "core/css/MediaQuery.h"
43 #include "core/css/MediaValuesDynamic.h"
44 #include "core/css/resolver/MediaQueryResult.h"
45 #include "core/dom/NodeRenderStyle.h"
46 #include "core/frame/FrameHost.h"
47 #include "core/frame/FrameView.h"
48 #include "core/frame/LocalFrame.h"
49 #include "core/frame/Settings.h"
50 #include "core/inspector/InspectorInstrumentation.h"
51 #include "core/rendering/RenderView.h"
52 #include "core/rendering/compositing/RenderLayerCompositor.h"
53 #include "core/rendering/style/RenderStyle.h"
54 #include "platform/PlatformScreen.h"
55 #include "platform/geometry/FloatRect.h"
56 #include "wtf/HashMap.h"
57
58 namespace WebCore {
59
60 using namespace MediaFeatureNames;
61
62 enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
63
64 typedef bool (*EvalFunc)(const MediaQueryExpValue&, MediaFeaturePrefix, const MediaValues&);
65 typedef HashMap<StringImpl*, EvalFunc> FunctionMap;
66 static FunctionMap* gFunctionMap;
67
68 MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
69     : m_expectedResult(mediaFeatureResult)
70 {
71 }
72
73 MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult)
74     : m_mediaType(acceptedMediaType)
75     , m_expectedResult(mediaFeatureResult)
76 {
77 }
78
79 MediaQueryEvaluator::MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult)
80     : m_mediaType(acceptedMediaType)
81     , m_expectedResult(mediaFeatureResult)
82 {
83 }
84
85 MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, LocalFrame* frame)
86     : m_mediaType(acceptedMediaType)
87     , m_expectedResult(false) // Doesn't matter when we have m_frame and m_style.
88     , m_mediaValues(MediaValues::createDynamicIfFrameExists(frame))
89 {
90 }
91
92 MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, const MediaValues& mediaValues)
93     : m_mediaType(acceptedMediaType)
94     , m_expectedResult(false) // Doesn't matter when we have mediaValues.
95     , m_mediaValues(mediaValues.copy())
96 {
97 }
98
99 MediaQueryEvaluator::~MediaQueryEvaluator()
100 {
101 }
102
103 bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const
104 {
105     return mediaTypeToMatch.isEmpty()
106         || equalIgnoringCase(mediaTypeToMatch, MediaTypeNames::all)
107         || equalIgnoringCase(mediaTypeToMatch, m_mediaType);
108 }
109
110 bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const
111 {
112     // Like mediaTypeMatch, but without the special cases for "" and "all".
113     ASSERT(mediaTypeToMatch);
114     ASSERT(mediaTypeToMatch[0] != '\0');
115     ASSERT(!equalIgnoringCase(mediaTypeToMatch, MediaTypeNames::all));
116     return equalIgnoringCase(mediaTypeToMatch, m_mediaType);
117 }
118
119 static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
120 {
121     return r == MediaQuery::Not ? !value : value;
122 }
123
124 bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, MediaQueryResultList* viewportDependentMediaQueryResults) const
125 {
126     if (!querySet)
127         return true;
128
129     const WillBeHeapVector<OwnPtrWillBeMember<MediaQuery> >& queries = querySet->queryVector();
130     if (!queries.size())
131         return true; // Empty query list evaluates to true.
132
133     // Iterate over queries, stop if any of them eval to true (OR semantics).
134     bool result = false;
135     for (size_t i = 0; i < queries.size() && !result; ++i) {
136         MediaQuery* query = queries[i].get();
137
138         if (mediaTypeMatch(query->mediaType())) {
139             const ExpressionHeapVector& expressions = query->expressions();
140             // Iterate through expressions, stop if any of them eval to false (AND semantics).
141             size_t j = 0;
142             for (; j < expressions.size(); ++j) {
143                 bool exprResult = eval(expressions.at(j).get());
144                 if (viewportDependentMediaQueryResults && expressions.at(j)->isViewportDependent())
145                     viewportDependentMediaQueryResults->append(adoptRefWillBeNoop(new MediaQueryResult(*expressions.at(j), exprResult)));
146                 if (!exprResult)
147                     break;
148             }
149
150             // Assume true if we are at the end of the list, otherwise assume false.
151             result = applyRestrictor(query->restrictor(), expressions.size() == j);
152         } else {
153             result = applyRestrictor(query->restrictor(), false);
154         }
155     }
156
157     return result;
158 }
159
160 template<typename T>
161 bool compareValue(T a, T b, MediaFeaturePrefix op)
162 {
163     switch (op) {
164     case MinPrefix:
165         return a >= b;
166     case MaxPrefix:
167         return a <= b;
168     case NoPrefix:
169         return a == b;
170     }
171     return false;
172 }
173
174 static bool compareAspectRatioValue(const MediaQueryExpValue& value, int width, int height, MediaFeaturePrefix op)
175 {
176     if (value.isRatio)
177         return compareValue(width * static_cast<int>(value.denominator), height * static_cast<int>(value.numerator), op);
178
179     return false;
180 }
181
182 static bool numberValue(const MediaQueryExpValue& value, float& result)
183 {
184     if (value.isValue && value.unit == CSSPrimitiveValue::CSS_NUMBER) {
185         result = value.value;
186         return true;
187     }
188     return false;
189 }
190
191 static bool colorMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
192 {
193     float number;
194     int bitsPerComponent = mediaValues.colorBitsPerComponent();
195     if (value.isValid())
196         return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op);
197
198     return bitsPerComponent != 0;
199 }
200
201 static bool colorIndexMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues&)
202 {
203     // FIXME: We currently assume that we do not support indexed displays, as it is unknown
204     // how to retrieve the information if the display mode is indexed. This matches Firefox.
205     if (!value.isValid())
206         return false;
207
208     // Acording to spec, if the device does not use a color lookup table, the value is zero.
209     float number;
210     return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
211 }
212
213 static bool monochromeMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
214 {
215     if (!mediaValues.monochromeBitsPerComponent()) {
216         if (value.isValid()) {
217             float number;
218             return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
219         }
220         return false;
221     }
222
223     return colorMediaFeatureEval(value, op, mediaValues);
224 }
225
226 static bool orientationMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
227 {
228     int width = mediaValues.viewportWidth();
229     int height = mediaValues.viewportHeight();
230
231     if (value.isID) {
232         if (width > height) // Square viewport is portrait.
233             return CSSValueLandscape == value.id;
234         return CSSValuePortrait == value.id;
235     }
236
237     // Expression (orientation) evaluates to true if width and height >= 0.
238     return height >= 0 && width >= 0;
239 }
240
241 static bool aspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
242 {
243     if (value.isValid())
244         return compareAspectRatioValue(value, mediaValues.viewportWidth(), mediaValues.viewportHeight(), op);
245
246     // ({,min-,max-}aspect-ratio)
247     // assume if we have a device, its aspect ratio is non-zero.
248     return true;
249 }
250
251 static bool deviceAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
252 {
253     if (value.isValid())
254         return compareAspectRatioValue(value, mediaValues.deviceWidth(), mediaValues.deviceHeight(), op);
255
256     // ({,min-,max-}device-aspect-ratio)
257     // assume if we have a device, its aspect ratio is non-zero.
258     return true;
259 }
260
261 static bool evalResolution(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
262 {
263     // According to MQ4, only 'screen', 'print' and 'speech' may match.
264     // FIXME: What should speech match? https://www.w3.org/Style/CSS/Tracker/issues/348
265     float actualResolution = 0;
266
267     // This checks the actual media type applied to the document, and we know
268     // this method only got called if this media type matches the one defined
269     // in the query. Thus, if if the document's media type is "print", the
270     // media type of the query will either be "print" or "all".
271     if (mediaValues.screenMediaType()) {
272         actualResolution = clampTo<float>(mediaValues.devicePixelRatio());
273     } else if (mediaValues.printMediaType()) {
274         // The resolution of images while printing should not depend on the DPI
275         // of the screen. Until we support proper ways of querying this info
276         // we use 300px which is considered minimum for current printers.
277         actualResolution = 300 / cssPixelsPerInch;
278     }
279
280     if (!value.isValid())
281         return !!actualResolution;
282
283     if (!value.isValue)
284         return false;
285
286     if (value.unit == CSSPrimitiveValue::CSS_NUMBER)
287         return compareValue(actualResolution, clampTo<float>(value.value), op);
288
289     if (!CSSPrimitiveValue::isResolution(value.unit))
290         return false;
291
292     double canonicalFactor = CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(value.unit);
293     double dppxFactor = CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(CSSPrimitiveValue::CSS_DPPX);
294     float valueInDppx = clampTo<float>(value.value * (canonicalFactor / dppxFactor));
295     if (CSSPrimitiveValue::isDotsPerCentimeter(value.unit)) {
296         // To match DPCM to DPPX values, we limit to 2 decimal points.
297         // The http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends
298         // "that the pixel unit refer to the whole number of device pixels that best
299         // approximates the reference pixel". With that in mind, allowing 2 decimal
300         // point precision seems appropriate.
301         return compareValue(
302             floorf(0.5 + 100 * actualResolution) / 100,
303             floorf(0.5 + 100 * valueInDppx) / 100, op);
304     }
305
306     return compareValue(actualResolution, valueInDppx, op);
307 }
308
309 static bool devicePixelRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
310 {
311     UseCounter::count(mediaValues.document(), UseCounter::PrefixedDevicePixelRatioMediaFeature);
312
313     return (!value.isValid() || value.unit == CSSPrimitiveValue::CSS_NUMBER) && evalResolution(value, op, mediaValues);
314 }
315
316 static bool resolutionMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& MediaValues)
317 {
318     return (!value.isValid() || CSSPrimitiveValue::isResolution(value.unit)) && evalResolution(value, op, MediaValues);
319 }
320
321 static bool gridMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues&)
322 {
323     // if output device is bitmap, grid: 0 == true
324     // assume we have bitmap device
325     float number;
326     if (value.isValid() && numberValue(value, number))
327         return compareValue(static_cast<int>(number), 0, op);
328     return false;
329 }
330
331 static bool computeLength(const MediaQueryExpValue& value, const MediaValues& mediaValues, int& result)
332 {
333     if (!value.isValue)
334         return false;
335
336     if (value.unit == CSSPrimitiveValue::CSS_NUMBER) {
337         result = clampTo<int>(value.value);
338         return !mediaValues.strictMode() || !result;
339     }
340
341     if (CSSPrimitiveValue::isLength(value.unit))
342         return mediaValues.computeLength(value.value, value.unit, result);
343     return false;
344 }
345
346 static bool deviceHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
347 {
348     if (value.isValid()) {
349         int length;
350         return computeLength(value, mediaValues, length) && compareValue(static_cast<int>(mediaValues.deviceHeight()), length, op);
351     }
352     // ({,min-,max-}device-height)
353     // assume if we have a device, assume non-zero
354     return true;
355 }
356
357 static bool deviceWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
358 {
359     if (value.isValid()) {
360         int length;
361         return computeLength(value, mediaValues, length) && compareValue(static_cast<int>(mediaValues.deviceWidth()), length, op);
362     }
363     // ({,min-,max-}device-width)
364     // assume if we have a device, assume non-zero
365     return true;
366 }
367
368 static bool heightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
369 {
370     int height = mediaValues.viewportHeight();
371     if (value.isValid()) {
372         int length;
373         return computeLength(value, mediaValues, length) && compareValue(height, length, op);
374     }
375
376     return height;
377 }
378
379 static bool widthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
380 {
381     int width = mediaValues.viewportWidth();
382     if (value.isValid()) {
383         int length;
384         return computeLength(value, mediaValues, length) && compareValue(width, length, op);
385     }
386
387     return width;
388 }
389
390 // Rest of the functions are trampolines which set the prefix according to the media feature expression used.
391
392 static bool minColorMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
393 {
394     return colorMediaFeatureEval(value, MinPrefix, mediaValues);
395 }
396
397 static bool maxColorMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
398 {
399     return colorMediaFeatureEval(value, MaxPrefix, mediaValues);
400 }
401
402 static bool minColorIndexMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
403 {
404     return colorIndexMediaFeatureEval(value, MinPrefix, mediaValues);
405 }
406
407 static bool maxColorIndexMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
408 {
409     return colorIndexMediaFeatureEval(value, MaxPrefix, mediaValues);
410 }
411
412 static bool minMonochromeMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
413 {
414     return monochromeMediaFeatureEval(value, MinPrefix, mediaValues);
415 }
416
417 static bool maxMonochromeMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
418 {
419     return monochromeMediaFeatureEval(value, MaxPrefix, mediaValues);
420 }
421
422 static bool minAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
423 {
424     return aspectRatioMediaFeatureEval(value, MinPrefix, mediaValues);
425 }
426
427 static bool maxAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
428 {
429     return aspectRatioMediaFeatureEval(value, MaxPrefix, mediaValues);
430 }
431
432 static bool minDeviceAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
433 {
434     return deviceAspectRatioMediaFeatureEval(value, MinPrefix, mediaValues);
435 }
436
437 static bool maxDeviceAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
438 {
439     return deviceAspectRatioMediaFeatureEval(value, MaxPrefix, mediaValues);
440 }
441
442 static bool minDevicePixelRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
443 {
444     UseCounter::count(mediaValues.document(), UseCounter::PrefixedMinDevicePixelRatioMediaFeature);
445
446     return devicePixelRatioMediaFeatureEval(value, MinPrefix, mediaValues);
447 }
448
449 static bool maxDevicePixelRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
450 {
451     UseCounter::count(mediaValues.document(), UseCounter::PrefixedMaxDevicePixelRatioMediaFeature);
452
453     return devicePixelRatioMediaFeatureEval(value, MaxPrefix, mediaValues);
454 }
455
456 static bool minHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
457 {
458     return heightMediaFeatureEval(value, MinPrefix, mediaValues);
459 }
460
461 static bool maxHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
462 {
463     return heightMediaFeatureEval(value, MaxPrefix, mediaValues);
464 }
465
466 static bool minWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
467 {
468     return widthMediaFeatureEval(value, MinPrefix, mediaValues);
469 }
470
471 static bool maxWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
472 {
473     return widthMediaFeatureEval(value, MaxPrefix, mediaValues);
474 }
475
476 static bool minDeviceHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
477 {
478     return deviceHeightMediaFeatureEval(value, MinPrefix, mediaValues);
479 }
480
481 static bool maxDeviceHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
482 {
483     return deviceHeightMediaFeatureEval(value, MaxPrefix, mediaValues);
484 }
485
486 static bool minDeviceWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
487 {
488     return deviceWidthMediaFeatureEval(value, MinPrefix, mediaValues);
489 }
490
491 static bool maxDeviceWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
492 {
493     return deviceWidthMediaFeatureEval(value, MaxPrefix, mediaValues);
494 }
495
496 static bool minResolutionMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
497 {
498     return resolutionMediaFeatureEval(value, MinPrefix, mediaValues);
499 }
500
501 static bool maxResolutionMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
502 {
503     return resolutionMediaFeatureEval(value, MaxPrefix, mediaValues);
504 }
505
506 static bool transform3dMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
507 {
508     UseCounter::count(mediaValues.document(), UseCounter::PrefixedTransform3dMediaFeature);
509
510     bool returnValueIfNoParameter;
511     int have3dRendering;
512
513     bool threeDEnabled = mediaValues.threeDEnabled();
514
515     returnValueIfNoParameter = threeDEnabled;
516     have3dRendering = threeDEnabled ? 1 : 0;
517
518     if (value.isValid()) {
519         float number;
520         return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op);
521     }
522     return returnValueIfNoParameter;
523 }
524
525 static bool hoverMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
526 {
527     MediaValues::PointerDeviceType pointer = mediaValues.pointer();
528
529     // If we're on a port that hasn't explicitly opted into providing pointer device information
530     // (or otherwise can't be confident in the pointer hardware available), then behave exactly
531     // as if this feature feature isn't supported.
532     if (pointer == MediaValues::UnknownPointer)
533         return false;
534
535     float number = 1;
536     if (value.isValid()) {
537         if (!numberValue(value, number))
538             return false;
539     }
540
541     return (pointer == MediaValues::NoPointer && !number)
542         || (pointer == MediaValues::TouchPointer && !number)
543         || (pointer == MediaValues::MousePointer && number == 1);
544 }
545
546 static bool pointerMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
547 {
548     MediaValues::PointerDeviceType pointer = mediaValues.pointer();
549
550     // If we're on a port that hasn't explicitly opted into providing pointer device information
551     // (or otherwise can't be confident in the pointer hardware available), then behave exactly
552     // as if this feature feature isn't supported.
553     if (pointer == MediaValues::UnknownPointer)
554         return false;
555
556     if (!value.isValid())
557         return pointer != MediaValues::NoPointer;
558
559     if (!value.isID)
560         return false;
561
562     return (pointer == MediaValues::NoPointer && value.id == CSSValueNone)
563         || (pointer == MediaValues::TouchPointer && value.id == CSSValueCoarse)
564         || (pointer == MediaValues::MousePointer && value.id == CSSValueFine);
565 }
566
567 static bool scanMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues)
568 {
569     if (!mediaValues.scanMediaType())
570         return false;
571
572     if (!value.isValid())
573         return true;
574
575     if (!value.isID)
576         return false;
577
578     // If a platform interface supplies progressive/interlace info for TVs in the
579     // future, it needs to be handled here. For now, assume a modern TV with
580     // progressive display.
581     return (value.id == CSSValueProgressive);
582 }
583
584 static void createFunctionMap()
585 {
586     // Create the table.
587     gFunctionMap = new FunctionMap;
588 #define ADD_TO_FUNCTIONMAP(name)  \
589     gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval);
590     CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP);
591 #undef ADD_TO_FUNCTIONMAP
592 }
593
594 bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const
595 {
596     if (!m_mediaValues || !m_mediaValues->hasValues())
597         return m_expectedResult;
598
599     if (!gFunctionMap)
600         createFunctionMap();
601
602     // Call the media feature evaluation function. Assume no prefix and let
603     // trampoline functions override the prefix if prefix is used.
604     EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl());
605     if (func)
606         return func(expr->expValue(), NoPrefix, *m_mediaValues);
607
608     return false;
609 }
610
611 } // namespace