• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "CSSValueKeywords.h"
34 #include "core/css/CSSAspectRatioValue.h"
35 #include "core/css/CSSHelper.h"
36 #include "core/css/CSSPrimitiveValue.h"
37 #include "core/css/CSSToLengthConversionData.h"
38 #include "core/css/MediaFeatureNames.h"
39 #include "core/css/MediaList.h"
40 #include "core/css/MediaQuery.h"
41 #include "core/css/resolver/MediaQueryResult.h"
42 #include "core/dom/NodeRenderStyle.h"
43 #include "core/inspector/InspectorInstrumentation.h"
44 #include "core/frame/Frame.h"
45 #include "core/frame/FrameView.h"
46 #include "core/page/Page.h"
47 #include "core/frame/Settings.h"
48 #include "core/rendering/RenderLayerCompositor.h"
49 #include "core/rendering/RenderView.h"
50 #include "core/rendering/style/RenderStyle.h"
51 #include "platform/PlatformScreen.h"
52 #include "platform/geometry/FloatRect.h"
53 #include "wtf/HashMap.h"
54 
55 namespace WebCore {
56 
57 using namespace MediaFeatureNames;
58 
59 enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
60 
61 typedef bool (*EvalFunc)(CSSValue*, RenderStyle*, Frame*, MediaFeaturePrefix);
62 typedef HashMap<StringImpl*, EvalFunc> FunctionMap;
63 static FunctionMap* gFunctionMap;
64 
MediaQueryEvaluator(bool mediaFeatureResult)65 MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
66     : m_frame(0)
67     , m_style(0)
68     , m_expResult(mediaFeatureResult)
69 {
70 }
71 
MediaQueryEvaluator(const AtomicString & acceptedMediaType,bool mediaFeatureResult)72 MediaQueryEvaluator::MediaQueryEvaluator(const AtomicString& acceptedMediaType, bool mediaFeatureResult)
73     : m_mediaType(acceptedMediaType)
74     , m_frame(0)
75     , m_style(0)
76     , m_expResult(mediaFeatureResult)
77 {
78 }
79 
MediaQueryEvaluator(const char * acceptedMediaType,bool mediaFeatureResult)80 MediaQueryEvaluator::MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult)
81     : m_mediaType(acceptedMediaType)
82     , m_frame(0)
83     , m_style(0)
84     , m_expResult(mediaFeatureResult)
85 {
86 }
87 
MediaQueryEvaluator(const AtomicString & acceptedMediaType,Frame * frame,RenderStyle * style)88 MediaQueryEvaluator::MediaQueryEvaluator(const AtomicString& acceptedMediaType, Frame* frame, 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 
~MediaQueryEvaluator()96 MediaQueryEvaluator::~MediaQueryEvaluator()
97 {
98 }
99 
mediaTypeMatch(const AtomicString & mediaTypeToMatch) const100 bool MediaQueryEvaluator::mediaTypeMatch(const AtomicString& mediaTypeToMatch) const
101 {
102     return mediaTypeToMatch.isEmpty()
103         || equalIgnoringCase(mediaTypeToMatch, "all")
104         || equalIgnoringCase(mediaTypeToMatch, m_mediaType);
105 }
106 
mediaTypeMatchSpecific(const char * mediaTypeToMatch) const107 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(!equalIgnoringCase(mediaTypeToMatch, AtomicString("all")));
113     return equalIgnoringCase(mediaTypeToMatch, m_mediaType);
114 }
115 
applyRestrictor(MediaQuery::Restrictor r,bool value)116 static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
117 {
118     return r == MediaQuery::Not ? !value : value;
119 }
120 
eval(const MediaQuerySet * querySet,MediaQueryResultList * viewportDependentMediaQueryResults) const121 bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, MediaQueryResultList* viewportDependentMediaQueryResults) const
122 {
123     if (!querySet)
124         return true;
125 
126     const Vector<OwnPtr<MediaQuery> >& 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 (mediaTypeMatch(query->mediaType())) {
136             const ExpressionVector& expressions = query->expressions();
137             // Iterate through expressions, stop if any of them eval to false (AND semantics).
138             size_t j = 0;
139             for (; j < expressions.size(); ++j) {
140                 bool exprResult = eval(expressions.at(j).get());
141                 if (viewportDependentMediaQueryResults && expressions.at(j)->isViewportDependent())
142                     viewportDependentMediaQueryResults->append(adoptRef(new MediaQueryResult(*expressions.at(j), exprResult)));
143                 if (!exprResult)
144                     break;
145             }
146 
147             // Assume true if we are at the end of the list, otherwise assume false.
148             result = applyRestrictor(query->restrictor(), expressions.size() == j);
149         } else
150             result = applyRestrictor(query->restrictor(), false);
151     }
152 
153     return result;
154 }
155 
156 template<typename T>
compareValue(T a,T b,MediaFeaturePrefix op)157 bool compareValue(T a, T b, MediaFeaturePrefix op)
158 {
159     switch (op) {
160     case MinPrefix:
161         return a >= b;
162     case MaxPrefix:
163         return a <= b;
164     case NoPrefix:
165         return a == b;
166     }
167     return false;
168 }
169 
compareAspectRatioValue(CSSValue * value,int width,int height,MediaFeaturePrefix op)170 static bool compareAspectRatioValue(CSSValue* value, int width, int height, MediaFeaturePrefix op)
171 {
172     if (value->isAspectRatioValue()) {
173         CSSAspectRatioValue* aspectRatio = toCSSAspectRatioValue(value);
174         return compareValue(width * static_cast<int>(aspectRatio->denominatorValue()), height * static_cast<int>(aspectRatio->numeratorValue()), op);
175     }
176 
177     return false;
178 }
179 
numberValue(CSSValue * value,float & result)180 static bool numberValue(CSSValue* value, float& result)
181 {
182     if (value->isPrimitiveValue()
183         && toCSSPrimitiveValue(value)->isNumber()) {
184         result = toCSSPrimitiveValue(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER);
185         return true;
186     }
187     return false;
188 }
189 
colorMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix op)190 static bool colorMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
191 {
192     int bitsPerComponent = screenDepthPerComponent(frame->view());
193     float number;
194     if (value)
195         return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op);
196 
197     return bitsPerComponent != 0;
198 }
199 
colorIndexMediaFeatureEval(CSSValue * value,RenderStyle *,Frame *,MediaFeaturePrefix op)200 static bool colorIndexMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
201 {
202     // FIXME: We currently assume that we do not support indexed displays, as it is unknown
203     // how to retrieve the information if the display mode is indexed. This matches Firefox.
204     if (!value)
205         return false;
206 
207     // Acording to spec, if the device does not use a color lookup table, the value is zero.
208     float number;
209     return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
210 }
211 
monochromeMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix op)212 static bool monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
213 {
214     if (!screenIsMonochrome(frame->view())) {
215         if (value) {
216             float number;
217             return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
218         }
219         return false;
220     }
221 
222     return colorMediaFeatureEval(value, style, frame, op);
223 }
224 
viewportSize(FrameView * view)225 static IntSize viewportSize(FrameView* view)
226 {
227     return view->layoutSize(ScrollableArea::IncludeScrollbars);
228 }
229 
orientationMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix)230 static bool orientationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix)
231 {
232     FrameView* view = frame->view();
233     int width = viewportSize(view).width();
234     int height = viewportSize(view).height();
235     if (value && value->isPrimitiveValue()) {
236         const CSSValueID id = toCSSPrimitiveValue(value)->getValueID();
237         if (width > height) // Square viewport is portrait.
238             return CSSValueLandscape == id;
239         return CSSValuePortrait == id;
240     }
241 
242     // Expression (orientation) evaluates to true if width and height >= 0.
243     return height >= 0 && width >= 0;
244 }
245 
aspectRatioMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix op)246 static bool aspectRatioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
247 {
248     if (value) {
249         FrameView* view = frame->view();
250         return compareAspectRatioValue(value, viewportSize(view).width(), viewportSize(view).height(), op);
251     }
252 
253     // ({,min-,max-}aspect-ratio)
254     // assume if we have a device, its aspect ratio is non-zero.
255     return true;
256 }
257 
deviceAspectRatioMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix op)258 static bool deviceAspectRatioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
259 {
260     if (value) {
261         FloatRect sg = screenRect(frame->view());
262         return compareAspectRatioValue(value, static_cast<int>(sg.width()), static_cast<int>(sg.height()), op);
263     }
264 
265     // ({,min-,max-}device-aspect-ratio)
266     // assume if we have a device, its aspect ratio is non-zero.
267     return true;
268 }
269 
evalResolution(CSSValue * value,Frame * frame,MediaFeaturePrefix op)270 static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op)
271 {
272     // According to MQ4, only 'screen', 'print' and 'speech' may match.
273     // FIXME: What should speech match? https://www.w3.org/Style/CSS/Tracker/issues/348
274     float actualResolution = 0;
275 
276     // This checks the actual media type applied to the document, and we know
277     // this method only got called if this media type matches the one defined
278     // in the query. Thus, if if the document's media type is "print", the
279     // media type of the query will either be "print" or "all".
280     String mediaType = frame->view()->mediaType();
281     if (equalIgnoringCase(mediaType, "screen"))
282         actualResolution = clampTo<float>(frame->devicePixelRatio());
283     else if (equalIgnoringCase(mediaType, "print")) {
284         // The resolution of images while printing should not depend on the DPI
285         // of the screen. Until we support proper ways of querying this info
286         // we use 300px which is considered minimum for current printers.
287         actualResolution = 300 / cssPixelsPerInch;
288     }
289 
290     if (!value)
291         return !!actualResolution;
292 
293     if (!value->isPrimitiveValue())
294         return false;
295 
296     CSSPrimitiveValue* resolution = toCSSPrimitiveValue(value);
297 
298     if (resolution->isNumber())
299         return compareValue(actualResolution, resolution->getFloatValue(), op);
300 
301     if (!resolution->isResolution())
302         return false;
303 
304     if (resolution->isDotsPerCentimeter()) {
305         // To match DPCM to DPPX values, we limit to 2 decimal points.
306         // The http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends
307         // "that the pixel unit refer to the whole number of device pixels that best
308         // approximates the reference pixel". With that in mind, allowing 2 decimal
309         // point precision seems appropriate.
310         return compareValue(
311             floorf(0.5 + 100 * actualResolution) / 100,
312             floorf(0.5 + 100 * resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX)) / 100, op);
313     }
314 
315     return compareValue(actualResolution, resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX), op);
316 }
317 
devicePixelRatioMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix op)318 static bool devicePixelRatioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
319 {
320     return (!value || toCSSPrimitiveValue(value)->isNumber()) && evalResolution(value, frame, op);
321 }
322 
resolutionMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix op)323 static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
324 {
325     return (!value || toCSSPrimitiveValue(value)->isResolution()) && evalResolution(value, frame, op);
326 }
327 
gridMediaFeatureEval(CSSValue * value,RenderStyle *,Frame *,MediaFeaturePrefix op)328 static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
329 {
330     // if output device is bitmap, grid: 0 == true
331     // assume we have bitmap device
332     float number;
333     if (value && numberValue(value, number))
334         return compareValue(static_cast<int>(number), 0, op);
335     return false;
336 }
337 
computeLength(CSSValue * value,bool strict,RenderStyle * initialStyle,int & result)338 static bool computeLength(CSSValue* value, bool strict, RenderStyle* initialStyle, int& result)
339 {
340     if (!value->isPrimitiveValue())
341         return false;
342 
343     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
344 
345     if (primitiveValue->isNumber()) {
346         result = primitiveValue->getIntValue();
347         return !strict || !result;
348     }
349 
350     if (primitiveValue->isLength()) {
351         // Relative (like EM) and root relative (like REM) units are always resolved against
352         // the initial values for media queries, hence the two initialStyle parameters.
353         result = primitiveValue->computeLength<int>(CSSToLengthConversionData(initialStyle, initialStyle, 1.0 /* zoom */, true /* computingFontSize */));
354         return true;
355     }
356 
357     return false;
358 }
359 
deviceHeightMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix op)360 static bool deviceHeightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
361 {
362     if (value) {
363         int length;
364         if (!computeLength(value, !frame->document()->inQuirksMode(), style, length))
365             return false;
366         int height = static_cast<int>(screenRect(frame->view()).height());
367         if (frame->settings()->reportScreenSizeInPhysicalPixelsQuirk())
368             height = lroundf(height * frame->page()->deviceScaleFactor());
369         return compareValue(height, length, op);
370     }
371     // ({,min-,max-}device-height)
372     // assume if we have a device, assume non-zero
373     return true;
374 }
375 
deviceWidthMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix op)376 static bool deviceWidthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
377 {
378     if (value) {
379         int length;
380         if (!computeLength(value, !frame->document()->inQuirksMode(), style, length))
381             return false;
382         int width = static_cast<int>(screenRect(frame->view()).width());
383         if (frame->settings()->reportScreenSizeInPhysicalPixelsQuirk())
384             width = lroundf(width * frame->page()->deviceScaleFactor());
385         return compareValue(width, length, op);
386     }
387     // ({,min-,max-}device-width)
388     // assume if we have a device, assume non-zero
389     return true;
390 }
391 
heightMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix op)392 static bool heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
393 {
394     FrameView* view = frame->view();
395 
396     int height = viewportSize(view).height();
397     if (value) {
398         if (RenderView* renderView = frame->document()->renderView())
399             height = adjustForAbsoluteZoom(height, renderView);
400         int length;
401         return computeLength(value, !frame->document()->inQuirksMode(), style, length) && compareValue(height, length, op);
402     }
403 
404     return height;
405 }
406 
widthMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix op)407 static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op)
408 {
409     FrameView* view = frame->view();
410 
411     int width = viewportSize(view).width();
412     if (value) {
413         if (RenderView* renderView = frame->document()->renderView())
414             width = adjustForAbsoluteZoom(width, renderView);
415         int length;
416         return computeLength(value, !frame->document()->inQuirksMode(), style, length) && compareValue(width, length, op);
417     }
418 
419     return width;
420 }
421 
422 // Rest of the functions are trampolines which set the prefix according to the media feature expression used.
423 
minColorMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)424 static bool minColorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
425 {
426     return colorMediaFeatureEval(value, style, frame, MinPrefix);
427 }
428 
maxColorMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)429 static bool maxColorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
430 {
431     return colorMediaFeatureEval(value, style, frame, MaxPrefix);
432 }
433 
minColorIndexMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)434 static bool minColorIndexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
435 {
436     return colorIndexMediaFeatureEval(value, style, frame, MinPrefix);
437 }
438 
maxColorIndexMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)439 static bool maxColorIndexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
440 {
441     return colorIndexMediaFeatureEval(value, style, frame, MaxPrefix);
442 }
443 
minMonochromeMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)444 static bool minMonochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
445 {
446     return monochromeMediaFeatureEval(value, style, frame, MinPrefix);
447 }
448 
maxMonochromeMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)449 static bool maxMonochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
450 {
451     return monochromeMediaFeatureEval(value, style, frame, MaxPrefix);
452 }
453 
minAspectRatioMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)454 static bool minAspectRatioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
455 {
456     return aspectRatioMediaFeatureEval(value, style, frame, MinPrefix);
457 }
458 
maxAspectRatioMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)459 static bool maxAspectRatioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
460 {
461     return aspectRatioMediaFeatureEval(value, style, frame, MaxPrefix);
462 }
463 
minDeviceAspectRatioMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)464 static bool minDeviceAspectRatioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
465 {
466     return deviceAspectRatioMediaFeatureEval(value, style, frame, MinPrefix);
467 }
468 
maxDeviceAspectRatioMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)469 static bool maxDeviceAspectRatioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
470 {
471     return deviceAspectRatioMediaFeatureEval(value, style, frame, MaxPrefix);
472 }
473 
minDevicePixelRatioMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)474 static bool minDevicePixelRatioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
475 {
476     return devicePixelRatioMediaFeatureEval(value, style, frame, MinPrefix);
477 }
478 
maxDevicePixelRatioMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)479 static bool maxDevicePixelRatioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
480 {
481     return devicePixelRatioMediaFeatureEval(value, style, frame, MaxPrefix);
482 }
483 
minHeightMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)484 static bool minHeightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
485 {
486     return heightMediaFeatureEval(value, style, frame, MinPrefix);
487 }
488 
maxHeightMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)489 static bool maxHeightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
490 {
491     return heightMediaFeatureEval(value, style, frame, MaxPrefix);
492 }
493 
minWidthMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)494 static bool minWidthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
495 {
496     return widthMediaFeatureEval(value, style, frame, MinPrefix);
497 }
498 
maxWidthMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)499 static bool maxWidthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
500 {
501     return widthMediaFeatureEval(value, style, frame, MaxPrefix);
502 }
503 
minDeviceHeightMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)504 static bool minDeviceHeightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
505 {
506     return deviceHeightMediaFeatureEval(value, style, frame, MinPrefix);
507 }
508 
maxDeviceHeightMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)509 static bool maxDeviceHeightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
510 {
511     return deviceHeightMediaFeatureEval(value, style, frame, MaxPrefix);
512 }
513 
minDeviceWidthMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)514 static bool minDeviceWidthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
515 {
516     return deviceWidthMediaFeatureEval(value, style, frame, MinPrefix);
517 }
518 
maxDeviceWidthMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)519 static bool maxDeviceWidthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
520 {
521     return deviceWidthMediaFeatureEval(value, style, frame, MaxPrefix);
522 }
523 
minResolutionMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)524 static bool minResolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
525 {
526     return resolutionMediaFeatureEval(value, style, frame, MinPrefix);
527 }
528 
maxResolutionMediaFeatureEval(CSSValue * value,RenderStyle * style,Frame * frame,MediaFeaturePrefix)529 static bool maxResolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix)
530 {
531     return resolutionMediaFeatureEval(value, style, frame, MaxPrefix);
532 }
533 
animationMediaFeatureEval(CSSValue * value,RenderStyle *,Frame *,MediaFeaturePrefix op)534 static bool animationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
535 {
536     if (value) {
537         float number;
538         return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
539     }
540     return true;
541 }
542 
deprecatedTransitionMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix op)543 static bool deprecatedTransitionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
544 {
545     UseCounter::countDeprecation(frame->document(), UseCounter::PrefixedTransitionMediaFeature);
546 
547     if (value) {
548         float number;
549         return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
550     }
551     return true;
552 }
553 
transform2dMediaFeatureEval(CSSValue * value,RenderStyle *,Frame *,MediaFeaturePrefix op)554 static bool transform2dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)
555 {
556     if (value) {
557         float number;
558         return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
559     }
560     return true;
561 }
562 
transform3dMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix op)563 static bool transform3dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
564 {
565     bool returnValueIfNoParameter;
566     int have3dRendering;
567 
568     bool threeDEnabled = false;
569     if (RenderView* view = frame->contentRenderer())
570         threeDEnabled = view->compositor()->canRender3DTransforms();
571 
572     returnValueIfNoParameter = threeDEnabled;
573     have3dRendering = threeDEnabled ? 1 : 0;
574 
575     if (value) {
576         float number;
577         return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op);
578     }
579     return returnValueIfNoParameter;
580 }
581 
viewModeMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix)582 static bool viewModeMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix)
583 {
584     if (!value)
585         return true;
586 
587     return toCSSPrimitiveValue(value)->getValueID() == CSSValueWindowed;
588 }
589 
590 enum PointerDeviceType { TouchPointer, MousePointer, NoPointer, UnknownPointer };
591 
leastCapablePrimaryPointerDeviceType(Frame * frame)592 static PointerDeviceType leastCapablePrimaryPointerDeviceType(Frame* frame)
593 {
594     if (frame->settings()->deviceSupportsTouch())
595         return TouchPointer;
596 
597     // FIXME: We should also try to determine if we know we have a mouse.
598     // When we do this, we'll also need to differentiate between known not to
599     // have mouse or touch screen (NoPointer) and unknown (UnknownPointer).
600     // We could also take into account other preferences like accessibility
601     // settings to decide which of the available pointers should be considered
602     // "primary".
603 
604     return UnknownPointer;
605 }
606 
hoverMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix)607 static bool hoverMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix)
608 {
609     PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame);
610 
611     // If we're on a port that hasn't explicitly opted into providing pointer device information
612     // (or otherwise can't be confident in the pointer hardware available), then behave exactly
613     // as if this feature feature isn't supported.
614     if (pointer == UnknownPointer)
615         return false;
616 
617     float number = 1;
618     if (value) {
619         if (!numberValue(value, number))
620             return false;
621     }
622 
623     return (pointer == NoPointer && !number)
624         || (pointer == TouchPointer && !number)
625         || (pointer == MousePointer && number == 1);
626 }
627 
pointerMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix)628 static bool pointerMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix)
629 {
630     PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame);
631 
632     // If we're on a port that hasn't explicitly opted into providing pointer device information
633     // (or otherwise can't be confident in the pointer hardware available), then behave exactly
634     // as if this feature feature isn't supported.
635     if (pointer == UnknownPointer)
636         return false;
637 
638     if (!value)
639         return pointer != NoPointer;
640 
641     if (!value->isPrimitiveValue())
642         return false;
643 
644     const CSSValueID id = toCSSPrimitiveValue(value)->getValueID();
645     return (pointer == NoPointer && id == CSSValueNone)
646         || (pointer == TouchPointer && id == CSSValueCoarse)
647         || (pointer == MousePointer && id == CSSValueFine);
648 }
649 
scanMediaFeatureEval(CSSValue * value,RenderStyle *,Frame * frame,MediaFeaturePrefix)650 static bool scanMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix)
651 {
652     // Scan only applies to 'tv' media.
653     if (!equalIgnoringCase(frame->view()->mediaType(), "tv"))
654         return false;
655 
656     if (!value)
657         return true;
658 
659     if (!value->isPrimitiveValue())
660         return false;
661 
662     // If a platform interface supplies progressive/interlace info for TVs in the
663     // future, it needs to be handled here. For now, assume a modern TV with
664     // progressive display.
665     return toCSSPrimitiveValue(value)->getValueID() == CSSValueProgressive;
666 }
667 
createFunctionMap()668 static void createFunctionMap()
669 {
670     // Create the table.
671     gFunctionMap = new FunctionMap;
672 #define ADD_TO_FUNCTIONMAP(name, str)  \
673     gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval);
674     CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP);
675 #undef ADD_TO_FUNCTIONMAP
676 }
677 
eval(const MediaQueryExp * expr) const678 bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const
679 {
680     if (!m_frame || !m_style)
681         return m_expResult;
682 
683     if (!gFunctionMap)
684         createFunctionMap();
685 
686     // Call the media feature evaluation function. Assume no prefix and let
687     // trampoline functions override the prefix if prefix is used.
688     EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl());
689     if (func)
690         return func(expr->value(), m_style.get(), m_frame, NoPrefix);
691 
692     return false;
693 }
694 
695 } // namespace
696