Implement :-moz-broken, :-moz-user-disabled, and :-moz-suppressed

pseudo-classes to allow styling of broken/blocked/disabled images, applets,
objects, embeds.  Bug 11011, r=biesi and roc, sr=dbaron
This commit is contained in:
bzbarsky%mit.edu 2005-09-18 18:05:40 +00:00
Родитель f41157f8c0
Коммит 608088a431
27 изменённых файлов: 646 добавлений и 941 удалений

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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<imgIRequest> & 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<imgIRequest> & req = mCurrentRequest ? mPendingRequest : mCurrentRequest;
nsCOMPtr<nsIContent> 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 <object> 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<nsIContent> 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(&currentLoadStatus);
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

Просмотреть файл

@ -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 <input> 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__

Просмотреть файл

@ -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__

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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)

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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();
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;

Просмотреть файл

@ -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**

Просмотреть файл

@ -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

Просмотреть файл

@ -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<imgIRequest> currentRequest;
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(currentRequest));
PRUint32 currentLoadStatus = imgIRequest::STATUS_ERROR;
if (currentRequest) {
currentRequest->GetImageStatus(&currentLoadStatus);
nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(currentRequest);
if (p)
p->AdjustPriority(-1);
// Give image loads associated with an image frame a small priority boost!
nsCOMPtr<nsISupportsPriority> 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
// <object> (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
// <object> 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<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
NS_ASSERTION(mContent, "Not an image loading content?");
NS_ASSERTION(imageLoader, "Not an image loading content?");
nsCOMPtr<imgIRequest> currentRequest;
if (imageLoader) {
@ -1319,31 +1274,21 @@ nsImageFrame::Paint(nsPresContext* aPresContext,
getter_AddRefs(currentRequest));
}
PRBool imageOK = ImageOK(mContent);
nsCOMPtr<imgIContainer> 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] = {

Просмотреть файл

@ -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<imgIDecoderObserver> 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

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -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 <param> 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;

Просмотреть файл

@ -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)

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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
};

Просмотреть файл

@ -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")

Просмотреть файл

@ -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) ||

Просмотреть файл

@ -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");
}

Просмотреть файл

@ -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 {