Bug 215083: Implement content: url(..) for elements. r?tnikkel,dholbert
Dynamic changes are handled correctly because content property changes already
cause a reframe.
This implements the same bits as Blink / WebKit do (single content item which is
an image, otherwise gets ignored), except for the edge cases where you use this
on an image.
In order to handle the edge cases right, we completely isolate the
nsImageLoadingContent usage based on `mKind`.
Blink's and WebKit's behavior there makes no sense and it's erratic, what I
implemented is consistent (we apply to images as long as they don't generate a
box, and we don't look at alt text or broken icons), though I'll update to
whatever the WG decides in https://github.com/w3c/csswg-drafts/issues/2831 /
https://github.com/w3c/csswg-drafts/issues/2832.
I don't think it matters in terms of web compat in any case.
MozReview-Commit-ID: JUurhC60hWr
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -315,16 +315,19 @@ nsIFrame*
NS_NewSliderFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame*
NS_NewScrollbarFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame*
NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle);
+nsIFrame*
+NS_NewImageFrameForContentProperty(nsIPresShell*, ComputedStyle*);
+
#ifdef NOISY_FINDFRAME
static int32_t FFWC_totalCount=0;
static int32_t FFWC_doLoop=0;
static int32_t FFWC_doSibling=0;
static int32_t FFWC_recursions=0;
static int32_t FFWC_nextInFlows=0;
#endif
@@ -5615,16 +5618,27 @@ ShouldSuppressFrameInNonOpenDetails(cons
!aChild->IsGeneratedContentContainerForBefore() &&
!aChild->IsGeneratedContentContainerForAfter()) {
return false;
}
return true;
}
+static bool
+ShouldCreateImageFrameForContent(ComputedStyle& aStyle)
+{
+ auto& content = *aStyle.StyleContent();
+ if (content.ContentCount() != 1) {
+ return false;
+ }
+
+ return content.ContentAt(0).GetType() == eStyleContentType_Image;
+}
+
void
nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
nsIContent* aContent,
nsContainerFrame* aParentFrame,
bool aSuppressWhiteSpaceOptimizations,
ComputedStyle* aComputedStyle,
uint32_t aFlags,
nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
@@ -5779,16 +5793,24 @@ nsCSSFrameConstructor::AddFrameConstruct
}
if (!data) {
data = FindSVGData(element, tag, namespaceId, aParentFrame,
aFlags & ITEM_IS_WITHIN_SVG_TEXT,
aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD,
computedStyle);
}
+ // Check for 'content: <image-url>' on the element (which makes us ignore
+ // 'display' values other than 'none' or 'contents').
+ if (!data && ShouldCreateImageFrameForContent(*computedStyle)) {
+ static const FrameConstructionData sImgData =
+ SIMPLE_FCDATA(NS_NewImageFrameForContentProperty);
+ data = &sImgData;
+ }
+
// Now check for XUL display types
if (!data) {
data = FindXULDisplayData(display, element, computedStyle);
}
// And general display types
if (!data) {
data = FindDisplayData(display, element, computedStyle);
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -125,25 +125,34 @@ inline bool HaveFixedSize(const ReflowIn
// auto (especially for intrinsic width calculations and for heights).
return aReflowInput.mStylePosition->mHeight.ConvertsToLength() &&
aReflowInput.mStylePosition->mWidth.ConvertsToLength();
}
nsIFrame*
NS_NewImageFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
{
- return new (aPresShell) nsImageFrame(aStyle);
+ return new (aPresShell) nsImageFrame(aStyle, nsImageFrame::Kind::ImageElement);
+}
+
+nsIFrame*
+NS_NewImageFrameForContentProperty(nsIPresShell* aPresShell,
+ ComputedStyle* aStyle)
+{
+ return new (aPresShell) nsImageFrame(
+ aStyle, nsImageFrame::Kind::NonGeneratedContentProperty);
}
NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame)
-nsImageFrame::nsImageFrame(ComputedStyle* aStyle, ClassID aID)
+nsImageFrame::nsImageFrame(ComputedStyle* aStyle, ClassID aID, Kind aKind)
: nsAtomicContainerFrame(aStyle, aID)
, mComputedSize(0, 0)
, mIntrinsicRatio(0, 0)
+ , mKind(aKind)
, mDisplayingIcon(false)
, mFirstFrameComplete(false)
, mReflowCallbackPosted(false)
, mForceSyncDecoding(false)
{
EnableVisibilityTracking();
// We assume our size is not constrained and we haven't gotten an
@@ -198,30 +207,35 @@ nsImageFrame::DestroyFrom(nsIFrame* aDes
mReflowCallbackPosted = false;
}
// Tell our image map, if there is one, to clean up
// This causes the nsImageMap to unregister itself as
// a DOM listener.
DisconnectMap();
- // set the frame to null so we don't send messages to a dead object.
- if (mListener) {
+ MOZ_ASSERT(mListener);
+
+ if (mKind == Kind::ImageElement) {
+ MOZ_ASSERT(!mContentURLRequest);
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
- if (imageLoader) {
- // Notify our image loading content that we are going away so it can
- // deregister with our refresh driver.
- imageLoader->FrameDestroyed(this);
+ MOZ_ASSERT(imageLoader);
- imageLoader->RemoveNativeObserver(mListener);
+ // Notify our image loading content that we are going away so it can
+ // deregister with our refresh driver.
+ imageLoader->FrameDestroyed(this);
+ imageLoader->RemoveNativeObserver(mListener);
+ } else {
+ if (mContentURLRequest) {
+ mContentURLRequest->Cancel(NS_BINDING_ABORTED);
}
-
- mListener->SetFrame(nullptr);
}
+ // set the frame to null so we don't send messages to a dead object.
+ mListener->SetFrame(nullptr);
mListener = nullptr;
// If we were displaying an icon, take ourselves off the list
if (mDisplayingIcon)
gIconLoad->RemoveIconObserver(this);
nsAtomicContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
}
@@ -261,27 +275,31 @@ nsImageFrame::Init(nsIContent* aCo
{
nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
mListener = new nsImageListener(this);
if (!gIconLoad)
LoadIcons(PresContext());
- nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aContent);
- if (!imageLoader) {
- MOZ_CRASH("Why do we have an nsImageFrame here at all?");
+ if (mKind == Kind::ImageElement) {
+ nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aContent);
+ MOZ_ASSERT(imageLoader);
+ imageLoader->AddNativeObserver(mListener);
+ // We have a PresContext now, so we need to notify the image content node
+ // that it can register images.
+ imageLoader->FrameCreated(this);
+ } else {
+ if (auto* proxy = StyleContent()->ContentAt(0).GetImage()) {
+ proxy->SyncClone(mListener,
+ mContent->OwnerDoc(),
+ getter_AddRefs(mContentURLRequest));
+ }
}
- imageLoader->AddNativeObserver(mListener);
-
- // We have a PresContext now, so we need to notify the image content node that
- // it can register images.
- imageLoader->FrameCreated(this);
-
// Give image loads associated with an image frame a small priority boost.
if (nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest()) {
uint32_t categoryToBoostPriority = imgIRequest::CATEGORY_FRAME_INIT;
// Increase load priority further if intrinsic size might be important for layout.
if (!HaveSpecifiedSize(StylePosition())) {
categoryToBoostPriority |= imgIRequest::CATEGORY_SIZE_QUERY;
}
@@ -325,17 +343,19 @@ nsImageFrame::UpdateIntrinsicSize(imgICo
return false;
IntrinsicSize oldIntrinsicSize = mIntrinsicSize;
mIntrinsicSize = IntrinsicSize();
// Set intrinsic size to match aImage's reported intrinsic width & height.
nsSize intrinsicSize;
if (NS_SUCCEEDED(aImage->GetIntrinsicSize(&intrinsicSize))) {
- ScaleIntrinsicSizeForDensity(*mContent, intrinsicSize);
+ if (mKind == Kind::ImageElement) {
+ ScaleIntrinsicSizeForDensity(*mContent, intrinsicSize);
+ }
// If the image has no intrinsic width, intrinsicSize.width will be -1, and
// we can leave mIntrinsicSize.width at its default value of eStyleUnit_None.
// Otherwise we use intrinsicSize.width. Height works the same way.
if (intrinsicSize.width != -1)
mIntrinsicSize.width.SetCoordValue(intrinsicSize.width);
if (intrinsicSize.height != -1)
mIntrinsicSize.height.SetCoordValue(intrinsicSize.height);
} else {
@@ -403,18 +423,23 @@ nsImageFrame::GetSourceToDestTransform(n
}
// This function checks whether the given request is the current request for our
// mContent.
bool
nsImageFrame::IsPendingLoad(imgIRequest* aRequest) const
{
// Default to pending load in case of errors
+ if (mKind == Kind::NonGeneratedContentProperty) {
+ MOZ_ASSERT(aRequest == mContentURLRequest);
+ return false;
+ }
+
nsCOMPtr<nsIImageLoadingContent> imageLoader(do_QueryInterface(mContent));
- NS_ASSERTION(imageLoader, "No image loading content?");
+ MOZ_ASSERT(imageLoader);
int32_t requestType = nsIImageLoadingContent::UNKNOWN_REQUEST;
imageLoader->GetRequestType(aRequest, &requestType);
return requestType != nsIImageLoadingContent::CURRENT_REQUEST;
}
nsRect
@@ -553,24 +578,25 @@ nsImageFrame::Notify(imgIRequest* aReque
static bool
SizeIsAvailable(imgIRequest* aRequest)
{
if (!aRequest)
return false;
uint32_t imageStatus = 0;
nsresult rv = aRequest->GetImageStatus(&imageStatus);
-
return NS_SUCCEEDED(rv) && (imageStatus & imgIRequest::STATUS_SIZE_AVAILABLE);
}
nsresult
nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
{
- if (!aImage) return NS_ERROR_INVALID_ARG;
+ if (!aImage) {
+ return NS_ERROR_INVALID_ARG;
+ }
/* Get requested animation policy from the pres context:
* normal = 0
* one frame = 1
* one loop = 2
*/
aImage->SetAnimationMode(PresContext()->ImageAnimationMode());
@@ -816,56 +842,66 @@ nsImageFrame::PredictedDestRect(const ns
StylePosition());
}
void
nsImageFrame::EnsureIntrinsicSizeAndRatio()
{
// If mIntrinsicSize.width and height are 0, then we need to update from the
// image container.
- if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
- mIntrinsicSize.width.GetCoordValue() == 0 &&
- mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
- mIntrinsicSize.height.GetCoordValue() == 0) {
+ if (mIntrinsicSize.width.GetUnit() != eStyleUnit_Coord ||
+ mIntrinsicSize.width.GetCoordValue() != 0 ||
+ mIntrinsicSize.height.GetUnit() != eStyleUnit_Coord ||
+ mIntrinsicSize.height.GetCoordValue() != 0) {
+ return;
+ }
- if (mImage) {
- UpdateIntrinsicSize(mImage);
- UpdateIntrinsicRatio(mImage);
- } else {
- // image request is null or image size not known, probably an
- // invalid image specified
- if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) {
- bool imageInvalid = false;
+ if (mImage) {
+ UpdateIntrinsicSize(mImage);
+ UpdateIntrinsicRatio(mImage);
+ return;
+ }
+
+ // NOTE(emilio, https://github.com/w3c/csswg-drafts/issues/2832): WebKit
+ // and Blink behave differently here for content: url(..), for now adapt to
+ // Blink's behavior.
+ const bool mayDisplayBrokenIcon = IsForNonGeneratedImageElement();
+ if (!mayDisplayBrokenIcon) {
+ return;
+ }
+ // image request is null or image size not known, probably an
+ // invalid image specified
+ bool imageInvalid = false;
- // check for broken images. valid null images (eg. img src="") are
- // not considered broken because they have no image requests
- if (nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest()) {
- uint32_t imageStatus;
- imageInvalid =
- NS_SUCCEEDED(currentRequest->GetImageStatus(&imageStatus)) &&
- (imageStatus & imgIRequest::STATUS_ERROR);
- } else if (nsCOMPtr<nsIImageLoadingContent> loader = do_QueryInterface(mContent)) {
- // check if images are user-disabled (or blocked for other
- // reasons)
- int16_t imageBlockingStatus;
- loader->GetImageBlockingStatus(&imageBlockingStatus);
- imageInvalid = imageBlockingStatus != nsIContentPolicy::ACCEPT;
- }
+ // check for broken images. valid null images (eg. img src="") are
+ // not considered broken because they have no image requests
+ if (nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest()) {
+ uint32_t imageStatus;
+ imageInvalid =
+ NS_SUCCEEDED(currentRequest->GetImageStatus(&imageStatus)) &&
+ (imageStatus & imgIRequest::STATUS_ERROR);
+ } else {
+ MOZ_ASSERT(mKind == Kind::ImageElement);
- // invalid image specified. make the image big enough for the "broken" icon
- if (imageInvalid) {
- nscoord edgeLengthToUse =
- nsPresContext::CSSPixelsToAppUnits(
- ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH)));
- mIntrinsicSize.width.SetCoordValue(edgeLengthToUse);
- mIntrinsicSize.height.SetCoordValue(edgeLengthToUse);
- mIntrinsicRatio.SizeTo(1, 1);
- }
- }
- }
+ nsCOMPtr<nsIImageLoadingContent> loader = do_QueryInterface(mContent);
+ MOZ_ASSERT(loader);
+ // check if images are user-disabled (or blocked for other reasons)
+ int16_t imageBlockingStatus;
+ loader->GetImageBlockingStatus(&imageBlockingStatus);
+ imageInvalid = imageBlockingStatus != nsIContentPolicy::ACCEPT;
+ }
+
+ // invalid image specified. make the image big enough for the "broken" icon
+ if (imageInvalid) {
+ nscoord edgeLengthToUse =
+ nsPresContext::CSSPixelsToAppUnits(
+ ICON_SIZE + (2 * (ICON_PADDING + ALT_BORDER_WIDTH)));
+ mIntrinsicSize.width.SetCoordValue(edgeLengthToUse);
+ mIntrinsicSize.height.SetCoordValue(edgeLengthToUse);
+ mIntrinsicRatio.SizeTo(1, 1);
}
}
/* virtual */
LogicalSize
nsImageFrame::ComputeSize(gfxContext *aRenderingContext,
WritingMode aWM,
const LogicalSize& aCBSize,
@@ -1456,24 +1492,21 @@ nsImageFrame::DisplayAltFeedback(gfxCont
inner.x += paddedIconSize;
}
inner.width -= paddedIconSize;
}
}
// If there's still room, display the alt-text
if (!inner.IsEmpty()) {
- nsIContent* content = GetContent();
- if (content) {
- nsAutoString altText;
- nsCSSFrameConstructor::GetAlternateTextFor(content->AsElement(),
- content->NodeInfo()->NameAtom(),
- altText);
- DisplayAltText(PresContext(), aRenderingContext, altText, inner);
- }
+ nsAutoString altText;
+ nsCSSFrameConstructor::GetAlternateTextFor(mContent->AsElement(),
+ mContent->NodeInfo()->NameAtom(),
+ altText);
+ DisplayAltText(PresContext(), aRenderingContext, altText, inner);
}
aRenderingContext.Restore();
return result;
}
#ifdef DEBUG
@@ -1775,24 +1808,27 @@ nsImageFrame::PaintImage(gfxContext& aRe
}
return result;
}
already_AddRefed<imgIRequest>
nsImageFrame::GetCurrentRequest() const
{
+ if (mKind == Kind::NonGeneratedContentProperty) {
+ return do_AddRef(mContentURLRequest);
+ }
+
+ MOZ_ASSERT(!mContentURLRequest);
+
nsCOMPtr<imgIRequest> request;
-
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
MOZ_ASSERT(imageLoader);
-
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(request));
-
return request.forget();
}
void
nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists)
{
if (!IsVisibleForPainting(aBuilder))
@@ -2113,25 +2149,21 @@ nsImageFrame::AttributeChanged(int32_t a
return NS_OK;
}
void
nsImageFrame::OnVisibilityChange(Visibility aNewVisibility,
const Maybe<OnNonvisible>& aNonvisibleAction)
{
- nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
- if (!imageLoader) {
- MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
- nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
- return;
+ if (mKind == Kind::ImageElement) {
+ nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
+ imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
}
- imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
-
if (aNewVisibility == Visibility::APPROXIMATELY_VISIBLE) {
MaybeDecodeForPredictedSize();
}
nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
}
#ifdef DEBUG_FRAME_DUMP
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -175,23 +175,49 @@ public:
InlineMinISizeData *aData) override;
void DisconnectMap();
// nsIReflowCallback
virtual bool ReflowFinished() override;
virtual void ReflowCallbackCanceled() override;
+ // The kind of image frame we are.
+ enum class Kind : uint8_t
+ {
+ // For an nsImageLoadingContent, including generated ::before and ::after
+ // content, which are an nsGenConImageContent.
+ ImageElement,
+ // For css 'content: url(..)' on other elements.
+ NonGeneratedContentProperty,
+ };
+
+ // Whether this frame is for a non-generated image element, that is, one that
+ // isn't a ::before / ::after.
+ bool IsForNonGeneratedImageElement() const
+ {
+ return mKind == Kind::ImageElement &&
+ !HasAnyStateBits(NS_FRAME_GENERATED_CONTENT);
+ }
+
private:
friend nsIFrame* NS_NewImageFrame(nsIPresShell*, ComputedStyle*);
- explicit nsImageFrame(ComputedStyle* aStyle)
- : nsImageFrame(aStyle, kClassID) {}
+ friend nsIFrame* NS_NewImageFrameForContentProperty(nsIPresShell*, ComputedStyle*);
+
+ nsImageFrame(ComputedStyle* aStyle, Kind aKind)
+ : nsImageFrame(aStyle, kClassID, aKind)
+ { }
+
+ nsImageFrame(ComputedStyle*, ClassID, Kind);
protected:
- nsImageFrame(ComputedStyle* aStyle, ClassID aID);
+ nsImageFrame(ComputedStyle* aStyle, ClassID aID)
+ : nsImageFrame(aStyle, aID, Kind::ImageElement)
+ { }
+
virtual ~nsImageFrame();
void EnsureIntrinsicSizeAndRatio();
bool GotInitialReflow() const
{
return !HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
}
@@ -333,22 +359,26 @@ private:
*/
void InvalidateSelf(const nsIntRect* aLayerInvalidRect,
const nsRect* aFrameInvalidRect);
RefPtr<nsImageMap> mImageMap;
RefPtr<nsImageListener> mListener;
+ // An image request created for content: url(..).
+ RefPtr<imgRequestProxy> mContentURLRequest;
+
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<imgIContainer> mPrevImage;
nsSize mComputedSize;
mozilla::IntrinsicSize mIntrinsicSize;
nsSize mIntrinsicRatio;
+ const Kind mKind;
bool mDisplayingIcon;
bool mFirstFrameComplete;
bool mReflowCallbackPosted;
bool mForceSyncDecoding;
static nsIIOService* sIOService;
/* loading / broken image icon support */
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -109430,16 +109430,52 @@
[
"/css/css-content/attr-case-insensitive-ref.html",
"=="
]
],
{}
]
],
+ "css/css-content/element-replacement-alt.html": [
+ [
+ "/css/css-content/element-replacement-alt.html",
+ [
+ [
+ "/css/css-content/element-replacement-alt-ref.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "css/css-content/element-replacement-display-contents.html": [
+ [
+ "/css/css-content/element-replacement-display-contents.html",
+ [
+ [
+ "/css/css-content/resources/blank.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
+ "css/css-content/element-replacement-display-none.html": [
+ [
+ "/css/css-content/element-replacement-display-none.html",
+ [
+ [
+ "/css/css-content/resources/blank.html",
+ "=="
+ ]
+ ],
+ {}
+ ]
+ ],
"css/css-content/element-replacement.html": [
[
"/css/css-content/element-replacement.html",
[
[
"/css/css-content/element-replacement-ref.html",
"=="
]
@@ -240839,21 +240875,31 @@
{}
]
],
"css/css-content/attr-case-insensitive-ref.html": [
[
{}
]
],
+ "css/css-content/element-replacement-alt-ref.html": [
+ [
+ {}
+ ]
+ ],
"css/css-content/element-replacement-ref.html": [
[
{}
]
],
+ "css/css-content/resources/blank.html": [
+ [
+ {}
+ ]
+ ],
"css/css-content/resources/rect.svg": [
[
{}
]
],
"css/css-counter-styles/OWNERS": [
[
{}
@@ -502642,24 +502688,44 @@
"css/css-content/attr-case-insensitive-ref.html": [
"30577fc39afb6ac028e25be11f363e060c0850b2",
"support"
],
"css/css-content/attr-case-insensitive.html": [
"6b6cf2c15295940fb8831d17209635dc4e31cd78",
"reftest"
],
+ "css/css-content/element-replacement-alt-ref.html": [
+ "6c67290991bc0ca57223e65a995054bae04bca0a",
+ "support"
+ ],
+ "css/css-content/element-replacement-alt.html": [
+ "383ba1ffc142ae6d783cc9300b296b83b4b2521f",
+ "reftest"
+ ],
+ "css/css-content/element-replacement-display-contents.html": [
+ "980d17c7c90c1de3f703423bcf41d0f14d25f4c1",
+ "reftest"
+ ],
+ "css/css-content/element-replacement-display-none.html": [
+ "b30f852673badcc7f9cb8a39cc4a12452d886d6f",
+ "reftest"
+ ],
"css/css-content/element-replacement-ref.html": [
"f1ad3fca133b1b671e45ae1307fbe9454c40e3ec",
"support"
],
"css/css-content/element-replacement.html": [
"f491ddf2b3062ea2f9b616c968c88b9cc95f22eb",
"reftest"
],
+ "css/css-content/resources/blank.html": [
+ "d96d45f3a57b58460787fcde5fd15ccb324b123c",
+ "support"
+ ],
"css/css-content/resources/rect.svg": [
"e0c37ea653aee58f962133219edc4484a734c6e0",
"support"
],
"css/css-counter-styles/OWNERS": [
"820cad495f069d1badb3a727b9a2514269c6008e",
"support"
],
@@ -549607,17 +549673,17 @@
"cd3f0233cc0eaf9295e602ca25aef87fb68df851",
"support"
],
"css/mediaqueries/support/min-width-tables-001-iframe.html": [
"29e7fb34c94e2e8411514d1e71d09aca2ddb642e",
"support"
],
"css/mediaqueries/test_media_queries.html": [
- "cff3585932589f611a7101329d3b5b6ca27820aa",
+ "a7d78b13e119f8cd1ffa8812a9af67e59280084d",
"testharness"
],
"css/mediaqueries/viewport-script-dynamic-ref.html": [
"7d55c513e2de39c9b362fc864233a3008ca6ced2",
"support"
],
"css/mediaqueries/viewport-script-dynamic.html": [
"1c2ba1a9116942599804ed29553e85628afadb04",
@@ -561211,17 +561277,17 @@
"a5c1df9b9c744ec4a61e9e390ae81fab25573562",
"support"
],
"docs/assets/praccepteddelete.png": [
"6adf9e6d9aad3f65fd25c7e5cfc2d3f6395beeab",
"support"
],
"docs/assets/pullrequestbtn.png": [
- "85e1015ecff6ee444168858cea8cd41804696905",
+ "41213000ac1fb6ab53c6a1199744ecde452eef55",
"support"
],
"docs/assets/reftest_graph_example.svg": [
"eae9457e309f47c0236944ab2d778f2fbc32f158",
"support"
],
"docs/index.html": [
"12c7175a4d6c486ca9ebea4c6a43d2aec9845d8b",
@@ -618359,17 +618425,17 @@
"f3e48d8ddd42f1eecb36af2a8e1cfade6d0a02d4",
"testharness"
],
"web-animations/animation-model/animation-types/interpolation-per-property.html": [
"ab09cd8b77d05a1036f9976c3f0e92a6d9e183f3",
"testharness"
],
"web-animations/animation-model/animation-types/property-list.js": [
- "9416f470f1ac1d320bb4d46461938e85946439e2",
+ "5a818163c3ddcb6e0901b4f0086d555e9d440e27",
"support"
],
"web-animations/animation-model/animation-types/property-types.js": [
"ecfe1d54d687bc6d0541b4a8c5ca9cf82c4d129e",
"support"
],
"web-animations/animation-model/animation-types/visibility.html": [
"da3370704ca9e83a1171a64320a240e3145fab2c",
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-content/element-replacement.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[element-replacement.html]
- expected: FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-content/element-replacement-alt-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<div style="content: url(broken);"></div>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-content/element-replacement-alt.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<title>The content CSS property with a broken image doesn't pull the alt attribute from that element</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="match" href="element-replacement-alt-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-content-3/#content-property">
+<div style="content: url(broken);" alt="Alt text">FAIL</div>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-content/element-replacement-display-contents.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>The content CSS property doesn't override display: contents</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="match" href="resources/blank.html">
+<link rel="help" href="https://drafts.csswg.org/css-content-3/#content-property">
+<style>
+ div {
+ display: contents;
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==);
+ }
+</style>
+<div></div>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-content/element-replacement-display-none.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>The content CSS property doesn't override display: none</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="match" href="resources/blank.html">
+<link rel="help" href="https://drafts.csswg.org/css-content-3/#content-property">
+<style>
+ div {
+ display: none;
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==);
+ }
+</style>
+<div>FAIL</div>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-content/resources/blank.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<!-- Intentionally blank -->