Chromium Code Reviews| 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 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 188 static bool compareAspectRatioValue(CSSValue* value, int width, int height, Medi aFeaturePrefix op) | 188 static bool compareAspectRatioValue(CSSValue* value, int width, int height, Medi aFeaturePrefix op) |
| 189 { | 189 { |
| 190 if (value->isAspectRatioValue()) { | 190 if (value->isAspectRatioValue()) { |
| 191 CSSAspectRatioValue* aspectRatio = static_cast<CSSAspectRatioValue*>(val ue); | 191 CSSAspectRatioValue* aspectRatio = static_cast<CSSAspectRatioValue*>(val ue); |
| 192 return compareValue(width * static_cast<int>(aspectRatio->denominatorVal ue()), height * static_cast<int>(aspectRatio->numeratorValue()), op); | 192 return compareValue(width * static_cast<int>(aspectRatio->denominatorVal ue()), height * static_cast<int>(aspectRatio->numeratorValue()), op); |
| 193 } | 193 } |
| 194 | 194 |
| 195 return false; | 195 return false; |
| 196 } | 196 } |
| 197 | 197 |
| 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) | 198 static bool numberValue(CSSValue* value, float& result) |
| 216 { | 199 { |
| 217 if (value->isPrimitiveValue() | 200 if (value->isPrimitiveValue() |
| 218 && static_cast<CSSPrimitiveValue*>(value)->isNumber()) { | 201 && static_cast<CSSPrimitiveValue*>(value)->isNumber()) { |
| 219 result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimit iveValue::CSS_NUMBER); | 202 result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimit iveValue::CSS_NUMBER); |
| 220 return true; | 203 return true; |
| 221 } | 204 } |
| 222 return false; | 205 return false; |
| 223 } | 206 } |
| 224 | 207 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 if (value) { | 261 if (value) { |
| 279 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); | 262 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); |
| 280 return compareAspectRatioValue(value, static_cast<int>(sg.width()), stat ic_cast<int>(sg.height()), op); | 263 return compareAspectRatioValue(value, static_cast<int>(sg.width()), stat ic_cast<int>(sg.height()), op); |
| 281 } | 264 } |
| 282 | 265 |
| 283 // ({,min-,max-}device-aspect-ratio) | 266 // ({,min-,max-}device-aspect-ratio) |
| 284 // assume if we have a device, its aspect ratio is non-zero | 267 // assume if we have a device, its aspect ratio is non-zero |
| 285 return true; | 268 return true; |
| 286 } | 269 } |
| 287 | 270 |
| 288 static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Fr ame* frame, MediaFeaturePrefix op) | 271 static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) |
| 289 { | 272 { |
| 290 // FIXME: Possible handle other media types than 'screen' and 'print'. | 273 // FIXME: Possible handle other media types than 'screen' and 'print'. |
| 291 float deviceScaleFactor = 0; | 274 float deviceScaleFactor = 0; |
| 292 | 275 |
| 293 // This checks the actual media type applied to the document, and we know | 276 // 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 | 277 // 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 | 278 // 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". | 279 // media type of the query will either be "print" or "all". |
| 297 String mediaType = frame->view()->mediaType(); | 280 String mediaType = frame->view()->mediaType(); |
| 298 if (equalIgnoringCase(mediaType, "screen")) | 281 if (equalIgnoringCase(mediaType, "screen")) |
| 299 deviceScaleFactor = frame->page()->deviceScaleFactor(); | 282 deviceScaleFactor = frame->page()->deviceScaleFactor(); |
| 300 else if (equalIgnoringCase(mediaType, "print")) { | 283 else if (equalIgnoringCase(mediaType, "print")) { |
| 301 // The resolution of images while printing should not depend on the dpi | 284 // 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 | 285 // of the screen. Until we support proper ways of querying this info |
| 303 // we use 300px which is considered minimum for current printers. | 286 // we use 300px which is considered minimum for current printers. |
| 304 deviceScaleFactor = 3.125; // 300dpi / 96dpi; | 287 deviceScaleFactor = 3.125; // 300dpi / 96dpi; |
| 305 } | 288 } |
| 306 | 289 |
| 307 if (!value) | 290 if (!value) |
| 308 return !!deviceScaleFactor; | 291 return !!deviceScaleFactor; |
| 309 | 292 |
| 310 return value->isPrimitiveValue() && compareValue(deviceScaleFactor, static_c ast<CSSPrimitiveValue*>(value)->getFloatValue(), op); | 293 if (!value->isPrimitiveValue()) |
| 294 return false; | |
| 295 | |
| 296 CSSPrimitiveValue* resolution = static_cast<CSSPrimitiveValue*>(value); | |
| 297 | |
| 298 if (resolution->isNumber()) | |
| 299 compareValue(deviceScaleFactor, resolution->getFloatValue(), op); | |
| 300 | |
| 301 if (resolution->isResolution()) { | |
| 302 // To match DPCM and DPI integer values to DPPX values, we limit to 2 de cimal | |
| 303 // points. The http://dev.w3.org/csswg/css3-values/#absolute-lengths rec ommends | |
| 304 // "that the pixel unit refer to the whole number of device pixels that best | |
| 305 // approximates the reference pixel". With that in mind, allowing 2 deci mal | |
| 306 // point precision seems appropriate. | |
| 307 return compareValue( | |
| 308 floorf(0.5 + 100 * deviceScaleFactor) / 100, | |
| 309 floorf(0.5 + 100 * resolution->getFloatValue(CSSPrimitiveValue::CSS_ DPPX)) / 100, op); | |
|
johnme
2013/04/23 18:16:23
I don't understand this line. A resolution for whi
| |
| 310 } | |
| 311 | |
| 312 return false; | |
| 313 } | |
| 314 | |
| 315 static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Fr ame* frame, MediaFeaturePrefix op) | |
| 316 { | |
| 317 return (!value || static_cast<CSSPrimitiveValue*>(value)->isNumber()) && eva lResolution(value, frame, op); | |
| 311 } | 318 } |
| 312 | 319 |
| 313 static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra me, MediaFeaturePrefix op) | 320 static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra me, MediaFeaturePrefix op) |
| 314 { | 321 { |
| 315 #if ENABLE(RESOLUTION_MEDIA_QUERY) | 322 #if ENABLE(RESOLUTION_MEDIA_QUERY) |
| 316 // The DPI below is dots per CSS inch and thus not device inch. The | 323 return (!value || static_cast<CSSPrimitiveValue*>(value)->isResolution()) && evalResolution(value, frame, op); |
| 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 | 324 #else |
| 406 UNUSED_PARAM(value); | 325 UNUSED_PARAM(value); |
| 407 UNUSED_PARAM(frame); | 326 UNUSED_PARAM(frame); |
| 408 UNUSED_PARAM(op); | 327 UNUSED_PARAM(op); |
| 409 #endif | |
| 410 | 328 |
| 411 return false; | 329 return false; |
| 330 #endif | |
| 412 } | 331 } |
| 413 | 332 |
| 414 static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFea turePrefix op) | 333 static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFea turePrefix op) |
| 415 { | 334 { |
| 416 // if output device is bitmap, grid: 0 == true | 335 // if output device is bitmap, grid: 0 == true |
| 417 // assume we have bitmap device | 336 // assume we have bitmap device |
| 418 float number; | 337 float number; |
| 419 if (value && numberValue(value, number)) | 338 if (value && numberValue(value, number)) |
| 420 return compareValue(static_cast<int>(number), 0, op); | 339 return compareValue(static_cast<int>(number), 0, op); |
| 421 return false; | 340 return false; |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 769 // and let trampoline functions override the prefix if prefix is | 688 // and let trampoline functions override the prefix if prefix is |
| 770 // used | 689 // used |
| 771 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); | 690 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); |
| 772 if (func) | 691 if (func) |
| 773 return func(expr->value(), m_style.get(), m_frame, NoPrefix); | 692 return func(expr->value(), m_style.get(), m_frame, NoPrefix); |
| 774 | 693 |
| 775 return false; | 694 return false; |
| 776 } | 695 } |
| 777 | 696 |
| 778 } // namespace | 697 } // namespace |
| OLD | NEW |