1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 * This Original Code has been modified by IBM Corporation. Modifications made by IBM
8 * described herein are Copyright (c) International Business Machines Corporation, 2000.
9 * Modifications to Mozilla code or documentation identified per MPL Section 3.3
11 * Date Modified by Description of modification
12 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
16 * style sheet and style rule processor representing data from presentational
20 #include "nsHTMLStyleSheet.h"
21 #include "nsMappedAttributes.h"
22 #include "nsGkAtoms.h"
23 #include "nsPresContext.h"
24 #include "nsEventStates.h"
25 #include "nsIDocument.h"
26 #include "nsIPresShell.h"
27 #include "nsStyleConsts.h"
28 #include "nsRuleWalker.h"
29 #include "nsRuleData.h"
31 #include "nsRuleProcessorData.h"
32 #include "nsCSSRuleProcessor.h"
33 #include "mozilla/dom/Element.h"
34 #include "nsCSSFrameConstructor.h"
36 using namespace mozilla::dom
;
38 NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::HTMLColorRule
, nsIStyleRule
)
41 nsHTMLStyleSheet::HTMLColorRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
43 if (aRuleData
->mSIDs
& NS_STYLE_INHERIT_BIT(Color
)) {
44 nsCSSValue
* color
= aRuleData
->ValueForColor();
45 if (color
->GetUnit() == eCSSUnit_Null
&&
46 aRuleData
->mPresContext
->UseDocumentColors())
47 color
->SetColorValue(mColor
);
53 nsHTMLStyleSheet::HTMLColorRule::List(FILE* out
, int32_t aIndent
) const
55 for (int32_t index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
56 fputs("[html color rule] {}\n", out
);
61 NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::GenericTableRule
, nsIStyleRule
)
65 nsHTMLStyleSheet::GenericTableRule::List(FILE* out
, int32_t aIndent
) const
67 for (int32_t index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
68 fputs("[generic table rule] {}\n", out
);
73 nsHTMLStyleSheet::TableTHRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
75 if (aRuleData
->mSIDs
& NS_STYLE_INHERIT_BIT(Text
)) {
76 nsCSSValue
* textAlign
= aRuleData
->ValueForTextAlign();
77 if (textAlign
->GetUnit() == eCSSUnit_Null
) {
78 textAlign
->SetIntValue(NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT
,
85 nsHTMLStyleSheet::TableQuirkColorRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
87 if (aRuleData
->mSIDs
& NS_STYLE_INHERIT_BIT(Color
)) {
88 nsCSSValue
* color
= aRuleData
->ValueForColor();
89 // We do not check UseDocumentColors() here, because we want to
90 // use the body color no matter what.
91 if (color
->GetUnit() == eCSSUnit_Null
)
92 color
->SetIntValue(NS_STYLE_COLOR_INHERIT_FROM_BODY
,
97 // -----------------------------------------------------------
99 struct MappedAttrTableEntry
: public PLDHashEntryHdr
{
100 nsMappedAttributes
*mAttributes
;
104 MappedAttrTable_HashKey(PLDHashTable
*table
, const void *key
)
106 nsMappedAttributes
*attributes
=
107 static_cast<nsMappedAttributes
*>(const_cast<void*>(key
));
109 return attributes
->HashValue();
113 MappedAttrTable_ClearEntry(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
)
115 MappedAttrTableEntry
*entry
= static_cast<MappedAttrTableEntry
*>(hdr
);
117 entry
->mAttributes
->DropStyleSheetReference();
118 memset(entry
, 0, sizeof(MappedAttrTableEntry
));
122 MappedAttrTable_MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
125 nsMappedAttributes
*attributes
=
126 static_cast<nsMappedAttributes
*>(const_cast<void*>(key
));
127 const MappedAttrTableEntry
*entry
=
128 static_cast<const MappedAttrTableEntry
*>(hdr
);
130 return attributes
->Equals(entry
->mAttributes
);
133 static PLDHashTableOps MappedAttrTable_Ops
= {
136 MappedAttrTable_HashKey
,
137 MappedAttrTable_MatchEntry
,
138 PL_DHashMoveEntryStub
,
139 MappedAttrTable_ClearEntry
,
140 PL_DHashFinalizeStub
,
144 // -----------------------------------------------------------
146 nsHTMLStyleSheet::nsHTMLStyleSheet(nsIURI
* aURL
, nsIDocument
* aDocument
)
148 , mDocument(aDocument
)
149 , mTableQuirkColorRule(new TableQuirkColorRule())
150 , mTableTHRule(new TableTHRule())
153 MOZ_ASSERT(aDocument
);
154 mMappedAttrTable
.ops
= nullptr;
157 nsHTMLStyleSheet::~nsHTMLStyleSheet()
159 if (mMappedAttrTable
.ops
)
160 PL_DHashTableFinish(&mMappedAttrTable
);
163 NS_IMPL_ISUPPORTS2(nsHTMLStyleSheet
, nsIStyleSheet
, nsIStyleRuleProcessor
)
166 nsHTMLStyleSheet::RulesMatching(ElementRuleProcessorData
* aData
)
168 nsRuleWalker
*ruleWalker
= aData
->mRuleWalker
;
169 if (aData
->mElement
->IsHTML() && !ruleWalker
->AuthorStyleDisabled()) {
170 nsIAtom
* tag
= aData
->mElement
->Tag();
172 // if we have anchor colors, check if this is an anchor with an href
173 if (tag
== nsGkAtoms::a
) {
174 if (mLinkRule
|| mVisitedRule
|| mActiveRule
) {
175 nsEventStates state
= nsCSSRuleProcessor::GetContentStateForVisitedHandling(
177 aData
->mTreeMatchContext
,
178 aData
->mTreeMatchContext
.VisitedHandling(),
179 // If the node being matched is a link,
180 // it's the relevant link.
181 nsCSSRuleProcessor::IsLink(aData
->mElement
));
182 if (mLinkRule
&& state
.HasState(NS_EVENT_STATE_UNVISITED
)) {
183 ruleWalker
->Forward(mLinkRule
);
184 aData
->mTreeMatchContext
.SetHaveRelevantLink();
186 else if (mVisitedRule
&& state
.HasState(NS_EVENT_STATE_VISITED
)) {
187 ruleWalker
->Forward(mVisitedRule
);
188 aData
->mTreeMatchContext
.SetHaveRelevantLink();
191 // No need to add to the active rule if it's not a link
192 if (mActiveRule
&& nsCSSRuleProcessor::IsLink(aData
->mElement
) &&
193 state
.HasState(NS_EVENT_STATE_ACTIVE
)) {
194 ruleWalker
->Forward(mActiveRule
);
196 } // end link/visited/active rules
198 // add the rule to handle text-align for a <th>
199 else if (tag
== nsGkAtoms::th
) {
200 ruleWalker
->Forward(mTableTHRule
);
202 else if (tag
== nsGkAtoms::table
) {
203 if (aData
->mTreeMatchContext
.mCompatMode
== eCompatibility_NavQuirks
) {
204 ruleWalker
->Forward(mTableQuirkColorRule
);
207 } // end html element
209 // just get the style rules from the content. For SVG we do this even if
210 // author style is disabled, because SVG presentational hints aren't
212 if (!ruleWalker
->AuthorStyleDisabled() || aData
->mElement
->IsSVG()) {
213 aData
->mElement
->WalkContentStyleRules(ruleWalker
);
217 // Test if style is dependent on content state
218 /* virtual */ nsRestyleHint
219 nsHTMLStyleSheet::HasStateDependentStyle(StateRuleProcessorData
* aData
)
221 if (aData
->mElement
->IsHTML(nsGkAtoms::a
) &&
222 nsCSSRuleProcessor::IsLink(aData
->mElement
) &&
223 ((mActiveRule
&& aData
->mStateMask
.HasState(NS_EVENT_STATE_ACTIVE
)) ||
224 (mLinkRule
&& aData
->mStateMask
.HasState(NS_EVENT_STATE_VISITED
)) ||
225 (mVisitedRule
&& aData
->mStateMask
.HasState(NS_EVENT_STATE_VISITED
)))) {
226 return eRestyle_Self
;
229 return nsRestyleHint(0);
233 nsHTMLStyleSheet::HasDocumentStateDependentStyle(StateRuleProcessorData
* aData
)
238 /* virtual */ nsRestyleHint
239 nsHTMLStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData
* aData
)
241 // Do nothing on before-change checks
242 if (!aData
->mAttrHasChanged
) {
243 return nsRestyleHint(0);
246 // Note: no need to worry about whether some states changed with this
247 // attribute here, because we handle that under HasStateDependentStyle() as
250 // Result is true for |href| changes on HTML links if we have link rules.
251 Element
*element
= aData
->mElement
;
252 if (aData
->mAttribute
== nsGkAtoms::href
&&
253 (mLinkRule
|| mVisitedRule
|| mActiveRule
) &&
254 element
->IsHTML(nsGkAtoms::a
)) {
255 return eRestyle_Self
;
258 // Don't worry about the mDocumentColorRule since it only applies
259 // to descendants of body, when we're already reresolving.
261 // Handle the content style rules.
262 if (element
->IsAttributeMapped(aData
->mAttribute
)) {
263 // cellpadding on tables is special and requires reresolving all
264 // the cells in the table
265 if (aData
->mAttribute
== nsGkAtoms::cellpadding
&&
266 element
->IsHTML(nsGkAtoms::table
)) {
267 return eRestyle_Subtree
;
269 return eRestyle_Self
;
272 return nsRestyleHint(0);
276 nsHTMLStyleSheet::MediumFeaturesChanged(nsPresContext
* aPresContext
)
282 nsHTMLStyleSheet::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf
) const
284 return 0; // nsHTMLStyleSheets are charged to the DOM, not layout
288 nsHTMLStyleSheet::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf
) const
290 return 0; // nsHTMLStyleSheets are charged to the DOM, not layout
294 nsHTMLStyleSheet::RulesMatching(PseudoElementRuleProcessorData
* aData
)
299 nsHTMLStyleSheet::RulesMatching(AnonBoxRuleProcessorData
* aData
)
305 nsHTMLStyleSheet::RulesMatching(XULTreeRuleProcessorData
* aData
)
311 /* virtual */ nsIURI
*
312 nsHTMLStyleSheet::GetSheetURI() const
317 /* virtual */ nsIURI
*
318 nsHTMLStyleSheet::GetBaseURI() const
324 nsHTMLStyleSheet::GetTitle(nsString
& aTitle
) const
330 nsHTMLStyleSheet::GetType(nsString
& aType
) const
332 aType
.AssignLiteral("text/html");
336 nsHTMLStyleSheet::HasRules() const
338 return true; // We have rules at all reasonable times
342 nsHTMLStyleSheet::IsApplicable() const
348 nsHTMLStyleSheet::SetEnabled(bool aEnabled
)
349 { // these can't be disabled
353 nsHTMLStyleSheet::IsComplete() const
359 nsHTMLStyleSheet::SetComplete()
363 /* virtual */ nsIStyleSheet
*
364 nsHTMLStyleSheet::GetParentSheet() const
369 /* virtual */ nsIDocument
*
370 nsHTMLStyleSheet::GetOwningDocument() const
376 nsHTMLStyleSheet::SetOwningDocument(nsIDocument
* aDocument
)
378 mDocument
= aDocument
; // not refcounted
382 nsHTMLStyleSheet::Reset(nsIURI
* aURL
)
387 mVisitedRule
= nullptr;
388 mActiveRule
= nullptr;
390 if (mMappedAttrTable
.ops
) {
391 PL_DHashTableFinish(&mMappedAttrTable
);
392 mMappedAttrTable
.ops
= nullptr;
397 nsHTMLStyleSheet::ImplLinkColorSetter(nsRefPtr
<HTMLColorRule
>& aRule
, nscolor aColor
)
399 if (aRule
&& aRule
->mColor
== aColor
) {
403 aRule
= new HTMLColorRule();
405 return NS_ERROR_OUT_OF_MEMORY
;
407 aRule
->mColor
= aColor
;
408 // Now make sure we restyle any links that might need it. This
409 // shouldn't happen often, so just rebuilding everything is ok.
410 if (mDocument
&& mDocument
->GetShell()) {
411 Element
* root
= mDocument
->GetRootElement();
413 mDocument
->GetShell()->FrameConstructor()->
414 PostRestyleEvent(root
, eRestyle_Subtree
, NS_STYLE_HINT_NONE
);
421 nsHTMLStyleSheet::SetLinkColor(nscolor aColor
)
423 return ImplLinkColorSetter(mLinkRule
, aColor
);
428 nsHTMLStyleSheet::SetActiveLinkColor(nscolor aColor
)
430 return ImplLinkColorSetter(mActiveRule
, aColor
);
434 nsHTMLStyleSheet::SetVisitedLinkColor(nscolor aColor
)
436 return ImplLinkColorSetter(mVisitedRule
, aColor
);
439 already_AddRefed
<nsMappedAttributes
>
440 nsHTMLStyleSheet::UniqueMappedAttributes(nsMappedAttributes
* aMapped
)
442 if (!mMappedAttrTable
.ops
) {
443 bool res
= PL_DHashTableInit(&mMappedAttrTable
, &MappedAttrTable_Ops
,
444 nullptr, sizeof(MappedAttrTableEntry
), 16);
446 mMappedAttrTable
.ops
= nullptr;
450 MappedAttrTableEntry
*entry
= static_cast<MappedAttrTableEntry
*>
451 (PL_DHashTableOperate(&mMappedAttrTable
, aMapped
, PL_DHASH_ADD
));
454 if (!entry
->mAttributes
) {
455 // We added a new entry to the hashtable, so we have a new unique set.
456 entry
->mAttributes
= aMapped
;
458 nsRefPtr
<nsMappedAttributes
> ret
= entry
->mAttributes
;
463 nsHTMLStyleSheet::DropMappedAttributes(nsMappedAttributes
* aMapped
)
465 NS_ENSURE_TRUE_VOID(aMapped
);
467 NS_ASSERTION(mMappedAttrTable
.ops
, "table uninitialized");
469 uint32_t entryCount
= mMappedAttrTable
.entryCount
- 1;
472 PL_DHashTableOperate(&mMappedAttrTable
, aMapped
, PL_DHASH_REMOVE
);
474 NS_ASSERTION(entryCount
== mMappedAttrTable
.entryCount
, "not removed");
479 nsHTMLStyleSheet::List(FILE* out
, int32_t aIndent
) const
482 for (int32_t index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
484 fputs("HTML Style Sheet: ", out
);
485 nsAutoCString urlSpec
;
486 mURL
->GetSpec(urlSpec
);
487 if (!urlSpec
.IsEmpty()) {
488 fputs(urlSpec
.get(), out
);
495 SizeOfAttributesEntryExcludingThis(PLDHashEntryHdr
* aEntry
,
496 nsMallocSizeOfFun aMallocSizeOf
,
499 NS_PRECONDITION(aEntry
, "The entry should not be null!");
501 MappedAttrTableEntry
* entry
= static_cast<MappedAttrTableEntry
*>(aEntry
);
502 NS_ASSERTION(entry
->mAttributes
, "entry->mAttributes should not be null!");
503 return entry
->mAttributes
->SizeOfIncludingThis(aMallocSizeOf
);
507 nsHTMLStyleSheet::DOMSizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf
) const
509 size_t n
= aMallocSizeOf(this);
511 if (mMappedAttrTable
.ops
) {
512 n
+= PL_DHashTableSizeOfExcludingThis(&mMappedAttrTable
,
513 SizeOfAttributesEntryExcludingThis
,
517 // Measurement of the following members may be added later if DMD finds it is
523 // - mTableQuirkColorRule
526 // The following members are not measured:
527 // - mDocument, because it's non-owning