forked from mirrors/gecko-dev
		
	 680815cd6e
			
		
	
	
		680815cd6e
		
	
	
	
	
		
			
			This patch was generated automatically by the "modeline.py" script, available here: https://github.com/amccreight/moz-source-tools/blob/master/modeline.py For every file that is modified in this patch, the changes are as follows: (1) The patch changes the file to use the exact C++ mode lines from the Mozilla coding style guide, available here: https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style#Mode_Line (2) The patch deletes any blank lines between the mode line & the MPL boilerplate comment. (3) If the file previously had the mode lines and MPL boilerplate in a single contiguous C++ comment, then the patch splits them into separate C++ comments, to match the boilerplate in the coding style. MozReview-Commit-ID: EuRsDue63tK --HG-- extra : rebase_source : 3356d4b80ff6213935192e87cdbc9103fec6084c
		
			
				
	
	
		
			1186 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1186 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | ||
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | ||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | ||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | ||
| 
 | ||
| #include "mozilla/GeckoStyleContext.h"
 | ||
| 
 | ||
| #include "CSSVariableImageTable.h"
 | ||
| #include "nsStyleConsts.h"
 | ||
| #include "nsStyleStruct.h"
 | ||
| #include "nsPresContext.h"
 | ||
| #include "nsRuleNode.h"
 | ||
| #include "nsStyleContextInlines.h"
 | ||
| #include "nsIFrame.h"
 | ||
| #include "nsLayoutUtils.h"
 | ||
| #include "mozilla/ReflowInput.h"
 | ||
| #include "RubyUtils.h"
 | ||
| 
 | ||
| using namespace mozilla;
 | ||
| 
 | ||
| #ifdef DEBUG
 | ||
| // Whether to perform expensive assertions in the nsStyleContext destructor.
 | ||
| static bool sExpensiveStyleStructAssertionsEnabled;
 | ||
| 
 | ||
| /* static */ void
 | ||
| GeckoStyleContext::Initialize()
 | ||
