michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsTreeStyleCache.h" michael@0: #include "nsStyleSet.h" michael@0: #include "mozilla/dom/Element.h" michael@0: michael@0: // The style context cache impl michael@0: nsStyleContext* michael@0: nsTreeStyleCache::GetStyleContext(nsICSSPseudoComparator* aComparator, michael@0: nsPresContext* aPresContext, michael@0: nsIContent* aContent, michael@0: nsStyleContext* aContext, michael@0: nsIAtom* aPseudoElement, michael@0: const AtomArray & aInputWord) michael@0: { michael@0: uint32_t count = aInputWord.Length(); michael@0: nsDFAState startState(0); michael@0: nsDFAState* currState = &startState; michael@0: michael@0: // Go ahead and init the transition table. michael@0: if (!mTransitionTable) { michael@0: // Automatic miss. Build the table michael@0: mTransitionTable = michael@0: new nsObjectHashtable(nullptr, nullptr, DeleteDFAState, nullptr); michael@0: } michael@0: michael@0: // The first transition is always made off the supplied pseudo-element. michael@0: nsTransitionKey key(currState->GetStateID(), aPseudoElement); michael@0: currState = static_cast(mTransitionTable->Get(&key)); michael@0: michael@0: if (!currState) { michael@0: // We had a miss. Make a new state and add it to our hash. michael@0: currState = new nsDFAState(mNextState); michael@0: mNextState++; michael@0: mTransitionTable->Put(&key, currState); michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: nsTransitionKey key(currState->GetStateID(), aInputWord[i]); michael@0: currState = static_cast(mTransitionTable->Get(&key)); michael@0: michael@0: if (!currState) { michael@0: // We had a miss. Make a new state and add it to our hash. michael@0: currState = new nsDFAState(mNextState); michael@0: mNextState++; michael@0: mTransitionTable->Put(&key, currState); michael@0: } michael@0: } michael@0: michael@0: // We're in a final state. michael@0: // Look up our style context for this state. michael@0: nsStyleContext* result = nullptr; michael@0: if (mCache) michael@0: result = static_cast(mCache->Get(currState)); michael@0: if (!result) { michael@0: // We missed the cache. Resolve this pseudo-style. michael@0: result = aPresContext->StyleSet()-> michael@0: ResolveXULTreePseudoStyle(aContent->AsElement(), aPseudoElement, michael@0: aContext, aComparator).take(); michael@0: michael@0: // Put the style context in our table, transferring the owning reference to the table. michael@0: if (!mCache) { michael@0: mCache = new nsObjectHashtable(nullptr, nullptr, ReleaseStyleContext, nullptr); michael@0: } michael@0: mCache->Put(currState, result); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: nsTreeStyleCache::DeleteDFAState(nsHashKey *aKey, michael@0: void *aData, michael@0: void *closure) michael@0: { michael@0: nsDFAState* entry = static_cast(aData); michael@0: delete entry; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsTreeStyleCache::ReleaseStyleContext(nsHashKey *aKey, michael@0: void *aData, michael@0: void *closure) michael@0: { michael@0: nsStyleContext* context = static_cast(aData); michael@0: context->Release(); michael@0: return true; michael@0: }