blob: c51f84e9112c5a42570e86724e0ce512fdf06e71 [file] [log] [blame]
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/cssom/media_feature.h"
#include "base/memory/ref_counted.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/cssom/integer_value.h"
#include "cobalt/cssom/length_value.h"
#include "cobalt/cssom/media_feature_keyword_value.h"
#include "cobalt/cssom/property_value.h"
#include "cobalt/cssom/ratio_value.h"
#include "cobalt/cssom/resolution_value.h"
#include "cobalt/math/safe_integer_conversions.h"
namespace cobalt {
namespace cssom {
namespace {
// The constants below are for the media features that are constant for Cobalt.
// The 'color-index' media feature describes the number of entries in the color
// lookup table of the output device. If the device does not use a color lookup
// table, the value is zero.
// https://www.w3.org/TR/css3-mediaqueries/#color-index
static const int kColorIndexMediaFeatureValue = 0;
// The 'color' media feature describes the number of bits per color component of
// the output device. If the device is not a color device, the value is zero.
// https://www.w3.org/TR/css3-mediaqueries/#color
static const int kColorMediaFeatureValue = 8;
// The 'monochrome' media feature describes the number of bits per pixel in a
// monochrome frame buffer. If the device is not a monochrome device, the output
// device value will be 0.
// https://www.w3.org/TR/css3-mediaqueries/#monochrome
static const int kMonochromeMediaFeatureValue = 0;
// The 'grid' media feature is used to query whether the output device is grid
// or bitmap. If the output device is grid-based (e.g., a "tty" terminal, or a
// phone display with only one fixed font), the value will be 1. Otherwise, the
// value will be 0.
// https://www.w3.org/TR/css3-mediaqueries/#grid
static const int kGridMediaFeatureValue = 0;
// The 'resolution' media feature describes the resolution of the output device,
// i.e. the density of the pixels.
// https://www.w3.org/TR/css3-mediaqueries/#resolution
// We calculate the pixel density from the length of the screen diagonal.
static const float kScreenDiagonalInInches = 55.0f;
// The 'scan' media feature describes the scanning process of "tv" output
// devices.
// https://www.w3.org/TR/css3-mediaqueries/#scan
static const MediaFeatureKeywordValue::Value kScanMediaFeatureValue =
MediaFeatureKeywordValue::kProgressive;
} // namespace
MediaFeature::MediaFeature(int name)
: name_(static_cast<MediaFeatureName>(name)), operator_(kNonZero) {}
MediaFeature::MediaFeature(int name, const scoped_refptr<PropertyValue>& value)
: name_(static_cast<MediaFeatureName>(name)),
value_(value),
operator_(kEquals) {}
bool MediaFeature::CompareAspectRatio(const math::Size& viewport_size) {
math::Rational media_ratio(viewport_size.width(), viewport_size.height());
RatioValue* specified_ratio =
base::polymorphic_downcast<RatioValue*>(value_.get());
switch (operator_) {
case kNonZero:
return true;
case kEquals:
return specified_ratio->value() == media_ratio;
case kMinimum:
return specified_ratio->value() <= media_ratio;
case kMaximum:
return specified_ratio->value() >= media_ratio;
}
NOTREACHED();
return false;
}
bool MediaFeature::CompareIntegerValue(int media_value) {
IntegerValue* specified_value =
base::polymorphic_downcast<IntegerValue*>(value_.get());
switch (operator_) {
case kNonZero:
return 0 != media_value;
case kEquals:
return *specified_value == media_value;
case kMinimum:
return *specified_value <= media_value;
case kMaximum:
return *specified_value >= media_value;
}
NOTREACHED();
return false;
}
bool MediaFeature::CompareLengthValue(int length_in_pixels) {
if (operator_ == kNonZero) {
return 0 != length_in_pixels;
} else {
LengthValue* specified_value =
base::polymorphic_downcast<LengthValue*>(value_.get());
// TODO: Support 'em' units for media features.
// https://www.w3.org/TR/css3-mediaqueries/#units
if (kPixelsUnit != specified_value->unit()) {
DLOG(WARNING)
<< "Media feature length value only supported in pixel units.";
return false;
}
switch (operator_) {
case kEquals:
return specified_value->value() == static_cast<float>(length_in_pixels);
case kMinimum:
return specified_value->value() <= static_cast<float>(length_in_pixels);
case kMaximum:
return specified_value->value() >= static_cast<float>(length_in_pixels);
case kNonZero:
break;
}
NOTREACHED();
return false;
}
}
bool MediaFeature::CompareOrientation(const math::Size& viewport_size) {
MediaFeatureKeywordValue* specified_value =
base::polymorphic_downcast<MediaFeatureKeywordValue*>(value_.get());
MediaFeatureKeywordValue::Value media_value =
viewport_size.height() >= viewport_size.width()
? MediaFeatureKeywordValue::kPortrait
: MediaFeatureKeywordValue::kLandscape;
switch (operator_) {
case kNonZero:
return true;
case kEquals:
return specified_value->value() == media_value;
case kMinimum:
case kMaximum:
NOTREACHED();
return false;
}
NOTREACHED();
return false;
}
bool MediaFeature::CompareResolution(const math::Size& viewport_size) {
ResolutionValue* specified_value =
base::polymorphic_downcast<ResolutionValue*>(value_.get());
float media_dpi = sqrtf(static_cast<float>(
viewport_size.width() * viewport_size.width() +
viewport_size.height() * viewport_size.height())) /
kScreenDiagonalInInches;
switch (operator_) {
case kNonZero:
return 0.0f != media_dpi;
case kEquals:
return specified_value->dpi_value() == media_dpi;
case kMinimum:
return specified_value->dpi_value() <= media_dpi;
case kMaximum:
return specified_value->dpi_value() >= media_dpi;
}
NOTREACHED();
return false;
}
bool MediaFeature::CompareScan() {
MediaFeatureKeywordValue* specified_value =
base::polymorphic_downcast<MediaFeatureKeywordValue*>(value_.get());
switch (operator_) {
case kNonZero:
return true;
case kEquals:
return specified_value->value() == kScanMediaFeatureValue;
case kMinimum:
case kMaximum:
NOTREACHED();
return false;
}
NOTREACHED();
return false;
}
bool MediaFeature::EvaluateConditionValue(const math::Size& viewport_size) {
switch (name_) {
case kInvalidFeature:
break;
case kAspectRatioMediaFeature:
case kDeviceAspectRatioMediaFeature:
return CompareAspectRatio(viewport_size);
case kColorIndexMediaFeature:
return CompareIntegerValue(kColorIndexMediaFeatureValue);
case kColorMediaFeature:
return CompareIntegerValue(kColorMediaFeatureValue);
case kDeviceHeightMediaFeature:
case kHeightMediaFeature:
return CompareLengthValue(viewport_size.height());
case kDeviceWidthMediaFeature:
case kWidthMediaFeature:
return CompareLengthValue(viewport_size.width());
case kGridMediaFeature:
return CompareIntegerValue(kGridMediaFeatureValue);
case kMonochromeMediaFeature:
return CompareIntegerValue(kMonochromeMediaFeatureValue);
case kOrientationMediaFeature:
return CompareOrientation(viewport_size);
case kResolutionMediaFeature:
return CompareResolution(viewport_size);
case kScanMediaFeature:
return CompareScan();
}
NOTREACHED();
return false;
}
} // namespace cssom
} // namespace cobalt