/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are Copyright (C) 1998 * Netscape Communications Corporation. All Rights Reserved. */ #include "nsCOMPtr.h" #include "nsIDOMHTMLBodyElement.h" #include "nsIScriptObjectOwner.h" #include "nsIDOMEventReceiver.h" #include "nsIHTMLContent.h" #include "nsGenericHTMLElement.h" #include "nsHTMLAtoms.h" #include "nsHTMLIIDs.h" #include "nsIStyleContext.h" #include "nsIMutableStyleContext.h" #include "nsStyleConsts.h" #include "nsIPresContext.h" #include "nsIPresShell.h" #include "nsStyleUtil.h" #include "nsIDocument.h" #include "nsIHTMLDocument.h" #include "nsIHTMLStyleSheet.h" #include "nsIHTMLCSSStyleSheet.h" #include "nsICSSStyleRule.h" #include "nsIWebShell.h" #include "nsIHTMLAttributes.h" #include "nsIHTMLContentContainer.h" #include "nsISupportsArray.h" static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID); static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); static NS_DEFINE_IID(kICSSStyleRuleIID, NS_ICSS_STYLE_RULE_IID); static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID); static NS_DEFINE_IID(kIDOMHTMLBodyElementIID, NS_IDOMHTMLBODYELEMENT_IID); static NS_DEFINE_IID(kIHTMLContentContainerIID, NS_IHTMLCONTENTCONTAINER_IID); //---------------------------------------------------------------------- class nsHTMLBodyElement; class BodyRule: public nsIStyleRule { public: BodyRule(nsHTMLBodyElement* aPart, nsIHTMLStyleSheet* aSheet); virtual ~BodyRule(); NS_DECL_ISUPPORTS NS_IMETHOD Equals(const nsIStyleRule* aRule, PRBool& aResult) const; NS_IMETHOD HashValue(PRUint32& aValue) const; NS_IMETHOD GetStyleSheet(nsIStyleSheet*& aSheet) const; // Strength is an out-of-band weighting, always 0 here NS_IMETHOD GetStrength(PRInt32& aStrength) const; NS_IMETHOD MapFontStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext); NS_IMETHOD MapStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext); NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const; nsHTMLBodyElement* mPart; // not ref-counted, cleared by content nsIHTMLStyleSheet* mSheet; // not ref-counted, cleared by content }; //---------------------------------------------------------------------- class BodyFixupRule : public nsIStyleRule { public: BodyFixupRule(nsHTMLBodyElement* aPart, nsIHTMLCSSStyleSheet* aSheet); virtual ~BodyFixupRule(); NS_DECL_ISUPPORTS NS_IMETHOD Equals(const nsIStyleRule* aRule, PRBool& aValue) const; NS_IMETHOD HashValue(PRUint32& aValue) const; NS_IMETHOD GetStyleSheet(nsIStyleSheet*& aSheet) const; // Strength is an out-of-band weighting, always maxint here NS_IMETHOD GetStrength(PRInt32& aStrength) const; NS_IMETHOD MapFontStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext); NS_IMETHOD MapStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext); NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const; nsHTMLBodyElement* mPart; // not ref-counted, cleared by content nsIHTMLCSSStyleSheet* mSheet; // not ref-counted, cleared by content }; //---------------------------------------------------------------------- // special subclass of inner class to override set document class nsBodyInner: public nsGenericHTMLContainerElement { public: nsBodyInner(); virtual ~nsBodyInner(); nsresult SetDocument(nsIDocument* aDocument, PRBool aDeep); BodyRule* mContentStyleRule; BodyFixupRule* mInlineStyleRule; }; nsBodyInner::nsBodyInner() : nsGenericHTMLContainerElement(), mContentStyleRule(nsnull), mInlineStyleRule(nsnull) { } nsBodyInner::~nsBodyInner() { if (nsnull != mContentStyleRule) { mContentStyleRule->mPart = nsnull; mContentStyleRule->mSheet = nsnull; NS_RELEASE(mContentStyleRule); } if (nsnull != mInlineStyleRule) { mInlineStyleRule->mPart = nsnull; mInlineStyleRule->mSheet = nsnull; NS_RELEASE(mInlineStyleRule); } } nsresult nsBodyInner::SetDocument(nsIDocument* aDocument, PRBool aDeep) { if (nsnull != mContentStyleRule) { mContentStyleRule->mPart = nsnull; mContentStyleRule->mSheet = nsnull; NS_RELEASE(mContentStyleRule); // destroy old style rule since the sheet will probably change } if (nsnull != mInlineStyleRule) { mInlineStyleRule->mPart = nsnull; mInlineStyleRule->mSheet = nsnull; NS_RELEASE(mInlineStyleRule); // destroy old style rule since the sheet will probably change } return nsGenericHTMLContainerElement::SetDocument(aDocument, aDeep); } //---------------------------------------------------------------------- class nsHTMLBodyElement : public nsIDOMHTMLBodyElement, public nsIScriptObjectOwner, public nsIDOMEventReceiver, public nsIHTMLContent { public: nsHTMLBodyElement(nsIAtom* aTag); virtual ~nsHTMLBodyElement(); // nsISupports NS_DECL_ISUPPORTS // nsIDOMNode NS_IMPL_IDOMNODE_USING_GENERIC(mInner) // nsIDOMElement NS_IMPL_IDOMELEMENT_USING_GENERIC(mInner) // nsIDOMHTMLElement NS_IMPL_IDOMHTMLELEMENT_USING_GENERIC(mInner) // nsIDOMHTMLBodyElement NS_IMETHOD GetALink(nsString& aALink); NS_IMETHOD SetALink(const nsString& aALink); NS_IMETHOD GetBackground(nsString& aBackground); NS_IMETHOD SetBackground(const nsString& aBackground); NS_IMETHOD GetBgColor(nsString& aBgColor); NS_IMETHOD SetBgColor(const nsString& aBgColor); NS_IMETHOD GetLink(nsString& aLink); NS_IMETHOD SetLink(const nsString& aLink); NS_IMETHOD GetText(nsString& aText); NS_IMETHOD SetText(const nsString& aText); NS_IMETHOD GetVLink(nsString& aVLink); NS_IMETHOD SetVLink(const nsString& aVLink); // nsIScriptObjectOwner NS_IMPL_ISCRIPTOBJECTOWNER_USING_GENERIC(mInner) // nsIDOMEventReceiver NS_IMPL_IDOMEVENTRECEIVER_USING_GENERIC(mInner) // nsIContent NS_IMPL_ICONTENT_USING_GENERIC(mInner) // nsIHTMLContent NS_IMPL_IHTMLCONTENT_USING_GENERIC2(mInner) protected: nsBodyInner mInner; friend class BodyRule; friend class BodyFixupRule; }; //---------------------------------------------------------------------- BodyRule::BodyRule(nsHTMLBodyElement* aPart, nsIHTMLStyleSheet* aSheet) { NS_INIT_REFCNT(); mPart = aPart; mSheet = aSheet; } BodyRule::~BodyRule() { } NS_IMPL_ISUPPORTS(BodyRule, kIStyleRuleIID); NS_IMETHODIMP BodyRule::Equals(const nsIStyleRule* aRule, PRBool& aResult) const { aResult = PRBool(this == aRule); return NS_OK; } NS_IMETHODIMP BodyRule::HashValue(PRUint32& aValue) const { aValue = (PRUint32)(mPart); return NS_OK; } NS_IMETHODIMP BodyRule::GetStyleSheet(nsIStyleSheet*& aSheet) const { NS_IF_ADDREF(mSheet); aSheet = mSheet; return NS_OK; } // Strength is an out-of-band weighting, useful for mapping CSS ! important // always 0 here NS_IMETHODIMP BodyRule::GetStrength(PRInt32& aStrength) const { aStrength = 0; return NS_OK; } NS_IMETHODIMP BodyRule::MapFontStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext) { // set up the basefont (defaults to 3) nsStyleFont* font = (nsStyleFont*)aContext->GetMutableStyleData(eStyleStruct_Font); PRInt32 scaler; aPresContext->GetFontScaler(&scaler); float scaleFactor = nsStyleUtil::GetScalingFactor(scaler); // apply font scaling to the body font->mFont.size = NSToCoordFloor(float(font->mFont.size) * scaleFactor); if (font->mFont.size < 1) { font->mFont.size = 1; } font->mFixedFont.size = NSToCoordFloor(float(font->mFixedFont.size) * scaleFactor); if (font->mFixedFont.size < 1) { font->mFixedFont.size = 1; } return NS_OK; } NS_IMETHODIMP BodyRule::MapStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext) { if (nsnull != mPart) { nsStyleSpacing* styleSpacing = (nsStyleSpacing*)(aContext->GetMutableStyleData(eStyleStruct_Spacing)); if (nsnull != styleSpacing) { nsHTMLValue value; PRInt32 attrCount; float p2t; mPart->GetAttributeCount(attrCount); aPresContext->GetScaledPixelsToTwips(&p2t); nscoord bodyMarginWidth = -1; nscoord bodyMarginHeight = -1; if (0 < attrCount) { // if marginwidth/marginheigth is set reflect them as 'margin' mPart->GetHTMLAttribute(nsHTMLAtoms::marginwidth, value); if (eHTMLUnit_Pixel == value.GetUnit()) { bodyMarginWidth = NSIntPixelsToTwips(value.GetPixelValue(), p2t); if (bodyMarginWidth < 0) { bodyMarginWidth = 0; } nsStyleCoord widthCoord(bodyMarginWidth); styleSpacing->mMargin.SetLeft(widthCoord); styleSpacing->mMargin.SetRight(widthCoord); } mPart->GetHTMLAttribute(nsHTMLAtoms::marginheight, value); if (eHTMLUnit_Pixel == value.GetUnit()) { bodyMarginHeight = NSIntPixelsToTwips(value.GetPixelValue(), p2t); if (bodyMarginHeight < 0) { bodyMarginHeight = 0; } nsStyleCoord heightCoord(bodyMarginHeight); styleSpacing->mMargin.SetTop(heightCoord); styleSpacing->mMargin.SetBottom(heightCoord); } } // XXX This is all pretty hokey... // if marginwidth or marginheight is set in the and not set in the
// reflect them as margin in the if ((0 > bodyMarginWidth) || (0 > bodyMarginHeight)) { nsISupports* container; aPresContext->GetContainer(&container); if (nsnull != container) { nsCompatibility mode; aPresContext->GetCompatibilityMode(&mode); nsIWebShell* webShell = nsnull; container->QueryInterface(kIWebShellIID, (void**) &webShell); if (nsnull != webShell) { nscoord pixel = NSIntPixelsToTwips(1, p2t); nscoord frameMarginWidth, frameMarginHeight; webShell->GetMarginWidth(frameMarginWidth); // -1 indicates not set webShell->GetMarginHeight(frameMarginHeight); if ((frameMarginWidth >= 0) && (0 > bodyMarginWidth)) { // set in & not in if (eCompatibility_NavQuirks == mode) { // allow 0 margins if ((0 > bodyMarginHeight) && (0 > frameMarginHeight)) { // another nav quirk frameMarginHeight = 0; } } else { // margins are at least 1 pixel if (0 == frameMarginWidth) { frameMarginWidth = pixel; } } } if ((frameMarginHeight >= 0) && (0 > bodyMarginHeight)) { // set in & not in if (eCompatibility_NavQuirks == mode) { // allow 0 margins if ((0 > bodyMarginWidth) && (0 > frameMarginWidth)) { // another nav quirk frameMarginWidth = 0; } } else { // margins are at least 1 pixel if (0 == frameMarginHeight) { frameMarginHeight = pixel; } } } if ((0 > bodyMarginWidth) && (frameMarginWidth >= 0)) { nsStyleCoord widthCoord(frameMarginWidth); styleSpacing->mMargin.SetLeft(widthCoord); styleSpacing->mMargin.SetRight(widthCoord); } if ((0 > bodyMarginHeight) && (frameMarginHeight >= 0)) { nsStyleCoord heightCoord(frameMarginHeight); styleSpacing->mMargin.SetTop(heightCoord); styleSpacing->mMargin.SetBottom(heightCoord); } NS_RELEASE(webShell); } NS_RELEASE(container); } } } } return NS_OK; } NS_IMETHODIMP BodyRule::List(FILE* out, PRInt32 aIndent) const { return NS_OK; } //---------------------------------------------------------------------- BodyFixupRule::BodyFixupRule(nsHTMLBodyElement* aPart, nsIHTMLCSSStyleSheet* aSheet) : mPart(aPart), mSheet(aSheet) { NS_INIT_REFCNT(); } BodyFixupRule::~BodyFixupRule() { } NS_IMPL_ADDREF(BodyFixupRule); NS_IMPL_RELEASE(BodyFixupRule); nsresult BodyFixupRule::QueryInterface(const nsIID& aIID, void** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } // static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); if (aIID.Equals(kIStyleRuleIID)) { *aInstancePtrResult = (void*) ((nsIStyleRule*)this); NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kISupportsIID)) { *aInstancePtrResult = (void*) ((nsISupports*)this); NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } NS_IMETHODIMP BodyFixupRule::Equals(const nsIStyleRule* aRule, PRBool& aResult) const { aResult = PRBool(this == aRule); return NS_OK; } NS_IMETHODIMP BodyFixupRule::HashValue(PRUint32& aValue) const { aValue = (PRUint32)(mPart); return NS_OK; } NS_IMETHODIMP BodyFixupRule::GetStyleSheet(nsIStyleSheet*& aSheet) const { NS_IF_ADDREF(mSheet); aSheet = mSheet; return NS_OK; } // Strength is an out-of-band weighting, always MaxInt here NS_IMETHODIMP BodyFixupRule::GetStrength(PRInt32& aStrength) const { aStrength = 2000000000; return NS_OK; } NS_IMETHODIMP BodyFixupRule::MapFontStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext) { return NS_OK; } NS_IMETHODIMP BodyFixupRule::MapStyleInto(nsIMutableStyleContext* aContext, nsIPresContext* aPresContext) { // XXX do any other body processing here const nsStyleColor* styleColor; styleColor = (const nsStyleColor*)aContext->GetStyleData(eStyleStruct_Color); // Use the CSS precedence rules for dealing with BODY background: if the value // of the 'background' property for the HTML element is different from // 'transparent' then use it, else use the value of the 'background' property // for the BODY element // See if the BODY has a background specified if (!styleColor->BackgroundIsTransparent()) { // Get the parent style context nsIStyleContext* parentContext = aContext->GetParent(); // Look at its 'background' property const nsStyleColor* parentStyleColor; parentStyleColor = (const nsStyleColor*)parentContext->GetStyleData(eStyleStruct_Color); // See if it's 'transparent' or set by us if (parentStyleColor->BackgroundIsTransparent() || (NS_STYLE_BG_PROPOGATED == (parentStyleColor->mBackgroundFlags & NS_STYLE_BG_PROPOGATED))) { // Have the parent (initial containing block) use the BODY's background nsStyleColor* mutableStyleColor; mutableStyleColor = (nsStyleColor*)parentContext->GetMutableStyleData(eStyleStruct_Color); mutableStyleColor->mBackgroundAttachment = styleColor->mBackgroundAttachment; mutableStyleColor->mBackgroundFlags = styleColor->mBackgroundFlags | NS_STYLE_BG_PROPOGATED; mutableStyleColor->mBackgroundRepeat = styleColor->mBackgroundRepeat; mutableStyleColor->mBackgroundColor = styleColor->mBackgroundColor; mutableStyleColor->mBackgroundXPosition = styleColor->mBackgroundXPosition; mutableStyleColor->mBackgroundYPosition = styleColor->mBackgroundYPosition; mutableStyleColor->mBackgroundImage = styleColor->mBackgroundImage; // Reset the BODY's background to transparent mutableStyleColor = (nsStyleColor*)aContext->GetMutableStyleData(eStyleStruct_Color); mutableStyleColor->mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT | NS_STYLE_BG_IMAGE_NONE; mutableStyleColor->mBackgroundImage.SetLength(0); mutableStyleColor->mBackgroundAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL; } NS_RELEASE(parentContext); } nsCOMPtr