LCOV - code coverage report
Current view: directory - layout/style - nsStyleContext.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 321 0 0.0 %
Date: 2012-06-02 Functions: 21 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   David Hyatt <hyatt@netscape.com>
      24                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 :  
      40                 : /* the interface (to internal code) for retrieving computed style data */
      41                 : 
      42                 : #include "nsStyleConsts.h"
      43                 : #include "nsString.h"
      44                 : #include "nsPresContext.h"
      45                 : #include "nsIStyleRule.h"
      46                 : 
      47                 : #include "nsCOMPtr.h"
      48                 : #include "nsStyleSet.h"
      49                 : #include "nsIPresShell.h"
      50                 : 
      51                 : #include "nsRuleNode.h"
      52                 : #include "nsStyleContext.h"
      53                 : #include "prlog.h"
      54                 : #include "nsStyleAnimation.h"
      55                 : 
      56                 : #ifdef DEBUG
      57                 : // #define NOISY_DEBUG
      58                 : #endif
      59                 : 
      60                 : //----------------------------------------------------------------------
      61                 : 
      62                 : 
      63               0 : nsStyleContext::nsStyleContext(nsStyleContext* aParent,
      64                 :                                nsIAtom* aPseudoTag,
      65                 :                                nsCSSPseudoElements::Type aPseudoType,
      66                 :                                nsRuleNode* aRuleNode,
      67                 :                                nsPresContext* aPresContext)
      68                 :   : mParent(aParent),
      69                 :     mChild(nsnull),
      70                 :     mEmptyChild(nsnull),
      71                 :     mPseudoTag(aPseudoTag),
      72                 :     mRuleNode(aRuleNode),
      73                 :     mAllocations(nsnull),
      74                 :     mCachedResetData(nsnull),
      75                 :     mBits(((PRUint32)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT),
      76               0 :     mRefCnt(0)
      77                 : {
      78                 :   // This check has to be done "backward", because if it were written the
      79                 :   // more natural way it wouldn't fail even when it needed to.
      80                 :   MOZ_STATIC_ASSERT((PR_UINT32_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
      81                 :                     nsCSSPseudoElements::ePseudo_MAX,
      82                 :                     "pseudo element bits no longer fit in a PRUint32");
      83                 : 
      84               0 :   mNextSibling = this;
      85               0 :   mPrevSibling = this;
      86               0 :   if (mParent) {
      87               0 :     mParent->AddRef();
      88               0 :     mParent->AddChild(this);
      89                 : #ifdef DEBUG
      90               0 :     nsRuleNode *r1 = mParent->GetRuleNode(), *r2 = aRuleNode;
      91               0 :     while (r1->GetParent())
      92               0 :       r1 = r1->GetParent();
      93               0 :     while (r2->GetParent())
      94               0 :       r2 = r2->GetParent();
      95               0 :     NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
      96                 : #endif
      97                 :   }
      98                 : 
      99               0 :   ApplyStyleFixups(aPresContext);
     100                 : 
     101                 :   #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
     102                 :   NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
     103                 :                "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
     104                 :   #undef eStyleStruct_LastItem
     105                 : 
     106               0 :   mRuleNode->AddRef();
     107               0 : }
     108                 : 
     109               0 : nsStyleContext::~nsStyleContext()
     110                 : {
     111               0 :   NS_ASSERTION((nsnull == mChild) && (nsnull == mEmptyChild), "destructing context with children");
     112                 : 
     113               0 :   nsPresContext *presContext = mRuleNode->GetPresContext();
     114                 : 
     115               0 :   mRuleNode->Release();
     116                 : 
     117                 :   presContext->PresShell()->StyleSet()->
     118               0 :     NotifyStyleContextDestroyed(presContext, this);
     119                 : 
     120               0 :   if (mParent) {
     121               0 :     mParent->RemoveChild(this);
     122               0 :     mParent->Release();
     123                 :   }
     124                 : 
     125                 :   // Free up our data structs.
     126               0 :   mCachedInheritedData.DestroyStructs(mBits, presContext);
     127               0 :   if (mCachedResetData) {
     128               0 :     mCachedResetData->Destroy(mBits, presContext);
     129                 :   }
     130                 : 
     131               0 :   FreeAllocations(presContext);
     132               0 : }
     133                 : 
     134               0 : void nsStyleContext::AddChild(nsStyleContext* aChild)
     135                 : {
     136               0 :   NS_ASSERTION(aChild->mPrevSibling == aChild &&
     137                 :                aChild->mNextSibling == aChild,
     138                 :                "child already in a child list");
     139                 : 
     140               0 :   nsStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
     141                 : 
     142                 :   // Insert at the beginning of the list.  See also FindChildWithRules.
     143               0 :   if (*list) {
     144                 :     // Link into existing elements, if there are any.
     145               0 :     aChild->mNextSibling = (*list);
     146               0 :     aChild->mPrevSibling = (*list)->mPrevSibling;
     147               0 :     (*list)->mPrevSibling->mNextSibling = aChild;
     148               0 :     (*list)->mPrevSibling = aChild;
     149                 :   }
     150               0 :   (*list) = aChild;
     151               0 : }
     152                 : 
     153               0 : void nsStyleContext::RemoveChild(nsStyleContext* aChild)
     154                 : {
     155               0 :   NS_PRECONDITION(nsnull != aChild && this == aChild->mParent, "bad argument");
     156                 : 
     157               0 :   nsStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
     158                 : 
     159               0 :   if (aChild->mPrevSibling != aChild) { // has siblings
     160               0 :     if ((*list) == aChild) {
     161               0 :       (*list) = (*list)->mNextSibling;
     162                 :     }
     163                 :   } 
     164                 :   else {
     165               0 :     NS_ASSERTION((*list) == aChild, "bad sibling pointers");
     166               0 :     (*list) = nsnull;
     167                 :   }
     168                 : 
     169               0 :   aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
     170               0 :   aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
     171               0 :   aChild->mNextSibling = aChild;
     172               0 :   aChild->mPrevSibling = aChild;
     173               0 : }
     174                 : 
     175                 : already_AddRefed<nsStyleContext>
     176               0 : nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag, 
     177                 :                                    nsRuleNode* aRuleNode,
     178                 :                                    nsRuleNode* aRulesIfVisited,
     179                 :                                    bool aRelevantLinkVisited)
     180                 : {
     181               0 :   NS_ABORT_IF_FALSE(aRulesIfVisited || !aRelevantLinkVisited,
     182                 :     "aRelevantLinkVisited should only be set when we have a separate style");
     183               0 :   PRUint32 threshold = 10; // The # of siblings we're willing to examine
     184                 :                            // before just giving this whole thing up.
     185                 : 
     186               0 :   nsStyleContext* result = nsnull;
     187               0 :   nsStyleContext *list = aRuleNode->IsRoot() ? mEmptyChild : mChild;
     188                 : 
     189               0 :   if (list) {
     190               0 :     nsStyleContext *child = list;
     191               0 :     do {
     192               0 :       if (child->mRuleNode == aRuleNode &&
     193               0 :           child->mPseudoTag == aPseudoTag &&
     194               0 :           !child->IsStyleIfVisited() &&
     195               0 :           child->RelevantLinkVisited() == aRelevantLinkVisited) {
     196               0 :         bool match = false;
     197               0 :         if (aRulesIfVisited) {
     198               0 :           match = child->GetStyleIfVisited() &&
     199               0 :                   child->GetStyleIfVisited()->mRuleNode == aRulesIfVisited;
     200                 :         } else {
     201               0 :           match = !child->GetStyleIfVisited();
     202                 :         }
     203               0 :         if (match) {
     204               0 :           result = child;
     205               0 :           break;
     206                 :         }
     207                 :       }
     208               0 :       child = child->mNextSibling;
     209               0 :       threshold--;
     210               0 :       if (threshold == 0)
     211               0 :         break;
     212                 :     } while (child != list);
     213                 :   }
     214                 : 
     215               0 :   if (result) {
     216               0 :     if (result != list) {
     217                 :       // Move result to the front of the list.
     218               0 :       RemoveChild(result);
     219               0 :       AddChild(result);
     220                 :     }
     221                 : 
     222                 :     // Add reference for the caller.
     223               0 :     result->AddRef();
     224                 :   }
     225                 : 
     226               0 :   return result;
     227                 : }
     228                 : 
     229               0 : const void* nsStyleContext::GetCachedStyleData(nsStyleStructID aSID)
     230                 : {
     231                 :   const void* cachedData;
     232               0 :   if (nsCachedStyleData::IsReset(aSID)) {
     233               0 :     if (mCachedResetData) {
     234               0 :       cachedData = mCachedResetData->mStyleStructs[aSID];
     235                 :     } else {
     236               0 :       cachedData = nsnull;
     237                 :     }
     238                 :   } else {
     239               0 :     cachedData = mCachedInheritedData.mStyleStructs[aSID];
     240                 :   }
     241               0 :   return cachedData;
     242                 : }
     243                 : 
     244               0 : const void* nsStyleContext::GetStyleData(nsStyleStructID aSID)
     245                 : {
     246               0 :   const void* cachedData = GetCachedStyleData(aSID);
     247               0 :   if (cachedData)
     248               0 :     return cachedData; // We have computed data stored on this node in the context tree.
     249               0 :   return mRuleNode->GetStyleData(aSID, this, true); // Our rule node will take care of it for us.
     250                 : }
     251                 : 
     252                 : // This is an evil evil function, since it forces you to alloc your own separate copy of
     253                 : // style data!  Do not use this function unless you absolutely have to!  You should avoid
     254                 : // this at all costs! -dwh
     255                 : void* 
     256               0 : nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
     257                 : {
     258                 :   // If we already own the struct and no kids could depend on it, then
     259                 :   // just return it.  (We leak in this case if there are kids -- and this
     260                 :   // function really shouldn't be called for style contexts that could
     261                 :   // have kids depending on the data.  ClearStyleData would be OK, but
     262                 :   // this test for no mChild or mEmptyChild doesn't catch that case.)
     263               0 :   const void *current = GetStyleData(aSID);
     264               0 :   if (!mChild && !mEmptyChild &&
     265               0 :       !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
     266               0 :       GetCachedStyleData(aSID))
     267               0 :     return const_cast<void*>(current);
     268                 : 
     269                 :   void* result;
     270               0 :   nsPresContext *presContext = PresContext();
     271               0 :   switch (aSID) {
     272                 : 
     273                 : #define UNIQUE_CASE(c_)                                                       \
     274                 :   case eStyleStruct_##c_:                                                     \
     275                 :     result = new (presContext) nsStyle##c_(                                   \
     276                 :       * static_cast<const nsStyle##c_ *>(current));                           \
     277                 :     break;
     278                 : 
     279               0 :   UNIQUE_CASE(Display)
     280               0 :   UNIQUE_CASE(Background)
     281               0 :   UNIQUE_CASE(Text)
     282               0 :   UNIQUE_CASE(TextReset)
     283                 : 
     284                 : #undef UNIQUE_CASE
     285                 : 
     286                 :   default:
     287               0 :     NS_ERROR("Struct type not supported.  Please find another way to do this if you can!");
     288               0 :     return nsnull;
     289                 :   }
     290                 : 
     291               0 :   if (!result) {
     292                 :     NS_WARNING("Ran out of memory while trying to allocate memory for a unique style struct! "
     293               0 :                "Returning the non-unique data.");
     294               0 :     return const_cast<void*>(current);
     295                 :   }
     296                 : 
     297               0 :   SetStyle(aSID, result);
     298               0 :   mBits &= ~nsCachedStyleData::GetBitForSID(aSID);
     299                 : 
     300               0 :   return result;
     301                 : }
     302                 : 
     303                 : void
     304               0 : nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
     305                 : {
     306                 :   // This method should only be called from nsRuleNode!  It is not a public
     307                 :   // method!
     308                 :   
     309               0 :   NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
     310                 : 
     311                 :   // NOTE:  nsCachedStyleData::GetStyleData works roughly the same way.
     312                 :   // See the comments there (in nsRuleNode.h) for more details about
     313                 :   // what this is doing and why.
     314                 : 
     315                 :   void** dataSlot;
     316               0 :   if (nsCachedStyleData::IsReset(aSID)) {
     317               0 :     if (!mCachedResetData) {
     318               0 :       mCachedResetData = new (mRuleNode->GetPresContext()) nsResetStyleData;
     319                 :       // XXXbz And if that fails?
     320                 :     }
     321               0 :     dataSlot = &mCachedResetData->mStyleStructs[aSID];
     322                 :   } else {
     323               0 :     dataSlot = &mCachedInheritedData.mStyleStructs[aSID];
     324                 :   }
     325               0 :   NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)),
     326                 :                "Going to leak style data");
     327               0 :   *dataSlot = aStruct;
     328               0 : }
     329                 : 
     330                 : void
     331               0 : nsStyleContext::ApplyStyleFixups(nsPresContext* aPresContext)
     332                 : {
     333                 :   // See if we have any text decorations.
     334                 :   // First see if our parent has text decorations.  If our parent does, then we inherit the bit.
     335               0 :   if (mParent && mParent->HasTextDecorationLines()) {
     336               0 :     mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
     337                 :   } else {
     338                 :     // We might have defined a decoration.
     339               0 :     const nsStyleTextReset* text = GetStyleTextReset();
     340               0 :     PRUint8 decorationLine = text->mTextDecorationLine;
     341               0 :     if (decorationLine != NS_STYLE_TEXT_DECORATION_LINE_NONE &&
     342                 :         decorationLine != NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL) {
     343               0 :       mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
     344                 :     }
     345                 :   }
     346                 : 
     347               0 :   if ((mParent && mParent->HasPseudoElementData()) || mPseudoTag) {
     348               0 :     mBits |= NS_STYLE_HAS_PSEUDO_ELEMENT_DATA;
     349                 :   }
     350                 : 
     351                 :   // Correct tables.
     352               0 :   const nsStyleDisplay* disp = GetStyleDisplay();
     353               0 :   if (disp->mDisplay == NS_STYLE_DISPLAY_TABLE) {
     354                 :     // -moz-center and -moz-right are used for HTML's alignment
     355                 :     // This is covering the <div align="right"><table>...</table></div> case.
     356                 :     // In this case, we don't want to inherit the text alignment into the table.
     357               0 :     const nsStyleText* text = GetStyleText();
     358                 :     
     359               0 :     if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
     360                 :         text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
     361                 :     {
     362               0 :       nsStyleText* uniqueText = (nsStyleText*)GetUniqueStyleData(eStyleStruct_Text);
     363               0 :       uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
     364                 :     }
     365                 :   }
     366                 : 
     367                 :   // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
     368                 :   // the root element.  We can't implement them in nsRuleNode because we
     369                 :   // don't want to store all display structs that aren't 'block',
     370                 :   // 'inline', or 'table' in the style context tree on the off chance
     371                 :   // that the root element has its style reresolved later.  So do them
     372                 :   // here if needed, by changing the style data, so that other code
     373                 :   // doesn't get confused by looking at the style data.
     374               0 :   if (!mParent) {
     375               0 :     if (disp->mDisplay != NS_STYLE_DISPLAY_NONE &&
     376                 :         disp->mDisplay != NS_STYLE_DISPLAY_BLOCK &&
     377                 :         disp->mDisplay != NS_STYLE_DISPLAY_TABLE) {
     378                 :       nsStyleDisplay *mutable_display = static_cast<nsStyleDisplay*>
     379               0 :                                                    (GetUniqueStyleData(eStyleStruct_Display));
     380                 :       // If we're in this code, then mOriginalDisplay doesn't matter
     381                 :       // for purposes of the cascade (because this nsStyleDisplay
     382                 :       // isn't living in the ruletree anyway), and for determining
     383                 :       // hypothetical boxes it's better to have mOriginalDisplay
     384                 :       // matching mDisplay here.
     385               0 :       if (mutable_display->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE)
     386                 :         mutable_display->mOriginalDisplay = mutable_display->mDisplay =
     387               0 :           NS_STYLE_DISPLAY_TABLE;
     388                 :       else
     389                 :         mutable_display->mOriginalDisplay = mutable_display->mDisplay =
     390               0 :           NS_STYLE_DISPLAY_BLOCK;
     391                 :     }
     392                 :   }
     393                 : 
     394                 :   // Computer User Interface style, to trigger loads of cursors
     395               0 :   GetStyleUserInterface();
     396               0 : }
     397                 : 
     398                 : nsChangeHint
     399               0 : nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
     400                 : {
     401               0 :   nsChangeHint hint = NS_STYLE_HINT_NONE;
     402               0 :   NS_ENSURE_TRUE(aOther, hint);
     403                 :   // We must always ensure that we populate the structs on the new style
     404                 :   // context that are filled in on the old context, so that if we get
     405                 :   // two style changes in succession, the second of which causes a real
     406                 :   // style change, the PeekStyleData doesn't return null (implying that
     407                 :   // nobody ever looked at that struct's data).  In other words, we
     408                 :   // can't skip later structs if we get a big change up front, because
     409                 :   // we could later get a small change in one of those structs that we
     410                 :   // don't want to miss.
     411                 : 
     412                 :   // If our rule nodes are the same, then we are looking at the same
     413                 :   // style data.  We know this because CalcStyleDifference is always
     414                 :   // called on two style contexts that point to the same element, so we
     415                 :   // know that our position in the style context tree is the same and
     416                 :   // our position in the rule node tree is also the same.
     417               0 :   bool compare = mRuleNode != aOther->mRuleNode;
     418                 : 
     419                 : #define DO_STRUCT_DIFFERENCE(struct_)                                         \
     420                 :   PR_BEGIN_MACRO                                                              \
     421                 :     NS_ASSERTION(NS_IsHintSubset(nsStyle##struct_::MaxDifference(), maxHint), \
     422                 :                  "Struct placed in the wrong maxHint section");               \
     423                 :     const nsStyle##struct_* this##struct_ = PeekStyle##struct_();             \
     424                 :     if (this##struct_) {                                                      \
     425                 :       const nsStyle##struct_* other##struct_ = aOther->GetStyle##struct_();   \
     426                 :       if ((compare || nsStyle##struct_::ForceCompare()) &&                    \
     427                 :           !NS_IsHintSubset(maxHint, hint) &&                                  \
     428                 :           this##struct_ != other##struct_) {                                  \
     429                 :         NS_ASSERTION(NS_IsHintSubset(                                         \
     430                 :              this##struct_->CalcDifference(*other##struct_),                  \
     431                 :              nsStyle##struct_::MaxDifference()),                              \
     432                 :              "CalcDifference() returned bigger hint than MaxDifference()");   \
     433                 :         NS_UpdateHint(hint, this##struct_->CalcDifference(*other##struct_));  \
     434                 :       }                                                                       \
     435                 :     }                                                                         \
     436                 :   PR_END_MACRO
     437                 : 
     438                 :   // We begin by examining those style structs that are capable of
     439                 :   // causing the maximal difference, a FRAMECHANGE.
     440                 :   // FRAMECHANGE Structs: Display, XUL, Content, UserInterface,
     441                 :   // Visibility, Outline, TableBorder, Table, Text, UIReset, Quotes
     442                 :   nsChangeHint maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
     443                 :       nsChangeHint_UpdateTransformLayer | nsChangeHint_UpdateOpacityLayer |
     444               0 :       nsChangeHint_UpdateOverflow);
     445               0 :   DO_STRUCT_DIFFERENCE(Display);
     446                 : 
     447                 :   maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
     448               0 :       nsChangeHint_UpdateCursor);
     449               0 :   DO_STRUCT_DIFFERENCE(XUL);
     450               0 :   DO_STRUCT_DIFFERENCE(Column);
     451               0 :   DO_STRUCT_DIFFERENCE(Content);
     452               0 :   DO_STRUCT_DIFFERENCE(UserInterface);
     453               0 :   DO_STRUCT_DIFFERENCE(Visibility);
     454               0 :   DO_STRUCT_DIFFERENCE(Outline);
     455               0 :   DO_STRUCT_DIFFERENCE(TableBorder);
     456               0 :   DO_STRUCT_DIFFERENCE(Table);
     457               0 :   DO_STRUCT_DIFFERENCE(UIReset);
     458               0 :   DO_STRUCT_DIFFERENCE(Text);
     459               0 :   DO_STRUCT_DIFFERENCE(List);
     460                 :   // If the quotes implementation is ever going to change we might not need
     461                 :   // a framechange here and a reflow should be sufficient.  See bug 35768.
     462               0 :   DO_STRUCT_DIFFERENCE(Quotes);
     463                 : 
     464               0 :   maxHint = nsChangeHint(NS_STYLE_HINT_REFLOW | nsChangeHint_UpdateEffects);
     465               0 :   DO_STRUCT_DIFFERENCE(SVGReset);
     466               0 :   DO_STRUCT_DIFFERENCE(SVG);
     467                 : 
     468                 :   // At this point, we know that the worst kind of damage we could do is
     469                 :   // a reflow.
     470               0 :   maxHint = NS_STYLE_HINT_REFLOW;
     471                 :       
     472                 :   // The following structs cause (as their maximal difference) a reflow
     473                 :   // to occur.  REFLOW Structs: Font, Margin, Padding, Border, List,
     474                 :   // Position, Text, TextReset
     475               0 :   DO_STRUCT_DIFFERENCE(Font);
     476               0 :   DO_STRUCT_DIFFERENCE(Margin);
     477               0 :   DO_STRUCT_DIFFERENCE(Padding);
     478               0 :   DO_STRUCT_DIFFERENCE(Border);
     479               0 :   DO_STRUCT_DIFFERENCE(Position);
     480               0 :   DO_STRUCT_DIFFERENCE(TextReset);
     481                 : 
     482                 :   // Most backgrounds only require a re-render (i.e., a VISUAL change), but
     483                 :   // backgrounds using -moz-element need to reset SVG effects, too.
     484               0 :   maxHint = nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_UpdateEffects);
     485               0 :   DO_STRUCT_DIFFERENCE(Background);
     486                 : 
     487                 :   // Color only needs a repaint.
     488               0 :   maxHint = NS_STYLE_HINT_VISUAL;
     489               0 :   DO_STRUCT_DIFFERENCE(Color);
     490                 : 
     491                 : #undef DO_STRUCT_DIFFERENCE
     492                 : 
     493                 :   // Note that we do not check whether this->RelevantLinkVisited() !=
     494                 :   // aOther->RelevantLinkVisited(); we don't need to since
     495                 :   // nsCSSFrameConstructor::DoContentStateChanged always adds
     496                 :   // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
     497                 :   // needs to, since HasStateDependentStyle probably doesn't work right
     498                 :   // for NS_EVENT_STATE_VISITED).  Hopefully this doesn't actually
     499                 :   // expose whether links are visited to performance tests since all
     500                 :   // link coloring happens asynchronously at a time when it's hard for
     501                 :   // the page to measure.
     502                 :   // However, we do need to compute the larger of the changes that can
     503                 :   // happen depending on whether the link is visited or unvisited, since
     504                 :   // doing only the one that's currently appropriate would expose which
     505                 :   // links are in history to easy performance measurement.  Therefore,
     506                 :   // here, we add nsChangeHint_RepaintFrame hints (the maximum for
     507                 :   // things that can depend on :visited) for the properties on which we
     508                 :   // call GetVisitedDependentColor.
     509               0 :   nsStyleContext *thisVis = GetStyleIfVisited(),
     510               0 :                 *otherVis = aOther->GetStyleIfVisited();
     511               0 :   if (!thisVis != !otherVis) {
     512                 :     // One style context has a style-if-visited and the other doesn't.
     513                 :     // Presume a difference.
     514               0 :     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
     515               0 :   } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
     516                 :     // Both style contexts have a style-if-visited.
     517               0 :     bool change = false;
     518                 : 
     519                 :     // NB: Calling Peek on |this|, not |thisVis|, since callers may look
     520                 :     // at a struct on |this| without looking at the same struct on
     521                 :     // |thisVis| (including this function if we skip one of these checks
     522                 :     // due to change being true already or due to the old style context
     523                 :     // not having a style-if-visited), but not the other way around.
     524               0 :     if (PeekStyleColor()) {
     525               0 :       if (thisVis->GetStyleColor()->mColor !=
     526               0 :           otherVis->GetStyleColor()->mColor) {
     527               0 :         change = true;
     528                 :       }
     529                 :     }
     530                 : 
     531                 :     // NB: Calling Peek on |this|, not |thisVis| (see above).
     532               0 :     if (!change && PeekStyleBackground()) {
     533               0 :       if (thisVis->GetStyleBackground()->mBackgroundColor !=
     534               0 :           otherVis->GetStyleBackground()->mBackgroundColor) {
     535               0 :         change = true;
     536                 :       }
     537                 :     }
     538                 : 
     539                 :     // NB: Calling Peek on |this|, not |thisVis| (see above).
     540               0 :     if (!change && PeekStyleBorder()) {
     541               0 :       const nsStyleBorder *thisVisBorder = thisVis->GetStyleBorder();
     542               0 :       const nsStyleBorder *otherVisBorder = otherVis->GetStyleBorder();
     543               0 :       NS_FOR_CSS_SIDES(side) {
     544                 :         bool thisFG, otherFG;
     545                 :         nscolor thisColor, otherColor;
     546               0 :         thisVisBorder->GetBorderColor(side, thisColor, thisFG);
     547               0 :         otherVisBorder->GetBorderColor(side, otherColor, otherFG);
     548               0 :         if (thisFG != otherFG || (!thisFG && thisColor != otherColor)) {
     549               0 :           change = true;
     550               0 :           break;
     551                 :         }
     552                 :       }
     553                 :     }
     554                 : 
     555                 :     // NB: Calling Peek on |this|, not |thisVis| (see above).
     556               0 :     if (!change && PeekStyleOutline()) {
     557               0 :       const nsStyleOutline *thisVisOutline = thisVis->GetStyleOutline();
     558               0 :       const nsStyleOutline *otherVisOutline = otherVis->GetStyleOutline();
     559                 :       bool haveColor;
     560                 :       nscolor thisColor, otherColor;
     561               0 :       if (thisVisOutline->GetOutlineInitialColor() != 
     562               0 :             otherVisOutline->GetOutlineInitialColor() ||
     563                 :           (haveColor = thisVisOutline->GetOutlineColor(thisColor)) != 
     564               0 :             otherVisOutline->GetOutlineColor(otherColor) ||
     565                 :           (haveColor && thisColor != otherColor)) {
     566               0 :         change = true;
     567                 :       }
     568                 :     }
     569                 : 
     570                 :     // NB: Calling Peek on |this|, not |thisVis| (see above).
     571               0 :     if (!change && PeekStyleColumn()) {
     572               0 :       const nsStyleColumn *thisVisColumn = thisVis->GetStyleColumn();
     573               0 :       const nsStyleColumn *otherVisColumn = otherVis->GetStyleColumn();
     574               0 :       if (thisVisColumn->mColumnRuleColor != otherVisColumn->mColumnRuleColor ||
     575                 :           thisVisColumn->mColumnRuleColorIsForeground !=
     576                 :             otherVisColumn->mColumnRuleColorIsForeground) {
     577               0 :         change = true;
     578                 :       }
     579                 :     }
     580                 : 
     581                 :     // NB: Calling Peek on |this|, not |thisVis| (see above).
     582               0 :     if (!change && PeekStyleTextReset()) {
     583               0 :       const nsStyleTextReset *thisVisTextReset = thisVis->GetStyleTextReset();
     584               0 :       const nsStyleTextReset *otherVisTextReset = otherVis->GetStyleTextReset();
     585                 :       nscolor thisVisDecColor, otherVisDecColor;
     586                 :       bool thisVisDecColorIsFG, otherVisDecColorIsFG;
     587                 :       thisVisTextReset->GetDecorationColor(thisVisDecColor,
     588               0 :                                            thisVisDecColorIsFG);
     589                 :       otherVisTextReset->GetDecorationColor(otherVisDecColor,
     590               0 :                                             otherVisDecColorIsFG);
     591               0 :       if (thisVisDecColorIsFG != otherVisDecColorIsFG ||
     592               0 :           (!thisVisDecColorIsFG && thisVisDecColor != otherVisDecColor)) {
     593               0 :         change = true;
     594                 :       }
     595                 :     }
     596                 : 
     597                 :     // NB: Calling Peek on |this|, not |thisVis| (see above).
     598               0 :     if (!change && PeekStyleSVG()) {
     599               0 :       const nsStyleSVG *thisVisSVG = thisVis->GetStyleSVG();
     600               0 :       const nsStyleSVG *otherVisSVG = otherVis->GetStyleSVG();
     601               0 :       if (thisVisSVG->mFill != otherVisSVG->mFill ||
     602               0 :           thisVisSVG->mStroke != otherVisSVG->mStroke) {
     603               0 :         change = true;
     604                 :       }
     605                 :     }
     606                 : 
     607               0 :     if (change) {
     608               0 :       NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
     609                 :     }
     610                 :   }
     611                 : 
     612               0 :   return hint;
     613                 : }
     614                 : 
     615                 : void
     616               0 : nsStyleContext::Mark()
     617                 : {
     618                 :   // Mark our rule node.
     619               0 :   mRuleNode->Mark();
     620                 : 
     621                 :   // Mark our children (i.e., tell them to mark their rule nodes, etc.).
     622               0 :   if (mChild) {
     623               0 :     nsStyleContext* child = mChild;
     624               0 :     do {
     625               0 :       child->Mark();
     626               0 :       child = child->mNextSibling;
     627                 :     } while (mChild != child);
     628                 :   }
     629                 :   
     630               0 :   if (mEmptyChild) {
     631               0 :     nsStyleContext* child = mEmptyChild;
     632               0 :     do {
     633               0 :       child->Mark();
     634               0 :       child = child->mNextSibling;
     635                 :     } while (mEmptyChild != child);
     636                 :   }
     637               0 : }
     638                 : 
     639                 : #ifdef DEBUG
     640               0 : void nsStyleContext::List(FILE* out, PRInt32 aIndent)
     641                 : {
     642                 :   // Indent
     643                 :   PRInt32 ix;
     644               0 :   for (ix = aIndent; --ix >= 0; ) fputs("  ", out);
     645                 :   fprintf(out, "%p(%d) parent=%p ",
     646               0 :           (void*)this, mRefCnt, (void *)mParent);
     647               0 :   if (mPseudoTag) {
     648               0 :     nsAutoString  buffer;
     649               0 :     mPseudoTag->ToString(buffer);
     650               0 :     fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
     651               0 :     fputs(" ", out);
     652                 :   }
     653                 : 
     654               0 :   if (mRuleNode) {
     655               0 :     fputs("{\n", out);
     656               0 :     nsRuleNode* ruleNode = mRuleNode;
     657               0 :     while (ruleNode) {
     658               0 :       nsIStyleRule *styleRule = ruleNode->GetRule();
     659               0 :       if (styleRule) {
     660               0 :         styleRule->List(out, aIndent + 1);
     661                 :       }
     662               0 :       ruleNode = ruleNode->GetParent();
     663                 :     }
     664               0 :     for (ix = aIndent; --ix >= 0; ) fputs("  ", out);
     665               0 :     fputs("}\n", out);
     666                 :   }
     667                 :   else {
     668               0 :     fputs("{}\n", out);
     669                 :   }
     670                 : 
     671               0 :   if (nsnull != mChild) {
     672               0 :     nsStyleContext* child = mChild;
     673               0 :     do {
     674               0 :       child->List(out, aIndent + 1);
     675               0 :       child = child->mNextSibling;
     676                 :     } while (mChild != child);
     677                 :   }
     678               0 :   if (nsnull != mEmptyChild) {
     679               0 :     nsStyleContext* child = mEmptyChild;
     680               0 :     do {
     681               0 :       child->List(out, aIndent + 1);
     682               0 :       child = child->mNextSibling;
     683                 :     } while (mEmptyChild != child);
     684                 :   }
     685               0 : }
     686                 : #endif
     687                 : 
     688                 : // Overloaded new operator. Initializes the memory to 0 and relies on an arena
     689                 : // (which comes from the presShell) to perform the allocation.
     690                 : void* 
     691               0 : nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
     692                 : {
     693                 :   // Check the recycle list first.
     694               0 :   return aPresContext->AllocateFromShell(sz);
     695                 : }
     696                 : 
     697                 : // Overridden to prevent the global delete from being called, since the memory
     698                 : // came out of an nsIArena instead of the global delete operator's heap.
     699                 : void 
     700               0 : nsStyleContext::Destroy()
     701                 : {
     702                 :   // Get the pres context from our rule node.
     703               0 :   nsRefPtr<nsPresContext> presContext = mRuleNode->GetPresContext();
     704                 : 
     705                 :   // Call our destructor.
     706               0 :   this->~nsStyleContext();
     707                 : 
     708                 :   // Don't let the memory be freed, since it will be recycled
     709                 :   // instead. Don't call the global operator delete.
     710               0 :   presContext->FreeToShell(sizeof(nsStyleContext), this);
     711               0 : }
     712                 : 
     713                 : already_AddRefed<nsStyleContext>
     714               0 : NS_NewStyleContext(nsStyleContext* aParentContext,
     715                 :                    nsIAtom* aPseudoTag,
     716                 :                    nsCSSPseudoElements::Type aPseudoType,
     717                 :                    nsRuleNode* aRuleNode,
     718                 :                    nsPresContext* aPresContext)
     719                 : {
     720                 :   nsStyleContext* context =
     721                 :     new (aPresContext) nsStyleContext(aParentContext, aPseudoTag, aPseudoType,
     722               0 :                                       aRuleNode, aPresContext);
     723               0 :   if (context)
     724               0 :     context->AddRef();
     725               0 :   return context;
     726                 : }
     727                 : 
     728               0 : static nscolor ExtractColor(nsCSSProperty aProperty,
     729                 :                             nsStyleContext *aStyleContext)
     730                 : {
     731               0 :   nsStyleAnimation::Value val;
     732                 : #ifdef DEBUG
     733                 :   bool success =
     734                 : #endif
     735               0 :     nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext, val);
     736               0 :   NS_ABORT_IF_FALSE(success,
     737                 :                     "aProperty must be extractable by nsStyleAnimation");
     738               0 :   return val.GetColorValue();
     739                 : }
     740                 : 
     741                 : struct ColorIndexSet {
     742                 :   PRUint8 colorIndex, alphaIndex;
     743                 : };
     744                 : 
     745                 : static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
     746                 : 
     747                 : nscolor
     748               0 : nsStyleContext::GetVisitedDependentColor(nsCSSProperty aProperty)
     749                 : {
     750               0 :   NS_ASSERTION(aProperty == eCSSProperty_color ||
     751                 :                aProperty == eCSSProperty_background_color ||
     752                 :                aProperty == eCSSProperty_border_top_color ||
     753                 :                aProperty == eCSSProperty_border_right_color_value ||
     754                 :                aProperty == eCSSProperty_border_bottom_color ||
     755                 :                aProperty == eCSSProperty_border_left_color_value ||
     756                 :                aProperty == eCSSProperty_outline_color ||
     757                 :                aProperty == eCSSProperty__moz_column_rule_color ||
     758                 :                aProperty == eCSSProperty_text_decoration_color ||
     759                 :                aProperty == eCSSProperty_fill ||
     760                 :                aProperty == eCSSProperty_stroke,
     761                 :                "we need to add to nsStyleContext::CalcStyleDifference");
     762                 : 
     763                 :   nscolor colors[2];
     764               0 :   colors[0] = ExtractColor(aProperty, this);
     765                 : 
     766               0 :   nsStyleContext *visitedStyle = this->GetStyleIfVisited();
     767               0 :   if (!visitedStyle) {
     768               0 :     return colors[0];
     769                 :   }
     770                 : 
     771               0 :   colors[1] = ExtractColor(aProperty, visitedStyle);
     772                 : 
     773                 :   return nsStyleContext::CombineVisitedColors(colors,
     774               0 :                                               this->RelevantLinkVisited());
     775                 : }
     776                 : 
     777                 : /* static */ nscolor
     778               0 : nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited)
     779                 : {
     780               0 :   if (NS_GET_A(aColors[1]) == 0) {
     781                 :     // If the style-if-visited is transparent, then just use the
     782                 :     // unvisited style rather than using the (meaningless) color
     783                 :     // components of the visited style along with a potentially
     784                 :     // non-transparent alpha value.
     785               0 :     aLinkIsVisited = false;
     786                 :   }
     787                 : 
     788                 :   // NOTE: We want this code to have as little timing dependence as
     789                 :   // possible on whether this->RelevantLinkVisited() is true.
     790                 :   const ColorIndexSet &set =
     791               0 :     gVisitedIndices[aLinkIsVisited ? 1 : 0];
     792                 : 
     793               0 :   nscolor colorColor = aColors[set.colorIndex];
     794               0 :   nscolor alphaColor = aColors[set.alphaIndex];
     795               0 :   return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor),
     796                 :                  NS_GET_B(colorColor), NS_GET_A(alphaColor));
     797                 : }
     798                 : 
     799                 : void*
     800               0 : nsStyleContext::Alloc(size_t aSize)
     801                 : {
     802               0 :   nsIPresShell *shell = PresContext()->PresShell();
     803                 : 
     804               0 :   aSize += offsetof(AllocationHeader, mStorageStart);
     805                 :   AllocationHeader *alloc =
     806               0 :     static_cast<AllocationHeader*>(shell->AllocateMisc(aSize));
     807                 : 
     808               0 :   alloc->mSize = aSize; // NOTE: inflated by header
     809                 : 
     810               0 :   alloc->mNext = mAllocations;
     811               0 :   mAllocations = alloc;
     812                 : 
     813               0 :   return static_cast<void*>(&alloc->mStorageStart);
     814                 : }
     815                 : 
     816                 : void
     817               0 : nsStyleContext::FreeAllocations(nsPresContext *aPresContext)
     818                 : {
     819               0 :   nsIPresShell *shell = aPresContext->PresShell();
     820                 : 
     821               0 :   for (AllocationHeader *alloc = mAllocations, *next; alloc; alloc = next) {
     822               0 :     next = alloc->mNext;
     823               0 :     shell->FreeMisc(alloc->mSize, alloc);
     824                 :   }
     825               0 : }

Generated by: LCOV version 1.7