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/PointerProperties.h" 45#include "core/css/resolver/MediaQueryResult.h" 46#include "core/dom/NodeRenderStyle.h" 47#include "core/frame/FrameHost.h" 48#include "core/frame/FrameView.h" 49#include "core/frame/LocalFrame.h" 50#include "core/frame/Settings.h" 51#include "core/frame/UseCounter.h" 52#include "core/inspector/InspectorInstrumentation.h" 53#include "core/rendering/RenderView.h" 54#include "core/rendering/compositing/RenderLayerCompositor.h" 55#include "core/rendering/style/RenderStyle.h" 56#include "platform/PlatformScreen.h" 57#include "platform/RuntimeEnabledFeatures.h" 58#include "platform/geometry/FloatRect.h" 59#include "wtf/HashMap.h" 60 61namespace blink { 62 63using namespace MediaFeatureNames; 64 65enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix }; 66 67typedef bool (*EvalFunc)(const MediaQueryExpValue&, MediaFeaturePrefix, const MediaValues&); 68typedef HashMap<StringImpl*, EvalFunc> FunctionMap; 69static FunctionMap* gFunctionMap; 70 71MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult) 72 : m_expectedResult(mediaFeatureResult) 73{ 74} 75 76MediaQueryEvaluator::MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult) 77 : m_mediaType(acceptedMediaType) 78 , m_expectedResult(mediaFeatureResult) 79{ 80} 81 82MediaQueryEvaluator::MediaQueryEvaluator(LocalFrame* frame) 83 : m_expectedResult(false) // Doesn't matter when we have m_frame and m_style. 84 , m_mediaValues(MediaValues::createDynamicIfFrameExists(frame)) 85{ 86} 87 88MediaQueryEvaluator::MediaQueryEvaluator(const MediaValues& mediaValues) 89 : m_expectedResult(false) // Doesn't matter when we have mediaValues. 90 , m_mediaValues(mediaValues.copy()) 91{ 92} 93 94MediaQueryEvaluator::~MediaQueryEvaluator() 95{ 96} 97 98const String MediaQueryEvaluator::mediaType() const 99{ 100 // If a static mediaType was given by the constructor, we use it here. 101 if (!m_mediaType.isEmpty()) 102 return m_mediaType; 103 // Otherwise, we get one from mediaValues (which may be dynamic or cached). 104 if (m_mediaValues) 105 return m_mediaValues->mediaType(); 106 return nullAtom; 107} 108 109bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const 110{ 111 return mediaTypeToMatch.isEmpty() 112 || equalIgnoringCase(mediaTypeToMatch, MediaTypeNames::all) 113 || equalIgnoringCase(mediaTypeToMatch, mediaType()); 114} 115 116static bool applyRestrictor(MediaQuery::Restrictor r, bool value) 117{ 118 return r == MediaQuery::Not ? !value : value; 119} 120 121bool MediaQueryEvaluator::eval(const MediaQuery* query, MediaQueryResultList* viewportDependentMediaQueryResults) const 122{ 123 if (!mediaTypeMatch(query->mediaType())) 124 return applyRestrictor(query->restrictor(), false); 125 126 const ExpressionHeapVector& expressions = query->expressions(); 127 // Iterate through expressions, stop if any of them eval to false (AND semantics). 128 size_t i = 0; 129 for (; i < expressions.size(); ++i) { 130 bool exprResult = eval(expressions.at(i).get()); 131 if (viewportDependentMediaQueryResults && expressions.at(i)->isViewportDependent()) 132 viewportDependentMediaQueryResults->append(adoptRefWillBeNoop(new MediaQueryResult(*expressions.at(i), exprResult))); 133 if (!exprResult) 134 break; 135 } 136 137 // Assume true if we are at the end of the list, otherwise assume false. 138 return applyRestrictor(query->restrictor(), expressions.size() == i); 139} 140 141bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, MediaQueryResultList* viewportDependentMediaQueryResults) const 142{ 143 if (!querySet) 144 return true; 145 146 const WillBeHeapVector<OwnPtrWillBeMember<MediaQuery> >& queries = querySet->queryVector(); 147 if (!queries.size()) 148 return true; // Empty query list evaluates to true. 149 150 // Iterate over queries, stop if any of them eval to true (OR semantics). 151 bool result = false; 152 for (size_t i = 0; i < queries.size() && !result; ++i) 153 result = eval(queries[i].get(), viewportDependentMediaQueryResults); 154 155 return result; 156} 157 158template<typename T> 159bool compareValue(T a, T b, MediaFeaturePrefix op) 160{ 161 switch (op) { 162 case MinPrefix: 163 return a >= b; 164 case MaxPrefix: 165 return a <= b; 166 case NoPrefix: 167 return a == b; 168 } 169 return false; 170} 171 172static bool compareAspectRatioValue(const MediaQueryExpValue& value, int width, int height, MediaFeaturePrefix op) 173{ 174 if (value.isRatio) 175 return compareValue(width * static_cast<int>(value.denominator), height * static_cast<int>(value.numerator), op); 176 177 return false; 178} 179 180static bool numberValue(const MediaQueryExpValue& value, float& result) 181{ 182 if (value.isValue && value.unit == CSSPrimitiveValue::CSS_NUMBER) { 183 result = value.value; 184 return true; 185 } 186 return false; 187} 188 189static bool colorMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 190{ 191 float number; 192 int bitsPerComponent = mediaValues.colorBitsPerComponent(); 193 if (value.isValid()) 194 return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op); 195 196 return bitsPerComponent != 0; 197} 198 199static bool colorIndexMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues&) 200{ 201 // FIXME: We currently assume that we do not support indexed displays, as it is unknown 202 // how to retrieve the information if the display mode is indexed. This matches Firefox. 203 if (!value.isValid()) 204 return false; 205 206 // Acording to spec, if the device does not use a color lookup table, the value is zero. 207 float number; 208 return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); 209} 210 211static bool monochromeMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 212{ 213 if (!mediaValues.monochromeBitsPerComponent()) { 214 if (value.isValid()) { 215 float number; 216 return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); 217 } 218 return false; 219 } 220 221 return colorMediaFeatureEval(value, op, mediaValues); 222} 223 224static bool orientationMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 225{ 226 int width = mediaValues.viewportWidth(); 227 int height = mediaValues.viewportHeight(); 228 229 if (value.isID) { 230 if (width > height) // Square viewport is portrait. 231 return CSSValueLandscape == value.id; 232 return CSSValuePortrait == value.id; 233 } 234 235 // Expression (orientation) evaluates to true if width and height >= 0. 236 return height >= 0 && width >= 0; 237} 238 239static bool aspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 240{ 241 if (value.isValid()) 242 return compareAspectRatioValue(value, mediaValues.viewportWidth(), mediaValues.viewportHeight(), op); 243 244 // ({,min-,max-}aspect-ratio) 245 // assume if we have a device, its aspect ratio is non-zero. 246 return true; 247} 248 249static bool deviceAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 250{ 251 if (value.isValid()) 252 return compareAspectRatioValue(value, mediaValues.deviceWidth(), mediaValues.deviceHeight(), op); 253 254 // ({,min-,max-}device-aspect-ratio) 255 // assume if we have a device, its aspect ratio is non-zero. 256 return true; 257} 258 259static bool evalResolution(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 260{ 261 // According to MQ4, only 'screen', 'print' and 'speech' may match. 262 // FIXME: What should speech match? https://www.w3.org/Style/CSS/Tracker/issues/348 263 float actualResolution = 0; 264 265 // This checks the actual media type applied to the document, and we know 266 // this method only got called if this media type matches the one defined 267 // in the query. Thus, if if the document's media type is "print", the 268 // media type of the query will either be "print" or "all". 269 if (equalIgnoringCase(mediaValues.mediaType(), MediaTypeNames::screen)) { 270 actualResolution = clampTo<float>(mediaValues.devicePixelRatio()); 271 } else if (equalIgnoringCase(mediaValues.mediaType(), MediaTypeNames::print)) { 272 // The resolution of images while printing should not depend on the DPI 273 // of the screen. Until we support proper ways of querying this info 274 // we use 300px which is considered minimum for current printers. 275 actualResolution = 300 / cssPixelsPerInch; 276 } 277 278 if (!value.isValid()) 279 return !!actualResolution; 280 281 if (!value.isValue) 282 return false; 283 284 if (value.unit == CSSPrimitiveValue::CSS_NUMBER) 285 return compareValue(actualResolution, clampTo<float>(value.value), op); 286 287 if (!CSSPrimitiveValue::isResolution(value.unit)) 288 return false; 289 290 double canonicalFactor = CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(value.unit); 291 double dppxFactor = CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(CSSPrimitiveValue::CSS_DPPX); 292 float valueInDppx = clampTo<float>(value.value * (canonicalFactor / dppxFactor)); 293 if (CSSPrimitiveValue::isDotsPerCentimeter(value.unit)) { 294 // To match DPCM to DPPX values, we limit to 2 decimal points. 295 // The http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends 296 // "that the pixel unit refer to the whole number of device pixels that best 297 // approximates the reference pixel". With that in mind, allowing 2 decimal 298 // point precision seems appropriate. 299 return compareValue( 300 floorf(0.5 + 100 * actualResolution) / 100, 301 floorf(0.5 + 100 * valueInDppx) / 100, op); 302 } 303 304 return compareValue(actualResolution, valueInDppx, op); 305} 306 307static bool devicePixelRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 308{ 309 UseCounter::count(mediaValues.document(), UseCounter::PrefixedDevicePixelRatioMediaFeature); 310 311 return (!value.isValid() || value.unit == CSSPrimitiveValue::CSS_NUMBER) && evalResolution(value, op, mediaValues); 312} 313 314static bool resolutionMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& MediaValues) 315{ 316 return (!value.isValid() || CSSPrimitiveValue::isResolution(value.unit)) && evalResolution(value, op, MediaValues); 317} 318 319static bool gridMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues&) 320{ 321 // if output device is bitmap, grid: 0 == true 322 // assume we have bitmap device 323 float number; 324 if (value.isValid() && numberValue(value, number)) 325 return compareValue(static_cast<int>(number), 0, op); 326 return false; 327} 328 329static bool computeLength(const MediaQueryExpValue& value, const MediaValues& mediaValues, int& result) 330{ 331 if (!value.isValue) 332 return false; 333 334 if (value.unit == CSSPrimitiveValue::CSS_NUMBER) { 335 result = clampTo<int>(value.value); 336 return !mediaValues.strictMode() || !result; 337 } 338 339 if (CSSPrimitiveValue::isLength(value.unit)) 340 return mediaValues.computeLength(value.value, value.unit, result); 341 return false; 342} 343 344static bool deviceHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 345{ 346 if (value.isValid()) { 347 int length; 348 return computeLength(value, mediaValues, length) && compareValue(static_cast<int>(mediaValues.deviceHeight()), length, op); 349 } 350 // ({,min-,max-}device-height) 351 // assume if we have a device, assume non-zero 352 return true; 353} 354 355static bool deviceWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 356{ 357 if (value.isValid()) { 358 int length; 359 return computeLength(value, mediaValues, length) && compareValue(static_cast<int>(mediaValues.deviceWidth()), length, op); 360 } 361 // ({,min-,max-}device-width) 362 // assume if we have a device, assume non-zero 363 return true; 364} 365 366static bool heightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 367{ 368 int height = mediaValues.viewportHeight(); 369 if (value.isValid()) { 370 int length; 371 return computeLength(value, mediaValues, length) && compareValue(height, length, op); 372 } 373 374 return height; 375} 376 377static bool widthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 378{ 379 int width = mediaValues.viewportWidth(); 380 if (value.isValid()) { 381 int length; 382 return computeLength(value, mediaValues, length) && compareValue(width, length, op); 383 } 384 385 return width; 386} 387 388// Rest of the functions are trampolines which set the prefix according to the media feature expression used. 389 390static bool minColorMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 391{ 392 return colorMediaFeatureEval(value, MinPrefix, mediaValues); 393} 394 395static bool maxColorMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 396{ 397 return colorMediaFeatureEval(value, MaxPrefix, mediaValues); 398} 399 400static bool minColorIndexMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 401{ 402 return colorIndexMediaFeatureEval(value, MinPrefix, mediaValues); 403} 404 405static bool maxColorIndexMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 406{ 407 return colorIndexMediaFeatureEval(value, MaxPrefix, mediaValues); 408} 409 410static bool minMonochromeMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 411{ 412 return monochromeMediaFeatureEval(value, MinPrefix, mediaValues); 413} 414 415static bool maxMonochromeMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 416{ 417 return monochromeMediaFeatureEval(value, MaxPrefix, mediaValues); 418} 419 420static bool minAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 421{ 422 return aspectRatioMediaFeatureEval(value, MinPrefix, mediaValues); 423} 424 425static bool maxAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 426{ 427 return aspectRatioMediaFeatureEval(value, MaxPrefix, mediaValues); 428} 429 430static bool minDeviceAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 431{ 432 return deviceAspectRatioMediaFeatureEval(value, MinPrefix, mediaValues); 433} 434 435static bool maxDeviceAspectRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 436{ 437 return deviceAspectRatioMediaFeatureEval(value, MaxPrefix, mediaValues); 438} 439 440static bool minDevicePixelRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 441{ 442 UseCounter::count(mediaValues.document(), UseCounter::PrefixedMinDevicePixelRatioMediaFeature); 443 444 return devicePixelRatioMediaFeatureEval(value, MinPrefix, mediaValues); 445} 446 447static bool maxDevicePixelRatioMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 448{ 449 UseCounter::count(mediaValues.document(), UseCounter::PrefixedMaxDevicePixelRatioMediaFeature); 450 451 return devicePixelRatioMediaFeatureEval(value, MaxPrefix, mediaValues); 452} 453 454static bool minHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 455{ 456 return heightMediaFeatureEval(value, MinPrefix, mediaValues); 457} 458 459static bool maxHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 460{ 461 return heightMediaFeatureEval(value, MaxPrefix, mediaValues); 462} 463 464static bool minWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 465{ 466 return widthMediaFeatureEval(value, MinPrefix, mediaValues); 467} 468 469static bool maxWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 470{ 471 return widthMediaFeatureEval(value, MaxPrefix, mediaValues); 472} 473 474static bool minDeviceHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 475{ 476 return deviceHeightMediaFeatureEval(value, MinPrefix, mediaValues); 477} 478 479static bool maxDeviceHeightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 480{ 481 return deviceHeightMediaFeatureEval(value, MaxPrefix, mediaValues); 482} 483 484static bool minDeviceWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 485{ 486 return deviceWidthMediaFeatureEval(value, MinPrefix, mediaValues); 487} 488 489static bool maxDeviceWidthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 490{ 491 return deviceWidthMediaFeatureEval(value, MaxPrefix, mediaValues); 492} 493 494static bool minResolutionMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 495{ 496 return resolutionMediaFeatureEval(value, MinPrefix, mediaValues); 497} 498 499static bool maxResolutionMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 500{ 501 return resolutionMediaFeatureEval(value, MaxPrefix, mediaValues); 502} 503 504static bool transform3dMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues) 505{ 506 UseCounter::count(mediaValues.document(), UseCounter::PrefixedTransform3dMediaFeature); 507 508 bool returnValueIfNoParameter; 509 int have3dRendering; 510 511 bool threeDEnabled = mediaValues.threeDEnabled(); 512 513 returnValueIfNoParameter = threeDEnabled; 514 have3dRendering = threeDEnabled ? 1 : 0; 515 516 if (value.isValid()) { 517 float number; 518 return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op); 519 } 520 return returnValueIfNoParameter; 521} 522 523static bool hoverMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 524{ 525 HoverType hover = mediaValues.primaryHoverType(); 526 527 if (RuntimeEnabledFeatures::hoverMediaQueryKeywordsEnabled()) { 528 if (!value.isValid()) 529 return hover != HoverTypeNone; 530 531 if (!value.isID) 532 return false; 533 534 return (hover == HoverTypeNone && value.id == CSSValueNone) 535 || (hover == HoverTypeOnDemand && value.id == CSSValueOnDemand) 536 || (hover == HoverTypeHover && value.id == CSSValueHover); 537 } else { 538 float number = 1; 539 if (value.isValid()) { 540 if (!numberValue(value, number)) 541 return false; 542 } 543 544 return (hover == HoverTypeNone && !number) 545 || (hover == HoverTypeOnDemand && !number) 546 || (hover == HoverTypeHover && number == 1); 547 } 548} 549 550static bool anyHoverMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 551{ 552 if (!RuntimeEnabledFeatures::anyPointerMediaQueriesEnabled()) 553 return false; 554 555 int availableHoverTypes = mediaValues.availableHoverTypes(); 556 557 if (!value.isValid()) 558 return availableHoverTypes & ~HoverTypeNone; 559 560 if (!value.isID) 561 return false; 562 563 switch (value.id) { 564 case CSSValueNone: 565 return availableHoverTypes & HoverTypeNone; 566 case CSSValueOnDemand: 567 return availableHoverTypes & HoverTypeOnDemand; 568 case CSSValueHover: 569 return availableHoverTypes & HoverTypeHover; 570 default: 571 ASSERT_NOT_REACHED(); 572 return false; 573 } 574} 575 576static bool pointerMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 577{ 578 PointerType pointer = mediaValues.primaryPointerType(); 579 580 if (!value.isValid()) 581 return pointer != PointerTypeNone; 582 583 if (!value.isID) 584 return false; 585 586 return (pointer == PointerTypeNone && value.id == CSSValueNone) 587 || (pointer == PointerTypeCoarse && value.id == CSSValueCoarse) 588 || (pointer == PointerTypeFine && value.id == CSSValueFine); 589} 590 591static bool anyPointerMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 592{ 593 if (!RuntimeEnabledFeatures::anyPointerMediaQueriesEnabled()) 594 return false; 595 596 int availablePointers = mediaValues.availablePointerTypes(); 597 598 if (!value.isValid()) 599 return availablePointers & ~PointerTypeNone; 600 601 if (!value.isID) 602 return false; 603 604 switch (value.id) { 605 case CSSValueCoarse: 606 return availablePointers & PointerTypeCoarse; 607 case CSSValueFine: 608 return availablePointers & PointerTypeFine; 609 case CSSValueNone: 610 return availablePointers & PointerTypeNone; 611 default: 612 ASSERT_NOT_REACHED(); 613 return false; 614 } 615} 616 617static bool scanMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix, const MediaValues& mediaValues) 618{ 619 // Scan only applies to 'tv' media. 620 if (!equalIgnoringCase(mediaValues.mediaType(), MediaTypeNames::tv)) 621 return false; 622 623 if (!value.isValid()) 624 return true; 625 626 if (!value.isID) 627 return false; 628 629 // If a platform interface supplies progressive/interlace info for TVs in the 630 // future, it needs to be handled here. For now, assume a modern TV with 631 // progressive display. 632 return (value.id == CSSValueProgressive); 633} 634 635static void createFunctionMap() 636{ 637 // Create the table. 638 gFunctionMap = new FunctionMap; 639#define ADD_TO_FUNCTIONMAP(name) \ 640 gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval); 641 CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); 642#undef ADD_TO_FUNCTIONMAP 643} 644 645bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const 646{ 647 if (!m_mediaValues || !m_mediaValues->hasValues()) 648 return m_expectedResult; 649 650 if (!gFunctionMap) 651 createFunctionMap(); 652 653 // Call the media feature evaluation function. Assume no prefix and let 654 // trampoline functions override the prefix if prefix is used. 655 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); 656 if (func) 657 return func(expr->expValue(), NoPrefix, *m_mediaValues); 658 659 return false; 660} 661 662} // namespace 663