| {
 | ||
|   Preferences::AddBoolVarCache(
 | ||
|       &sExpensiveStyleStructAssertionsEnabled,
 | ||
|       "layout.css.expensive-style-struct-assertions.enabled");
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| GeckoStyleContext::GeckoStyleContext(GeckoStyleContext* aParent,
 | ||
|                                      nsAtom* aPseudoTag,
 | ||
|                                      CSSPseudoElementType aPseudoType,
 | ||
|                                      already_AddRefed<nsRuleNode> aRuleNode,
 | ||
|                                      bool aSkipParentDisplayBasedStyleFixup)
 | ||
|   : nsStyleContext(aPseudoTag, aPseudoType)
 | ||
|   , mCachedResetData(nullptr)
 | ||
|   , mRefCnt(0)
 | ||
|   , mChild(nullptr)
 | ||
|   , mEmptyChild(nullptr)
 | ||
|   , mRuleNode(Move(aRuleNode))
 | ||
|   , mParent(aParent)
 | ||
| #ifdef DEBUG
 | ||
|   , mComputingStruct(nsStyleStructID_None)
 | ||
|   , mFrameRefCnt(0)
 | ||
| #endif
 | ||
| {
 | ||
|   mBits |= NS_STYLE_CONTEXT_IS_GECKO;
 | ||
| 
 | ||
|   if (aParent) {
 | ||
| #ifdef DEBUG
 | ||
|     nsRuleNode *r1 = mParent->RuleNode(), *r2 = mRuleNode;
 | ||
|     while (r1->GetParent())
 | ||
|       r1 = r1->GetParent();
 | ||
|     while (r2->GetParent())
 | ||
|       r2 = r2->GetParent();
 | ||
|     NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
 | ||
| #endif
 | ||
|   } else {
 | ||
|     PresContext()->PresShell()->StyleSet()->RootStyleContextAdded();
 | ||
|   }
 | ||
| 
 | ||
|   mRuleNode->SetUsedDirectly(); // before ApplyStyleFixups()!
 | ||
|   // FinishConstruction() calls AddChild which needs these
 | ||
|   // to be initialized!
 | ||
|   mNextSibling = this;
 | ||
|   mPrevSibling = this;
 | ||
| 
 | ||
|   FinishConstruction();
 | ||
|   ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
 | ||
| }
 | ||
| 
 | ||
| // Overloaded new operator. Initializes the memory to 0 and relies on an arena
 | ||
| // (which comes from the presShell) to perform the allocation.
 | ||
| void*
 | ||
| GeckoStyleContext::operator new(size_t sz, nsPresContext* aPresContext)
 | ||
| {
 | ||
|   MOZ_ASSERT(sz == sizeof(GeckoStyleContext));
 | ||
|   // Check the recycle list first.
 | ||
|   return aPresContext->PresShell()->
 | ||
|     AllocateByObjectID(eArenaObjectID_GeckoStyleContext, sz);
 | ||
| }
 | ||
| 
 | ||
| // Overridden to prevent the global delete from being called, since the memory
 | ||
| // came out of an nsIArena instead of the global delete operator's heap.
 | ||
| void
 | ||
| GeckoStyleContext::Destroy()
 | ||
| {
 | ||
|   // Get the pres context.
 | ||
|   RefPtr<nsPresContext> presContext = PresContext();
 | ||
|   // Call our destructor.
 | ||
|   this->~GeckoStyleContext();
 | ||
|   // Don't let the memory be freed, since it will be recycled
 | ||
|   // instead. Don't call the global operator delete.
 | ||
|   presContext->PresShell()->
 | ||
|     FreeByObjectID(eArenaObjectID_GeckoStyleContext, this);
 | ||
| }
 | ||
| 
 | ||
| GeckoStyleContext::~GeckoStyleContext()
 | ||
| {
 | ||
|   nsPresContext *presContext = PresContext();
 | ||
| #ifdef DEBUG
 | ||
|   NS_ASSERTION(HasNoChildren(), "destructing context with children");
 | ||
|   if (sExpensiveStyleStructAssertionsEnabled) {
 | ||
|     // Assert that the style structs we are about to destroy are not referenced
 | ||
|     // anywhere else in the style context tree.  These checks are expensive,
 | ||
|     // which is why they are not enabled by default.
 | ||
|     GeckoStyleContext* root = this;
 | ||
|     while (root->GetParent()) {
 | ||
|       root = root->GetParent();
 | ||
|     }
 | ||
|     root->AssertStructsNotUsedElsewhere(this,
 | ||
|                                         std::numeric_limits<int32_t>::max());
 | ||
|   } else {
 | ||
|     // In DEBUG builds when the pref is not enabled, we perform a more limited
 | ||
|     // check just of the children of this style context.
 | ||
|     this->AssertStructsNotUsedElsewhere(this, 2);
 | ||
|   }
 | ||
| 
 | ||
|   nsStyleSet* geckoStyleSet = presContext->PresShell()->StyleSet()->GetAsGecko();
 | ||
|   NS_ASSERTION(!geckoStyleSet ||
 | ||
|                geckoStyleSet->GetRuleTree() == AsGecko()->RuleNode()->RuleTree() ||
 | ||
|                geckoStyleSet->IsInRuleTreeReconstruct(),
 | ||
|                "destroying style context from old rule tree too late");
 | ||
| #endif
 | ||
| 
 | ||
|   if (mParent) {
 | ||
|     mParent->AsGecko()->RemoveChild(this);
 | ||
|   } else {
 | ||
|     presContext->StyleSet()->RootStyleContextRemoved();
 | ||
|   }
 | ||
| 
 | ||
|   // Free up our data structs.
 | ||
|   DestroyCachedStructs(presContext);
 | ||
|   CSSVariableImageTable::RemoveAll(this);
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::AddChild(GeckoStyleContext* aChild)
 | ||
| {
 | ||
|   NS_ASSERTION(aChild->mPrevSibling == aChild &&
 | ||
|                aChild->mNextSibling == aChild,
 | ||
|                "child already in a child list");
 | ||
| 
 | ||
|   GeckoStyleContext **listPtr = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
 | ||
|   if (const nsRuleNode* source = aChild->mRuleNode) {
 | ||
|     if (source->IsRoot()) {
 | ||
|       listPtr = &mEmptyChild;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
 | ||
|   // etc. don't alias with what ever listPtr points at.
 | ||
|   GeckoStyleContext *list = *listPtr;
 | ||
| 
 | ||
|   // Insert at the beginning of the list.  See also FindChildWithRules.
 | ||
|   if (list) {
 | ||
|     // Link into existing elements, if there are any.
 | ||
|     aChild->mNextSibling = list;
 | ||
|     aChild->mPrevSibling = list->mPrevSibling;
 | ||
|     list->mPrevSibling->mNextSibling = aChild;
 | ||
|     list->mPrevSibling = aChild;
 | ||
|   }
 | ||
|   (*listPtr) = aChild;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::MoveTo(GeckoStyleContext* aNewParent)
 | ||
| {
 | ||
|   MOZ_ASSERT(aNewParent != mParent);
 | ||
| 
 | ||
|   // This function shouldn't be getting called if the parents have different
 | ||
|   // values for some flags in mBits (unless the flag is also set on this style
 | ||
|   // context) because if that were the case we would need to recompute those
 | ||
|   // bits for |this|.
 | ||
| 
 | ||
| #define CHECK_FLAG(bit_) \
 | ||
|   MOZ_ASSERT((mParent->AsGecko()->mBits & (bit_)) ==                          \
 | ||
|                (aNewParent->mBits & (bit_)) || (mBits & (bit_)),              \
 | ||
|              "MoveTo cannot be called if " #bit_ " value on old and new "     \
 | ||
|              "style context parents do not match, unless the flag is set "    \
 | ||
|              "on this style context");
 | ||
| 
 | ||
|   CHECK_FLAG(NS_STYLE_HAS_PSEUDO_ELEMENT_DATA)
 | ||
|   CHECK_FLAG(NS_STYLE_IN_DISPLAY_NONE_SUBTREE)
 | ||
|   CHECK_FLAG(NS_STYLE_HAS_TEXT_DECORATION_LINES)
 | ||
|   CHECK_FLAG(NS_STYLE_RELEVANT_LINK_VISITED)
 | ||
| 
 | ||
| #undef CHECK_FLAG
 | ||
| 
 | ||
|   // Assertions checking for visited style are just to avoid some tricky
 | ||
|   // cases we can't be bothered handling at the moment.
 | ||
|   MOZ_ASSERT(!IsStyleIfVisited());
 | ||
|   MOZ_ASSERT(!mParent->IsStyleIfVisited());
 | ||
|   MOZ_ASSERT(!aNewParent->IsStyleIfVisited());
 | ||
|   auto* styleIfVisited = GetStyleIfVisited();
 | ||
|   MOZ_ASSERT(!styleIfVisited || styleIfVisited->mParent == mParent);
 | ||
| 
 | ||
|   if (mParent->HasChildThatUsesResetStyle()) {
 | ||
|     aNewParent->AddStyleBit(NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE);
 | ||
|   }
 | ||
| 
 | ||
|   mParent->RemoveChild(this);
 | ||
|   mParent = aNewParent;
 | ||
|   mParent->AddChild(this);
 | ||
| 
 | ||
|   if (styleIfVisited) {
 | ||
|     styleIfVisited->mParent->RemoveChild(styleIfVisited);
 | ||
|     styleIfVisited->mParent = aNewParent;
 | ||
|     styleIfVisited->mParent->AddChild(styleIfVisited);
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::RemoveChild(GeckoStyleContext* aChild)
 | ||
| {
 | ||
|   NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
 | ||
| 
 | ||
|   MOZ_ASSERT(aChild->mRuleNode, "child context should have rule node");
 | ||
|   GeckoStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
 | ||
| 
 | ||
|   if (aChild->mPrevSibling != aChild) { // has siblings
 | ||
|     if ((*list) == aChild) {
 | ||
|       (*list) = (*list)->mNextSibling;
 | ||
|     }
 | ||
|   }
 | ||
|   else {
 | ||
|     NS_ASSERTION((*list) == aChild, "bad sibling pointers");
 | ||
|     (*list) = nullptr;
 | ||
|   }
 | ||
| 
 | ||
|   aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
 | ||
|   aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
 | ||
|   aChild->mNextSibling = aChild;
 | ||
|   aChild->mPrevSibling = aChild;
 | ||
| }
 | ||
| 
 | ||
| #ifdef DEBUG
 | ||
| void
 | ||
| GeckoStyleContext::ListDescendants(FILE* out, int32_t aIndent)
 | ||
| {
 | ||
|   if (nullptr != mChild) {
 | ||
|     GeckoStyleContext* child = mChild;
 | ||
|     do {
 | ||
|       child->List(out, aIndent + 1, true);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mChild != child);
 | ||
|   }
 | ||
|   if (nullptr != mEmptyChild) {
 | ||
|     GeckoStyleContext* child = mEmptyChild;
 | ||
|     do {
 | ||
|       child->List(out, aIndent + 1, true);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mEmptyChild != child);
 | ||
|   }
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
 | ||
| {
 | ||
|   if (mChild) {
 | ||
|     GeckoStyleContext* child = mChild;
 | ||
|     do {
 | ||
|       child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mChild != child);
 | ||
|   }
 | ||
|   if (mEmptyChild) {
 | ||
|     GeckoStyleContext* child = mEmptyChild;
 | ||
|     do {
 | ||
|       child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mEmptyChild != child);
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
 | ||
| {
 | ||
|   NS_ASSERTION(mFrameRefCnt == 0, "frame still referencing style context");
 | ||
|   for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
 | ||
|        i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
 | ||
|        i = nsStyleStructID(i + 1)) {
 | ||
|     uint32_t bit = nsCachedStyleData::GetBitForSID(i);
 | ||
|     if (aStructs & bit) {
 | ||
|       if (!(mBits & bit) && mCachedInheritedData.mStyleStructs[i]) {
 | ||
|         aStructs &= ~bit;
 | ||
|       } else {
 | ||
|         mCachedInheritedData.mStyleStructs[i] = nullptr;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   if (mCachedResetData) {
 | ||
|     for (nsStyleStructID i = nsStyleStructID_Reset_Start;
 | ||
|          i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
 | ||
|          i = nsStyleStructID(i + 1)) {
 | ||
|       uint32_t bit = nsCachedStyleData::GetBitForSID(i);
 | ||
|       if (aStructs & bit) {
 | ||
|         if (!(mBits & bit) && mCachedResetData->mStyleStructs[i]) {
 | ||
|           aStructs &= ~bit;
 | ||
|         } else {
 | ||
|           mCachedResetData->mStyleStructs[i] = nullptr;
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   if (aStructs == 0) {
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   ClearCachedInheritedStyleDataOnDescendants(aStructs);
 | ||
| }
 | ||
| 
 | ||
| already_AddRefed<GeckoStyleContext>
 | ||
| GeckoStyleContext::FindChildWithRules(const nsAtom* aPseudoTag,
 | ||
|                                    nsRuleNode* aSource,
 | ||
|                                    nsRuleNode* aSourceIfVisited,
 | ||
|                                    bool aRelevantLinkVisited)
 | ||
| {
 | ||
|   uint32_t threshold = 10; // The # of siblings we're willing to examine
 | ||
|                            // before just giving this whole thing up.
 | ||
| 
 | ||
|   RefPtr<GeckoStyleContext> result;
 | ||
|   MOZ_ASSERT(aSource);
 | ||
|   GeckoStyleContext *list = aSource->IsRoot() ? mEmptyChild : mChild;
 | ||
| 
 | ||
|   if (list) {
 | ||
|     GeckoStyleContext *child = list;
 | ||
|     do {
 | ||
|       if (child->RuleNode() == aSource &&
 | ||
|           child->mPseudoTag == aPseudoTag &&
 | ||
|           !child->IsStyleIfVisited() &&
 | ||
|           child->RelevantLinkVisited() == aRelevantLinkVisited) {
 | ||
|         bool match = false;
 | ||
|         if (aSourceIfVisited) {
 | ||
|           match = child->GetStyleIfVisited() &&
 | ||
|                   child->GetStyleIfVisited()->RuleNode() == aSourceIfVisited;
 | ||
|         } else {
 | ||
|           match = !child->GetStyleIfVisited();
 | ||
|         }
 | ||
|         if (match && !(child->mBits & NS_STYLE_INELIGIBLE_FOR_SHARING)) {
 | ||
|           result = child;
 | ||
|           break;
 | ||
|         }
 | ||
|       }
 | ||
|       child = child->mNextSibling;
 | ||
|       threshold--;
 | ||
|       if (threshold == 0)
 | ||
|         break;
 | ||
|     } while (child != list);
 | ||
|   }
 | ||
| 
 | ||
|   if (result) {
 | ||
|     if (result != list) {
 | ||
|       // Move result to the front of the list.
 | ||
|       RemoveChild(result);
 | ||
|       AddChild(result);
 | ||
|     }
 | ||
|     result->mBits |= NS_STYLE_IS_SHARED;
 | ||
|   }
 | ||
| 
 | ||
|   return result.forget();
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| // This is an evil evil function, since it forces you to alloc your own separate copy of
 | ||
| // style data!  Do not use this function unless you absolutely have to!  You should avoid
 | ||
| // this at all costs! -dwh
 | ||
| void*
 | ||
| GeckoStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
 | ||
| {
 | ||
|   // If we already own the struct and no kids could depend on it, then
 | ||
|   // just return it.  (We leak in this case if there are kids -- and this
 | ||
|   // function really shouldn't be called for style contexts that could
 | ||
|   // have kids depending on the data.  ClearStyleData would be OK, but
 | ||
|   // this test for no mChild or mEmptyChild doesn't catch that case.)
 | ||
|   const void *current = StyleData(aSID);
 | ||
|   if (!mChild && !mEmptyChild &&
 | ||
|       !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
 | ||
|       GetCachedStyleData(aSID))
 | ||
|     return const_cast<void*>(current);
 | ||
| 
 | ||
|   void* result;
 | ||
|   nsPresContext *presContext = PresContext();
 | ||
|   switch (aSID) {
 | ||
| 
 | ||
| #define UNIQUE_CASE(c_)                                                       \
 | ||
|   case eStyleStruct_##c_:                                                     \
 | ||
|     result = new (presContext) nsStyle##c_(                                   \
 | ||
|       * static_cast<const nsStyle##c_ *>(current));                           \
 | ||
|     break;
 | ||
| 
 | ||
|   UNIQUE_CASE(Font)
 | ||
|   UNIQUE_CASE(Display)
 | ||
|   UNIQUE_CASE(Position)
 | ||
|   UNIQUE_CASE(Text)
 | ||
|   UNIQUE_CASE(TextReset)
 | ||
|   UNIQUE_CASE(Visibility)
 | ||
| 
 | ||
| #undef UNIQUE_CASE
 | ||
| 
 | ||
|   default:
 | ||
|     NS_ERROR("Struct type not supported.  Please find another way to do this if you can!");
 | ||
|     return nullptr;
 | ||
|   }
 | ||
| 
 | ||
|   SetStyle(aSID, result);
 | ||
|   mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID));
 | ||
| 
 | ||
|   return result;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| // This is an evil function, but less evil than GetUniqueStyleData. It
 | ||
| // creates an empty style struct for this nsStyleContext.
 | ||
| void*
 | ||
| GeckoStyleContext::CreateEmptyStyleData(const nsStyleStructID& aSID)
 | ||
| {
 | ||
|   MOZ_ASSERT(!mChild && !mEmptyChild &&
 | ||
|              !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
 | ||
|              !GetCachedStyleData(aSID),
 | ||
|              "This style should not have been computed");
 | ||
| 
 | ||
|   void* result;
 | ||
|   nsPresContext* presContext = PresContext();
 | ||
|   switch (aSID) {
 | ||
| #define UNIQUE_CASE(c_) \
 | ||
|     case eStyleStruct_##c_: \
 | ||
|       result = new (presContext) nsStyle##c_(presContext); \
 | ||
|       break;
 | ||
| 
 | ||
|   UNIQUE_CASE(Border)
 | ||
|   UNIQUE_CASE(Padding)
 | ||
| 
 | ||
| #undef UNIQUE_CASE
 | ||
| 
 | ||
|   default:
 | ||
|     NS_ERROR("Struct type not supported.");
 | ||
|     return nullptr;
 | ||
|   }
 | ||
| 
 | ||
|   // The new struct is owned by this style context, but that we don't
 | ||
|   // need to clear the bit in mBits because we've asserted that at the
 | ||
|   // top of this function.
 | ||
|   SetStyle(aSID, result);
 | ||
|   return result;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::SetIneligibleForSharing()
 | ||
| {
 | ||
|   if (mBits & NS_STYLE_INELIGIBLE_FOR_SHARING) {
 | ||
|     return;
 | ||
|   }
 | ||
|   mBits |= NS_STYLE_INELIGIBLE_FOR_SHARING;
 | ||
|   if (mChild) {
 | ||
|     GeckoStyleContext* child = mChild;
 | ||
|     do {
 | ||
|       child->SetIneligibleForSharing();
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mChild != child);
 | ||
|   }
 | ||
|   if (mEmptyChild) {
 | ||
|     GeckoStyleContext* child = mEmptyChild;
 | ||
|     do {
 | ||
|       child->SetIneligibleForSharing();
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mEmptyChild != child);
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| #ifdef RESTYLE_LOGGING
 | ||
| nsCString
 | ||
| GeckoStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
 | ||
| {
 | ||
|   nsCString structs;
 | ||
|   for (nsStyleStructID i = nsStyleStructID(0);
 | ||
|        i < nsStyleStructID_Length;
 | ||
|        i = nsStyleStructID(i + 1)) {
 | ||
|     if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
 | ||
|       const void* data = GetCachedStyleData(i);
 | ||
|       if (!structs.IsEmpty()) {
 | ||
|         structs.Append(' ');
 | ||
|       }
 | ||
|       structs.AppendPrintf("%s=%p", StructName(i), data);
 | ||
|       if (HasCachedDependentStyleData(i)) {
 | ||
|         structs.AppendLiteral("(dependent)");
 | ||
|       } else {
 | ||
|         structs.AppendLiteral("(owned)");
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
|   return structs;
 | ||
| }
 | ||
| 
 | ||
| int32_t&
 | ||
| GeckoStyleContext::LoggingDepth()
 | ||
| {
 | ||
|   static int32_t depth = 0;
 | ||
|   return depth;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
 | ||
| {
 | ||
|   LoggingDepth() = aLoggingDepth;
 | ||
|   LogStyleContextTree(true, aStructs);
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
 | ||
| {
 | ||
|   nsCString structs = GetCachedStyleDataAsString(aStructs);
 | ||
|   if (!structs.IsEmpty()) {
 | ||
|     structs.Append(' ');
 | ||
|   }
 | ||
| 
 | ||
|   nsCString pseudo;
 | ||
|   if (mPseudoTag) {
 | ||
|     nsAutoString pseudoTag;
 | ||
|     mPseudoTag->ToString(pseudoTag);
 | ||
|     AppendUTF16toUTF8(pseudoTag, pseudo);
 | ||
|     pseudo.Append(' ');
 | ||
|   }
 | ||
| 
 | ||
|   nsCString flags;
 | ||
|   if (IsStyleIfVisited()) {
 | ||
|     flags.AppendLiteral("IS_STYLE_IF_VISITED ");
 | ||
|   }
 | ||
|   if (HasChildThatUsesGrandancestorStyle()) {
 | ||
|     flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
 | ||
|   }
 | ||
|   if (IsShared()) {
 | ||
|     flags.AppendLiteral("IS_SHARED ");
 | ||
|   }
 | ||
| 
 | ||
|   nsCString parent;
 | ||
|   if (aFirst) {
 | ||
|     parent.AppendPrintf("parent=%p ", mParent.get());
 | ||
|   }
 | ||
| 
 | ||
|   LOG_RESTYLE("%p(%d) %s%s%s%s",
 | ||
|               this, mRefCnt,
 | ||
|               structs.get(), pseudo.get(), flags.get(), parent.get());
 | ||
| 
 | ||
|   LOG_RESTYLE_INDENT();
 | ||
| 
 | ||
|   if (nullptr != mChild) {
 | ||
|     GeckoStyleContext* child = mChild;
 | ||
|     do {
 | ||
|       child->LogStyleContextTree(false, aStructs);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mChild != child);
 | ||
|   }
 | ||
|   if (nullptr != mEmptyChild) {
 | ||
|     GeckoStyleContext* child = mEmptyChild;
 | ||
|     do {
 | ||
|       child->LogStyleContextTree(false, aStructs);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (mEmptyChild != child);
 | ||
|   }
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| static bool
 | ||
| ShouldSuppressLineBreak(const nsStyleContext* aContext,
 | ||
|                         const nsStyleDisplay* aDisplay,
 | ||
|                         const nsStyleContext* aParentContext,
 | ||
|                         const nsStyleDisplay* aParentDisplay)
 | ||
| {
 | ||
|   // The display change should only occur for "in-flow" children
 | ||
|   if (aDisplay->IsOutOfFlowStyle()) {
 | ||
|     return false;
 | ||
|   }
 | ||
|   // Display value of any anonymous box should not be touched. In most
 | ||
|   // cases, anonymous boxes are actually not in ruby frame, but instead,
 | ||
|   // some other frame with a ruby display value. Non-element pseudos
 | ||
|   // which represents text frames, as well as ruby pseudos are excluded
 | ||
|   // because we still want to set the flag for them.
 | ||
|   if ((aContext->GetPseudoType() == CSSPseudoElementType::InheritingAnonBox ||
 | ||
|        aContext->GetPseudoType() == CSSPseudoElementType::NonInheritingAnonBox) &&
 | ||
|       !nsCSSAnonBoxes::IsNonElement(aContext->GetPseudo()) &&
 | ||
|       !RubyUtils::IsRubyPseudo(aContext->GetPseudo())) {
 | ||
|     return false;
 | ||
|   }
 | ||
|   if (aParentContext->ShouldSuppressLineBreak()) {
 | ||
|     // Line break suppressing bit is propagated to any children of
 | ||
|     // line participants, which include inline, contents, and inline
 | ||
|     // ruby boxes.
 | ||
|     if (aParentDisplay->mDisplay == mozilla::StyleDisplay::Inline ||
 | ||
|         aParentDisplay->mDisplay == mozilla::StyleDisplay::Contents ||
 | ||
|         aParentDisplay->mDisplay == mozilla::StyleDisplay::Ruby ||
 | ||
|         aParentDisplay->mDisplay == mozilla::StyleDisplay::RubyBaseContainer) {
 | ||
|       return true;
 | ||
|     }
 | ||
|   }
 | ||
|   // Any descendant of ruby level containers is non-breakable, but
 | ||
|   // the level containers themselves are breakable. We have to check
 | ||
|   // the container display type against all ruby display type here
 | ||
|   // because any of the ruby boxes could be anonymous.
 | ||
|   // Note that, when certain HTML tags, e.g. form controls, have ruby
 | ||
|   // level container display type, they could also escape from this flag
 | ||
|   // while they shouldn't. However, it is generally fine since they
 | ||
|   // won't usually break the assertion that there is no line break
 | ||
|   // inside ruby, because:
 | ||
|   // 1. their display types, the ruby level container types, are inline-
 | ||
|   //    outside, which means they won't cause any forced line break; and
 | ||
|   // 2. they never start an inline span, which means their children, if
 | ||
|   //    any, won't be able to break the line its ruby ancestor lays; and
 | ||
|   // 3. their parent frame is always a ruby content frame (due to
 | ||
|   //    anonymous ruby box generation), which makes line layout suppress
 | ||
|   //    any optional line break around this frame.
 | ||
|   // However, there is one special case which is BR tag, because it
 | ||
|   // directly affects the line layout. This case is handled by the BR
 | ||
|   // frame which checks the flag of its parent frame instead of itself.
 | ||
|   if ((aParentDisplay->IsRubyDisplayType() &&
 | ||
|        aDisplay->mDisplay != mozilla::StyleDisplay::RubyBaseContainer &&
 | ||
|        aDisplay->mDisplay != mozilla::StyleDisplay::RubyTextContainer) ||
 | ||
|       // Since ruby base and ruby text may exist themselves without any
 | ||
|       // non-anonymous frame outside, we should also check them.
 | ||
|       aDisplay->mDisplay == mozilla::StyleDisplay::RubyBase ||
 | ||
|       aDisplay->mDisplay == mozilla::StyleDisplay::RubyText) {
 | ||
|     return true;
 | ||
|   }
 | ||
|   return false;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::FinishConstruction()
 | ||
| {
 | ||
|   MOZ_ASSERT(RuleNode());
 | ||
| 
 | ||
|   if (mParent) {
 | ||
|     mParent->AddChild(this);
 | ||
|   }
 | ||
| 
 | ||
|   SetStyleBits();
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::SetStyleBits()
 | ||
| {
 | ||
|   if ((mParent && mParent->HasPseudoElementData()) || IsPseudoElement()) {
 | ||
|     AddStyleBit(NS_STYLE_HAS_PSEUDO_ELEMENT_DATA);
 | ||
|   }
 | ||
| 
 | ||
|   // Set the NS_STYLE_IN_DISPLAY_NONE_SUBTREE bit
 | ||
|   const nsStyleDisplay* disp = StyleDisplay();
 | ||
|   if ((mParent && mParent->IsInDisplayNoneSubtree()) ||
 | ||
|       disp->mDisplay == mozilla::StyleDisplay::None) {
 | ||
|     AddStyleBit(NS_STYLE_IN_DISPLAY_NONE_SUBTREE);
 | ||
|   }
 | ||
| 
 | ||
|   // Mark text combined for text-combine-upright, as needed.
 | ||
|   if (mPseudoTag == nsCSSAnonBoxes::mozText && mParent &&
 | ||
|       mParent->StyleVisibility()->mWritingMode !=
 | ||
|         NS_STYLE_WRITING_MODE_HORIZONTAL_TB &&
 | ||
|       mParent->StyleText()->mTextCombineUpright ==
 | ||
|         NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
 | ||
|     AddStyleBit(NS_STYLE_IS_TEXT_COMBINED);
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| // Flex & grid containers blockify their children.
 | ||
| //  "The display value of a flex item is blockified"
 | ||
| //    https://drafts.csswg.org/css-flexbox-1/#flex-items
 | ||
| //  "The display value of a grid item is blockified"
 | ||
| //    https://drafts.csswg.org/css-grid/#grid-items
 | ||
| static bool
 | ||
| ShouldBlockifyChildren(const nsStyleDisplay* aStyleDisp)
 | ||
| {
 | ||
|   auto displayVal = aStyleDisp->mDisplay;
 | ||
|   return mozilla::StyleDisplay::Flex == displayVal ||
 | ||
|     mozilla::StyleDisplay::InlineFlex == displayVal ||
 | ||
|     mozilla::StyleDisplay::Grid == displayVal ||
 | ||
|     mozilla::StyleDisplay::InlineGrid == displayVal;
 | ||
| }
 | ||
| 
 | ||
| #ifdef DEBUG
 | ||
| void
 | ||
| GeckoStyleContext::AssertStructsNotUsedElsewhere(
 | ||
|                                        GeckoStyleContext* aDestroyingContext,
 | ||
|                                        int32_t aLevels) const
 | ||
| {
 | ||
|   if (aLevels == 0) {
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   void* data;
 | ||
| 
 | ||
|   if (mBits & NS_STYLE_IS_GOING_AWAY) {
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   if (this != aDestroyingContext) {
 | ||
|     nsInheritedStyleData& destroyingInheritedData =
 | ||
|       aDestroyingContext->mCachedInheritedData;
 | ||
| #define STYLE_STRUCT_INHERITED(name_, checkdata_cb)                            \
 | ||
|     data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_];        \
 | ||
|     if (data &&                                                                \
 | ||
|         !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&          \
 | ||
|          (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
 | ||
|       printf_stderr("style struct %p found on style context %p\n", data, this);\
 | ||
|       nsString url;                                                            \
 | ||
|       nsresult rv = PresContext()->Document()->GetURL(url);                    \
 | ||
|       if (NS_SUCCEEDED(rv)) {                                                  \
 | ||
|         printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());          \
 | ||
|       }                                                                        \
 | ||
|       MOZ_ASSERT(false, "destroying " #name_ " style struct still present "    \
 | ||
|                         "in style context tree");                              \
 | ||
|     }
 | ||
| #define STYLE_STRUCT_RESET(name_, checkdata_cb)
 | ||
| 
 | ||
| #include "nsStyleStructList.h"
 | ||
| 
 | ||
| #undef STYLE_STRUCT_INHERITED
 | ||
| #undef STYLE_STRUCT_RESET
 | ||
| 
 | ||
|     if (mCachedResetData) {
 | ||
|       nsResetStyleData* destroyingResetData =
 | ||
|         aDestroyingContext->mCachedResetData;
 | ||
|       if (destroyingResetData) {
 | ||
| #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
 | ||
| #define STYLE_STRUCT_RESET(name_, checkdata_cb)                                \
 | ||
|         data = destroyingResetData->mStyleStructs[eStyleStruct_##name_];       \
 | ||
|         if (data &&                                                            \
 | ||
|             !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&      \
 | ||
|             (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
 | ||
|           printf_stderr("style struct %p found on style context %p\n", data,   \
 | ||
|                         this);                                                 \
 | ||
|           nsString url;                                                        \
 | ||
|           nsresult rv = PresContext()->Document()->GetURL(url);                \
 | ||
|           if (NS_SUCCEEDED(rv)) {                                              \
 | ||
|             printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());      \
 | ||
|           }                                                                    \
 | ||
|           MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
 | ||
|                             "in style context tree");                          \
 | ||
|         }
 | ||
| 
 | ||
| #include "nsStyleStructList.h"
 | ||
| 
 | ||
| #undef STYLE_STRUCT_INHERITED
 | ||
| #undef STYLE_STRUCT_RESET
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   if (mChild) {
 | ||
|     const GeckoStyleContext* child = mChild;
 | ||
|     do {
 | ||
|       child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (child != mChild);
 | ||
|   }
 | ||
| 
 | ||
|   if (mEmptyChild) {
 | ||
|     const GeckoStyleContext* child = mEmptyChild;
 | ||
|     do {
 | ||
|       child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
 | ||
|       child = child->mNextSibling;
 | ||
|     } while (child != mEmptyChild);
 | ||
|   }
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
 | ||
| {
 | ||
| #define GET_UNIQUE_STYLE_DATA(name_) \
 | ||
|   static_cast<nsStyle##name_*>(GetUniqueStyleData(eStyleStruct_##name_))
 | ||
| 
 | ||
|   // CSS Inline Layout Level 3 - 3.5 Sizing Initial Letters:
 | ||
|   // For an N-line drop initial in a Western script, the cap-height of the
 | ||
|   // letter needs to be (N – 1) times the line-height, plus the cap-height
 | ||
|   // of the surrounding text.
 | ||
|   if (mPseudoTag == nsCSSPseudoElements::firstLetter) {
 | ||
|     const nsStyleTextReset* textReset = StyleTextReset();
 | ||
|     if (textReset->mInitialLetterSize != 0.0f) {
 | ||
|       GeckoStyleContext* containerSC = GetParent();
 | ||
|       const nsStyleDisplay* containerDisp = containerSC->StyleDisplay();
 | ||
|       while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
 | ||
|         if (!containerSC->GetParent()) {
 | ||
|           break;
 | ||
|         }
 | ||
|         containerSC = containerSC->GetParent();
 | ||
|         containerDisp = containerSC->StyleDisplay();
 | ||
|       }
 | ||
|       nscoord containerLH =
 | ||
|         ReflowInput::CalcLineHeight(nullptr, containerSC, NS_AUTOHEIGHT, 1.0f);
 | ||
|       RefPtr<nsFontMetrics> containerFM =
 | ||
|         nsLayoutUtils::GetFontMetricsForStyleContext(containerSC);
 | ||
|       MOZ_ASSERT(containerFM, "Should have fontMetrics!!");
 | ||
|       nscoord containerCH = containerFM->CapHeight();
 | ||
|       RefPtr<nsFontMetrics> firstLetterFM =
 | ||
|         nsLayoutUtils::GetFontMetricsForStyleContext(this);
 | ||
|       MOZ_ASSERT(firstLetterFM, "Should have fontMetrics!!");
 | ||
|       nscoord firstLetterCH = firstLetterFM->CapHeight();
 | ||
|       nsStyleFont* mutableStyleFont = GET_UNIQUE_STYLE_DATA(Font);
 | ||
|       float invCapHeightRatio =
 | ||
|         mutableStyleFont->mFont.size / NSCoordToFloat(firstLetterCH);
 | ||
|       mutableStyleFont->mFont.size =
 | ||
|         NSToCoordRound(((textReset->mInitialLetterSize - 1) * containerLH +
 | ||
|                         containerCH) *
 | ||
|                        invCapHeightRatio);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Change writing mode of text frame for text-combine-upright. We use
 | ||
|   // style structs of the parent to avoid triggering computation before
 | ||
|   // we change the writing mode.
 | ||
|   // It is safe to look at the parent's style because we are looking at
 | ||
|   // inherited properties, and ::-moz-text never matches any rules.
 | ||
|   if (mPseudoTag == nsCSSAnonBoxes::mozText && mParent &&
 | ||
|       mParent->StyleVisibility()->mWritingMode !=
 | ||
|         NS_STYLE_WRITING_MODE_HORIZONTAL_TB &&
 | ||
|       mParent->StyleText()->mTextCombineUpright ==
 | ||
|         NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
 | ||
|     MOZ_ASSERT(!PeekStyleVisibility(), "If StyleVisibility was already "
 | ||
|                "computed, some properties may have been computed "
 | ||
|                "incorrectly based on the old writing mode value");
 | ||
|     nsStyleVisibility* mutableVis = GET_UNIQUE_STYLE_DATA(Visibility);
 | ||
|     mutableVis->mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
 | ||
|   }
 | ||
| 
 | ||
|   // See if we have any text decorations.
 | ||
|   // First see if our parent has text decorations.  If our parent does, then we inherit the bit.
 | ||
|   if (mParent && mParent->HasTextDecorationLines()) {
 | ||
|     AddStyleBit(NS_STYLE_HAS_TEXT_DECORATION_LINES);
 | ||
|   } else {
 | ||
|     // We might have defined a decoration.
 | ||
|     if (StyleTextReset()->HasTextDecorationLines()) {
 | ||
|       AddStyleBit(NS_STYLE_HAS_TEXT_DECORATION_LINES);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // CSS 2.1 10.1: Propagate the root element's 'direction' to the ICB.
 | ||
|   // (PageContentFrame/CanvasFrame etc will inherit 'direction')
 | ||
|   if (mPseudoTag == nsCSSAnonBoxes::viewport) {
 | ||
|     nsPresContext* presContext = PresContext();
 | ||
|     mozilla::dom::Element* docElement = presContext->Document()->GetRootElement();
 | ||
|     if (docElement) {
 | ||
|       RefPtr<nsStyleContext> rootStyle =
 | ||
|         presContext->StyleSet()->AsGecko()->ResolveStyleFor(docElement, nullptr);
 | ||
|       auto dir = rootStyle->StyleVisibility()->mDirection;
 | ||
|       if (dir != StyleVisibility()->mDirection) {
 | ||
|         nsStyleVisibility* uniqueVisibility = GET_UNIQUE_STYLE_DATA(Visibility);
 | ||
|         uniqueVisibility->mDirection = dir;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Correct tables.
 | ||
|   const nsStyleDisplay* disp = StyleDisplay();
 | ||
|   if (disp->mDisplay == mozilla::StyleDisplay::Table) {
 | ||
|     // -moz-center and -moz-right are used for HTML's alignment
 | ||
|     // This is covering the <div align="right"><table>...</table></div> case.
 | ||
|     // In this case, we don't want to inherit the text alignment into the table.
 | ||
|     const nsStyleText* text = StyleText();
 | ||
| 
 | ||
|     if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
 | ||
|         text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
 | ||
|         text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
 | ||
|     {
 | ||
|       nsStyleText* uniqueText = GET_UNIQUE_STYLE_DATA(Text);
 | ||
|       uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_START;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Fixup the "justify-items: auto" value based on our parent style here if
 | ||
|   // needed.
 | ||
|   //
 | ||
|   // Note that this only pulls a unique struct in the case the parent has the
 | ||
|   // "legacy" modifier (which is not the default), and the computed value would
 | ||
|   // change as a result.
 | ||
|   //
 | ||
|   // We check the parent first just to avoid unconditionally pulling the
 | ||
|   // nsStylePosition struct on every style context.
 | ||
|   if (mParent &&
 | ||
|       mParent->StylePosition()->mJustifyItems & NS_STYLE_JUSTIFY_LEGACY &&
 | ||
|       StylePosition()->mSpecifiedJustifyItems == NS_STYLE_JUSTIFY_AUTO &&
 | ||
|       StylePosition()->mJustifyItems != mParent->StylePosition()->mJustifyItems) {
 | ||
|     nsStylePosition* uniquePosition = GET_UNIQUE_STYLE_DATA(Position);
 | ||
|     uniquePosition->mJustifyItems = mParent->StylePosition()->mJustifyItems;
 | ||
|   }
 | ||
| 
 | ||
|   // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
 | ||
|   // the root element.  We can't implement them in nsRuleNode because we
 | ||
|   // don't want to store all display structs that aren't 'block',
 | ||
|   // 'inline', or 'table' in the style context tree on the off chance
 | ||
|   // that the root element has its style reresolved later.  So do them
 | ||
|   // here if needed, by changing the style data, so that other code
 | ||
|   // doesn't get confused by looking at the style data.
 | ||
|   if (!mParent &&
 | ||
|       // We don't want to blockify various anon boxes that just happen to not
 | ||
|       // inherit from anything.  So restrict blockification only to actual
 | ||
|       // elements, the viewport (which should be block anyway, but in SVG
 | ||
|       // document's isn't because we lazy-load ua.css there), and the ::backdrop
 | ||
|       // pseudo-element.  This last is explicitly allowed to have any specified
 | ||
|       // display type in the spec, but computes to a blockified display type per
 | ||
|       // various provisions of
 | ||
|       // https://fullscreen.spec.whatwg.org/#new-stacking-layer
 | ||
|       (!mPseudoTag ||
 | ||
|        mPseudoTag == nsCSSAnonBoxes::viewport ||
 | ||
|        mPseudoTag == nsCSSPseudoElements::backdrop)) {
 | ||
|     auto displayVal = disp->mDisplay;
 | ||
|     if (displayVal != mozilla::StyleDisplay::Contents) {
 | ||
|       nsRuleNode::EnsureBlockDisplay(displayVal, true);
 | ||
|     } else {
 | ||
|       // http://dev.w3.org/csswg/css-display/#transformations
 | ||
|       // "... a display-outside of 'contents' computes to block-level
 | ||
|       //  on the root element."
 | ||
|       displayVal = mozilla::StyleDisplay::Block;
 | ||
|     }
 | ||
|     if (displayVal != disp->mDisplay) {
 | ||
|       nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
 | ||
|       disp = mutable_display;
 | ||
| 
 | ||
|       // If we're in this code, then mOriginalDisplay doesn't matter
 | ||
|       // for purposes of the cascade (because this nsStyleDisplay
 | ||
|       // isn't living in the ruletree anyway), and for determining
 | ||
|       // hypothetical boxes it's better to have mOriginalDisplay
 | ||
|       // matching mDisplay here.
 | ||
|       mutable_display->mOriginalDisplay = mutable_display->mDisplay =
 | ||
|         displayVal;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Adjust the "display" values of flex and grid items (but not for raw text
 | ||
|   // or placeholders). CSS3 Flexbox section 4 says:
 | ||
|   //   # The computed 'display' of a flex item is determined
 | ||
|   //   # by applying the table in CSS 2.1 Chapter 9.7.
 | ||
|   // ...which converts inline-level elements to their block-level equivalents.
 | ||
|   // Any block-level element directly contained by elements with ruby display
 | ||
|   // values are converted to their inline-level equivalents.
 | ||
|   if (!aSkipParentDisplayBasedStyleFixup && mParent) {
 | ||
|     // Skip display:contents ancestors to reach the potential container.
 | ||
|     // (If there are only display:contents ancestors between this node and
 | ||
|     // a flex/grid container ancestor, then this node is a flex/grid item, since
 | ||
|     // its parent *in the frame tree* will be the flex/grid container. So we treat
 | ||
|     // it like a flex/grid item here.)
 | ||
|     GeckoStyleContext* containerContext = GetParent();
 | ||
|     const nsStyleDisplay* containerDisp = containerContext->StyleDisplay();
 | ||
|     while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
 | ||
|       if (!containerContext->GetParent()) {
 | ||
|         break;
 | ||
|       }
 | ||
|       containerContext = containerContext->GetParent();
 | ||
|       containerDisp = containerContext->StyleDisplay();
 | ||
|     }
 | ||
|     if (ShouldBlockifyChildren(containerDisp) &&
 | ||
|         !nsCSSAnonBoxes::IsNonElement(GetPseudo())) {
 | ||
|       // NOTE: Technically, we shouldn't modify the 'display' value of
 | ||
|       // positioned elements, since they aren't flex/grid items. However,
 | ||
|       // we don't need to worry about checking for that, because if we're
 | ||
|       // positioned, we'll have already been through a call to
 | ||
|       // EnsureBlockDisplay() in nsRuleNode, so this call here won't change
 | ||
|       // anything. So we're OK.
 | ||
|       auto displayVal = disp->mDisplay;
 | ||
|       nsRuleNode::EnsureBlockDisplay(displayVal);
 | ||
|       if (displayVal != disp->mDisplay) {
 | ||
|         NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(),
 | ||
|                      "We shouldn't be changing the display value of "
 | ||
|                      "positioned content (and we should have already "
 | ||
|                      "converted its display value to be block-level...)");
 | ||
|         nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
 | ||
|         disp = mutable_display;
 | ||
|         mutable_display->mDisplay = displayVal;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Note: This must come after the blockification above, otherwise we fail
 | ||
|   // the grid-item-blockifying-001.html reftest.
 | ||
|   if (mParent && ::ShouldSuppressLineBreak(this, disp, mParent,
 | ||
|                                            mParent->StyleDisplay())) {
 | ||
|     mBits |= NS_STYLE_SUPPRESS_LINEBREAK;
 | ||
|     auto displayVal = disp->mDisplay;
 | ||
|     nsRuleNode::EnsureInlineDisplay(displayVal);
 | ||
|     if (displayVal != disp->mDisplay) {
 | ||
|       nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
 | ||
|       disp = mutable_display;
 | ||
|       mutable_display->mDisplay = displayVal;
 | ||
|     }
 | ||
|   }
 | ||
|   // Suppress border/padding of ruby level containers
 | ||
|   if (disp->mDisplay == mozilla::StyleDisplay::RubyBaseContainer ||
 | ||
|       disp->mDisplay == mozilla::StyleDisplay::RubyTextContainer) {
 | ||
|     CreateEmptyStyleData(eStyleStruct_Border);
 | ||
|     CreateEmptyStyleData(eStyleStruct_Padding);
 | ||
|   }
 | ||
|   if (disp->IsRubyDisplayType()) {
 | ||
|     // Per CSS Ruby spec section Bidi Reordering, for all ruby boxes,
 | ||
|     // the 'normal' and 'embed' values of 'unicode-bidi' should compute to
 | ||
|     // 'isolate', and 'bidi-override' should compute to 'isolate-override'.
 | ||
|     const nsStyleTextReset* textReset = StyleTextReset();
 | ||
|     uint8_t unicodeBidi = textReset->mUnicodeBidi;
 | ||
|     if (unicodeBidi == NS_STYLE_UNICODE_BIDI_NORMAL ||
 | ||
|         unicodeBidi == NS_STYLE_UNICODE_BIDI_EMBED) {
 | ||
|       unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE;
 | ||
|     } else if (unicodeBidi == NS_STYLE_UNICODE_BIDI_BIDI_OVERRIDE) {
 | ||
|       unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE;
 | ||
|     }
 | ||
|     if (unicodeBidi != textReset->mUnicodeBidi) {
 | ||
|       nsStyleTextReset* mutableTextReset = GET_UNIQUE_STYLE_DATA(TextReset);
 | ||
|       mutableTextReset->mUnicodeBidi = unicodeBidi;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   /*
 | ||
|    * According to https://drafts.csswg.org/css-writing-modes-3/#block-flow:
 | ||
|    *
 | ||
|    * If a box has a different block flow direction than its containing block:
 | ||
|    *   * If the box has a specified display of inline, its display computes
 | ||
|    *     to inline-block. [CSS21]
 | ||
|    *   ...etc.
 | ||
|    */
 | ||
|   if (disp->mDisplay == mozilla::StyleDisplay::Inline &&
 | ||
|       !nsCSSAnonBoxes::IsNonElement(mPseudoTag) &&
 | ||
|       mParent) {
 | ||
|     auto cbContext = GetParent();
 | ||
|     while (cbContext->StyleDisplay()->mDisplay == mozilla::StyleDisplay::Contents) {
 | ||
|       cbContext = cbContext->GetParent();
 | ||
|     }
 | ||
|     MOZ_ASSERT(cbContext, "the root context can't have display:contents");
 | ||
|     // We don't need the full mozilla::WritingMode value (incorporating dir
 | ||
|     // and text-orientation) here; just the writing-mode property is enough.
 | ||
|     if (StyleVisibility()->mWritingMode !=
 | ||
|           cbContext->StyleVisibility()->mWritingMode) {
 | ||
|       nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
 | ||
|       disp = mutable_display;
 | ||
|       mutable_display->mOriginalDisplay = mutable_display->mDisplay =
 | ||
|         mozilla::StyleDisplay::InlineBlock;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Compute User Interface style, to trigger loads of cursors
 | ||
|   StyleUserInterface();
 | ||
| #undef GET_UNIQUE_STYLE_DATA
 | ||
| }
 | ||
| 
 | ||
| bool
 | ||
| GeckoStyleContext::HasNoChildren() const
 | ||
| {
 | ||
|   return (nullptr == mChild) && (nullptr == mEmptyChild);
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
 | ||
| {
 | ||
|   // This method should only be called from nsRuleNode!  It is not a public
 | ||
|   // method!
 | ||
| 
 | ||
|   NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
 | ||
| 
 | ||
|   // NOTE:  nsCachedStyleData::GetStyleData works roughly the same way.
 | ||
|   // See the comments there (in nsRuleNode.h) for more details about
 | ||
|   // what this is doing and why.
 | ||
| 
 | ||
|   void** dataSlot;
 | ||
|   if (nsCachedStyleData::IsReset(aSID)) {
 | ||
|     if (!mCachedResetData) {
 | ||
|       mCachedResetData = new (PresContext()) nsResetStyleData;
 | ||
|     }
 | ||
|     dataSlot = &mCachedResetData->mStyleStructs[aSID];
 | ||
|   } else {
 | ||
|     dataSlot = &mCachedInheritedData.mStyleStructs[aSID];
 | ||
|   }
 | ||
|   NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)),
 | ||
|                "Going to leak style data");
 | ||
|   *dataSlot = aStruct;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| const void*
 | ||
| GeckoStyleContext::StyleData(nsStyleStructID aSID)
 | ||
| {
 | ||
|   const void* cachedData = GetCachedStyleData(aSID);
 | ||
|   if (cachedData)
 | ||
|     return cachedData; // We have computed data stored on this node in the context tree.
 | ||
|   // Our style source will take care of it for us.
 | ||
|   const void* newData = AsGecko()->RuleNode()->GetStyleData(aSID, this->AsGecko(), true);
 | ||
|   if (!nsCachedStyleData::IsReset(aSID)) {
 | ||
|     // always cache inherited data on the style context; the rule
 | ||
|     // node set the bit in mBits for us if needed.
 | ||
|     mCachedInheritedData.mStyleStructs[aSID] = const_cast<void*>(newData);
 | ||
|   }
 | ||
| 
 | ||
|   return newData;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::DestroyCachedStructs(nsPresContext* aPresContext)
 | ||
| {
 | ||
|   mCachedInheritedData.DestroyStructs(mBits, aPresContext);
 | ||
|   if (mCachedResetData) {
 | ||
|     mCachedResetData->Destroy(mBits, aPresContext);
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::SwapStyleData(GeckoStyleContext* aNewContext, uint32_t aStructs)
 | ||
| {
 | ||
|   static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
 | ||
| 
 | ||
|   for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
 | ||
|        i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
 | ||
|        i = nsStyleStructID(i + 1)) {
 | ||
|     uint32_t bit = nsCachedStyleData::GetBitForSID(i);
 | ||
|     if (!(aStructs & bit)) {
 | ||
|       continue;
 | ||
|     }
 | ||
|     void*& thisData = mCachedInheritedData.mStyleStructs[i];
 | ||
|     void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
 | ||
|     if (mBits & bit) {
 | ||
|       if (thisData == otherData) {
 | ||
|         thisData = nullptr;
 | ||
|       }
 | ||
|     } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
 | ||
|       std::swap(thisData, otherData);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   for (nsStyleStructID i = nsStyleStructID_Reset_Start;
 | ||
|        i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
 | ||
|        i = nsStyleStructID(i + 1)) {
 | ||
|     uint32_t bit = nsCachedStyleData::GetBitForSID(i);
 | ||
|     if (!(aStructs & bit)) {
 | ||
|       continue;
 | ||
|     }
 | ||
|     if (!mCachedResetData) {
 | ||
|       mCachedResetData = new (PresContext()) nsResetStyleData;
 | ||
|     }
 | ||
|     if (!aNewContext->mCachedResetData) {
 | ||
|       aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
 | ||
|     }
 | ||
|     void*& thisData = mCachedResetData->mStyleStructs[i];
 | ||
|     void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
 | ||
|     if (mBits & bit) {
 | ||
|       if (thisData == otherData) {
 | ||
|         thisData = nullptr;
 | ||
|       }
 | ||
|     } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
 | ||
|       std::swap(thisData, otherData);
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void
 | ||
| GeckoStyleContext::SetStyleIfVisited(already_AddRefed<GeckoStyleContext> aStyleIfVisited)
 | ||
| {
 | ||
|   MOZ_ASSERT(!IsStyleIfVisited(), "this context is not visited data");
 | ||
|   NS_ASSERTION(!mStyleIfVisited, "should only be set once");
 | ||
| 
 | ||
|   mStyleIfVisited = aStyleIfVisited;
 | ||
| 
 | ||
|   MOZ_ASSERT(mStyleIfVisited->IsStyleIfVisited(),
 | ||
|              "other context is visited data");
 | ||
|   MOZ_ASSERT(!mStyleIfVisited->GetStyleIfVisited(),
 | ||
|              "other context does not have visited data");
 | ||
|   NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
 | ||
|                "pseudo tag mismatch");
 | ||
|   if (GetParent() && GetParent()->GetStyleIfVisited()) {
 | ||
|     MOZ_ASSERT(GetStyleIfVisited()->GetParent() ==
 | ||
|                    GetParent()->GetStyleIfVisited() ||
 | ||
|                  GetStyleIfVisited()->GetParent() ==
 | ||
|                    GetParent(),
 | ||
|                  "parent mismatch");
 | ||
|   } else {
 | ||
|     MOZ_ASSERT(GetStyleIfVisited()->GetParent() ==
 | ||
|                    GetParent(),
 | ||
|                  "parent mismatch");
 | ||
|   }
 | ||
| }
 | ||
| 
 |