Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/CounterStyleManager.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
#ifndef mozilla_CounterStyleManager_h_
7
#define mozilla_CounterStyleManager_h_
8
9
#include "nsAtom.h"
10
#include "nsStringFwd.h"
11
#include "nsDataHashtable.h"
12
#include "nsHashKeys.h"
13
14
#include "nsStyleConsts.h"
15
16
#include "mozilla/Attributes.h"
17
18
#include "nsCSSValue.h"
19
20
class nsPresContext;
21
22
namespace mozilla {
23
24
class WritingMode;
25
26
typedef int32_t CounterValue;
27
28
class CounterStyleManager;
29
class AnonymousCounterStyle;
30
31
struct NegativeType;
32
struct PadType;
33
34
class CounterStyle
35
{
36
protected:
37
  explicit constexpr CounterStyle(int32_t aStyle)
38
    : mStyle(aStyle)
39
0
  {
40
0
  }
41
42
private:
43
  CounterStyle(const CounterStyle& aOther) = delete;
44
  void operator=(const CounterStyle& other) = delete;
45
46
public:
47
0
  constexpr int32_t GetStyle() const { return mStyle; }
48
0
  bool IsNone() const { return mStyle == NS_STYLE_LIST_STYLE_NONE; }
49
0
  bool IsCustomStyle() const { return mStyle == NS_STYLE_LIST_STYLE_CUSTOM; }
50
  // A style is dependent if it depends on the counter style manager.
51
  // Custom styles are certainly dependent. In addition, some builtin
52
  // styles are dependent for fallback.
53
  bool IsDependentStyle() const;
54
55
  virtual nsAtom* GetStyleName() const = 0;
56
  virtual void GetPrefix(nsAString& aResult) = 0;
57
  virtual void GetSuffix(nsAString& aResult) = 0;
58
  void GetCounterText(CounterValue aOrdinal,
59
                      WritingMode aWritingMode,
60
                      nsAString& aResult,
61
                      bool& aIsRTL);
62
  virtual void GetSpokenCounterText(CounterValue aOrdinal,
63
                                    WritingMode aWritingMode,
64
                                    nsAString& aResult,
65
                                    bool& aIsBullet);
66
67
  // XXX This method could be removed once ::-moz-list-bullet and
68
  //     ::-moz-list-number are completely merged into ::marker.
69
  virtual bool IsBullet() = 0;
70
71
  virtual void GetNegative(NegativeType& aResult) = 0;
72
  /**
73
   * This method returns whether an ordinal is in the range of this
74
   * counter style. Note that, it is possible that an ordinal in range
75
   * is rejected by the generating algorithm.
76
   */
77
  virtual bool IsOrdinalInRange(CounterValue aOrdinal) = 0;
78
  /**
79
   * This method returns whether an ordinal is in the default range of
80
   * this counter style. This is the effective range when no 'range'
81
   * descriptor is specified.
82
   */
83
  virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) = 0;
84
  virtual void GetPad(PadType& aResult) = 0;
85
  virtual CounterStyle* GetFallback() = 0;
86
  virtual uint8_t GetSpeakAs() = 0;
87
  virtual bool UseNegativeSign() = 0;
88
89
  virtual void CallFallbackStyle(CounterValue aOrdinal,
90
                                 WritingMode aWritingMode,
91
                                 nsAString& aResult,
92
                                 bool& aIsRTL);
93
  virtual bool GetInitialCounterText(CounterValue aOrdinal,
94
                                     WritingMode aWritingMode,
95
                                     nsAString& aResult,
96
                                     bool& aIsRTL) = 0;
97
98
0
  virtual AnonymousCounterStyle* AsAnonymous() { return nullptr; }
99
100
protected:
101
  const int32_t mStyle;
102
};
103
104
class AnonymousCounterStyle final : public CounterStyle
105
{
106
public:
107
  explicit AnonymousCounterStyle(const nsAString& aContent);
108
  AnonymousCounterStyle(uint8_t aSystem, nsTArray<nsString> aSymbols);
109
  explicit AnonymousCounterStyle(const nsCSSValue::Array* aValue);
110
111
  virtual nsAtom* GetStyleName() const override;
112
  virtual void GetPrefix(nsAString& aResult) override;
113
  virtual void GetSuffix(nsAString& aResult) override;
114
  virtual bool IsBullet() override;
115
116
  virtual void GetNegative(NegativeType& aResult) override;
117
  virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
118
  virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
119
  virtual void GetPad(PadType& aResult) override;
120
  virtual CounterStyle* GetFallback() override;
121
  virtual uint8_t GetSpeakAs() override;
122
  virtual bool UseNegativeSign() override;
123
124
  virtual bool GetInitialCounterText(CounterValue aOrdinal,
125
                                     WritingMode aWritingMode,
126
                                     nsAString& aResult,
127
                                     bool& aIsRTL) override;
128
129
0
  virtual AnonymousCounterStyle* AsAnonymous() override { return this; }
130
131
0
  bool IsSingleString() const { return mSingleString; }
132
  uint8_t GetSystem() const { return mSystem; }
133
  const nsTArray<nsString>& GetSymbols() const { return mSymbols; }
134
135
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousCounterStyle)
136
137
private:
138
0
  ~AnonymousCounterStyle() {}
