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