Bug 1463589 - Add contain:size and contain:content parsing functionality.
MozReview-Commit-ID: 4fOqln3oOpC
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -521,16 +521,17 @@ CSS_KEY(sepia, sepia)
CSS_KEY(serif, serif)
CSS_KEY(sesame, sesame)
CSS_KEY(show, show)
CSS_KEY(sideways, sideways)
CSS_KEY(sideways-lr, sideways_lr)
CSS_KEY(sideways-right, sideways_right) /* alias for 'sideways' */
CSS_KEY(sideways-rl, sideways_rl)
CSS_KEY(simplified, simplified)
+CSS_KEY(size, size)
CSS_KEY(skew, skew)
CSS_KEY(skewx, skewx)
CSS_KEY(skewy, skewy)
CSS_KEY(slashed-zero, slashed_zero)
CSS_KEY(slice, slice)
CSS_KEY(small, small)
CSS_KEY(small-caps, small_caps)
CSS_KEY(small-caption, small_caption)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1043,19 +1043,21 @@ const KTableEntry nsCSSProps::kListStyle
{ eCSSKeyword_inside, NS_STYLE_LIST_STYLE_POSITION_INSIDE },
{ eCSSKeyword_outside, NS_STYLE_LIST_STYLE_POSITION_OUTSIDE },
{ eCSSKeyword_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kContainKTable[] = {
{ eCSSKeyword_none, NS_STYLE_CONTAIN_NONE },
{ eCSSKeyword_strict, NS_STYLE_CONTAIN_STRICT },
+ { eCSSKeyword_content, NS_STYLE_CONTAIN_CONTENT },
{ eCSSKeyword_layout, NS_STYLE_CONTAIN_LAYOUT },
{ eCSSKeyword_style, NS_STYLE_CONTAIN_STYLE },
{ eCSSKeyword_paint, NS_STYLE_CONTAIN_PAINT },
+ { eCSSKeyword_size, NS_STYLE_CONTAIN_SIZE },
{ eCSSKeyword_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kObjectFitKTable[] = {
{ eCSSKeyword_fill, NS_STYLE_OBJECT_FIT_FILL },
{ eCSSKeyword_contain, NS_STYLE_OBJECT_FIT_CONTAIN },
{ eCSSKeyword_cover, NS_STYLE_OBJECT_FIT_COVER },
{ eCSSKeyword_none, NS_STYLE_OBJECT_FIT_NONE },
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5040,24 +5040,28 @@ nsComputedDOMStyle::DoGetContain()
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
int32_t mask = StyleDisplay()->mContain;
if (mask == 0) {
val->SetIdent(eCSSKeyword_none);
} else if (mask & NS_STYLE_CONTAIN_STRICT) {
NS_ASSERTION(mask == (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS),
- "contain: strict should imply contain: layout style paint");
+ "contain: strict should imply contain: size layout style paint");
val->SetIdent(eCSSKeyword_strict);
- } else {
+ } else if (mask & NS_STYLE_CONTAIN_CONTENT) {
+ NS_ASSERTION(mask == (NS_STYLE_CONTAIN_CONTENT | NS_STYLE_CONTAIN_CONTENT_BITS),
+ "contain: content should imply contain: layout style paint");
+ val->SetIdent(eCSSKeyword_content);
+ } else {
nsAutoString valueStr;
-
nsStyleUtil::AppendBitmaskCSSValue(nsCSSProps::kContainKTable,
- mask, NS_STYLE_CONTAIN_LAYOUT,
- NS_STYLE_CONTAIN_PAINT, valueStr);
+ mask,
+ NS_STYLE_CONTAIN_SIZE, NS_STYLE_CONTAIN_PAINT,
+ valueStr);
val->SetString(valueStr);
}
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetPosition()
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -450,26 +450,32 @@ enum class StyleDisplay : uint8_t {
MozInlineStack,
MozDeck,
MozGroupbox,
MozPopup,
#endif
};
// See nsStyleDisplay
-// If these are re-ordered, nsComputedDOMStyle::DoGetContain() and
-// nsCSSValue::AppendToString() must be updated.
+// If these are re-ordered, nsComputedDOMStyle::DoGetContain() must be updated.
#define NS_STYLE_CONTAIN_NONE 0
-#define NS_STYLE_CONTAIN_STRICT 0x1
-#define NS_STYLE_CONTAIN_LAYOUT 0x2
-#define NS_STYLE_CONTAIN_STYLE 0x4
-#define NS_STYLE_CONTAIN_PAINT 0x8
+#define NS_STYLE_CONTAIN_SIZE 0x01
+#define NS_STYLE_CONTAIN_LAYOUT 0x02
+#define NS_STYLE_CONTAIN_STYLE 0x04
+#define NS_STYLE_CONTAIN_PAINT 0x08
+#define NS_STYLE_CONTAIN_STRICT 0x10
+#define NS_STYLE_CONTAIN_CONTENT 0x20
// NS_STYLE_CONTAIN_ALL_BITS does not correspond to a keyword.
#define NS_STYLE_CONTAIN_ALL_BITS (NS_STYLE_CONTAIN_LAYOUT | \
NS_STYLE_CONTAIN_STYLE | \
+ NS_STYLE_CONTAIN_PAINT | \
+ NS_STYLE_CONTAIN_SIZE)
+// NS_STYLE_CONTAIN_CONTENT_BITS does not correspond to a keyword.
+#define NS_STYLE_CONTAIN_CONTENT_BITS (NS_STYLE_CONTAIN_LAYOUT | \
+ NS_STYLE_CONTAIN_STYLE | \
NS_STYLE_CONTAIN_PAINT)
// Shared constants for all align/justify properties (nsStylePosition):
#define NS_STYLE_ALIGN_AUTO 0
#define NS_STYLE_ALIGN_NORMAL 1
#define NS_STYLE_ALIGN_START 2
#define NS_STYLE_ALIGN_END 3
#define NS_STYLE_ALIGN_FLEX_START 4
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -7273,38 +7273,50 @@ if (IsCSSPropertyPrefEnabled("layout.css
domProp: "contain",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [
"strict",
"layout",
"style",
+ "size",
+ "content",
"layout style",
"style layout",
"paint",
"layout paint",
"paint layout",
"style paint",
"paint style",
+ "size layout",
+ "style size",
+ "paint size",
"layout style paint",
"layout paint style",
"style paint layout",
"paint style layout",
],
invalid_values: [
"none strict",
"strict layout",
"strict layout style",
"layout strict",
+ "layout content",
+ "strict content",
"layout style strict",
"layout style paint strict",
"paint strict",
"style strict",
"paint paint",
+ "content content",
+ "size content",
+ "content strict size",
+ "paint layout content",
+ "layout size content",
"strict strict",
"auto",
"10px",
"0",
]
};
}
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -3622,72 +3622,100 @@ fn static_assert() {
T::AnimateableFeatures(custom_idents.into_boxed_slice())
}
<% impl_shape_source("shape_outside", "mShapeOutside") %>
pub fn set_contain(&mut self, v: longhands::contain::computed_value::T) {
use gecko_bindings::structs::NS_STYLE_CONTAIN_NONE;
use gecko_bindings::structs::NS_STYLE_CONTAIN_STRICT;
+ use gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT;
+ use gecko_bindings::structs::NS_STYLE_CONTAIN_SIZE;
use gecko_bindings::structs::NS_STYLE_CONTAIN_LAYOUT;
use gecko_bindings::structs::NS_STYLE_CONTAIN_STYLE;
use gecko_bindings::structs::NS_STYLE_CONTAIN_PAINT;
use gecko_bindings::structs::NS_STYLE_CONTAIN_ALL_BITS;
+ use gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT_BITS;
use properties::longhands::contain::SpecifiedValue;
if v.is_empty() {
self.gecko.mContain = NS_STYLE_CONTAIN_NONE as u8;
return;
}
if v.contains(SpecifiedValue::STRICT) {
self.gecko.mContain = (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS) as u8;
return;
}
+ if v.contains(SpecifiedValue::CONTENT) {
+ self.gecko.mContain = (NS_STYLE_CONTAIN_CONTENT | NS_STYLE_CONTAIN_CONTENT_BITS) as u8;
+ return;
+ }
let mut bitfield = 0;
if v.contains(SpecifiedValue::LAYOUT) {
bitfield |= NS_STYLE_CONTAIN_LAYOUT;
}
if v.contains(SpecifiedValue::STYLE) {
bitfield |= NS_STYLE_CONTAIN_STYLE;
}
if v.contains(SpecifiedValue::PAINT) {
bitfield |= NS_STYLE_CONTAIN_PAINT;
}
+ if v.contains(SpecifiedValue::SIZE) {
+ bitfield |= NS_STYLE_CONTAIN_SIZE;
+ }
self.gecko.mContain = bitfield as u8;
}
pub fn clone_contain(&self) -> longhands::contain::computed_value::T {
use gecko_bindings::structs::NS_STYLE_CONTAIN_STRICT;
+ use gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT;
+ use gecko_bindings::structs::NS_STYLE_CONTAIN_SIZE;
use gecko_bindings::structs::NS_STYLE_CONTAIN_LAYOUT;
use gecko_bindings::structs::NS_STYLE_CONTAIN_STYLE;
use gecko_bindings::structs::NS_STYLE_CONTAIN_PAINT;
use gecko_bindings::structs::NS_STYLE_CONTAIN_ALL_BITS;
+ use gecko_bindings::structs::NS_STYLE_CONTAIN_CONTENT_BITS;
use properties::longhands::contain::{self, SpecifiedValue};
let mut servo_flags = contain::computed_value::T::empty();
let gecko_flags = self.gecko.mContain;
- if gecko_flags & (NS_STYLE_CONTAIN_STRICT as u8) != 0 &&
- gecko_flags & (NS_STYLE_CONTAIN_ALL_BITS as u8) != 0 {
+ if gecko_flags & (NS_STYLE_CONTAIN_STRICT as u8) != 0 {
+ debug_assert_eq!(
+ gecko_flags & (NS_STYLE_CONTAIN_ALL_BITS as u8),
+ NS_STYLE_CONTAIN_ALL_BITS as u8,
+ "When strict is specified, ALL_BITS should be specified as well"
+ );
servo_flags.insert(SpecifiedValue::STRICT | SpecifiedValue::STRICT_BITS);
return servo_flags;
}
-
+ if gecko_flags & (NS_STYLE_CONTAIN_CONTENT as u8) != 0 {
+ debug_assert_eq!(
+ gecko_flags & (NS_STYLE_CONTAIN_CONTENT_BITS as u8),
+ NS_STYLE_CONTAIN_CONTENT_BITS as u8,
+ "When content is specified, CONTENT_BITS should be specified as well"
+ );
+ servo_flags.insert(SpecifiedValue::CONTENT | SpecifiedValue::CONTENT_BITS);
+ return servo_flags;
+ }
if gecko_flags & (NS_STYLE_CONTAIN_LAYOUT as u8) != 0 {
servo_flags.insert(SpecifiedValue::LAYOUT);
}
- if gecko_flags & (NS_STYLE_CONTAIN_STYLE as u8) != 0{
+ if gecko_flags & (NS_STYLE_CONTAIN_STYLE as u8) != 0 {
servo_flags.insert(SpecifiedValue::STYLE);
}
if gecko_flags & (NS_STYLE_CONTAIN_PAINT as u8) != 0 {
servo_flags.insert(SpecifiedValue::PAINT);
}
+ if gecko_flags & (NS_STYLE_CONTAIN_SIZE as u8) != 0 {
+ servo_flags.insert(SpecifiedValue::SIZE);
+ }
return servo_flags;
}
${impl_simple_copy("contain", "mContain")}
${impl_simple_type_with_conversion("touch_action")}
</%self:impl_trait>
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -520,56 +520,66 @@ pub fn assert_touch_action_matches() {
NS_STYLE_TOUCH_ACTION_PAN_X => TouchAction::TOUCH_ACTION_PAN_X,
NS_STYLE_TOUCH_ACTION_PAN_Y => TouchAction::TOUCH_ACTION_PAN_Y,
NS_STYLE_TOUCH_ACTION_MANIPULATION => TouchAction::TOUCH_ACTION_MANIPULATION,
}
}
bitflags! {
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)]
- #[value_info(other_values = "none,strict,layout,style,paint")]
+ #[value_info(other_values = "none,strict,content,size,layout,style,paint")]
/// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property
pub struct Contain: u8 {
+ /// 'size' variant, turns on size containment
+ const SIZE = 0x01;
/// `layout` variant, turns on layout containment
- const LAYOUT = 0x01;
+ const LAYOUT = 0x02;
/// `style` variant, turns on style containment
- const STYLE = 0x02;
+ const STYLE = 0x04;
/// `paint` variant, turns on paint containment
- const PAINT = 0x04;
+ const PAINT = 0x08;
/// `strict` variant, turns on all types of containment
- const STRICT = 0x8;
+ const STRICT = 0x10;
+ /// 'content' variant, turns on style, layout, and paint containment
+ const CONTENT = 0x20;
/// variant with all the bits that contain: strict turns on
- const STRICT_BITS = Contain::LAYOUT.bits | Contain::STYLE.bits | Contain::PAINT.bits;
+ const STRICT_BITS = Contain::LAYOUT.bits | Contain::STYLE.bits | Contain::PAINT.bits | Contain::SIZE.bits;
+ /// variant with all the bits that contain: content turns on
+ const CONTENT_BITS = Contain::STYLE.bits | Contain::LAYOUT.bits | Contain::PAINT.bits;
}
}
impl ToCss for Contain {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("none");
}
if self.contains(Contain::STRICT) {
return dest.write_str("strict");
}
+ if self.contains(Contain::CONTENT) {
+ return dest.write_str("content");
+ }
let mut has_any = false;
macro_rules! maybe_write_value {
($ident:path => $str:expr) => {
if self.contains($ident) {
if has_any {
dest.write_str(" ")?;
}
has_any = true;
dest.write_str($str)?;
}
};
}
+ maybe_write_value!(Contain::SIZE => "size");
maybe_write_value!(Contain::LAYOUT => "layout");
maybe_write_value!(Contain::STYLE => "style");
maybe_write_value!(Contain::PAINT => "paint");
debug_assert!(has_any);
Ok(())
}
}
@@ -578,20 +588,22 @@ impl Parse for Contain {
/// none | strict | content | [ size || layout || style || paint ]
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Contain, ParseError<'i>> {
let mut result = Contain::empty();
while let Ok(name) = input.try(|i| i.expect_ident_cloned()) {
let flag = match_ignore_ascii_case! { &name,
+ "size" => Some(Contain::SIZE),
"layout" => Some(Contain::LAYOUT),
"style" => Some(Contain::STYLE),
"paint" => Some(Contain::PAINT),
"strict" if result.is_empty() => return Ok(Contain::STRICT | Contain::STRICT_BITS),
+ "content" if result.is_empty() => return Ok(Contain::CONTENT | Contain::CONTENT_BITS),
"none" if result.is_empty() => return Ok(result),
_ => None
};
let flag = match flag {
Some(flag) if !result.contains(flag) => flag,
_ => {
return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name)))