2 * CSS Media Query Evaluator
4 * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>.
5 * Copyright (C) 2013 Apple Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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 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.
30 #include "MediaQueryEvaluator.h"
32 #include "CSSAspectRatioValue.h"
33 #include "CSSPrimitiveValue.h"
34 #include "CSSToLengthConversionData.h"
35 #include "CSSValueKeywords.h"
36 #include "CSSValueList.h"
37 #include "FloatRect.h"
38 #include "FrameView.h"
40 #include "MainFrame.h"
41 #include "MediaFeatureNames.h"
42 #include "MediaList.h"
43 #include "MediaQuery.h"
44 #include "NodeRenderStyle.h"
46 #include "PlatformScreen.h"
47 #include "RenderStyle.h"
48 #include "RenderView.h"
51 #include "StyleResolver.h"
53 #include <wtf/HashMap.h>
55 #if ENABLE(3D_TRANSFORMS)
56 #include "RenderLayerCompositor.h"
61 enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
63 typedef bool (*MediaQueryFunction)(CSSValue*, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix);
64 typedef HashMap<AtomicStringImpl*, MediaQueryFunction> MediaQueryFunctionMap;
66 static bool isViewportDependent(const AtomicString& mediaFeature)
68 return mediaFeature == MediaFeatureNames::width
69 || mediaFeature == MediaFeatureNames::height
70 || mediaFeature == MediaFeatureNames::minWidth
71 || mediaFeature == MediaFeatureNames::minHeight
72 || mediaFeature == MediaFeatureNames::maxWidth
73 || mediaFeature == MediaFeatureNames::maxHeight
74 || mediaFeature == MediaFeatureNames::orientation
75 || mediaFeature == MediaFeatureNames::aspectRatio
76 || mediaFeature == MediaFeatureNames::minAspectRatio
77 || mediaFeature == MediaFeatureNames::maxAspectRatio;
80 MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
81 : m_fallbackResult(mediaFeatureResult)
85 MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult)
86 : m_mediaType(acceptedMediaType)
87 , m_fallbackResult(mediaFeatureResult)
91 MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, const Document& document, const RenderStyle* style)
92 : m_mediaType(acceptedMediaType)
93 , m_frame(document.frame())
98 bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const
100 return mediaTypeToMatch.isEmpty()
101 || equalLettersIgnoringASCIICase(mediaTypeToMatch, "all")
102 || equalIgnoringASCIICase(mediaTypeToMatch, m_mediaType);
105 bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const
107 // Like mediaTypeMatch, but without the special cases for "" and "all".
108 ASSERT(mediaTypeToMatch);
109 ASSERT(mediaTypeToMatch[0] != '\0');
110 ASSERT(!equalLettersIgnoringASCIICase(StringView(mediaTypeToMatch), "all"));
111 return equalIgnoringASCIICase(m_mediaType, mediaTypeToMatch);
114 static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
116 return r == MediaQuery::Not ? !value : value;
119 bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, StyleResolver* styleResolver) const
121 auto& queries = querySet.queryVector();
123 return true; // empty query list evaluates to true
125 // iterate over queries, stop if any of them eval to true (OR semantics)
127 for (size_t i = 0; i < queries.size() && !result; ++i) {
128 auto& query = queries[i];
130 if (query.ignored() || (!query.expressions().size() && query.mediaType().isEmpty()))
133 if (mediaTypeMatch(query.mediaType())) {
134 auto& expressions = query.expressions();
135 // iterate through expressions, stop if any of them eval to false (AND semantics)
137 for (; j < expressions.size(); ++j) {
138 bool expressionResult = evaluate(expressions[j]);
139 if (styleResolver && isViewportDependent(expressions[j].mediaFeature()))
140 styleResolver->addViewportDependentMediaQueryResult(expressions[j], expressionResult);
141 if (!expressionResult)
145 // assume true if we are at the end of the list,
146 // otherwise assume false
147 result = applyRestrictor(query.restrictor(), expressions.size() == j);
149 result = applyRestrictor(query.restrictor(), false);
155 bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, Vector<MediaQueryResult>& results) const
157 auto& queries = querySet.queryVector();
162 for (size_t i = 0; i < queries.size() && !result; ++i) {
163 auto& query = queries[i];
168 if (mediaTypeMatch(query.mediaType())) {
169 auto& expressions = query.expressions();
171 for (; j < expressions.size(); ++j) {
172 bool expressionResult = evaluate(expressions[j]);
173 if (isViewportDependent(expressions[j].mediaFeature()))
174 results.append({ expressions[j], expressionResult });
175 if (!expressionResult)
178 result = applyRestrictor(query.restrictor(), expressions.size() == j);
180 result = applyRestrictor(query.restrictor(), false);
186 template<typename T, typename U> bool compareValue(T a, U b, MediaFeaturePrefix op)
199 static bool compareAspectRatioValue(CSSValue* value, int width, int height, MediaFeaturePrefix op)
201 if (!is<CSSAspectRatioValue>(value))
203 auto& aspectRatio = downcast<CSSAspectRatioValue>(*value);
204 return compareValue(width * aspectRatio.denominatorValue(), height * aspectRatio.numeratorValue(), op);
207 static Optional<double> doubleValue(CSSValue* value)
209 if (!is<CSSPrimitiveValue>(value) || !downcast<CSSPrimitiveValue>(*value).isNumber())
211 return downcast<CSSPrimitiveValue>(*value).doubleValue(CSSPrimitiveValue::CSS_NUMBER);
214 static bool zeroEvaluate(CSSValue* value, MediaFeaturePrefix op)
216 auto numericValue = doubleValue(value);
217 return numericValue && compareValue(0, numericValue.value(), op);
220 static bool oneEvaluate(CSSValue* value, MediaFeaturePrefix op)
224 auto numericValue = doubleValue(value);
225 return numericValue && compareValue(1, numericValue.value(), op);
228 static bool colorEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op)
230 int bitsPerComponent = screenDepthPerComponent(frame.mainFrame().view());
231 auto numericValue = doubleValue(value);
233 return bitsPerComponent;
234 return compareValue(bitsPerComponent, numericValue.value(), op);
237 static bool colorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op)
239 // Always return false for indexed display.
240 return zeroEvaluate(value, op);
243 static bool colorGamutEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix)
248 switch (downcast<CSSPrimitiveValue>(*value).valueID()) {
252 // FIXME: For the moment we just assume any "extended color" display is at least as good as P3.
253 return screenSupportsExtendedColor(frame.mainFrame().view());
254 case CSSValueRec2020:
255 // FIXME: At some point we should start detecting displays that support more colors.
262 static bool monochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op)
266 if (frame.settings().forcedDisplayIsMonochromeAccessibilityValue() == Settings::ForcedAccessibilityValue::On)
268 else if (frame.settings().forcedDisplayIsMonochromeAccessibilityValue() == Settings::ForcedAccessibilityValue::Off)
269 isMonochrome = false;
271 isMonochrome = screenIsMonochrome(frame.mainFrame().view());
274 return zeroEvaluate(value, op);
275 return colorEvaluate(value, conversionData, frame, op);
278 static bool invertedColorsEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix)
282 if (frame.settings().forcedColorsAreInvertedAccessibilityValue() == Settings::ForcedAccessibilityValue::On)
284 else if (frame.settings().forcedColorsAreInvertedAccessibilityValue() == Settings::ForcedAccessibilityValue::Off)
287 isInverted = screenHasInvertedColors();
292 return downcast<CSSPrimitiveValue>(*value).valueID() == (isInverted ? CSSValueInverted : CSSValueNone);
295 static bool orientationEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix)
297 FrameView* view = frame.view();
301 auto width = view->layoutWidth();
302 auto height = view->layoutHeight();
304 if (!is<CSSPrimitiveValue>(value)) {
305 // Expression (orientation) evaluates to true if width and height >= 0.
306 return height >= 0 && width >= 0;
309 auto keyword = downcast<CSSPrimitiveValue>(*value).valueID();
310 if (width > height) // Square viewport is portrait.
311 return keyword == CSSValueLandscape;
312 return keyword == CSSValuePortrait;
315 static bool aspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op)
317 // ({,min-,max-}aspect-ratio)
318 // assume if we have a device, its aspect ratio is non-zero
322 FrameView* view = frame.view();
326 return compareAspectRatioValue(value, view->layoutWidth(), view->layoutHeight(), op);
329 static bool deviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op)
331 // ({,min-,max-}device-aspect-ratio)
332 // assume if we have a device, its aspect ratio is non-zero
336 auto size = screenRect(frame.mainFrame().view()).size();
337 return compareAspectRatioValue(value, size.width(), size.height(), op);
340 static bool evaluateResolution(CSSValue* value, Frame& frame, MediaFeaturePrefix op)
342 // FIXME: Possible handle other media types than 'screen' and 'print'.
343 FrameView* view = frame.view();
347 float deviceScaleFactor = 0;
349 // This checks the actual media type applied to the document, and we know
350 // this method only got called if this media type matches the one defined
351 // in the query. Thus, if if the document's media type is "print", the
352 // media type of the query will either be "print" or "all".
353 String mediaType = view->mediaType();
354 if (equalLettersIgnoringASCIICase(mediaType, "screen"))
355 deviceScaleFactor = frame.page() ? frame.page()->deviceScaleFactor() : 1;
356 else if (equalLettersIgnoringASCIICase(mediaType, "print")) {
357 // The resolution of images while printing should not depend on the dpi
358 // of the screen. Until we support proper ways of querying this info
359 // we use 300px which is considered minimum for current printers.
360 deviceScaleFactor = 3.125; // 300dpi / 96dpi;
364 return !!deviceScaleFactor;
366 if (!is<CSSPrimitiveValue>(value))
369 auto& resolution = downcast<CSSPrimitiveValue>(*value);
370 return compareValue(deviceScaleFactor, resolution.isNumber() ? resolution.floatValue() : resolution.floatValue(CSSPrimitiveValue::CSS_DPPX), op);
373 static bool devicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op)
375 return (!value || (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).isNumber())) && evaluateResolution(value, frame, op);
378 static bool resolutionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op)
380 #if ENABLE(RESOLUTION_MEDIA_QUERY)
381 return (!value || (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).isResolution())) && evaluateResolution(value, frame, op);
390 static bool gridEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op)
392 return zeroEvaluate(value, op);
395 static bool computeLength(CSSValue* value, bool strict, const CSSToLengthConversionData& conversionData, int& result)
397 if (!is<CSSPrimitiveValue>(value))
400 auto& primitiveValue = downcast<CSSPrimitiveValue>(*value);
402 if (primitiveValue.isNumber()) {
403 result = primitiveValue.intValue();
404 return !strict || !result;
407 if (primitiveValue.isLength()) {
408 result = primitiveValue.computeLength<int>(conversionData);
415 static bool deviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op)
417 // ({,min-,max-}device-height)
418 // assume if we have a device, assume non-zero
422 auto height = screenRect(frame.mainFrame().view()).height();
423 return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(height, length, op);
426 static bool deviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op)
428 // ({,min-,max-}device-width)
429 // assume if we have a device, assume non-zero
433 auto width = screenRect(frame.mainFrame().view()).width();
434 return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(width, length, op);
437 static bool heightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op)
439 FrameView* view = frame.view();
442 int height = view->layoutHeight();
445 if (auto* renderView = frame.document()->renderView())
446 height = adjustForAbsoluteZoom(height, *renderView);
448 return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(height, length, op);
451 static bool widthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op)
453 FrameView* view = frame.view();
456 int width = view->layoutWidth();
459 if (auto* renderView = frame.document()->renderView())
460 width = adjustForAbsoluteZoom(width, *renderView);
462 return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(width, length, op);
465 static bool minColorEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
467 return colorEvaluate(value, conversionData, frame, MinPrefix);
470 static bool maxColorEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
472 return colorEvaluate(value, conversionData, frame, MaxPrefix);
475 static bool minColorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
477 return colorIndexEvaluate(value, conversionData, frame, MinPrefix);
480 static bool maxColorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
482 return colorIndexEvaluate(value, conversionData, frame, MaxPrefix);
485 static bool minMonochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
487 return monochromeEvaluate(value, conversionData, frame, MinPrefix);
490 static bool maxMonochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
492 return monochromeEvaluate(value, conversionData, frame, MaxPrefix);
495 static bool minAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
497 return aspectRatioEvaluate(value, conversionData, frame, MinPrefix);
500 static bool maxAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
502 return aspectRatioEvaluate(value, conversionData, frame, MaxPrefix);
505 static bool minDeviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
507 return deviceAspectRatioEvaluate(value, conversionData, frame, MinPrefix);
510 static bool maxDeviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
512 return deviceAspectRatioEvaluate(value, conversionData, frame, MaxPrefix);
515 static bool minDevicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
517 return devicePixelRatioEvaluate(value, conversionData, frame, MinPrefix);
520 static bool maxDevicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
522 return devicePixelRatioEvaluate(value, conversionData, frame, MaxPrefix);
525 static bool minHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
527 return heightEvaluate(value, conversionData, frame, MinPrefix);
530 static bool maxHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
532 return heightEvaluate(value, conversionData, frame, MaxPrefix);
535 static bool minWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
537 return widthEvaluate(value, conversionData, frame, MinPrefix);
540 static bool maxWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
542 return widthEvaluate(value, conversionData, frame, MaxPrefix);
545 static bool minDeviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
547 return deviceHeightEvaluate(value, conversionData, frame, MinPrefix);
550 static bool maxDeviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
552 return deviceHeightEvaluate(value, conversionData, frame, MaxPrefix);
555 static bool minDeviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
557 return deviceWidthEvaluate(value, conversionData, frame, MinPrefix);
560 static bool maxDeviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
562 return deviceWidthEvaluate(value, conversionData, frame, MaxPrefix);
565 static bool minResolutionEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
567 return resolutionEvaluate(value, conversionData, frame, MinPrefix);
570 static bool maxResolutionEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix)
572 return resolutionEvaluate(value, conversionData, frame, MaxPrefix);
575 static bool animationEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op)
577 return oneEvaluate(value, op);
580 static bool transitionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op)
582 return oneEvaluate(value, op);
585 static bool transform2dEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op)
587 return oneEvaluate(value, op);
590 static bool transform3dEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op)
592 #if ENABLE(3D_TRANSFORMS)
593 auto* view = frame.contentRenderer();
594 return view && view->compositor().canRender3DTransforms() ? oneEvaluate(value, op) : zeroEvaluate(value, op);
597 return zeroEvaluate(value, op);
601 #if ENABLE(VIEW_MODE_CSS_MEDIA)
603 static bool viewModeEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix)
608 auto keyword = downcast<CSSPrimitiveValue>(*value).valueID();
610 switch (frame.page()->viewMode()) {
611 case Page::ViewModeWindowed:
612 return keyword == CSSValueWindowed;
613 case Page::ViewModeFloating:
614 return keyword == CSSValueFloating;
615 case Page::ViewModeFullscreen:
616 return keyword == CSSValueFullscreen;
617 case Page::ViewModeMaximized:
618 return keyword == CSSValueMaximized;
619 case Page::ViewModeMinimized:
620 return keyword == CSSValueMinimized;
628 #endif // ENABLE(VIEW_MODE_CSS_MEDIA)
630 static bool videoPlayableInlineEvaluate(CSSValue*, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix)
632 return frame.settings().allowsInlineMediaPlayback();
635 static bool hoverEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix)
637 if (!is<CSSPrimitiveValue>(value)) {
638 #if ENABLE(TOUCH_EVENTS)
645 auto keyword = downcast<CSSPrimitiveValue>(*value).valueID();
646 #if ENABLE(TOUCH_EVENTS)
647 return keyword == CSSValueNone;
649 return keyword == CSSValueHover;
653 static bool anyHoverEvaluate(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame& frame, MediaFeaturePrefix prefix)
655 return hoverEvaluate(value, cssToLengthConversionData, frame, prefix);
658 static bool pointerEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix)
660 if (!is<CSSPrimitiveValue>(value))
663 auto keyword = downcast<CSSPrimitiveValue>(*value).valueID();
664 #if ENABLE(TOUCH_EVENTS)
665 return keyword == CSSValueCoarse;
667 return keyword == CSSValueFine;
671 static bool anyPointerEvaluate(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame& frame, MediaFeaturePrefix prefix)
673 return pointerEvaluate(value, cssToLengthConversionData, frame, prefix);
676 static bool prefersReducedMotionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix)
678 bool userPrefersReducedMotion = false;
680 if (frame.settings().forcedPrefersReducedMotionAccessibilityValue() == Settings::ForcedAccessibilityValue::On)
681 userPrefersReducedMotion = true;
682 else if (frame.settings().forcedPrefersReducedMotionAccessibilityValue() == Settings::ForcedAccessibilityValue::Off)
683 userPrefersReducedMotion = false;
684 #if PLATFORM(IOS) || USE(NEW_THEME)
686 userPrefersReducedMotion = platformTheme()->userPrefersReducedMotion();
690 return userPrefersReducedMotion;
692 return downcast<CSSPrimitiveValue>(*value).valueID() == (userPrefersReducedMotion ? CSSValueReduce : CSSValueDefault);
695 // Use this function instead of calling add directly to avoid inlining.
696 static void add(MediaQueryFunctionMap& map, AtomicStringImpl* key, MediaQueryFunction value)
701 bool MediaQueryEvaluator::evaluate(const MediaQueryExpression& expression) const
703 if (!m_frame || !m_frame->view() || !m_style)
704 return m_fallbackResult;
706 if (!expression.isValid())
709 static NeverDestroyed<MediaQueryFunctionMap> map = [] {
710 MediaQueryFunctionMap map;
711 #define ADD_TO_FUNCTIONMAP(name, str) add(map, MediaFeatureNames::name.impl(), name##Evaluate);
712 CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP);
713 #undef ADD_TO_FUNCTIONMAP
717 auto function = map.get().get(expression.mediaFeature().impl());
721 Document& document = *m_frame->document();
722 if (!document.documentElement())
724 return function(expression.value(), { m_style, document.documentElement()->renderStyle(), document.renderView(), 1, false }, *m_frame, NoPrefix);