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 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "MediaQueryEvaluator.h" 31 32#include "CSSAspectRatioValue.h" 33#include "CSSPrimitiveValue.h" 34#include "CSSValueKeywords.h" 35#include "CSSValueList.h" 36#include "Chrome.h" 37#include "ChromeClient.h" 38#include "DOMWindow.h" 39#include "FloatRect.h" 40#include "Frame.h" 41#include "FrameView.h" 42#include "IntRect.h" 43#include "MediaFeatureNames.h" 44#include "MediaList.h" 45#include "MediaQuery.h" 46#include "MediaQueryExp.h" 47#include "NodeRenderStyle.h" 48#include "Page.h" 49#include "PlatformScreen.h" 50#include "RenderStyle.h" 51#include "RenderView.h" 52#include "Screen.h" 53#include "Settings.h" 54#include "StyleResolver.h" 55#include <wtf/HashMap.h> 56 57#if ENABLE(3D_RENDERING) && USE(ACCELERATED_COMPOSITING) 58#include "RenderLayerCompositor.h" 59#endif 60 61namespace WebCore { 62 63using namespace MediaFeatureNames; 64 65enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix }; 66 67typedef bool (*EvalFunc)(CSSValue*, RenderStyle*, Frame*, MediaFeaturePrefix); 68typedef HashMap<AtomicStringImpl*, EvalFunc> FunctionMap; 69static FunctionMap* gFunctionMap; 70 71/* 72 * FIXME: following media features are not implemented: scan 73 * 74 * scan: The "scan" media feature describes the scanning process of 75 * tv output devices. It's unknown how to retrieve this information from 76 * the platform 77 */ 78 79MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult) 80 : m_frame(0) 81 , m_style(0) 82 , m_expResult(mediaFeatureResult) 83{ 84} 85 86MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult) 87 : m_mediaType(acceptedMediaType) 88 , m_frame(0) 89 , m_style(0) 90 , m_expResult(mediaFeatureResult) 91{ 92} 93 94MediaQueryEvaluator::MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult) 95 : m_mediaType(acceptedMediaType) 96 , m_frame(0) 97 , m_style(0) 98 , m_expResult(mediaFeatureResult) 99{ 100} 101 102MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, Frame* frame, RenderStyle* style) 103 : m_mediaType(acceptedMediaType) 104 , m_frame(frame) 105 , m_style(style) 106 , m_expResult(false) // doesn't matter when we have m_frame and m_style 107{ 108} 109 110MediaQueryEvaluator::~MediaQueryEvaluator() 111{ 112} 113 114bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const 115{ 116 return mediaTypeToMatch.isEmpty() 117 || equalIgnoringCase(mediaTypeToMatch, "all") 118 || equalIgnoringCase(mediaTypeToMatch, m_mediaType); 119} 120 121bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const 122{ 123 // Like mediaTypeMatch, but without the special cases for "" and "all". 124 ASSERT(mediaTypeToMatch); 125 ASSERT(mediaTypeToMatch[0] != '\0'); 126 ASSERT(!equalIgnoringCase(mediaTypeToMatch, String("all"))); 127 return equalIgnoringCase(mediaTypeToMatch, m_mediaType); 128} 129 130static bool applyRestrictor(MediaQuery::Restrictor r, bool value) 131{ 132 return r == MediaQuery::Not ? !value : value; 133} 134 135bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, StyleResolver* styleResolver) const 136{ 137 if (!querySet) 138 return true; 139 140 const Vector<OwnPtr<MediaQuery> >& queries = querySet->queryVector(); 141 if (!queries.size()) 142 return true; // empty query list evaluates to true 143 144 // iterate over queries, stop if any of them eval to true (OR semantics) 145 bool result = false; 146 for (size_t i = 0; i < queries.size() && !result; ++i) { 147 MediaQuery* query = queries[i].get(); 148 149 if (query->ignored()) 150 continue; 151 152 if (mediaTypeMatch(query->mediaType())) { 153 const Vector<OwnPtr<MediaQueryExp> >* exps = query->expressions(); 154 // iterate through expressions, stop if any of them eval to false 155 // (AND semantics) 156 size_t j = 0; 157 for (; j < exps->size(); ++j) { 158 bool exprResult = eval(exps->at(j).get()); 159 if (styleResolver && exps->at(j)->isViewportDependent()) 160 styleResolver->addViewportDependentMediaQueryResult(exps->at(j).get(), exprResult); 161 if (!exprResult) 162 break; 163 } 164 165 // assume true if we are at the end of the list, 166 // otherwise assume false 167 result = applyRestrictor(query->restrictor(), exps->size() == j); 168 } else 169 result = applyRestrictor(query->restrictor(), false); 170 } 171 172 return result; 173} 174 175template<typename T> 176bool compareValue(T a, T b, MediaFeaturePrefix op) 177{ 178 switch (op) { 179 case MinPrefix: 180 return a >= b; 181 case MaxPrefix: 182 return a <= b; 183 case NoPrefix: 184 return a == b; 185 } 186 return false; 187} 188 189static bool compareAspectRatioValue(CSSValue* value, int width, int height, MediaFeaturePrefix op) 190{ 191 if (value->isAspectRatioValue()) { 192 CSSAspectRatioValue* aspectRatio = static_cast<CSSAspectRatioValue*>(value); 193 return compareValue(width * static_cast<int>(aspectRatio->denominatorValue()), height * static_cast<int>(aspectRatio->numeratorValue()), op); 194 } 195 196 return false; 197} 198 199static bool numberValue(CSSValue* value, float& result) 200{ 201 if (value->isPrimitiveValue() 202 && static_cast<CSSPrimitiveValue*>(value)->isNumber()) { 203 result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); 204 return true; 205 } 206 return false; 207} 208 209static bool colorMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 210{ 211 int bitsPerComponent = screenDepthPerComponent(frame->page()->mainFrame()->view()); 212 float number; 213 if (value) 214 return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op); 215 216 return bitsPerComponent != 0; 217} 218 219static bool color_indexMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 220{ 221 // FIXME: It's unknown how to retrieve the information if the display mode is indexed 222 // Assume we don't support indexed display. 223 if (!value) 224 return false; 225 226 float number; 227 return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); 228} 229 230static bool monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 231{ 232 if (!screenIsMonochrome(frame->page()->mainFrame()->view())) { 233 if (value) { 234 float number; 235 return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); 236 } 237 return false; 238 } 239 240 return colorMediaFeatureEval(value, style, frame, op); 241} 242 243static bool orientationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) 244{ 245 FrameView* view = frame->view(); 246 if (!view) 247 return false; 248 249 int width = view->layoutWidth(); 250 int height = view->layoutHeight(); 251 if (value && value->isPrimitiveValue()) { 252 const int id = static_cast<CSSPrimitiveValue*>(value)->getIdent(); 253 if (width > height) // Square viewport is portrait. 254 return CSSValueLandscape == id; 255 return CSSValuePortrait == id; 256 } 257 258 // Expression (orientation) evaluates to true if width and height >= 0. 259 return height >= 0 && width >= 0; 260} 261 262static bool aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 263{ 264 FrameView* view = frame->view(); 265 if (!view) 266 return true; 267 268 if (value) 269 return compareAspectRatioValue(value, view->layoutWidth(), view->layoutHeight(), op); 270 271 // ({,min-,max-}aspect-ratio) 272 // assume if we have a device, its aspect ratio is non-zero 273 return true; 274} 275 276static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 277{ 278 if (value) { 279 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); 280 return compareAspectRatioValue(value, static_cast<int>(sg.width()), static_cast<int>(sg.height()), op); 281 } 282 283 // ({,min-,max-}device-aspect-ratio) 284 // assume if we have a device, its aspect ratio is non-zero 285 return true; 286} 287 288static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) 289{ 290 // FIXME: Possible handle other media types than 'screen' and 'print'. 291 FrameView* view = frame->view(); 292 if (!view) 293 return false; 294 295 float deviceScaleFactor = 0; 296 // This checks the actual media type applied to the document, and we know 297 // this method only got called if this media type matches the one defined 298 // in the query. Thus, if if the document's media type is "print", the 299 // media type of the query will either be "print" or "all". 300 String mediaType = view->mediaType(); 301 if (equalIgnoringCase(mediaType, "screen")) 302 deviceScaleFactor = frame->page()->deviceScaleFactor(); 303 else if (equalIgnoringCase(mediaType, "print")) { 304 // The resolution of images while printing should not depend on the dpi 305 // of the screen. Until we support proper ways of querying this info 306 // we use 300px which is considered minimum for current printers. 307 deviceScaleFactor = 3.125; // 300dpi / 96dpi; 308 } 309 310 if (!value) 311 return !!deviceScaleFactor; 312 313 if (!value->isPrimitiveValue()) 314 return false; 315 316 CSSPrimitiveValue* resolution = static_cast<CSSPrimitiveValue*>(value); 317 return compareValue(deviceScaleFactor, resolution->isNumber() ? resolution->getFloatValue() : resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX), op); 318} 319 320static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 321{ 322 return (!value || static_cast<CSSPrimitiveValue*>(value)->isNumber()) && evalResolution(value, frame, op); 323} 324 325static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 326{ 327#if ENABLE(RESOLUTION_MEDIA_QUERY) 328 return (!value || static_cast<CSSPrimitiveValue*>(value)->isResolution()) && evalResolution(value, frame, op); 329#else 330 UNUSED_PARAM(value); 331 UNUSED_PARAM(frame); 332 UNUSED_PARAM(op); 333 return false; 334#endif 335} 336 337static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 338{ 339 // if output device is bitmap, grid: 0 == true 340 // assume we have bitmap device 341 float number; 342 if (value && numberValue(value, number)) 343 return compareValue(static_cast<int>(number), 0, op); 344 return false; 345} 346 347static bool computeLength(CSSValue* value, bool strict, RenderStyle* style, RenderStyle* rootStyle, int& result) 348{ 349 if (!value->isPrimitiveValue()) 350 return false; 351 352 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 353 354 if (primitiveValue->isNumber()) { 355 result = primitiveValue->getIntValue(); 356 return !strict || !result; 357 } 358 359 if (primitiveValue->isLength()) { 360 result = primitiveValue->computeLength<int>(style, rootStyle); 361 return true; 362 } 363 364 return false; 365} 366 367static bool device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 368{ 369 if (value) { 370 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); 371 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 372 int length; 373 long height = sg.height(); 374 InspectorInstrumentation::applyScreenHeightOverride(frame, &height); 375 return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast<int>(height), length, op); 376 } 377 // ({,min-,max-}device-height) 378 // assume if we have a device, assume non-zero 379 return true; 380} 381 382static bool device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 383{ 384 if (value) { 385 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); 386 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 387 int length; 388 long width = sg.width(); 389 InspectorInstrumentation::applyScreenWidthOverride(frame, &width); 390 return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast<int>(width), length, op); 391 } 392 // ({,min-,max-}device-width) 393 // assume if we have a device, assume non-zero 394 return true; 395} 396 397static bool heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 398{ 399 FrameView* view = frame->view(); 400 if (!view) 401 return false; 402 403 if (value) { 404 int height = view->layoutHeight(); 405 if (RenderView* renderView = frame->document()->renderView()) 406 height = adjustForAbsoluteZoom(height, renderView); 407 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 408 int length; 409 return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(height, length, op); 410 } 411 412 return view->layoutHeight() != 0; 413} 414 415static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 416{ 417 FrameView* view = frame->view(); 418 if (!view) 419 return false; 420 421 if (value) { 422 int width = view->layoutWidth(); 423 if (RenderView* renderView = frame->document()->renderView()) 424 width = adjustForAbsoluteZoom(width, renderView); 425 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 426 int length; 427 return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(width, length, op); 428 } 429 430 return view->layoutWidth() != 0; 431} 432 433// rest of the functions are trampolines which set the prefix according to the media feature expression used 434 435static bool min_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 436{ 437 return colorMediaFeatureEval(value, style, frame, MinPrefix); 438} 439 440static bool max_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 441{ 442 return colorMediaFeatureEval(value, style, frame, MaxPrefix); 443} 444 445static bool min_color_indexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 446{ 447 return color_indexMediaFeatureEval(value, style, frame, MinPrefix); 448} 449 450static bool max_color_indexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 451{ 452 return color_indexMediaFeatureEval(value, style, frame, MaxPrefix); 453} 454 455static bool min_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 456{ 457 return monochromeMediaFeatureEval(value, style, frame, MinPrefix); 458} 459 460static bool max_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 461{ 462 return monochromeMediaFeatureEval(value, style, frame, MaxPrefix); 463} 464 465static bool min_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 466{ 467 return aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); 468} 469 470static bool max_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 471{ 472 return aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); 473} 474 475static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 476{ 477 return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); 478} 479 480static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 481{ 482 return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); 483} 484 485static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 486{ 487 return device_pixel_ratioMediaFeatureEval(value, style, frame, MinPrefix); 488} 489 490static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 491{ 492 return device_pixel_ratioMediaFeatureEval(value, style, frame, MaxPrefix); 493} 494 495static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 496{ 497 return heightMediaFeatureEval(value, style, frame, MinPrefix); 498} 499 500static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 501{ 502 return heightMediaFeatureEval(value, style, frame, MaxPrefix); 503} 504 505static bool min_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 506{ 507 return widthMediaFeatureEval(value, style, frame, MinPrefix); 508} 509 510static bool max_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 511{ 512 return widthMediaFeatureEval(value, style, frame, MaxPrefix); 513} 514 515static bool min_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 516{ 517 return device_heightMediaFeatureEval(value, style, frame, MinPrefix); 518} 519 520static bool max_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 521{ 522 return device_heightMediaFeatureEval(value, style, frame, MaxPrefix); 523} 524 525static bool min_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 526{ 527 return device_widthMediaFeatureEval(value, style, frame, MinPrefix); 528} 529 530static bool max_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 531{ 532 return device_widthMediaFeatureEval(value, style, frame, MaxPrefix); 533} 534 535static bool min_resolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 536{ 537 return resolutionMediaFeatureEval(value, style, frame, MinPrefix); 538} 539 540static bool max_resolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 541{ 542 return resolutionMediaFeatureEval(value, style, frame, MaxPrefix); 543} 544 545static bool animationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 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 554static bool transitionMediaFeatureEval(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 563static bool transform_2dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 564{ 565 if (value) { 566 float number; 567 return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); 568 } 569 return true; 570} 571 572static bool transform_3dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 573{ 574 bool returnValueIfNoParameter; 575 int have3dRendering; 576 577#if ENABLE(3D_RENDERING) 578 bool threeDEnabled = false; 579#if USE(ACCELERATED_COMPOSITING) 580 if (RenderView* view = frame->contentRenderer()) 581 threeDEnabled = view->compositor()->canRender3DTransforms(); 582#endif 583 584 returnValueIfNoParameter = threeDEnabled; 585 have3dRendering = threeDEnabled ? 1 : 0; 586#else 587 UNUSED_PARAM(frame); 588 returnValueIfNoParameter = false; 589 have3dRendering = 0; 590#endif 591 592 if (value) { 593 float number; 594 return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op); 595 } 596 return returnValueIfNoParameter; 597} 598 599#if ENABLE(VIEW_MODE_CSS_MEDIA) 600static bool view_modeMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 601{ 602 UNUSED_PARAM(op); 603 if (!value) 604 return true; 605 606 const int viewModeCSSKeywordID = static_cast<CSSPrimitiveValue*>(value)->getIdent(); 607 const Page::ViewMode viewMode = frame->page()->viewMode(); 608 bool result = false; 609 switch (viewMode) { 610 case Page::ViewModeWindowed: 611 result = viewModeCSSKeywordID == CSSValueWindowed; 612 break; 613 case Page::ViewModeFloating: 614 result = viewModeCSSKeywordID == CSSValueFloating; 615 break; 616 case Page::ViewModeFullscreen: 617 result = viewModeCSSKeywordID == CSSValueFullscreen; 618 break; 619 case Page::ViewModeMaximized: 620 result = viewModeCSSKeywordID == CSSValueMaximized; 621 break; 622 case Page::ViewModeMinimized: 623 result = viewModeCSSKeywordID == CSSValueMinimized; 624 break; 625 default: 626 result = false; 627 break; 628 } 629 630 return result; 631} 632#endif // ENABLE(VIEW_MODE_CSS_MEDIA) 633 634enum PointerDeviceType { TouchPointer, MousePointer, NoPointer, UnknownPointer }; 635 636static PointerDeviceType leastCapablePrimaryPointerDeviceType(Frame* frame) 637{ 638 if (frame->settings()->deviceSupportsTouch()) 639 return TouchPointer; 640 641 // FIXME: We should also try to determine if we know we have a mouse. 642 // When we do this, we'll also need to differentiate between known not to 643 // have mouse or touch screen (NoPointer) and unknown (UnknownPointer). 644 // We could also take into account other preferences like accessibility 645 // settings to decide which of the available pointers should be considered 646 // "primary". 647 648 return UnknownPointer; 649} 650 651static bool hoverMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) 652{ 653 PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame); 654 655 // If we're on a port that hasn't explicitly opted into providing pointer device information 656 // (or otherwise can't be confident in the pointer hardware available), then behave exactly 657 // as if this feature feature isn't supported. 658 if (pointer == UnknownPointer) 659 return false; 660 661 float number = 1; 662 if (value) { 663 if (!numberValue(value, number)) 664 return false; 665 } 666 667 return (pointer == NoPointer && !number) 668 || (pointer == TouchPointer && !number) 669 || (pointer == MousePointer && number == 1); 670} 671 672static bool pointerMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) 673{ 674 PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame); 675 676 // If we're on a port that hasn't explicitly opted into providing pointer device information 677 // (or otherwise can't be confident in the pointer hardware available), then behave exactly 678 // as if this feature feature isn't supported. 679 if (pointer == UnknownPointer) 680 return false; 681 682 if (!value) 683 return pointer != NoPointer; 684 685 if (!value->isPrimitiveValue()) 686 return false; 687 688 const int id = static_cast<CSSPrimitiveValue*>(value)->getIdent(); 689 return (pointer == NoPointer && id == CSSValueNone) 690 || (pointer == TouchPointer && id == CSSValueCoarse) 691 || (pointer == MousePointer && id == CSSValueFine); 692} 693 694static void createFunctionMap() 695{ 696 // Create the table. 697 gFunctionMap = new FunctionMap; 698#define ADD_TO_FUNCTIONMAP(name, str) \ 699 gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval); 700 CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); 701#undef ADD_TO_FUNCTIONMAP 702} 703 704bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const 705{ 706 if (!m_frame || !m_frame->view() || !m_style) 707 return m_expResult; 708 709 if (!expr->isValid()) 710 return false; 711 712 if (!gFunctionMap) 713 createFunctionMap(); 714 715 // call the media feature evaluation function. Assume no prefix 716 // and let trampoline functions override the prefix if prefix is 717 // used 718 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); 719 if (func) 720 return func(expr->value(), m_style.get(), m_frame, NoPrefix); 721 722 return false; 723} 724 725} // namespace 726