layout/style/nsHTMLStyleSheet.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     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/.
     6  *
     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
    10  *
    11  * Date             Modified by     Description of modification
    12  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
    13  */
    15 /*
    16  * style sheet and style rule processor representing data from presentational
    17  * HTML attributes
    18  */
    20 #include "nsHTMLStyleSheet.h"
    21 #include "nsMappedAttributes.h"
    22 #include "nsGkAtoms.h"
    23 #include "nsPresContext.h"
    24 #include "mozilla/EventStates.h"
    25 #include "nsIDocument.h"
    26 #include "nsIPresShell.h"
    27 #include "nsStyleConsts.h"
    28 #include "nsRuleWalker.h"
    29 #include "nsRuleData.h"
    30 #include "nsError.h"
    31 #include "nsRuleProcessorData.h"
    32 #include "nsCSSRuleProcessor.h"
    33 #include "mozilla/MemoryReporting.h"
    34 #include "mozilla/dom/Element.h"
    35 #include "nsHashKeys.h"
    36 #include "RestyleManager.h"
    38 using namespace mozilla;
    39 using namespace mozilla::dom;
    41 NS_IMPL_ISUPPORTS(nsHTMLStyleSheet::HTMLColorRule, nsIStyleRule)
    43 /* virtual */ void
    44 nsHTMLStyleSheet::HTMLColorRule::MapRuleInfoInto(nsRuleData* aRuleData)
    45 {
    46   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
    47     nsCSSValue* color = aRuleData->ValueForColor();
    48     if (color->GetUnit() == eCSSUnit_Null &&
    49         aRuleData->mPresContext->UseDocumentColors())
    50       color->SetColorValue(mColor);
    51   }
    52 }
    54 #ifdef DEBUG
    55 /* virtual */ void
    56 nsHTMLStyleSheet::HTMLColorRule::List(FILE* out, int32_t aIndent) const
    57 {
    58   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
    59   fputs("[html color rule] {}\n", out);
    60 }
    61 #endif
    64 NS_IMPL_ISUPPORTS(nsHTMLStyleSheet::GenericTableRule, nsIStyleRule)
    66 #ifdef DEBUG
    67 /* virtual */ void
    68 nsHTMLStyleSheet::GenericTableRule::List(FILE* out, int32_t aIndent) const
    69 {
    70   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
    71   fputs("[generic table rule] {}\n", out);
    72 }
    73 #endif
    75 /* virtual */ void
    76 nsHTMLStyleSheet::TableTHRule::MapRuleInfoInto(nsRuleData* aRuleData)
    77 {
    78   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
    79     nsCSSValue* textAlign = aRuleData->ValueForTextAlign();
    80     if (textAlign->GetUnit() == eCSSUnit_Null) {
    81       textAlign->SetIntValue(NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT,
    82                              eCSSUnit_Enumerated);
    83     }
    84   }
    85 }
    87 /* virtual */ void
    88 nsHTMLStyleSheet::TableQuirkColorRule::MapRuleInfoInto(nsRuleData* aRuleData)
    89 {
    90   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
    91     nsCSSValue* color = aRuleData->ValueForColor();
    92     // We do not check UseDocumentColors() here, because we want to
    93     // use the body color no matter what.
    94     if (color->GetUnit() == eCSSUnit_Null)
    95       color->SetIntValue(NS_STYLE_COLOR_INHERIT_FROM_BODY,
    96                          eCSSUnit_Enumerated);
    97   }
    98 }
   101 NS_IMPL_ISUPPORTS(nsHTMLStyleSheet::LangRule, nsIStyleRule)
   103 /* virtual */ void
   104 nsHTMLStyleSheet::LangRule::MapRuleInfoInto(nsRuleData* aRuleData)
   105 {
   106   if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
   107     nsCSSValue* lang = aRuleData->ValueForLang();
   108     if (lang->GetUnit() == eCSSUnit_Null) {
   109       lang->SetStringValue(mLang, eCSSUnit_Ident);
   110     }
   111   }
   112 }
   114 #ifdef DEBUG
   115 /* virtual */ void
   116 nsHTMLStyleSheet::LangRule::List(FILE* out, int32_t aIndent) const
   117 {
   118   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
   119   fputs("[lang rule] { language: \"", out);
   120   fputs(NS_ConvertUTF16toUTF8(mLang).get(), out);
   121   fputs("\" }\n", out);
   122 }
   123 #endif
   125 // -----------------------------------------------------------
   127 struct MappedAttrTableEntry : public PLDHashEntryHdr {
   128   nsMappedAttributes *mAttributes;
   129 };
   131 static PLDHashNumber
   132 MappedAttrTable_HashKey(PLDHashTable *table, const void *key)
   133 {
   134   nsMappedAttributes *attributes =
   135     static_cast<nsMappedAttributes*>(const_cast<void*>(key));
   137   return attributes->HashValue();
   138 }
   140 static void
   141 MappedAttrTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
   142 {
   143   MappedAttrTableEntry *entry = static_cast<MappedAttrTableEntry*>(hdr);
   145   entry->mAttributes->DropStyleSheetReference();
   146   memset(entry, 0, sizeof(MappedAttrTableEntry));
   147 }
   149 static bool
   150 MappedAttrTable_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
   151                            const void *key)
   152 {
   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);
   159 }
   161 static const PLDHashTableOps MappedAttrTable_Ops = {
   162   PL_DHashAllocTable,
   163   PL_DHashFreeTable,
   164   MappedAttrTable_HashKey,
   165   MappedAttrTable_MatchEntry,
   166   PL_DHashMoveEntryStub,
   167   MappedAttrTable_ClearEntry,
   168   PL_DHashFinalizeStub,
   169   nullptr
   170 };
   172 // -----------------------------------------------------------
   174 struct LangRuleTableEntry : public PLDHashEntryHdr {
   175   nsRefPtr<nsHTMLStyleSheet::LangRule> mRule;
   176 };
   178 static PLDHashNumber
   179 LangRuleTable_HashKey(PLDHashTable *table, const void *key)
   180 {
   181   const nsString *lang = static_cast<const nsString*>(key);
   182   return HashString(*lang);
   183 }
   185 static void
   186 LangRuleTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
   187 {
   188   LangRuleTableEntry *entry = static_cast<LangRuleTableEntry*>(hdr);
   190   entry->~LangRuleTableEntry();
   191   memset(entry, 0, sizeof(LangRuleTableEntry));
   192 }
   194 static bool
   195 LangRuleTable_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
   196                          const void *key)
   197 {
   198   const nsString *lang = static_cast<const nsString*>(key);
   199   const LangRuleTableEntry *entry = static_cast<const LangRuleTableEntry*>(hdr);
   201   return entry->mRule->mLang == *lang;
   202 }
   204 static bool
   205 LangRuleTable_InitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
   206                         const void *key)
   207 {
   208   const nsString *lang = static_cast<const nsString*>(key);
   210   LangRuleTableEntry *entry = new (hdr) LangRuleTableEntry();
   212   // Create the unique rule for this language
   213   entry->mRule = new nsHTMLStyleSheet::LangRule(*lang);
   215   return true;
   216 }
   218 static const PLDHashTableOps LangRuleTable_Ops = {
   219   PL_DHashAllocTable,
   220   PL_DHashFreeTable,
   221   LangRuleTable_HashKey,
   222   LangRuleTable_MatchEntry,
   223   PL_DHashMoveEntryStub,
   224   LangRuleTable_ClearEntry,
   225   PL_DHashFinalizeStub,
   226   LangRuleTable_InitEntry
   227 };
   229 // -----------------------------------------------------------
   231 nsHTMLStyleSheet::nsHTMLStyleSheet(nsIDocument* aDocument)
   232   : mDocument(aDocument)
   233   , mTableQuirkColorRule(new TableQuirkColorRule())
   234   , mTableTHRule(new TableTHRule())
   235 {
   236   MOZ_ASSERT(aDocument);
   237   mMappedAttrTable.ops = nullptr;
   238   mLangRuleTable.ops = nullptr;
   239 }
   241 nsHTMLStyleSheet::~nsHTMLStyleSheet()
   242 {
   243   if (mLangRuleTable.ops)
   244     PL_DHashTableFinish(&mLangRuleTable);
   245   if (mMappedAttrTable.ops)
   246     PL_DHashTableFinish(&mMappedAttrTable);
   247 }
   249 NS_IMPL_ISUPPORTS(nsHTMLStyleSheet, nsIStyleRuleProcessor)
   251 /* virtual */ void
   252 nsHTMLStyleSheet::RulesMatching(ElementRuleProcessorData* aData)
   253 {
   254   nsRuleWalker *ruleWalker = aData->mRuleWalker;
   255   if (aData->mElement->IsHTML() && !ruleWalker->AuthorStyleDisabled()) {
   256     nsIAtom* tag = aData->mElement->Tag();
   258     // if we have anchor colors, check if this is an anchor with an href
   259     if (tag == nsGkAtoms::a) {
   260       if (mLinkRule || mVisitedRule || mActiveRule) {
   261         EventStates state =
   262           nsCSSRuleProcessor::GetContentStateForVisitedHandling(
   263                                   aData->mElement,
   264                                   aData->mTreeMatchContext,
   265                                   aData->mTreeMatchContext.VisitedHandling(),
   266                                   // If the node being matched is a link,
   267                                   // it's the relevant link.
   268                                   nsCSSRuleProcessor::IsLink(aData->mElement));
   269         if (mLinkRule && state.HasState(NS_EVENT_STATE_UNVISITED)) {
   270           ruleWalker->Forward(mLinkRule);
   271           aData->mTreeMatchContext.SetHaveRelevantLink();
   272         }
   273         else if (mVisitedRule && state.HasState(NS_EVENT_STATE_VISITED)) {
   274           ruleWalker->Forward(mVisitedRule);
   275           aData->mTreeMatchContext.SetHaveRelevantLink();
   276         }
   278         // No need to add to the active rule if it's not a link
   279         if (mActiveRule && nsCSSRuleProcessor::IsLink(aData->mElement) &&
   280             state.HasState(NS_EVENT_STATE_ACTIVE)) {
   281           ruleWalker->Forward(mActiveRule);
   282         }
   283       } // end link/visited/active rules
   284     } // end A tag
   285     // add the rule to handle text-align for a <th>
   286     else if (tag == nsGkAtoms::th) {
   287       ruleWalker->Forward(mTableTHRule);
   288     }
   289     else if (tag == nsGkAtoms::table) {
   290       if (aData->mTreeMatchContext.mCompatMode == eCompatibility_NavQuirks) {
   291         ruleWalker->Forward(mTableQuirkColorRule);
   292       }
   293     }
   294   } // end html element
   296   // just get the style rules from the content.  For SVG we do this even if
   297   // author style is disabled, because SVG presentational hints aren't
   298   // considered style.
   299   if (!ruleWalker->AuthorStyleDisabled() || aData->mElement->IsSVG()) {
   300     aData->mElement->WalkContentStyleRules(ruleWalker);
   301   }
   303   // http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#language
   304   // says that the xml:lang attribute overrides HTML's lang attribute,
   305   // so we need to do this after WalkContentStyleRules.
   306   nsString lang;
   307   if (aData->mElement->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang, lang)) {
   308     ruleWalker->Forward(LangRuleFor(lang));
   309   }
   310 }
   312 // Test if style is dependent on content state
   313 /* virtual */ nsRestyleHint
   314 nsHTMLStyleSheet::HasStateDependentStyle(StateRuleProcessorData* aData)
   315 {
   316   if (aData->mElement->IsHTML(nsGkAtoms::a) &&
   317       nsCSSRuleProcessor::IsLink(aData->mElement) &&
   318       ((mActiveRule && aData->mStateMask.HasState(NS_EVENT_STATE_ACTIVE)) ||
   319        (mLinkRule && aData->mStateMask.HasState(NS_EVENT_STATE_VISITED)) ||
   320        (mVisitedRule && aData->mStateMask.HasState(NS_EVENT_STATE_VISITED)))) {
   321     return eRestyle_Self;
   322   }
   324   return nsRestyleHint(0);
   325 }
   327 /* virtual */ nsRestyleHint
   328 nsHTMLStyleSheet::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
   329 {
   330   return nsRestyleHint(0);
   331 }
   333 /* virtual */ bool
   334 nsHTMLStyleSheet::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
   335 {
   336   return false;
   337 }
   339 /* virtual */ nsRestyleHint
   340 nsHTMLStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
   341 {
   342   // Do nothing on before-change checks
   343   if (!aData->mAttrHasChanged) {
   344     return nsRestyleHint(0);
   345   }
   347   // Note: no need to worry about whether some states changed with this
   348   // attribute here, because we handle that under HasStateDependentStyle() as
   349   // needed.
   351   // Result is true for |href| changes on HTML links if we have link rules.
   352   Element *element = aData->mElement;
   353   if (aData->mAttribute == nsGkAtoms::href &&
   354       (mLinkRule || mVisitedRule || mActiveRule) &&
   355       element->IsHTML(nsGkAtoms::a)) {
   356     return eRestyle_Self;
   357   }
   359   // Don't worry about the mDocumentColorRule since it only applies
   360   // to descendants of body, when we're already reresolving.
   362   // Handle the content style rules.
   363   if (element->IsAttributeMapped(aData->mAttribute)) {
   364     // cellpadding on tables is special and requires reresolving all
   365     // the cells in the table
   366     if (aData->mAttribute == nsGkAtoms::cellpadding &&
   367         element->IsHTML(nsGkAtoms::table)) {
   368       return eRestyle_Subtree;
   369     }
   370     return eRestyle_Self;
   371   }
   373   return nsRestyleHint(0);
   374 }
   376 /* virtual */ bool
   377 nsHTMLStyleSheet::MediumFeaturesChanged(nsPresContext* aPresContext)
   378 {
   379   return false;
   380 }
   382 /* virtual */ size_t
   383 nsHTMLStyleSheet::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   384 {
   385   return 0; // nsHTMLStyleSheets are charged to the DOM, not layout
   386 }
   388 /* virtual */ size_t
   389 nsHTMLStyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   390 {
   391   return 0; // nsHTMLStyleSheets are charged to the DOM, not layout
   392 }
   394 /* virtual */ void
   395 nsHTMLStyleSheet::RulesMatching(PseudoElementRuleProcessorData* aData)
   396 {
   397 }
   399 /* virtual */ void
   400 nsHTMLStyleSheet::RulesMatching(AnonBoxRuleProcessorData* aData)
   401 {
   402 }
   404 #ifdef MOZ_XUL
   405 /* virtual */ void
   406 nsHTMLStyleSheet::RulesMatching(XULTreeRuleProcessorData* aData)
   407 {
   408 }
   409 #endif
   411 void
   412 nsHTMLStyleSheet::SetOwningDocument(nsIDocument* aDocument)
   413 {
   414   mDocument = aDocument; // not refcounted
   415 }
   417 void
   418 nsHTMLStyleSheet::Reset()
   419 {
   420   mLinkRule          = nullptr;
   421   mVisitedRule       = nullptr;
   422   mActiveRule        = nullptr;
   424   if (mLangRuleTable.ops) {
   425     PL_DHashTableFinish(&mLangRuleTable);
   426     mLangRuleTable.ops = nullptr;
   427   }
   428   if (mMappedAttrTable.ops) {
   429     PL_DHashTableFinish(&mMappedAttrTable);
   430     mMappedAttrTable.ops = nullptr;
   431   }
   432 }
   434 nsresult
   435 nsHTMLStyleSheet::ImplLinkColorSetter(nsRefPtr<HTMLColorRule>& aRule, nscolor aColor)
   436 {
   437   if (aRule && aRule->mColor == aColor) {
   438     return NS_OK;
   439   }
   441   aRule = new HTMLColorRule();
   442   if (!aRule)
   443     return NS_ERROR_OUT_OF_MEMORY;
   445   aRule->mColor = aColor;
   446   // Now make sure we restyle any links that might need it.  This
   447   // shouldn't happen often, so just rebuilding everything is ok.
   448   if (mDocument && mDocument->GetShell()) {
   449     Element* root = mDocument->GetRootElement();
   450     if (root) {
   451       mDocument->GetShell()->GetPresContext()->RestyleManager()->
   452         PostRestyleEvent(root, eRestyle_Subtree, NS_STYLE_HINT_NONE);
   453     }
   454   }
   455   return NS_OK;
   456 }
   458 nsresult
   459 nsHTMLStyleSheet::SetLinkColor(nscolor aColor)
   460 {
   461   return ImplLinkColorSetter(mLinkRule, aColor);
   462 }
   465 nsresult
   466 nsHTMLStyleSheet::SetActiveLinkColor(nscolor aColor)
   467 {
   468   return ImplLinkColorSetter(mActiveRule, aColor);
   469 }
   471 nsresult
   472 nsHTMLStyleSheet::SetVisitedLinkColor(nscolor aColor)
   473 {
   474   return ImplLinkColorSetter(mVisitedRule, aColor);
   475 }
   477 already_AddRefed<nsMappedAttributes>
   478 nsHTMLStyleSheet::UniqueMappedAttributes(nsMappedAttributes* aMapped)
   479 {
   480   if (!mMappedAttrTable.ops) {
   481     PL_DHashTableInit(&mMappedAttrTable, &MappedAttrTable_Ops,
   482                       nullptr, sizeof(MappedAttrTableEntry), 16);
   483   }
   484   MappedAttrTableEntry *entry = static_cast<MappedAttrTableEntry*>
   485                                            (PL_DHashTableOperate(&mMappedAttrTable, aMapped, PL_DHASH_ADD));
   486   if (!entry)
   487     return nullptr;
   488   if (!entry->mAttributes) {
   489     // We added a new entry to the hashtable, so we have a new unique set.
   490     entry->mAttributes = aMapped;
   491   }
   492   nsRefPtr<nsMappedAttributes> ret = entry->mAttributes;
   493   return ret.forget();
   494 }
   496 void
   497 nsHTMLStyleSheet::DropMappedAttributes(nsMappedAttributes* aMapped)
   498 {
   499   NS_ENSURE_TRUE_VOID(aMapped);
   501   NS_ASSERTION(mMappedAttrTable.ops, "table uninitialized");
   502 #ifdef DEBUG
   503   uint32_t entryCount = mMappedAttrTable.entryCount - 1;
   504 #endif
   506   PL_DHashTableOperate(&mMappedAttrTable, aMapped, PL_DHASH_REMOVE);
   508   NS_ASSERTION(entryCount == mMappedAttrTable.entryCount, "not removed");
   509 }
   511 nsIStyleRule*
   512 nsHTMLStyleSheet::LangRuleFor(const nsString& aLanguage)
   513 {
   514   if (!mLangRuleTable.ops) {
   515     PL_DHashTableInit(&mLangRuleTable, &LangRuleTable_Ops,
   516                       nullptr, sizeof(LangRuleTableEntry), 16);
   517   }
   518   LangRuleTableEntry *entry = static_cast<LangRuleTableEntry*>
   519     (PL_DHashTableOperate(&mLangRuleTable, &aLanguage, PL_DHASH_ADD));
   520   if (!entry) {
   521     NS_ASSERTION(false, "out of memory");
   522     return nullptr;
   523   }
   524   return entry->mRule;
   525 }
   527 static size_t
   528 SizeOfAttributesEntryExcludingThis(PLDHashEntryHdr* aEntry,
   529                                    MallocSizeOf aMallocSizeOf,
   530                                    void* aArg)
   531 {
   532   NS_PRECONDITION(aEntry, "The entry should not be null!");
   534   MappedAttrTableEntry* entry = static_cast<MappedAttrTableEntry*>(aEntry);
   535   NS_ASSERTION(entry->mAttributes, "entry->mAttributes should not be null!");
   536   return entry->mAttributes->SizeOfIncludingThis(aMallocSizeOf);
   537 }
   539 size_t
   540 nsHTMLStyleSheet::DOMSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   541 {
   542   size_t n = aMallocSizeOf(this);
   544   if (mMappedAttrTable.ops) {
   545     n += PL_DHashTableSizeOfExcludingThis(&mMappedAttrTable,
   546                                           SizeOfAttributesEntryExcludingThis,
   547                                           aMallocSizeOf);
   548   }
   550   // Measurement of the following members may be added later if DMD finds it is
   551   // worthwhile:
   552   // - mURL
   553   // - mLinkRule
   554   // - mVisitedRule
   555   // - mActiveRule
   556   // - mTableQuirkColorRule
   557   // - mTableTHRule
   558   // - mLangRuleTable
   559   //
   560   // The following members are not measured:
   561   // - mDocument, because it's non-owning
   563   return n;
   564 }

mercurial