139
140
  bool mSingleString;
141
  uint8_t mSystem;
142
  nsTArray<nsString> mSymbols;
143
};
144
145
// A smart pointer to CounterStyle. It either owns a reference to an
146
// anonymous counter style, or weakly refers to a named counter style
147
// managed by counter style manager.
148
class CounterStylePtr
149
{
150
public:
151
0
  CounterStylePtr() : mRaw(0) {}
152
  CounterStylePtr(const CounterStylePtr& aOther)
153
    : mRaw(aOther.mRaw)
154
0
  {
155
0
    switch (GetType()) {
156
0
      case eCounterStyle:
157
0
        break;
158
0
      case eAnonymousCounterStyle:
159
0
        AsAnonymous()->AddRef();
160
0
        break;
161
0
      case eUnresolvedAtom:
162
0
        AsAtom()->AddRef();
163
0
        break;
164
0
      case eMask:
165
0
        MOZ_ASSERT_UNREACHABLE("Unknown type");
166
0
        break;
167
0
    }
168
0
  }
169
  CounterStylePtr(CounterStylePtr&& aOther)
170
    : mRaw(aOther.mRaw)
171
  {
172
    aOther.mRaw = 0;
173
  }
174
0
  ~CounterStylePtr() { Reset(); }
175
176
  CounterStylePtr& operator=(const CounterStylePtr& aOther)
177
0
  {
178
0
    if (this != &aOther) {
179
0
      Reset();
180
0
      new (this) CounterStylePtr(aOther);
181
0
    }
182
0
    return *this;
183
0
  }
184
  CounterStylePtr& operator=(CounterStylePtr&& aOther)
185
  {
186
    if (this != &aOther) {
187
      Reset();
188
      mRaw = aOther.mRaw;
189
      aOther.mRaw = 0;
190
    }
191
    return *this;
192
  }
193
  CounterStylePtr& operator=(decltype(nullptr))
194
  {
195
    Reset();
196
    return *this;
197
  }
198
  CounterStylePtr& operator=(already_AddRefed<nsAtom> aAtom)
199
0
  {
200
0
    Reset();
201
0
    if (nsAtom* raw = aAtom.take()) {
202
0
      AssertPointerAligned(raw);
203
0
      mRaw = reinterpret_cast<uintptr_t>(raw) | eUnresolvedAtom;
204
0
    }
205
0
    return *this;
206
0
  }
207
  CounterStylePtr& operator=(AnonymousCounterStyle* aCounterStyle)
208
0
  {
209
0
    Reset();
210
0
    if (aCounterStyle) {
211
0
      CounterStyle* raw = do_AddRef(aCounterStyle).take();
212
0
      AssertPointerAligned(raw);
213
0
      mRaw = reinterpret_cast<uintptr_t>(raw) | eAnonymousCounterStyle;
214
0
    }
215
0
    return *this;
216
0
  }
217
  CounterStylePtr& operator=(CounterStyle* aCounterStyle)
218
0
  {
219
0
    Reset();
220
0
    if (aCounterStyle) {
221
0
      MOZ_ASSERT(!aCounterStyle->AsAnonymous());
222
0
      AssertPointerAligned(aCounterStyle);
223
0
      mRaw = reinterpret_cast<uintptr_t>(aCounterStyle) | eCounterStyle;
224
0
    }
225
0
    return *this;
226
0
  }
227
228
0
  operator CounterStyle*() const & { return Get(); }
229
  operator CounterStyle*() const && = delete;
230
0
  CounterStyle* operator->() const { return Get(); }
231
  explicit operator bool() const { return !!mRaw; }
232
  bool operator!() const { return !mRaw; }
233
  bool operator==(const CounterStylePtr& aOther) const
234
0
    { return mRaw == aOther.mRaw; }
235
  bool operator!=(const CounterStylePtr& aOther) const
236
0
    { return mRaw != aOther.mRaw; }
237
238
0
  bool IsResolved() const { return !IsUnresolved(); }
239
  inline void Resolve(CounterStyleManager* aManager);
240
241
  nsAtom* AsAtom() const
242
0
  {
243
0
    MOZ_ASSERT(IsUnresolved());
244
0
    return reinterpret_cast<nsAtom*>(mRaw & ~eMask);
245
0
  }
246
  AnonymousCounterStyle* AsAnonymous() const
247
0
  {
248
0
    MOZ_ASSERT(IsAnonymous());
249
0
    return static_cast<AnonymousCounterStyle*>(
250
0
      reinterpret_cast<CounterStyle*>(mRaw & ~eMask));
251
0
  }
252
253
private:
254
  CounterStyle* Get() const
255
0
  {
256
0
    MOZ_ASSERT(IsResolved());
257
0
    return reinterpret_cast<CounterStyle*>(mRaw & ~eMask);
258
0
  }
259
  template<typename T>
260
  void AssertPointerAligned(T* aPointer)
261
0
  {
262
0
    // This can be checked at compile time via
263
0
    // > static_assert(alignof(CounterStyle) >= 4);
264
0
    // > static_assert(alignof(nsAtom) >= 4);
265
0
    // but MSVC2015 doesn't support using alignof on an abstract class.
266
0
    // Once we move to MSVC2017, we can replace this runtime check with
267
0
    // the compile time check above.
268
0
    MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aPointer) & eMask));
