Bug 1365045 - Introduce ValueInBooleanContext in nsCSSKTableEntry and use it in the boolean context. r?heycam
The values in the boolean context depend on its feature. For examples, in the
case of prefers-reduced-motion 'no-preference' means false and 'reduced' mean
true in the boolean context, whereas in the case of prefers-contrast
'no-preference' means false and other two values, 'high' and 'low' means true
in the boolean context. To support it we introduce a new enum into each
nsCSSKTableEntry to represent the value in the boolean context and use it
when we have no specified value in the media feature (i.e. in the boolean
context).
MozReview-Commit-ID: Kr30bA1MtKx
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -130,16 +130,17 @@ rusty-enums = [
"nsStyleUnit",
"nsCSSKeyword",
"nsIDocument_DocumentTheme",
"nsIDocument_Type",
"nsCSSUnit",
"nsCSSFontDesc",
"nsCSSPropertyID",
"nsCSSCounterDesc",
+ "nsCSSKTableEntry_ValueInBooleanContext",
"nsMediaFeature_RangeType",
"nsMediaFeature_ValueType",
"nsresult",
"nsAtom_AtomKind",
"nsStyleImageLayers_LayerType",
"nsTimingFunction_Type",
"mozilla::ServoElementSnapshotFlags",
"mozilla::Side",
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -35,42 +35,54 @@ class ComputedStyle;
extern "C" {
nsCSSPropertyID Servo_ResolveLogicalProperty(nsCSSPropertyID,
const mozilla::ComputedStyle*);
}
struct nsCSSKTableEntry
{
+ // Indicates what this value represents in the boolean context.
+ enum ValueInBooleanContext {
+ eFalse,
+ eTrue,
+ };
+
// nsCSSKTableEntry objects can be initialized either with an int16_t value
// or a value of an enumeration type that can fit within an int16_t.
constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword, int16_t aValue)
: mKeyword(aKeyword)
, mValue(aValue)
+ , mValueInBooleanContext(ValueInBooleanContext::eTrue)
{
}
template<typename T,
typename = typename std::enable_if<std::is_enum<T>::value>::type>
- constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword, T aValue)
+ constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword,
+ T aValue,
+ ValueInBooleanContext aValueInBooleanContext =
+ eTrue)
: mKeyword(aKeyword)
, mValue(static_cast<int16_t>(aValue))
+ , mValueInBooleanContext(aValueInBooleanContext)
{
static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
"aValue must be an enum that fits within mValue");
}
bool IsSentinel() const
{
return mKeyword == eCSSKeyword_UNKNOWN && mValue == -1;
}
nsCSSKeyword mKeyword;
int16_t mValue;
+ ValueInBooleanContext mValueInBooleanContext;
};
class nsCSSProps {
public:
typedef mozilla::CSSEnabledState EnabledState;
typedef mozilla::CSSPropFlags Flags;
typedef nsCSSKTableEntry KTableEntry;
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -8,17 +8,18 @@ use app_units::AU_PER_PX;
use app_units::Au;
use context::QuirksMode;
use cssparser::{Parser, RGBA, Token};
use euclid::Size2D;
use euclid::TypedScale;
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use gecko_bindings::bindings;
use gecko_bindings::structs;
-use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSValue};
+use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKTableEntry_ValueInBooleanContext};
+use gecko_bindings::structs::{nsCSSKeyword, nsCSSUnit, nsCSSValue};
use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
use gecko_bindings::structs::RawGeckoPresContextOwned;
use media_queries::MediaType;
use parser::{Parse, ParserContext};
use properties::ComputedValues;
use servo_arc::Arc;
use std::fmt::{self, Write};
@@ -459,17 +460,17 @@ impl MediaExpressionValue {
MediaExpressionValue::Enumerated(value) => unsafe {
use std::{slice, str};
use std::os::raw::c_char;
// NB: All the keywords on nsMediaFeatures are static,
// well-formed utf-8.
let mut length = 0;
- let (keyword, _value) = find_in_table(
+ let (keyword, _value, _) = find_in_table(
*for_expr.feature.mData.mKeywordTable.as_ref(),
|_kw, val| val == value,
).expect("Value not found in the keyword table?");
let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length);
let buffer = slice::from_raw_parts(buffer as *const u8, length as usize);
let string = str::from_utf8_unchecked(buffer);
@@ -494,30 +495,30 @@ where
}
}
None
}
unsafe fn find_in_table<F>(
mut current_entry: *const nsCSSKTableEntry,
mut f: F,
-) -> Option<(nsCSSKeyword, i16)>
+) -> Option<(nsCSSKeyword, i16, nsCSSKTableEntry_ValueInBooleanContext)>
where
F: FnMut(nsCSSKeyword, i16) -> bool,
{
loop {
let value = (*current_entry).mValue;
let keyword = (*current_entry).mKeyword;
if value == -1 {
return None; // End of the table.
}
if f(keyword, value) {
- return Some((keyword, value));
+ return Some((keyword, value, (*current_entry).mValueInBooleanContext));
}
current_entry = current_entry.offset(1);
}
}
fn parse_feature_value<'i, 't>(
feature: &nsMediaFeature,
@@ -561,17 +562,17 @@ fn parse_feature_value<'i, 't>(
let keyword = unsafe {
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
};
let first_table_entry: *const nsCSSKTableEntry =
unsafe { *feature.mData.mKeywordTable.as_ref() };
let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } {
- Some((_kw, value)) => value,
+ Some((_kw, value, _)) => value,
None => {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
},
};
MediaExpressionValue::Enumerated(value)
},
nsMediaFeature_ValueType::eIdent => {
@@ -829,16 +830,24 @@ impl MediaFeatureExpression {
return match *actual_value {
BoolInteger(v) => v,
Integer(v) => v != 0,
Length(ref l) => computed::Context::for_media_query_evaluation(
device,
quirks_mode,
|context| l.to_computed_value(&context).px() != 0.,
),
+ Enumerated(value) => {
+ let (_kw, _value, value_in_boolean_context) = unsafe { find_in_table(
+ *self.feature.mData.mKeywordTable.as_ref(),
+ |_kw, val| val == value,
+ ).expect("Value not found in the keyword table?")
+ };
+ value_in_boolean_context == nsCSSKTableEntry_ValueInBooleanContext::eTrue
+ }
_ => true,
};
},
};
// FIXME(emilio): Handle the possible floating point errors?
let cmp = match (actual_value, required_value) {
(&Length(ref one), &Length(ref other)) => {