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 |