summaryrefslogtreecommitdiff
path: root/layout/style/RuleProcessorCache.h
blob: 7eb808fc943c48e32a670d2d5c254fe1814e2578 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* -*- 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/. */

/*
 * cache of re-usable nsCSSRuleProcessors for given sets of style sheets
 */

#ifndef mozilla_RuleProcessorCache_h
#define mozilla_RuleProcessorCache_h

#include "mozilla/MemoryReporting.h"
#include "mozilla/StaticPtr.h"
#include "nsCSSRuleProcessor.h"
#include "nsExpirationTracker.h"
#include "nsIMediaList.h"
#include "nsIMemoryReporter.h"
#include "nsTArray.h"

class nsCSSRuleProcessor;
namespace mozilla {
class CSSStyleSheet;
namespace css {
class DocumentRule;
} // namespace css
} // namespace mozilla

namespace mozilla {

/**
 * The RuleProcessorCache is a singleton object that caches
 * nsCSSRuleProcessors keyed off a list of style sheets and the result of
 * evaluating all @-moz-documents in the style sheets.  nsStyleSet gets and
 * puts nsCSSRuleProcessors from/to the RuleProcessorCache.
 *
 * State bits on CSSStyleSheet and nsCSSRuleProcessor track whether they are in
 * the RuleProcessorCache.  This lets us remove them from the RuleProcessorCache
 * when they're going away.
 */
class RuleProcessorCache final : public nsIMemoryReporter
{
  NS_DECL_ISUPPORTS
  NS_DECL_NSIMEMORYREPORTER

public:
  static nsCSSRuleProcessor* GetRuleProcessor(
      const nsTArray<CSSStyleSheet*>& aSheets,
      nsPresContext* aPresContext);
  static void PutRuleProcessor(
      const nsTArray<CSSStyleSheet*>& aSheets,
      nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
      const nsDocumentRuleResultCacheKey& aCacheKey,
      nsCSSRuleProcessor* aRuleProcessor);
  static void StartTracking(nsCSSRuleProcessor* aRuleProcessor);
  static void StopTracking(nsCSSRuleProcessor* aRuleProcessor);

#ifdef DEBUG
  static bool HasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
#endif
  static void RemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
  static void RemoveSheet(CSSStyleSheet* aSheet);

  static void Shutdown() { gShutdown = true; gRuleProcessorCache = nullptr; }

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);

private:
  class ExpirationTracker : public nsExpirationTracker<nsCSSRuleProcessor,3>
  {
  public:
    explicit ExpirationTracker(RuleProcessorCache* aCache)
      : nsExpirationTracker<nsCSSRuleProcessor,3>(
          10000, "RuleProcessorCache::ExpirationTracker")
      , mCache(aCache) {}

    void RemoveObjectIfTracked(nsCSSRuleProcessor* aRuleProcessor);

    virtual void NotifyExpired(nsCSSRuleProcessor* aRuleProcessor) override {
      mCache->RemoveRuleProcessor(aRuleProcessor);
    }

  private:
    RuleProcessorCache* mCache;
  };

  RuleProcessorCache() : mExpirationTracker(this) {}
  ~RuleProcessorCache();

  void InitMemoryReporter();

  static bool EnsureGlobal();
  static StaticRefPtr<RuleProcessorCache> gRuleProcessorCache;
  static bool gShutdown;

  void DoRemoveSheet(CSSStyleSheet* aSheet);
  nsCSSRuleProcessor* DoGetRuleProcessor(
      const nsTArray<CSSStyleSheet*>& aSheets,
      nsPresContext* aPresContext);
  void DoPutRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
                          nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
                          const nsDocumentRuleResultCacheKey& aCacheKey,
                          nsCSSRuleProcessor* aRuleProcessor);
#ifdef DEBUG
  bool DoHasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
#endif
  void DoRemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
  void DoStartTracking(nsCSSRuleProcessor* aRuleProcessor);
  void DoStopTracking(nsCSSRuleProcessor* aRuleProcessor);

  struct DocumentEntry {
    nsDocumentRuleResultCacheKey mCacheKey;
    RefPtr<nsCSSRuleProcessor> mRuleProcessor;
  };

  struct Entry {
    nsTArray<CSSStyleSheet*>     mSheets;
    nsTArray<css::DocumentRule*> mDocumentRulesInSheets;
    nsTArray<DocumentEntry>      mDocumentEntries;
  };

  // Function object to test whether an Entry object has a given sheet
  // in its mSheets array.  If it does, removes all of its rule processors
  // before returning true.
  struct HasSheet_ThenRemoveRuleProcessors {
    HasSheet_ThenRemoveRuleProcessors(RuleProcessorCache* aCache,
                                      CSSStyleSheet* aSheet)
      : mCache(aCache), mSheet(aSheet) {}
    bool operator()(Entry& aEntry) {
      if (aEntry.mSheets.Contains(mSheet)) {
        for (DocumentEntry& de : aEntry.mDocumentEntries) {
          de.mRuleProcessor->SetInRuleProcessorCache(false);
          mCache->mExpirationTracker.RemoveObjectIfTracked(de.mRuleProcessor);
        }
        return true;
      }
      return false;
    }
    RuleProcessorCache* mCache;
    CSSStyleSheet* mSheet;
  };

  ExpirationTracker mExpirationTracker;
  nsTArray<Entry> mEntries;
};

} // namespace mozilla

#endif // mozilla_RuleProcessorCache_h