diff --git a/mozilla/content/base/src/nsGenConImageContent.cpp b/mozilla/content/base/src/nsGenConImageContent.cpp index b0fa2759403..51753e3bd2e 100644 --- a/mozilla/content/base/src/nsGenConImageContent.cpp +++ b/mozilla/content/base/src/nsGenConImageContent.cpp @@ -38,6 +38,7 @@ #include "nsXMLElement.h" #include "nsImageLoadingContent.h" #include "imgIRequest.h" +#include "nsIEventStateManager.h" /** * A fake content node class so that the image frame for @@ -58,6 +59,10 @@ public: { return aImageRequest->Clone(this, getter_AddRefs(mCurrentRequest)); } + + // nsIContent overrides + virtual PRInt32 IntrinsicState() const; + private: ~nsGenConImageContent() {} @@ -81,3 +86,18 @@ NS_NewGenConImageContent(nsIContent** aResult, nsINodeInfo* aNodeInfo, NS_RELEASE(*aResult); return rv; } + +PRInt32 +nsGenConImageContent::IntrinsicState() const +{ + PRInt32 state = nsXMLElement::IntrinsicState(); + + PRInt32 imageState = nsImageLoadingContent::ImageState(); + if (imageState & NS_EVENT_STATE_BROKEN) { + // We should never be in an error state; if the image fails to load, we + // just go to the suppressed state. + imageState |= NS_EVENT_STATE_SUPPRESSED; + imageState &= ~NS_EVENT_STATE_BROKEN; + } + return state | imageState; +} diff --git a/mozilla/content/base/src/nsImageLoadingContent.cpp b/mozilla/content/base/src/nsImageLoadingContent.cpp index b75174d0c8a..8a776cd4c76 100644 --- a/mozilla/content/base/src/nsImageLoadingContent.cpp +++ b/mozilla/content/base/src/nsImageLoadingContent.cpp @@ -58,6 +58,7 @@ #include "nsPresContext.h" #include "nsIPresShell.h" +#include "nsIEventStateManager.h" #include "nsGUIEvent.h" #include "nsIChannel.h" @@ -95,7 +96,11 @@ static void PrintReqURL(imgIRequest* req) { nsImageLoadingContent::nsImageLoadingContent() : mObserverList(nsnull), mImageBlockingStatus(nsIContentPolicy::ACCEPT), - mLoadingEnabled(PR_TRUE) + mLoadingEnabled(PR_TRUE), + // mBroken starts out true, since an image without a URI is broken.... + mBroken(PR_TRUE), + mUserDisabled(PR_FALSE), + mSuppressed(PR_FALSE) { if (!nsContentUtils::GetImgLoader()) mLoadingEnabled = PR_FALSE; @@ -212,6 +217,13 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest, FireEvent(NS_LITERAL_STRING("error")); } + // Have to check for state changes here (for example, the new load could + // have resulted in a broken image). Note that we don't want to do this + // async, unlike the event, because while this is waiting to happen our + // state could change yet again, and then we'll get confused about our + // state. + UpdateImageState(PR_TRUE); + return NS_OK; } @@ -383,21 +395,29 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel, nsCOMPtr & req = mCurrentRequest ? mPendingRequest : mCurrentRequest; - return nsContentUtils::GetImgLoader()->LoadImageWithChannel(aChannel, this, doc, aListener, getter_AddRefs(req)); + nsresult rv = nsContentUtils::GetImgLoader()-> + LoadImageWithChannel(aChannel, this, doc, aListener, getter_AddRefs(req)); + + // Make sure our state is up to date + UpdateImageState(PR_TRUE); + + return rv; } // XXX This should be a protected method, not an interface method!!! NS_IMETHODIMP nsImageLoadingContent::ImageURIChanged(const nsAString& aNewURI) { - return ImageURIChanged(aNewURI, PR_TRUE); + return ImageURIChanged(aNewURI, PR_TRUE, PR_FALSE); } /* * Non-interface methods */ + nsresult nsImageLoadingContent::ImageURIChanged(const nsAString& aNewURI, - PRBool aForce) + PRBool aForce, + PRBool aNotify) { if (!mLoadingEnabled) { FireEvent(NS_LITERAL_STRING("error")); @@ -431,11 +451,10 @@ nsImageLoadingContent::ImageURIChanged(const nsAString& aNewURI, } } - // Remember the URL of this request, in case someone asks us for it later - // But this only matters if we are affecting the current request - if (!mCurrentRequest) - mCurrentURI = imageURI; - + // From this point on, our state could change before return, so make + // sure to notify if it does. + AutoStateChanger changer(this, aNotify); + // If we'll be loading a new image, we want to cancel our existing // requests; the question is what reason to pass in. If everything // is going smoothly, that reason should be @@ -455,6 +474,13 @@ nsImageLoadingContent::ImageURIChanged(const nsAString& aNewURI, CancelImageRequests(cancelResult, PR_FALSE, newImageStatus); + // Remember the URL of this request, in case someone asks us for it later. + // But this only matters if we are affecting the current request. Need to do + // this after CancelImageRequests, since that affects the value of + // mCurrentRequest. + if (!mCurrentRequest) + mCurrentURI = imageURI; + if (!loadImage) { // Don't actually load anything! This was blocked by CanLoadImage. FireEvent(NS_LITERAL_STRING("error")); @@ -463,17 +489,6 @@ nsImageLoadingContent::ImageURIChanged(const nsAString& aNewURI, nsCOMPtr & req = mCurrentRequest ? mPendingRequest : mCurrentRequest; - nsCOMPtr thisContent = do_QueryInterface(this, &rv); - NS_ENSURE_TRUE(thisContent, rv); - - // It may be that one of our frames has replaced itself with alt text... This - // would only have happened if our mCurrentRequest had issues, and we would - // have set it to null by now in that case. Have to save that information - // here, since LoadImage may clobber the value of mCurrentRequest. On the - // other hand, if we've never had an observer, we know there aren't any frames - // that have changed to alt text on us yet. - PRBool mayNeedReframe = thisContent->MayHaveFrame() && !mCurrentRequest; - rv = nsContentUtils::LoadImage(imageURI, doc, doc->GetDocumentURI(), this, nsIRequest::LOAD_NORMAL, getter_AddRefs(req)); @@ -488,52 +503,68 @@ nsImageLoadingContent::ImageURIChanged(const nsAString& aNewURI, mCurrentURI = nsnull; } - if (!mayNeedReframe) { - // We're all set - return NS_OK; - } - - // Only continue if we're in a document -- that would mean we're a useful - // chunk of the content model and _may_ have a frame. This should eliminate - // things like SetAttr calls during the parsing process, as well as things - // like setting src on |new Image()|-type things. - if (!thisContent->IsInDoc()) { - return NS_OK; - } - - // OK, now for each PresShell, see whether we have a frame -- this tends to - // be expensive, which is why it's the last check.... If we have a frame - // and it's not of the right type, reframe it. - PRInt32 numShells = doc->GetNumberOfShells(); - for (PRInt32 i = 0; i < numShells; ++i) { - nsIPresShell *shell = doc->GetShellAt(i); - if (shell) { - nsIFrame* frame = shell->GetPrimaryFrameFor(thisContent); - if (frame) { - // XXXbz I don't like this one bit... we really need a better way of - // doing the CantRenderReplacedElement stuff.. In particular, it needs - // to be easily detectable. For example, I suspect that this code will - // fail for in the current CantRenderReplacedElement - // implementation... - nsIAtom* frameType = frame->GetType(); - if (frameType != nsLayoutAtoms::imageFrame && - frameType != nsLayoutAtoms::imageControlFrame && - frameType != nsLayoutAtoms::objectFrame) { - shell->RecreateFramesFor(thisContent); - } - } - } - } - return NS_OK; } +PRInt32 +nsImageLoadingContent::ImageState() const +{ + return + (mBroken * NS_EVENT_STATE_BROKEN) | + (mUserDisabled * NS_EVENT_STATE_USERDISABLED) | + (mSuppressed * NS_EVENT_STATE_SUPPRESSED); +} + void -nsImageLoadingContent::CancelImageRequests() +nsImageLoadingContent::UpdateImageState(PRBool aNotify) +{ + nsCOMPtr thisContent = do_QueryInterface(this); + if (!thisContent) { + return; + } + + PRInt32 oldState = ImageState(); + + mBroken = mUserDisabled = mSuppressed = PR_FALSE; + + // If we were blocked by server-based content policy, we claim to be + // suppressed. If we were blocked by type-based content policy, we claim to + // be user-disabled. Otherwise, claim to be broken. + if (mImageBlockingStatus == nsIContentPolicy::REJECT_SERVER) { + mSuppressed = PR_TRUE; + } else if (mImageBlockingStatus == nsIContentPolicy::REJECT_TYPE) { + mUserDisabled = PR_TRUE; + } else if (!mCurrentRequest) { + // No current request means error, since we weren't disabled or suppressed + mBroken = PR_TRUE; + } else { + PRUint32 currentLoadStatus; + nsresult rv = mCurrentRequest->GetImageStatus(¤tLoadStatus); + if (NS_FAILED(rv) || (currentLoadStatus & imgIRequest::STATUS_ERROR)) { + mBroken = PR_TRUE; + } + } + + if (aNotify) { + nsIDocument* doc = thisContent->GetCurrentDoc(); + if (doc) { + NS_ASSERTION(thisContent->IsInDoc(), "Something is confused"); + PRInt32 changedBits = oldState ^ ImageState(); + if (changedBits) { + mozAutoDocUpdate(doc, UPDATE_CONTENT_STATE, PR_TRUE); + doc->ContentStatesChanged(thisContent, nsnull, changedBits); + } + } + } +} + +void +nsImageLoadingContent::CancelImageRequests(PRBool aNotify) { // Make sure to null out mCurrentURI here, so we no longer look like an image mCurrentURI = nsnull; CancelImageRequests(NS_BINDING_ABORTED, PR_TRUE, nsIContentPolicy::ACCEPT); + UpdateImageState(aNotify); } void diff --git a/mozilla/content/base/src/nsImageLoadingContent.h b/mozilla/content/base/src/nsImageLoadingContent.h index 5d3878579a5..2cec88a7f87 100644 --- a/mozilla/content/base/src/nsImageLoadingContent.h +++ b/mozilla/content/base/src/nsImageLoadingContent.h @@ -83,16 +83,33 @@ protected: * @param aNewURI the URI spec to be loaded (may be a relative URI) * @param aForce If true, make sure to load the URI. If false, only * load if the URI is different from the currently loaded URI. + * @param aNotify If true, nsIDocumentObserver state change notifications + * will be sent as needed. Note that this is only here so + * nsObjectFrame can avoid getting reframed inside reflow; + * once objects load data from content we want to always + * notify. */ nsresult ImageURIChanged(const nsAString& aNewURI, - PRBool aForce); + PRBool aForce, PRBool aNotify = PR_TRUE); + + /** + * ImageState is called by subclasses that are computing their content state. + * The return value will have the NS_EVENT_STATE_BROKEN, + * NS_EVENT_STATE_USERDISABLED, and NS_EVENT_STATE_SUPPRESSED bits set as + * needed. Note that this state assumes that this node is "trying" to be an + * image (so for example complete lack of attempt to load an image will lead + * to NS_EVENT_STATE_BROKEN being set). Subclasses that are not "trying" to + * be an image (eg an HTML of type other than "image") should just + * not call this method when computing their intrinsic state. + */ + PRInt32 ImageState() const; /** * CancelImageRequests is called by subclasses when they want to * cancel all image requests (for example when the subclass is * somehow not an image anymore). */ - void CancelImageRequests(); + void CancelImageRequests(PRBool aNotify); private: /** @@ -117,6 +134,34 @@ private: ImageObserver* mNext; }; + /** + * Struct to report state changes + */ + struct AutoStateChanger { + AutoStateChanger(nsImageLoadingContent* aImageContent, + PRBool aNotify) : + mImageContent(aImageContent), + mNotify(aNotify) + { + } + ~AutoStateChanger() + { + mImageContent->UpdateImageState(mNotify); + } + + nsImageLoadingContent* mImageContent; + PRBool mNotify; + }; + + friend struct AutoStateChanger; + + /** + * UpdateImageState recomputes the current state of this image loading + * content and updates what ImageState() returns accordingly. It will also + * fire a ContentStatesChanged() notification as needed if aNotify is true. + */ + void UpdateImageState(PRBool aNotify); + /** * CancelImageRequests can be called when we want to cancel the * image requests, generally due to our src changing and us wanting @@ -179,7 +224,15 @@ private: ImageObserver mObserverList; PRInt16 mImageBlockingStatus; - PRPackedBool mLoadingEnabled; + PRPackedBool mLoadingEnabled : 1; + + /** + * The state we had the last time we checked whether we needed to notify the + * document of a state change. These are maintained by UpdateImageState. + */ + PRPackedBool mBroken : 1; + PRPackedBool mUserDisabled : 1; + PRPackedBool mSuppressed : 1; }; #endif // nsImageLoadingContent_h__ diff --git a/mozilla/content/events/public/nsIEventStateManager.h b/mozilla/content/events/public/nsIEventStateManager.h index 079c8da3ab8..eaa78757c72 100644 --- a/mozilla/content/events/public/nsIEventStateManager.h +++ b/mozilla/content/events/public/nsIEventStateManager.h @@ -159,17 +159,23 @@ public: #define NS_EVENT_STATE_URLTARGET 0x00000010 // content is URL's target (ref) // The following states are used only for ContentStatesChanged -// CSS 3 Selectors -#define NS_EVENT_STATE_CHECKED 0x00000020 -#define NS_EVENT_STATE_ENABLED 0x00000040 -#define NS_EVENT_STATE_DISABLED 0x00000080 -// CSS 3 UI -#define NS_EVENT_STATE_REQUIRED 0x00000100 -#define NS_EVENT_STATE_OPTIONAL 0x00000200 -#define NS_EVENT_STATE_VISITED 0x00000400 -#define NS_EVENT_STATE_VALID 0x00000800 -#define NS_EVENT_STATE_INVALID 0x00001000 -#define NS_EVENT_STATE_INRANGE 0x00002000 -#define NS_EVENT_STATE_OUTOFRANGE 0x00004000 + +#define NS_EVENT_STATE_CHECKED 0x00000020 // CSS3-Selectors +#define NS_EVENT_STATE_ENABLED 0x00000040 // CSS3-Selectors +#define NS_EVENT_STATE_DISABLED 0x00000080 // CSS3-Selectors +#define NS_EVENT_STATE_REQUIRED 0x00000100 // CSS3-UI +#define NS_EVENT_STATE_OPTIONAL 0x00000200 // CSS3-UI +#define NS_EVENT_STATE_VISITED 0x00000400 // CSS2 +#define NS_EVENT_STATE_VALID 0x00000800 // CSS3-UI +#define NS_EVENT_STATE_INVALID 0x00001000 // CSS3-UI +#define NS_EVENT_STATE_INRANGE 0x00002000 // CSS3-UI +#define NS_EVENT_STATE_OUTOFRANGE 0x00004000 // CSS3-UI + +// Content could not be rendered (image/object/etc). +#define NS_EVENT_STATE_BROKEN 0x00008000 +// Content disabled by the user (images turned off, say) +#define NS_EVENT_STATE_USERDISABLED 0x00010000 +// Content suppressed by the user (ad blocking, etc) +#define NS_EVENT_STATE_SUPPRESSED 0x00020000 #endif // nsIEventStateManager_h__ diff --git a/mozilla/content/html/content/src/nsHTMLAppletElement.cpp b/mozilla/content/html/content/src/nsHTMLAppletElement.cpp index 82899e622fe..3f066de89b2 100644 --- a/mozilla/content/html/content/src/nsHTMLAppletElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLAppletElement.cpp @@ -43,6 +43,8 @@ #include "nsPresContext.h" #include "nsIDocument.h" #include "nsLayoutAtoms.h" +#include "nsCSSPseudoClasses.h" +#include "nsIEventStateManager.h" // XXX this is to get around conflicts with windows.h defines // introduced through jni.h @@ -87,6 +89,7 @@ public: nsAttrValue& aResult); virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; + virtual PRInt32 IntrinsicState() const; protected: PRPackedBool mReflectedApplet; @@ -192,3 +195,16 @@ nsHTMLAppletElement::GetAttributeMappingFunction() const { return &MapAttributesIntoRule; } + +PRInt32 +nsHTMLAppletElement::IntrinsicState() const +{ + PRInt32 state = nsGenericHTMLElement::IntrinsicState(); + + void* broken = GetProperty(nsCSSPseudoClasses::mozBroken); + if (NS_PTR_TO_INT32(broken)) { + state |= NS_EVENT_STATE_BROKEN; + } + + return state; +} diff --git a/mozilla/content/html/content/src/nsHTMLImageElement.cpp b/mozilla/content/html/content/src/nsHTMLImageElement.cpp index ff8d6ecc8a7..71332162b90 100644 --- a/mozilla/content/html/content/src/nsHTMLImageElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLImageElement.cpp @@ -145,6 +145,8 @@ public: nsIContent* aBindingParent, PRBool aCompileEventHandlers); + virtual PRInt32 IntrinsicState() const; + protected: void GetImageFrame(nsIImageFrame** aImageFrame); nsPoint GetXY(); @@ -603,6 +605,13 @@ nsHTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, return rv; } +PRInt32 +nsHTMLImageElement::IntrinsicState() const +{ + return nsGenericHTMLElement::IntrinsicState() | + nsImageLoadingContent::ImageState(); +} + NS_IMETHODIMP nsHTMLImageElement::Initialize(JSContext* aContext, JSObject *aObj, PRUint32 argc, jsval *argv) diff --git a/mozilla/content/html/content/src/nsHTMLInputElement.cpp b/mozilla/content/html/content/src/nsHTMLInputElement.cpp index b8ea59fcba5..b29edf649de 100644 --- a/mozilla/content/html/content/src/nsHTMLInputElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLInputElement.cpp @@ -549,10 +549,8 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, // We're no longer an image input. Cancel our image requests, if we have // any. Note that doing this when we already weren't an image is ok -- // just does nothing. - CancelImageRequests(); - } - - if (aNotify && mType == NS_FORM_INPUT_IMAGE && !mCurrentRequest) { + CancelImageRequests(aNotify); + } else if (aNotify) { // We just got switched to be an image input; we should see // whether we have an image to load; nsAutoString src; @@ -2479,6 +2477,8 @@ nsHTMLInputElement::IntrinsicState() const (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO)) { state |= NS_EVENT_STATE_CHECKED; + } else if (mType == NS_FORM_INPUT_IMAGE) { + state |= nsImageLoadingContent::ImageState(); } return state; } diff --git a/mozilla/content/html/content/src/nsHTMLObjectElement.cpp b/mozilla/content/html/content/src/nsHTMLObjectElement.cpp index e7c1ba717e0..17cc816ee73 100644 --- a/mozilla/content/html/content/src/nsHTMLObjectElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLObjectElement.cpp @@ -50,6 +50,9 @@ #include "nsIPluginInstance.h" #include "nsIPluginInstanceInternal.h" #include "nsIPluginElement.h" +#include "nsIEventStateManager.h" +#include "nsCSSPseudoClasses.h" +#include "nsLayoutAtoms.h" class nsHTMLObjectElement : public nsGenericHTMLFormElement, public nsImageLoadingContent, @@ -97,6 +100,7 @@ public: nsAttrValue& aResult); virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; + virtual PRInt32 IntrinsicState() const; protected: PRPackedBool mIsDoneAddingChildren; @@ -335,3 +339,21 @@ nsHTMLObjectElement::GetAttributeMappingFunction() const { return &MapAttributesIntoRule; } + +PRInt32 +nsHTMLObjectElement::IntrinsicState() const +{ + PRInt32 state = nsGenericHTMLFormElement::IntrinsicState(); + + void* image = GetProperty(nsLayoutAtoms::imageFrame); + if (NS_PTR_TO_INT32(image)) { + state |= nsImageLoadingContent::ImageState(); + } + + void* broken = GetProperty(nsCSSPseudoClasses::mozBroken); + if (NS_PTR_TO_INT32(broken)) { + state |= NS_EVENT_STATE_BROKEN; + } + + return state; +} diff --git a/mozilla/content/html/content/src/nsHTMLSharedElement.cpp b/mozilla/content/html/content/src/nsHTMLSharedElement.cpp index 15eee5f182b..147c59f4eae 100644 --- a/mozilla/content/html/content/src/nsHTMLSharedElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLSharedElement.cpp @@ -52,6 +52,9 @@ #include "nsMappedAttributes.h" #include "nsStyleContext.h" #include "nsIPluginElement.h" +#include "nsCSSPseudoClasses.h" +#include "nsIEventStateManager.h" +#include "nsLayoutAtoms.h" #ifdef MOZ_SVG #include "nsIDOMGetSVGDocument.h" @@ -141,6 +144,7 @@ public: nsAttrValue& aResult); virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; + virtual PRInt32 IntrinsicState() const; protected: nsCString mActualType; @@ -508,3 +512,20 @@ nsHTMLSharedElement::GetAttributeMappingFunction() const return nsGenericHTMLElement::GetAttributeMappingFunction(); } + +PRInt32 +nsHTMLSharedElement::IntrinsicState() const +{ + PRInt32 state = nsGenericHTMLElement::IntrinsicState(); + if (mNodeInfo->Equals(nsHTMLAtoms::embed)) { + void* image = GetProperty(nsLayoutAtoms::imageFrame); + if (NS_PTR_TO_INT32(image)) { + state |= nsImageLoadingContent::ImageState(); + } + void* broken = GetProperty(nsCSSPseudoClasses::mozBroken); + if (NS_PTR_TO_INT32(broken)) { + state |= NS_EVENT_STATE_BROKEN; + } + } + return state; +} diff --git a/mozilla/content/html/content/src/nsHTMLSharedObjectElement.cpp b/mozilla/content/html/content/src/nsHTMLSharedObjectElement.cpp index c62d7af55da..3f5661ec6b2 100644 --- a/mozilla/content/html/content/src/nsHTMLSharedObjectElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLSharedObjectElement.cpp @@ -46,6 +46,10 @@ #include "nsIDOMDocument.h" #include "nsIWebNavigation.h" #include "nsIFormControl.h" +#include "nsIEventStateManager.h" +#include "nsCSSPseudoClasses.h" +#include "nsLayoutAtoms.h" + class nsHTMLObjectElement : public nsGenericHTMLFormElement, public nsImageLoadingContent, @@ -87,6 +91,7 @@ public: nsAttrValue& aResult); nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; + virtual PRInt32 IntrinsicState() const; }; @@ -238,3 +243,21 @@ nsHTMLObjectElement::GetAttributeMappingFunction() const { return &MapAttributesIntoRule; } + +PRInt32 +nsHTMLObjectElement::IntrinsicState() const +{ + PRInt32 state = nsGenericHTMLFormElement::IntrinsicState(); + + void* image = GetProperty(nsLayoutAtoms::imageFrame); + if (NS_PTR_TO_INT32(image)) { + state |= nsImageLoadingContent::ImageState(); + } + + void* broken = GetProperty(nsCSSPseudoClasses::mozBroken); + if (NS_PTR_TO_INT32(broken)) { + state |= NS_EVENT_STATE_BROKEN; + } + + return state; +} diff --git a/mozilla/content/svg/content/src/nsSVGImageElement.cpp b/mozilla/content/svg/content/src/nsSVGImageElement.cpp index 5d0be1897b4..f959a7a4cd1 100644 --- a/mozilla/content/svg/content/src/nsSVGImageElement.cpp +++ b/mozilla/content/svg/content/src/nsSVGImageElement.cpp @@ -87,6 +87,8 @@ public: NS_IMETHOD DidModifySVGObservable(nsISVGValue *observable, nsISVGValue::modificationType aModType); + // nsIContent specializations + virtual PRInt32 IntrinsicState() const; protected: void GetSrc(nsAString& src); @@ -391,3 +393,12 @@ nsSVGImageElement::DidModifySVGObservable(nsISVGValue* aObservable, return nsSVGImageElementBase::DidModifySVGObservable(aObservable, aModType); } +//---------------------------------------------------------------------- +// nsIContent methods: + +PRInt32 +nsSVGImageElement::IntrinsicState() const +{ + return nsSVGImageElementBase::IntrinsicState() | + nsImageLoadingContent::ImageState(); +} diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 4e7ff5d47d8..b36acf333aa 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -62,6 +62,7 @@ #include "nsIPresShell.h" #include "nsStyleSet.h" #include "nsIViewManager.h" +#include "nsIEventStateManager.h" #include "nsIScrollableView.h" #include "nsStyleConsts.h" #include "nsTableOuterFrame.h" @@ -112,6 +113,7 @@ #include "nsXULAtoms.h" #include "nsBoxFrame.h" #include "nsIBoxLayout.h" +#include "nsImageFrame.h" static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); @@ -1590,9 +1592,8 @@ AdjustFloatParentPtrs(nsIFrame* aFrame, outOfFlowFrame->SetParent(parent); if (outOfFlowFrame->GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) { - // We don't need to walk up the tree, since each level of - // recursion of the SplitToContainingBlock will propagate the - // bit. + // We don't need to walk up the tree, since we're doing this + // recursively parent->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW); } } @@ -1959,6 +1960,48 @@ nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) } } +nsresult +nsCSSFrameConstructor::CreateAttributeContent(nsIContent* aParentContent, + nsIFrame* aParentFrame, + PRInt32 aAttrNamespace, + nsIAtom* aAttrName, + nsStyleContext* aStyleContext, + nsIContent** aNewContent, + nsIFrame** aNewFrame) +{ + *aNewFrame = nsnull; + *aNewContent = nsnull; + nsCOMPtr content; + nsresult rv = NS_NewAttributeContent(mDocument, aAttrNamespace, aAttrName, + getter_AddRefs(content)); + NS_ENSURE_SUCCESS(rv, rv); + + // Set aContent as the parent content so that event handling works. + rv = content->BindToTree(mDocument, aParentContent, content, PR_TRUE); + if (NS_FAILED(rv)) { + content->UnbindFromTree(); + return rv; + } + + content->SetNativeAnonymous(PR_TRUE); + + // Create a text frame and initialize it + nsIFrame* textFrame = nsnull; + NS_NewTextFrame(mPresShell, &textFrame); + rv = textFrame->Init(mPresShell->GetPresContext(), content, aParentFrame, + aStyleContext, nsnull); + if (NS_FAILED(rv)) { + content->UnbindFromTree(); + textFrame->Destroy(mPresShell->GetPresContext()); + textFrame = nsnull; + content = nsnull; + } + + *aNewFrame = textFrame; + content.swap(*aNewContent); + return rv; +} + nsresult nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFrame, nsIContent* aContent, @@ -2062,32 +2105,11 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram return NS_ERROR_OUT_OF_MEMORY; } - // Creates the content and frame and return if successful - nsresult rv = NS_ERROR_FAILURE; - if (attrName) { - nsIFrame* textFrame = nsnull; - rv = NS_NewAttributeContent(mDocument, attrNameSpace, attrName, - getter_AddRefs(content)); - NS_ENSURE_SUCCESS(rv, rv); - - // Set aContent as the parent content so that event handling works. - rv = content->BindToTree(mDocument, aContent, content, PR_TRUE); - if (NS_FAILED(rv)) { - content->UnbindFromTree(); - return rv; - } - - content->SetNativeAnonymous(PR_TRUE); - - // Create a text frame and initialize it - NS_NewTextFrame(mPresShell, &textFrame); - textFrame->Init(presContext, content, aParentFrame, aStyleContext, - nsnull); - - // Return the text frame - *aFrame = textFrame; - rv = NS_OK; - } + nsresult rv = + CreateAttributeContent(aContent, aParentFrame, attrNameSpace, + attrName, aStyleContext, + getter_AddRefs(content), aFrame); + NS_ENSURE_SUCCESS(rv, rv); } break; @@ -2147,6 +2169,37 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram } break; + case eStyleContentType_AltContent: + { + // Use the "alt" attribute; if that fails and the node is an HTML + // , try the value attribute and then fall back to some default + // localized text we have. + nsresult rv = NS_OK; + if (aContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::alt)) { + rv = CreateAttributeContent(aContent, aParentFrame, + kNameSpaceID_None, nsHTMLAtoms::alt, + aStyleContext, getter_AddRefs(content), + aFrame); + } else if (aContent->IsContentOfType(nsIContent::eHTML) && + aContent->GetNodeInfo()->Equals(nsHTMLAtoms::input)) { + if (aContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::value)) { + rv = CreateAttributeContent(aContent, aParentFrame, + kNameSpaceID_None, nsHTMLAtoms::value, + aStyleContext, getter_AddRefs(content), + aFrame); + } else { + nsXPIDLString temp; + rv = nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, + "Submit", temp); + contentString = temp; + } + } else { + *aFrame = nsnull; + rv = NS_ERROR_NOT_AVAILABLE; + } + NS_ENSURE_SUCCESS(rv, rv); + } + break; } // switch @@ -2301,6 +2354,9 @@ nsCSSFrameConstructor::CreateInputFrame(nsIContent *aContent, nsIFrame **aFrame, nsStyleContext *aStyleContext) { + // Note: do not do anything in this method that assumes pseudo-frames have + // been processed. If you feel the urge to do something like that, fix + // callers accordingly. nsCOMPtr control = do_QueryInterface(aContent); NS_ASSERTION(control, "input is not an nsIFormControl!"); @@ -2337,7 +2393,8 @@ nsCSSFrameConstructor::CreateInputFrame(nsIContent *aContent, // in IsSpecialHTMLContent case NS_FORM_INPUT_IMAGE: - return NS_NewImageControlFrame(mPresShell, aFrame); + return CreateHTMLImageFrame(aContent, aStyleContext, + NS_NewImageControlFrame, aFrame); case NS_FORM_INPUT_TEXT: case NS_FORM_INPUT_PASSWORD: @@ -2349,6 +2406,20 @@ nsCSSFrameConstructor::CreateInputFrame(nsIContent *aContent, } } +nsresult +nsCSSFrameConstructor::CreateHTMLImageFrame(nsIContent* aContent, + nsStyleContext* aStyleContext, + ImageFrameCreatorFunc aFunc, + nsIFrame** aFrame) +{ + if (nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) { + return (*aFunc)(mPresShell, aFrame); + } + + *aFrame = nsnull; + return NS_OK; +} + static PRBool IsOnlyWhitespace(nsIContent* aContent) { @@ -3213,6 +3284,8 @@ IsSpecialHTMLContent(nsIContent* aContent) // Gross hack. Return true if this is a content node that we'd create an HTML // frame for based on something other than display -- in other words if this // is an HTML node that could never have a nsTableCellFrame, for example. + // XXXbz of course this fails if this is an image that'll get replaced by alt + // text or something like that.... oh, well. if (!aContent->IsContentOfType(nsIContent::eHTML)) { return PR_FALSE; } @@ -5266,13 +5339,14 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, // Create a frame based on the tag if (nsHTMLAtoms::img == aTag) { - isReplaced = PR_TRUE; - if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { - ProcessPseudoFrames(aState, aFrameItems); + rv = CreateHTMLImageFrame(aContent, aStyleContext, NS_NewImageFrame, + &newFrame); + if (NS_SUCCEEDED(rv) && newFrame) { + isReplaced = PR_TRUE; + if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { + ProcessPseudoFrames(aState, aFrameItems); + } } - // XXX If image display is turned off, then use ConstructAlternateFrame() - // instead... - rv = NS_NewImageFrame(mPresShell, &newFrame); } else if (nsHTMLAtoms::br == aTag) { if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { @@ -5292,11 +5366,13 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, rv = NS_NewWBRFrame(mPresShell, &newFrame); } else if (nsHTMLAtoms::input == aTag) { - if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { - ProcessPseudoFrames(aState, aFrameItems); - } - isReplaced = PR_TRUE; rv = CreateInputFrame(aContent, &newFrame, aStyleContext); + if (NS_SUCCEEDED(rv) && newFrame) { + if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { + ProcessPseudoFrames(aState, aFrameItems); + } + isReplaced = PR_TRUE; + } } else if (nsHTMLAtoms::textarea == aTag) { if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { @@ -5324,11 +5400,15 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, else if (nsHTMLAtoms::object == aTag || nsHTMLAtoms::applet == aTag || nsHTMLAtoms::embed == aTag) { - if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { - ProcessPseudoFrames(aState, aFrameItems); + if (!(aContent->IntrinsicState() & + (NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED | + NS_EVENT_STATE_SUPPRESSED))) { + if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { + ProcessPseudoFrames(aState, aFrameItems); + } + isReplaced = PR_TRUE; + rv = NS_NewObjectFrame(mPresShell, &newFrame); } - isReplaced = PR_TRUE; - rv = NS_NewObjectFrame(mPresShell, &newFrame); } else if (nsHTMLAtoms::fieldset == aTag) { if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { @@ -5437,66 +5517,47 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, rv = InitAndRestoreFrame(aState, aContent, geometricParent, aStyleContext, nsnull, newFrame); - if (rv == NS_ERROR_FRAME_REPLACED) { - // The frame called CantRenderReplacedElement from inside Init(). That - // failed to do anything useful, since the frame was not in the frame - // tree yet... Create an alternate frame ourselves - newFrame->Destroy(aState.mPresContext); + NS_ASSERTION(NS_SUCCEEDED(rv), "InitAndRestoreFrame failed"); + // See if we need to create a view, e.g. the frame is absolutely + // positioned + nsHTMLContainerFrame::CreateViewForFrame(newFrame, aParentFrame, PR_FALSE); - if (aTag != nsHTMLAtoms::img && aTag != nsHTMLAtoms::input) { - // XXXbz This should really be made to work for too... - return NS_OK; - } - - // Try to construct the alternate frame - newFrame = nsnull; - rv = ConstructAlternateFrame(aContent, aStyleContext, geometricParent, - aParentFrame, newFrame); - NS_ENSURE_SUCCESS(rv, rv); - NS_ASSERTION(newFrame, "ConstructAlternateFrame needs better error-checking"); - } else { - NS_ASSERTION(NS_SUCCEEDED(rv), "InitAndRestoreFrame failed"); - // See if we need to create a view, e.g. the frame is absolutely - // positioned - nsHTMLContainerFrame::CreateViewForFrame(newFrame, aParentFrame, PR_FALSE); - - rv = aState.AddChild(newFrame, aFrameItems, display, aContent, - aStyleContext, aParentFrame); - if (NS_FAILED(rv)) { - return rv; - } - addedToFrameList = PR_TRUE; + rv = aState.AddChild(newFrame, aFrameItems, display, aContent, + aStyleContext, aParentFrame); + if (NS_FAILED(rv)) { + return rv; + } + addedToFrameList = PR_TRUE; - // Process the child content if requested - nsFrameItems childItems; - nsFrameConstructorSaveState absoluteSaveState; - nsFrameConstructorSaveState floatSaveState; - if (!newFrame->IsLeaf()) { - if (display->IsPositioned()) { - aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState); - } - if (isFloatContainer) { - PRBool haveFirstLetterStyle, haveFirstLineStyle; - HaveSpecialBlockStyle(aContent, aStyleContext, - &haveFirstLetterStyle, &haveFirstLineStyle); - aState.PushFloatContainingBlock(newFrame, floatSaveState, - PR_FALSE, PR_FALSE); - } - - // Process the child frames - rv = ProcessChildren(aState, aContent, newFrame, - PR_TRUE, childItems, PR_FALSE); + // Process the child content if requested + nsFrameItems childItems; + nsFrameConstructorSaveState absoluteSaveState; + nsFrameConstructorSaveState floatSaveState; + if (!newFrame->IsLeaf()) { + if (display->IsPositioned()) { + aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState); + } + if (isFloatContainer) { + PRBool haveFirstLetterStyle, haveFirstLineStyle; + HaveSpecialBlockStyle(aContent, aStyleContext, + &haveFirstLetterStyle, &haveFirstLineStyle); + aState.PushFloatContainingBlock(newFrame, floatSaveState, + PR_FALSE, PR_FALSE); } - // if there are any anonymous children create frames for them - CreateAnonymousFrames(aTag, aState, aContent, newFrame, - PR_FALSE, childItems); + // Process the child frames + rv = ProcessChildren(aState, aContent, newFrame, + PR_TRUE, childItems, PR_FALSE); + } - // Set the frame's initial child list - if (childItems.childList) { - newFrame->SetInitialChildList(aState.mPresContext, nsnull, - childItems.childList); - } + // if there are any anonymous children create frames for them + CreateAnonymousFrames(aTag, aState, aContent, newFrame, + PR_FALSE, childItems); + + // Set the frame's initial child list + if (childItems.childList) { + newFrame->SetInitialChildList(aState.mPresContext, nsnull, + childItems.childList); } } @@ -10282,19 +10343,26 @@ nsCSSFrameConstructor::DoContentStateChanged(nsIContent* aContent, NS_ASSERTION(styleSet, "couldn't get style set"); if (aContent) { - nsIFrame* primaryFrame = mPresShell->GetPrimaryFrameFor(aContent); - - nsChangeHint hint = NS_STYLE_HINT_NONE; - if (primaryFrame) { - PRUint8 app = primaryFrame->GetStyleDisplay()->mAppearance; - if (app) { - nsITheme *theme = presContext->GetTheme(); - if (theme && theme->ThemeSupportsWidget(presContext, - primaryFrame, app)) { - PRBool repaint = PR_FALSE; - theme->WidgetStateChanged(primaryFrame, app, nsnull, &repaint); - if (repaint) { - NS_UpdateHint(hint, nsChangeHint_RepaintFrame); + nsChangeHint hint; + if (aStateMask & (NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED | + NS_EVENT_STATE_SUPPRESSED)) { + // Any change to a content state that affects which frames we + // construct must lead to a frame reconstruct here + hint = nsChangeHint_ReconstructFrame; + } else { + hint = NS_STYLE_HINT_NONE; + nsIFrame* primaryFrame = mPresShell->GetPrimaryFrameFor(aContent); + if (primaryFrame) { + PRUint8 app = primaryFrame->GetStyleDisplay()->mAppearance; + if (app) { + nsITheme *theme = presContext->GetTheme(); + if (theme && theme->ThemeSupportsWidget(presContext, + primaryFrame, app)) { + PRBool repaint = PR_FALSE; + theme->WidgetStateChanged(primaryFrame, app, nsnull, &repaint); + if (repaint) { + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); + } } } } @@ -10466,6 +10534,9 @@ nsCSSFrameConstructor::WillDestroyFrameTree() } //STATIC + +// XXXbz I'd really like this method to go away. Once we have inline-block and +// I can just use that for sized broken images, that can happen, maybe. void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent, nsIAtom* aTag, // content object's tag nsXPIDLString& aAltText) @@ -10491,345 +10562,6 @@ void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent, } } -// Construct an alternate frame to use when the image can't be rendered -nsresult -nsCSSFrameConstructor::ConstructAlternateFrame(nsIContent* aContent, - nsStyleContext* aStyleContext, - nsIFrame* aGeometricParent, - nsIFrame* aContentParent, - nsIFrame*& aFrame) -{ - nsresult rv; - nsXPIDLString altText; - - // Initialize OUT parameter - aFrame = nsnull; - - // Get the alternate text to use - GetAlternateTextFor(aContent, aContent->Tag(), altText); - - // Create a text content element for the alternate text - nsCOMPtr altTextContent; - rv = NS_NewTextNode(getter_AddRefs(altTextContent)); - if (NS_FAILED(rv)) - return rv; - - // Set the content's text - altTextContent->SetText(altText, PR_TRUE); - - // Set aContent as the parent content. - // XXXbz should this set the binding parent to |altTextContent|? - rv = altTextContent->BindToTree(mDocument, aContent, nsnull, PR_TRUE); - if (NS_FAILED(rv)) { - altTextContent->UnbindFromTree(); - return rv; - } - - // XXXbz shouldn't it be set native anonymous too? - - // Create either an inline frame, block frame, or area frame - nsIFrame* containerFrame; - PRBool isOutOfFlow = PR_FALSE; - const nsStyleDisplay* display = aStyleContext->GetStyleDisplay(); - - if (display->IsAbsolutelyPositioned()) { - NS_NewAbsoluteItemWrapperFrame(mPresShell, &containerFrame); - isOutOfFlow = PR_TRUE; - } else if (display->IsFloating()) { - NS_NewFloatingItemWrapperFrame(mPresShell, &containerFrame); - isOutOfFlow = PR_TRUE; - } else if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { - NS_NewBlockFrame(mPresShell, &containerFrame); - } else { - NS_NewInlineFrame(mPresShell, &containerFrame); - } - nsPresContext* presContext = mPresShell->GetPresContext(); - containerFrame->Init(presContext, aContent, aGeometricParent, aStyleContext, - nsnull); - nsHTMLContainerFrame::CreateViewForFrame(containerFrame, aContentParent, - PR_FALSE); - - // If the frame is out-of-flow, then mark it as such - if (isOutOfFlow) { - containerFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW); - } - - // Create a text frame to display the alt-text. It gets a pseudo-element - // style context - nsIFrame* textFrame; - NS_NewTextFrame(mPresShell, &textFrame); - - nsRefPtr textStyleContext; - textStyleContext = mPresShell->StyleSet()-> - ResolveStyleForNonElement(aStyleContext); - - textFrame->Init(presContext, altTextContent, containerFrame, - textStyleContext, nsnull); - containerFrame->SetInitialChildList(presContext, nsnull, textFrame); - - // Return the container frame - aFrame = containerFrame; - - return NS_OK; -} - -#ifdef NS_DEBUG -static PRBool -IsPlaceholderFrame(nsIFrame* aFrame) -{ - return aFrame->GetType() == nsLayoutAtoms::placeholderFrame; -} -#endif - - -static PRBool -HasDisplayableChildren(nsIFrame* aContainerFrame) -{ - // Returns 'true' if there are frames within aContainerFrame that - // could be displayed in the frame list. - NS_PRECONDITION(aContainerFrame != nsnull, "null ptr"); - if (! aContainerFrame) - return PR_FALSE; - - nsIFrame* frame = aContainerFrame->GetFirstChild(nsnull); - - while (frame) { - // If it's not a text frame, then assume that it's displayable. - if (frame->GetType() != nsLayoutAtoms::textFrame) - return PR_TRUE; - - // If not only whitespace, then we have displayable content here. - if (! IsOnlyWhitespace(frame->GetContent())) - return PR_TRUE; - - // Otherwise, on to the next frame... - frame = frame->GetNextSibling(); - } - - // If we get here, then we've iterated through all the child frames, - // and every one is a text frame containing whitespace. (Or, there - // weren't any frames at all!) There is nothing to diplay. - return PR_FALSE; -} - - - -nsresult -nsCSSFrameConstructor::CantRenderReplacedElement(nsIFrame* aFrame) -{ - nsresult rv = NS_OK; - - // Get parent frame and style context - nsIFrame* parentFrame = aFrame->GetParent(); - nsStyleContext* styleContext = aFrame->GetStyleContext(); - - // Get aFrame's content object and the tag name - nsIAtom* tag; - - nsIContent* content = aFrame->GetContent(); - NS_ASSERTION(content, "null content object"); - tag = content->Tag(); - - // Get the child list name that the frame is contained in - nsCOMPtr listName; - GetChildListNameFor(parentFrame, aFrame, getter_AddRefs(listName)); - - // If the frame is out of the flow, then it has a placeholder frame. - nsPlaceholderFrame* placeholderFrame = nsnull; - if (listName) { - mPresShell->GetPlaceholderFrameFor(aFrame, (nsIFrame**) &placeholderFrame); - } - - // Get the previous sibling frame - nsFrameList frameList(parentFrame->GetFirstChild(listName)); - - // See whether it's an IMG or an INPUT element (for image buttons) - // or if it is an applet with no displayable children - // XXX need to check nameSpaceID in these spots - if (nsHTMLAtoms::img == tag || nsHTMLAtoms::input == tag || - (nsHTMLAtoms::applet == tag && !HasDisplayableChildren(aFrame))) { - // Try and construct an alternate frame to use when the - // image can't be rendered - nsIFrame* newFrame; - rv = ConstructAlternateFrame(content, styleContext, - parentFrame, nsnull, newFrame); - - if (NS_SUCCEEDED(rv)) { - nsFrameManager *frameManager = mPresShell->FrameManager(); - - // Replace the old frame with the new frame - - DeletingFrameSubtree(mPresShell->GetPresContext(), mPresShell, - frameManager, aFrame); - - // Reset the primary frame mapping - frameManager->SetPrimaryFrameFor(content, newFrame); - - // Replace the old frame with the new frame - // XXXbz If this fails, we leak the content node newFrame points to! - frameManager->ReplaceFrame(parentFrame, listName, aFrame, newFrame); - - // Now that we've replaced the primary frame, if there's a placeholder - // frame then complete the transition from image frame to new frame - if (placeholderFrame) { - // Remove the association between the old frame and its placeholder - frameManager->UnregisterPlaceholderFrame(placeholderFrame); - - // Placeholder frames have a pointer back to the out-of-flow frame. - // Make sure that's correct, too. - placeholderFrame->SetOutOfFlowFrame(newFrame); - - // Reuse the existing placeholder frame, and add an association to the - // new frame - frameManager->RegisterPlaceholderFrame(placeholderFrame); - - // XXX Work around a bug in the block code where the float won't get - // reflowed unless the line containing the placeholder frame is reflowed... - placeholderFrame->GetParent()-> - ReflowDirtyChild(mPresShell, placeholderFrame); - } - } - - } else if ((nsHTMLAtoms::object == tag) || - (nsHTMLAtoms::embed == tag) || - (nsHTMLAtoms::applet == tag)) { - // It's an OBJECT, EMBED, or APPLET, so we should display the contents - // instead - nsIFrame* absoluteContainingBlock; - nsIFrame* floatContainingBlock; - nsIFrame* inFlowParent = parentFrame; - - // If the OBJECT frame is out-of-flow, then get the placeholder frame's - // parent and use that when determining the absolute containing block and - // float containing block - if (placeholderFrame) { - inFlowParent = placeholderFrame->GetParent(); - } - - absoluteContainingBlock = GetAbsoluteContainingBlock(inFlowParent); - floatContainingBlock = GetFloatContainingBlock(inFlowParent); - -#ifdef NS_DEBUG - // Verify that we calculated the same containing block - if (listName == nsLayoutAtoms::absoluteList) { - NS_ASSERTION(absoluteContainingBlock == parentFrame, - "wrong absolute containing block"); - } else if (listName == nsLayoutAtoms::floatList) { - NS_ASSERTION(floatContainingBlock == parentFrame, - "wrong float containing block"); - } -#endif - - // Now initialize the frame construction state - nsFrameConstructorState state(mPresShell, mFixedContainingBlock, - absoluteContainingBlock, - floatContainingBlock); - nsFrameItems frameItems; - const nsStyleDisplay* display = styleContext->GetStyleDisplay(); - - // Create a new frame based on the display type. - // Note: if the old frame was out-of-flow, then so will the new frame - // and we'll get a new placeholder frame - // XXXbz handle pseudos? Just trying to do it here doesn't quite work - // because of the list-munging we end up doing later in this function.... - rv = ConstructFrameByDisplayType(state, display, - content, content->GetNameSpaceID(), tag, - inFlowParent, styleContext, frameItems, - PR_FALSE); - - if (NS_FAILED(rv)) return rv; - - nsIFrame* newFrame = frameItems.childList; - - - if (NS_SUCCEEDED(rv)) { - if (placeholderFrame) { - // Remove the association between the old frame and its placeholder - // Note: ConstructFrameByDisplayType() will already have added an - // association for the new placeholder frame - state.mFrameManager->UnregisterPlaceholderFrame(placeholderFrame); - - // Verify that the new frame is also a placeholder frame - NS_ASSERTION(IsPlaceholderFrame(newFrame), "unexpected frame type"); - - // Replace the old placeholder frame with the new placeholder frame - state.mFrameManager->ReplaceFrame(inFlowParent, nsnull, - placeholderFrame, newFrame); - } - - // Replace the primary frame - if (listName == nsnull) { - if (IsInlineFrame(parentFrame) && !AreAllKidsInline(newFrame)) { - // We're in the uncomfortable position of being an inline - // that now contains a block. As in ConstructInline(), break - // the newly constructed frames into three lists: the inline - // frames before the first block frame (list1), the inline - // frames after the last block frame (list3), and all the - // frames between the first and last block frames (list2). - nsIFrame* list1 = newFrame; - - nsIFrame* prevToFirstBlock; - nsIFrame* list2 = FindFirstBlock(list1, &prevToFirstBlock); - NS_ASSERTION(list2, "Why did we get into this code?"); - - if (prevToFirstBlock) - prevToFirstBlock->SetNextSibling(nsnull); - else list1 = nsnull; - - nsIFrame* afterFirstBlock = list2->GetNextSibling(); - - nsIFrame* lastBlock = FindLastBlock(afterFirstBlock); - if (! lastBlock) - lastBlock = list2; - - nsIFrame* list3 = lastBlock->GetNextSibling(); - lastBlock->SetNextSibling(nsnull); - - // Create "special" inline-block linkage between the frames - // XXXldb Do we really need to do this? It doesn't seem - // consistent with the use in ConstructInline. - SetFrameIsSpecial(list1, list2); - SetFrameIsSpecial(list2, list3); - if (list3) { - SetFrameIsSpecial(list3, nsnull); - } - - // Recursively split inlines back up to the first containing - // block frame. - SplitToContainingBlock(state, parentFrame, list1, list2, list3, - PR_FALSE); - } - } else if (listName == nsLayoutAtoms::absoluteList) { - newFrame = state.mAbsoluteItems.childList; - state.mAbsoluteItems.childList = nsnull; - } else if (listName == nsLayoutAtoms::fixedList) { - newFrame = state.mFixedItems.childList; - state.mFixedItems.childList = nsnull; - } else if (listName == nsLayoutAtoms::floatList) { - newFrame = state.mFloatedItems.childList; - state.mFloatedItems.childList = nsnull; - } - DeletingFrameSubtree(state.mPresContext, mPresShell, - state.mFrameManager, aFrame); - state.mFrameManager->ReplaceFrame(parentFrame, listName, aFrame, - newFrame); - - // Reset the primary frame mapping. Don't assume that - // ConstructFrameByDisplayType() has done this - state.mFrameManager->SetPrimaryFrameFor(content, newFrame); - } - } else if (nsHTMLAtoms::input == tag) { - // XXX image INPUT elements are also image frames, but don't throw away the - // image frame, because the frame class has extra logic that is specific to - // INPUT elements - - } else { - NS_ASSERTION(PR_FALSE, "unexpected tag"); - } - - return rv; -} - nsresult nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell* aPresShell, nsPresContext* aPresContext, @@ -13213,265 +12945,6 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, } -/* - * Recursively split an inline frame until we reach a block frame. - * Below is an example of how SplitToContainingBlock() works. - * - * 1. In the initial state, you've got a block frame |B| that contains - * a bunch of inline frames eventually winding down to the - * frame |o|. (Block frames are indicated with upper case letters, - * inline frames are indicated with lower case.) - * - * A-->B-->C - * | - * i-->j-->k - * | - * l-->m-->n - * | - * o - * - * 2. Now the object frame |o| gets split into the left inlines |o|, - * the block frames |O|, and the right inlines |o'|. - * - * o O o' - * - * 3. We call SplitToContainingBlock(), which will split |m| as follows. - * - * .--------. - * / \ - * l-->m==>M==>m' n - * | | | - * o O o' - * - * Note that |m| gets split into |M| and |m'|, which correspond to - * the anonymous block and inline frames, - * respectively. Furthermore, note that |m| still refers to |n| as - * its next sibling, and that |m'| does not yet have a next sibling. - * - * The double-arrow line indicates that an annotation is made in - * the frame manager that indicates |M| is the ``special sibling'' - * of |m|, and that |m'| is the ``special sibling'' of |M|. - * - * 4. We recurse again to split |j|. At this point, we'll break the - * link between |m| and |n|, and make |n| be the next sibling of - * |m'|. - * - * .-----------. - * / \ - * i-->j=====>J==>j' k - * | | | - * l-->m=>M==>m'-->n - * | | | - * o O o' - * - * As before, |j| retains |k| as its next sibling, and |j'| is not - * yet assigned its next sibling. - * - * 5. When we hit B, the recursion terminates. We now insert |J| and - * |j'| immediately after |j|, resulting in the following frame - * model. This is done using the "normal" frame insertion - * mechanism, nsIFrame::InsertFrames(), which properly recomputes - * the line boxes. - * - * A-->B-->C - * | - * i-->j-=-=-=>J-=->j'-->k - * | | | - * l-->m==>M===>m'-->n - * | | | - * o O o' - * - * Since B is a block, it is allowed to contain both block and - * inline frames, so we can let |J| and |j'| be "real siblings" of - * |j|. - * - * Note that |J| is both the ``normal'' sibling and ``special'' - * sibling of |j|, and |j'| is both the ``normal'' and ``special'' - * sibling of |J|. - */ -nsresult -nsCSSFrameConstructor::SplitToContainingBlock(nsFrameConstructorState& aState, - nsIFrame* aFrame, - nsIFrame* aLeftInlineChildFrame, - nsIFrame* aBlockChildFrame, - nsIFrame* aRightInlineChildFrame, - PRBool aTransfer) -{ - // If aFrame is an inline frame, then recursively "split" it until - // we reach a block frame. aLeftInlineChildFrame is the original - // inline child of aFrame (or null, if there were no frames to the - // left of the new block); aBlockChildFrame and - // aRightInlineChildFrame are the newly created frames that were - // constructed as a result of the previous recursion's - // "split". aRightInlineChildFrame may be null if there are no - // inlines to the right of the new block. - // - // aBlockChildFrame and aRightInlineChildFrame will be "orphaned" frames upon - // entry to this routine; that is, they won't be parented. We'll - // assign them proper parents. - NS_PRECONDITION(aFrame != nsnull, "no frame to split"); - if (! aFrame) - return NS_ERROR_NULL_POINTER; - - NS_PRECONDITION(aBlockChildFrame != nsnull, "no block child"); - if (! aBlockChildFrame) - return NS_ERROR_NULL_POINTER; - - if (IsBlockFrame(aFrame)) { - // If aFrame is a block frame, then we're done: make - // aBlockChildFrame and aRightInlineChildFrame children of aFrame, - // and insert aBlockChildFrame and aRightInlineChildFrame after - // aLeftInlineChildFrame - aBlockChildFrame->SetParent(aFrame); - - if (aRightInlineChildFrame) - aRightInlineChildFrame->SetParent(aFrame); - - aBlockChildFrame->SetNextSibling(aRightInlineChildFrame); - aFrame->InsertFrames(nsnull, aLeftInlineChildFrame, aBlockChildFrame); - - // If aLeftInlineChild has a view... - if (aLeftInlineChildFrame && aLeftInlineChildFrame->HasView()) { - // ...create a new view for the block child, and reparent views - // XXXbz should we be passing in a non-null aContentParentFrame? - // force creation of a view; it'll probably need one anyway since it - // has the same style context, and it's easier to think about if we can - // be sure the left inlines, the block and the right inlines all have a view - nsHTMLContainerFrame::CreateViewForFrame(aBlockChildFrame, nsnull, PR_TRUE); - - nsIFrame* frame = aBlockChildFrame->GetFirstChild(nsnull); - nsHTMLContainerFrame::ReparentFrameViewList(aState.mPresContext, frame, - aLeftInlineChildFrame, - aBlockChildFrame); - - if (aRightInlineChildFrame) { - // Same for the right inline children - // XXXbz should we be passing in a non-null aContentParentFrame? - nsHTMLContainerFrame::CreateViewForFrame(aRightInlineChildFrame, - nsnull, PR_TRUE); - - frame = aRightInlineChildFrame->GetFirstChild(nsnull); - nsHTMLContainerFrame::ReparentFrameViewList(aState.mPresContext, frame, - aLeftInlineChildFrame, - aRightInlineChildFrame); - } - } - - return NS_OK; - } - - // Otherwise, aFrame is inline. Split it, and recurse to find the - // containing block frame. - nsIContent* content = aFrame->GetContent(); - - // Create an "anonymous block" frame that will parent - // aBlockChildFrame. The new frame won't have a parent yet: the recursion - // will parent it. - nsIFrame* blockFrame; - NS_NewBlockFrame(mPresShell, &blockFrame); - if (! blockFrame) - return NS_ERROR_OUT_OF_MEMORY; - - nsStyleContext* styleContext = aFrame->GetStyleContext(); - - nsRefPtr blockSC; - blockSC = mPresShell->StyleSet()-> - ResolvePseudoStyleFor(content, nsCSSAnonBoxes::mozAnonymousBlock, - styleContext); - - InitAndRestoreFrame(aState, content, nsnull, blockSC, nsnull, blockFrame, - PR_FALSE); - - blockFrame->SetInitialChildList(aState.mPresContext, nsnull, aBlockChildFrame); - MoveChildrenTo(aState.mFrameManager, blockSC, blockFrame, aBlockChildFrame, - nsnull); - - // Create an anonymous inline frame that will parent - // aRightInlineChildFrame. The new frame won't have a parent yet: - // the recursion will parent it. - // XXXldb Why bother if |aRightInlineChildFrame| is null? - nsIFrame* inlineFrame = nsnull; - NS_NewInlineFrame(mPresShell, &inlineFrame); - if (! inlineFrame) - return NS_ERROR_OUT_OF_MEMORY; - - InitAndRestoreFrame(aState, content, nsnull, styleContext, nsnull, - inlineFrame, PR_FALSE); - - inlineFrame->SetInitialChildList(aState.mPresContext, nsnull, - aRightInlineChildFrame); - MoveChildrenTo(aState.mFrameManager, nsnull, inlineFrame, - aRightInlineChildFrame, nsnull); - - // Make the "special" inline-block linkage between aFrame and the - // newly created anonymous frames. We need to create the linkage - // between the first in flow, so if we're a continuation frame, walk - // back to find it. - nsIFrame* firstInFlow = aFrame->GetFirstInFlow(); - - SetFrameIsSpecial(firstInFlow, blockFrame); - SetFrameIsSpecial(blockFrame, inlineFrame); - SetFrameIsSpecial(inlineFrame, nsnull); - - MarkIBSpecialPrevSibling(aState.mPresContext, blockFrame, firstInFlow); - - // If we have a continuation frame, then we need to break the - // continuation. - nsIFrame* nextInFlow = aFrame->GetNextInFlow(); - if (nextInFlow) { - aFrame->SetNextInFlow(nsnull); - nextInFlow->SetPrevInFlow(nsnull); - } - - // This is where the mothership lands and we start to get a bit - // funky. We're going to do a bit of work to ensure that the frames - // from the *last* recursion are properly hooked up. - // - // aTransfer will be set once the recursion begins to nest. (It's - // not set at the first level of recursion, because - // aLeftInlineChildFrame, aBlockChildFrame, and - // aRightInlineChildFrame already have their sibling and parent - // pointers properly initialized.) - // - // Once we begin to nest recursion, aLeftInlineChildFrame - // corresponds to the original inline that we're trying to split, - // and aBlockChildFrame and aRightInlineChildFrame are the anonymous - // frames we created to protect the inline-block invariant. - if (aTransfer) { - // We'd better have the left- and right-inline children! - NS_ASSERTION(aLeftInlineChildFrame != nsnull, "no left inline child frame"); - NS_ASSERTION(aRightInlineChildFrame != nsnull, "no right inline child frame"); - - // We need to move any successors of the original inline - // (aLeftInlineChildFrame) to aRightInlineChildFrame. - nsIFrame* nextInlineFrame = aLeftInlineChildFrame->GetNextSibling(); - aLeftInlineChildFrame->SetNextSibling(nsnull); - aRightInlineChildFrame->SetNextSibling(nextInlineFrame); - - // Any frame that was moved will need its parent pointer fixed, - // and will need to be marked as dirty. - while (nextInlineFrame) { - nextInlineFrame->SetParent(inlineFrame); - nextInlineFrame->AddStateBits(NS_FRAME_IS_DIRTY); - nextInlineFrame = nextInlineFrame->GetNextSibling(); - } - } - - // Recurse to the parent frame. This will assign a parent frame to - // each new frame we've just created. - nsIFrame* parent = aFrame->GetParent(); - - NS_ASSERTION(parent != nsnull, "frame has no geometric parent"); - if (! parent) - return NS_ERROR_FAILURE; - - // When we recur, we'll make the "left inline child frame" be the - // inline frame we've just begun to "split", and we'll pass the - // newly created anonymous frames as aBlockChildFrame and - // aRightInlineChildFrame. - return SplitToContainingBlock(aState, parent, aFrame, blockFrame, inlineFrame, PR_TRUE); -} - nsresult nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame) { diff --git a/mozilla/layout/base/nsCSSFrameConstructor.h b/mozilla/layout/base/nsCSSFrameConstructor.h index 1d893c9d772..e68efb16ca8 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.h +++ b/mozilla/layout/base/nsCSSFrameConstructor.h @@ -144,9 +144,6 @@ public: void PostRestyleEvent(nsIContent* aContent, nsReStyleHint aRestyleHint, nsChangeHint aMinChangeHint); - // Notification that we were unable to render a replaced element. - nsresult CantRenderReplacedElement(nsIFrame* aFrame); - // Request to create a continuing frame nsresult CreateContinuingFrame(nsPresContext* aPresContext, nsIFrame* aFrame, @@ -232,6 +229,26 @@ private: nsIFrame** aNewTableFrame, nsFrameConstructorState& aState); + /** + * CreateAttributeContent creates a single content/frame combination for an + * |attr(foo)| generated content. + * + * @param aParentContent the parent content for the generated content + * @param aParentFrame the parent frame for the generated frame + * @param aAttrNamespace the namespace of the attribute in question + * @param aAttrName the localname of the attribute + * @param aStyleContext the style context to use + * @param [out] aNewContent the content node we create + * @param [out] aNewFrame the new frame we create + */ + nsresult CreateAttributeContent(nsIContent* aParentContent, + nsIFrame* aParentFrame, + PRInt32 aAttrNamespace, + nsIAtom* aAttrName, + nsStyleContext* aStyleContext, + nsIContent** aNewContent, + nsIFrame** aNewFrame); + nsresult CreateGeneratedFrameFor(nsIFrame* aParentFrame, nsIContent* aContent, nsStyleContext* aStyleContext, @@ -451,12 +468,6 @@ protected: nsIFrame** aPlaceholderFrame); private: - nsresult ConstructAlternateFrame(nsIContent* aContent, - nsStyleContext* aStyleContext, - nsIFrame* aGeometricParent, - nsIFrame* aContentParent, - nsIFrame*& aFrame); - // @param OUT aNewFrame the new radio control frame nsresult ConstructRadioControlFrame(nsIFrame** aNewFrame, nsIContent* aContent, @@ -631,6 +642,20 @@ private: nsIFrame** aFrame, nsStyleContext* aStyleContext); + // A function that can be invoked to create some sort of image frame. + typedef nsresult (* ImageFrameCreatorFunc)(nsIPresShell*, nsIFrame**); + + /** + * CreateHTMLImageFrame will do some tests on aContent, and if it determines + * that the content should get an image frame it'll create one via aFunc and + * return it in *aFrame. Note that if this content node isn't supposed to + * have an image frame this method will return NS_OK and set *aFrame to null. + */ + nsresult CreateHTMLImageFrame(nsIContent* aContent, + nsStyleContext* aStyleContext, + ImageFrameCreatorFunc aFunc, + nsIFrame** aFrame); + nsresult AddDummyFrameToSelect(nsFrameConstructorState& aState, nsIFrame* aListFrame, nsIFrame* aParentFrame, @@ -788,13 +813,6 @@ private: nsIFrame*& aPrevSibling, nsIFrame* aNextSibling); - nsresult SplitToContainingBlock(nsFrameConstructorState& aState, - nsIFrame* aFrame, - nsIFrame* aLeftInlineChildFrame, - nsIFrame* aBlockChildFrame, - nsIFrame* aRightInlineChildFrame, - PRBool aTransfer); - nsresult ReframeContainingBlock(nsIFrame* aFrame); nsresult StyleChangeReflow(nsIFrame* aFrame, nsIAtom* aAttribute); diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index 68ebd6bf1f5..464396ef03f 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -392,6 +392,8 @@ public: * instead render the element's contents. * The content object associated with aFrame should either be a IMG * element, an OBJECT element, or an APPLET element + * XXXbz this should just go away once object loading moves to + * content, since nsObjectFrame is the only caller at this point. */ NS_IMETHOD CantRenderReplacedElement(nsIFrame* aFrame) = 0; diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 22db097d959..2ce1d2350f1 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -3916,9 +3916,10 @@ CantRenderReplacedElementEvent::HandleEvent() } // Make sure to prevent reflow while we're messing with frames - ++presShell->mChangeNestCount; - presShell->FrameConstructor()->CantRenderReplacedElement(mFrame); - --presShell->mChangeNestCount; + mozAutoDocUpdate(presShell->mDocument, UPDATE_CONTENT_STATE, PR_TRUE); + presShell->mDocument->ContentStatesChanged(mFrame->GetContent(), + nsnull, + NS_EVENT_STATE_BROKEN); } CantRenderReplacedElementEvent** diff --git a/mozilla/layout/base/nsStyleConsts.h b/mozilla/layout/base/nsStyleConsts.h index 2a9de3078fb..69ec36db6ac 100644 --- a/mozilla/layout/base/nsStyleConsts.h +++ b/mozilla/layout/base/nsStyleConsts.h @@ -267,11 +267,12 @@ #define NS_STYLE_CLEAR_PAGE 7 #define NS_STYLE_CLEAR_LAST_VALUE NS_STYLE_CLEAR_PAGE -// See +// See nsStyleContent #define NS_STYLE_CONTENT_OPEN_QUOTE 0 #define NS_STYLE_CONTENT_CLOSE_QUOTE 1 #define NS_STYLE_CONTENT_NO_OPEN_QUOTE 2 #define NS_STYLE_CONTENT_NO_CLOSE_QUOTE 3 +#define NS_STYLE_CONTENT_ALT_CONTENT 4 // See nsStyleColor #define NS_STYLE_CURSOR_AUTO 1 diff --git a/mozilla/layout/generic/nsImageFrame.cpp b/mozilla/layout/generic/nsImageFrame.cpp index 5df9975d442..7825e4f1c39 100644 --- a/mozilla/layout/generic/nsImageFrame.cpp +++ b/mozilla/layout/generic/nsImageFrame.cpp @@ -102,7 +102,7 @@ #include "nsIContentPolicy.h" #include "nsContentPolicyUtils.h" - +#include "nsIEventStateManager.h" #include "nsLayoutErrors.h" #ifdef DEBUG @@ -296,24 +296,14 @@ nsImageFrame::Init(nsPresContext* aPresContext, if (!gIconLoad) LoadIcons(aPresContext); + // Give image loads associated with an image frame a small priority boost! nsCOMPtr currentRequest; imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, getter_AddRefs(currentRequest)); - PRUint32 currentLoadStatus = imgIRequest::STATUS_ERROR; - if (currentRequest) { - currentRequest->GetImageStatus(¤tLoadStatus); + nsCOMPtr p = do_QueryInterface(currentRequest); + if (p) + p->AdjustPriority(-1); - // Give image loads associated with an image frame a small priority boost! - nsCOMPtr p = do_QueryInterface(currentRequest); - if (p) - p->AdjustPriority(-1); - } - - if (currentLoadStatus & imgIRequest::STATUS_ERROR) { - PRInt16 imageStatus = nsIContentPolicy::ACCEPT; - imageLoader->GetImageBlockingStatus(&imageStatus); - rv = HandleLoadError(imageStatus); - } // If we already have an image container, OnStartContainer won't be called // Set the animation mode here if (currentRequest) { @@ -447,27 +437,26 @@ nsImageFrame::SourceRectToDest(const nsRect& aRect) return r; } -nsresult -nsImageFrame::HandleLoadError(PRInt16 aImageStatus) +static PRBool +ImageOK(nsIContent* aContent) { - if (!NS_CP_ACCEPTED(aImageStatus) && - aImageStatus == nsIContentPolicy::REJECT_SERVER) { - // Don't display any alt feedback in this case; we're blocking images - // from that site and don't care to see anything from them - return NS_OK; - } - - // If we have an image map, don't do anything here - // XXXbz Why? This is what the code used to do, but there's no good - // reason for it.... + // Note that we treat NS_EVENT_STATE_SUPPRESSED images as "OK". This means + // that we'll construct image frames for them as needed if their display is + // toggled from "none" (though we won't paint them, unless their visibility + // is changed too). + return !(aContent->IntrinsicState() & + (NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED)); +} - nsAutoString usemap; - mContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::usemap, usemap); - if (!usemap.IsEmpty()) { - return NS_OK; +/* static */ +PRBool +nsImageFrame::ShouldCreateImageFrameFor(nsIContent* aContent, + nsStyleContext* aStyleContext) +{ + if (ImageOK(aContent)) { + // Image is fine; do the image frame thing + return PR_TRUE; } - - nsPresContext* presContext = GetPresContext(); // Check if we want to use a placeholder box with an icon or just // let the the presShell make us into inline text. Decide as follows: @@ -478,68 +467,43 @@ nsImageFrame::HandleLoadError(PRInt16 aImageStatus) // - if QuirksMode, and there is no alt attribute, and this is not an // (which could not possibly have such an attribute), show an // icon. - // - if QuirksMode, and the IMG has a size, and the image is - // broken, not blocked, show an icon. + // - if QuirksMode, and the IMG has a size show an icon. // - otherwise, skip the icon - PRBool useSizedBox; - const nsStyleUIReset* uiResetData = GetStyleUIReset(); - if (uiResetData->mForceBrokenImageIcon) { + if (aStyleContext->GetStyleUIReset()->mForceBrokenImageIcon) { useSizedBox = PR_TRUE; } else if (gIconLoad && gIconLoad->mPrefForceInlineAltText) { useSizedBox = PR_FALSE; } else { - if (presContext->CompatibilityMode() != eCompatibility_NavQuirks) { + if (aStyleContext->PresContext()->CompatibilityMode() != + eCompatibility_NavQuirks) { useSizedBox = PR_FALSE; } else { // We are in quirks mode, so we can just check the tag name; no need to // check the namespace. - nsINodeInfo *nodeInfo = mContent->GetNodeInfo(); + nsINodeInfo *nodeInfo = aContent->GetNodeInfo(); - if (!mContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::alt) && + // Use a sized box if we have no alt text. This means no alt attribute + // and the node is not an object or an input (since those always have alt + // text). + if (!aContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::alt) && nodeInfo && - !nodeInfo->Equals(nsHTMLAtoms::object)) { + !nodeInfo->Equals(nsHTMLAtoms::object) && + !nodeInfo->Equals(nsHTMLAtoms::input)) { useSizedBox = PR_TRUE; } - else if (!NS_CP_ACCEPTED(aImageStatus)) { - useSizedBox = PR_FALSE; - } else { // check whether we have fixed size - useSizedBox = HaveFixedSize(GetStylePosition()); + useSizedBox = HaveFixedSize(aStyleContext->GetStylePosition()); } } } - if (!useSizedBox) { - // let the presShell handle converting this into the inline alt - // text frame - nsIFrame* primaryFrame = nsnull; - if (mContent->IsContentOfType(nsIContent::eHTML) && - (mContent->Tag() == nsHTMLAtoms::object || - mContent->Tag() == nsHTMLAtoms::embed)) { - // We have to try to get the primary frame for mContent, since for - // the frame CantRenderReplacedElement wants is the - // ObjectFrame, not us (we're an anonymous frame then).... - primaryFrame = presContext->PresShell()->GetPrimaryFrameFor(mContent); - } - - if (!primaryFrame) { - primaryFrame = this; - } - - presContext->PresShell()->CantRenderReplacedElement(primaryFrame); - return NS_ERROR_FRAME_REPLACED; - } - - // we are handling it - // invalidate the icon area (it may change states) - InvalidateIcon(); - return NS_OK; + return useSizedBox; } nsresult @@ -691,15 +655,6 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest, } } - // if src failed to load, determine how to handle it: - // - either render the ALT text in this frame, or let the presShell - // handle it - if (NS_FAILED(aStatus) && aStatus != NS_ERROR_IMAGE_SRC_CHANGED) { - PRInt16 imageStatus = nsIContentPolicy::ACCEPT; - imageLoader->GetImageBlockingStatus(&imageStatus); - HandleLoadError(imageStatus); - } - return NS_OK; } @@ -1311,7 +1266,7 @@ nsImageFrame::Paint(nsPresContext* aPresContext, if (mComputedSize.width != 0 && mComputedSize.height != 0) { nsCOMPtr imageLoader = do_QueryInterface(mContent); - NS_ASSERTION(mContent, "Not an image loading content?"); + NS_ASSERTION(imageLoader, "Not an image loading content?"); nsCOMPtr currentRequest; if (imageLoader) { @@ -1319,31 +1274,21 @@ nsImageFrame::Paint(nsPresContext* aPresContext, getter_AddRefs(currentRequest)); } + PRBool imageOK = ImageOK(mContent); + nsCOMPtr imgCon; - - PRUint32 loadStatus = imgIRequest::STATUS_ERROR; - if (currentRequest) { currentRequest->GetImage(getter_AddRefs(imgCon)); - currentRequest->GetImageStatus(&loadStatus); } - if (loadStatus & imgIRequest::STATUS_ERROR || !imgCon) { + if (!imageOK || !imgCon) { // No image yet, or image load failed. Draw the alt-text and an icon - // indicating the status (unless image is blocked, in which case we show nothing) + // indicating the status - PRInt16 imageStatus = nsIContentPolicy::ACCEPT; - if (imageLoader) { - imageLoader->GetImageBlockingStatus(&imageStatus); - } - - if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer && - (NS_CP_ACCEPTED(imageStatus) || - imageStatus != nsIContentPolicy::REJECT_SERVER)) { + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { DisplayAltFeedback(aPresContext, aRenderingContext, - (loadStatus & imgIRequest::STATUS_ERROR) - ? gIconLoad->mBrokenImage - : gIconLoad->mLoadingImage); + imageOK ? gIconLoad->mLoadingImage + : gIconLoad->mBrokenImage); } } else { @@ -1983,23 +1928,6 @@ PRBool nsImageFrame::HandleIconLoads(imgIRequest* aRequest, PRBool aLoaded) return result; } -void nsImageFrame::InvalidateIcon() -{ - // invalidate the inner area, where the icon lives - - nsPresContext *presContext = GetPresContext(); - float p2t = presContext->ScaledPixelsToTwips(); - nsRect inner = GetInnerArea(); - - nsRect rect(inner.x, - inner.y, - NSIntPixelsToTwips(ICON_SIZE+ICON_PADDING, p2t), - NSIntPixelsToTwips(ICON_SIZE+ICON_PADDING, p2t)); - NS_ASSERTION(!rect.IsEmpty(), "icon rect cannot be empty!"); - // update image area - Invalidate(rect, PR_FALSE); -} - NS_IMPL_ISUPPORTS1(nsImageFrame::IconLoad, nsIObserver) static const char kIconLoadPrefs[][40] = { diff --git a/mozilla/layout/generic/nsImageFrame.h b/mozilla/layout/generic/nsImageFrame.h index 7d773e936c0..fc2843a5efa 100644 --- a/mozilla/layout/generic/nsImageFrame.h +++ b/mozilla/layout/generic/nsImageFrame.h @@ -141,6 +141,14 @@ public: NS_IF_RELEASE(sIOService); } + /** + * Function to test whether aContent, which has aStyleContext as its style, + * should get an image frame. Note that this method is only used by the + * frame constructor; it's only here because it uses gIconLoad for now. + */ + static PRBool ShouldCreateImageFrameFor(nsIContent* aContent, + nsStyleContext* aStyleContext); + protected: // nsISupports NS_IMETHOD_(nsrefcnt) AddRef(void); @@ -231,14 +239,6 @@ private: */ nsRect SourceRectToDest(const nsRect & aRect); - /** - * Function to call when a load fails; this handles things like alt - * text, broken image icons, etc. Returns NS_ERROR_FRAME_REPLACED - * if it called CantRenderReplacedElement, NS_OK otherwise. - * @param aImageStatus the status of the image (@see nsIContentPolicy) - */ - nsresult HandleLoadError(PRInt16 aImageStatus); - nsImageMap* mImageMap; nsCOMPtr mListener; @@ -267,7 +267,6 @@ private: // is, handle it and return TRUE otherwise, return FALSE (aCompleted // is an input arg telling the routine if the request has completed) PRBool HandleIconLoads(imgIRequest* aRequest, PRBool aCompleted); - void InvalidateIcon(); class IconLoad : public nsIObserver { // private class that wraps the data and logic needed for diff --git a/mozilla/layout/generic/nsObjectFrame.cpp b/mozilla/layout/generic/nsObjectFrame.cpp index 4f1aeaed22a..2ac6566b7ae 100644 --- a/mozilla/layout/generic/nsObjectFrame.cpp +++ b/mozilla/layout/generic/nsObjectFrame.cpp @@ -127,6 +127,8 @@ #include "nsIClassInfo.h" #include "jsapi.h" +#include "nsCSSPseudoClasses.h" + // XXX For temporary paint code #include "nsStyleContext.h" @@ -662,6 +664,10 @@ nsObjectFrame::Init(nsPresContext* aPresContext, rv = aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, data); imageLoader->ImageURIChanged(data); + // Let the content know that it's actually loading an image. + // XXXbz this is a bit of a hack, pending moving object data + // loading to content. + aContent->SetProperty(nsLayoutAtoms::imageFrame, NS_INT32_TO_PTR(1)); nsIFrame * aNewFrame = nsnull; rv = NS_NewImageFrame(aPresContext->PresShell(), &aNewFrame); @@ -708,6 +714,9 @@ nsObjectFrame::Destroy(nsPresContext* aPresContext) { NS_ASSERTION(!mInstantiating, "about to crash due to bug 136927"); + // Note: we don't want to unset the broken property here, since that would + // cause frame construction to just try constructing an object frame again... + // we need to finish with the plugin before native window is destroyed // doing this in the destructor is too late. if (mInstanceOwner != nsnull) { @@ -1251,16 +1260,17 @@ nsObjectFrame::Reflow(nsPresContext* aPresContext, // finish up if (NS_FAILED(rv)) { - // if we got an error, we are probably going to be replaced + // XXXbz A bit of a hack with the property name, but that's ok. + // biesi's moving this stuff into content anyway. ;) + mContent->SetProperty(nsCSSPseudoClasses::mozBroken, + NS_INT32_TO_PTR(1)); - // for a replaced object frame, clear our vertical alignment style info, see bug 36997 - nsStyleTextReset* text = NS_STATIC_CAST(nsStyleTextReset*, - mStyleContext->GetUniqueStyleData(eStyleStruct_TextReset)); - text->mVerticalAlign.SetNormalValue(); - - //check for alternative content with CantRenderReplacedElement() + // check for alternative content with CantRenderReplacedElement() rv = aPresContext->PresShell()->CantRenderReplacedElement(this); } else { + // XXXbz can't quite unset the property here, since that would + // actually clobber it on nodes that are supposed to have it! Not + // sure why... NotifyContentObjectWrapper(); } diff --git a/mozilla/layout/style/html.css b/mozilla/layout/style/html.css index 9cc299cb270..adcdea00ff0 100644 --- a/mozilla/layout/style/html.css +++ b/mozilla/layout/style/html.css @@ -392,6 +392,40 @@ hr[size="1"] { border: 2px solid; } +img:-moz-broken::before, input:-moz-broken::before, +img:-moz-user-disabled::before, input:-moz-user-disabled::before, +/* Nonempty applets should just show their kids. + XXXbz do we need a selector that will ignore elements? */ +applet:empty:-moz-broken::before, +applet:empty:-moz-user-disabled::before { + content: -moz-alt-content !important; +} + +object:-moz-broken, embed:-moz-broken, applet:-moz-broken +object:-moz-user-disabled, embed:-moz-user-disabled, +applet:-moz-user-disabled { + /* + Ideally, we wouldn't map in the align attribute in cases like this, but + that's hard.... So have to use !important to override the preshint. This + can go away once object loading is in content, since then not mapping in + the preshint should be easy. + */ + vertical-align: normal !important; +} + +img:-moz-suppressed, input:-moz-suppressed, object:-moz-suppressed, +embed:-moz-suppressed, applet:-moz-suppressed { + /* + Set visibility too in case the page changes display. Note that we _may_ + want to just set visibility and not display, in general, if we find that + display:none breaks too many layouts. And if we decide we really do want + people to be able to right-click blocked images, etc, we need to set + neither one, and hack the painting code.... :( + */ + display: none !important; + visibility: hidden !important; +} + img[usemap], object[usemap] { cursor: pointer; color: blue; diff --git a/mozilla/layout/style/nsCSSKeywordList.h b/mozilla/layout/style/nsCSSKeywordList.h index fcf6a6f9bee..d1227b42b70 100644 --- a/mozilla/layout/style/nsCSSKeywordList.h +++ b/mozilla/layout/style/nsCSSKeywordList.h @@ -68,6 +68,7 @@ CSS_KEY(-moz-activehyperlinktext, _moz_activehyperlinktext) CSS_KEY(-moz-alias, _moz_alias) CSS_KEY(-moz-all, _moz_all) +CSS_KEY(-moz-alt-content, _moz_alt_content) CSS_KEY(-moz-anchor-decoration, _moz_anchor_decoration) CSS_KEY(-moz-arabic-indic, _moz_arabic_indic) CSS_KEY(-moz-bengali, _moz_bengali) diff --git a/mozilla/layout/style/nsCSSParser.cpp b/mozilla/layout/style/nsCSSParser.cpp index ded9d0a48a1..260a2f4c59d 100644 --- a/mozilla/layout/style/nsCSSParser.cpp +++ b/mozilla/layout/style/nsCSSParser.cpp @@ -5210,11 +5210,16 @@ PRBool CSSParserImpl::ParseContent(nsresult& aErrorCode) } if (eCSSUnit_Inherit == value.GetUnit() || eCSSUnit_Initial == value.GetUnit() || - eCSSUnit_Normal == value.GetUnit()) { + eCSSUnit_Normal == value.GetUnit() || + (eCSSUnit_Enumerated == value.GetUnit() && + NS_STYLE_CONTENT_ALT_CONTENT == value.GetIntValue())) { // This only matters the first time through the loop. return PR_FALSE; } - if (ParseVariant(aErrorCode, value, VARIANT_CONTENT, nsCSSProps::kContentKTable)) { + if (ParseVariant(aErrorCode, value, VARIANT_CONTENT, nsCSSProps::kContentKTable) && + // Make sure we didn't end up with NS_STYLE_CONTENT_ALT_CONTENT here + (value.GetUnit() != eCSSUnit_Enumerated || + value.GetIntValue() != NS_STYLE_CONTENT_ALT_CONTENT)) { list->mNext = new nsCSSValueList(); list = list->mNext; if (nsnull != list) { diff --git a/mozilla/layout/style/nsCSSProps.cpp b/mozilla/layout/style/nsCSSProps.cpp index 24ed33070fc..4ef627eba50 100644 --- a/mozilla/layout/style/nsCSSProps.cpp +++ b/mozilla/layout/style/nsCSSProps.cpp @@ -447,6 +447,7 @@ const PRInt32 nsCSSProps::kContentKTable[] = { eCSSKeyword_close_quote, NS_STYLE_CONTENT_CLOSE_QUOTE, eCSSKeyword_no_open_quote, NS_STYLE_CONTENT_NO_OPEN_QUOTE, eCSSKeyword_no_close_quote, NS_STYLE_CONTENT_NO_CLOSE_QUOTE, + eCSSKeyword__moz_alt_content, NS_STYLE_CONTENT_ALT_CONTENT, eCSSKeyword_UNKNOWN,-1 }; diff --git a/mozilla/layout/style/nsCSSPseudoClassList.h b/mozilla/layout/style/nsCSSPseudoClassList.h index e40e0cd183d..0230cba1061 100644 --- a/mozilla/layout/style/nsCSSPseudoClassList.h +++ b/mozilla/layout/style/nsCSSPseudoClassList.h @@ -76,6 +76,11 @@ CSS_PSEUDO_CLASS(lastChild, ":last-child") CSS_PSEUDO_CLASS(lastNode, ":-moz-last-node") CSS_PSEUDO_CLASS(onlyChild, ":only-child") +// Image, object, etc state pseudo-classes +CSS_PSEUDO_CLASS(mozBroken, ":-moz-broken") +CSS_PSEUDO_CLASS(mozUserDisabled, ":-moz-user-disabled") +CSS_PSEUDO_CLASS(mozSuppressed, ":-moz-suppressed") + // CSS 3 UI // http://www.w3.org/TR/2004/CR-css3-ui-20040511/#pseudo-classes CSS_PSEUDO_CLASS(required, ":required") diff --git a/mozilla/layout/style/nsCSSStyleSheet.cpp b/mozilla/layout/style/nsCSSStyleSheet.cpp index 9b30541c0ed..bf9f7bb607a 100644 --- a/mozilla/layout/style/nsCSSStyleSheet.cpp +++ b/mozilla/layout/style/nsCSSStyleSheet.cpp @@ -3134,6 +3134,15 @@ static PRBool SelectorMatches(RuleProcessorData &data, } else if (nsCSSPseudoClasses::disabled == pseudoClass->mAtom) { result = STATE_CHECK(NS_EVENT_STATE_DISABLED); + } + else if (nsCSSPseudoClasses::mozBroken == pseudoClass->mAtom) { + result = STATE_CHECK(NS_EVENT_STATE_BROKEN); + } + else if (nsCSSPseudoClasses::mozUserDisabled == pseudoClass->mAtom) { + result = STATE_CHECK(NS_EVENT_STATE_USERDISABLED); + } + else if (nsCSSPseudoClasses::mozSuppressed == pseudoClass->mAtom) { + result = STATE_CHECK(NS_EVENT_STATE_SUPPRESSED); } else if (nsCSSPseudoClasses::required == pseudoClass->mAtom) { result = STATE_CHECK(NS_EVENT_STATE_REQUIRED); @@ -3670,6 +3679,9 @@ PRBool IsStateSelector(nsCSSSelector& aSelector) (pseudoClass->mAtom == nsCSSPseudoClasses::visited) || (pseudoClass->mAtom == nsCSSPseudoClasses::enabled) || (pseudoClass->mAtom == nsCSSPseudoClasses::disabled) || + (pseudoClass->mAtom == nsCSSPseudoClasses::mozBroken) || + (pseudoClass->mAtom == nsCSSPseudoClasses::mozUserDisabled) || + (pseudoClass->mAtom == nsCSSPseudoClasses::mozSuppressed) || (pseudoClass->mAtom == nsCSSPseudoClasses::required) || (pseudoClass->mAtom == nsCSSPseudoClasses::optional) || (pseudoClass->mAtom == nsCSSPseudoClasses::valid) || diff --git a/mozilla/layout/style/nsRuleNode.cpp b/mozilla/layout/style/nsRuleNode.cpp index bb15a2349ae..d4f8678a89d 100644 --- a/mozilla/layout/style/nsRuleNode.cpp +++ b/mozilla/layout/style/nsRuleNode.cpp @@ -4228,6 +4228,8 @@ nsRuleNode::ComputeContentData(nsStyleStruct* aStartStruct, type = eStyleContentType_NoOpenQuote; break; case NS_STYLE_CONTENT_NO_CLOSE_QUOTE: type = eStyleContentType_NoCloseQuote; break; + case NS_STYLE_CONTENT_ALT_CONTENT: + type = eStyleContentType_AltContent; break; default: NS_ERROR("bad content value"); } diff --git a/mozilla/layout/style/nsStyleStruct.h b/mozilla/layout/style/nsStyleStruct.h index 85fd7adaaca..8a696c56b9b 100644 --- a/mozilla/layout/style/nsStyleStruct.h +++ b/mozilla/layout/style/nsStyleStruct.h @@ -913,7 +913,8 @@ enum nsStyleContentType { eStyleContentType_OpenQuote = 40, eStyleContentType_CloseQuote = 41, eStyleContentType_NoOpenQuote = 42, - eStyleContentType_NoCloseQuote = 43 + eStyleContentType_NoCloseQuote = 43, + eStyleContentType_AltContent = 50 }; struct nsStyleContentData {