зеркало из https://github.com/mozilla/gecko-dev.git
254 строки
7.3 KiB
C++
254 строки
7.3 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) {
|
|
using Tag = StyleCounterStyle::Tag;
|
|
const auto& listStyleType = aFrame->StyleList()->mListStyleType;
|
|
switch (listStyleType.tag) {
|
|
case Tag::None:
|
|
return;
|
|
case Tag::String:
|
|
listStyleType.AsString().AsAtom()->ToString(aText);
|
|
return;
|
|
case Tag::Symbols:
|
|
case Tag::Name:
|
|
break;
|
|
}
|
|
|
|
CounterValue ordinal = 1;
|
|
GetFirstCounterValueForScopeAndFrame(&GetRootScope(), aFrame, ordinal);
|
|
|
|
aFrame->PresContext()->CounterStyleManager()->WithCounterStyleNameOrSymbols(
|
|
listStyleType, [&](CounterStyle* aStyle) {
|
|
nsAutoString text;
|
|
bool isBullet;
|
|
aStyle->GetSpokenCounterText(ordinal, aFrame->GetWritingMode(), text,
|
|
isBullet);
|
|
if (isBullet) {
|
|
aText = text;
|
|
aText.Append(' ');
|
|
} else {
|
|
aStyle->GetPrefix(aText);
|
|
aText += text;
|
|
nsAutoString suffix;
|
|
aStyle->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
|