269
0
  }
Unexecuted instantiation: void mozilla::CounterStylePtr::AssertPointerAligned<nsAtom>(nsAtom*)
Unexecuted instantiation: void mozilla::CounterStylePtr::AssertPointerAligned<mozilla::CounterStyle>(mozilla::CounterStyle*)
270
271
  enum Type : uintptr_t {
272
    eCounterStyle = 0,
273
    eAnonymousCounterStyle = 1,
274
    eUnresolvedAtom = 2,
275
    eMask = 3,
276
  };
277
278
0
  Type GetType() const { return static_cast<Type>(mRaw & eMask); }
279
0
  bool IsUnresolved() const { return GetType() == eUnresolvedAtom; }
280
  bool IsAnonymous() const { return GetType() == eAnonymousCounterStyle; }
281
282
  void Reset()
283
0
  {
284
0
    switch (GetType()) {
285
0
      case eCounterStyle:
286
0
        break;
287
0
      case eAnonymousCounterStyle:
288
0
        AsAnonymous()->Release();
289
0
        break;
290
0
      case eUnresolvedAtom:
291
0
        AsAtom()->Release();
292
0
        break;
293
0
      case eMask:
294
0
        MOZ_ASSERT_UNREACHABLE("Unknown type");
295
0
        break;
296
0
    }
297
0
    mRaw = 0;
298
0
  }
299
300
  // mRaw contains the pointer, and its last two bits are used for type
301
  // of the pointer.
302
  // If the type is eUnresolvedAtom, the pointer owns a reference to an
303
  // nsAtom, and it needs to be resolved to a counter style before use.
304
  // If the type is eAnonymousCounterStyle, it owns a reference to an
305
  // anonymous counter style.
306
  // Otherwise it is a weak pointer referring a named counter style
307
  // managed by CounterStyleManager.
308
  uintptr_t mRaw;
309
};
310
311
class CounterStyleManager final
312
{
313
private:
314
  ~CounterStyleManager();
315
public:
316
  explicit CounterStyleManager(nsPresContext* aPresContext);
317
318
  void Disconnect();
319
320
  bool IsInitial() const
321
0
  {
322
0
    // only 'none', 'decimal', and 'disc'
323
0
    return mStyles.Count() == 3;
324
0
  }
325
326
  // Returns the counter style object for the given name from the style
327
  // table if it is already built, and nullptr otherwise.
328
0
  CounterStyle* GetCounterStyle(nsAtom* aName) const {
329
0
    return mStyles.Get(aName);
330
0
  }
331
  // Same as GetCounterStyle but try to build the counter style object
332
  // rather than returning nullptr if that hasn't been built.
333
  CounterStyle* BuildCounterStyle(nsAtom* aName);
334
335
  static CounterStyle* GetBuiltinStyle(int32_t aStyle);
336
  static CounterStyle* GetNoneStyle()
337
0
  {
338
0
    return GetBuiltinStyle(NS_STYLE_LIST_STYLE_NONE);
339
0
  }
340
  static CounterStyle* GetDecimalStyle()
341
0
  {
342
0
    return GetBuiltinStyle(NS_STYLE_LIST_STYLE_DECIMAL);
343
0
  }
344
  static CounterStyle* GetDiscStyle()
345
0
  {
346
0
    return GetBuiltinStyle(NS_STYLE_LIST_STYLE_DISC);
347
0
  }
348
349
  static nsAtom* GetStyleNameFromType(int32_t aStyle);
350
351
  // This method will scan all existing counter styles generated by this
352
  // manager, and remove or mark data dirty accordingly. It returns true
353
  // if any counter style is changed, false elsewise. This method should
354
  // be called when any counter style may be affected.
355
  bool NotifyRuleChanged();
356
  // NotifyRuleChanged will evict no longer needed counter styles into
357
  // mRetiredStyles, and this function destroys all objects listed there.
358
  // It should be called only after no one may ever use those objects.
359
  void CleanRetiredStyles();
360
361
0
  nsPresContext* PresContext() const { return mPresContext; }
362
363
  NS_INLINE_DECL_REFCOUNTING(CounterStyleManager)
364
365
private:
366
  void DestroyCounterStyle(CounterStyle* aCounterStyle);
367
368
  nsPresContext* mPresContext;
369
  nsDataHashtable<nsRefPtrHashKey<nsAtom>, CounterStyle*> mStyles;
370
  nsTArray<CounterStyle*> mRetiredStyles;
371
};
372
373
void
374
CounterStylePtr::Resolve(CounterStyleManager* aManager)
375
0
{
376
0
  if (IsUnresolved()) {
377
0
    *this = aManager->BuildCounterStyle(AsAtom());
378
0
  }
379
0
}
380
381
} // namespace mozilla
382
383
#endif /* !defined(mozilla_CounterStyleManager_h_) */