| OLD | NEW |
| 1 /* | 1 /* |
| 2 * CSS Media Query | 2 * CSS Media Query |
| 3 * | 3 * |
| 4 * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. | 4 * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. |
| 5 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | 5 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
| 6 * Copyright (C) 2013 Apple Inc. All rights reserved. | 6 * Copyright (C) 2013 Apple Inc. All rights reserved. |
| 7 * | 7 * |
| 8 * Redistribution and use in source and binary forms, with or without | 8 * Redistribution and use in source and binary forms, with or without |
| 9 * modification, are permitted provided that the following conditions | 9 * modification, are permitted provided that the following conditions |
| 10 * are met: | 10 * are met: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 */ | 28 */ |
| 29 | 29 |
| 30 #include "config.h" | 30 #include "config.h" |
| 31 #include "core/css/MediaQueryExp.h" | 31 #include "core/css/MediaQueryExp.h" |
| 32 | 32 |
| 33 #include "CSSValueKeywords.h" | |
| 34 #include "core/css/CSSAspectRatioValue.h" | 33 #include "core/css/CSSAspectRatioValue.h" |
| 35 #include "core/css/CSSParserValues.h" | 34 #include "core/css/CSSParserValues.h" |
| 36 #include "core/css/CSSPrimitiveValue.h" | 35 #include "core/css/CSSPrimitiveValue.h" |
| 37 #include "core/html/parser/HTMLParserIdioms.h" | 36 #include "core/html/parser/HTMLParserIdioms.h" |
| 37 #include "wtf/DecimalNumber.h" |
| 38 #include "wtf/text/StringBuffer.h" |
| 38 #include "wtf/text/StringBuilder.h" | 39 #include "wtf/text/StringBuilder.h" |
| 39 | 40 |
| 40 namespace WebCore { | 41 namespace WebCore { |
| 41 | 42 |
| 42 using namespace MediaFeatureNames; | 43 using namespace MediaFeatureNames; |
| 43 | 44 |
| 44 static inline bool featureWithCSSValueID(const String& mediaFeature, const CSSPa
rserValue* value) | 45 static inline bool featureWithCSSValueID(const String& mediaFeature, const CSSPa
rserValue* value) |
| 45 { | 46 { |
| 46 if (!value->id) | 47 if (!value->id) |
| 47 return false; | 48 return false; |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 || m_mediaFeature == orientationMediaFeature | 195 || m_mediaFeature == orientationMediaFeature |
| 195 || m_mediaFeature == aspectRatioMediaFeature | 196 || m_mediaFeature == aspectRatioMediaFeature |
| 196 || m_mediaFeature == minAspectRatioMediaFeature | 197 || m_mediaFeature == minAspectRatioMediaFeature |
| 197 || m_mediaFeature == devicePixelRatioMediaFeature | 198 || m_mediaFeature == devicePixelRatioMediaFeature |
| 198 || m_mediaFeature == resolutionMediaFeature | 199 || m_mediaFeature == resolutionMediaFeature |
| 199 || m_mediaFeature == maxAspectRatioMediaFeature; | 200 || m_mediaFeature == maxAspectRatioMediaFeature; |
| 200 } | 201 } |
| 201 | 202 |
| 202 MediaQueryExp::MediaQueryExp(const MediaQueryExp& other) | 203 MediaQueryExp::MediaQueryExp(const MediaQueryExp& other) |
| 203 : m_mediaFeature(other.mediaFeature()) | 204 : m_mediaFeature(other.mediaFeature()) |
| 204 , m_value(other.value()) | 205 , m_expValue(other.expValue()) |
| 205 { | 206 { |
| 206 } | 207 } |
| 207 | 208 |
| 208 MediaQueryExp::MediaQueryExp(const String& mediaFeature, PassRefPtrWillBeRawPtr<
CSSValue> value) | 209 MediaQueryExp::MediaQueryExp(const String& mediaFeature, const MediaQueryExpValu
e& expValue) |
| 209 : m_mediaFeature(mediaFeature) | 210 : m_mediaFeature(mediaFeature) |
| 210 , m_value(value) | 211 , m_expValue(expValue) |
| 211 { | 212 { |
| 212 } | 213 } |
| 213 | 214 |
| 214 PassOwnPtrWillBeRawPtr<MediaQueryExp> MediaQueryExp::createIfValid(const String&
mediaFeature, CSSParserValueList* valueList) | 215 PassOwnPtrWillBeRawPtr<MediaQueryExp> MediaQueryExp::createIfValid(const String&
mediaFeature, CSSParserValueList* valueList) |
| 215 { | 216 { |
| 216 ASSERT(!mediaFeature.isNull()); | 217 ASSERT(!mediaFeature.isNull()); |
| 217 | 218 |
| 218 // FIXME - Creation of CSSValue here may not be thread safe. | 219 MediaQueryExpValue expValue; |
| 219 // It should be replaced by a different way to pass the values to MediaQuery
Evaluator. | |
| 220 RefPtrWillBeRawPtr<CSSValue> cssValue = nullptr; | |
| 221 bool isValid = false; | 220 bool isValid = false; |
| 222 String lowerMediaFeature = attemptStaticStringCreation(mediaFeature.lower())
; | 221 String lowerMediaFeature = attemptStaticStringCreation(mediaFeature.lower())
; |
| 223 | 222 |
| 224 // Create value for media query expression that must have 1 or more values. | 223 // Create value for media query expression that must have 1 or more values. |
| 225 if (valueList && valueList->size() > 0) { | 224 if (valueList && valueList->size() > 0) { |
| 226 if (valueList->size() == 1) { | 225 if (valueList->size() == 1) { |
| 227 CSSParserValue* value = valueList->current(); | 226 CSSParserValue* value = valueList->current(); |
| 228 ASSERT(value); | 227 ASSERT(value); |
| 229 | 228 |
| 230 if (featureWithCSSValueID(lowerMediaFeature, value)) { | 229 if (featureWithCSSValueID(lowerMediaFeature, value) && featureWithVa
lidIdent(lowerMediaFeature, value->id)) { |
| 231 // Media features that use CSSValueIDs. | 230 // Media features that use CSSValueIDs. |
| 232 cssValue = CSSPrimitiveValue::createIdentifier(value->id); | 231 expValue.id = value->id; |
| 233 if (!featureWithValidIdent(lowerMediaFeature, toCSSPrimitiveValu
e(cssValue.get())->getValueID())) | 232 expValue.unit = CSSPrimitiveValue::CSS_VALUE_ID; |
| 234 cssValue.clear(); | 233 expValue.isID = true; |
| 235 } else if (featureWithValidDensity(lowerMediaFeature, value)) { | 234 } else if (featureWithValidDensity(lowerMediaFeature, value) |
| 236 // Media features that must have non-negative <density>, ie. dpp
x, dpi or dpcm. | 235 || featureWithValidPositiveLength(lowerMediaFeature, value)) { |
| 237 cssValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiv
eValue::UnitTypes) value->unit); | 236 // Media features that must have non-negative <density>, ie. dpp
x, dpi or dpcm, |
| 238 } else if (featureWithValidPositiveLength(lowerMediaFeature, value))
{ | 237 // or Media features that must have non-negative <length> or num
ber value. |
| 239 // Media features that must have non-negative <lenght> or number
value. | 238 expValue.value = value->fValue; |
| 240 cssValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiv
eValue::UnitTypes) value->unit); | 239 expValue.unit = (CSSPrimitiveValue::UnitTypes)value->unit; |
| 241 } else if (featureWithPositiveInteger(lowerMediaFeature, value)) { | 240 expValue.isValue = true; |
| 242 // Media features that must have non-negative integer value. | 241 expValue.isInteger = value->isInt; |
| 243 cssValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitive
Value::CSS_NUMBER); | 242 } else if (featureWithPositiveInteger(lowerMediaFeature, value) |
| 244 } else if (featureWithPositiveNumber(lowerMediaFeature, value)) { | 243 || featureWithPositiveNumber(lowerMediaFeature, value) |
| 245 // Media features that must have non-negative number value. | 244 || featureWithZeroOrOne(lowerMediaFeature, value)) { |
| 246 cssValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitive
Value::CSS_NUMBER); | 245 // Media features that must have non-negative integer value, |
| 247 } else if (featureWithZeroOrOne(lowerMediaFeature, value)) { | 246 // or media features that must have non-negative number value, |
| 248 // Media features that must have (0|1) value. | 247 // or media features that must have (0|1) value. |
| 249 cssValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitive
Value::CSS_NUMBER); | 248 expValue.value = value->fValue; |
| 249 expValue.unit = CSSPrimitiveValue::CSS_NUMBER; |
| 250 expValue.isValue = true; |
| 251 expValue.isInteger = value->isInt; |
| 250 } | 252 } |
| 251 | 253 |
| 252 isValid = cssValue; | 254 isValid = (expValue.isID || expValue.isValue); |
| 253 | 255 |
| 254 } else if (valueList->size() == 3 && featureWithAspectRatio(lowerMediaFe
ature)) { | 256 } else if (valueList->size() == 3 && featureWithAspectRatio(lowerMediaFe
ature)) { |
| 255 // Create list of values. | 257 // Create list of values. |
| 256 // Currently accepts only <integer>/<integer>. | 258 // Currently accepts only <integer>/<integer>. |
| 257 // Applicable to device-aspect-ratio and aspec-ratio. | 259 // Applicable to device-aspect-ratio and aspec-ratio. |
| 258 isValid = true; | 260 isValid = true; |
| 259 float numeratorValue = 0; | 261 float numeratorValue = 0; |
| 260 float denominatorValue = 0; | 262 float denominatorValue = 0; |
| 261 // The aspect-ratio must be <integer> (whitespace)? / (whitespace)?
<integer>. | 263 // The aspect-ratio must be <integer> (whitespace)? / (whitespace)?
<integer>. |
| 262 for (unsigned i = 0; i < 3; ++i, valueList->next()) { | 264 for (unsigned i = 0; i < 3; ++i, valueList->next()) { |
| 263 const CSSParserValue* value = valueList->current(); | 265 const CSSParserValue* value = valueList->current(); |
| 264 if (i != 1 && value->unit == CSSPrimitiveValue::CSS_NUMBER && va
lue->fValue > 0 && value->isInt) { | 266 if (i != 1 && value->unit == CSSPrimitiveValue::CSS_NUMBER && va
lue->fValue > 0 && value->isInt) { |
| 265 if (!i) | 267 if (!i) |
| 266 numeratorValue = value->fValue; | 268 numeratorValue = value->fValue; |
| 267 else | 269 else |
| 268 denominatorValue = value->fValue; | 270 denominatorValue = value->fValue; |
| 269 } else if (i == 1 && value->unit == CSSParserValue::Operator &&
value->iValue == '/') { | 271 } else if (i == 1 && value->unit == CSSParserValue::Operator &&
value->iValue == '/') { |
| 270 continue; | 272 continue; |
| 271 } else { | 273 } else { |
| 272 isValid = false; | 274 isValid = false; |
| 273 break; | 275 break; |
| 274 } | 276 } |
| 275 } | 277 } |
| 276 | 278 |
| 277 if (isValid) | 279 if (isValid) { |
| 278 cssValue = CSSAspectRatioValue::create(numeratorValue, denominat
orValue); | 280 expValue.numerator = (unsigned)numeratorValue; |
| 281 expValue.denominator = (unsigned)denominatorValue; |
| 282 expValue.isRatio = true; |
| 283 } |
| 279 } | 284 } |
| 280 } else if (featureWithoutValue(lowerMediaFeature)) { | 285 } else if (featureWithoutValue(lowerMediaFeature)) { |
| 281 isValid = true; | 286 isValid = true; |
| 282 } | 287 } |
| 283 | 288 |
| 284 if (!isValid) | 289 if (!isValid) |
| 285 return nullptr; | 290 return nullptr; |
| 286 | 291 |
| 287 return adoptPtrWillBeNoop(new MediaQueryExp(lowerMediaFeature, cssValue)); | 292 return adoptPtrWillBeNoop(new MediaQueryExp(lowerMediaFeature, expValue)); |
| 288 } | 293 } |
| 289 | 294 |
| 290 MediaQueryExp::~MediaQueryExp() | 295 MediaQueryExp::~MediaQueryExp() |
| 291 { | 296 { |
| 292 } | 297 } |
| 293 | 298 |
| 299 bool MediaQueryExp::operator==(const MediaQueryExp& other) const |
| 300 { |
| 301 return (other.m_mediaFeature == m_mediaFeature) |
| 302 && ((!other.m_expValue.isValid() && !m_expValue.isValid()) |
| 303 || (other.m_expValue.isValid() && m_expValue.isValid() && other.m_ex
pValue.equals(m_expValue))); |
| 304 } |
| 305 |
| 294 String MediaQueryExp::serialize() const | 306 String MediaQueryExp::serialize() const |
| 295 { | 307 { |
| 296 StringBuilder result; | 308 StringBuilder result; |
| 297 result.append("("); | 309 result.append("("); |
| 298 result.append(m_mediaFeature.lower()); | 310 result.append(m_mediaFeature.lower()); |
| 299 if (m_value) { | 311 if (m_expValue.isValid()) { |
| 300 result.append(": "); | 312 result.append(": "); |
| 301 result.append(m_value->cssText()); | 313 result.append(m_expValue.cssText()); |
| 302 } | 314 } |
| 303 result.append(")"); | 315 result.append(")"); |
| 304 | 316 |
| 305 return result.toString(); | 317 return result.toString(); |
| 306 } | 318 } |
| 307 | 319 |
| 320 static String printNumber(double number) |
| 321 { |
| 322 DecimalNumber decimal(number); |
| 323 StringBuffer<LChar> buffer(decimal.bufferLengthForStringDecimal()); |
| 324 decimal.toStringDecimal(buffer.characters(), buffer.length()); |
| 325 return String::adopt(buffer); |
| 326 } |
| 327 |
| 328 String MediaQueryExpValue::cssText() const |
| 329 { |
| 330 StringBuilder output; |
| 331 if (isValue) { |
| 332 output.append(printNumber(value)); |
| 333 output.append(CSSPrimitiveValue::unitTypeToString(unit)); |
| 334 } else if (isRatio) { |
| 335 output.append(printNumber(numerator)); |
| 336 output.append("/"); |
| 337 output.append(printNumber(denominator)); |
| 338 } else if (isID) { |
| 339 output.append(getValueName(id)); |
| 340 } |
| 341 |
| 342 return output.toString(); |
| 343 } |
| 344 |
| 308 } // namespace | 345 } // namespace |
| OLD | NEW |