forked from mirrors/gecko-dev
		
	 a4d842c063
			
		
	
	
		a4d842c063
		
	
	
	
	
		
			
			Make TreeOrderedArray support what the form controls stuff needs, and use it instead of custom nsContentUtils stuff. Differential Revision: https://phabricator.services.mozilla.com/D201261
		
			
				
	
	
		
			242 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
	
		
			7 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 "ContainStyleScopeManager.h"
 | |
| 
 | |
| #include "mozilla/ServoStyleSet.h"
 | |
| #include "nsIContentInlines.h"
 | |
| #include "CounterStyleManager.h"
 | |
| #include "nsCounterManager.h"
 | |
| #include "nsIContent.h"
 | |
| #include "nsIFrame.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsQuoteList.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| 
 | |
| nsGenConNode* ContainStyleScope::GetPrecedingElementInGenConList(
 | |
|     nsGenConList* aList) {
 | |
|   auto IsAfter = [this](nsGenConNode* aNode) {
 | |
|     return nsContentUtils::CompareTreePosition<TreeKind::Flat>(
 | |
|                mContent, aNode->mPseudoFrame->GetContent(),
 | |
|                /* aCommonAncestor = */ nullptr) > 0;
 | |
|   };
 | |
|   return aList->BinarySearch(IsAfter);
 | |
| }
 | |
| 
 | |
