/* * Copyright (C) 2006 Kimmo Kinnunen . * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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 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 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "MediaQueryExp.h" #include "CSSAspectRatioValue.h" #include "CSSParser.h" #include "CSSPrimitiveValue.h" #include "CSSValueList.h" #include namespace WebCore { static inline bool featureWithCSSValueID(const AtomicString& mediaFeature, const CSSParserValue* value) { if (!value->id) return false; return mediaFeature == MediaFeatureNames::orientationMediaFeature #if ENABLE(VIEW_MODE_CSS_MEDIA) || mediaFeature == MediaFeatureNames::view_modeMediaFeature #endif // ENABLE(VIEW_MODE_CSS_MEDIA) || mediaFeature == MediaFeatureNames::any_hoverMediaFeature || mediaFeature == MediaFeatureNames::any_pointerMediaFeature || mediaFeature == MediaFeatureNames::hoverMediaFeature || mediaFeature == MediaFeatureNames::inverted_colorsMediaFeature || mediaFeature == MediaFeatureNames::pointerMediaFeature; } static inline bool featureWithValidPositiveLenghtOrNumber(const AtomicString& mediaFeature, const CSSParserValue* value) { if (!(CSSPrimitiveValue::isLength(value->unit) || value->unit == CSSPrimitiveValue::CSS_NUMBER) || value->fValue < 0) return false; return mediaFeature == MediaFeatureNames::heightMediaFeature || mediaFeature == MediaFeatureNames::max_heightMediaFeature || mediaFeature == MediaFeatureNames::min_heightMediaFeature || mediaFeature == MediaFeatureNames::widthMediaFeature || mediaFeature == MediaFeatureNames::max_widthMediaFeature || mediaFeature == MediaFeatureNames::min_widthMediaFeature || mediaFeature == MediaFeatureNames::device_heightMediaFeature || mediaFeature == MediaFeatureNames::max_device_heightMediaFeature || mediaFeature == MediaFeatureNames::min_device_heightMediaFeature || mediaFeature == MediaFeatureNames::device_widthMediaFeature || mediaFeature == MediaFeatureNames::max_device_widthMediaFeature || mediaFeature == MediaFeatureNames::min_device_widthMediaFeature; } static inline bool featureWithValidDensity(const AtomicString& mediaFeature, const CSSParserValue* value) { if (!CSSPrimitiveValue::isResolution(value->unit) || value->fValue <= 0) return false; return mediaFeature == MediaFeatureNames::resolutionMediaFeature || mediaFeature == MediaFeatureNames::max_resolutionMediaFeature || mediaFeature == MediaFeatureNames::min_resolutionMediaFeature; } static inline bool featureWithPositiveInteger(const AtomicString& mediaFeature, const CSSParserValue* value) { if (!value->isInt || value->fValue < 0) return false; return mediaFeature == MediaFeatureNames::colorMediaFeature || mediaFeature == MediaFeatureNames::max_colorMediaFeature || mediaFeature == MediaFeatureNames::min_colorMediaFeature || mediaFeature == MediaFeatureNames::color_indexMediaFeature || mediaFeature == MediaFeatureNames::max_color_indexMediaFeature || mediaFeature == MediaFeatureNames::min_color_indexMediaFeature || mediaFeature == MediaFeatureNames::min_monochromeMediaFeature || mediaFeature == MediaFeatureNames::max_monochromeMediaFeature; } static inline bool featureWithPositiveNumber(const AtomicString& mediaFeature, const CSSParserValue* value) { if (value->unit != CSSPrimitiveValue::CSS_NUMBER || value->fValue < 0) return false; return mediaFeature == MediaFeatureNames::transform_2dMediaFeature || mediaFeature == MediaFeatureNames::transform_3dMediaFeature || mediaFeature == MediaFeatureNames::transitionMediaFeature || mediaFeature == MediaFeatureNames::animationMediaFeature || mediaFeature == MediaFeatureNames::device_pixel_ratioMediaFeature || mediaFeature == MediaFeatureNames::max_device_pixel_ratioMediaFeature || mediaFeature == MediaFeatureNames::min_device_pixel_ratioMediaFeature; } static inline bool featureWithZeroOrOne(const AtomicString& mediaFeature, const CSSParserValue* value) { if (!value->isInt || !(value->fValue == 1 || !value->fValue)) return false; return mediaFeature == MediaFeatureNames::gridMediaFeature; } static inline bool featureWithAspectRatio(const AtomicString& mediaFeature) { return mediaFeature == MediaFeatureNames::aspect_ratioMediaFeature || mediaFeature == MediaFeatureNames::device_aspect_ratioMediaFeature || mediaFeature == MediaFeatureNames::min_aspect_ratioMediaFeature || mediaFeature == MediaFeatureNames::max_aspect_ratioMediaFeature || mediaFeature == MediaFeatureNames::min_device_aspect_ratioMediaFeature || mediaFeature == MediaFeatureNames::max_device_aspect_ratioMediaFeature; } static inline bool featureWithoutValue(const AtomicString& mediaFeature) { // Media features that are prefixed by min/max cannot be used without a value. return mediaFeature == MediaFeatureNames::any_hoverMediaFeature || mediaFeature == MediaFeatureNames::any_pointerMediaFeature || mediaFeature == MediaFeatureNames::monochromeMediaFeature || mediaFeature == MediaFeatureNames::colorMediaFeature || mediaFeature == MediaFeatureNames::color_indexMediaFeature || mediaFeature == MediaFeatureNames::gridMediaFeature || mediaFeature == MediaFeatureNames::heightMediaFeature || mediaFeature == MediaFeatureNames::widthMediaFeature || mediaFeature == MediaFeatureNames::device_heightMediaFeature || mediaFeature == MediaFeatureNames::device_widthMediaFeature || mediaFeature == MediaFeatureNames::orientationMediaFeature || mediaFeature == MediaFeatureNames::aspect_ratioMediaFeature || mediaFeature == MediaFeatureNames::device_aspect_ratioMediaFeature || mediaFeature == MediaFeatureNames::hoverMediaFeature || mediaFeature == MediaFeatureNames::transform_2dMediaFeature || mediaFeature == MediaFeatureNames::transform_3dMediaFeature || mediaFeature == MediaFeatureNames::transitionMediaFeature || mediaFeature == MediaFeatureNames::animationMediaFeature || mediaFeature == MediaFeatureNames::inverted_colorsMediaFeature #if ENABLE(VIEW_MODE_CSS_MEDIA) || mediaFeature == MediaFeatureNames::view_modeMediaFeature #endif // ENABLE(VIEW_MODE_CSS_MEDIA) || mediaFeature == MediaFeatureNames::pointerMediaFeature || mediaFeature == MediaFeatureNames::device_pixel_ratioMediaFeature || mediaFeature == MediaFeatureNames::resolutionMediaFeature || mediaFeature == MediaFeatureNames::video_playable_inlineMediaFeature; } MediaQueryExp::MediaQueryExp(const AtomicString& mediaFeature, CSSParserValueList* valueList) : m_mediaFeature(mediaFeature) { // Initialize media query expression that must have 1 or more values. if (valueList) { if (valueList->size() == 1) { CSSParserValue* value = valueList->current(); // Media features that use CSSValueIDs. if (featureWithCSSValueID(mediaFeature, value)) m_value = CSSPrimitiveValue::createIdentifier(value->id); // Media features that must have non-negative , ie. dppx, dpi or dpcm. else if (featureWithValidDensity(mediaFeature, value)) m_value = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); // Media features that must have non-negative or number value. else if (featureWithValidPositiveLenghtOrNumber(mediaFeature, value)) m_value = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); // Media features that must have non-negative integer value. else if (featureWithPositiveInteger(mediaFeature, value)) m_value = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_NUMBER); // Media features that must have non-negative number value. else if (featureWithPositiveNumber(mediaFeature, value)) m_value = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_NUMBER); // Media features that must have (0|1) value. else if (featureWithZeroOrOne(mediaFeature, value)) m_value = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_NUMBER); m_isValid = m_value; } else if (valueList->size() == 3 && featureWithAspectRatio(mediaFeature)) { // Create list of values. // Currently accepts only /. // Applicable to device-aspect-ratio and aspec-ratio. bool isValid = true; float numeratorValue = 0; float denominatorValue = 0; // The aspect-ratio must be (whitespace)? / (whitespace)? . for (unsigned i = 0; i < 3; ++i, valueList->next()) { const CSSParserValue* value = valueList->current(); if (i != 1 && value->unit == CSSPrimitiveValue::CSS_NUMBER && value->fValue > 0 && value->isInt) { if (!i) numeratorValue = value->fValue; else denominatorValue = value->fValue; } else if (i == 1 && value->unit == CSSParserValue::Operator && value->iValue == '/') continue; else { isValid = false; break; } } if (isValid) m_value = CSSAspectRatioValue::create(numeratorValue, denominatorValue); m_isValid = m_value; } } else if (featureWithoutValue(mediaFeature)) m_isValid = true; } String MediaQueryExp::serialize() const { if (!m_serializationCache.isNull()) return m_serializationCache; StringBuilder result; result.append('('); result.append(m_mediaFeature.convertToASCIILowercase()); if (m_value) { result.appendLiteral(": "); result.append(m_value->cssText()); } result.append(')'); m_serializationCache = result.toString(); return m_serializationCache; } } // namespace