123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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/ServoStyleSet.h"
- #include "ServoBindings.h"
- #include "mozilla/ServoRestyleManager.h"
- #include "mozilla/dom/ChildIterator.h"
- #include "nsCSSAnonBoxes.h"
- #include "nsCSSPseudoElements.h"
- #include "nsIDocumentInlines.h"
- #include "nsPrintfCString.h"
- #include "nsStyleContext.h"
- #include "nsStyleSet.h"
- using namespace mozilla;
- using namespace mozilla::dom;
- ServoStyleSet::ServoStyleSet()
- : mPresContext(nullptr)
- , mRawSet(Servo_StyleSet_Init())
- , mBatching(0)
- {
- }
- void
- ServoStyleSet::Init(nsPresContext* aPresContext)
- {
- mPresContext = aPresContext;
- }
- void
- ServoStyleSet::BeginShutdown()
- {
- }
- void
- ServoStyleSet::Shutdown()
- {
- mRawSet = nullptr;
- }
- bool
- ServoStyleSet::GetAuthorStyleDisabled() const
- {
- return false;
- }
- nsresult
- ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
- {
- MOZ_CRASH("stylo: not implemented");
- }
- void
- ServoStyleSet::BeginUpdate()
- {
- ++mBatching;
- }
- nsresult
- ServoStyleSet::EndUpdate()
- {
- MOZ_ASSERT(mBatching > 0);
- if (--mBatching > 0) {
- return NS_OK;
- }
- // ... do something ...
- return NS_OK;
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ResolveStyleFor(Element* aElement,
- nsStyleContext* aParentContext)
- {
- return GetContext(aElement, aParentContext, nullptr,
- CSSPseudoElementType::NotPseudo);
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::GetContext(nsIContent* aContent,
- nsStyleContext* aParentContext,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType)
- {
- RefPtr<ServoComputedValues> computedValues =
- Servo_ComputedValues_Get(aContent).Consume();
- MOZ_ASSERT(computedValues);
- return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType);
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
- nsStyleContext* aParentContext,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType)
- {
- // XXXbholley: nsStyleSet does visited handling here.
- // XXXbholley: Figure out the correct thing to pass here. Does this fixup
- // duplicate something that servo already does?
- bool skipFixup = false;
- return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
- aPseudoType, Move(aComputedValues), skipFixup);
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ResolveStyleFor(Element* aElement,
- nsStyleContext* aParentContext,
- TreeMatchContext& aTreeMatchContext)
- {
- // aTreeMatchContext is used to speed up selector matching,
- // but if the element already has a ServoComputedValues computed in
- // advance, then we shouldn't need to use it.
- return ResolveStyleFor(aElement, aParentContext);
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
- nsStyleContext* aParentContext)
- {
- MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
- MOZ_ASSERT(aTextNode->GetParent());
- MOZ_ASSERT(aParentContext);
- // Gecko expects text node style contexts to be like elements that match no
- // rules: inherit the inherit structs, reset the reset structs. This is cheap
- // enough to do on the main thread, which means that the parallel style system
- // can avoid worrying about text nodes.
- const ServoComputedValues* parentComputedValues =
- aParentContext->StyleSource().AsServoComputedValues();
- RefPtr<ServoComputedValues> computedValues =
- Servo_ComputedValues_Inherit(parentComputedValues).Consume();
- return GetContext(computedValues.forget(), aParentContext,
- nsCSSAnonBoxes::mozText, CSSPseudoElementType::AnonBox);
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ResolveStyleForOtherNonElement(nsStyleContext* aParentContext)
- {
- // The parent context can be null if the non-element share a style context
- // with the root of an anonymous subtree.
- const ServoComputedValues* parent =
- aParentContext ? aParentContext->StyleSource().AsServoComputedValues() : nullptr;
- RefPtr<ServoComputedValues> computedValues =
- Servo_ComputedValues_Inherit(parent).Consume();
- MOZ_ASSERT(computedValues);
- return GetContext(computedValues.forget(), aParentContext,
- nsCSSAnonBoxes::mozOtherNonElement,
- CSSPseudoElementType::AnonBox);
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
- CSSPseudoElementType aType,
- nsStyleContext* aParentContext,
- Element* aPseudoElement)
- {
- if (aPseudoElement) {
- NS_ERROR("stylo: We don't support CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE yet");
- }
- MOZ_ASSERT(aParentContext);
- MOZ_ASSERT(aType < CSSPseudoElementType::Count);
- nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
- RefPtr<ServoComputedValues> computedValues =
- Servo_ComputedValues_GetForPseudoElement(
- aParentContext->StyleSource().AsServoComputedValues(),
- aParentElement, pseudoTag, mRawSet.get(), /* is_probe = */ false).Consume();
- MOZ_ASSERT(computedValues);
- return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType);
- }
- // aFlags is an nsStyleSet flags bitfield
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
- nsStyleContext* aParentContext,
- uint32_t aFlags)
- {
- MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag));
- MOZ_ASSERT(aFlags == 0 ||
- aFlags == nsStyleSet::eSkipParentDisplayBasedStyleFixup);
- bool skipFixup = aFlags & nsStyleSet::eSkipParentDisplayBasedStyleFixup;
- const ServoComputedValues* parentStyle =
- aParentContext ? aParentContext->StyleSource().AsServoComputedValues()
- : nullptr;
- RefPtr<ServoComputedValues> computedValues =
- Servo_ComputedValues_GetForAnonymousBox(parentStyle, aPseudoTag,
- mRawSet.get()).Consume();
- #ifdef DEBUG
- if (!computedValues) {
- nsString pseudo;
- aPseudoTag->ToString(pseudo);
- NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
- NS_ConvertUTF16toUTF8(pseudo).get()).get());
- MOZ_CRASH();
- }
- #endif
- return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
- CSSPseudoElementType::AnonBox,
- computedValues.forget(), skipFixup);
- }
- // manage the set of style sheets in the style set
- nsresult
- ServoStyleSet::AppendStyleSheet(SheetType aType,
- ServoStyleSheet* aSheet)
- {
- MOZ_ASSERT(aSheet);
- MOZ_ASSERT(aSheet->IsApplicable());
- MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
- mSheets[aType].RemoveElement(aSheet);
- mSheets[aType].AppendElement(aSheet);
- // Maintain a mirrored list of sheets on the servo side.
- Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet->RawSheet());
- return NS_OK;
- }
- nsresult
- ServoStyleSet::PrependStyleSheet(SheetType aType,
- ServoStyleSheet* aSheet)
- {
- MOZ_ASSERT(aSheet);
- MOZ_ASSERT(aSheet->IsApplicable());
- MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
- mSheets[aType].RemoveElement(aSheet);
- mSheets[aType].InsertElementAt(0, aSheet);
- // Maintain a mirrored list of sheets on the servo side.
- Servo_StyleSet_PrependStyleSheet(mRawSet.get(), aSheet->RawSheet());
- return NS_OK;
- }
- nsresult
- ServoStyleSet::RemoveStyleSheet(SheetType aType,
- ServoStyleSheet* aSheet)
- {
- MOZ_ASSERT(aSheet);
- MOZ_ASSERT(aSheet->IsApplicable());
- MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
- mSheets[aType].RemoveElement(aSheet);
- // Maintain a mirrored list of sheets on the servo side.
- Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet->RawSheet());
- return NS_OK;
- }
- nsresult
- ServoStyleSet::ReplaceSheets(SheetType aType,
- const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets)
- {
- // Gecko uses a two-dimensional array keyed by sheet type, whereas Servo
- // stores a flattened list. This makes ReplaceSheets a pretty clunky thing
- // to express. If the need ever arises, we can easily make this more efficent,
- // probably by aligning the representations better between engines.
- for (ServoStyleSheet* sheet : mSheets[aType]) {
- Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet->RawSheet());
- }
- mSheets[aType].Clear();
- mSheets[aType].AppendElements(aNewSheets);
- for (ServoStyleSheet* sheet : mSheets[aType]) {
- Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet->RawSheet());
- }
- return NS_OK;
- }
- nsresult
- ServoStyleSet::InsertStyleSheetBefore(SheetType aType,
- ServoStyleSheet* aNewSheet,
- ServoStyleSheet* aReferenceSheet)
- {
- MOZ_ASSERT(aNewSheet);
- MOZ_ASSERT(aReferenceSheet);
- MOZ_ASSERT(aNewSheet->IsApplicable());
- mSheets[aType].RemoveElement(aNewSheet);
- size_t idx = mSheets[aType].IndexOf(aReferenceSheet);
- if (idx == mSheets[aType].NoIndex) {
- return NS_ERROR_INVALID_ARG;
- }
- mSheets[aType].InsertElementAt(idx, aNewSheet);
- // Maintain a mirrored list of sheets on the servo side.
- Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aNewSheet->RawSheet(),
- aReferenceSheet->RawSheet());
- return NS_OK;
- }
- int32_t
- ServoStyleSet::SheetCount(SheetType aType) const
- {
- MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
- return mSheets[aType].Length();
- }
- ServoStyleSheet*
- ServoStyleSet::StyleSheetAt(SheetType aType,
- int32_t aIndex) const
- {
- MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
- return mSheets[aType][aIndex];
- }
- nsresult
- ServoStyleSet::RemoveDocStyleSheet(ServoStyleSheet* aSheet)
- {
- return RemoveStyleSheet(SheetType::Doc, aSheet);
- }
- nsresult
- ServoStyleSet::AddDocStyleSheet(ServoStyleSheet* aSheet,
- nsIDocument* aDocument)
- {
- RefPtr<StyleSheet> strong(aSheet);
- mSheets[SheetType::Doc].RemoveElement(aSheet);
- size_t index =
- aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], *aSheet);
- mSheets[SheetType::Doc].InsertElementAt(index, aSheet);
- // Maintain a mirrored list of sheets on the servo side.
- ServoStyleSheet* followingSheet =
- mSheets[SheetType::Doc].SafeElementAt(index + 1);
- if (followingSheet) {
- Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet->RawSheet(),
- followingSheet->RawSheet());
- } else {
- Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet->RawSheet());
- }
- return NS_OK;
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ProbePseudoElementStyle(Element* aParentElement,
- CSSPseudoElementType aType,
- nsStyleContext* aParentContext)
- {
- MOZ_ASSERT(aParentContext);
- MOZ_ASSERT(aType < CSSPseudoElementType::Count);
- nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
- RefPtr<ServoComputedValues> computedValues =
- Servo_ComputedValues_GetForPseudoElement(
- aParentContext->StyleSource().AsServoComputedValues(),
- aParentElement, pseudoTag, mRawSet.get(), /* is_probe = */ true).Consume();
- if (!computedValues) {
- return nullptr;
- }
- // For :before and :after pseudo-elements, having display: none or no
- // 'content' property is equivalent to not having the pseudo-element
- // at all.
- if (computedValues &&
- (pseudoTag == nsCSSPseudoElements::before ||
- pseudoTag == nsCSSPseudoElements::after)) {
- const nsStyleDisplay *display = Servo_GetStyleDisplay(computedValues);
- const nsStyleContent *content = Servo_GetStyleContent(computedValues);
- // XXXldb What is contentCount for |content: ""|?
- if (display->mDisplay == StyleDisplay::None ||
- content->ContentCount() == 0) {
- return nullptr;
- }
- }
- return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType);
- }
- already_AddRefed<nsStyleContext>
- ServoStyleSet::ProbePseudoElementStyle(Element* aParentElement,
- CSSPseudoElementType aType,
- nsStyleContext* aParentContext,
- TreeMatchContext& aTreeMatchContext,
- Element* aPseudoElement)
- {
- if (aPseudoElement) {
- NS_ERROR("stylo: We don't support CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE yet");
- }
- return ProbePseudoElementStyle(aParentElement, aType, aParentContext);
- }
- nsRestyleHint
- ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
- EventStates aStateMask)
- {
- NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
- return nsRestyleHint(0);
- }
- nsRestyleHint
- ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
- CSSPseudoElementType aPseudoType,
- dom::Element* aPseudoElement,
- EventStates aStateMask)
- {
- NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
- return nsRestyleHint(0);
- }
- nsRestyleHint
- ServoStyleSet::ComputeRestyleHint(dom::Element* aElement,
- ServoElementSnapshot* aSnapshot)
- {
- return Servo_ComputeRestyleHint(aElement, aSnapshot, mRawSet.get());
- }
- static void
- ClearDirtyBits(nsIContent* aContent)
- {
- bool traverseDescendants = aContent->HasDirtyDescendantsForServo();
- aContent->UnsetIsDirtyAndHasDirtyDescendantsForServo();
- if (!traverseDescendants) {
- return;
- }
- StyleChildrenIterator it(aContent);
- for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
- ClearDirtyBits(n);
- }
- }
- void
- ServoStyleSet::StyleDocument(bool aLeaveDirtyBits)
- {
- // Grab the root.
- nsIDocument* doc = mPresContext->Document();
- nsIContent* root = doc->GetRootElement();
- MOZ_ASSERT(root);
- // Restyle the document, clearing the dirty bits if requested.
- Servo_RestyleSubtree(root, mRawSet.get());
- if (!aLeaveDirtyBits) {
- ClearDirtyBits(root);
- doc->UnsetHasDirtyDescendantsForServo();
- }
- }
- void
- ServoStyleSet::StyleNewSubtree(nsIContent* aContent)
- {
- MOZ_ASSERT(aContent->IsDirtyForServo());
- if (aContent->IsElement() || aContent->IsNodeOfType(nsINode::eTEXT)) {
- Servo_RestyleSubtree(aContent, mRawSet.get());
- }
- ClearDirtyBits(aContent);
- }
- void
- ServoStyleSet::StyleNewChildren(nsIContent* aParent)
- {
- MOZ_ASSERT(aParent->HasDirtyDescendantsForServo());
- Servo_RestyleSubtree(aParent, mRawSet.get());
- ClearDirtyBits(aParent);
- }
|