Line data Source code
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 "nsIAtom.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 0 : explicit constexpr CounterStyle(int32_t aStyle)
38 0 : : mStyle(aStyle)
39 : {
40 0 : }
41 :
42 : private:
43 : CounterStyle(const CounterStyle& aOther) = delete;
44 : void operator=(const CounterStyle& other) = delete;
45 :
46 : public:
47 0 : 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 void GetStyleName(nsAString& aResult) = 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 3 : virtual AnonymousCounterStyle* AsAnonymous() { return nullptr; }
99 :
100 : protected:
101 : 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 void GetStyleName(nsAString& aResult) 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 0 : uint8_t GetSystem() const { return mSystem; }
133 0 : const nsTArray<nsString>& GetSymbols() const { return mSymbols; }
134 :
135 0 : 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 3 : CounterStylePtr() : mRaw(0) {}
152 130 : CounterStylePtr(const CounterStylePtr& aOther)
153 130 : : mRaw(aOther.mRaw)
154 : {
155 130 : switch (GetType()) {
156 : case eCounterStyle:
157 130 : break;
158 : case eAnonymousCounterStyle:
159 0 : AsAnonymous()->AddRef();
160 0 : break;
161 : case eUnresolvedAtom:
162 0 : AsAtom()->AddRef();
163 0 : break;
164 : case eMask:
165 0 : MOZ_ASSERT_UNREACHABLE("Unknown type");
166 : break;
167 : }
168 130 : }
169 : CounterStylePtr(CounterStylePtr&& aOther)
170 : : mRaw(aOther.mRaw)
171 : {
172 : aOther.mRaw = 0;
173 : }
174 105 : ~CounterStylePtr() { Reset(); }
175 :
176 0 : CounterStylePtr& operator=(const CounterStylePtr& aOther)
177 : {
178 0 : if (this != &aOther) {
179 0 : Reset();
180 0 : new (this) CounterStylePtr(aOther);
181 : }
182 0 : return *this;
183 : }
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 0 : CounterStylePtr& operator=(already_AddRefed<nsIAtom> aAtom)
199 : {
200 0 : Reset();
201 0 : if (nsIAtom* raw = aAtom.take()) {
202 0 : AssertPointerAligned(raw);
203 0 : mRaw = reinterpret_cast<uintptr_t>(raw) | eUnresolvedAtom;
204 : }
205 0 : return *this;
206 : }
207 0 : CounterStylePtr& operator=(AnonymousCounterStyle* aCounterStyle)
208 : {
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 : }
215 0 : return *this;
216 : }
217 3 : CounterStylePtr& operator=(CounterStyle* aCounterStyle)
218 : {
219 3 : Reset();
220 3 : if (aCounterStyle) {
221 3 : MOZ_ASSERT(!aCounterStyle->AsAnonymous());
222 3 : AssertPointerAligned(aCounterStyle);
223 3 : mRaw = reinterpret_cast<uintptr_t>(aCounterStyle) | eCounterStyle;
224 : }
225 3 : return *this;
226 : }
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 0 : bool operator==(const CounterStylePtr& aOther) const
234 0 : { return mRaw == aOther.mRaw; }
235 93 : bool operator!=(const CounterStylePtr& aOther) const
236 93 : { return mRaw != aOther.mRaw; }
237 :
238 0 : bool IsResolved() const { return !IsUnresolved(); }
239 : inline void Resolve(CounterStyleManager* aManager);
240 :
241 : private:
242 0 : CounterStyle* Get() const
243 : {
244 0 : MOZ_ASSERT(IsResolved());
245 0 : return reinterpret_cast<CounterStyle*>(mRaw & ~eMask);
246 : }
247 : template<typename T>
248 3 : void AssertPointerAligned(T* aPointer)
249 : {
250 : // This can be checked at compile time via
251 : // > static_assert(alignof(CounterStyle) >= 4);
252 : // > static_assert(alignof(nsIAtom) >= 4);
253 : // but MSVC2015 doesn't support using alignof on an abstract class.
254 : // Once we move to MSVC2017, we can replace this runtime check with
255 : // the compile time check above.
256 3 : MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aPointer) & eMask));
257 3 : }
258 :
259 : enum Type : uintptr_t {
260 : eCounterStyle = 0,
261 : eAnonymousCounterStyle = 1,
262 : eUnresolvedAtom = 2,
263 : eMask = 3,
264 : };
265 :
266 238 : Type GetType() const { return static_cast<Type>(mRaw & eMask); }
267 0 : bool IsUnresolved() const { return GetType() == eUnresolvedAtom; }
268 0 : bool IsAnonymous() const { return GetType() == eAnonymousCounterStyle; }
269 0 : nsIAtom* AsAtom()
270 : {
271 0 : MOZ_ASSERT(IsUnresolved());
272 0 : return reinterpret_cast<nsIAtom*>(mRaw & ~eMask);
273 : }
274 0 : AnonymousCounterStyle* AsAnonymous()
275 : {
276 0 : MOZ_ASSERT(IsAnonymous());
277 : return static_cast<AnonymousCounterStyle*>(
278 0 : reinterpret_cast<CounterStyle*>(mRaw & ~eMask));
279 : }
280 :
281 108 : void Reset()
282 : {
283 108 : switch (GetType()) {
284 : case eCounterStyle:
285 108 : break;
286 : case eAnonymousCounterStyle:
287 0 : AsAnonymous()->Release();
288 0 : break;
289 : case eUnresolvedAtom:
290 0 : AsAtom()->Release();
291 0 : break;
292 : case eMask:
293 0 : MOZ_ASSERT_UNREACHABLE("Unknown type");
294 : break;
295 : }
296 108 : mRaw = 0;
297 108 : }
298 :
299 : // mRaw contains the pointer, and its last two bits are used for type
300 : // of the pointer.
301 : // If the type is eUnresolvedAtom, the pointer owns a reference to an
302 : // nsIAtom, and it needs to be resolved to a counter style before use.
303 : // If the type is eAnonymousCounterStyle, it owns a reference to an
304 : // anonymous counter style.
305 : // Otherwise it is a weak pointer referring a named counter style
306 : // managed by CounterStyleManager.
307 : uintptr_t mRaw;
308 : };
309 :
310 : class CounterStyleManager final
311 : {
312 : private:
313 : ~CounterStyleManager();
314 : public:
315 : explicit CounterStyleManager(nsPresContext* aPresContext);
316 :
317 : static void InitializeBuiltinCounterStyles();
318 :
319 : void Disconnect();
320 :
321 247 : bool IsInitial() const
322 : {
323 : // only 'none', 'decimal', and 'disc'
324 247 : return mStyles.Count() == 3;
325 : }
326 :
327 : // Returns the counter style object for the given name from the style
328 : // table if it is already built, and nullptr otherwise.
329 0 : CounterStyle* GetCounterStyle(nsIAtom* aName) const {
330 0 : return mStyles.Get(aName);
331 : }
332 : // Same as GetCounterStyle but try to build the counter style object
333 : // rather than returning nullptr if that hasn't been built.
334 : CounterStyle* BuildCounterStyle(nsIAtom* aName);
335 :
336 : static CounterStyle* GetBuiltinStyle(int32_t aStyle);
337 28 : static CounterStyle* GetNoneStyle()
338 : {
339 28 : return GetBuiltinStyle(NS_STYLE_LIST_STYLE_NONE);
340 : }
341 28 : static CounterStyle* GetDecimalStyle()
342 : {
343 28 : return GetBuiltinStyle(NS_STYLE_LIST_STYLE_DECIMAL);
344 : }
345 31 : static CounterStyle* GetDiscStyle()
346 : {
347 31 : return GetBuiltinStyle(NS_STYLE_LIST_STYLE_DISC);
348 : }
349 :
350 : // This method will scan all existing counter styles generated by this
351 : // manager, and remove or mark data dirty accordingly. It returns true
352 : // if any counter style is changed, false elsewise. This method should
353 : // be called when any counter style may be affected.
354 : bool NotifyRuleChanged();
355 : // NotifyRuleChanged will evict no longer needed counter styles into
356 : // mRetiredStyles, and this function destroys all objects listed there.
357 : // It should be called only after no one may ever use those objects.
358 : void CleanRetiredStyles();
359 :
360 0 : nsPresContext* PresContext() const { return mPresContext; }
361 :
362 36 : NS_INLINE_DECL_REFCOUNTING(CounterStyleManager)
363 :
364 : private:
365 : void DestroyCounterStyle(CounterStyle* aCounterStyle);
366 :
367 : nsPresContext* mPresContext;
368 : nsDataHashtable<nsRefPtrHashKey<nsIAtom>, CounterStyle*> mStyles;
369 : nsTArray<CounterStyle*> mRetiredStyles;
370 : };
371 :
372 : void
373 0 : CounterStylePtr::Resolve(CounterStyleManager* aManager)
374 : {
375 0 : if (IsUnresolved()) {
376 0 : *this = aManager->BuildCounterStyle(AsAtom());
377 : }
378 0 : }
379 :
380 : } // namespace mozilla
381 :
382 : #endif /* !defined(mozilla_CounterStyleManager_h_) */
|