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