| OLD | NEW |
| 1 /* | 1 /* |
| 2 * CSS Media Query Evaluator | 2 * CSS Media Query Evaluator |
| 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) 2013 Apple Inc. All rights reserved. | 5 * Copyright (C) 2013 Apple Inc. All rights reserved. |
| 6 * | 6 * |
| 7 * Redistribution and use in source and binary forms, with or without | 7 * Redistribution and use in source and binary forms, with or without |
| 8 * modification, are permitted provided that the following conditions | 8 * modification, are permitted provided that the following conditions |
| 9 * are met: | 9 * are met: |
| 10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 #include "CSSValueKeywords.h" | 32 #include "CSSValueKeywords.h" |
| 33 #include "core/css/CSSAspectRatioValue.h" | 33 #include "core/css/CSSAspectRatioValue.h" |
| 34 #include "core/css/CSSPrimitiveValue.h" | 34 #include "core/css/CSSPrimitiveValue.h" |
| 35 #include "core/css/CSSValueList.h" | 35 #include "core/css/CSSValueList.h" |
| 36 #include "core/css/MediaFeatureNames.h" | 36 #include "core/css/MediaFeatureNames.h" |
| 37 #include "core/css/MediaList.h" | 37 #include "core/css/MediaList.h" |
| 38 #include "core/css/MediaQuery.h" | 38 #include "core/css/MediaQuery.h" |
| 39 #include "core/css/MediaQueryExp.h" | 39 #include "core/css/MediaQueryExp.h" |
| 40 #include "core/css/StyleResolver.h" | 40 #include "core/css/StyleResolver.h" |
| 41 #include "core/css/CSSHelper.h" |
| 41 #include "core/dom/NodeRenderStyle.h" | 42 #include "core/dom/NodeRenderStyle.h" |
| 42 #include "core/page/Chrome.h" | 43 #include "core/page/Chrome.h" |
| 43 #include "core/page/ChromeClient.h" | 44 #include "core/page/ChromeClient.h" |
| 44 #include "core/page/DOMWindow.h" | 45 #include "core/page/DOMWindow.h" |
| 45 #include "core/page/Frame.h" | 46 #include "core/page/Frame.h" |
| 46 #include "core/page/FrameView.h" | 47 #include "core/page/FrameView.h" |
| 47 #include "core/page/Page.h" | 48 #include "core/page/Page.h" |
| 48 #include "core/page/Screen.h" | 49 #include "core/page/Screen.h" |
| 49 #include "core/page/Settings.h" | 50 #include "core/page/Settings.h" |
| 50 #include "core/platform/PlatformScreen.h" | 51 #include "core/platform/PlatformScreen.h" |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 static bool compareAspectRatioValue(CSSValue* value, int width, int height, Medi
aFeaturePrefix op) | 189 static bool compareAspectRatioValue(CSSValue* value, int width, int height, Medi
aFeaturePrefix op) |
| 189 { | 190 { |
| 190 if (value->isAspectRatioValue()) { | 191 if (value->isAspectRatioValue()) { |
| 191 CSSAspectRatioValue* aspectRatio = static_cast<CSSAspectRatioValue*>(val
ue); | 192 CSSAspectRatioValue* aspectRatio = static_cast<CSSAspectRatioValue*>(val
ue); |
| 192 return compareValue(width * static_cast<int>(aspectRatio->denominatorVal
ue()), height * static_cast<int>(aspectRatio->numeratorValue()), op); | 193 return compareValue(width * static_cast<int>(aspectRatio->denominatorVal
ue()), height * static_cast<int>(aspectRatio->numeratorValue()), op); |
| 193 } | 194 } |
| 194 | 195 |
| 195 return false; | 196 return false; |
| 196 } | 197 } |
| 197 | 198 |
| 198 #if ENABLE(RESOLUTION_MEDIA_QUERY) | |
| 199 static bool compareResolution(float min, float max, float value, MediaFeaturePre
fix op) | |
| 200 { | |
| 201 switch (op) { | |
| 202 case NoPrefix: | |
| 203 // A 'resolution' (without a "min-" or "max-" prefix) query | |
| 204 // never matches a device with non-square pixels. | |
| 205 return value == min && value == max; | |
| 206 case MinPrefix: | |
| 207 return min >= value; | |
| 208 case MaxPrefix: | |
| 209 return max <= value; | |
| 210 } | |
| 211 return false; | |
| 212 } | |
| 213 #endif | |
| 214 | |
| 215 static bool numberValue(CSSValue* value, float& result) | 199 static bool numberValue(CSSValue* value, float& result) |
| 216 { | 200 { |
| 217 if (value->isPrimitiveValue() | 201 if (value->isPrimitiveValue() |
| 218 && static_cast<CSSPrimitiveValue*>(value)->isNumber()) { | 202 && static_cast<CSSPrimitiveValue*>(value)->isNumber()) { |
| 219 result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimit
iveValue::CSS_NUMBER); | 203 result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimit
iveValue::CSS_NUMBER); |
| 220 return true; | 204 return true; |
| 221 } | 205 } |
| 222 return false; | 206 return false; |
| 223 } | 207 } |
| 224 | 208 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 if (value) { | 262 if (value) { |
| 279 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); | 263 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); |
| 280 return compareAspectRatioValue(value, static_cast<int>(sg.width()), stat
ic_cast<int>(sg.height()), op); | 264 return compareAspectRatioValue(value, static_cast<int>(sg.width()), stat
ic_cast<int>(sg.height()), op); |
| 281 } | 265 } |
| 282 | 266 |
| 283 // ({,min-,max-}device-aspect-ratio) | 267 // ({,min-,max-}device-aspect-ratio) |
| 284 // assume if we have a device, its aspect ratio is non-zero | 268 // assume if we have a device, its aspect ratio is non-zero |
| 285 return true; | 269 return true; |
| 286 } | 270 } |
| 287 | 271 |
| 288 static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Fr
ame* frame, MediaFeaturePrefix op) | 272 static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) |
| 289 { | 273 { |
| 290 // FIXME: Possible handle other media types than 'screen' and 'print'. | 274 // FIXME: Possible handle other media types than 'screen' and 'print'. |
| 291 float deviceScaleFactor = 0; | 275 float deviceScaleFactor = 0; |
| 292 | 276 |
| 293 // This checks the actual media type applied to the document, and we know | 277 // This checks the actual media type applied to the document, and we know |
| 294 // this method only got called if this media type matches the one defined | 278 // this method only got called if this media type matches the one defined |
| 295 // in the query. Thus, if if the document's media type is "print", the | 279 // in the query. Thus, if if the document's media type is "print", the |
| 296 // media type of the query will either be "print" or "all". | 280 // media type of the query will either be "print" or "all". |
| 297 String mediaType = frame->view()->mediaType(); | 281 String mediaType = frame->view()->mediaType(); |
| 298 if (equalIgnoringCase(mediaType, "screen")) | 282 if (equalIgnoringCase(mediaType, "screen")) |
| 299 deviceScaleFactor = frame->page()->deviceScaleFactor(); | 283 deviceScaleFactor = frame->page()->deviceScaleFactor(); |
| 300 else if (equalIgnoringCase(mediaType, "print")) { | 284 else if (equalIgnoringCase(mediaType, "print")) { |
| 301 // The resolution of images while printing should not depend on the dpi | 285 // The resolution of images while printing should not depend on the DPI |
| 302 // of the screen. Until we support proper ways of querying this info | 286 // of the screen. Until we support proper ways of querying this info |
| 303 // we use 300px which is considered minimum for current printers. | 287 // we use 300px which is considered minimum for current printers. |
| 304 deviceScaleFactor = 3.125; // 300dpi / 96dpi; | 288 deviceScaleFactor = 300 / cssPixelsPerInch; |
| 305 } | 289 } |
| 306 | 290 |
| 307 if (!value) | 291 if (!value) |
| 308 return !!deviceScaleFactor; | 292 return !!deviceScaleFactor; |
| 309 | 293 |
| 310 return value->isPrimitiveValue() && compareValue(deviceScaleFactor, static_c
ast<CSSPrimitiveValue*>(value)->getFloatValue(), op); | 294 if (!value->isPrimitiveValue()) |
| 295 return false; |
| 296 |
| 297 CSSPrimitiveValue* resolution = static_cast<CSSPrimitiveValue*>(value); |
| 298 |
| 299 if (resolution->isNumber()) |
| 300 return compareValue(deviceScaleFactor, resolution->getFloatValue(), op); |
| 301 |
| 302 if (!resolution->isResolution()) |
| 303 return false; |
| 304 |
| 305 if (resolution->isDotsPerCentimeter()) { |
| 306 // To match DPCM to DPPX values, we limit to 2 decimal points. |
| 307 // The http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends |
| 308 // "that the pixel unit refer to the whole number of device pixels that
best |
| 309 // approximates the reference pixel". With that in mind, allowing 2 deci
mal |
| 310 // point precision seems appropriate. |
| 311 return compareValue( |
| 312 floorf(0.5 + 100 * deviceScaleFactor) / 100, |
| 313 floorf(0.5 + 100 * resolution->getFloatValue(CSSPrimitiveValue::CSS_
DPPX)) / 100, op); |
| 314 } |
| 315 |
| 316 return compareValue(deviceScaleFactor, resolution->getFloatValue(CSSPrimitiv
eValue::CSS_DPPX), op); |
| 317 } |
| 318 |
| 319 static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Fr
ame* frame, MediaFeaturePrefix op) |
| 320 { |
| 321 return (!value || static_cast<CSSPrimitiveValue*>(value)->isNumber()) && eva
lResolution(value, frame, op); |
| 311 } | 322 } |
| 312 | 323 |
| 313 static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra
me, MediaFeaturePrefix op) | 324 static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra
me, MediaFeaturePrefix op) |
| 314 { | 325 { |
| 315 #if ENABLE(RESOLUTION_MEDIA_QUERY) | 326 return (!value || static_cast<CSSPrimitiveValue*>(value)->isResolution()) &&
evalResolution(value, frame, op); |
| 316 // The DPI below is dots per CSS inch and thus not device inch. The | |
| 317 // functions should respect this. | |
| 318 // | |
| 319 // For square pixels, it is simply the device scale factor (dppx) times 96, | |
| 320 // per definition. | |
| 321 // | |
| 322 // The device scale factor is a predefined value which is calculated per | |
| 323 // device given the preferred distance in arms length (considered one arms | |
| 324 // length for desktop computers and usually 0.6 arms length for phones). | |
| 325 // | |
| 326 // The value can be calculated as follows (rounded to quarters): | |
| 327 // round((deviceDotsPerInch * distanceInArmsLength / 96) * 4) / 4. | |
| 328 // Example (mid-range resolution phone): | |
| 329 // round((244 * 0.6 / 96) * 4) / 4 = 1.5 | |
| 330 // Example (high-range resolution laptop): | |
| 331 // round((220 * 1.0 / 96) * 4) / 4 = 2.0 | |
| 332 | |
| 333 float horiDPI; | |
| 334 float vertDPI; | |
| 335 | |
| 336 // This checks the actual media type applied to the document, and we know | |
| 337 // this method only got called if this media type matches the one defined | |
| 338 // in the query. Thus, if if the document's media type is "print", the | |
| 339 // media type of the query will either be "print" or "all". | |
| 340 String mediaType = frame->view()->mediaType(); | |
| 341 if (equalIgnoringCase(mediaType, "screen")) { | |
| 342 Screen* screen = frame->document()->domWindow()->screen(); | |
| 343 horiDPI = screen->horizontalDPI(); | |
| 344 vertDPI = screen->verticalDPI(); | |
| 345 } else if (equalIgnoringCase(mediaType, "print")) { | |
| 346 // The resolution of images while printing should not depend on the dpi | |
| 347 // of the screen. Until we support proper ways of querying this info | |
| 348 // we use 300px which is considered minimum for current printers. | |
| 349 horiDPI = vertDPI = 300; | |
| 350 } else { | |
| 351 // FIXME: Possible handle other media types than 'screen' and 'print'. | |
| 352 // For now, do not match. | |
| 353 return false; | |
| 354 } | |
| 355 | |
| 356 float leastDenseDPI = std::min(horiDPI, vertDPI); | |
| 357 float mostDenseDPI = std::max(horiDPI, vertDPI); | |
| 358 | |
| 359 // According to spec, (resolution) will evaluate to true if (resolution:x) | |
| 360 // will evaluate to true for a value x other than zero or zero followed by | |
| 361 // a valid unit identifier (i.e., other than 0, 0dpi, 0dpcm, or 0dppx.), | |
| 362 // which is always the case. But the spec special cases 'resolution' to | |
| 363 // never matches a device with non-square pixels. | |
| 364 if (!value) { | |
| 365 ASSERT(op == NoPrefix); | |
| 366 return leastDenseDPI == mostDenseDPI; | |
| 367 } | |
| 368 | |
| 369 if (!value->isPrimitiveValue()) | |
| 370 return false; | |
| 371 | |
| 372 // http://dev.w3.org/csswg/css3-values/#resolution defines resolution as a | |
| 373 // dimension, which contains a number (decimal point allowed), not just an | |
| 374 // integer. Also, http://dev.w3.org/csswg/css3-values/#numeric-types says | |
| 375 // "CSS theoretically supports infinite precision and infinite ranges for | |
| 376 // all value types; | |
| 377 CSSPrimitiveValue* rawValue = static_cast<CSSPrimitiveValue*>(value); | |
| 378 | |
| 379 if (rawValue->isDotsPerPixel()) { | |
| 380 // http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends | |
| 381 // "that the pixel unit refer to the whole number of device pixels that | |
| 382 // best approximates the reference pixel". We compare with 3 decimal | |
| 383 // points, which aligns with current device-pixel-ratio's in use. | |
| 384 float leastDenseDensity = floorf(leastDenseDPI * 1000 / 96) / 1000; | |
| 385 float mostDenseDensity = floorf(leastDenseDPI * 1000 / 96) / 1000; | |
| 386 float testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_DPP
X); | |
| 387 return compareResolution(leastDenseDensity, mostDenseDensity, testedDens
ity, op); | |
| 388 } | |
| 389 | |
| 390 if (rawValue->isDotsPerInch()) { | |
| 391 unsigned testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_
DPI); | |
| 392 return compareResolution(leastDenseDPI, mostDenseDPI, testedDensity, op)
; | |
| 393 } | |
| 394 | |
| 395 // http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends "that | |
| 396 // the pixel unit refer to the whole number of device pixels that best | |
| 397 // approximates the reference pixel". | |
| 398 float leastDenseDPCM = roundf(leastDenseDPI / 2.54); // (2.54 cm/in) | |
| 399 float mostDenseDPCM = roundf(mostDenseDPI / 2.54); | |
| 400 | |
| 401 if (rawValue->isDotsPerCentimeter()) { | |
| 402 float testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_DPC
M); | |
| 403 return compareResolution(leastDenseDPCM, mostDenseDPCM, testedDensity, o
p); | |
| 404 } | |
| 405 #else | |
| 406 UNUSED_PARAM(value); | |
| 407 UNUSED_PARAM(frame); | |
| 408 UNUSED_PARAM(op); | |
| 409 #endif | |
| 410 | |
| 411 return false; | |
| 412 } | 327 } |
| 413 | 328 |
| 414 static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFea
turePrefix op) | 329 static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFea
turePrefix op) |
| 415 { | 330 { |
| 416 // if output device is bitmap, grid: 0 == true | 331 // if output device is bitmap, grid: 0 == true |
| 417 // assume we have bitmap device | 332 // assume we have bitmap device |
| 418 float number; | 333 float number; |
| 419 if (value && numberValue(value, number)) | 334 if (value && numberValue(value, number)) |
| 420 return compareValue(static_cast<int>(number), 0, op); | 335 return compareValue(static_cast<int>(number), 0, op); |
| 421 return false; | 336 return false; |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 // and let trampoline functions override the prefix if prefix is | 660 // and let trampoline functions override the prefix if prefix is |
| 746 // used | 661 // used |
| 747 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); | 662 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); |
| 748 if (func) | 663 if (func) |
| 749 return func(expr->value(), m_style.get(), m_frame, NoPrefix); | 664 return func(expr->value(), m_style.get(), m_frame, NoPrefix); |
| 750 | 665 |
| 751 return false; | 666 return false; |
| 752 } | 667 } |
| 753 | 668 |
| 754 } // namespace | 669 } // namespace |
| OLD | NEW |