Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(470)

Unified Diff: Source/core/css/MediaQueryEvaluator.cpp

Issue 14408004: Fix incorrect evaluation of resolution media queries (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/css/MediaQueryEvaluator.cpp
diff --git a/Source/core/css/MediaQueryEvaluator.cpp b/Source/core/css/MediaQueryEvaluator.cpp
index db54b7745bd630e9548e8c5356a84526e4eac674..80f69690b0b6a899b63a3d8923fb9bef8f9622ae 100644
--- a/Source/core/css/MediaQueryEvaluator.cpp
+++ b/Source/core/css/MediaQueryEvaluator.cpp
@@ -38,6 +38,7 @@
#include "core/css/MediaQuery.h"
#include "core/css/MediaQueryExp.h"
#include "core/css/StyleResolver.h"
+#include "core/css/CSSHelper.h"
#include "core/dom/NodeRenderStyle.h"
#include "core/page/Chrome.h"
#include "core/page/ChromeClient.h"
@@ -195,23 +196,6 @@ static bool compareAspectRatioValue(CSSValue* value, int width, int height, Medi
return false;
}
-#if ENABLE(RESOLUTION_MEDIA_QUERY)
-static bool compareResolution(float min, float max, float value, MediaFeaturePrefix op)
-{
- switch (op) {
- case NoPrefix:
- // A 'resolution' (without a "min-" or "max-" prefix) query
- // never matches a device with non-square pixels.
- return value == min && value == max;
- case MinPrefix:
- return min >= value;
- case MaxPrefix:
- return max <= value;
- }
- return false;
-}
-#endif
-
static bool numberValue(CSSValue* value, float& result)
{
if (value->isPrimitiveValue()
@@ -285,7 +269,7 @@ static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, F
return true;
}
-static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
+static bool evalResolution(CSSValue* value, Frame* frame, MediaFeaturePrefix op)
{
// FIXME: Possible handle other media types than 'screen' and 'print'.
float deviceScaleFactor = 0;
@@ -298,117 +282,48 @@ static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Fr
if (equalIgnoringCase(mediaType, "screen"))
deviceScaleFactor = frame->page()->deviceScaleFactor();
else if (equalIgnoringCase(mediaType, "print")) {
- // The resolution of images while printing should not depend on the dpi
+ // The resolution of images while printing should not depend on the DPI
// of the screen. Until we support proper ways of querying this info
// we use 300px which is considered minimum for current printers.
- deviceScaleFactor = 3.125; // 300dpi / 96dpi;
+ deviceScaleFactor = 300 / cssPixelsPerInch;
}
if (!value)
return !!deviceScaleFactor;
- return value->isPrimitiveValue() && compareValue(deviceScaleFactor, static_cast<CSSPrimitiveValue*>(value)->getFloatValue(), op);
-}
-
-static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
-{
-#if ENABLE(RESOLUTION_MEDIA_QUERY)
- // The DPI below is dots per CSS inch and thus not device inch. The
- // functions should respect this.
- //
- // For square pixels, it is simply the device scale factor (dppx) times 96,
- // per definition.
- //
- // The device scale factor is a predefined value which is calculated per
- // device given the preferred distance in arms length (considered one arms
- // length for desktop computers and usually 0.6 arms length for phones).
- //
- // The value can be calculated as follows (rounded to quarters):
- // round((deviceDotsPerInch * distanceInArmsLength / 96) * 4) / 4.
- // Example (mid-range resolution phone):
- // round((244 * 0.6 / 96) * 4) / 4 = 1.5
- // Example (high-range resolution laptop):
- // round((220 * 1.0 / 96) * 4) / 4 = 2.0
-
- float horiDPI;
- float vertDPI;
-
- // This checks the actual media type applied to the document, and we know
- // this method only got called if this media type matches the one defined
- // in the query. Thus, if if the document's media type is "print", the
- // media type of the query will either be "print" or "all".
- String mediaType = frame->view()->mediaType();
- if (equalIgnoringCase(mediaType, "screen")) {
- Screen* screen = frame->document()->domWindow()->screen();
- horiDPI = screen->horizontalDPI();
- vertDPI = screen->verticalDPI();
- } else if (equalIgnoringCase(mediaType, "print")) {
- // The resolution of images while printing should not depend on the dpi
- // of the screen. Until we support proper ways of querying this info
- // we use 300px which is considered minimum for current printers.
- horiDPI = vertDPI = 300;
- } else {
- // FIXME: Possible handle other media types than 'screen' and 'print'.
- // For now, do not match.
+ if (!value->isPrimitiveValue())
return false;
- }
- float leastDenseDPI = std::min(horiDPI, vertDPI);
- float mostDenseDPI = std::max(horiDPI, vertDPI);
-
- // According to spec, (resolution) will evaluate to true if (resolution:x)
- // will evaluate to true for a value x other than zero or zero followed by
- // a valid unit identifier (i.e., other than 0, 0dpi, 0dpcm, or 0dppx.),
- // which is always the case. But the spec special cases 'resolution' to
- // never matches a device with non-square pixels.
- if (!value) {
- ASSERT(op == NoPrefix);
- return leastDenseDPI == mostDenseDPI;
- }
+ CSSPrimitiveValue* resolution = static_cast<CSSPrimitiveValue*>(value);
- if (!value->isPrimitiveValue())
- return false;
+ if (resolution->isNumber())
+ return compareValue(deviceScaleFactor, resolution->getFloatValue(), op);
- // http://dev.w3.org/csswg/css3-values/#resolution defines resolution as a
- // dimension, which contains a number (decimal point allowed), not just an
- // integer. Also, http://dev.w3.org/csswg/css3-values/#numeric-types says
- // "CSS theoretically supports infinite precision and infinite ranges for
- // all value types;
- CSSPrimitiveValue* rawValue = static_cast<CSSPrimitiveValue*>(value);
-
- if (rawValue->isDotsPerPixel()) {
- // http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends
- // "that the pixel unit refer to the whole number of device pixels that
- // best approximates the reference pixel". We compare with 3 decimal
- // points, which aligns with current device-pixel-ratio's in use.
- float leastDenseDensity = floorf(leastDenseDPI * 1000 / 96) / 1000;
- float mostDenseDensity = floorf(leastDenseDPI * 1000 / 96) / 1000;
- float testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_DPPX);
- return compareResolution(leastDenseDensity, mostDenseDensity, testedDensity, op);
- }
+ if (!resolution->isResolution())
+ return false;
- if (rawValue->isDotsPerInch()) {
- unsigned testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_DPI);
- return compareResolution(leastDenseDPI, mostDenseDPI, testedDensity, op);
+ if (resolution->isDotsPerCentimeter()) {
+ // To match DPCM to DPPX values, we limit to 2 decimal points.
+ // The http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends
+ // "that the pixel unit refer to the whole number of device pixels that best
+ // approximates the reference pixel". With that in mind, allowing 2 decimal
+ // point precision seems appropriate.
+ return compareValue(
+ floorf(0.5 + 100 * deviceScaleFactor) / 100,
+ floorf(0.5 + 100 * resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX)) / 100, op);
}
- // http://dev.w3.org/csswg/css3-values/#absolute-lengths recommends "that
- // the pixel unit refer to the whole number of device pixels that best
- // approximates the reference pixel".
- float leastDenseDPCM = roundf(leastDenseDPI / 2.54); // (2.54 cm/in)
- float mostDenseDPCM = roundf(mostDenseDPI / 2.54);
+ return compareValue(deviceScaleFactor, resolution->getFloatValue(CSSPrimitiveValue::CSS_DPPX), op);
+}
- if (rawValue->isDotsPerCentimeter()) {
- float testedDensity = rawValue->getFloatValue(CSSPrimitiveValue::CSS_DPCM);
- return compareResolution(leastDenseDPCM, mostDenseDPCM, testedDensity, op);
- }
-#else
- UNUSED_PARAM(value);
- UNUSED_PARAM(frame);
- UNUSED_PARAM(op);
-#endif
+static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
+{
+ return (!value || static_cast<CSSPrimitiveValue*>(value)->isNumber()) && evalResolution(value, frame, op);
+}
- return false;
+static bool resolutionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op)
+{
+ return (!value || static_cast<CSSPrimitiveValue*>(value)->isResolution()) && evalResolution(value, frame, op);
}
static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op)

Powered by Google App Engine
This is Rietveld 408576698