nsTreeStyleCache.cpp (3774B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "nsTreeStyleCache.h" 8 9 #include "mozilla/ComputedStyleInlines.h" 10 #include "mozilla/ServoStyleSet.h" 11 #include "mozilla/dom/Element.h" 12 #include "nsPresContextInlines.h" 13 14 using namespace mozilla; 15 16 nsTreeStyleCache::Transition::Transition(DFAState aState, nsAtom* aSymbol) 17 : mState(aState), mInputSymbol(aSymbol) {} 18 19 bool nsTreeStyleCache::Transition::operator==(const Transition& aOther) const { 20 return aOther.mState == mState && aOther.mInputSymbol == mInputSymbol; 21 } 22 23 uint32_t nsTreeStyleCache::Transition::Hash() const { 24 // Make a 32-bit integer that combines the low-order 16 bits of the state and 25 // the input symbol. 26 uint32_t hb = mState << 16; 27 uint32_t lb = (NS_PTR_TO_UINT32(mInputSymbol.get()) << 16) >> 16; 28 return hb + lb; 29 } 30 31 // The ComputedStyle cache impl 32 ComputedStyle* nsTreeStyleCache::GetComputedStyle( 33 nsPresContext* aPresContext, nsIContent* aContent, ComputedStyle* aStyle, 34 nsCSSAnonBoxPseudoStaticAtom* aPseudoElement, const AtomArray& aInputWord) { 35 MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoElement)); 36 37 uint32_t count = aInputWord.Length(); 38 39 // Go ahead and init the transition table. 40 if (!mTransitionTable) { 41 // Automatic miss. Build the table 42 mTransitionTable = MakeUnique<TransitionTable>(); 43 } 44 45 // The first transition is always made off the supplied pseudo-element. 46 Transition transition(0, aPseudoElement); 47 DFAState currState = mTransitionTable->Get(transition); 48 49 if (!currState) { 50 // We had a miss. Make a new state and add it to our hash. 51 currState = mNextState; 52 mNextState++; 53 mTransitionTable->InsertOrUpdate(transition, currState); 54 } 55 56 for (uint32_t i = 0; i < count; i++) { 57 Transition transition(currState, aInputWord[i]); 58 currState = mTransitionTable->Get(transition); 59 60 if (!currState) { 61 // We had a miss. Make a new state and add it to our hash. 62 currState = mNextState; 63 mNextState++; 64 mTransitionTable->InsertOrUpdate(transition, currState); 65 } 66 } 67 68 // We're in a final state. 69 // Look up our ComputedStyle for this state. 70 ComputedStyle* result = nullptr; 71 if (mCache) { 72 result = mCache->GetWeak(currState); 73 } 74 if (!result) { 75 // We missed the cache. Resolve this pseudo-style. 76 RefPtr<ComputedStyle> newResult = 77 aPresContext->StyleSet()->ResolveXULTreePseudoStyle( 78 aContent->AsElement(), aPseudoElement, aStyle, aInputWord); 79 80 // Normally we rely on nsIFrame::Init / RestyleManager to call this, but 81 // these are weird and don't use a frame, yet ::-moz-tree-twisty definitely 82 // pokes at list-style-image. 83 newResult->StartImageLoads(*aPresContext->Document()); 84 85 // Even though xul-tree pseudos are defined in nsCSSAnonBoxList, nothing has 86 // ever treated them as an anon box, and they don't ever get boxes anyway. 87 // 88 // This is really weird, and probably nothing really relies on the result of 89 // these assert, but it's here just to avoid changing them accidentally. 90 MOZ_ASSERT(newResult->GetPseudoType() == PseudoStyleType::XULTree); 91 MOZ_ASSERT(!newResult->IsAnonBox()); 92 MOZ_ASSERT(!newResult->IsPseudoElement()); 93 94 // Put the ComputedStyle in our table, transferring the owning reference to 95 // the table. 96 if (!mCache) { 97 mCache = MakeUnique<ComputedStyleCache>(); 98 } 99 result = newResult.get(); 100 mCache->InsertOrUpdate(currState, std::move(newResult)); 101 } 102 103 return result; 104 }