| void ContainStyleScope::RecalcAllCounters() {
 | |
|   GetCounterManager().RecalcAll();
 | |
|   for (auto* child : mChildren) {
 | |
|     child->RecalcAllCounters();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ContainStyleScope::RecalcAllQuotes() {
 | |
|   GetQuoteList().RecalcAll();
 | |
|   for (auto* child : mChildren) {
 | |
|     child->RecalcAllQuotes();
 | |
|   }
 | |
| }
 | |
| 
 | |
| ContainStyleScope& ContainStyleScopeManager::GetOrCreateScopeForContent(
 | |
|     nsIContent* aContent) {
 | |
|   for (; aContent; aContent = aContent->GetFlattenedTreeParent()) {
 | |
|     auto* element = dom::Element::FromNode(*aContent);
 | |
|     if (!element) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // Do not allow elements which have `display: contents` to create style
 | |
|     // boundaries. See https://github.com/w3c/csswg-drafts/issues/7392.
 | |
|     if (element->IsDisplayContents()) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     const auto* style = Servo_Element_GetMaybeOutOfDateStyle(element);
 | |
|     if (!style) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (!style->SelfOrAncestorHasContainStyle()) {
 | |
|       return GetRootScope();
 | |
|     }
 | |
| 
 | |
|     if (!style->StyleDisplay()->IsContainStyle()) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (auto* scope = mScopes.Get(aContent)) {
 | |
|       return *scope;
 | |
|     }
 | |
| 
 | |
|     auto& parentScope =
 | |
|         GetOrCreateScopeForContent(aContent->GetFlattenedTreeParent());
 | |
|     return *mScopes.InsertOrUpdate(
 | |
|         aContent, MakeUnique<ContainStyleScope>(this, &parentScope, aContent));
 | |
|   }
 | |
| 
 | |
|   return GetRootScope();
 | |
| }
 | |
| 
 | |
| ContainStyleScope& ContainStyleScopeManager::GetScopeForContent(
 | |
|     nsIContent* aContent) {
 | |
|   MOZ_ASSERT(aContent);
 | |
| 
 | |
|   if (auto* element = dom::Element::FromNode(*aContent)) {
 | |
|     if (const auto* style = Servo_Element_GetMaybeOutOfDateStyle(element)) {
 | |
|       if (!style->SelfOrAncestorHasContainStyle()) {
 | |
|         return GetRootScope();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (; aContent; aContent = aContent->GetFlattenedTreeParent()) {
 | |
|     if (auto* scope = mScopes.Get(aContent)) {
 | |
|       return *scope;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return GetRootScope();
 | |
| }
 | |
| 
 | |
| void ContainStyleScopeManager::Clear() {
 | |
|   GetRootScope().GetQuoteList().Clear();
 | |
|   GetRootScope().GetCounterManager().Clear();
 | |
| 
 | |
|   DestroyScope(&GetRootScope());
 | |
|   MOZ_DIAGNOSTIC_ASSERT(mScopes.IsEmpty(),
 | |
|                         "Destroying the root scope should destroy all scopes.");
 | |
| }
 | |
| 
 | |
| void ContainStyleScopeManager::DestroyScopesFor(nsIFrame* aFrame) {
 | |
|   if (auto* scope = mScopes.Get(aFrame->GetContent())) {
 | |
|     DestroyScope(scope);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ContainStyleScopeManager::DestroyScope(ContainStyleScope* aScope) {
 | |
|   // Deleting a scope modifies the array of children in its parent, so we don't
 | |
|   // use an iterator here.
 | |
|   while (!aScope->GetChildren().IsEmpty()) {
 | |
|     DestroyScope(aScope->GetChildren().ElementAt(0));
 | |
|   }
 | |
|   mScopes.Remove(aScope->GetContent());
 | |
| }
 | |
| 
 | |
| bool ContainStyleScopeManager::DestroyCounterNodesFor(nsIFrame* aFrame) {
 | |
|   bool result = false;
 | |
|   for (auto* scope = &GetScopeForContent(aFrame->GetContent()); scope;
 | |
|        scope = scope->GetParent()) {
 | |
|     result |= scope->GetCounterManager().DestroyNodesFor(aFrame);
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| bool ContainStyleScopeManager::AddCounterChanges(nsIFrame* aNewFrame) {
 | |
|   return GetOrCreateScopeForContent(
 | |
|              aNewFrame->GetContent()->GetFlattenedTreeParent())
 | |
|       .GetCounterManager()
 | |
|       .AddCounterChanges(aNewFrame);
 | |
| }
 | |
| 
 | |
| nsCounterList* ContainStyleScopeManager::GetOrCreateCounterList(
 | |
|     dom::Element& aElement, nsAtom* aCounterName) {
 | |
|   return GetOrCreateScopeForContent(&aElement)
 | |
|       .GetCounterManager()
 | |
|       .GetOrCreateCounterList(aCounterName);
 | |
| }
 | |
| 
 | |
| bool ContainStyleScopeManager::CounterDirty(nsAtom* aCounterName) {
 | |
|   return mDirtyCounters.Contains(aCounterName);
 | |
| }
 | |
| 
 | |
| void ContainStyleScopeManager::SetCounterDirty(nsAtom* aCounterName) {
 | |
|   mDirtyCounters.Insert(aCounterName);
 | |
| }
 | |
| 
 | |
| void ContainStyleScopeManager::RecalcAllCounters() {
 | |
|   GetRootScope().RecalcAllCounters();
 | |
|   mDirtyCounters.Clear();
 | |
| }
 | |
| 
 | |
| #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
 | |
| void ContainStyleScopeManager::DumpCounters() {
 | |
|   GetRootScope().GetCounterManager().Dump();
 | |
|   for (auto& entry : mScopes) {
 | |
|     entry.GetWeak()->GetCounterManager().Dump();
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef ACCESSIBILITY
 | |
| static bool GetFirstCounterValueForScopeAndFrame(ContainStyleScope* aScope,
 | |
|                                                  nsIFrame* aFrame,
 | |
|                                                  CounterValue& aOrdinal) {
 | |
|   if (aScope->GetCounterManager().GetFirstCounterValueForFrame(aFrame,
 | |
|                                                                aOrdinal)) {
 | |
|     return true;
 | |
|   }
 | |
|   for (auto* child : aScope->GetChildren()) {
 | |
|     if (GetFirstCounterValueForScopeAndFrame(child, aFrame, aOrdinal)) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void ContainStyleScopeManager::GetSpokenCounterText(nsIFrame* aFrame,
 | |
|                                                     nsAString& aText) {
 | |
|   CounterValue ordinal = 1;
 | |
|   GetFirstCounterValueForScopeAndFrame(&GetRootScope(), aFrame, ordinal);
 | |
| 
 | |
|   CounterStyle* counterStyle =
 | |
|       aFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle(
 | |
|           aFrame->StyleList()->mCounterStyle);
 | |
|   nsAutoString text;
 | |
|   bool isBullet;
 | |
|   counterStyle->GetSpokenCounterText(ordinal, aFrame->GetWritingMode(), text,
 | |
|                                      isBullet);
 | |
|   if (isBullet) {
 | |
|     aText = text;
 | |
|     if (!counterStyle->IsNone()) {
 | |
|       aText.Append(' ');
 | |
|     }
 | |
|   } else {
 | |
|     counterStyle->GetPrefix(aText);
 | |
|     aText += text;
 | |
|     nsAutoString suffix;
 | |
|     counterStyle->GetSuffix(suffix);
 | |
|     aText += suffix;
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void ContainStyleScopeManager::SetAllCountersDirty() {
 | |
|   GetRootScope().GetCounterManager().SetAllDirty();
 | |
|   for (auto& entry : mScopes) {
 | |
|     entry.GetWeak()->GetCounterManager().SetAllDirty();
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool ContainStyleScopeManager::DestroyQuoteNodesFor(nsIFrame* aFrame) {
 | |
|   bool result = false;
 | |
|   for (auto* scope = &GetScopeForContent(aFrame->GetContent()); scope;
 | |
|        scope = scope->GetParent()) {
 | |
|     result |= scope->GetQuoteList().DestroyNodesFor(aFrame);
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| nsQuoteList* ContainStyleScopeManager::QuoteListFor(dom::Element& aElement) {
 | |
|   return &GetOrCreateScopeForContent(&aElement).GetQuoteList();
 | |
| }
 | |
| 
 | |
| void ContainStyleScopeManager::RecalcAllQuotes() {
 | |
|   GetRootScope().RecalcAllQuotes();
 | |
| }
 | |
| 
 | |
| }  // namespace mozilla
 |