diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/MediaQueryEvaluator.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/css/MediaQueryEvaluator.cpp')
-rw-r--r-- | Source/WebCore/css/MediaQueryEvaluator.cpp | 735 |
1 files changed, 367 insertions, 368 deletions
diff --git a/Source/WebCore/css/MediaQueryEvaluator.cpp b/Source/WebCore/css/MediaQueryEvaluator.cpp index 1d176edf1..f7027d28a 100644 --- a/Source/WebCore/css/MediaQueryEvaluator.cpp +++ b/Source/WebCore/css/MediaQueryEvaluator.cpp @@ -16,7 +16,7 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -31,20 +31,16 @@ #include "CSSAspectRatioValue.h" #include "CSSPrimitiveValue.h" +#include "CSSToLengthConversionData.h" #include "CSSValueKeywords.h" #include "CSSValueList.h" -#include "Chrome.h" -#include "ChromeClient.h" -#include "DOMWindow.h" #include "FloatRect.h" #include "FrameView.h" -#include "InspectorInstrumentation.h" #include "IntRect.h" #include "MainFrame.h" #include "MediaFeatureNames.h" #include "MediaList.h" #include "MediaQuery.h" -#include "MediaQueryExp.h" #include "NodeRenderStyle.h" #include "Page.h" #include "PlatformScreen.h" @@ -53,66 +49,66 @@ #include "Screen.h" #include "Settings.h" #include "StyleResolver.h" +#include "Theme.h" #include <wtf/HashMap.h> -#if ENABLE(3D_RENDERING) && USE(ACCELERATED_COMPOSITING) +#if ENABLE(3D_TRANSFORMS) #include "RenderLayerCompositor.h" #endif -#if PLATFORM(IOS) -#include "WebCoreSystemInterface.h" -#endif - namespace WebCore { -using namespace MediaFeatureNames; - enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix }; -typedef bool (*EvalFunc)(CSSValue*, RenderStyle*, Frame*, MediaFeaturePrefix); -typedef HashMap<AtomicStringImpl*, EvalFunc> FunctionMap; -static FunctionMap* gFunctionMap; +typedef bool (*MediaQueryFunction)(CSSValue*, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix); +typedef HashMap<AtomicStringImpl*, MediaQueryFunction> MediaQueryFunctionMap; -/* - * FIXME: following media features are not implemented: scan - * - * scan: The "scan" media feature describes the scanning process of - * tv output devices. It's unknown how to retrieve this information from - * the platform - */ +static bool isAccessibilitySettingsDependent(const AtomicString& mediaFeature) +{ + return mediaFeature == MediaFeatureNames::invertedColors + || mediaFeature == MediaFeatureNames::maxMonochrome + || mediaFeature == MediaFeatureNames::minMonochrome + || mediaFeature == MediaFeatureNames::monochrome + || mediaFeature == MediaFeatureNames::prefersReducedMotion; +} + +static bool isViewportDependent(const AtomicString& mediaFeature) +{ + return mediaFeature == MediaFeatureNames::width + || mediaFeature == MediaFeatureNames::height + || mediaFeature == MediaFeatureNames::minWidth + || mediaFeature == MediaFeatureNames::minHeight + || mediaFeature == MediaFeatureNames::maxWidth + || mediaFeature == MediaFeatureNames::maxHeight + || mediaFeature == MediaFeatureNames::orientation + || mediaFeature == MediaFeatureNames::aspectRatio + || mediaFeature == MediaFeatureNames::minAspectRatio + || mediaFeature == MediaFeatureNames::maxAspectRatio; +} MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult) - : m_frame(0) - , m_style(0) - , m_expResult(mediaFeatureResult) + : m_fallbackResult(mediaFeatureResult) { } MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult) : m_mediaType(acceptedMediaType) - , m_frame(0) - , m_style(0) - , m_expResult(mediaFeatureResult) + , m_fallbackResult(mediaFeatureResult) { } -MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, Frame* frame, RenderStyle* style) +MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, const Document& document, const RenderStyle* style) : m_mediaType(acceptedMediaType) - , m_frame(frame) + , m_frame(document.frame()) , m_style(style) - , m_expResult(false) // doesn't matter when we have m_frame and m_style -{ -} - -MediaQueryEvaluator::~MediaQueryEvaluator() { } bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const { return mediaTypeToMatch.isEmpty() - || equalIgnoringCase(mediaTypeToMatch, "all") - || equalIgnoringCase(mediaTypeToMatch, m_mediaType); + || equalLettersIgnoringASCIICase(mediaTypeToMatch, "all") + || equalIgnoringASCIICase(mediaTypeToMatch, m_mediaType); } bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const @@ -120,8 +116,8 @@ bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) c // Like mediaTypeMatch, but without the special cases for "" and "all". ASSERT(mediaTypeToMatch); ASSERT(mediaTypeToMatch[0] != '\0'); - ASSERT(!equalIgnoringCase(mediaTypeToMatch, String("all"))); - return equalIgnoringCase(mediaTypeToMatch, m_mediaType); + ASSERT(!equalLettersIgnoringASCIICase(StringView(mediaTypeToMatch), "all")); + return equalIgnoringASCIICase(m_mediaType, mediaTypeToMatch); } static bool applyRestrictor(MediaQuery::Restrictor r, bool value) @@ -129,48 +125,75 @@ static bool applyRestrictor(MediaQuery::Restrictor r, bool value) return r == MediaQuery::Not ? !value : value; } -bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, StyleResolver* styleResolver) const +bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, StyleResolver* styleResolver) const { - if (!querySet) - return true; - - const Vector<OwnPtr<MediaQuery>>& queries = querySet->queryVector(); + auto& queries = querySet.queryVector(); if (!queries.size()) - return true; // empty query list evaluates to true + return true; // Empty query list evaluates to true. - // iterate over queries, stop if any of them eval to true (OR semantics) + // Iterate over queries, stop if any of them eval to true (OR semantics). bool result = false; for (size_t i = 0; i < queries.size() && !result; ++i) { - MediaQuery* query = queries[i].get(); + auto& query = queries[i]; - if (query->ignored()) + if (query.ignored() || (!query.expressions().size() && query.mediaType().isEmpty())) continue; - if (mediaTypeMatch(query->mediaType())) { - const Vector<OwnPtr<MediaQueryExp>>& expressions = query->expressions(); - // iterate through expressions, stop if any of them eval to false - // (AND semantics) + if (mediaTypeMatch(query.mediaType())) { + auto& expressions = query.expressions(); + // Iterate through expressions, stop if any of them eval to false (AND semantics). size_t j = 0; for (; j < expressions.size(); ++j) { - bool exprResult = eval(expressions.at(j).get()); - if (styleResolver && expressions.at(j)->isViewportDependent()) - styleResolver->addViewportDependentMediaQueryResult(expressions.at(j).get(), exprResult); - if (!exprResult) + bool expressionResult = evaluate(expressions[j]); + if (styleResolver && isViewportDependent(expressions[j].mediaFeature())) + styleResolver->addViewportDependentMediaQueryResult(expressions[j], expressionResult); + if (styleResolver && isAccessibilitySettingsDependent(expressions[j].mediaFeature())) + styleResolver->addAccessibilitySettingsDependentMediaQueryResult(expressions[j], expressionResult); + if (!expressionResult) break; } - // assume true if we are at the end of the list, - // otherwise assume false - result = applyRestrictor(query->restrictor(), expressions.size() == j); + // Assume true if we are at the end of the list, otherwise assume false. + result = applyRestrictor(query.restrictor(), expressions.size() == j); } else - result = applyRestrictor(query->restrictor(), false); + result = applyRestrictor(query.restrictor(), false); } return result; } -template<typename T> -bool compareValue(T a, T b, MediaFeaturePrefix op) +bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, Vector<MediaQueryResult>& results) const +{ + auto& queries = querySet.queryVector(); + if (!queries.size()) + return true; + + bool result = false; + for (size_t i = 0; i < queries.size() && !result; ++i) { + auto& query = queries[i]; + + if (query.ignored()) + continue; + + if (mediaTypeMatch(query.mediaType())) { + auto& expressions = query.expressions(); + size_t j = 0; + for (; j < expressions.size(); ++j) { + bool expressionResult = evaluate(expressions[j]); + if (isViewportDependent(expressions[j].mediaFeature())) + results.append({ expressions[j], expressionResult }); + if (!expressionResult) + break; + } + result = applyRestrictor(query.restrictor(), expressions.size() == j); + } else + result = applyRestrictor(query.restrictor(), false); + } + + return result; +} + +template<typename T, typename U> bool compareValue(T a, U b, MediaFeaturePrefix op) { switch (op) { case MinPrefix: @@ -185,119 +208,162 @@ bool compareValue(T a, T b, MediaFeaturePrefix op) static bool compareAspectRatioValue(CSSValue* value, int width, int height, MediaFeaturePrefix op) { - if (value->isAspectRatioValue()) { - CSSAspectRatioValue* aspectRatio = toCSSAspectRatioValue(value); - return compareValue(width * static_cast<int>(aspectRatio->denominatorValue()), height * static_cast<int>(aspectRatio->numeratorValue()), op); - } + if (!is<CSSAspectRatioValue>(value)) + return false; + auto& aspectRatio = downcast<CSSAspectRatioValue>(*value); + return compareValue(width * aspectRatio.denominatorValue(), height * aspectRatio.numeratorValue(), op); +} - return false; +static std::optional<double> doubleValue(CSSValue* value) +{ + if (!is<CSSPrimitiveValue>(value) || !downcast<CSSPrimitiveValue>(*value).isNumber()) + return std::nullopt; + return downcast<CSSPrimitiveValue>(*value).doubleValue(CSSPrimitiveValue::CSS_NUMBER); } -static bool numberValue(CSSValue* value, float& result) +static bool zeroEvaluate(CSSValue* value, MediaFeaturePrefix op) { - if (value->isPrimitiveValue() - && toCSSPrimitiveValue(value)->isNumber()) { - result = toCSSPrimitiveValue(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); + auto numericValue = doubleValue(value); + return numericValue && compareValue(0, numericValue.value(), op); +} + +static bool oneEvaluate(CSSValue* value, MediaFeaturePrefix op) +{ + if (!value) return true; - } - return false; + auto numericValue = doubleValue(value); + return numericValue && compareValue(1, numericValue.value(), op); } -static bool colorMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool colorEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - int bitsPerComponent = screenDepthPerComponent(frame->page()->mainFrame().view()); - float number; - if (value) - return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op); + int bitsPerComponent = screenDepthPerComponent(frame.mainFrame().view()); + auto numericValue = doubleValue(value); + if (!numericValue) + return bitsPerComponent; + return compareValue(bitsPerComponent, numericValue.value(), op); +} - return bitsPerComponent != 0; +static bool colorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) +{ + // Always return false for indexed display. + return zeroEvaluate(value, op); } -static bool color_indexMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool colorGamutEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - // FIXME: It's unknown how to retrieve the information if the display mode is indexed - // Assume we don't support indexed display. if (!value) + return true; + + switch (downcast<CSSPrimitiveValue>(*value).valueID()) { + case CSSValueSRGB: + return true; + case CSSValueP3: + // FIXME: For the moment we just assume any "extended color" display is at least as good as P3. + return screenSupportsExtendedColor(frame.mainFrame().view()); + case CSSValueRec2020: + // FIXME: At some point we should start detecting displays that support more colors. return false; + default: + return false; // Any unknown value should not be considered a match. + } +} + +static bool monochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) +{ + bool isMonochrome; + + if (frame.settings().forcedDisplayIsMonochromeAccessibilityValue() == Settings::ForcedAccessibilityValue::On) + isMonochrome = true; + else if (frame.settings().forcedDisplayIsMonochromeAccessibilityValue() == Settings::ForcedAccessibilityValue::Off) + isMonochrome = false; + else + isMonochrome = screenIsMonochrome(frame.mainFrame().view()); - float number; - return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); + if (!isMonochrome) + return zeroEvaluate(value, op); + return colorEvaluate(value, conversionData, frame, op); } -static bool monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool invertedColorsEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - if (!screenIsMonochrome(frame->page()->mainFrame().view())) { - if (value) { - float number; - return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); - } - return false; - } + bool isInverted; + + if (frame.settings().forcedColorsAreInvertedAccessibilityValue() == Settings::ForcedAccessibilityValue::On) + isInverted = true; + else if (frame.settings().forcedColorsAreInvertedAccessibilityValue() == Settings::ForcedAccessibilityValue::Off) + isInverted = false; + else + isInverted = screenHasInvertedColors(); - return colorMediaFeatureEval(value, style, frame, op); + if (!value) + return isInverted; + + return downcast<CSSPrimitiveValue>(*value).valueID() == (isInverted ? CSSValueInverted : CSSValueNone); } -static bool orientationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool orientationEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; - int width = view->layoutWidth(); - int height = view->layoutHeight(); - if (value && value->isPrimitiveValue()) { - const CSSValueID id = toCSSPrimitiveValue(value)->getValueID(); - if (width > height) // Square viewport is portrait. - return CSSValueLandscape == id; - return CSSValuePortrait == id; + auto width = view->layoutWidth(); + auto height = view->layoutHeight(); + + if (!is<CSSPrimitiveValue>(value)) { + // Expression (orientation) evaluates to true if width and height >= 0. + return height >= 0 && width >= 0; } - // Expression (orientation) evaluates to true if width and height >= 0. - return height >= 0 && width >= 0; + auto keyword = downcast<CSSPrimitiveValue>(*value).valueID(); + if (width > height) // Square viewport is portrait. + return keyword == CSSValueLandscape; + return keyword == CSSValuePortrait; } -static bool aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool aspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - FrameView* view = frame->view(); - if (!view) + // ({,min-,max-}aspect-ratio) + // assume if we have a device, its aspect ratio is non-zero + if (!value) return true; - if (value) - return compareAspectRatioValue(value, view->layoutWidth(), view->layoutHeight(), op); + FrameView* view = frame.view(); + if (!view) + return true; - // ({,min-,max-}aspect-ratio) - // assume if we have a device, its aspect ratio is non-zero - return true; + return compareAspectRatioValue(value, view->layoutWidth(), view->layoutHeight(), op); } -static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool deviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - if (value) { - FloatRect sg = screenRect(frame->page()->mainFrame().view()); - return compareAspectRatioValue(value, static_cast<int>(sg.width()), static_cast<int>(sg.height()), op); - } - // ({,min-,max-}device-aspect-ratio) // assume if we have a device, its aspect ratio is non-zero - return true; + if (!value) + return true; + + auto size = screenRect(frame.mainFrame().view()).size(); + return compareAspectRatioValue(value, size.width(), size.height(), op); } -static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) +static bool evaluateResolution(CSSValue* value, Frame& frame, MediaFeaturePrefix op) { // FIXME: Possible handle other media types than 'screen' and 'print'. - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; float deviceScaleFactor = 0; + // This checks the actual media type applied to the document, and we know // this method only got called if this media type matches the one defined // in the query. Thus, if if the document's media type is "print", the // media type of the query will either be "print" or "all". String mediaType = view->mediaType(); - if (equalIgnoringCase(mediaType, "screen")) - deviceScaleFactor = frame->page()->deviceScaleFactor(); - else if (equalIgnoringCase(mediaType, "print")) { + if (equalLettersIgnoringASCIICase(mediaType, "screen")) + deviceScaleFactor = frame.page() ? frame.page()->deviceScaleFactor() : 1; + else if (equalLettersIgnoringASCIICase(mediaType, "print")) { // The resolution of images while printing should not depend on the dpi // of the screen. Until we support proper ways of querying this info // we use 300px which is considered minimum for current printers. @@ -307,22 +373,22 @@ static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) if (!value) return !!deviceScaleFactor; - if (!value->isPrimitiveValue()) + if (!is<CSSPrimitiveValue>(value)) return false; - CSSPrimitiveValue* resolution = toCSSPrimitiveValue(value); - return compareValue(deviceScaleFactor, resolution->isNumber() ? resolution->getFloatValue() : resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX), op); + auto& resolution = downcast<CSSPrimitiveValue>(*value); + return compareValue(deviceScaleFactor, resolution.isNumber() ? resolution.floatValue() : resolution.floatValue(CSSPrimitiveValue::CSS_DPPX), op); } -static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool devicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - return (!value || toCSSPrimitiveValue(value)->isNumber()) && evalResolution(value, frame, op); + return (!value || (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).isNumber())) && evaluateResolution(value, frame, op); } -static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool resolutionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { #if ENABLE(RESOLUTION_MEDIA_QUERY) - return (!value || toCSSPrimitiveValue(value)->isResolution()) && evalResolution(value, frame, op); + return (!value || (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).isResolution())) && evaluateResolution(value, frame, op); #else UNUSED_PARAM(value); UNUSED_PARAM(frame); @@ -331,408 +397,341 @@ static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra #endif } -static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool gridEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - // if output device is bitmap, grid: 0 == true - // assume we have bitmap device - float number; - if (value && numberValue(value, number)) - return compareValue(static_cast<int>(number), 0, op); - return false; + return zeroEvaluate(value, op); } -static bool computeLength(CSSValue* value, bool strict, RenderStyle* style, RenderStyle* rootStyle, int& result) +static bool computeLength(CSSValue* value, bool strict, const CSSToLengthConversionData& conversionData, int& result) { - if (!value->isPrimitiveValue()) + if (!is<CSSPrimitiveValue>(value)) return false; - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); + auto& primitiveValue = downcast<CSSPrimitiveValue>(*value); - if (primitiveValue->isNumber()) { - result = primitiveValue->getIntValue(); + if (primitiveValue.isNumber()) { + result = primitiveValue.intValue(); return !strict || !result; } - if (primitiveValue->isLength()) { - result = primitiveValue->computeLength<int>(style, rootStyle); + if (primitiveValue.isLength()) { + result = primitiveValue.computeLength<int>(conversionData); return true; } return false; } -static bool device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool deviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - if (value) { - FloatRect sg = screenRect(frame->page()->mainFrame().view()); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - long height = sg.height(); - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast<int>(height), length, op); - } // ({,min-,max-}device-height) // assume if we have a device, assume non-zero - return true; + if (!value) + return true; + int length; + auto height = screenRect(frame.mainFrame().view()).height(); + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(height, length, op); } -static bool device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool deviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - if (value) { - FloatRect sg = screenRect(frame->page()->mainFrame().view()); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - long width = sg.width(); - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(static_cast<int>(width), length, op); - } // ({,min-,max-}device-width) // assume if we have a device, assume non-zero - return true; + if (!value) + return true; + int length; + auto width = screenRect(frame.mainFrame().view()).width(); + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(width, length, op); } -static bool heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool heightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; - - if (value) { - int height = view->layoutHeight(); - if (RenderView* renderView = frame->document()->renderView()) - height = adjustForAbsoluteZoom(height, *renderView); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(height, length, op); - } - - return view->layoutHeight() != 0; + int height = view->layoutHeight(); + if (!value) + return height; + if (auto* renderView = frame.document()->renderView()) + height = adjustForAbsoluteZoom(height, *renderView); + int length; + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(height, length, op); } -static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) +static bool widthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix op) { - FrameView* view = frame->view(); + FrameView* view = frame.view(); if (!view) return false; - - if (value) { - int width = view->layoutWidth(); - if (RenderView* renderView = frame->document()->renderView()) - width = adjustForAbsoluteZoom(width, *renderView); - RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); - int length; - return computeLength(value, !frame->document()->inQuirksMode(), style, rootStyle, length) && compareValue(width, length, op); - } - - return view->layoutWidth() != 0; + int width = view->layoutWidth(); + if (!value) + return width; + if (auto* renderView = frame.document()->renderView()) + width = adjustForAbsoluteZoom(width, *renderView); + int length; + return computeLength(value, !frame.document()->inQuirksMode(), conversionData, length) && compareValue(width, length, op); } -// rest of the functions are trampolines which set the prefix according to the media feature expression used - -static bool min_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minColorEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return colorMediaFeatureEval(value, style, frame, MinPrefix); + return colorEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxColorEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return colorMediaFeatureEval(value, style, frame, MaxPrefix); + return colorEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_color_indexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minColorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return color_indexMediaFeatureEval(value, style, frame, MinPrefix); + return colorIndexEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_color_indexMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxColorIndexEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return color_indexMediaFeatureEval(value, style, frame, MaxPrefix); + return colorIndexEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minMonochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return monochromeMediaFeatureEval(value, style, frame, MinPrefix); + return monochromeEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxMonochromeEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return monochromeMediaFeatureEval(value, style, frame, MaxPrefix); + return monochromeEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); + return aspectRatioEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); + return aspectRatioEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDeviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); + return deviceAspectRatioEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDeviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); + return deviceAspectRatioEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDevicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_pixel_ratioMediaFeatureEval(value, style, frame, MinPrefix); + return devicePixelRatioEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDevicePixelRatioEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_pixel_ratioMediaFeatureEval(value, style, frame, MaxPrefix); + return devicePixelRatioEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return heightMediaFeatureEval(value, style, frame, MinPrefix); + return heightEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return heightMediaFeatureEval(value, style, frame, MaxPrefix); + return heightEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return widthMediaFeatureEval(value, style, frame, MinPrefix); + return widthEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return widthMediaFeatureEval(value, style, frame, MaxPrefix); + return widthEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDeviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_heightMediaFeatureEval(value, style, frame, MinPrefix); + return deviceHeightEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDeviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_heightMediaFeatureEval(value, style, frame, MaxPrefix); + return deviceHeightEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minDeviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_widthMediaFeatureEval(value, style, frame, MinPrefix); + return deviceWidthEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxDeviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return device_widthMediaFeatureEval(value, style, frame, MaxPrefix); + return deviceWidthEvaluate(value, conversionData, frame, MaxPrefix); } -static bool min_resolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool minResolutionEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return resolutionMediaFeatureEval(value, style, frame, MinPrefix); + return resolutionEvaluate(value, conversionData, frame, MinPrefix); } -static bool max_resolutionMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) +static bool maxResolutionEvaluate(CSSValue* value, const CSSToLengthConversionData& conversionData, Frame& frame, MediaFeaturePrefix) { - return resolutionMediaFeatureEval(value, style, frame, MaxPrefix); + return resolutionEvaluate(value, conversionData, frame, MaxPrefix); } -static bool animationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool animationEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - if (value) { - float number; - return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); - } - return true; + return oneEvaluate(value, op); } -static bool transitionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool transitionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - if (value) { - float number; - return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); - } - return true; + return oneEvaluate(value, op); } -static bool transform_2dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) +static bool transform2dEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix op) { - if (value) { - float number; - return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); - } - return true; + return oneEvaluate(value, op); } -static bool transform_3dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) +static bool transform3dEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix op) { - bool returnValueIfNoParameter; - int have3dRendering; - -#if ENABLE(3D_RENDERING) - bool threeDEnabled = false; -#if USE(ACCELERATED_COMPOSITING) - if (RenderView* view = frame->contentRenderer()) - threeDEnabled = view->compositor().canRender3DTransforms(); -#endif - - returnValueIfNoParameter = threeDEnabled; - have3dRendering = threeDEnabled ? 1 : 0; +#if ENABLE(3D_TRANSFORMS) + auto* view = frame.contentRenderer(); + return view && view->compositor().canRender3DTransforms() ? oneEvaluate(value, op) : zeroEvaluate(value, op); #else UNUSED_PARAM(frame); - returnValueIfNoParameter = false; - have3dRendering = 0; + return zeroEvaluate(value, op); #endif - - if (value) { - float number; - return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op); - } - return returnValueIfNoParameter; } #if ENABLE(VIEW_MODE_CSS_MEDIA) -static bool view_modeMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) + +static bool viewModeEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - UNUSED_PARAM(op); if (!value) return true; - const int viewModeCSSKeywordID = toCSSPrimitiveValue(value)->getValueID(); - const Page::ViewMode viewMode = frame->page()->viewMode(); - bool result = false; - switch (viewMode) { + auto keyword = downcast<CSSPrimitiveValue>(*value).valueID(); + + switch (frame.page()->viewMode()) { case Page::ViewModeWindowed: - result = viewModeCSSKeywordID == CSSValueWindowed; - break; + return keyword == CSSValueWindowed; case Page::ViewModeFloating: - result = viewModeCSSKeywordID == CSSValueFloating; - break; + return keyword == CSSValueFloating; case Page::ViewModeFullscreen: - result = viewModeCSSKeywordID == CSSValueFullscreen; - break; + return keyword == CSSValueFullscreen; case Page::ViewModeMaximized: - result = viewModeCSSKeywordID == CSSValueMaximized; - break; + return keyword == CSSValueMaximized; case Page::ViewModeMinimized: - result = viewModeCSSKeywordID == CSSValueMinimized; - break; + return keyword == CSSValueMinimized; default: - result = false; break; } - return result; + return false; } + #endif // ENABLE(VIEW_MODE_CSS_MEDIA) -// FIXME: Find a better place for this function. Maybe ChromeClient? -static inline bool isRunningOnIPhoneOrIPod() +static bool videoPlayableInlineEvaluate(CSSValue*, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) +{ + return frame.settings().allowsInlineMediaPlayback(); +} + +static bool hoverEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix) { -#if PLATFORM(IOS) - static wkDeviceClass deviceClass = iosDeviceClass(); - return deviceClass == wkDeviceClassiPhone || deviceClass == wkDeviceClassiPod; + if (!is<CSSPrimitiveValue>(value)) { +#if ENABLE(TOUCH_EVENTS) + return false; #else - return false; + return true; +#endif + } + + auto keyword = downcast<CSSPrimitiveValue>(*value).valueID(); +#if ENABLE(TOUCH_EVENTS) + return keyword == CSSValueNone; +#else + return keyword == CSSValueHover; #endif } -static bool video_playable_inlineMediaFeatureEval(CSSValue*, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool anyHoverEvaluate(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame& frame, MediaFeaturePrefix prefix) { - return !isRunningOnIPhoneOrIPod() || frame->settings().mediaPlaybackAllowsInline(); + return hoverEvaluate(value, cssToLengthConversionData, frame, prefix); } -enum PointerDeviceType { TouchPointer, MousePointer, NoPointer, UnknownPointer }; - -static PointerDeviceType leastCapablePrimaryPointerDeviceType(Frame* frame) +static bool pointerEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix) { - if (frame->settings().deviceSupportsTouch()) - return TouchPointer; - - // FIXME: We should also try to determine if we know we have a mouse. - // When we do this, we'll also need to differentiate between known not to - // have mouse or touch screen (NoPointer) and unknown (UnknownPointer). - // We could also take into account other preferences like accessibility - // settings to decide which of the available pointers should be considered - // "primary". + if (!is<CSSPrimitiveValue>(value)) + return true; - return UnknownPointer; + auto keyword = downcast<CSSPrimitiveValue>(*value).valueID(); +#if ENABLE(TOUCH_EVENTS) + return keyword == CSSValueCoarse; +#else + return keyword == CSSValueFine; +#endif } -static bool hoverMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool anyPointerEvaluate(CSSValue* value, const CSSToLengthConversionData& cssToLengthConversionData, Frame& frame, MediaFeaturePrefix prefix) { - PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame); - - // If we're on a port that hasn't explicitly opted into providing pointer device information - // (or otherwise can't be confident in the pointer hardware available), then behave exactly - // as if this feature feature isn't supported. - if (pointer == UnknownPointer) - return false; - - float number = 1; - if (value) { - if (!numberValue(value, number)) - return false; - } - - return (pointer == NoPointer && !number) - || (pointer == TouchPointer && !number) - || (pointer == MousePointer && number == 1); + return pointerEvaluate(value, cssToLengthConversionData, frame, prefix); } -static bool pointerMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) +static bool prefersReducedMotionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { - PointerDeviceType pointer = leastCapablePrimaryPointerDeviceType(frame); + bool userPrefersReducedMotion = false; - // If we're on a port that hasn't explicitly opted into providing pointer device information - // (or otherwise can't be confident in the pointer hardware available), then behave exactly - // as if this feature feature isn't supported. - if (pointer == UnknownPointer) - return false; + if (frame.settings().forcedPrefersReducedMotionAccessibilityValue() == Settings::ForcedAccessibilityValue::On) + userPrefersReducedMotion = true; + else if (frame.settings().forcedPrefersReducedMotionAccessibilityValue() == Settings::ForcedAccessibilityValue::Off) + userPrefersReducedMotion = false; +#if PLATFORM(IOS) || USE(NEW_THEME) + else + userPrefersReducedMotion = platformTheme()->userPrefersReducedMotion(); +#endif if (!value) - return pointer != NoPointer; + return userPrefersReducedMotion; - if (!value->isPrimitiveValue()) - return false; - - const CSSValueID id = toCSSPrimitiveValue(value)->getValueID(); - return (pointer == NoPointer && id == CSSValueNone) - || (pointer == TouchPointer && id == CSSValueCoarse) - || (pointer == MousePointer && id == CSSValueFine); + return downcast<CSSPrimitiveValue>(*value).valueID() == (userPrefersReducedMotion ? CSSValueReduce : CSSValueNoPreference); } -// FIXME: Remove unnecessary '&' from the following 'ADD_TO_FUNCTIONMAP' definition -// once we switch to a non-broken Visual Studio compiler. https://bugs.webkit.org/show_bug.cgi?id=121235 -static void createFunctionMap() +// Use this function instead of calling add directly to avoid inlining. +static void add(MediaQueryFunctionMap& map, AtomicStringImpl* key, MediaQueryFunction value) { - // Create the table. - gFunctionMap = new FunctionMap; -#define ADD_TO_FUNCTIONMAP(name, str) \ - gFunctionMap->set(name##MediaFeature.impl(), &name##MediaFeatureEval); - CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); -#undef ADD_TO_FUNCTIONMAP + map.add(key, value); } -bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const +bool MediaQueryEvaluator::evaluate(const MediaQueryExpression& expression) const { if (!m_frame || !m_frame->view() || !m_style) - return m_expResult; + return m_fallbackResult; - if (!expr->isValid()) + if (!expression.isValid()) return false; - if (!gFunctionMap) - createFunctionMap(); + static NeverDestroyed<MediaQueryFunctionMap> map = [] { + MediaQueryFunctionMap map; +#define ADD_TO_FUNCTIONMAP(name, str) add(map, MediaFeatureNames::name.impl(), name##Evaluate); + CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); +#undef ADD_TO_FUNCTIONMAP + return map; + }(); - // call the media feature evaluation function. Assume no prefix - // and let trampoline functions override the prefix if prefix is - // used - EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); - if (func) - return func(expr->value(), m_style.get(), m_frame, NoPrefix); + auto function = map.get().get(expression.mediaFeature().impl()); + if (!function) + return false; - return false; + Document& document = *m_frame->document(); + if (!document.documentElement()) + return false; + return function(expression.value(), { m_style, document.documentElement()->renderStyle(), document.renderView(), 1, false }, *m_frame, NoPrefix); } } // namespace |