1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK *****
39 * This Original Code has been modified by IBM Corporation. Modifications made by IBM
40 * described herein are Copyright (c) International Business Machines Corporation, 2000.
41 * Modifications to Mozilla code or documentation identified per MPL Section 3.3
43 * Date Modified by Description of modification
44 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
48 * style sheet and style rule processor representing data from presentational
52 #include "nsHTMLStyleSheet.h"
53 #include "nsINameSpaceManager.h"
56 #include "nsMappedAttributes.h"
59 #include "nsStyleContext.h"
60 #include "nsGkAtoms.h"
61 #include "nsPresContext.h"
62 #include "nsIEventStateManager.h"
63 #include "nsIDocument.h"
64 #include "nsIPresShell.h"
65 #include "nsStyleConsts.h"
66 #include "nsIHTMLDocument.h"
67 #include "nsIDOMHTMLElement.h"
68 #include "nsCSSAnonBoxes.h"
69 #include "nsRuleWalker.h"
70 #include "nsRuleData.h"
71 #include "nsContentErrors.h"
72 #include "nsRuleProcessorData.h"
73 #include "mozilla/dom/Element.h"
74 #include "nsCSSFrameConstructor.h"
76 using namespace mozilla::dom
;
78 NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::HTMLColorRule
, nsIStyleRule
)
81 nsHTMLStyleSheet::HTMLColorRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
83 if (aRuleData
->mSIDs
& NS_STYLE_INHERIT_BIT(Color
)) {
84 if (aRuleData
->mColorData
->mColor
.GetUnit() == eCSSUnit_Null
&&
85 aRuleData
->mPresContext
->UseDocumentColors())
86 aRuleData
->mColorData
->mColor
.SetColorValue(mColor
);
92 nsHTMLStyleSheet::HTMLColorRule::List(FILE* out
, PRInt32 aIndent
) const
98 NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::GenericTableRule
, nsIStyleRule
)
101 nsHTMLStyleSheet::GenericTableRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
108 nsHTMLStyleSheet::GenericTableRule::List(FILE* out
, PRInt32 aIndent
) const
114 nsHTMLStyleSheet::TableTHRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
116 if (aRuleData
->mSIDs
& NS_STYLE_INHERIT_BIT(Text
)) {
117 if (aRuleData
->mTextData
->mTextAlign
.GetUnit() == eCSSUnit_Null
) {
118 aRuleData
->mTextData
->mTextAlign
.
119 SetIntValue(NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT
,
120 eCSSUnit_Enumerated
);
125 // -----------------------------------------------------------
127 struct MappedAttrTableEntry
: public PLDHashEntryHdr
{
128 nsMappedAttributes
*mAttributes
;
132 MappedAttrTable_HashKey(PLDHashTable
*table
, const void *key
)
134 nsMappedAttributes
*attributes
=
135 static_cast<nsMappedAttributes
*>(const_cast<void*>(key
));
137 return attributes
->HashValue();
141 MappedAttrTable_ClearEntry(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
)
143 MappedAttrTableEntry
*entry
= static_cast<MappedAttrTableEntry
*>(hdr
);
145 entry
->mAttributes
->DropStyleSheetReference();
146 memset(entry
, 0, sizeof(MappedAttrTableEntry
));
150 MappedAttrTable_MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
153 nsMappedAttributes
*attributes
=
154 static_cast<nsMappedAttributes
*>(const_cast<void*>(key
));
155 const MappedAttrTableEntry
*entry
=
156 static_cast<const MappedAttrTableEntry
*>(hdr
);
158 return attributes
->Equals(entry
->mAttributes
);
161 static PLDHashTableOps MappedAttrTable_Ops
= {
164 MappedAttrTable_HashKey
,
165 MappedAttrTable_MatchEntry
,
166 PL_DHashMoveEntryStub
,
167 MappedAttrTable_ClearEntry
,
168 PL_DHashFinalizeStub
,
172 // -----------------------------------------------------------
174 nsHTMLStyleSheet::nsHTMLStyleSheet(void)
177 mMappedAttrTable
.ops
= nsnull
;
181 nsHTMLStyleSheet::Init()
183 mTableTHRule
= new TableTHRule();
185 return NS_ERROR_OUT_OF_MEMORY
;
189 nsHTMLStyleSheet::~nsHTMLStyleSheet()
191 if (mMappedAttrTable
.ops
)
192 PL_DHashTableFinish(&mMappedAttrTable
);
195 NS_IMPL_ISUPPORTS2(nsHTMLStyleSheet
, nsIStyleSheet
, nsIStyleRuleProcessor
)
197 static nsresult
GetBodyColor(nsPresContext
* aPresContext
, nscolor
* aColor
)
199 nsIPresShell
*shell
= aPresContext
->PresShell();
200 nsCOMPtr
<nsIHTMLDocument
> htmlDoc
= do_QueryInterface(shell
->GetDocument());
202 return NS_ERROR_FAILURE
;
203 nsIContent
* bodyContent
= htmlDoc
->GetBodyContentExternal();
205 return NS_ERROR_FAILURE
;
206 nsIFrame
*bodyFrame
= bodyContent
->GetPrimaryFrame();
208 return NS_ERROR_FAILURE
;
209 *aColor
= bodyFrame
->GetStyleColor()->mColor
;
214 nsHTMLStyleSheet::RulesMatching(ElementRuleProcessorData
* aData
)
216 nsRuleWalker
*ruleWalker
= aData
->mRuleWalker
;
217 if (aData
->mIsHTMLContent
) {
218 nsIAtom
* tag
= aData
->mContentTag
;
220 // if we have anchor colors, check if this is an anchor with an href
221 if (tag
== nsGkAtoms::a
) {
222 if (mLinkRule
|| mVisitedRule
|| mActiveRule
) {
223 nsEventStates state
= aData
->GetContentStateForVisitedHandling(
224 ruleWalker
->VisitedHandling(),
225 // If the node being matched is a link,
226 // it's the relevant link.
228 if (mLinkRule
&& state
.HasState(NS_EVENT_STATE_UNVISITED
)) {
229 ruleWalker
->Forward(mLinkRule
);
230 ruleWalker
->SetHaveRelevantLink();
232 else if (mVisitedRule
&& state
.HasState(NS_EVENT_STATE_VISITED
)) {
233 ruleWalker
->Forward(mVisitedRule
);
234 ruleWalker
->SetHaveRelevantLink();
237 // No need to add to the active rule if it's not a link
238 if (mActiveRule
&& aData
->IsLink() &&
239 state
.HasState(NS_EVENT_STATE_ACTIVE
)) {
240 ruleWalker
->Forward(mActiveRule
);
242 } // end link/visited/active rules
244 // add the rule to handle text-align for a <th>
245 else if (tag
== nsGkAtoms::th
) {
246 ruleWalker
->Forward(mTableTHRule
);
248 else if (tag
== nsGkAtoms::table
) {
249 if (aData
->mCompatMode
== eCompatibility_NavQuirks
) {
252 GetBodyColor(ruleWalker
->CurrentNode()->GetPresContext(),
254 if (NS_SUCCEEDED(rv
) &&
255 (!mDocumentColorRule
|| bodyColor
!= mDocumentColorRule
->mColor
)) {
256 mDocumentColorRule
= new HTMLColorRule();
257 if (mDocumentColorRule
) {
258 mDocumentColorRule
->mColor
= bodyColor
;
261 if (mDocumentColorRule
)
262 ruleWalker
->Forward(mDocumentColorRule
);
265 } // end html element
267 // just get the style rules from the content
268 aData
->mElement
->WalkContentStyleRules(ruleWalker
);
271 // Test if style is dependent on content state
272 /* virtual */ nsRestyleHint
273 nsHTMLStyleSheet::HasStateDependentStyle(StateRuleProcessorData
* aData
)
275 if (aData
->mIsHTMLContent
&&
276 aData
->mContentTag
== nsGkAtoms::a
&&
278 ((mActiveRule
&& aData
->mStateMask
.HasState(NS_EVENT_STATE_ACTIVE
)) ||
279 (mLinkRule
&& aData
->mStateMask
.HasState(NS_EVENT_STATE_VISITED
)) ||
280 (mVisitedRule
&& aData
->mStateMask
.HasState(NS_EVENT_STATE_VISITED
)))) {
281 return eRestyle_Self
;
284 return nsRestyleHint(0);
288 nsHTMLStyleSheet::HasDocumentStateDependentStyle(StateRuleProcessorData
* aData
)
293 /* virtual */ nsRestyleHint
294 nsHTMLStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData
* aData
)
296 // Do nothing on before-change checks
297 if (!aData
->mAttrHasChanged
) {
298 return nsRestyleHint(0);
301 // Note: no need to worry about whether some states changed with this
302 // attribute here, because we handle that under HasStateDependentStyle() as
305 // Result is true for |href| changes on HTML links if we have link rules.
306 Element
*element
= aData
->mElement
;
307 if (aData
->mAttribute
== nsGkAtoms::href
&&
308 (mLinkRule
|| mVisitedRule
|| mActiveRule
) &&
310 aData
->mContentTag
== nsGkAtoms::a
) {
311 return eRestyle_Self
;
314 // Don't worry about the mDocumentColorRule since it only applies
315 // to descendants of body, when we're already reresolving.
317 // Handle the content style rules.
318 if (element
->IsAttributeMapped(aData
->mAttribute
)) {
319 // cellpadding on tables is special and requires reresolving all
320 // the cells in the table
321 if (aData
->mAttribute
== nsGkAtoms::cellpadding
&&
323 aData
->mContentTag
== nsGkAtoms::table
) {
324 return eRestyle_Subtree
;
326 return eRestyle_Self
;
329 return nsRestyleHint(0);
333 nsHTMLStyleSheet::MediumFeaturesChanged(nsPresContext
* aPresContext
)
340 nsHTMLStyleSheet::RulesMatching(PseudoElementRuleProcessorData
* aData
)
345 nsHTMLStyleSheet::RulesMatching(AnonBoxRuleProcessorData
* aData
)
351 nsHTMLStyleSheet::RulesMatching(XULTreeRuleProcessorData
* aData
)
357 /* virtual */ nsIURI
*
358 nsHTMLStyleSheet::GetSheetURI() const
363 /* virtual */ nsIURI
*
364 nsHTMLStyleSheet::GetBaseURI() const
370 nsHTMLStyleSheet::GetTitle(nsString
& aTitle
) const
376 nsHTMLStyleSheet::GetType(nsString
& aType
) const
378 aType
.AssignLiteral("text/html");
382 nsHTMLStyleSheet::HasRules() const
384 return PR_TRUE
; // We have rules at all reasonable times
388 nsHTMLStyleSheet::IsApplicable() const
394 nsHTMLStyleSheet::SetEnabled(PRBool aEnabled
)
395 { // these can't be disabled
399 nsHTMLStyleSheet::IsComplete() const
405 nsHTMLStyleSheet::SetComplete()
409 /* virtual */ nsIStyleSheet
*
410 nsHTMLStyleSheet::GetParentSheet() const
415 /* virtual */ nsIDocument
*
416 nsHTMLStyleSheet::GetOwningDocument() const
422 nsHTMLStyleSheet::SetOwningDocument(nsIDocument
* aDocument
)
424 mDocument
= aDocument
; // not refcounted
428 nsHTMLStyleSheet::Init(nsIURI
* aURL
, nsIDocument
* aDocument
)
430 NS_PRECONDITION(aURL
&& aDocument
, "null ptr");
431 if (! aURL
|| ! aDocument
)
432 return NS_ERROR_NULL_POINTER
;
434 if (mURL
|| mDocument
)
435 return NS_ERROR_ALREADY_INITIALIZED
;
437 mDocument
= aDocument
; // not refcounted!
443 nsHTMLStyleSheet::Reset(nsIURI
* aURL
)
448 mVisitedRule
= nsnull
;
449 mActiveRule
= nsnull
;
450 mDocumentColorRule
= nsnull
;
452 if (mMappedAttrTable
.ops
) {
453 PL_DHashTableFinish(&mMappedAttrTable
);
454 mMappedAttrTable
.ops
= nsnull
;
459 nsHTMLStyleSheet::ImplLinkColorSetter(nsRefPtr
<HTMLColorRule
>& aRule
, nscolor aColor
)
461 if (aRule
&& aRule
->mColor
== aColor
) {
465 aRule
= new HTMLColorRule();
467 return NS_ERROR_OUT_OF_MEMORY
;
469 aRule
->mColor
= aColor
;
470 // Now make sure we restyle any links that might need it. This
471 // shouldn't happen often, so just rebuilding everything is ok.
472 if (mDocument
&& mDocument
->GetShell()) {
473 Element
* root
= mDocument
->GetRootElement();
475 mDocument
->GetShell()->FrameConstructor()->
476 PostRestyleEvent(root
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
483 nsHTMLStyleSheet::SetLinkColor(nscolor aColor
)
485 return ImplLinkColorSetter(mLinkRule
, aColor
);
490 nsHTMLStyleSheet::SetActiveLinkColor(nscolor aColor
)
492 return ImplLinkColorSetter(mActiveRule
, aColor
);
496 nsHTMLStyleSheet::SetVisitedLinkColor(nscolor aColor
)
498 return ImplLinkColorSetter(mVisitedRule
, aColor
);
501 already_AddRefed
<nsMappedAttributes
>
502 nsHTMLStyleSheet::UniqueMappedAttributes(nsMappedAttributes
* aMapped
)
504 if (!mMappedAttrTable
.ops
) {
505 PRBool res
= PL_DHashTableInit(&mMappedAttrTable
, &MappedAttrTable_Ops
,
506 nsnull
, sizeof(MappedAttrTableEntry
), 16);
508 mMappedAttrTable
.ops
= nsnull
;
512 MappedAttrTableEntry
*entry
= static_cast<MappedAttrTableEntry
*>
513 (PL_DHashTableOperate(&mMappedAttrTable
, aMapped
, PL_DHASH_ADD
));
516 if (!entry
->mAttributes
) {
517 // We added a new entry to the hashtable, so we have a new unique set.
518 entry
->mAttributes
= aMapped
;
520 NS_ADDREF(entry
->mAttributes
); // for caller
521 return entry
->mAttributes
;
525 nsHTMLStyleSheet::DropMappedAttributes(nsMappedAttributes
* aMapped
)
527 NS_ENSURE_TRUE(aMapped
, /**/);
529 NS_ASSERTION(mMappedAttrTable
.ops
, "table uninitialized");
531 PRUint32 entryCount
= mMappedAttrTable
.entryCount
- 1;
534 PL_DHashTableOperate(&mMappedAttrTable
, aMapped
, PL_DHASH_REMOVE
);
536 NS_ASSERTION(entryCount
== mMappedAttrTable
.entryCount
, "not removed");
541 nsHTMLStyleSheet::List(FILE* out
, PRInt32 aIndent
) const
544 for (PRInt32 index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
546 fputs("HTML Style Sheet: ", out
);
547 nsCAutoString urlSpec
;
548 mURL
->GetSpec(urlSpec
);
549 if (!urlSpec
.IsEmpty()) {
550 fputs(urlSpec
.get(), out
);
556 // XXX For convenience and backwards compatibility
558 NS_NewHTMLStyleSheet(nsHTMLStyleSheet
** aInstancePtrResult
, nsIURI
* aURL
,
559 nsIDocument
* aDocument
)
562 nsHTMLStyleSheet
* sheet
;
563 if (NS_FAILED(rv
= NS_NewHTMLStyleSheet(&sheet
)))
566 if (NS_FAILED(rv
= sheet
->Init(aURL
, aDocument
))) {
571 *aInstancePtrResult
= sheet
;
577 NS_NewHTMLStyleSheet(nsHTMLStyleSheet
** aInstancePtrResult
)
579 NS_ASSERTION(aInstancePtrResult
, "null out param");
581 nsHTMLStyleSheet
*it
= new nsHTMLStyleSheet();
583 *aInstancePtrResult
= nsnull
;
584 return NS_ERROR_OUT_OF_MEMORY
;
588 nsresult rv
= it
->Init();
592 *aInstancePtrResult
= it
; // NS_ADDREF above, or set to null by NS_RELEASE