mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
style: Introduce nsCSSKeywordAndBoolTableEntry.
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 child struct of nsCSSKTableEntry that has an additional field representing 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). Bug: 1365045 Reviewed-by: heycam MozReview-Commit-ID: 79HiW8l5ous
This commit is contained in:
parent
d1733aa502
commit
c63a9a37a9
1 changed files with 127 additions and 35 deletions
|
@ -16,6 +16,7 @@ use gecko_bindings::structs;
|
||||||
use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSValue};
|
use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSValue};
|
||||||
use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
|
use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
|
||||||
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
|
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
|
||||||
|
use gecko_bindings::structs::nsCSSKeywordAndBoolTableEntry;
|
||||||
use gecko_bindings::structs::RawGeckoPresContextOwned;
|
use gecko_bindings::structs::RawGeckoPresContextOwned;
|
||||||
use media_queries::MediaType;
|
use media_queries::MediaType;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
|
@ -374,6 +375,9 @@ pub enum MediaExpressionValue {
|
||||||
/// An enumerated value, defined by the variant keyword table in the
|
/// An enumerated value, defined by the variant keyword table in the
|
||||||
/// feature's `mData` member.
|
/// feature's `mData` member.
|
||||||
Enumerated(i16),
|
Enumerated(i16),
|
||||||
|
/// Similar to the above Enumerated but the variant keyword table has an
|
||||||
|
/// additional field what the keyword value means in the Boolean Context.
|
||||||
|
BoolEnumerated(i16),
|
||||||
/// An identifier.
|
/// An identifier.
|
||||||
Ident(Atom),
|
Ident(Atom),
|
||||||
}
|
}
|
||||||
|
@ -420,6 +424,10 @@ impl MediaExpressionValue {
|
||||||
let value = css_value.integer_unchecked() as i16;
|
let value = css_value.integer_unchecked() as i16;
|
||||||
Some(MediaExpressionValue::Enumerated(value))
|
Some(MediaExpressionValue::Enumerated(value))
|
||||||
},
|
},
|
||||||
|
nsMediaFeature_ValueType::eBoolEnumerated => {
|
||||||
|
let value = css_value.integer_unchecked() as i16;
|
||||||
|
Some(MediaExpressionValue::BoolEnumerated(value))
|
||||||
|
},
|
||||||
nsMediaFeature_ValueType::eIdent => {
|
nsMediaFeature_ValueType::eIdent => {
|
||||||
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_AtomIdent);
|
debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_AtomIdent);
|
||||||
Some(MediaExpressionValue::Ident(unsafe {
|
Some(MediaExpressionValue::Ident(unsafe {
|
||||||
|
@ -457,25 +465,43 @@ impl MediaExpressionValue {
|
||||||
MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
|
MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
|
||||||
MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest),
|
MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest),
|
||||||
MediaExpressionValue::Enumerated(value) => unsafe {
|
MediaExpressionValue::Enumerated(value) => unsafe {
|
||||||
use std::{slice, str};
|
let keyword = find_in_table(
|
||||||
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(
|
|
||||||
*for_expr.feature.mData.mKeywordTable.as_ref(),
|
*for_expr.feature.mData.mKeywordTable.as_ref(),
|
||||||
|_kw, val| val == value,
|
|_kw, val| val == value,
|
||||||
|
|e| e.keyword(),
|
||||||
).expect("Value not found in the keyword table?");
|
).expect("Value not found in the keyword table?");
|
||||||
|
|
||||||
let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length);
|
MediaExpressionValue::keyword_to_css(keyword, dest)
|
||||||
let buffer = slice::from_raw_parts(buffer as *const u8, length as usize);
|
|
||||||
|
|
||||||
let string = str::from_utf8_unchecked(buffer);
|
|
||||||
|
|
||||||
dest.write_str(string)
|
|
||||||
},
|
},
|
||||||
|
MediaExpressionValue::BoolEnumerated(value) => unsafe {
|
||||||
|
let keyword = find_in_table(
|
||||||
|
*for_expr.feature.mData.mKeywordAndBoolTable.as_ref(),
|
||||||
|
|_kw, val| val == value,
|
||||||
|
|e| e.keyword(),
|
||||||
|
).expect("Value not found in the keyword table?");
|
||||||
|
|
||||||
|
MediaExpressionValue::keyword_to_css(keyword, dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn keyword_to_css<W>(keyword: nsCSSKeyword, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: fmt::Write,
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
unsafe {
|
||||||
|
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);
|
||||||
|
|
||||||
|
dest.write_str(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,23 +522,51 @@ where
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn find_in_table<F>(
|
trait TableEntry {
|
||||||
mut current_entry: *const nsCSSKTableEntry,
|
fn value(&self) -> i16;
|
||||||
mut f: F,
|
fn keyword(&self) -> nsCSSKeyword;
|
||||||
) -> Option<(nsCSSKeyword, i16)>
|
}
|
||||||
|
|
||||||
|
impl TableEntry for nsCSSKTableEntry {
|
||||||
|
fn value(&self) -> i16 {
|
||||||
|
self.mValue
|
||||||
|
}
|
||||||
|
fn keyword(&self) -> nsCSSKeyword {
|
||||||
|
self.mKeyword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableEntry for nsCSSKeywordAndBoolTableEntry {
|
||||||
|
fn value(&self) -> i16 {
|
||||||
|
self._base.mValue
|
||||||
|
}
|
||||||
|
fn keyword(&self) -> nsCSSKeyword {
|
||||||
|
self._base.mKeyword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn find_in_table<T, R, FindFunc, ResultFunc>(
|
||||||
|
current_entry: *const T,
|
||||||
|
find: FindFunc,
|
||||||
|
result_func: ResultFunc,
|
||||||
|
) -> Option<R>
|
||||||
where
|
where
|
||||||
F: FnMut(nsCSSKeyword, i16) -> bool,
|
T: TableEntry,
|
||||||
|
FindFunc: Fn(nsCSSKeyword, i16) -> bool,
|
||||||
|
ResultFunc: Fn(&T) -> R,
|
||||||
{
|
{
|
||||||
|
let mut current_entry = current_entry;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let value = (*current_entry).mValue;
|
let value = (*current_entry).value();
|
||||||
let keyword = (*current_entry).mKeyword;
|
let keyword = (*current_entry).keyword();
|
||||||
|
|
||||||
if value == -1 {
|
if value == -1 {
|
||||||
return None; // End of the table.
|
return None; // End of the table.
|
||||||
}
|
}
|
||||||
|
|
||||||
if f(keyword, value) {
|
if find(keyword, value) {
|
||||||
return Some((keyword, value));
|
return Some(result_func(&*current_entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
current_entry = current_entry.offset(1);
|
current_entry = current_entry.offset(1);
|
||||||
|
@ -556,24 +610,21 @@ fn parse_feature_value<'i, 't>(
|
||||||
MediaExpressionValue::Resolution(Resolution::parse(context, input)?)
|
MediaExpressionValue::Resolution(Resolution::parse(context, input)?)
|
||||||
},
|
},
|
||||||
nsMediaFeature_ValueType::eEnumerated => {
|
nsMediaFeature_ValueType::eEnumerated => {
|
||||||
let location = input.current_source_location();
|
|
||||||
let keyword = input.expect_ident()?;
|
|
||||||
let keyword = unsafe {
|
|
||||||
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
|
|
||||||
};
|
|
||||||
|
|
||||||
let first_table_entry: *const nsCSSKTableEntry =
|
let first_table_entry: *const nsCSSKTableEntry =
|
||||||
unsafe { *feature.mData.mKeywordTable.as_ref() };
|
unsafe { *feature.mData.mKeywordTable.as_ref() };
|
||||||
|
|
||||||
let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } {
|
let value = parse_keyword(input, first_table_entry)?;
|
||||||
Some((_kw, value)) => value,
|
|
||||||
None => {
|
|
||||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
MediaExpressionValue::Enumerated(value)
|
MediaExpressionValue::Enumerated(value)
|
||||||
},
|
},
|
||||||
|
nsMediaFeature_ValueType::eBoolEnumerated => {
|
||||||
|
let first_table_entry: *const nsCSSKeywordAndBoolTableEntry =
|
||||||
|
unsafe { *feature.mData.mKeywordAndBoolTable.as_ref() };
|
||||||
|
|
||||||
|
let value = parse_keyword(input, first_table_entry)?;
|
||||||
|
|
||||||
|
MediaExpressionValue::BoolEnumerated(value)
|
||||||
|
},
|
||||||
nsMediaFeature_ValueType::eIdent => {
|
nsMediaFeature_ValueType::eIdent => {
|
||||||
MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref()))
|
MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref()))
|
||||||
},
|
},
|
||||||
|
@ -582,6 +633,30 @@ fn parse_feature_value<'i, 't>(
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a keyword and returns the corresponding i16 value.
|
||||||
|
fn parse_keyword<'i, 't, T>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
first_table_entry: *const T,
|
||||||
|
) -> Result<i16, ParseError<'i>>
|
||||||
|
where
|
||||||
|
T: TableEntry,
|
||||||
|
{
|
||||||
|
let location = input.current_source_location();
|
||||||
|
let keyword = input.expect_ident()?;
|
||||||
|
let keyword = unsafe {
|
||||||
|
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
|
||||||
|
};
|
||||||
|
|
||||||
|
let value = unsafe {
|
||||||
|
find_in_table(first_table_entry, |kw, _| kw == keyword, |e| e.value())
|
||||||
|
};
|
||||||
|
|
||||||
|
match value {
|
||||||
|
Some(value) => Ok(value),
|
||||||
|
None => Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes an operation or a colon, or returns an error.
|
/// Consumes an operation or a colon, or returns an error.
|
||||||
fn consume_operation_or_colon(
|
fn consume_operation_or_colon(
|
||||||
input: &mut Parser,
|
input: &mut Parser,
|
||||||
|
@ -834,6 +909,16 @@ impl MediaFeatureExpression {
|
||||||
quirks_mode,
|
quirks_mode,
|
||||||
|context| l.to_computed_value(&context).px() != 0.,
|
|context| l.to_computed_value(&context).px() != 0.,
|
||||||
),
|
),
|
||||||
|
BoolEnumerated(value) => {
|
||||||
|
let value = unsafe {
|
||||||
|
find_in_table(
|
||||||
|
*self.feature.mData.mKeywordAndBoolTable.as_ref(),
|
||||||
|
|_kw, val| val == value,
|
||||||
|
|e| e.mValueInBooleanContext,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
value.expect("Value not found in the keyword table?")
|
||||||
|
},
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -880,6 +965,13 @@ impl MediaFeatureExpression {
|
||||||
);
|
);
|
||||||
return one == other;
|
return one == other;
|
||||||
},
|
},
|
||||||
|
(&BoolEnumerated(one), &BoolEnumerated(other)) => {
|
||||||
|
debug_assert_ne!(
|
||||||
|
self.feature.mRangeType,
|
||||||
|
nsMediaFeature_RangeType::eMinMaxAllowed
|
||||||
|
);
|
||||||
|
return one == other;
|
||||||
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue