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 13 matching lines...) Expand all Loading... |
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 */ | 27 */ |
28 | 28 |
29 #include "config.h" | 29 #include "config.h" |
30 #include "core/css/MediaQueryEvaluator.h" | 30 #include "core/css/MediaQueryEvaluator.h" |
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/CSSHelper.h" |
34 #include "core/css/CSSPrimitiveValue.h" | 35 #include "core/css/CSSPrimitiveValue.h" |
35 #include "core/css/CSSValueList.h" | 36 #include "core/css/CSSValueList.h" |
36 #include "core/css/MediaFeatureNames.h" | 37 #include "core/css/MediaFeatureNames.h" |
37 #include "core/css/MediaList.h" | 38 #include "core/css/MediaList.h" |
38 #include "core/css/MediaQuery.h" | 39 #include "core/css/MediaQuery.h" |
39 #include "core/css/MediaQueryExp.h" | 40 #include "core/css/MediaQueryExp.h" |
40 #include "core/css/resolver/StyleResolver.h" | 41 #include "core/css/resolver/StyleResolver.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" |
(...skipping 144 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 && toCSSPrimitiveValue(value)->isNumber()) { | 202 && toCSSPrimitiveValue(value)->isNumber()) { |
219 result = toCSSPrimitiveValue(value)->getFloatValue(CSSPrimitiveValue::CS
S_NUMBER); | 203 result = toCSSPrimitiveValue(value)->getFloatValue(CSSPrimitiveValue::CS
S_NUMBER); |
220 return true; | 204 return true; |
221 } | 205 } |
222 return false; | 206 return false; |
223 } | 207 } |
224 | 208 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 if (value) { | 267 if (value) { |
284 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); | 268 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); |
285 return compareAspectRatioValue(value, static_cast<int>(sg.width()), stat
ic_cast<int>(sg.height()), op); | 269 return compareAspectRatioValue(value, static_cast<int>(sg.width()), stat
ic_cast<int>(sg.height()), op); |
286 } | 270 } |
287 | 271 |
288 // ({,min-,max-}device-aspect-ratio) | 272 // ({,min-,max-}device-aspect-ratio) |
289 // assume if we have a device, its aspect ratio is non-zero | 273 // assume if we have a device, its aspect ratio is non-zero |
290 return true; | 274 return true; |
291 } | 275 } |
292 | 276 |
293 static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Fr
ame* frame, MediaFeaturePrefix op) | 277 static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op) |
294 { | 278 { |
295 // FIXME: Possible handle other media types than 'screen' and 'print'. | 279 // FIXME: Possible handle other media types than 'screen' and 'print'. |
296 float deviceScaleFactor = 0; | 280 float deviceScaleFactor = 0; |
297 | 281 |
298 // This checks the actual media type applied to the document, and we know | 282 // This checks the actual media type applied to the document, and we know |
299 // this method only got called if this media type matches the one defined | 283 // this method only got called if this media type matches the one defined |
300 // in the query. Thus, if if the document's media type is "print", the | 284 // in the query. Thus, if if the document's media type is "print", the |
301 // media type of the query will either be "print" or "all". | 285 // media type of the query will either be "print" or "all". |
302 String mediaType = frame->view()->mediaType(); | 286 String mediaType = frame->view()->mediaType(); |
303 if (equalIgnoringCase(mediaType, "screen")) | 287 if (equalIgnoringCase(mediaType, "screen")) |
304 deviceScaleFactor = frame->page()->deviceScaleFactor(); | 288 deviceScaleFactor = frame->page()->deviceScaleFactor(); |
305 else if (equalIgnoringCase(mediaType, "print")) { | 289 else if (equalIgnoringCase(mediaType, "print")) { |
306 // The resolution of images while printing should not depend on the dpi | 290 // The resolution of images while printing should not depend on the DPI |
307 // of the screen. Until we support proper ways of querying this info | 291 // of the screen. Until we support proper ways of querying this info |
308 // we use 300px which is considered minimum for current printers. | 292 // we use 300px which is considered minimum for current printers. |
309 deviceScaleFactor = 3.125; // 300dpi / 96dpi; | 293 deviceScaleFactor = 300 / cssPixelsPerInch; |
310 } | 294 } |
311 | 295 |
312 if (!value) | 296 if (!value) |
313 return !!deviceScaleFactor; | 297 return !!deviceScaleFactor; |
314 | 298 |
315 return value->isPrimitiveValue() && compareValue(deviceScaleFactor, toCSSPri
mitiveValue(value)->getFloatValue(), op); | 299 if (!value->isPrimitiveValue()) |
| 300 return false; |
| 301 |
| 302 CSSPrimitiveValue* resolution = toCSSPrimitiveValue(value); |
| 303 |
| 304 if (resolution->isNumber()) |
| 305 return compareValue(deviceScaleFactor, resolution->getFloatValue(), op); |
| 306 |
| 307 if (!resolution->isResolution()) |
| 308 return false; |
| 309 |
| 310 if (resolution->isDotsPerCentimeter()) { |
| 311 // To match DPCM to DPPX values, we limit to 2 decimal points. |
| 312 // The http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends |
| 313 // "that the pixel unit refer to the whole number of device pixels that
best |
| 314 // approximates the reference pixel". With that in mind, allowing 2 deci
mal |
| 315 // point precision seems appropriate. |
| 316 return compareValue( |
| 317 floorf(0.5 + 100 * deviceScaleFactor) / 100, |
| 318 floorf(0.5 + 100 * resolution->getFloatValue(CSSPrimitiveValue::CSS_
DPPX)) / 100, op); |
| 319 } |
| 320 |
| 321 return compareValue(deviceScaleFactor, resolution->getFloatValue(CSSPrimitiv
eValue::CSS_DPPX), op); |
| 322 } |
| 323 |
| 324 static bool devicePixelRatioMediaFeatureEval(CSSValue *value, RenderStyle*, Fram
e* frame, MediaFeaturePrefix op) |
| 325 { |
| 326 return (!value || toCSSPrimitiveValue(value)->isNumber()) && evalResolution(
value, frame, op); |
316 } | 327 } |
317 | 328 |
318 static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra
me, MediaFeaturePrefix op) | 329 static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* fra
me, MediaFeaturePrefix op) |
319 { | 330 { |
320 #if ENABLE(RESOLUTION_MEDIA_QUERY) | 331 return (!value || toCSSPrimitiveValue(value)->isResolution()) && evalResolut
ion(value, frame, op); |
321 // The DPI below is dots per CSS inch and thus not device inch. The | |
322 // functions should respect this. | |
323 // | |
324 // For square pixels, it is simply the device scale factor (dppx) times 96, | |
325 // per definition. | |
326 // | |
327 // The device scale factor is a predefined value which is calculated per | |
328 // device given the preferred distance in arms length (considered one arms | |
329 // length for desktop computers and usually 0.6 arms length for phones). | |
330 // | |
331 // The value can be calculated as follows (rounded to quarters): | |
332 // round((deviceDotsPerInch * distanceInArmsLength / 96) * 4) / 4. | |
333 // Example (mid-range resolution phone): | |
334 // round((244 * 0.6 / 96) * 4) / 4 = 1.5 | |
335 // Example (high-range resolution laptop): | |
336 // round((220 * 1.0 / 96) * 4) / 4 = 2.0 | |
337 | |
338 float horiDPI; | |
339 float vertDPI; | |
340 | |
341 // This checks the actual media type applied to the document, and we know | |
342 // this method only got called if this media type matches the one defined | |
343 // in the query. Thus, if if the document's media type is "print", the | |
344 // media type of the query will either be "print" or "all". | |
345 String mediaType = frame->view()->mediaType(); | |
346 if (equalIgnoringCase(mediaType, "screen")) { | |
347 Screen* screen = frame->document()->domWindow()->screen(); | |
348 horiDPI = screen->horizontalDPI(); | |
349 vertDPI = screen->verticalDPI(); | |
350 } else if (equalIgnoringCase(mediaType, "print")) { | |
351 // The resolution of images while printing should not depend on the dpi | |
352 // of the screen. Until we support proper ways of querying this info | |
353 // we use 300px which is considered minimum for current printers. | |
354 horiDPI = vertDPI = 300; | |
355 } else { | |
356 // FIXME: Possible handle other media types than 'screen' and 'print'. | |
357 // For now, do not match. | |
358 return false; | |
359 } | |
360 | |
361 float leastDenseDPI = std::min(horiDPI, vertDPI); | |
362 float mostDenseDPI = std::max(horiDPI, vertDPI); | |
363 | |
364 // According to spec, (resolution) will evaluate to true if (resolution:x) | |
365 // will evaluate to true for a value x other than zero or zero followed by | |
366 // a valid unit identifier (i.e., other than 0, 0dpi, 0dpcm, or 0dppx.), | |
367 // which is always the case. But the spec special cases 'resolution' to | |
368 // never matches a device with non-square pixels. | |
369 if (!value) { | |
370 ASSERT(op == NoPrefix); | |
371 return leastDenseDPI == mostDenseDPI; | |
372 } | |
373 | |
374 if (!value->isPrimitiveValue()) | |
375 return false; | |
376 | |
377 // http://dev.w3.org/csswg/css3-values/#resolution defines resolution as a | |
378 // dimension, which contains a number (decimal point allowed), not just an | |
379 // integer. Also, http://dev.w3.org/csswg/css3-values/#numeric-types says | |
380 // "CSS theoretically supports infinite precision and infinite ranges for | |
381 // all value types; | |
382 CSSPrimitiveValue* rawValue = toCSSPrimitiveValue(value); | |
383 | |
384 if (rawValue->isDotsPerPixel()) { | |
385 // http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends | |
386 // "that the pixel unit refer to the whole number of device pixels that | |
387 // best approximates the reference pixel". We compare with 3 decimal | |
388 // points, which aligns with current device-pixel-ratio's in use. | |
389 float leastDenseDensity = floorf(leastDenseDPI * 1000 / 96) / 1000; | |
390 float mostDenseDensity = floorf(leastDenseDPI * 1000 / 96) / 1000; | |
391 float testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_DPP
X); | |
392 return compareResolution(leastDenseDensity, mostDenseDensity, testedDens
ity, op); | |
393 } | |
394 | |
395 if (rawValue->isDotsPerInch()) { | |
396 unsigned testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_
DPI); | |
397 return compareResolution(leastDenseDPI, mostDenseDPI, testedDensity, op)
; | |
398 } | |
399 | |
400 // http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends "that | |
401 // the pixel unit refer to the whole number of device pixels that best | |
402 // approximates the reference pixel". | |
403 float leastDenseDPCM = roundf(leastDenseDPI / 2.54); // (2.54 cm/in) | |
404 float mostDenseDPCM = roundf(mostDenseDPI / 2.54); | |
405 | |
406 if (rawValue->isDotsPerCentimeter()) { | |
407 float testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_DPC
M); | |
408 return compareResolution(leastDenseDPCM, mostDenseDPCM, testedDensity, o
p); | |
409 } | |
410 #else | |
411 UNUSED_PARAM(value); | |
412 UNUSED_PARAM(frame); | |
413 UNUSED_PARAM(op); | |
414 #endif | |
415 | |
416 return false; | |
417 } | 332 } |
418 | 333 |
419 static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFea
turePrefix op) | 334 static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFea
turePrefix op) |
420 { | 335 { |
421 // if output device is bitmap, grid: 0 == true | 336 // if output device is bitmap, grid: 0 == true |
422 // assume we have bitmap device | 337 // assume we have bitmap device |
423 float number; | 338 float number; |
424 if (value && numberValue(value, number)) | 339 if (value && numberValue(value, number)) |
425 return compareValue(static_cast<int>(number), 0, op); | 340 return compareValue(static_cast<int>(number), 0, op); |
426 return false; | 341 return false; |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle
* style, Frame* frame, MediaFeaturePrefix) | 458 static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle
* style, Frame* frame, MediaFeaturePrefix) |
544 { | 459 { |
545 return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); | 460 return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); |
546 } | 461 } |
547 | 462 |
548 static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle
* style, Frame* frame, MediaFeaturePrefix) | 463 static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle
* style, Frame* frame, MediaFeaturePrefix) |
549 { | 464 { |
550 return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); | 465 return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); |
551 } | 466 } |
552 | 467 |
553 static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle*
style, Frame* frame, MediaFeaturePrefix) | 468 static bool minDevicePixelRatioMediaFeatureEval(CSSValue* value, RenderStyle* st
yle, Frame* frame, MediaFeaturePrefix) |
554 { | 469 { |
555 return device_pixel_ratioMediaFeatureEval(value, style, frame, MinPrefix); | 470 return devicePixelRatioMediaFeatureEval(value, style, frame, MinPrefix); |
556 } | 471 } |
557 | 472 |
558 static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle*
style, Frame* frame, MediaFeaturePrefix) | 473 static bool maxDevicePixelRatioMediaFeatureEval(CSSValue* value, RenderStyle* st
yle, Frame* frame, MediaFeaturePrefix) |
559 { | 474 { |
560 return device_pixel_ratioMediaFeatureEval(value, style, frame, MaxPrefix); | 475 return devicePixelRatioMediaFeatureEval(value, style, frame, MaxPrefix); |
561 } | 476 } |
562 | 477 |
563 static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Fram
e* frame, MediaFeaturePrefix) | 478 static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Fram
e* frame, MediaFeaturePrefix) |
564 { | 479 { |
565 return heightMediaFeatureEval(value, style, frame, MinPrefix); | 480 return heightMediaFeatureEval(value, style, frame, MinPrefix); |
566 } | 481 } |
567 | 482 |
568 static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Fram
e* frame, MediaFeaturePrefix) | 483 static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Fram
e* frame, MediaFeaturePrefix) |
569 { | 484 { |
570 return heightMediaFeatureEval(value, style, frame, MaxPrefix); | 485 return heightMediaFeatureEval(value, style, frame, MaxPrefix); |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 // and let trampoline functions override the prefix if prefix is | 665 // and let trampoline functions override the prefix if prefix is |
751 // used | 666 // used |
752 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); | 667 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); |
753 if (func) | 668 if (func) |
754 return func(expr->value(), m_style.get(), m_frame, NoPrefix); | 669 return func(expr->value(), m_style.get(), m_frame, NoPrefix); |
755 | 670 |
756 return false; | 671 return false; |
757 } | 672 } |
758 | 673 |
759 } // namespace | 674 } // namespace |
OLD | NEW |