Bug 1850238 - Make BROKEN state non-intrinsic. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D187108
This commit is contained in:
Emilio Cobos Álvarez
2023-08-31 07:46:24 +00:00
parent a14c4a020b
commit 01b6773528
22 changed files with 80 additions and 184 deletions

View File

@@ -74,6 +74,7 @@ class nsFocusManager;
class nsGenericHTMLFormControlElementWithState; class nsGenericHTMLFormControlElementWithState;
class nsGlobalWindowInner; class nsGlobalWindowInner;
class nsGlobalWindowOuter; class nsGlobalWindowOuter;
class nsImageLoadingContent;
class nsIAutoCompletePopup; class nsIAutoCompletePopup;
class nsIBrowser; class nsIBrowser;
class nsIDOMXULButtonElement; class nsIDOMXULButtonElement;
@@ -93,6 +94,7 @@ class nsIPrincipal;
class nsIScreen; class nsIScreen;
class nsIScrollableFrame; class nsIScrollableFrame;
class nsIURI; class nsIURI;
class nsObjectLoadingContent;
class nsPresContext; class nsPresContext;
class nsWindowSizes; class nsWindowSizes;
struct JSContext; struct JSContext;
@@ -758,6 +760,8 @@ class Element : public FragmentOrElement {
friend class ::nsGlobalWindowInner; friend class ::nsGlobalWindowInner;
friend class ::nsGlobalWindowOuter; friend class ::nsGlobalWindowOuter;
friend class ::nsFocusManager; friend class ::nsFocusManager;
friend class ::nsImageLoadingContent;
friend class ::nsObjectLoadingContent;
friend class mozilla::dom::HTMLFormElement; friend class mozilla::dom::HTMLFormElement;
// Allow CusomtElementRegistry to call AddStates. // Allow CusomtElementRegistry to call AddStates.

View File

@@ -32,13 +32,6 @@ class GeneratedImageContent final : public nsGenericHTMLElement {
"Someone messed up our nodeinfo"); "Someone messed up our nodeinfo");
} }
ElementState IntrinsicState() const override {
ElementState state = nsGenericHTMLElement::IntrinsicState();
if (mBroken) {
state |= ElementState::BROKEN;
}
return state;
}
nsresult Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const final; nsresult Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const final;
nsresult CopyInnerTo(GeneratedImageContent* aDest) { nsresult CopyInnerTo(GeneratedImageContent* aDest) {
@@ -56,8 +49,7 @@ class GeneratedImageContent final : public nsGenericHTMLElement {
// Notify this image failed to load. // Notify this image failed to load.
void NotifyLoadFailed() { void NotifyLoadFailed() {
mBroken = true; SetStates(ElementState::BROKEN, true);
UpdateState(true);
} }
protected: protected:
@@ -66,7 +58,6 @@ class GeneratedImageContent final : public nsGenericHTMLElement {
private: private:
virtual ~GeneratedImageContent() = default; virtual ~GeneratedImageContent() = default;
uint32_t mIndex = 0; uint32_t mIndex = 0;
bool mBroken = false;
}; };
} // namespace mozilla::dom } // namespace mozilla::dom

View File

@@ -103,8 +103,6 @@ nsImageLoadingContent::nsImageLoadingContent()
mRequestGeneration(0), mRequestGeneration(0),
mLoadingEnabled(true), mLoadingEnabled(true),
mLoading(false), mLoading(false),
// mBroken starts out true, since an image without a URI is broken....
mBroken(true),
mNewRequestsWillNeedAnimationReset(false), mNewRequestsWillNeedAnimationReset(false),
mUseUrgentStartForChannel(false), mUseUrgentStartForChannel(false),
mLazyLoading(false), mLazyLoading(false),
@@ -1346,14 +1344,6 @@ CSSIntSize nsImageLoadingContent::GetWidthHeightForImage() {
return size; return size;
} }
ElementState nsImageLoadingContent::ImageState() const {
ElementState states;
if (mBroken) {
states |= ElementState::BROKEN;
}
return states;
}
void nsImageLoadingContent::UpdateImageState(bool aNotify) { void nsImageLoadingContent::UpdateImageState(bool aNotify) {
if (mStateChangerDepth > 0) { if (mStateChangerDepth > 0) {
// Ignore this call; we'll update our state when the outermost state changer // Ignore this call; we'll update our state when the outermost state changer
@@ -1365,9 +1355,12 @@ void nsImageLoadingContent::UpdateImageState(bool aNotify) {
return; return;
} }
nsIContent* thisContent = AsContent(); Element* thisElement = AsContent()->AsElement();
mLoading = mBroken = false; mLoading = false;
Element::AutoStateChangeNotifier notifier(*thisElement, aNotify);
thisElement->RemoveStatesSilently(ElementState::BROKEN);
// If we were blocked, we're broken, so are we if we don't have an image // If we were blocked, we're broken, so are we if we don't have an image
// request at all or the image has errored. // request at all or the image has errored.
@@ -1375,21 +1368,19 @@ void nsImageLoadingContent::UpdateImageState(bool aNotify) {
if (!mLazyLoading) { if (!mLazyLoading) {
// In case of non-lazy loading, no current request means error, since we // In case of non-lazy loading, no current request means error, since we
// weren't disabled or suppressed // weren't disabled or suppressed
mBroken = true; thisElement->AddStatesSilently(ElementState::BROKEN);
RejectDecodePromises(NS_ERROR_DOM_IMAGE_BROKEN); RejectDecodePromises(NS_ERROR_DOM_IMAGE_BROKEN);
} }
} else { } else {
uint32_t currentLoadStatus; uint32_t currentLoadStatus;
nsresult rv = mCurrentRequest->GetImageStatus(&currentLoadStatus); nsresult rv = mCurrentRequest->GetImageStatus(&currentLoadStatus);
if (NS_FAILED(rv) || (currentLoadStatus & imgIRequest::STATUS_ERROR)) { if (NS_FAILED(rv) || (currentLoadStatus & imgIRequest::STATUS_ERROR)) {
mBroken = true; thisElement->AddStatesSilently(ElementState::BROKEN);
RejectDecodePromises(NS_ERROR_DOM_IMAGE_BROKEN); RejectDecodePromises(NS_ERROR_DOM_IMAGE_BROKEN);
} else if (!(currentLoadStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) { } else if (!(currentLoadStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
mLoading = true; mLoading = true;
} }
} }
thisContent->AsElement()->UpdateState(aNotify);
} }
void nsImageLoadingContent::CancelImageRequests(bool aNotify) { void nsImageLoadingContent::CancelImageRequests(bool aNotify) {

View File

@@ -560,7 +560,6 @@ class nsImageLoadingContent : public nsIImageLoadingContent {
* document of a state change. These are maintained by UpdateImageState. * document of a state change. These are maintained by UpdateImageState.
*/ */
bool mLoading : 1; bool mLoading : 1;
bool mBroken : 1;
/** /**
* A hack to get animations to reset, see bug 594771. On requests * A hack to get animations to reset, see bug 594771. On requests

View File

@@ -676,35 +676,6 @@ nsObjectLoadingContent::AsyncOnChannelRedirect(
return NS_OK; return NS_OK;
} }
// <public>
ElementState nsObjectLoadingContent::ObjectState() const {
switch (mType) {
case eType_Loading:
return {};
case eType_Image:
return ImageState();
case eType_FakePlugin:
case eType_Document: {
// These are OK. If documents start to load successfully, they display
// something, and are thus not broken in this sense. The same goes for
// plugins.
ElementState states = ElementState();
if (mLoadingSyntheticDocument) {
states |= ImageState();
}
return states;
}
case eType_Fallback:
// This may end up handled as TYPE_NULL or as a "special" type, as
// chosen by the layout.use-plugin-fallback pref.
return ElementState();
case eType_Null:
return ElementState::BROKEN;
}
MOZ_ASSERT_UNREACHABLE("unknown type?");
return {};
}
void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI, void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI,
nsIURI* aBaseURI, nsIURI* aBaseURI,
nsIURI** aRewrittenURI) { nsIURI** aRewrittenURI) {
@@ -1300,7 +1271,7 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
ObjectType oldType = mType; ObjectType oldType = mType;
mType = eType_Fallback; mType = eType_Fallback;
ConfigureFallback(); ConfigureFallback();
NotifyStateChanged(oldType, ObjectState(), true, false); NotifyStateChanged(oldType, true);
return NS_OK; return NS_OK;
} }
@@ -1333,7 +1304,6 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
} }
// Save these for NotifyStateChanged(); // Save these for NotifyStateChanged();
ElementState oldState = ObjectState();
ObjectType oldType = mType; ObjectType oldType = mType;
ParameterUpdateFlags stateChange = UpdateObjectParameters(); ParameterUpdateFlags stateChange = UpdateObjectParameters();
@@ -1586,7 +1556,7 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
} }
// Notify of our final state // Notify of our final state
NotifyStateChanged(oldType, oldState, aNotify, false); NotifyStateChanged(oldType, aNotify);
NS_ENSURE_TRUE(mIsLoading, NS_OK); NS_ENSURE_TRUE(mIsLoading, NS_OK);
// //
@@ -1625,7 +1595,7 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
NS_ENSURE_TRUE(mIsLoading, NS_OK); NS_ENSURE_TRUE(mIsLoading, NS_OK);
CloseChannel(); CloseChannel();
ConfigureFallback(); ConfigureFallback();
NotifyStateChanged(oldType, ObjectState(), true, false); NotifyStateChanged(oldType, true);
} }
return NS_OK; return NS_OK;
@@ -1883,26 +1853,17 @@ void nsObjectLoadingContent::UnloadObject(bool aResetState) {
} }
void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType, void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
ElementState aOldState, bool aNotify) {
bool aNotify, LOG(("OBJLC [%p]: NotifyStateChanged: (%u) -> (%u) (notify %i)", this,
bool aForceRestyle) { aOldType, mType, aNotify));
LOG(("OBJLC [%p]: NotifyStateChanged: (%u, %" PRIx64 ") -> (%u, %" PRIx64 ")"
" (notify %i)",
this, aOldType, aOldState.GetInternalValue(), mType,
ObjectState().GetInternalValue(), aNotify));
nsCOMPtr<dom::Element> thisEl = AsContent()->AsElement(); dom::Element* thisEl = AsContent()->AsElement();
MOZ_ASSERT(thisEl, "must be an element"); if (mType != eType_Image) {
// Non-images are always not broken.
thisEl->RemoveStates(ElementState::BROKEN, aNotify);
}
// XXX(johns): A good bit of the code below replicates UpdateState(true) if (mType == aOldType) {
// Unfortunately, we do some state changes without notifying
// (e.g. in Fallback when canceling image requests), so we have to
// manually notify object state changes.
thisEl->UpdateState(aForceRestyle);
if (!aNotify) {
// We're done here
return; return;
} }
@@ -1911,21 +1872,13 @@ void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
return; // Nothing to do return; // Nothing to do
} }
const ElementState newState = ObjectState(); PresShell* presShell = doc->GetPresShell();
if (newState == aOldState && mType == aOldType) {
return; // Also done.
}
RefPtr<PresShell> presShell = doc->GetPresShell();
// If there is no PresShell or it hasn't been initialized there isn't much to // If there is no PresShell or it hasn't been initialized there isn't much to
// do. // do.
if (!presShell || !presShell->DidInitialize()) { if (!presShell || !presShell->DidInitialize()) {
return; return;
} }
if (presShell && (aOldType != mType)) {
presShell->PostRecreateFramesFor(thisEl); presShell->PostRecreateFramesFor(thisEl);
}
} }
nsObjectLoadingContent::ObjectType nsObjectLoadingContent::GetTypeOfContent( nsObjectLoadingContent::ObjectType nsObjectLoadingContent::GetTypeOfContent(
@@ -2200,7 +2153,6 @@ void nsObjectLoadingContent::SubdocumentIntrinsicSizeOrRatioChanged(
} }
void nsObjectLoadingContent::SubdocumentImageLoadComplete(nsresult aResult) { void nsObjectLoadingContent::SubdocumentImageLoadComplete(nsresult aResult) {
ElementState oldState = ObjectState();
ObjectType oldType = mType; ObjectType oldType = mType;
mLoadingSyntheticDocument = false; mLoadingSyntheticDocument = false;
@@ -2208,15 +2160,14 @@ void nsObjectLoadingContent::SubdocumentImageLoadComplete(nsresult aResult) {
UnloadObject(); UnloadObject();
mType = eType_Fallback; mType = eType_Fallback;
ConfigureFallback(); ConfigureFallback();
NotifyStateChanged(oldType, oldState, true, false); NotifyStateChanged(oldType, true);
return; return;
} }
// (mChannelLoaded && mChannel) indicates this is a good state, not any sort // (mChannelLoaded && mChannel) indicates this is a good state, not any sort
// of failures. // of failures.
MOZ_DIAGNOSTIC_ASSERT_IF(mChannelLoaded && mChannel, mType == eType_Document); MOZ_DIAGNOSTIC_ASSERT_IF(mChannelLoaded && mChannel, mType == eType_Document);
NotifyStateChanged(oldType, true);
NotifyStateChanged(oldType, oldState, true, true);
} }
void nsObjectLoadingContent::MaybeStoreCrossOriginFeaturePolicy() { void nsObjectLoadingContent::MaybeStoreCrossOriginFeaturePolicy() {

View File

@@ -78,12 +78,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent,
NS_DECL_NSIOBJECTLOADINGCONTENT NS_DECL_NSIOBJECTLOADINGCONTENT
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
/**
* Object state. This is a bitmask of NS_EVENT_STATEs epresenting the
* current state of the object.
*/
mozilla::dom::ElementState ObjectState() const;
ObjectType Type() const { return mType; } ObjectType Type() const { return mType; }
void SetIsNetworkCreated(bool aNetworkCreated) { void SetIsNetworkCreated(bool aNetworkCreated) {
@@ -429,9 +423,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent,
* *
* @param aNotify if false, only need to update the state of our element. * @param aNotify if false, only need to update the state of our element.
*/ */
void NotifyStateChanged(ObjectType aOldType, void NotifyStateChanged(ObjectType aOldType, bool aNotify);
mozilla::dom::ElementState aOldState, bool aNotify,
bool aForceRestyle);
/** /**
* Returns a ObjectType value corresponding to the type of content we would * Returns a ObjectType value corresponding to the type of content we would

View File

@@ -189,6 +189,7 @@ bitflags! {
Self::OUTOFRANGE.bits | Self::OUTOFRANGE.bits |
Self::VISITED.bits | Self::VISITED.bits |
Self::UNVISITED.bits | Self::UNVISITED.bits |
Self::BROKEN.bits |
Self::VALIDITY_STATES.bits; Self::VALIDITY_STATES.bits;
const INTRINSIC_STATES = !Self::EXTERNALLY_MANAGED_STATES.bits; const INTRINSIC_STATES = !Self::EXTERNALLY_MANAGED_STATES.bits;

View File

@@ -233,10 +233,6 @@ void HTMLEmbedElement::StartObjectLoad(bool aNotify, bool aForceLoad) {
SetIsNetworkCreated(false); SetIsNetworkCreated(false);
} }
ElementState HTMLEmbedElement::IntrinsicState() const {
return nsGenericHTMLElement::IntrinsicState() | ObjectState();
}
uint32_t HTMLEmbedElement::GetCapabilities() const { uint32_t HTMLEmbedElement::GetCapabilities() const {
return eSupportPlugins | eAllowPluginSkipChannel | eSupportImages | return eSupportPlugins | eAllowPluginSkipChannel | eSupportImages |
eSupportDocuments; eSupportDocuments;

View File

@@ -49,7 +49,6 @@ class HTMLEmbedElement final : public nsGenericHTMLElement,
nsAttrValue& aResult) override; nsAttrValue& aResult) override;
nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override; nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
ElementState IntrinsicState() const override;
void DestroyContent() override; void DestroyContent() override;
// nsObjectLoadingContent // nsObjectLoadingContent

View File

@@ -649,11 +649,6 @@ void HTMLImageElement::MaybeLoadImage(bool aAlwaysForceLoad) {
} }
} }
ElementState HTMLImageElement::IntrinsicState() const {
return nsGenericHTMLElement::IntrinsicState() |
nsImageLoadingContent::ImageState();
}
void HTMLImageElement::NodeInfoChanged(Document* aOldDoc) { void HTMLImageElement::NodeInfoChanged(Document* aOldDoc) {
nsGenericHTMLElement::NodeInfoChanged(aOldDoc); nsGenericHTMLElement::NodeInfoChanged(aOldDoc);

View File

@@ -76,7 +76,6 @@ class HTMLImageElement final : public nsGenericHTMLElement,
nsresult BindToTree(BindContext&, nsINode& aParent) override; nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(bool aNullParent) override; void UnbindFromTree(bool aNullParent) override;
ElementState IntrinsicState() const override;
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
void NodeInfoChanged(Document* aOldDoc) override; void NodeInfoChanged(Document* aOldDoc) override;

View File

@@ -4528,11 +4528,14 @@ void HTMLInputElement::HandleTypeChange(FormControlType aNewType,
// We're no longer an image input. Cancel our image requests, if we have // We're no longer an image input. Cancel our image requests, if we have
// any. // any.
CancelImageRequests(aNotify); CancelImageRequests(aNotify);
} else if (aNotify) { RemoveStates(ElementState::BROKEN, aNotify);
} else {
// We just got switched to be an image input; we should see whether we // We just got switched to be an image input; we should see whether we
// have an image to load; // have an image to load;
bool hasSrc = false;
if (aNotify) {
nsAutoString src; nsAutoString src;
if (GetAttr(nsGkAtoms::src, src)) { if ((hasSrc = GetAttr(nsGkAtoms::src, src))) {
// Mark channel as urgent-start before load image if the image load is // Mark channel as urgent-start before load image if the image load is
// initiated by a user interaction. // initiated by a user interaction.
mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput();
@@ -4540,6 +4543,12 @@ void HTMLInputElement::HandleTypeChange(FormControlType aNewType,
LoadImage(src, false, aNotify, eImageLoadType_Normal, LoadImage(src, false, aNotify, eImageLoadType_Normal,
mSrcTriggeringPrincipal); mSrcTriggeringPrincipal);
} }
} else {
hasSrc = HasAttr(nsGkAtoms::src);
}
if (!hasSrc) {
AddStates(ElementState::BROKEN, aNotify);
}
} }
// We should update our mapped attribute mapping function. // We should update our mapped attribute mapping function.
if (mAttrs.HasAttrs() && !mAttrs.IsPendingMappedAttributeEvaluation()) { if (mAttrs.HasAttrs() && !mAttrs.IsPendingMappedAttributeEvaluation()) {
@@ -6059,17 +6068,6 @@ void HTMLInputElement::DestroyContent() {
TextControlElement::DestroyContent(); TextControlElement::DestroyContent();
} }
ElementState HTMLInputElement::IntrinsicState() const {
// If you add states here, and they're type-dependent, you need to add them to
// HandleTypeChange.
ElementState state =
nsGenericHTMLFormControlElementWithState::IntrinsicState();
if (mType == FormControlType::InputImage) {
state |= nsImageLoadingContent::ImageState();
}
return state;
}
void HTMLInputElement::UpdateValidityElementStates(bool aNotify) { void HTMLInputElement::UpdateValidityElementStates(bool aNotify) {
AutoStateChangeNotifier notifier(*this, aNotify); AutoStateChangeNotifier notifier(*this, aNotify);
RemoveStatesSilently(ElementState::VALIDITY_STATES); RemoveStatesSilently(ElementState::VALIDITY_STATES);

View File

@@ -211,8 +211,6 @@ class HTMLInputElement final : public TextControlElement,
void DestroyContent() override; void DestroyContent() override;
ElementState IntrinsicState() const override;
void SetLastValueChangeWasInteractive(bool); void SetLastValueChangeWasInteractive(bool);
// TextControlElement // TextControlElement

View File

@@ -61,11 +61,6 @@ void HTMLMeterElement::UpdateOptimumState(bool aNotify) {
AddStatesSilently(GetOptimumState()); AddStatesSilently(GetOptimumState());
} }
/*
* Value getters :
* const getters used by XPCOM methods and by IntrinsicState
*/
double HTMLMeterElement::Min() const { double HTMLMeterElement::Min() const {
/** /**
* If the attribute min is defined, the minimum is this value. * If the attribute min is defined, the minimum is this value.

View File

@@ -266,10 +266,6 @@ void HTMLObjectElement::StartObjectLoad(bool aNotify, bool aForce) {
SetIsNetworkCreated(false); SetIsNetworkCreated(false);
} }
ElementState HTMLObjectElement::IntrinsicState() const {
return nsGenericHTMLFormControlElement::IntrinsicState() | ObjectState();
}
uint32_t HTMLObjectElement::GetCapabilities() const { uint32_t HTMLObjectElement::GetCapabilities() const {
return nsObjectLoadingContent::GetCapabilities() | eFallbackIfClassIDPresent; return nsObjectLoadingContent::GetCapabilities() | eFallbackIfClassIDPresent;
} }

View File

@@ -58,7 +58,6 @@ class HTMLObjectElement final : public nsGenericHTMLFormControlElement,
nsAttrValue& aResult) override; nsAttrValue& aResult) override;
nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override; nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
ElementState IntrinsicState() const override;
void DestroyContent() override; void DestroyContent() override;
// nsObjectLoadingContent // nsObjectLoadingContent

View File

@@ -175,11 +175,6 @@ void SVGFEImageElement::UnbindFromTree(bool aNullParent) {
SVGFEImageElementBase::UnbindFromTree(aNullParent); SVGFEImageElementBase::UnbindFromTree(aNullParent);
} }
ElementState SVGFEImageElement::IntrinsicState() const {
return SVGFEImageElementBase::IntrinsicState() |
nsImageLoadingContent::ImageState();
}
void SVGFEImageElement::DestroyContent() { void SVGFEImageElement::DestroyContent() {
nsImageLoadingContent::Destroy(); nsImageLoadingContent::Destroy();
SVGFEImageElementBase::DestroyContent(); SVGFEImageElementBase::DestroyContent();

View File

@@ -71,7 +71,6 @@ class SVGFEImageElement final : public SVGFEImageElementBase,
nsIPrincipal* aSubjectPrincipal, bool aNotify) override; nsIPrincipal* aSubjectPrincipal, bool aNotify) override;
nsresult BindToTree(BindContext&, nsINode& aParent) override; nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(bool aNullParent) override; void UnbindFromTree(bool aNullParent) override;
ElementState IntrinsicState() const override;
void DestroyContent() override; void DestroyContent() override;
NS_DECL_IMGINOTIFICATIONOBSERVER NS_DECL_IMGINOTIFICATIONOBSERVER

View File

@@ -265,11 +265,6 @@ void SVGImageElement::UnbindFromTree(bool aNullParent) {
SVGImageElementBase::UnbindFromTree(aNullParent); SVGImageElementBase::UnbindFromTree(aNullParent);
} }
ElementState SVGImageElement::IntrinsicState() const {
return SVGImageElementBase::IntrinsicState() |
nsImageLoadingContent::ImageState();
}
void SVGImageElement::DestroyContent() { void SVGImageElement::DestroyContent() {
nsImageLoadingContent::Destroy(); nsImageLoadingContent::Destroy();
SVGImageElementBase::DestroyContent(); SVGImageElementBase::DestroyContent();

View File

@@ -62,8 +62,6 @@ class SVGImageElement final : public SVGImageElementBase,
nsresult BindToTree(BindContext&, nsINode& aParent) override; nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(bool aNullParent) override; void UnbindFromTree(bool aNullParent) override;
ElementState IntrinsicState() const override;
void DestroyContent() override; void DestroyContent() override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* name) const override; NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* name) const override;

View File

@@ -35,6 +35,7 @@
#include "mozilla/dom/DocumentInlines.h" #include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/ElementInlines.h" #include "mozilla/dom/ElementInlines.h"
#include "mozilla/dom/HTMLBodyElement.h" #include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "ScrollSnap.h" #include "ScrollSnap.h"
#include "nsAnimationManager.h" #include "nsAnimationManager.h"
@@ -505,31 +506,36 @@ static bool StateChangeMayAffectFrame(const Element& aElement,
const nsIFrame& aFrame, const nsIFrame& aFrame,
ElementState aStates) { ElementState aStates) {
const bool brokenChanged = aStates.HasState(ElementState::BROKEN); const bool brokenChanged = aStates.HasState(ElementState::BROKEN);
if (aFrame.IsGeneratedContentFrame()) {
if (aElement.IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage)) {
return brokenChanged;
}
// If it's other generated content, ignore LOADING/etc state changes on it.
return false;
}
if (!brokenChanged) { if (!brokenChanged) {
return false; return false;
} }
if (aFrame.IsGeneratedContentFrame()) {
// If it's other generated content, ignore state changes on it.
return aElement.IsHTMLElement(nsGkAtoms::mozgeneratedcontentimage);
}
if (aElement.IsAnyOfHTMLElements(nsGkAtoms::object, nsGkAtoms::embed)) {
// Broken affects object fallback behavior.
return true;
}
const bool mightChange = [&] {
if (aElement.IsHTMLElement(nsGkAtoms::img)) { if (aElement.IsHTMLElement(nsGkAtoms::img)) {
return true;
}
const auto* input = HTMLInputElement::FromNode(aElement);
return input && input->ControlType() == FormControlType::InputImage;
}();
if (!mightChange) {
return false;
}
const bool needsImageFrame = const bool needsImageFrame =
nsImageFrame::ImageFrameTypeFor(aElement, *aFrame.Style()) != nsImageFrame::ImageFrameTypeFor(aElement, *aFrame.Style()) !=
nsImageFrame::ImageFrameType::None; nsImageFrame::ImageFrameType::None;
return needsImageFrame != aFrame.IsImageFrameOrSubclass(); return needsImageFrame != aFrame.IsImageFrameOrSubclass();
}
if (aElement.IsSVGElement(nsGkAtoms::image)) {
// <image> gets an SVGImageFrame all the time.
return false;
}
return brokenChanged;
} }
/** /**

View File

@@ -3642,20 +3642,19 @@ static nsIFrame* NS_NewSubDocumentOrImageFrame(mozilla::PresShell* aPresShell,
const nsCSSFrameConstructor::FrameConstructionData* const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindObjectData(const Element& aElement, nsCSSFrameConstructor::FindObjectData(const Element& aElement,
ComputedStyle& aStyle) { ComputedStyle& aStyle) {
// GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
// cases when the object is broken/suppressed/etc (e.g. a broken image), but
// we want to treat those cases as TYPE_NULL
uint32_t type; uint32_t type;
if (aElement.State().HasState(ElementState::BROKEN)) {
type = nsIObjectLoadingContent::TYPE_NULL;
} else {
nsCOMPtr<nsIObjectLoadingContent> objContent = nsCOMPtr<nsIObjectLoadingContent> objContent =
do_QueryInterface(const_cast<Element*>(&aElement)); do_QueryInterface(const_cast<Element*>(&aElement));
NS_ASSERTION(objContent, NS_ASSERTION(objContent,
"embed and object must implement " "embed and object must implement "
"nsIObjectLoadingContent!"); "nsIObjectLoadingContent!");
objContent->GetDisplayedType(&type); objContent->GetDisplayedType(&type);
if (type == nsIObjectLoadingContent::TYPE_IMAGE &&
aElement.State().HasState(ElementState::BROKEN)) {
// GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
// cases when the object is broken/suppressed/etc (e.g. a broken image), but
// we want to treat those cases as TYPE_NULL
type = nsIObjectLoadingContent::TYPE_NULL;
} }
if (type == nsIObjectLoadingContent::TYPE_FALLBACK && if (type == nsIObjectLoadingContent::TYPE_FALLBACK &&