mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1281158 - Parse alternative text for the content property. r=dshin
This doesn't yet expose it to a11y but that will be done by the a11y folks, since this blocks some of the a11y interop test-cases. Modify the tests to not hit the network, and make -moz-alt-content not exposed to content (we only need it for UA stylesheets). Differential Revision: https://phabricator.services.mozilla.com/D209690
This commit is contained in:
parent
dc9b47aecf
commit
4d5aee49f3
@ -1537,12 +1537,11 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGenConTextNode(
|
||||
|
||||
void nsCSSFrameConstructor::CreateGeneratedContent(
|
||||
nsFrameConstructorState& aState, Element& aOriginatingElement,
|
||||
ComputedStyle& aPseudoStyle, uint32_t aContentIndex,
|
||||
const FunctionRef<void(nsIContent*)> aAddChild) {
|
||||
ComputedStyle& aPseudoStyle, const StyleContentItem& aItem,
|
||||
size_t aContentIndex, const FunctionRef<void(nsIContent*)> aAddChild) {
|
||||
using Type = StyleContentItem::Tag;
|
||||
// Get the content value
|
||||
const auto& item = aPseudoStyle.StyleContent()->ContentAt(aContentIndex);
|
||||
const Type type = item.tag;
|
||||
const Type type = aItem.tag;
|
||||
|
||||
switch (type) {
|
||||
case Type::Image: {
|
||||
@ -1552,7 +1551,7 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
|
||||
}
|
||||
|
||||
case Type::String: {
|
||||
const auto string = item.AsString().AsString();
|
||||
const auto string = aItem.AsString().AsString();
|
||||
if (string.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -1563,7 +1562,7 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
|
||||
}
|
||||
|
||||
case Type::Attr: {
|
||||
const auto& attr = item.AsAttr();
|
||||
const auto& attr = aItem.AsAttr();
|
||||
RefPtr<nsAtom> attrName = attr.attribute.AsAtom();
|
||||
int32_t attrNameSpace = kNameSpaceID_None;
|
||||
RefPtr<nsAtom> ns = attr.namespace_url.AsAtom();
|
||||
@ -1592,11 +1591,11 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
|
||||
CounterStylePtr ptr;
|
||||
nsString separator;
|
||||
if (type == Type::Counter) {
|
||||
auto& counter = item.AsCounter();
|
||||
auto& counter = aItem.AsCounter();
|
||||
name = counter._0.AsAtom();
|
||||
ptr = CounterStylePtr::FromStyle(counter._1);
|
||||
} else {
|
||||
auto& counters = item.AsCounters();
|
||||
auto& counters = aItem.AsCounters();
|
||||
name = counters._0.AsAtom();
|
||||
CopyUTF8toUTF16(counters._1.AsString(), separator);
|
||||
ptr = CounterStylePtr::FromStyle(counters._2);
|
||||
@ -1947,13 +1946,14 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
|
||||
mPresShell->StyleSet()->StyleNewSubtree(childElement);
|
||||
}
|
||||
};
|
||||
const uint32_t contentCount = pseudoStyle->StyleContent()->ContentCount();
|
||||
for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
|
||||
CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle,
|
||||
contentIndex, AppendChild);
|
||||
auto items = pseudoStyle->StyleContent()->NonAltContentItems();
|
||||
size_t index = 0;
|
||||
for (const auto& item : items) {
|
||||
CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item,
|
||||
index++, AppendChild);
|
||||
}
|
||||
// If a ::marker has no 'content' then generate it from its 'list-style-*'.
|
||||
if (contentCount == 0 && aPseudoElement == PseudoStyleType::marker) {
|
||||
if (index == 0 && aPseudoElement == PseudoStyleType::marker) {
|
||||
CreateGeneratedContentFromListStyle(aState, aOriginatingElement,
|
||||
*pseudoStyle, AppendChild);
|
||||
}
|
||||
|
@ -477,7 +477,8 @@ class nsCSSFrameConstructor final : public nsFrameManager {
|
||||
*/
|
||||
void CreateGeneratedContent(
|
||||
nsFrameConstructorState& aState, Element& aOriginatingElement,
|
||||
ComputedStyle& aPseudoStyle, uint32_t aContentIndex,
|
||||
ComputedStyle& aPseudoStyle, const mozilla::StyleContentItem& aItem,
|
||||
size_t aContentIndex,
|
||||
const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
|
||||
|
||||
/**
|
||||
|
@ -12,12 +12,13 @@
|
||||
#include "nsIFrame.h"
|
||||
|
||||
void nsGenConNode::CheckFrameAssertions() {
|
||||
NS_ASSERTION(
|
||||
mContentIndex < int32_t(mPseudoFrame->StyleContent()->ContentCount()) ||
|
||||
// Special-case for the USE node created for the legacy markers,
|
||||
// which don't use the content property.
|
||||
mContentIndex == 0,
|
||||
"index out of range");
|
||||
NS_ASSERTION(mContentIndex < int32_t(mPseudoFrame->StyleContent()
|
||||
->NonAltContentItems()
|
||||
.Length()) ||
|
||||
// Special-case for the USE node created for the legacy
|
||||
// markers, which don't use the content property.
|
||||
mContentIndex == 0,
|
||||
"index out of range");
|
||||
// We allow negative values of mContentIndex for 'counter-reset' and
|
||||
// 'counter-increment'.
|
||||
|
||||
|
@ -900,7 +900,7 @@ void nsLayoutUtils::GetMarkerSpokenText(const nsIContent* aContent,
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame->StyleContent()->ContentCount() > 0) {
|
||||
if (!frame->StyleContent()->NonAltContentItems().IsEmpty()) {
|
||||
for (nsIFrame* child : frame->PrincipalChildList()) {
|
||||
nsIFrame::RenderedText text = child->GetRenderedText();
|
||||
aText += text.mString;
|
||||
|
@ -7980,7 +7980,7 @@ bool nsBlockFrame::MarkerIsEmpty() const {
|
||||
const nsStyleList* list = marker->StyleList();
|
||||
return marker->StyleContent()->mContent.IsNone() ||
|
||||
(list->mCounterStyle.IsNone() && list->mListStyleImage.IsNone() &&
|
||||
marker->StyleContent()->ContentCount() == 0);
|
||||
marker->StyleContent()->NonAltContentItems().IsEmpty());
|
||||
}
|
||||
|
||||
void nsBlockFrame::ReflowOutsideMarker(nsIFrame* aMarkerFrame,
|
||||
|
@ -645,8 +645,9 @@ const StyleImage* nsImageFrame::GetImageFromStyle() const {
|
||||
nonAnonymousParent->GetContent());
|
||||
styleContent = nonAnonymousParent->StyleContent();
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(contentIndex < styleContent->ContentCount());
|
||||
auto& contentItem = styleContent->ContentAt(contentIndex);
|
||||
auto items = styleContent->NonAltContentItems();
|
||||
MOZ_RELEASE_ASSERT(contentIndex < items.Length());
|
||||
const auto& contentItem = items[contentIndex];
|
||||
MOZ_RELEASE_ASSERT(contentItem.IsImage());
|
||||
return &contentItem.AsImage();
|
||||
}
|
||||
@ -1055,11 +1056,8 @@ bool nsImageFrame::ShouldCreateImageFrameForContentProperty(
|
||||
if (aElement.IsRootOfNativeAnonymousSubtree()) {
|
||||
return false;
|
||||
}
|
||||
const auto& content = aStyle.StyleContent()->mContent;
|
||||
if (!content.IsItems()) {
|
||||
return false;
|
||||
}
|
||||
Span<const StyleContentItem> items = content.AsItems().AsSpan();
|
||||
Span<const StyleContentItem> items =
|
||||
aStyle.StyleContent()->NonAltContentItems();
|
||||
return items.Length() == 1 && items[0].IsImage();
|
||||
}
|
||||
|
||||
|
@ -767,7 +767,7 @@ bool ServoStyleSet::GeneratedContentPseudoExists(
|
||||
if (!aPseudoStyle.StyleContent()->mContent.IsItems()) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(aPseudoStyle.StyleContent()->ContentCount() > 0,
|
||||
MOZ_ASSERT(!aPseudoStyle.StyleContent()->NonAltContentItems().IsEmpty(),
|
||||
"IsItems() implies we have at least one item");
|
||||
// display:none is equivalent to not having a pseudo at all.
|
||||
if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
|
||||
|
@ -2698,12 +2698,11 @@ void nsStyleContent::TriggerImageLoads(Document& aDoc,
|
||||
}
|
||||
|
||||
Span<const StyleContentItem> oldItems;
|
||||
if (aOld && aOld->mContent.IsItems()) {
|
||||
oldItems = aOld->mContent.AsItems().AsSpan();
|
||||
if (aOld) {
|
||||
oldItems = aOld->NonAltContentItems();
|
||||
}
|
||||
|
||||
auto items = mContent.AsItems().AsSpan();
|
||||
|
||||
auto items = NonAltContentItems();
|
||||
for (size_t i = 0; i < items.Length(); ++i) {
|
||||
const auto& item = items[i];
|
||||
if (!item.IsImage()) {
|
||||
|
@ -1603,12 +1603,22 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent {
|
||||
|
||||
using CounterPair = mozilla::StyleGenericCounterPair<int32_t>;
|
||||
|
||||
size_t ContentCount() const {
|
||||
return mContent.IsItems() ? mContent.AsItems().Length() : 0;
|
||||
/// Returns the content items that aren't alternative content.
|
||||
mozilla::Span<const mozilla::StyleContentItem> NonAltContentItems() const {
|
||||
if (!mContent.IsItems()) {
|
||||
return {};
|
||||
}
|
||||
const auto& items = mContent.AsItems();
|
||||
return mozilla::Span(items.items).To(items.alt_start);
|
||||
}
|
||||
|
||||
const mozilla::StyleContentItem& ContentAt(size_t aIndex) const {
|
||||
return mContent.AsItems().AsSpan()[aIndex];
|
||||
/// Returns the content items that /are/ alternative content.
|
||||
mozilla::Span<const mozilla::StyleContentItem> AltContentItems() const {
|
||||
if (!mContent.IsItems()) {
|
||||
return {};
|
||||
}
|
||||
const auto& items = mContent.AsItems();
|
||||
return mozilla::Span(items.items).From(items.alt_start);
|
||||
}
|
||||
|
||||
mozilla::StyleContent mContent;
|
||||
|
@ -5382,7 +5382,6 @@ var gCSSProperties = {
|
||||
"counter(\\()",
|
||||
"counters(a\\+b, '.')",
|
||||
"counter(\\}, upper-alpha)",
|
||||
"-moz-alt-content",
|
||||
"counter(foo, symbols('*'))",
|
||||
"counter(foo, symbols(numeric '0' '1'))",
|
||||
"counters(foo, '.', symbols('*'))",
|
||||
@ -5400,6 +5399,7 @@ var gCSSProperties = {
|
||||
"attr(-2)",
|
||||
"counter(2)",
|
||||
"counters(-2, '.')",
|
||||
"-moz-alt-content",
|
||||
"-moz-alt-content 'foo'",
|
||||
"'foo' -moz-alt-content",
|
||||
"counter(one, two, three) 'foo'",
|
||||
|
@ -8623,6 +8623,13 @@
|
||||
mirror: always
|
||||
rust: true
|
||||
|
||||
# Whether alt text in content is enabled.
|
||||
- name: layout.css.content.alt-text.enabled
|
||||
type: RelaxedAtomicBool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
rust: true
|
||||
|
||||
# Should stray control characters be rendered visibly?
|
||||
- name: layout.css.control-characters.visible
|
||||
type: RelaxedAtomicBool
|
||||
|
@ -203,6 +203,41 @@ fn is_decimal(counter_type: &CounterStyleType) -> bool {
|
||||
*counter_type == CounterStyle::decimal()
|
||||
}
|
||||
|
||||
/// The non-normal, non-none values of the content property.
|
||||
#[derive(
|
||||
Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToShmem,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct GenericContentItems<Image> {
|
||||
/// The actual content items. Note that, past the alt marker, only some subset (strings,
|
||||
/// attr(), counter())
|
||||
pub items: thin_vec::ThinVec<GenericContentItem<Image>>,
|
||||
/// The index at which alt text starts, always non-zero. If equal to items.len(), no alt text
|
||||
/// exists.
|
||||
pub alt_start: usize,
|
||||
}
|
||||
|
||||
impl<Image> ToCss for GenericContentItems<Image>
|
||||
where
|
||||
Image: ToCss,
|
||||
{
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
for (i, item) in self.items.iter().enumerate() {
|
||||
if i == self.alt_start {
|
||||
dest.write_str(" /")?;
|
||||
}
|
||||
if i != 0 {
|
||||
dest.write_str(" ")?;
|
||||
}
|
||||
item.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The specified value for the `content` property.
|
||||
///
|
||||
/// https://drafts.csswg.org/css-content/#propdef-content
|
||||
@ -216,7 +251,7 @@ pub enum GenericContent<Image> {
|
||||
/// `none` reserved keyword.
|
||||
None,
|
||||
/// Content items.
|
||||
Items(#[css(iterable)] crate::OwnedSlice<GenericContentItem<Image>>),
|
||||
Items(GenericContentItems<Image>),
|
||||
}
|
||||
|
||||
pub use self::GenericContent as Content;
|
||||
|
@ -192,29 +192,33 @@ impl Parse for Content {
|
||||
return Ok(generics::Content::None);
|
||||
}
|
||||
|
||||
let mut content = vec![];
|
||||
let mut has_alt_content = false;
|
||||
let mut items = thin_vec::ThinVec::new();
|
||||
let mut alt_start = None;
|
||||
loop {
|
||||
{
|
||||
if alt_start.is_none() {
|
||||
if let Ok(image) = input.try_parse(|i| Image::parse_forbid_none(context, i)) {
|
||||
content.push(generics::ContentItem::Image(image));
|
||||
items.push(generics::ContentItem::Image(image));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match input.next() {
|
||||
Ok(&Token::QuotedString(ref value)) => {
|
||||
content.push(generics::ContentItem::String(
|
||||
let Ok(t) = input.next() else { break };
|
||||
match *t {
|
||||
Token::QuotedString(ref value) => {
|
||||
items.push(generics::ContentItem::String(
|
||||
value.as_ref().to_owned().into(),
|
||||
));
|
||||
},
|
||||
Ok(&Token::Function(ref name)) => {
|
||||
Token::Function(ref name) => {
|
||||
// FIXME(emilio): counter() / counters() should be valid per spec past
|
||||
// the alt marker, but it's likely non-trivial to support and other
|
||||
// browsers don't support it either, so restricting it for now.
|
||||
let result = match_ignore_ascii_case! { &name,
|
||||
"counter" => input.parse_nested_block(|input| {
|
||||
"counter" if alt_start.is_none() => input.parse_nested_block(|input| {
|
||||
let name = CustomIdent::parse(input, &[])?;
|
||||
let style = Content::parse_counter_style(context, input);
|
||||
Ok(generics::ContentItem::Counter(name, style))
|
||||
}),
|
||||
"counters" => input.parse_nested_block(|input| {
|
||||
"counters" if alt_start.is_none() => input.parse_nested_block(|input| {
|
||||
let name = CustomIdent::parse(input, &[])?;
|
||||
input.expect_comma()?;
|
||||
let separator = input.expect_string()?.as_ref().to_owned().into();
|
||||
@ -232,17 +236,16 @@ impl Parse for Content {
|
||||
))
|
||||
}
|
||||
}?;
|
||||
content.push(result);
|
||||
items.push(result);
|
||||
},
|
||||
Ok(&Token::Ident(ref ident)) => {
|
||||
content.push(match_ignore_ascii_case! { &ident,
|
||||
Token::Ident(ref ident) if alt_start.is_none() => {
|
||||
items.push(match_ignore_ascii_case! { &ident,
|
||||
"open-quote" => generics::ContentItem::OpenQuote,
|
||||
"close-quote" => generics::ContentItem::CloseQuote,
|
||||
"no-open-quote" => generics::ContentItem::NoOpenQuote,
|
||||
"no-close-quote" => generics::ContentItem::NoCloseQuote,
|
||||
#[cfg(feature = "gecko")]
|
||||
"-moz-alt-content" => {
|
||||
has_alt_content = true;
|
||||
"-moz-alt-content" if context.in_ua_sheet() => {
|
||||
generics::ContentItem::MozAltContent
|
||||
},
|
||||
"-moz-label-content" if context.chrome_rules_enabled() => {
|
||||
@ -256,17 +259,26 @@ impl Parse for Content {
|
||||
}
|
||||
});
|
||||
},
|
||||
Err(_) => break,
|
||||
Ok(t) => {
|
||||
Token::Delim('/')
|
||||
if alt_start.is_none() &&
|
||||
!items.is_empty() &&
|
||||
static_prefs::pref!("layout.css.content.alt-text.enabled") =>
|
||||
{
|
||||
alt_start = Some(items.len());
|
||||
},
|
||||
ref t => {
|
||||
let t = t.clone();
|
||||
return Err(input.new_unexpected_token_error(t));
|
||||
},
|
||||
}
|
||||
}
|
||||
// We don't allow to parse `-moz-alt-content` in multiple positions.
|
||||
if content.is_empty() || (has_alt_content && content.len() != 1) {
|
||||
if items.is_empty() {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
Ok(generics::Content::Items(content.into()))
|
||||
let alt_start = alt_start.unwrap_or(items.len());
|
||||
Ok(generics::Content::Items(generics::GenericContentItems {
|
||||
items,
|
||||
alt_start,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
[content-computed.html]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1281158
|
||||
[Property content value 'open-quote / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'close-quote / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'no-open-quote / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'no-close-quote / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counter(counter-name) / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counter(counter-name, counter-style) / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counter(counter-name, dECiMaL) / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counter(counter-name, DECIMAL) / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counters(counter-name, ".") / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counters(counter-name, ".", counter-style) / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counters(counter-name, ".", dECiMaL) / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counters(counter-name, ".", DECIMAL) / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'url("https://www.example.com/picture.svg") / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value '"hello" / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counter(counter-name) "potato" / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'counters(counter-name, ".") "potato" / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value '"(" counters(counter-name, ".", counter-style) ")" / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'open-quote "hello" "world" close-quote / "alt text"']
|
||||
expected: FAIL
|
||||
|
||||
[Property content value 'url("https://www.example.com/picture.svg") "hello" / "alt text"']
|
||||
expected: FAIL
|
@ -1,207 +0,0 @@
|
||||
[content-valid.html]
|
||||
[e.style['content'\] = "open-quote / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "open-quote / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "open-quote / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "close-quote / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "close-quote / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "close-quote / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "no-open-quote / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "no-open-quote / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "no-open-quote / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "no-close-quote / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "no-close-quote / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "no-close-quote / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "attr(alt) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "attr(alt) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "attr(alt) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "attr(data-foo) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "attr(data-foo) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "attr(data-foo) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, counter-style) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, counter-style) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, counter-style) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, dECiMaL) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, dECiMaL) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, dECiMaL) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, DECIMAL) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, DECIMAL) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name, DECIMAL) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\") / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\") / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\") / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", counter-style) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", counter-style) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", counter-style) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", dECiMaL) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", dECiMaL) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", dECiMaL) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", DECIMAL) / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", DECIMAL) / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\", DECIMAL) / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "url(\\"https://www.example.com/picture.svg\\") / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "url(\\"https://www.example.com/picture.svg\\") / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "url(\\"https://www.example.com/picture.svg\\") / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" \\"world\\" / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" \\"world\\" / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" \\"world\\" / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" attr(alt) \\"world\\" / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" attr(alt) \\"world\\" / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"hello\\" attr(alt) \\"world\\" / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name) \\"potato\\" / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name) \\"potato\\" / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counter(counter-name) \\"potato\\" / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\") \\"potato\\" / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\") \\"potato\\" / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "counters(counter-name, \\".\\") \\"potato\\" / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"(\\" counters(counter-name, \\".\\", counter-style) \\")\\" / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"(\\" counters(counter-name, \\".\\", counter-style) \\")\\" / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "\\"(\\" counters(counter-name, \\".\\", counter-style) \\")\\" / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "open-quote \\"hello\\" \\"world\\" close-quote / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "open-quote \\"hello\\" \\"world\\" close-quote / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "open-quote \\"hello\\" \\"world\\" close-quote / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "url(\\"https://www.example.com/picture.svg\\") \\"hello\\" / \\"alt text\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "url(\\"https://www.example.com/picture.svg\\") \\"hello\\" / \\"alt text\\" attr(foo) \\"bar\\"" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['content'\] = "url(\\"https://www.example.com/picture.svg\\") \\"hello\\" / attr(foo)" should set the property value]
|
||||
expected: FAIL
|
@ -42,7 +42,7 @@ test_valid_value_combinations("content", `counters(counter-name, ".", counter-st
|
||||
test_valid_value_combinations("content", `counters(counter-name, ".", dECiMaL)`, `counters(counter-name, ".")`);
|
||||
test_valid_value_combinations("content", `counters(counter-name, ".", DECIMAL)`, `counters(counter-name, ".")`);
|
||||
|
||||
test_valid_value_combinations("content", `url("https://www.example.com/picture.svg")`);
|
||||
test_valid_value_combinations("content", `url("picture.svg")`);
|
||||
|
||||
test_valid_value_combinations("content", `"hello"`);
|
||||
|
||||
@ -52,7 +52,7 @@ test_valid_value_combinations("content", `counter(counter-name) "potato"`);
|
||||
test_valid_value_combinations("content", `counters(counter-name, ".") "potato"`);
|
||||
test_valid_value_combinations("content", `"(" counters(counter-name, ".", counter-style) ")"`);
|
||||
test_valid_value_combinations("content", `open-quote "hello" "world" close-quote`);
|
||||
test_valid_value_combinations("content", `url("https://www.example.com/picture.svg") "hello"`);
|
||||
test_valid_value_combinations("content", `url("picture.svg") "hello"`);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user