/* -*- 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 "mozilla/IncrementalClearCOMRuleArray.h" #include <algorithm> // For std::min #include "nsCycleCollector.h" #include "mozilla/DeferredFinalize.h" #include "nsTArray.h" #include "nsCCUncollectableMarker.h" using namespace mozilla; typedef nsCOMArray<css::Rule> RuleArray; typedef nsTArray<RuleArray> RuleArrayArray; // These methods are based on those in DeferredFinalizerImpl. static void* AppendRulesArrayPointer(void* aData, void* aObject) { RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData); RuleArray* oldRules = static_cast<RuleArray*>(aObject); if (!rulesArray) { rulesArray = new RuleArrayArray(); } RuleArray* newRules = rulesArray->AppendElement(); newRules->SwapElements(*oldRules); return rulesArray; } // Remove up to |aSliceBudget| css::Rules from the arrays, starting at // the end of the last array. static bool DeferredFinalizeRulesArray(uint32_t aSliceBudget, void* aData) { MOZ_ASSERT(aSliceBudget > 0, "nonsensical/useless call with aSliceBudget == 0"); RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData); size_t newOuterLen = rulesArray->Length(); while (aSliceBudget > 0 && newOuterLen > 0) { RuleArray& lastArray = rulesArray->ElementAt(newOuterLen - 1); uint32_t innerLen = lastArray.Length(); uint32_t currSlice = std::min(innerLen, aSliceBudget); uint32_t newInnerLen = innerLen - currSlice; lastArray.TruncateLength(newInnerLen); aSliceBudget -= currSlice; if (newInnerLen == 0) { newOuterLen -= 1; } } rulesArray->TruncateLength(newOuterLen); if (newOuterLen == 0) { delete rulesArray; return true; } return false; } void IncrementalClearCOMRuleArray::Clear() { // Destroy the array incrementally if it is long and we // haven't started shutting down. if (Length() > 10 && nsCCUncollectableMarker::sGeneration) { DeferredFinalize(AppendRulesArrayPointer, DeferredFinalizeRulesArray, this); } else { nsCOMArray<css::Rule>::Clear(); } MOZ_ASSERT(Length() == 0); }