This source file includes following definitions.
- m_expectedResult
- m_expectedResult
- m_mediaValues
- m_mediaValues
- mediaTypeMatch
- mediaTypeMatchSpecific
- applyRestrictor
- eval
- compareValue
- compareAspectRatioValue
- numberValue
- colorMediaFeatureEval
- colorIndexMediaFeatureEval
- monochromeMediaFeatureEval
- orientationMediaFeatureEval
- aspectRatioMediaFeatureEval
- deviceAspectRatioMediaFeatureEval
- evalResolution
- devicePixelRatioMediaFeatureEval
- resolutionMediaFeatureEval
- gridMediaFeatureEval
- computeLengthWithoutStyle
- computeLength
- deviceHeightMediaFeatureEval
- deviceWidthMediaFeatureEval
- heightMediaFeatureEval
- widthMediaFeatureEval
- minColorMediaFeatureEval
- maxColorMediaFeatureEval
- minColorIndexMediaFeatureEval
- maxColorIndexMediaFeatureEval
- minMonochromeMediaFeatureEval
- maxMonochromeMediaFeatureEval
- minAspectRatioMediaFeatureEval
- maxAspectRatioMediaFeatureEval
- minDeviceAspectRatioMediaFeatureEval
- maxDeviceAspectRatioMediaFeatureEval
- minDevicePixelRatioMediaFeatureEval
- maxDevicePixelRatioMediaFeatureEval
- minHeightMediaFeatureEval
- maxHeightMediaFeatureEval
- minWidthMediaFeatureEval
- maxWidthMediaFeatureEval
- minDeviceHeightMediaFeatureEval
- maxDeviceHeightMediaFeatureEval
- minDeviceWidthMediaFeatureEval
- maxDeviceWidthMediaFeatureEval
- minResolutionMediaFeatureEval
- maxResolutionMediaFeatureEval
- animationMediaFeatureEval
- transform2dMediaFeatureEval
- transform3dMediaFeatureEval
- viewModeMediaFeatureEval
- hoverMediaFeatureEval
- pointerMediaFeatureEval
- scanMediaFeatureEval
- createFunctionMap
- eval
#include "config.h"
#include "core/css/MediaQueryEvaluator.h"
#include "CSSValueKeywords.h"
#include "MediaFeatureNames.h"
#include "MediaFeatures.h"
#include "MediaTypeNames.h"
#include "core/css/CSSAspectRatioValue.h"
#include "core/css/CSSHelper.h"
#include "core/css/CSSPrimitiveValue.h"
#include "core/css/CSSToLengthConversionData.h"
#include "core/css/MediaList.h"
#include "core/css/MediaQuery.h"
#include "core/css/MediaValues.h"
#include "core/css/resolver/MediaQueryResult.h"
#include "core/dom/NodeRenderStyle.h"
#include "core/frame/FrameHost.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "core/rendering/RenderView.h"
#include "core/rendering/compositing/RenderLayerCompositor.h"
#include "core/rendering/style/RenderStyle.h"
#include "platform/PlatformScreen.h"
#include "platform/geometry/FloatRect.h"
#include "wtf/HashMap.h"
namespace WebCore {
using namespace MediaFeatureNames;
enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
typedef bool (*EvalFunc)(CSSValue*, MediaFeaturePrefix, const MediaValues&);
typedef HashMap<StringImpl*, EvalFunc> FunctionMap;
static FunctionMap* gFunctionMap;
MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
: m_expectedResult(mediaFeatureResult)
{
}
MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult)
: m_mediaType(acceptedMediaType)
, m_expectedResult(mediaFeatureResult)
{
}
MediaQueryEvaluator::MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult)
: m_mediaType(acceptedMediaType)
, m_expectedResult(mediaFeatureResult)
{
}
MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, LocalFrame* frame, RenderStyle* style)
: m_mediaType(acceptedMediaType)
, m_expectedResult(false)
, m_mediaValues(MediaValues::create(frame, style, MediaValues::DynamicMode))
{
}
MediaQueryEvaluator::MediaQueryEvaluator(const String& acceptedMediaType, const MediaValues& mediaValues)
: m_mediaType(acceptedMediaType)
, m_expectedResult(false)
, m_mediaValues(mediaValues.copy())
{
}
MediaQueryEvaluator::~MediaQueryEvaluator()
{
}
bool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const
{
return mediaTypeToMatch.isEmpty()
|| equalIgnoringCase(mediaTypeToMatch, MediaTypeNames::all)
|| equalIgnoringCase(mediaTypeToMatch, m_mediaType);
}
bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const
{
ASSERT(mediaTypeToMatch);
ASSERT(mediaTypeToMatch[0] != '\0');
ASSERT(!equalIgnoringCase(mediaTypeToMatch, MediaTypeNames::all));
return equalIgnoringCase(mediaTypeToMatch, m_mediaType);
}
static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
{
return r == MediaQuery::Not ? !value : value;
}
bool MediaQueryEvaluator::eval(const MediaQuerySet* querySet, MediaQueryResultList* viewportDependentMediaQueryResults) const
{
if (!querySet)
return true;
const WillBeHeapVector<OwnPtrWillBeMember<MediaQuery> >& queries = querySet->queryVector();
if (!queries.size())
return true;
bool result = false;
for (size_t i = 0; i < queries.size() && !result; ++i) {
MediaQuery* query = queries[i].get();
if (mediaTypeMatch(query->mediaType())) {
const ExpressionHeapVector& expressions = query->expressions();
size_t j = 0;
for (; j < expressions.size(); ++j) {
bool exprResult = eval(expressions.at(j).get());
if (viewportDependentMediaQueryResults && expressions.at(j)->isViewportDependent())
viewportDependentMediaQueryResults->append(adoptRefWillBeNoop(new MediaQueryResult(*expressions.at(j), exprResult)));
if (!exprResult)
break;
}
result = applyRestrictor(query->restrictor(), expressions.size() == j);
} else {
result = applyRestrictor(query->restrictor(), false);
}
}
return result;
}
template<typename T>
bool compareValue(T a, T b, MediaFeaturePrefix op)
{
switch (op) {
case MinPrefix:
return a >= b;
case MaxPrefix:
return a <= b;
case NoPrefix:
return a == b;
}
return false;
}
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);
}
return false;
}
static bool numberValue(CSSValue* value, float& result)
{
if (value->isPrimitiveValue()
&& toCSSPrimitiveValue(value)->isNumber()) {
result = toCSSPrimitiveValue(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER);
return true;
}
return false;
}
static bool colorMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
float number;
int bitsPerComponent = mediaValues.colorBitsPerComponent();
if (value)
return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op);
return bitsPerComponent != 0;
}
static bool colorIndexMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues&)
{
if (!value)
return false;
float number;
return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
}
static bool monochromeMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
if (!mediaValues.monochromeBitsPerComponent()) {
if (value) {
float number;
return numberValue(value, number) && compareValue(0, static_cast<int>(number), op);
}
return false;
}
return colorMediaFeatureEval(value, op, mediaValues);
}
static bool orientationMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
int width = mediaValues.viewportWidth();
int height = mediaValues.viewportHeight();
if (value && value->isPrimitiveValue()) {
const CSSValueID id = toCSSPrimitiveValue(value)->getValueID();
if (width > height)
return CSSValueLandscape == id;
return CSSValuePortrait == id;
}
return height >= 0 && width >= 0;
}
static bool aspectRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
if (value)
return compareAspectRatioValue(value, mediaValues.viewportWidth(), mediaValues.viewportHeight(), op);
return true;
}
static bool deviceAspectRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
if (value)
return compareAspectRatioValue(value, mediaValues.deviceWidth(), mediaValues.deviceHeight(), op);
return true;
}
static bool evalResolution(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
float actualResolution = 0;
if (mediaValues.screenMediaType()) {
actualResolution = clampTo<float>(mediaValues.devicePixelRatio());
} else if (mediaValues.printMediaType()) {
actualResolution = 300 / cssPixelsPerInch;
}
if (!value)
return !!actualResolution;
if (!value->isPrimitiveValue())
return false;
CSSPrimitiveValue* resolution = toCSSPrimitiveValue(value);
if (resolution->isNumber())
return compareValue(actualResolution, resolution->getFloatValue(), op);
if (!resolution->isResolution())
return false;
if (resolution->isDotsPerCentimeter()) {
return compareValue(
floorf(0.5 + 100 * actualResolution) / 100,
floorf(0.5 + 100 * resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX)) / 100, op);
}
return compareValue(actualResolution, resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX), op);
}
static bool devicePixelRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
UseCounter::count(mediaValues.document(), UseCounter::PrefixedDevicePixelRatioMediaFeature);
return (!value || toCSSPrimitiveValue(value)->isNumber()) && evalResolution(value, op, mediaValues);
}
static bool resolutionMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& MediaValues)
{
return (!value || toCSSPrimitiveValue(value)->isResolution()) && evalResolution(value, op, MediaValues);
}
static bool gridMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues&)
{
float number;
if (value && numberValue(value, number))
return compareValue(static_cast<int>(number), 0, op);
return false;
}
static bool computeLengthWithoutStyle(CSSPrimitiveValue* primitiveValue, int defaultFontSize, int& result)
{
unsigned short type = primitiveValue->primitiveType();
int factor = 0;
if (type == CSSPrimitiveValue::CSS_EMS || type == CSSPrimitiveValue::CSS_REMS) {
if (defaultFontSize > 0)
factor = defaultFontSize;
else
return false;
} else if (type == CSSPrimitiveValue::CSS_PX) {
factor = 1;
} else {
return false;
}
result = roundForImpreciseConversion<int>(primitiveValue->getDoubleValue()*factor);
return true;
}
static bool computeLength(CSSValue* value, bool strict, RenderStyle* initialStyle, int defaultFontSize, int& result)
{
if (!value->isPrimitiveValue())
return false;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (primitiveValue->isNumber()) {
result = primitiveValue->getIntValue();
return !strict || !result;
}
if (primitiveValue->isLength()) {
if (initialStyle) {
result = primitiveValue->computeLength<int>(CSSToLengthConversionData(initialStyle, initialStyle, 0, 1.0 , true ));
} else {
return computeLengthWithoutStyle(primitiveValue, defaultFontSize, result);
}
return true;
}
return false;
}
static bool deviceHeightMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
if (value) {
int length;
return computeLength(value, mediaValues.strictMode(), mediaValues.style(), mediaValues.defaultFontSize(), length)
&& compareValue(static_cast<int>(mediaValues.deviceHeight()), length, op);
}
return true;
}
static bool deviceWidthMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
if (value) {
int length;
return computeLength(value, mediaValues.strictMode(), mediaValues.style(), mediaValues.defaultFontSize(), length)
&& compareValue(static_cast<int>(mediaValues.deviceWidth()), length, op);
}
return true;
}
static bool heightMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
int height = mediaValues.viewportHeight();
if (value) {
int length;
return computeLength(value, mediaValues.strictMode(), mediaValues.style(), mediaValues.defaultFontSize(), length)
&& compareValue(height, length, op);
}
return height;
}
static bool widthMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
int width = mediaValues.viewportWidth();
if (value) {
int length;
return computeLength(value, mediaValues.strictMode(), mediaValues.style(), mediaValues.defaultFontSize(), length)
&& compareValue(width, length, op);
}
return width;
}
static bool minColorMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return colorMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxColorMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return colorMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minColorIndexMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return colorIndexMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxColorIndexMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return colorIndexMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minMonochromeMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return monochromeMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxMonochromeMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return monochromeMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minAspectRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return aspectRatioMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxAspectRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return aspectRatioMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minDeviceAspectRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return deviceAspectRatioMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxDeviceAspectRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return deviceAspectRatioMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minDevicePixelRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
UseCounter::count(mediaValues.document(), UseCounter::PrefixedMinDevicePixelRatioMediaFeature);
return devicePixelRatioMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxDevicePixelRatioMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
UseCounter::count(mediaValues.document(), UseCounter::PrefixedMaxDevicePixelRatioMediaFeature);
return devicePixelRatioMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minHeightMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return heightMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxHeightMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return heightMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minWidthMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return widthMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxWidthMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return widthMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minDeviceHeightMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return deviceHeightMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxDeviceHeightMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return deviceHeightMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minDeviceWidthMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return deviceWidthMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxDeviceWidthMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return deviceWidthMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool minResolutionMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return resolutionMediaFeatureEval(value, MinPrefix, mediaValues);
}
static bool maxResolutionMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
return resolutionMediaFeatureEval(value, MaxPrefix, mediaValues);
}
static bool animationMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
UseCounter::count(mediaValues.document(), UseCounter::PrefixedAnimationMediaFeature);
if (value) {
float number;
return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
}
return true;
}
static bool transform2dMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
UseCounter::count(mediaValues.document(), UseCounter::PrefixedTransform2dMediaFeature);
if (value) {
float number;
return numberValue(value, number) && compareValue(1, static_cast<int>(number), op);
}
return true;
}
static bool transform3dMediaFeatureEval(CSSValue* value, MediaFeaturePrefix op, const MediaValues& mediaValues)
{
UseCounter::count(mediaValues.document(), UseCounter::PrefixedTransform3dMediaFeature);
bool returnValueIfNoParameter;
int have3dRendering;
bool threeDEnabled = mediaValues.threeDEnabled();
returnValueIfNoParameter = threeDEnabled;
have3dRendering = threeDEnabled ? 1 : 0;
if (value) {
float number;
return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op);
}
return returnValueIfNoParameter;
}
static bool viewModeMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
UseCounter::count(mediaValues.document(), UseCounter::PrefixedViewModeMediaFeature);
if (!value)
return true;
return toCSSPrimitiveValue(value)->getValueID() == CSSValueWindowed;
}
static bool hoverMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
MediaValues::PointerDeviceType pointer = mediaValues.pointer();
if (pointer == MediaValues::UnknownPointer)
return false;
float number = 1;
if (value) {
if (!numberValue(value, number))
return false;
}
return (pointer == MediaValues::NoPointer && !number)
|| (pointer == MediaValues::TouchPointer && !number)
|| (pointer == MediaValues::MousePointer && number == 1);
}
static bool pointerMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
MediaValues::PointerDeviceType pointer = mediaValues.pointer();
if (pointer == MediaValues::UnknownPointer)
return false;
if (!value)
return pointer != MediaValues::NoPointer;
if (!value->isPrimitiveValue())
return false;
const CSSValueID id = toCSSPrimitiveValue(value)->getValueID();
return (pointer == MediaValues::NoPointer && id == CSSValueNone)
|| (pointer == MediaValues::TouchPointer && id == CSSValueCoarse)
|| (pointer == MediaValues::MousePointer && id == CSSValueFine);
}
static bool scanMediaFeatureEval(CSSValue* value, MediaFeaturePrefix, const MediaValues& mediaValues)
{
if (!mediaValues.scanMediaType())
return false;
if (!value)
return true;
if (!value->isPrimitiveValue())
return false;
return toCSSPrimitiveValue(value)->getValueID() == CSSValueProgressive;
}
static void createFunctionMap()
{
gFunctionMap = new FunctionMap;
#define ADD_TO_FUNCTIONMAP(name) \
gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval);
CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP);
#undef ADD_TO_FUNCTIONMAP
}
bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const
{
if (!m_mediaValues)
return m_expectedResult;
if (!gFunctionMap)
createFunctionMap();
EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl());
if (func)
return func(expr->value(), NoPrefix, *m_mediaValues);
return false;
}
}