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 |