--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1015,16 +1015,49 @@ protected:
// Our list of all pending bindings. When we're done, we need to call
// AddToAttachedQueue on all of them, in order.
LinkedList<PendingBinding> mPendingBindings;
PendingBinding* mCurrentPendingBindingInsertionPoint;
};
+/**
+ * Set the provided style root location to the provided frame if it's style
+ * containing.
+ * If we should be in a style root, but aren't, scan up the frame tree to find
+ * the correct style root.
+ * Automatically restore the style root when destroyed.
+ */
+class MOZ_STACK_CLASS AutoRestoreContainStyleRoot {
+ private:
+ nsIFrame*& mLocation;
+ nsIFrame* mLastRoot;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
+
+ public:
+ AutoRestoreContainStyleRoot(nsIFrame*& aLocation, nsIFrame* aPotentialRoot MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : mLocation(aLocation)
+ , mLastRoot(aLocation)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ if (aPotentialRoot) {
+ if (aPotentialRoot->StyleDisplay()->IsContainStyle()) {
+ mLocation = aPotentialRoot;
+ } else if (!aLocation &&
+ aPotentialRoot->Style()->HasContainStyle()) {
+ mLocation = nsCSSFrameConstructor::FindContainStyleRoot(aPotentialRoot);
+ }
+ }
+ }
+ ~AutoRestoreContainStyleRoot() {
+ mLocation = mLastRoot;
+ }
+};
+
nsFrameConstructorState::nsFrameConstructorState(
nsIPresShell* aPresShell,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock,
already_AddRefed<nsILayoutHistoryState> aHistoryState)
: mPresContext(aPresShell->GetPresContext()),
mPresShell(aPresShell),
@@ -1588,16 +1621,17 @@ MoveChildrenTo(nsIFrame* aOldParent,
nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument* aDocument,
nsIPresShell* aPresShell)
: nsFrameManager(aPresShell)
, mDocument(aDocument)
, mRootElementFrame(nullptr)
, mRootElementStyleFrame(nullptr)
, mDocElementContainingBlock(nullptr)
, mPageSequenceFrame(nullptr)
+ , mContainStyleRoot(nullptr)
, mFirstFreeFCItem(nullptr)
, mFCItemsInUse(0)
, mCurrentDepth(0)
, mQuotesDirty(false)
, mCountersDirty(false)
, mIsDestroyingFrameTree(false)
, mHasRootAbsPosContainingBlock(false)
, mAlwaysCreateFramesForIgnorableWhitespace(false)
@@ -1656,18 +1690,19 @@ nsCSSFrameConstructor::nsCSSFrameConstru
void
nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame)
{
if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
if (mQuoteList.DestroyNodesFor(aFrame))
QuotesDirty();
}
+ // XXX kzentner: Can we already know our style root here?
if (aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE) &&
- mCounterManager.DestroyNodesFor(aFrame)) {
+ mCounterManager.DestroyNodesFor(FindContainStyleRoot(aFrame), aFrame)) {
// Technically we don't need to update anything if we destroyed only
// USE nodes. However, this is unlikely to happen in the real world
// since USE nodes generally go along with INCREMENT nodes.
CountersDirty();
}
RestyleManager()->NotifyDestroyingFrame(aFrame);
}
@@ -1698,16 +1733,17 @@ nsCSSFrameConstructor::CreateGenConTextN
nsINode::DeleteProperty<nsGenConInitializer>);
aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
}
return content.forget();
}
already_AddRefed<nsIContent>
nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState,
+ nsContainerFrame* aParentFrame,
Element* aParentContent,
ComputedStyle* aComputedStyle,
uint32_t aContentIndex)
{
// Get the content value
const nsStyleContentData &data =
aComputedStyle->StyleContent()->ContentAt(aContentIndex);
nsStyleContentType type = data.GetType();
@@ -1751,17 +1787,18 @@ nsCSSFrameConstructor::CreateGeneratedCo
attrNameSpace, attrName, getter_AddRefs(content));
return content.forget();
}
case eStyleContentType_Counter:
case eStyleContentType_Counters: {
nsStyleContentData::CounterFunction* counters = data.GetCounters();
nsCounterList* counterList =
- mCounterManager.CounterListFor(counters->mIdent);
+ mCounterManager.CounterListFor(GetContainStyleRoot(aParentFrame),
+ counters->mIdent);
nsCounterUseNode* node =
new nsCounterUseNode(counters, aContentIndex,
type == eStyleContentType_Counters);
nsGenConInitializer* initializer =
new nsGenConInitializer(node, counterList,
&nsCSSFrameConstructor::CountersDirty);
@@ -1908,17 +1945,17 @@ nsCSSFrameConstructor::CreateGeneratedCo
// and replace old one.
mPresShell->StyleSet()->StyleNewSubtree(container);
pseudoComputedStyle = styleSet->ResolveServoStyle(container);
}
uint32_t contentCount = pseudoComputedStyle->StyleContent()->ContentCount();
for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
nsCOMPtr<nsIContent> content =
- CreateGeneratedContent(aState, aParentContent, pseudoComputedStyle,
+ CreateGeneratedContent(aState, aParentFrame, aParentContent, pseudoComputedStyle,
contentIndex);
if (content) {
container->AppendChildTo(content, false);
if (content->IsElement()) {
// If we created any children elements, Servo needs to traverse them, but
// the root is already set up.
mPresShell->StyleSet()->StyleNewSubtree(content->AsElement());
}
@@ -4947,18 +4984,20 @@ nsCSSFrameConstructor::InitAndRestoreFra
aNewFrame->Init(aContent, aParentFrame, nullptr);
aNewFrame->AddStateBits(aState.mAdditionalStateBits);
if (aState.mFrameState) {
// Restore frame state for just the newly created frame.
RestoreFrameStateFor(aNewFrame, aState.mFrameState);
}
+ AutoRestoreContainStyleRoot savedContainStyleRoot(mContainStyleRoot, aNewFrame);
if (aAllowCounters &&
- mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) {
+ mCounterManager.AddCounterResetsAndIncrements(GetContainStyleRoot(aNewFrame),
+ aNewFrame)) {
CountersDirty();
}
}
already_AddRefed<ComputedStyle>
nsCSSFrameConstructor::ResolveComputedStyle(nsIContent* aContent)
{
ServoStyleSet* styleSet = mPresShell->StyleSet();
@@ -8238,16 +8277,17 @@ nsCSSFrameConstructor::EnsureFrameForTex
// pages that repeatedly query metrics for collapsed-whitespace text nodes
// don't trigger pathological behavior.
mAlwaysCreateFramesForIgnorableWhitespace = true;
Element* root = mDocument->GetRootElement();
if (!root) {
return false;
}
+ AutoRestoreContainStyleRoot savedContainStyleRoot(mContainStyleRoot, aContent->GetPrimaryFrame());
RestyleManager()->PostRestyleEvent(
root, nsRestyleHint(0), nsChangeHint_ReconstructFrame);
return true;
}
void
nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
const CharacterDataChangeInfo& aInfo)
@@ -10193,16 +10233,18 @@ nsCSSFrameConstructor::ProcessChildren(n
const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
static_assert(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
AutoRestore<uint16_t> savedDepth(mCurrentDepth);
if (mCurrentDepth != UINT16_MAX) {
++mCurrentDepth;
}
+ AutoRestoreContainStyleRoot savedContainStyleRoot(mContainStyleRoot, aFrame);
+
if (!aPossiblyLeafFrame) {
aPossiblyLeafFrame = aFrame;
}
// XXXbz ideally, this would do all the pushing of various
// containing blocks as needed, so callers don't have to do it...
// Check that our parent frame is a block before allowing ::first-letter/line.
@@ -11136,16 +11178,17 @@ nsCSSFrameConstructor::CreateListBoxCont
// any frame at all
const nsStyleDisplay* display = computedStyle->StyleDisplay();
if (StyleDisplay::None == display->mDisplay) {
*aNewFrame = nullptr;
return;
}
+ AutoRestoreContainStyleRoot savedContainStyleRoot(mContainStyleRoot, aParentFrame);
AutoFrameConstructionItemList items(this);
AddFrameConstructionItemsInternal(state, aChild, aParentFrame,
true, computedStyle,
ITEM_ALLOW_XBL_BASE, nullptr, items);
ConstructFramesFromItemList(state, items, aParentFrame,
/* aParentIsWrapperAnonBox = */ false,
frameItems);
@@ -11952,16 +11995,17 @@ nsCSSFrameConstructor::ReframeContaining
InsertionKind::Async);
}
void
nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
{
{
nsAutoScriptBlocker scriptBlocker;
+ AutoRestoreContainStyleRoot savedContainStyleRoot(mContainStyleRoot, aFrame);
nsFrameItems childItems;
nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
// We don't have a parent frame with a pending binding constructor here,
// so no need to worry about ordering of the kids' constructors with it.
// Pass null for the PendingBinding.
ProcessChildren(state, aFrame->GetContent(), aFrame->Style(),
aFrame, false, childItems, false,
nullptr);
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -461,23 +461,25 @@ private:
* Create a content node for the given generated content style.
* The caller takes care of making it SetIsNativeAnonymousRoot, binding it
* to the document, and creating frames for it.
* @param aParentContent is the node that has the before/after style
* @param aComputedStyle is the 'before' or 'after' pseudo-element style.
* @param aContentIndex is the index of the content item to create
*/
already_AddRefed<nsIContent> CreateGeneratedContent(nsFrameConstructorState& aState,
+ nsContainerFrame* aParentFrame,
mozilla::dom::Element* aParentContent,
ComputedStyle* aComputedStyle,
uint32_t aContentIndex);
+ // XXX delete below comment upon successfull impl. of contain:style
// aFrame may be null; this method doesn't use it directly in any case.
void CreateGeneratedContentItem(nsFrameConstructorState& aState,
- nsContainerFrame* aFrame,
+ nsContainerFrame* aParentFrame,
mozilla::dom::Element* aContent,
ComputedStyle* aComputedStyle,
CSSPseudoElementType aPseudoElement,
FrameConstructionItemList& aItems);
// This method can change aFrameList: it can chop off the beginning and put
// it in aParentFrame while putting the remainder into a ib-split sibling of
// aParentFrame. aPrevSibling must be the frame after which aFrameList is to
@@ -2126,21 +2128,43 @@ private:
void QuotesDirty();
void CountersDirty();
// Create touch caret frame.
void ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
nsIFrame* aFrame,
nsIContent* aDocElement);
+
+ nsIFrame* GetContainStyleRoot(nsIFrame* aRootDescendant) {
+ NS_ASSERTION(mContainStyleRoot == FindContainStyleRoot(aRootDescendant),
+ "mContainStyleRoot should be set correctly.");
+ return mContainStyleRoot;
+ }
public:
friend class nsFrameConstructorState;
+ static
+ nsIFrame* FindContainStyleRoot(nsIFrame* aDescendant) {
+ nsIFrame* ancestor = aDescendant;
+ if (!ancestor->Style()->HasContainStyle()) {
+ // We're not contain style.
+ // XXX: Return root frame here, see link below:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1172087#c57
+ //return ancestor->PresContext()->PresShell()->GetRootFrame();
+ return nullptr;
+ }
+ while (ancestor && !ancestor->StyleDisplay()->IsContainStyle()) {
+ ancestor = ancestor->GetParent();
+ }
+ return ancestor;
+}
+
private:
// For allocating FrameConstructionItems from the mFCItemPool arena.
friend struct FrameConstructionItem;
void* AllocateFCItem();
void FreeFCItem(FrameConstructionItem*);
nsIDocument* mDocument; // Weak ref
@@ -2159,16 +2183,17 @@ private:
// FrameConstructionItem arena + list of freed items available for re-use.
mozilla::ArenaAllocator<4096, 8> mFCItemPool;
struct FreeFCItemLink { FreeFCItemLink* mNext; };
FreeFCItemLink* mFirstFreeFCItem;
size_t mFCItemsInUse;
nsQuoteList mQuoteList;
nsCounterManager mCounterManager;
+ nsIFrame* mContainStyleRoot;
// Current ProcessChildren depth.
uint16_t mCurrentDepth;
bool mQuotesDirty : 1;
bool mCountersDirty : 1;
bool mIsDestroyingFrameTree : 1;
// This is true if mDocElementContainingBlock supports absolute positioning
bool mHasRootAbsPosContainingBlock : 1;
bool mAlwaysCreateFramesForIgnorableWhitespace : 1;
--- a/layout/base/nsCounterManager.cpp
+++ b/layout/base/nsCounterManager.cpp
@@ -146,17 +146,29 @@ nsCounterList::SetScope(nsCounterNode* a
// A reset's outer scope can't be a scope created by a sibling.
if (!(aNode->mType == nsCounterNode::RESET &&
nodeContent == startContent) &&
// everything is inside the root (except the case above,
// a second reset on the root)
(!startContent ||
nsContentUtils::ContentIsDescendantOf(nodeContent,
- startContent))) {
+ startContent) /*||
+ // Test if we hit the beginning of the list. This implies that
+ // there are no acceptable start of scopes for this counter inside
+ // the current 'contain: style' element (or the whole document, if
+ // there is no such element).
+ // Therefore, we should treat this null start of scope as an
+ // "implicit reset", which will start our scope unless we are the
+ // start of our own scope.
+ // If there is no such 'contain: style' element, and we should be
+ // scoped to the entire document, then the !startContent test
+ // above would have succeeded, so this condition should only
+ // succeed from using style containment.
+ (start == First() && aNode->mType != nsCounterNode::RESET)*/)) {
aNode->mScopeStart = start;
aNode->mScopePrev = prev;
return;
}
}
aNode->mScopeStart = nullptr;
aNode->mScopePrev = nullptr;
@@ -181,51 +193,53 @@ nsCounterList::RecalcAll()
useNode->GetText(text);
useNode->mText->SetData(text, IgnoreErrors());
}
}
}
}
bool
-nsCounterManager::AddCounterResetsAndIncrements(nsIFrame* aFrame)
+nsCounterManager::AddCounterResetsAndIncrements(nsIFrame* aRoot,
+ nsIFrame* aFrame)
{
const nsStyleContent* styleContent = aFrame->StyleContent();
if (!styleContent->CounterIncrementCount() &&
!styleContent->CounterResetCount()) {
MOZ_ASSERT(!aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE));
return false;
}
aFrame->AddStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE);
// Add in order, resets first, so all the comparisons will be optimized
// for addition at the end of the list.
int32_t i, i_end;
bool dirty = false;
for (i = 0, i_end = styleContent->CounterResetCount(); i != i_end; ++i) {
- dirty |= AddResetOrIncrement(aFrame, i, styleContent->CounterResetAt(i),
+ dirty |= AddResetOrIncrement(aRoot, aFrame, i, styleContent->CounterResetAt(i),
nsCounterChangeNode::RESET);
}
for (i = 0, i_end = styleContent->CounterIncrementCount(); i != i_end; ++i) {
- dirty |= AddResetOrIncrement(aFrame, i, styleContent->CounterIncrementAt(i),
+ dirty |= AddResetOrIncrement(aRoot, aFrame, i, styleContent->CounterIncrementAt(i),
nsCounterChangeNode::INCREMENT);
}
return dirty;
}
bool
-nsCounterManager::AddResetOrIncrement(nsIFrame* aFrame, int32_t aIndex,
+nsCounterManager::AddResetOrIncrement(nsIFrame *aRoot, nsIFrame* aFrame,
+ int32_t aIndex,
const nsStyleCounterData& aCounterData,
nsCounterNode::Type aType)
{
nsCounterChangeNode* node =
new nsCounterChangeNode(aFrame, aType, aCounterData.mValue, aIndex);
- nsCounterList* counterList = CounterListFor(aCounterData.mCounter);
+ nsCounterList* counterList = CounterListFor(aRoot, aCounterData.mCounter);
counterList->Insert(node);
if (!counterList->IsLast(node)) {
// Tell the caller it's responsible for recalculating the entire
// list.
counterList->SetDirty();
return true;
}
@@ -233,64 +247,75 @@ nsCounterManager::AddResetOrIncrement(ns
// anyway, and trying to calculate with a dirty list doesn't work.
if (MOZ_LIKELY(!counterList->IsDirty())) {
node->Calc(counterList);
}
return false;
}
nsCounterList*
-nsCounterManager::CounterListFor(const nsAString& aCounterName)
+nsCounterManager::CounterListFor(nsIFrame *aRoot, const nsAString& aCounterName)
{
- return mNames.LookupForAdd(aCounterName).OrInsert([]() {
+ NameTable* names = GetNames(aRoot);
+ return names->LookupForAdd(aCounterName).OrInsert([]() {
return new nsCounterList();
});
}
void
nsCounterManager::RecalcAll()
{
- for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) {
- nsCounterList* list = iter.UserData();
- if (list->IsDirty()) {
- list->RecalcAll();
- }
+ for (auto iter = mContainStyleRoots.ConstIter(); !iter.Done(); iter.Next()) {
+ NameTable* rootNames = iter.UserData();
+ for (auto iter_l2 = rootNames->ConstIter(); !iter_l2.Done(); iter_l2.Next()) {
+ nsCounterList* list = iter_l2.UserData();
+ if (list->IsDirty()) {
+ list->RecalcAll();
+ }
+ }
}
}
void
nsCounterManager::SetAllDirty()
{
- for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) {
- iter.UserData()->SetDirty();
+ for (auto iter = mContainStyleRoots.Iter(); !iter.Done(); iter.Next()) {
+ NameTable* rootNames = iter.UserData();
+ for (auto iter_l2 = rootNames->ConstIter(); !iter_l2.Done(); iter_l2.Next()) {
+ iter_l2.UserData()->SetDirty();
+ }
}
}
bool
-nsCounterManager::DestroyNodesFor(nsIFrame* aFrame)
+nsCounterManager::DestroyNodesFor(nsIFrame *aRoot, nsIFrame* aFrame)
{
MOZ_ASSERT(aFrame->HasAnyStateBits(NS_FRAME_HAS_CSS_COUNTER_STYLE),
"why call me?");
bool destroyedAny = false;
- for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) {
+ NameTable* rootNames = GetNames(aRoot, false);
+ for (auto iter = rootNames->Iter(); !iter.Done(); iter.Next()) {
nsCounterList* list = iter.UserData();
if (list->DestroyNodesFor(aFrame)) {
destroyedAny = true;
list->SetDirty();
+ mContainStyleRoots.Remove(aFrame);
}
}
return destroyedAny;
}
#ifdef DEBUG
void
nsCounterManager::Dump()
{
- printf("\n\nCounter Manager Lists:\n");
- for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) {
+ // XXX: Temporarily commented out, fix this after fixing
+ // contain:style implementation.
+ /*printf("\n\nCounter Manager Lists:\n");
+ for (auto iter = mContainStyleRoots.Iter(); !iter.Done(); iter.Next()) {
printf("Counter named \"%s\":\n",
NS_ConvertUTF16toUTF8(iter.Key()).get());
nsCounterList* list = iter.UserData();
int32_t i = 0;
for (nsCounterNode* node = list->First(); node; node = list->Next(node)) {
const char* types[] = { "RESET", "INCREMENT", "USE" };
printf(" Node #%d @%p frame=%p index=%d type=%s valAfter=%d\n"
@@ -302,11 +327,11 @@ nsCounterManager::Dump()
if (node->mType == nsCounterNode::USE) {
nsAutoString text;
node->UseNode()->GetText(text);
printf(" text=%s", NS_ConvertUTF16toUTF8(text).get());
}
printf("\n");
}
}
- printf("\n\n");
+ printf("\n\n");*/
}
#endif
--- a/layout/base/nsCounterManager.h
+++ b/layout/base/nsCounterManager.h
@@ -203,34 +203,34 @@ private:
/**
* The counter manager maintains an |nsCounterList| for each named
* counter to keep track of all scopes with that name.
*/
class nsCounterManager {
public:
// Returns true if dirty
- bool AddCounterResetsAndIncrements(nsIFrame *aFrame);
+ bool AddCounterResetsAndIncrements(nsIFrame *aRoot, nsIFrame *aFrame);
// Gets the appropriate counter list, creating it if necessary.
// Guaranteed to return non-null. (Uses an infallible hashtable API.)
- nsCounterList* CounterListFor(const nsAString& aCounterName);
+ nsCounterList* CounterListFor(nsIFrame *aRoot, const nsAString& aCounterName);
// Clean up data in any dirty counter lists.
void RecalcAll();
// Set all counter lists dirty
void SetAllDirty();
// Destroy nodes for the frame in any lists, and return whether any
// nodes were destroyed.
- bool DestroyNodesFor(nsIFrame *aFrame);
+ bool DestroyNodesFor(nsIFrame *aRoot, nsIFrame *aFrame);
// Clear all data.
- void Clear() { mNames.Clear(); }
+ void Clear() { mContainStyleRoots.Clear(); }
#ifdef DEBUG
void Dump();
#endif
static int32_t IncrementCounter(int32_t aOldValue, int32_t aIncrement)
{
// Addition of unsigned values is defined to be arithmetic
@@ -250,18 +250,30 @@ public:
// counter will get stuck at the largest multiple of 5 less than
// the maximum 32-bit integer.)
if ((aIncrement > 0) != (newValue > aOldValue)) {
newValue = aOldValue;
}
return newValue;
}
+ typedef nsClassHashtable<nsStringHashKey, nsCounterList> NameTable;
+
private:
- // for |AddCounterResetsAndIncrements| only
- bool AddResetOrIncrement(nsIFrame* aFrame, int32_t aIndex,
+ // for |AddCounterResetsAndIncrements| only
+ bool AddResetOrIncrement(nsIFrame *aRoot, nsIFrame* aFrame,
+ int32_t aIndex,
const nsStyleCounterData& aCounterData,
nsCounterNode::Type aType);
- nsClassHashtable<nsStringHashKey, nsCounterList> mNames;
+ NameTable* GetNames(nsIFrame* aRoot, bool aShouldCreate = true) {
+ NameTable* names = mContainStyleRoots.Get(aRoot);
+ if (!names && aShouldCreate) {
+ names = new NameTable();
+ mContainStyleRoots.Put(aRoot, names);
+ }
+ return names;
+ }
+
+ nsClassHashtable<nsPtrHashKey<const nsIFrame>, NameTable> mContainStyleRoots;
};
#endif /* nsCounterManager_h_ */
--- a/layout/style/ComputedStyle.h
+++ b/layout/style/ComputedStyle.h
@@ -65,16 +65,17 @@ class ComputedStyle;
enum class ComputedStyleBit : uint8_t
{
HasTextDecorationLines = 1 << 0,
HasPseudoElementData = 1 << 1,
SuppressLineBreak = 1 << 2,
IsTextCombined = 1 << 3,
RelevantLinkVisited = 1 << 4,
+ HasContainStyle = 1 << 5
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ComputedStyleBit)
class ComputedStyle
{
using Bit = ComputedStyleBit;
public:
@@ -157,16 +158,22 @@ public:
// decoration lines?
// Differs from nsStyleTextReset::HasTextDecorationLines, which tests
// only the data for a single context.
bool HasTextDecorationLines() const
{
return bool(mBits & Bit::HasTextDecorationLines);
}
+ // Does this style context or any of its ancestors have 'contain: style' set?
+ bool HasContainStyle() const
+ {
+ return bool(mBits & Bit::HasContainStyle);
+ }
+
// Whether any line break inside should be suppressed? If this returns
// true, the line should not be broken inside, which means inlines act
// as if nowrap is set, <br> is suppressed, and blocks are inlinized.
// This bit is propogated to all children of line partitipants. It is
// currently used by ruby to make its content frames unbreakable.
// NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak()
// instead of this method.
bool ShouldSuppressLineBreak() const
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2432,16 +2432,20 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
bool IsScrollableOverflow() const {
// mOverflowX and mOverflowY always match when one of them is
// NS_STYLE_OVERFLOW_VISIBLE or NS_STYLE_OVERFLOW_CLIP.
return mOverflowX != NS_STYLE_OVERFLOW_VISIBLE &&
mOverflowX != NS_STYLE_OVERFLOW_CLIP;
}
+ bool IsContainStyle() const {
+ return (NS_STYLE_CONTAIN_STYLE & mContain);
+ }
+
bool IsContainPaint() const {
return (NS_STYLE_CONTAIN_PAINT & mContain) &&
!IsInternalRubyDisplayType() &&
!IsInternalTableStyleExceptCell();
}
/* Returns whether the element has the -moz-transform property
* or a related property. */
--- a/servo/components/style/properties/computed_value_flags.rs
+++ b/servo/components/style/properties/computed_value_flags.rs
@@ -36,16 +36,19 @@ bitflags! {
/// A flag used to mark styles under a relevant link that is also
/// visited.
const IS_RELEVANT_LINK_VISITED = 1 << 3;
/// A flag used to mark styles which are a pseudo-element or under one.
const IS_IN_PSEUDO_ELEMENT_SUBTREE = 1 << 4;
+ /// A flag used to mark styles which have contain:style or under one.
+ const HAS_CONTAIN_STYLE = 1 << 5;
+
/// Whether this style inherits the `display` property.
///
/// This is important because it may affect our optimizations to avoid
/// computing the style of pseudo-elements, given whether the
/// pseudo-element is generated depends on the `display` value.
const INHERITS_DISPLAY = 1 << 6;
/// Whether this style inherits the `content` property.
--- a/servo/components/style/style_adjuster.rs
+++ b/servo/components/style/style_adjuster.rs
@@ -187,16 +187,17 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
.mutate_box()
.set_adjusted_display(blockified_display, is_item_or_root);
}
}
/// Compute a few common flags for both text and element's style.
pub fn set_bits(&mut self) {
let display = self.style.get_box().clone_display();
+ use properties::longhands::contain::SpecifiedValue;
if !display.is_contents() &&
!self.style
.get_text()
.clone_text_decoration_line()
.is_empty()
{
self.style
@@ -205,16 +206,26 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
if self.style.is_pseudo_element() {
self.style
.flags
.insert(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE);
}
+ if self.style
+ .get_box()
+ .clone_contain()
+ .contains(SpecifiedValue::PAINT)
+ {
+ self.style
+ .flags
+ .insert(ComputedValueFlags::HAS_CONTAIN_STYLE);
+ }
+
#[cfg(feature = "servo")]
{
if self.style.get_parent_column().is_multicol() {
self.style
.flags
.insert(ComputedValueFlags::CAN_BE_FRAGMENTED);
}
}
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3117,16 +3117,19 @@ pub extern "C" fn Servo_ComputedValues_G
result |= structs::ComputedStyleBit_SuppressLineBreak;
}
if flags.contains(ComputedValueFlags::IS_TEXT_COMBINED) {
result |= structs::ComputedStyleBit_IsTextCombined;
}
if flags.contains(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE) {
result |= structs::ComputedStyleBit_HasPseudoElementData;
}
+ if flags.contains(ComputedValueFlags::HAS_CONTAIN_STYLE) {
+ result |= structs::ComputedStyleBit_HasContainStyle;
+ }
result
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
values: ComputedStyleBorrowed,
) -> bool {
let b = values.get_box();