Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLStyleSheet.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK *****
00038  *
00039  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
00040  * described herein are Copyright (c) International Business Machines Corporation, 2000.
00041  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
00042  *
00043  * Date             Modified by     Description of modification
00044  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
00045  */
00046 
00047 #include "nsHTMLStyleSheet.h"
00048 #include "nsINameSpaceManager.h"
00049 #include "nsIAtom.h"
00050 #include "nsIURL.h"
00051 #include "nsISupportsArray.h"
00052 #include "nsMappedAttributes.h"
00053 #include "nsILink.h"
00054 #include "nsIFrame.h"
00055 #include "nsStyleContext.h"
00056 #include "nsHTMLAtoms.h"
00057 #include "nsPresContext.h"
00058 #include "nsIEventStateManager.h"
00059 #include "nsIDocument.h"
00060 #include "nsIPresShell.h"
00061 #include "nsStyleConsts.h"
00062 #include "nsIDOMHTMLDocument.h"
00063 #include "nsIDOMHTMLElement.h"
00064 #include "nsCSSAnonBoxes.h"
00065 #include "nsRuleWalker.h"
00066 #include "nsRuleData.h"
00067 
00068 NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::HTMLColorRule, nsIStyleRule)
00069 
00070 NS_IMETHODIMP
00071 nsHTMLStyleSheet::HTMLColorRule::MapRuleInfoInto(nsRuleData* aRuleData)
00072 {
00073   if (aRuleData->mSID == eStyleStruct_Color) {
00074     if (aRuleData->mColorData->mColor.GetUnit() == eCSSUnit_Null)
00075       aRuleData->mColorData->mColor = nsCSSValue(mColor);
00076   }
00077   return NS_OK;
00078 }
00079 
00080 #ifdef DEBUG
00081 NS_IMETHODIMP
00082 nsHTMLStyleSheet::HTMLColorRule::List(FILE* out, PRInt32 aIndent) const
00083 {
00084   return NS_OK;
00085 }
00086 #endif
00087 
00088  
00089 NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::GenericTableRule, nsIStyleRule)
00090 
00091 NS_IMETHODIMP
00092 nsHTMLStyleSheet::GenericTableRule::MapRuleInfoInto(nsRuleData* aRuleData)
00093 {
00094   // Nothing to do.
00095   return NS_OK;
00096 }
00097 
00098 #ifdef DEBUG
00099 NS_IMETHODIMP
00100 nsHTMLStyleSheet::GenericTableRule::List(FILE* out, PRInt32 aIndent) const
00101 {
00102   return NS_OK;
00103 }
00104 #endif
00105 
00106 static void PostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
00107 {
00108   nsStyleText* text = (nsStyleText*)aStyleStruct;
00109   if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_DEFAULT) {
00110     nsStyleContext* parentContext = aRuleData->mStyleContext->GetParent();
00111 
00112     if (parentContext) {
00113       const nsStyleText* parentStyleText = parentContext->GetStyleText();
00114       PRUint8 parentAlign = parentStyleText->mTextAlign;
00115       text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign)
00116                               ? NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
00117     }
00118   }
00119 }
00120 
00121 NS_IMETHODIMP
00122 nsHTMLStyleSheet::TableTHRule::MapRuleInfoInto(nsRuleData* aRuleData)
00123 {
00124   if (aRuleData && aRuleData->mSID == eStyleStruct_Text) {
00125     aRuleData->mCanStoreInRuleTree = PR_FALSE;
00126     aRuleData->mPostResolveCallback = &PostResolveCallback;
00127   }
00128   return NS_OK;
00129 }
00130 
00131 static void 
00132 ProcessTableRulesAttribute(nsStyleStruct* aStyleStruct, 
00133                            nsRuleData*    aRuleData,
00134                            PRUint8        aSide,
00135                            PRBool         aGroup,
00136                            PRUint8        aRulesArg1,
00137                            PRUint8        aRulesArg2,
00138                            PRUint8        aRulesArg3)
00139 {
00140   if (!aStyleStruct || !aRuleData || !aRuleData->mPresContext) return;
00141 
00142   nsStyleContext* tableContext = aRuleData->mStyleContext->GetParent();
00143   if (!tableContext)
00144     return;
00145   if (!aGroup) {
00146     tableContext = tableContext->GetParent();
00147     if (!tableContext)
00148       return;
00149   } 
00150   
00151   const nsStyleTable* tableData = tableContext->GetStyleTable();
00152   if (aRulesArg1 == tableData->mRules ||
00153       aRulesArg2 == tableData->mRules ||
00154       aRulesArg3 == tableData->mRules) {
00155     const nsStyleBorder* tableBorderData = tableContext->GetStyleBorder();
00156     PRUint8 tableBorderStyle = tableBorderData->GetBorderStyle(aSide);
00157 
00158     nsStyleBorder* borderData = (nsStyleBorder*)aStyleStruct;
00159     if (!borderData)
00160       return;
00161     PRUint8 borderStyle = borderData->GetBorderStyle(aSide);
00162     // XXX It appears that the style system erronously applies the custom style rule after css style, 
00163     // consequently it does not properly fit into the casade. For now, assume that a border style of none
00164     // implies that the style has not been set.
00165     // XXXldb No, there's nothing wrong with the style system.  The problem
00166     // is that the author of all these table rules made them work as
00167     // post-resolve callbacks, which is an override mechanism that was meant
00168     // to be used for other things.  They should instead map their rule data
00169     // normally (see nsIStyleRule.h).
00170     if (NS_STYLE_BORDER_STYLE_NONE == borderStyle) {
00171       // use the table's border style if it is dashed or dotted, otherwise use solid
00172       PRUint8 bStyle = ((NS_STYLE_BORDER_STYLE_NONE != tableBorderStyle) &&
00173                         (NS_STYLE_BORDER_STYLE_HIDDEN != tableBorderStyle)) 
00174                         ? tableBorderStyle : NS_STYLE_BORDER_STYLE_SOLID;
00175       if ((NS_STYLE_BORDER_STYLE_DASHED != bStyle) && 
00176           (NS_STYLE_BORDER_STYLE_DOTTED != bStyle) && 
00177           (NS_STYLE_BORDER_STYLE_SOLID  != bStyle)) {
00178         bStyle = NS_STYLE_BORDER_STYLE_SOLID;
00179       }
00180       bStyle |= NS_STYLE_BORDER_STYLE_RULES_MARKER;
00181       borderData->SetBorderStyle(aSide, bStyle);
00182 
00183       nscolor borderColor;
00184       PRBool transparent, foreground;
00185       borderData->GetBorderColor(aSide, borderColor, transparent, foreground);
00186       if (transparent || foreground) {
00187         // use the table's border color if it is set, otherwise use black
00188         nscolor tableBorderColor;
00189         tableBorderData->GetBorderColor(aSide, tableBorderColor, transparent, foreground);
00190         borderColor = (transparent || foreground) ? NS_RGB(0,0,0) : tableBorderColor;
00191         borderData->SetBorderColor(aSide, borderColor);
00192       }
00193       // set the border width to be 1 pixel
00194       nscoord onePixel =
00195         NSToCoordRound(aRuleData->mPresContext->ScaledPixelsToTwips());
00196       borderData->SetBorderWidth(aSide, onePixel);
00197     }
00198   }
00199 }
00200 
00201 static void TbodyPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
00202 {
00203   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_TOP, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
00204                                NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_ROWS);
00205   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_BOTTOM, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
00206                                NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_ROWS);
00207 }
00208 
00209 NS_IMETHODIMP
00210 nsHTMLStyleSheet::TableTbodyRule::MapRuleInfoInto(nsRuleData* aRuleData)
00211 {
00212   if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
00213     aRuleData->mCanStoreInRuleTree = PR_FALSE;
00214     aRuleData->mPostResolveCallback = &TbodyPostResolveCallback;
00215   }
00216   return NS_OK;
00217 }
00218 // -----------------------------------------------------------
00219 
00220 static void RowPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
00221 {
00222   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_TOP, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
00223                                NS_STYLE_TABLE_RULES_ROWS, NS_STYLE_TABLE_RULES_ROWS);
00224   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_BOTTOM, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
00225                                NS_STYLE_TABLE_RULES_ROWS, NS_STYLE_TABLE_RULES_ROWS);
00226 }
00227 
00228 NS_IMETHODIMP
00229 nsHTMLStyleSheet::TableRowRule::MapRuleInfoInto(nsRuleData* aRuleData)
00230 {
00231   if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
00232     aRuleData->mCanStoreInRuleTree = PR_FALSE;
00233     aRuleData->mPostResolveCallback = &RowPostResolveCallback;
00234   }
00235   return NS_OK;
00236 }
00237 
00238 static void ColgroupPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
00239 {
00240   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
00241                                NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
00242   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_RIGHT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
00243                                NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
00244 }
00245 
00246 NS_IMETHODIMP
00247 nsHTMLStyleSheet::TableColgroupRule::MapRuleInfoInto(nsRuleData* aRuleData)
00248 {
00249   if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
00250     aRuleData->mCanStoreInRuleTree = PR_FALSE;
00251     aRuleData->mPostResolveCallback = &ColgroupPostResolveCallback;
00252   }
00253   return NS_OK;
00254 }
00255 
00256 static void ColPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
00257 {
00258   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
00259                                NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
00260   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_RIGHT, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
00261                                NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
00262 }
00263 
00264 static void UngroupedColPostResolveCallback(nsStyleStruct* aStyleStruct,
00265                                             nsRuleData* aRuleData)
00266 {
00267   // Pass PR_TRUE for aGroup, so that we find the table's style
00268   // context correctly.
00269   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
00270                                NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
00271   ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_RIGHT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
00272                                NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
00273 }
00274 
00275 NS_IMETHODIMP
00276 nsHTMLStyleSheet::TableColRule::MapRuleInfoInto(nsRuleData* aRuleData)
00277 {
00278   if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
00279     aRuleData->mCanStoreInRuleTree = PR_FALSE;
00280     aRuleData->mPostResolveCallback = &ColPostResolveCallback;
00281   }
00282   return NS_OK;
00283 }
00284 
00285 NS_IMETHODIMP
00286 nsHTMLStyleSheet::TableUngroupedColRule::MapRuleInfoInto(nsRuleData* aRuleData)
00287 {
00288   if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
00289     aRuleData->mCanStoreInRuleTree = PR_FALSE;
00290     aRuleData->mPostResolveCallback = &UngroupedColPostResolveCallback;
00291   }
00292   return NS_OK;
00293 }
00294 // -----------------------------------------------------------
00295 
00296 struct MappedAttrTableEntry : public PLDHashEntryHdr {
00297   nsMappedAttributes *mAttributes;
00298 };
00299 
00300 PR_STATIC_CALLBACK(PLDHashNumber)
00301 MappedAttrTable_HashKey(PLDHashTable *table, const void *key)
00302 {
00303   nsMappedAttributes *attributes =
00304     NS_STATIC_CAST(nsMappedAttributes*, NS_CONST_CAST(void*, key));
00305 
00306   return attributes->HashValue();
00307 }
00308 
00309 PR_STATIC_CALLBACK(void)
00310 MappedAttrTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
00311 {
00312   MappedAttrTableEntry *entry = NS_STATIC_CAST(MappedAttrTableEntry*, hdr);
00313 
00314   entry->mAttributes->DropStyleSheetReference();
00315   memset(entry, 0, sizeof(MappedAttrTableEntry));
00316 }
00317 
00318 PR_STATIC_CALLBACK(PRBool)
00319 MappedAttrTable_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00320                            const void *key)
00321 {
00322   nsMappedAttributes *attributes =
00323     NS_STATIC_CAST(nsMappedAttributes*, NS_CONST_CAST(void*, key));
00324   const MappedAttrTableEntry *entry =
00325     NS_STATIC_CAST(const MappedAttrTableEntry*, hdr);
00326 
00327   return attributes->Equals(entry->mAttributes);
00328 }
00329 
00330 static PLDHashTableOps MappedAttrTable_Ops = {
00331   PL_DHashAllocTable,
00332   PL_DHashFreeTable,
00333   PL_DHashGetKeyStub,
00334   MappedAttrTable_HashKey,
00335   MappedAttrTable_MatchEntry,
00336   PL_DHashMoveEntryStub,
00337   MappedAttrTable_ClearEntry,
00338   PL_DHashFinalizeStub,
00339   NULL
00340 };
00341 
00342 // -----------------------------------------------------------
00343 
00344 nsHTMLStyleSheet::nsHTMLStyleSheet(void)
00345   : mURL(nsnull),
00346     mDocument(nsnull),
00347     mLinkRule(nsnull),
00348     mVisitedRule(nsnull),
00349     mActiveRule(nsnull),
00350     mDocumentColorRule(nsnull)
00351 {
00352   mMappedAttrTable.ops = nsnull;
00353 }
00354 
00355 nsresult
00356 nsHTMLStyleSheet::Init()
00357 {
00358   mTableTbodyRule = new TableTbodyRule();
00359   if (!mTableTbodyRule)
00360     return NS_ERROR_OUT_OF_MEMORY;
00361   NS_ADDREF(mTableTbodyRule);
00362 
00363   mTableRowRule = new TableRowRule();
00364   if (!mTableRowRule)
00365     return NS_ERROR_OUT_OF_MEMORY;
00366   NS_ADDREF(mTableRowRule);
00367 
00368   mTableColgroupRule = new TableColgroupRule();
00369   if (!mTableColgroupRule)
00370     return NS_ERROR_OUT_OF_MEMORY;
00371   NS_ADDREF(mTableColgroupRule);
00372 
00373   mTableColRule = new TableColRule();
00374   if (!mTableColRule)
00375     return NS_ERROR_OUT_OF_MEMORY;
00376   NS_ADDREF(mTableColRule);
00377 
00378   mTableUngroupedColRule = new TableUngroupedColRule();
00379   if (!mTableUngroupedColRule)
00380     return NS_ERROR_OUT_OF_MEMORY;
00381   NS_ADDREF(mTableUngroupedColRule);
00382 
00383   mTableTHRule = new TableTHRule();
00384   if (!mTableTHRule)
00385     return NS_ERROR_OUT_OF_MEMORY;
00386   NS_ADDREF(mTableTHRule);
00387   return NS_OK;
00388 }
00389 
00390 nsHTMLStyleSheet::~nsHTMLStyleSheet()
00391 {
00392   NS_IF_RELEASE(mURL);
00393 
00394   NS_IF_RELEASE(mLinkRule);
00395   NS_IF_RELEASE(mVisitedRule);
00396   NS_IF_RELEASE(mActiveRule);
00397   NS_IF_RELEASE(mDocumentColorRule);
00398   NS_IF_RELEASE(mTableTbodyRule);
00399   NS_IF_RELEASE(mTableRowRule);
00400   NS_IF_RELEASE(mTableColgroupRule);
00401   NS_IF_RELEASE(mTableColRule);
00402   NS_IF_RELEASE(mTableUngroupedColRule);
00403   NS_IF_RELEASE(mTableTHRule);
00404 
00405   if (mMappedAttrTable.ops)
00406     PL_DHashTableFinish(&mMappedAttrTable);
00407 }
00408 
00409 NS_IMPL_ISUPPORTS2(nsHTMLStyleSheet, nsIStyleSheet, nsIStyleRuleProcessor)
00410 
00411 static nsresult GetBodyColor(nsPresContext* aPresContext, nscolor* aColor)
00412 {
00413   nsIPresShell *shell = aPresContext->PresShell();
00414   nsCOMPtr<nsIDOMHTMLDocument> domdoc = do_QueryInterface(shell->GetDocument());
00415   if (!domdoc)
00416     return NS_ERROR_FAILURE;
00417   nsCOMPtr<nsIDOMHTMLElement> body;
00418   domdoc->GetBody(getter_AddRefs(body));
00419   nsCOMPtr<nsIContent> bodyContent = do_QueryInterface(body);
00420   nsIFrame *bodyFrame;
00421   shell->GetPrimaryFrameFor(bodyContent, &bodyFrame);
00422   if (!bodyFrame)
00423     return NS_ERROR_FAILURE;
00424   *aColor = bodyFrame->GetStyleColor()->mColor;
00425   return NS_OK;
00426 }
00427 
00428 NS_IMETHODIMP
00429 nsHTMLStyleSheet::RulesMatching(ElementRuleProcessorData* aData)
00430 {
00431   nsIStyledContent *styledContent = aData->mStyledContent;
00432 
00433   if (styledContent) {
00434     nsRuleWalker *ruleWalker = aData->mRuleWalker;
00435     if (aData->mIsHTMLContent) {
00436       nsIAtom* tag = aData->mContentTag;
00437 
00438       // if we have anchor colors, check if this is an anchor with an href
00439       if (tag == nsHTMLAtoms::a) {
00440         if (mLinkRule || mVisitedRule || mActiveRule) {
00441           if (aData->mIsHTMLLink) {
00442             switch (aData->mLinkState) {
00443               case eLinkState_Unvisited:
00444                 if (mLinkRule)
00445                   ruleWalker->Forward(mLinkRule);
00446                 break;
00447               case eLinkState_Visited:
00448                 if (mVisitedRule)
00449                   ruleWalker->Forward(mVisitedRule);
00450                 break;
00451               default:
00452                 break;
00453             }
00454 
00455             // No need to add to the active rule if it's not a link
00456             if (mActiveRule && (aData->mEventState & NS_EVENT_STATE_ACTIVE))
00457               ruleWalker->Forward(mActiveRule);
00458           }
00459         } // end link/visited/active rules
00460       } // end A tag
00461       // add the rule to handle text-align for a <th>
00462       else if (tag == nsHTMLAtoms::th) {
00463         ruleWalker->Forward(mTableTHRule);
00464       }
00465       else if (tag == nsHTMLAtoms::tr) {
00466         ruleWalker->Forward(mTableRowRule);
00467       }
00468       else if ((tag == nsHTMLAtoms::thead) || (tag == nsHTMLAtoms::tbody) || (tag == nsHTMLAtoms::tfoot)) {
00469         ruleWalker->Forward(mTableTbodyRule);
00470       }
00471       else if (tag == nsHTMLAtoms::col) {
00472         nsIContent* parent = aData->mParentContent;
00473         if (parent && parent->IsContentOfType(nsIContent::eHTML) &&
00474             parent->Tag() == nsHTMLAtoms::colgroup) {
00475           ruleWalker->Forward(mTableColRule);
00476         } else {
00477           ruleWalker->Forward(mTableUngroupedColRule);
00478         }
00479       }
00480       else if (tag == nsHTMLAtoms::colgroup) {
00481         ruleWalker->Forward(mTableColgroupRule);
00482       }
00483       else if (tag == nsHTMLAtoms::table) {
00484         if (aData->mCompatMode == eCompatibility_NavQuirks) {
00485           nscolor bodyColor;
00486           nsresult rv =
00487             GetBodyColor(ruleWalker->GetCurrentNode()->GetPresContext(),
00488                          &bodyColor);
00489           if (NS_SUCCEEDED(rv) &&
00490               (!mDocumentColorRule || bodyColor != mDocumentColorRule->mColor)) {
00491             NS_IF_RELEASE(mDocumentColorRule);
00492             mDocumentColorRule = new HTMLColorRule();
00493             if (mDocumentColorRule) {
00494               NS_ADDREF(mDocumentColorRule);
00495               mDocumentColorRule->mColor = bodyColor;
00496             }
00497           }
00498           if (mDocumentColorRule)
00499             ruleWalker->Forward(mDocumentColorRule);
00500         }
00501       }
00502     } // end html element
00503 
00504     // just get the style rules from the content
00505     styledContent->WalkContentStyleRules(ruleWalker);
00506   }
00507 
00508   return NS_OK;
00509 }
00510 
00511 // Test if style is dependent on content state
00512 NS_IMETHODIMP
00513 nsHTMLStyleSheet::HasStateDependentStyle(StateRuleProcessorData* aData,
00514                                          nsReStyleHint* aResult)
00515 {
00516   if (aData->mStyledContent &&
00517       aData->mIsHTMLContent &&
00518       aData->mIsHTMLLink &&
00519       aData->mContentTag == nsHTMLAtoms::a &&
00520       ((mActiveRule && (aData->mStateMask & NS_EVENT_STATE_ACTIVE)) ||
00521        (mLinkRule && (aData->mStateMask & NS_EVENT_STATE_VISITED)) ||
00522        (mVisitedRule && (aData->mStateMask & NS_EVENT_STATE_VISITED)))) {
00523     *aResult = eReStyle_Self;
00524   }
00525   else
00526     *aResult = nsReStyleHint(0);
00527 
00528   return NS_OK;
00529 }
00530 
00531 NS_IMETHODIMP
00532 nsHTMLStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
00533                                              nsReStyleHint* aResult)
00534 {
00535   // Result is true for |href| changes on HTML links if we have link rules.
00536   nsIStyledContent *styledContent = aData->mStyledContent;
00537   if (aData->mAttribute == nsHTMLAtoms::href &&
00538       (mLinkRule || mVisitedRule || mActiveRule) &&
00539       styledContent &&
00540       styledContent->IsContentOfType(nsIContent::eHTML) &&
00541       aData->mContentTag == nsHTMLAtoms::a) {
00542     *aResult = eReStyle_Self;
00543     return NS_OK;
00544   }
00545 
00546   // Don't worry about the mDocumentColorRule since it only applies
00547   // to descendants of body, when we're already reresolving.
00548 
00549   // Handle the content style rules.
00550   if (styledContent && styledContent->IsAttributeMapped(aData->mAttribute)) {
00551     *aResult = eReStyle_Self;
00552     return NS_OK;
00553   }
00554 
00555   *aResult = nsReStyleHint(0);
00556   return NS_OK;
00557 }
00558 
00559 
00560 NS_IMETHODIMP
00561 nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData)
00562 {
00563   nsIAtom* pseudoTag = aData->mPseudoTag;
00564   if (pseudoTag == nsCSSAnonBoxes::tableCol) {
00565     nsRuleWalker *ruleWalker = aData->mRuleWalker;
00566     if (ruleWalker) {
00567       ruleWalker->Forward(mTableColRule);
00568     }
00569   }
00570   return NS_OK;
00571 }
00572 
00573 
00574   // nsIStyleSheet api
00575 NS_IMETHODIMP
00576 nsHTMLStyleSheet::GetSheetURI(nsIURI** aSheetURI) const
00577 {
00578   *aSheetURI = mURL;
00579   NS_IF_ADDREF(*aSheetURI);
00580   return NS_OK;
00581 }
00582 
00583 NS_IMETHODIMP
00584 nsHTMLStyleSheet::GetBaseURI(nsIURI** aBaseURI) const
00585 {
00586   *aBaseURI = mURL;
00587   NS_IF_ADDREF(*aBaseURI);
00588   return NS_OK;
00589 }
00590 
00591 NS_IMETHODIMP
00592 nsHTMLStyleSheet::GetTitle(nsString& aTitle) const
00593 {
00594   aTitle.Truncate();
00595   return NS_OK;
00596 }
00597 
00598 NS_IMETHODIMP
00599 nsHTMLStyleSheet::GetType(nsString& aType) const
00600 {
00601   aType.AssignLiteral("text/html");
00602   return NS_OK;
00603 }
00604 
00605 NS_IMETHODIMP_(PRBool)
00606 nsHTMLStyleSheet::UseForMedium(nsPresContext* aPresContext) const
00607 {
00608   return PR_TRUE; // works for all media
00609 }
00610 
00611 NS_IMETHODIMP_(PRBool)
00612 nsHTMLStyleSheet::HasRules() const
00613 {
00614   return PR_TRUE; // We have rules at all reasonable times
00615 }
00616 
00617 NS_IMETHODIMP
00618 nsHTMLStyleSheet::GetApplicable(PRBool& aApplicable) const
00619 {
00620   aApplicable = PR_TRUE;
00621   return NS_OK;
00622 }
00623 
00624 NS_IMETHODIMP
00625 nsHTMLStyleSheet::SetEnabled(PRBool aEnabled)
00626 { // these can't be disabled
00627   return NS_OK;
00628 }
00629 
00630 NS_IMETHODIMP
00631 nsHTMLStyleSheet::GetComplete(PRBool& aComplete) const
00632 {
00633   aComplete = PR_TRUE;
00634   return NS_OK;
00635 }
00636 
00637 NS_IMETHODIMP
00638 nsHTMLStyleSheet::SetComplete()
00639 {
00640   return NS_OK;
00641 }
00642 
00643 NS_IMETHODIMP
00644 nsHTMLStyleSheet::GetParentSheet(nsIStyleSheet*& aParent) const
00645 {
00646   aParent = nsnull;
00647   return NS_OK;
00648 }
00649 
00650 NS_IMETHODIMP
00651 nsHTMLStyleSheet::GetOwningDocument(nsIDocument*& aDocument) const
00652 {
00653   aDocument = mDocument;
00654   NS_IF_ADDREF(aDocument);
00655   return NS_OK;
00656 }
00657 
00658 NS_IMETHODIMP
00659 nsHTMLStyleSheet::SetOwningDocument(nsIDocument* aDocument)
00660 {
00661   mDocument = aDocument; // not refcounted
00662   return NS_OK;
00663 }
00664 
00665 nsresult
00666 nsHTMLStyleSheet::Init(nsIURI* aURL, nsIDocument* aDocument)
00667 {
00668   NS_PRECONDITION(aURL && aDocument, "null ptr");
00669   if (! aURL || ! aDocument)
00670     return NS_ERROR_NULL_POINTER;
00671 
00672   if (mURL || mDocument)
00673     return NS_ERROR_ALREADY_INITIALIZED;
00674 
00675   mDocument = aDocument; // not refcounted!
00676   mURL = aURL;
00677   NS_ADDREF(mURL);
00678   return NS_OK;
00679 }
00680 
00681 nsresult
00682 nsHTMLStyleSheet::Reset(nsIURI* aURL)
00683 {
00684   NS_IF_RELEASE(mURL);
00685   mURL = aURL;
00686   NS_ADDREF(mURL);
00687 
00688   NS_IF_RELEASE(mLinkRule);
00689   NS_IF_RELEASE(mVisitedRule);
00690   NS_IF_RELEASE(mActiveRule);
00691   NS_IF_RELEASE(mDocumentColorRule);
00692 
00693   if (mMappedAttrTable.ops) {
00694     PL_DHashTableFinish(&mMappedAttrTable);
00695     mMappedAttrTable.ops = nsnull;
00696   }
00697 
00698   return NS_OK;
00699 }
00700 
00701 nsresult
00702 nsHTMLStyleSheet::GetLinkColor(nscolor& aColor)
00703 {
00704   if (!mLinkRule) {
00705     return NS_HTML_STYLE_PROPERTY_NOT_THERE;
00706   }
00707   else {
00708     aColor = mLinkRule->mColor;
00709     return NS_OK;
00710   }
00711 }
00712 
00713 nsresult
00714 nsHTMLStyleSheet::GetActiveLinkColor(nscolor& aColor)
00715 {
00716   if (!mActiveRule) {
00717     return NS_HTML_STYLE_PROPERTY_NOT_THERE;
00718   }
00719   else {
00720     aColor = mActiveRule->mColor;
00721     return NS_OK;
00722   }
00723 }
00724 
00725 nsresult
00726 nsHTMLStyleSheet::GetVisitedLinkColor(nscolor& aColor)
00727 {
00728   if (!mVisitedRule) {
00729     return NS_HTML_STYLE_PROPERTY_NOT_THERE;
00730   }
00731   else {
00732     aColor = mVisitedRule->mColor;
00733     return NS_OK;
00734   }
00735 }
00736 
00737 nsresult
00738 nsHTMLStyleSheet::SetLinkColor(nscolor aColor)
00739 {
00740   if (mLinkRule) {
00741     if (mLinkRule->mColor == aColor)
00742       return NS_OK;
00743     NS_RELEASE(mLinkRule);
00744   }
00745 
00746   mLinkRule = new HTMLColorRule();
00747   if (!mLinkRule)
00748     return NS_ERROR_OUT_OF_MEMORY;
00749   NS_ADDREF(mLinkRule);
00750 
00751   mLinkRule->mColor = aColor;
00752   return NS_OK;
00753 }
00754 
00755 
00756 nsresult
00757 nsHTMLStyleSheet::SetActiveLinkColor(nscolor aColor)
00758 {
00759   if (mActiveRule) {
00760     if (mActiveRule->mColor == aColor)
00761       return NS_OK;
00762     NS_RELEASE(mActiveRule);
00763   }
00764 
00765   mActiveRule = new HTMLColorRule();
00766   if (!mActiveRule)
00767     return NS_ERROR_OUT_OF_MEMORY;
00768   NS_ADDREF(mActiveRule);
00769 
00770   mActiveRule->mColor = aColor;
00771   return NS_OK;
00772 }
00773 
00774 nsresult
00775 nsHTMLStyleSheet::SetVisitedLinkColor(nscolor aColor)
00776 {
00777   if (mVisitedRule) {
00778     if (mVisitedRule->mColor == aColor)
00779       return NS_OK;
00780     NS_RELEASE(mVisitedRule);
00781   }
00782 
00783   mVisitedRule = new HTMLColorRule();
00784   if (!mVisitedRule)
00785     return NS_ERROR_OUT_OF_MEMORY;
00786   NS_ADDREF(mVisitedRule);
00787 
00788   mVisitedRule->mColor = aColor;
00789   return NS_OK;
00790 }
00791 
00792 already_AddRefed<nsMappedAttributes>
00793 nsHTMLStyleSheet::UniqueMappedAttributes(nsMappedAttributes* aMapped)
00794 {
00795   if (!mMappedAttrTable.ops) {
00796     PRBool res = PL_DHashTableInit(&mMappedAttrTable, &MappedAttrTable_Ops,
00797                                    nsnull, sizeof(MappedAttrTableEntry), 16);
00798     if (!res) {
00799       mMappedAttrTable.ops = nsnull;
00800       return nsnull;
00801     }
00802   }
00803   MappedAttrTableEntry *entry = NS_STATIC_CAST(MappedAttrTableEntry*,
00804     PL_DHashTableOperate(&mMappedAttrTable, aMapped, PL_DHASH_ADD));
00805   if (!entry)
00806     return nsnull;
00807   if (!entry->mAttributes) {
00808     // We added a new entry to the hashtable, so we have a new unique set.
00809     entry->mAttributes = aMapped;
00810   }
00811   NS_ADDREF(entry->mAttributes); // for caller
00812   return entry->mAttributes;
00813 }
00814 
00815 void
00816 nsHTMLStyleSheet::DropMappedAttributes(nsMappedAttributes* aMapped)
00817 {
00818   NS_ENSURE_TRUE(aMapped, );
00819 
00820   NS_ASSERTION(mMappedAttrTable.ops, "table uninitialized");
00821 #ifdef DEBUG
00822   PRUint32 entryCount = mMappedAttrTable.entryCount - 1;
00823 #endif
00824 
00825   PL_DHashTableOperate(&mMappedAttrTable, aMapped, PL_DHASH_REMOVE);
00826 
00827   NS_ASSERTION(entryCount == mMappedAttrTable.entryCount, "not removed");
00828 }
00829 
00830 #ifdef DEBUG
00831 void nsHTMLStyleSheet::List(FILE* out, PRInt32 aIndent) const
00832 {
00833   // Indent
00834   for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
00835 
00836   fputs("HTML Style Sheet: ", out);
00837   nsCAutoString urlSpec;
00838   mURL->GetSpec(urlSpec);
00839   if (!urlSpec.IsEmpty()) {
00840     fputs(urlSpec.get(), out);
00841   }
00842   fputs("\n", out);
00843 }
00844 #endif
00845 
00846 // XXX For convenience and backwards compatibility
00847 nsresult
00848 NS_NewHTMLStyleSheet(nsHTMLStyleSheet** aInstancePtrResult, nsIURI* aURL, 
00849                      nsIDocument* aDocument)
00850 {
00851   nsresult rv;
00852   nsHTMLStyleSheet* sheet;
00853   if (NS_FAILED(rv = NS_NewHTMLStyleSheet(&sheet)))
00854     return rv;
00855 
00856   if (NS_FAILED(rv = sheet->Init(aURL, aDocument))) {
00857     NS_RELEASE(sheet);
00858     return rv;
00859   }
00860 
00861   *aInstancePtrResult = sheet;
00862   return NS_OK;
00863 }
00864 
00865 
00866 nsresult
00867 NS_NewHTMLStyleSheet(nsHTMLStyleSheet** aInstancePtrResult)
00868 {
00869   NS_ASSERTION(aInstancePtrResult, "null out param");
00870 
00871   nsHTMLStyleSheet *it = new nsHTMLStyleSheet();
00872   if (!it) {
00873     *aInstancePtrResult = nsnull;
00874     return NS_ERROR_OUT_OF_MEMORY;
00875   }
00876 
00877   NS_ADDREF(it);
00878   nsresult rv = it->Init();
00879   if (NS_FAILED(rv))
00880     NS_RELEASE(it);
00881 
00882   *aInstancePtrResult = it; // NS_ADDREF above, or set to null by NS_RELEASE
00883   return rv;
00884 }