Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/painting/MaskLayerImageCache.h
Line
Count
Source (jump to first uncovered line)
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
#ifndef MASKLAYERIMAGECACHE_H_
8
#define MASKLAYERIMAGECACHE_H_
9
10
#include "DisplayItemClip.h"
11
#include "nsAutoPtr.h"
12
#include "nsPresContext.h"
13
#include "mozilla/gfx/Matrix.h"
14
15
namespace mozilla {
16
17
namespace layers {
18
class ImageContainer;
19
class KnowsCompositor;
20
} // namespace layers
21
22
/**
23
 * Keeps a record of image containers for mask layers, containers are mapped
24
 * from the rounded rects used to create them.
25
 * The cache stores MaskLayerImageEntries indexed by MaskLayerImageKeys.
26
 * Each MaskLayerImageEntry owns a heap-allocated MaskLayerImageKey
27
 * (heap-allocated so that a mask layer's userdata can keep a pointer to the
28
 * key for its image, in spite of the hashtable moving its entries around).
29
 * The key consists of the rounded rects used to create the mask,
30
 * an nsRefPtr to the ImageContainer containing the image, and a count
31
 * of the number of layers currently using this ImageContainer.
32
 * When the key's layer count is zero, the cache
33
 * may remove the entry, which deletes the key object.
34
 */
35
class MaskLayerImageCache
36
{
37
  typedef mozilla::layers::ImageContainer ImageContainer;
38
  typedef mozilla::layers::KnowsCompositor KnowsCompositor;
39
40
public:
41
  MaskLayerImageCache();
42
  ~MaskLayerImageCache();
43
44
  /**
45
   * Representation of a rounded rectangle in device pixel coordinates, in
46
   * contrast to DisplayItemClip::RoundedRect, which uses app units.
47
   * In particular, our internal representation uses a gfxRect, rather than
48
   * an nsRect, so this class is easier to use with transforms.
49
   */
50
  struct PixelRoundedRect
51
  {
52
    PixelRoundedRect() = delete;
53
54
    PixelRoundedRect(const DisplayItemClip::RoundedRect& aRRect,
55
                     nsPresContext* aPresContext)
56
      : mRect(aPresContext->AppUnitsToGfxUnits(aRRect.mRect.x),
57
              aPresContext->AppUnitsToGfxUnits(aRRect.mRect.y),
58
              aPresContext->AppUnitsToGfxUnits(aRRect.mRect.width),
59
              aPresContext->AppUnitsToGfxUnits(aRRect.mRect.height))
60
0
    {
61
0
      MOZ_COUNT_CTOR(PixelRoundedRect);
62
0
      NS_FOR_CSS_HALF_CORNERS(corner)
63
0
      {
64
0
        mRadii[corner] =
65
0
          aPresContext->AppUnitsToGfxUnits(aRRect.mRadii[corner]);
66
0
      }
67
0
    }
68
69
    PixelRoundedRect(const PixelRoundedRect& aPRR)
70
      : mRect(aPRR.mRect)
71
0
    {
72
0
      MOZ_COUNT_CTOR(PixelRoundedRect);
73
0
      NS_FOR_CSS_HALF_CORNERS(corner) { mRadii[corner] = aPRR.mRadii[corner]; }
74
0
    }
75
76
0
    ~PixelRoundedRect() { MOZ_COUNT_DTOR(PixelRoundedRect); }
77
78
    // Applies the scale and translate components of aTransform.
79
    // It is an error to pass a matrix which does more than just scale
80
    // and translate.
81
    void ScaleAndTranslate(const gfx::Matrix& aTransform)
82
0
    {
83
0
      NS_ASSERTION(aTransform._12 == 0 && aTransform._21 == 0,
84
0
                   "Transform has a component other than scale and translate");
85
0
86
0
      mRect = aTransform.TransformBounds(mRect);
87
0
88
0
      for (size_t i = 0; i < ArrayLength(mRadii); i += 2) {
89
0
        mRadii[i] *= aTransform._11;
90
0
        mRadii[i + 1] *= aTransform._22;
91
0
      }
92
0
    }
93
94
    bool operator==(const PixelRoundedRect& aOther) const
95
0
    {
96
0
      if (!mRect.IsEqualInterior(aOther.mRect)) {
97
0
        return false;
98
0
      }
99
0
100
0
      NS_FOR_CSS_HALF_CORNERS(corner)
101
0
      {
102
0
        if (mRadii[corner] != aOther.mRadii[corner]) {
103
0
          return false;
104
0
        }
105
0
      }
106
0
      return true;
107
0
    }
108
    bool operator!=(const PixelRoundedRect& aOther) const
109
0
    {
110
0
      return !(*this == aOther);
111
0
    }
112
113
    // Create a hash for this object.
114
    PLDHashNumber Hash() const
115
0
    {
116
0
      PLDHashNumber hash = HashBytes(&mRect.x, 4 * sizeof(gfxFloat));
117
0
      hash = AddToHash(hash, HashBytes(mRadii, 8 * sizeof(gfxFloat)));
118
0
119
0
      return hash;
120
0
    }
121
122
    gfx::Rect mRect;
123
    // Indices into mRadii are the enum HalfCorner constants in gfx/2d/Types.h
124
    gfxFloat mRadii[8];
125
  };
126
127
  struct MaskLayerImageKeyRef;
128
129
  /**
130
   * A key to identify cached image containers.
131
   * The const-ness of this class is with respect to its use as a key into a
132
   * hashtable, so anything not used to create the hash is mutable.
133
   * mLayerCount counts the number of mask layers which have a reference to
134
   * MaskLayerImageEntry::mContainer; it is maintained by MaskLayerUserData,
135
   * which keeps a reference to the key. There will usually be mLayerCount + 1
136
   * pointers to a key object (the +1 being from the hashtable entry), but this
137
   * invariant may be temporarily broken.
138
   */
139
  struct MaskLayerImageKey
140
  {
141
    friend struct MaskLayerImageKeyRef;
142
143
    MaskLayerImageKey();
144
    MaskLayerImageKey(const MaskLayerImageKey& aKey);
145
146
    ~MaskLayerImageKey();
147
148
0
    bool HasZeroLayerCount() const { return mLayerCount == 0; }
149
150
    PLDHashNumber Hash() const
151
0
    {
152
0
      PLDHashNumber hash = 0;
153
0
154
0
      for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
155
0
        hash = AddToHash(hash, mRoundedClipRects[i].Hash());
156
0
      }
157
0
      hash = AddToHash(hash, mKnowsCompositor.get());
158
0
159
0
      return hash;
160
0
    }
161
162
    bool operator==(const MaskLayerImageKey& aOther) const
163
0
    {
164
0
      return mKnowsCompositor == aOther.mKnowsCompositor &&
165
0
             mRoundedClipRects == aOther.mRoundedClipRects;
166
0
    }
167
168
    nsTArray<PixelRoundedRect> mRoundedClipRects;
169
    RefPtr<KnowsCompositor> mKnowsCompositor;
170
171
  private:
172
0
    void IncLayerCount() const { ++mLayerCount; }
173
    void DecLayerCount() const
174
0
    {
175
0
      NS_ASSERTION(mLayerCount > 0, "Inconsistent layer count");
176
0
      --mLayerCount;
177
0
    }
178
    mutable uint32_t mLayerCount;
179
  };
180
181
  /**
182
   * This struct maintains a reference to a MaskLayerImageKey, via a variant on
183
   * refcounting. When a key is passed in via Reset(), we increment the
184
   * passed-in key's mLayerCount, and we decrement its mLayerCount when we're
185
   * destructed (or when the key is replaced via a second Reset() call).
186
   *
187
   * However, unlike standard refcounting smart-pointers, this object does
188
   * *not* delete the tracked MaskLayerImageKey -- instead, deletion happens
189
   * in MaskLayerImageCache::Sweep(), for any keys whose mLayerCount is 0.
190
   */
191
  struct MaskLayerImageKeyRef
192
  {
193
    ~MaskLayerImageKeyRef()
194
0
    {
195
0
      if (mRawPtr) {
196
0
        mRawPtr->DecLayerCount();
197
0
      }
198
0
    }
199
200
    MaskLayerImageKeyRef()
201
      : mRawPtr(nullptr)
202
0
    {
203
0
    }
204
    MaskLayerImageKeyRef(const MaskLayerImageKeyRef&) = delete;
205
    void operator=(const MaskLayerImageKeyRef&) = delete;
206
207
    void Reset(const MaskLayerImageKey* aPtr)
208
0
    {
209
0
      MOZ_ASSERT(
210
0
        aPtr, "Cannot initialize a MaskLayerImageKeyRef with a null pointer");
211
0
      aPtr->IncLayerCount();
212
0
      if (mRawPtr) {
213
0
        mRawPtr->DecLayerCount();
214
0
      }
215
0
      mRawPtr = aPtr;
216
0
    }
217
218
  private:
219
    const MaskLayerImageKey* mRawPtr;
220
  };
221
222
  // Find an image container for aKey, returns nullptr if there is no suitable
223
  // cached image. If there is an image, then aKey is set to point at the stored
224
  // key for the image.
225
  ImageContainer* FindImageFor(const MaskLayerImageKey** aKey);
226
227
  // Add an image container with a key to the cache
228
  // The image container used will be set as the container in aKey and aKey
229
  // itself will be linked from this cache
230
  void PutImage(const MaskLayerImageKey* aKey, ImageContainer* aContainer);
231
232
  // Sweep the cache for old image containers that can be deleted
233
  void Sweep();
234
235
protected:
236
  class MaskLayerImageEntry : public PLDHashEntryHdr
237
  {
238
  public:
239
    typedef const MaskLayerImageKey& KeyType;
240
    typedef const MaskLayerImageKey* KeyTypePointer;
241
242
    explicit MaskLayerImageEntry(KeyTypePointer aKey)
243
      : mKey(aKey)
244
0
    {
245
0
      MOZ_COUNT_CTOR(MaskLayerImageEntry);
246
0
    }
247
    MaskLayerImageEntry(const MaskLayerImageEntry& aOther)
248
      : mKey(aOther.mKey.get())
249
0
    {
250
0
      NS_ERROR("ALLOW_MEMMOVE == true, should never be called");
251
0
    }
252
0
    ~MaskLayerImageEntry() { MOZ_COUNT_DTOR(MaskLayerImageEntry); }
253
254
    // KeyEquals(): does this entry match this key?
255
0
    bool KeyEquals(KeyTypePointer aKey) const { return *mKey == *aKey; }
256
257
    // KeyToPointer(): Convert KeyType to KeyTypePointer
258
0
    static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
259
260
    // HashKey(): calculate the hash number
261
0
    static PLDHashNumber HashKey(KeyTypePointer aKey) { return aKey->Hash(); }
262
263
    // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
264
    // to use the copy constructor?
265
    enum
266
    {
267
      ALLOW_MEMMOVE = true
268
    };
269
270
    bool operator==(const MaskLayerImageEntry& aOther) const
271
0
    {
272
0
      return KeyEquals(aOther.mKey);
273
0
    }
274
275
    nsAutoPtr<const MaskLayerImageKey> mKey;
276
    RefPtr<ImageContainer> mContainer;
277
  };
278
279
  nsTHashtable<MaskLayerImageEntry> mMaskImageContainers;
280
};
281
282
} // namespace mozilla
283
284
#endif