Bug 1883861 - Part 1: Move visitMemoryBarrier into the common CodeGenerator file...
[gecko.git] / layout / style / CounterStyleManager.h
blobb6d9c2a0a95f318355c5bf69fb30fad8f51fc3a4
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_
9 #include "nsGkAtoms.h"
10 #include "nsStringFwd.h"
11 #include "nsTHashMap.h"
12 #include "nsHashKeys.h"
14 #include "nsStyleConsts.h"
16 #include "mozilla/Attributes.h"
18 class nsPresContext;
20 namespace mozilla {
22 enum class SpeakAs : uint8_t {
23 Bullets = 0,
24 Numbers = 1,
25 Words = 2,
26 Spellout = 3,
27 Other = 255
30 class WritingMode;
32 typedef int32_t CounterValue;
34 class CounterStyleManager;
35 class AnonymousCounterStyle;
37 struct NegativeType;
38 struct PadType;
40 class CounterStyle {
41 protected:
42 explicit constexpr CounterStyle(ListStyle aStyle) : mStyle(aStyle) {}
44 private:
45 CounterStyle(const CounterStyle& aOther) = delete;
46 void operator=(const CounterStyle& other) = delete;
48 public:
49 constexpr ListStyle GetStyle() const { return mStyle; }
50 bool IsNone() const { return mStyle == ListStyle::None; }
51 bool IsCustomStyle() const { return mStyle == ListStyle::Custom; }
52 // A style is dependent if it depends on the counter style manager.
53 // Custom styles are certainly dependent. In addition, some builtin
54 // styles are dependent for fallback.
55 bool IsDependentStyle() const;
57 virtual void GetPrefix(nsAString& aResult) = 0;
58 virtual void GetSuffix(nsAString& aResult) = 0;
59 void GetCounterText(CounterValue aOrdinal, WritingMode aWritingMode,
60 nsAString& aResult, bool& aIsRTL);
61 virtual void GetSpokenCounterText(CounterValue aOrdinal,
62 WritingMode aWritingMode,
63 nsAString& aResult, bool& aIsBullet);
65 // XXX This method could be removed once ::-moz-list-bullet and
66 // ::-moz-list-number are completely merged into ::marker.
67 virtual bool IsBullet() = 0;
69 virtual void GetNegative(NegativeType& aResult) = 0;
70 /**
71 * This method returns whether an ordinal is in the range of this
72 * counter style. Note that, it is possible that an ordinal in range
73 * is rejected by the generating algorithm.
75 virtual bool IsOrdinalInRange(CounterValue aOrdinal) = 0;
76 /**
77 * This method returns whether an ordinal is in the default range of
78 * this counter style. This is the effective range when no 'range'
79 * descriptor is specified.
81 virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) = 0;
82 virtual void GetPad(PadType& aResult) = 0;
83 virtual CounterStyle* GetFallback() = 0;
84 virtual SpeakAs GetSpeakAs() = 0;
85 virtual bool UseNegativeSign() = 0;
87 virtual void CallFallbackStyle(CounterValue aOrdinal,
88 WritingMode aWritingMode, nsAString& aResult,
89 bool& aIsRTL);
90 virtual bool GetInitialCounterText(CounterValue aOrdinal,
91 WritingMode aWritingMode,
92 nsAString& aResult, bool& aIsRTL) = 0;
94 virtual AnonymousCounterStyle* AsAnonymous() { return nullptr; }
96 protected:
97 const ListStyle mStyle;
100 class AnonymousCounterStyle final : public CounterStyle {
101 public:
102 explicit AnonymousCounterStyle(const nsAString& aContent);
103 AnonymousCounterStyle(StyleSymbolsType, nsTArray<nsString> aSymbols);
105 virtual void GetPrefix(nsAString& aResult) override;
106 virtual void GetSuffix(nsAString& aResult) override;
107 virtual bool IsBullet() override;
109 virtual void GetNegative(NegativeType& aResult) override;
110 virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
111 virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
112 virtual void GetPad(PadType& aResult) override;
113 virtual CounterStyle* GetFallback() override;
114 virtual SpeakAs GetSpeakAs() override;
115 virtual bool UseNegativeSign() override;
117 virtual bool GetInitialCounterText(CounterValue aOrdinal,
118 WritingMode aWritingMode,
119 nsAString& aResult, bool& aIsRTL) override;
121 virtual AnonymousCounterStyle* AsAnonymous() override { return this; }
123 bool IsSingleString() const { return mSingleString; }
124 auto GetSymbols() const { return Span<const nsString>{mSymbols}; }
126 StyleCounterSystem GetSystem() const;
128 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousCounterStyle)
130 private:
131 ~AnonymousCounterStyle() = default;
133 bool mSingleString;
134 StyleSymbolsType mSymbolsType;
135 nsTArray<nsString> mSymbols;
138 // A smart pointer to CounterStyle. It either owns a reference to an
139 // anonymous counter style, or weakly refers to a named counter style
140 // managed by counter style manager.
141 class CounterStylePtr {
142 public:
143 CounterStylePtr() : mRaw(0) {}
144 CounterStylePtr(const CounterStylePtr& aOther) : mRaw(aOther.mRaw) {
145 if (!mRaw) {
146 return;
148 switch (GetType()) {
149 case eAnonymousCounterStyle:
150 AsAnonymous()->AddRef();
151 break;
152 case eAtom:
153 AsAtom()->AddRef();
154 break;
155 default:
156 MOZ_ASSERT_UNREACHABLE("Unknown type");
157 break;
160 CounterStylePtr(CounterStylePtr&& aOther) : mRaw(aOther.mRaw) {
161 aOther.mRaw = 0;
163 ~CounterStylePtr() { Reset(); }
165 CounterStylePtr& operator=(const CounterStylePtr& aOther) {
166 if (this != &aOther) {
167 Reset();
168 new (this) CounterStylePtr(aOther);
170 return *this;
172 CounterStylePtr& operator=(CounterStylePtr&& aOther) {
173 if (this != &aOther) {
174 Reset();
175 mRaw = aOther.mRaw;
176 aOther.mRaw = 0;
178 return *this;
180 CounterStylePtr& operator=(decltype(nullptr)) {
181 Reset();
182 return *this;
184 CounterStylePtr& operator=(nsStaticAtom* aStaticAtom) {
185 Reset();
186 mRaw = reinterpret_cast<uintptr_t>(aStaticAtom) | eAtom;
187 return *this;
189 CounterStylePtr& operator=(already_AddRefed<nsAtom> aAtom) {
190 Reset();
191 mRaw = reinterpret_cast<uintptr_t>(aAtom.take()) | eAtom;
192 return *this;
194 CounterStylePtr& operator=(AnonymousCounterStyle* aCounterStyle) {
195 Reset();
196 if (aCounterStyle) {
197 CounterStyle* raw = do_AddRef(aCounterStyle).take();
198 mRaw = reinterpret_cast<uintptr_t>(raw) | eAnonymousCounterStyle;
200 return *this;
203 // TODO(emilio): Make CounterStyle have a single representation, either by
204 // removing CounterStylePtr or by moving this representation to Rust.
205 static CounterStylePtr FromStyle(const StyleCounterStyle& aStyle) {
206 CounterStylePtr ret;
207 if (aStyle.IsName()) {
208 ret = do_AddRef(aStyle.AsName().AsAtom());
209 } else {
210 StyleSymbolsType type = aStyle.AsSymbols()._0;
211 Span<const StyleSymbol> symbols = aStyle.AsSymbols()._1._0.AsSpan();
212 nsTArray<nsString> transcoded(symbols.Length());
213 for (const auto& symbol : symbols) {
214 MOZ_ASSERT(symbol.IsString(), "Should not have <ident> in symbols()");
215 transcoded.AppendElement(
216 NS_ConvertUTF8toUTF16(symbol.AsString().AsString()));
218 ret = new AnonymousCounterStyle(type, std::move(transcoded));
220 return ret;
223 explicit operator bool() const { return !!mRaw; }
224 bool operator!() const { return !mRaw; }
225 bool operator==(const CounterStylePtr& aOther) const {
226 // FIXME(emilio): For atoms this is all right, but for symbols doesn't this
227 // cause us to compare as unequal all the time, even if the specified
228 // symbols didn't change?
229 return mRaw == aOther.mRaw;
231 bool operator!=(const CounterStylePtr& aOther) const {
232 return mRaw != aOther.mRaw;
235 nsAtom* AsAtom() const {
236 MOZ_ASSERT(IsAtom());
237 return reinterpret_cast<nsAtom*>(mRaw & ~eMask);
239 AnonymousCounterStyle* AsAnonymous() const {
240 MOZ_ASSERT(IsAnonymous());
241 return static_cast<AnonymousCounterStyle*>(
242 reinterpret_cast<CounterStyle*>(mRaw & ~eMask));
245 bool IsAtom() const { return GetType() == eAtom; }
246 bool IsAnonymous() const { return GetType() == eAnonymousCounterStyle; }
248 bool IsNone() const { return IsAtom() && AsAtom() == nsGkAtoms::none; }
250 private:
251 enum Type : uintptr_t {
252 eAnonymousCounterStyle = 0,
253 eAtom = 1,
254 eMask = 1,
257 static_assert(alignof(CounterStyle) >= 1 << eMask,
258 "We're gonna tag the pointer, so it better fit");
259 static_assert(alignof(nsAtom) >= 1 << eMask,
260 "We're gonna tag the pointer, so it better fit");
262 Type GetType() const { return static_cast<Type>(mRaw & eMask); }
264 void Reset() {
265 if (!mRaw) {
266 return;
268 switch (GetType()) {
269 case eAnonymousCounterStyle:
270 AsAnonymous()->Release();
271 break;
272 case eAtom:
273 AsAtom()->Release();
274 break;
275 default:
276 MOZ_ASSERT_UNREACHABLE("Unknown type");
277 break;
279 mRaw = 0;
282 // mRaw contains the pointer, and its last bit is used to store the type of
283 // the pointer.
284 // If the type is eAtom, the pointer owns a reference to an nsAtom
285 // (potentially null).
286 // If the type is eAnonymousCounterStyle, it owns a reference to an
287 // anonymous counter style (never null).
288 uintptr_t mRaw;
291 class CounterStyleManager final {
292 private:
293 ~CounterStyleManager();
295 public:
296 explicit CounterStyleManager(nsPresContext* aPresContext);
298 void Disconnect();
300 bool IsInitial() const {
301 // only 'none', 'decimal', and 'disc'
302 return mStyles.Count() == 3;
305 // Returns the counter style object for the given name from the style
306 // table if it is already built, and nullptr otherwise.
307 CounterStyle* GetCounterStyle(nsAtom* aName) const {
308 return mStyles.Get(aName);
310 // Same as GetCounterStyle but try to build the counter style object
311 // rather than returning nullptr if that hasn't been built.
312 CounterStyle* ResolveCounterStyle(nsAtom* aName);
313 CounterStyle* ResolveCounterStyle(const CounterStylePtr& aPtr) {
314 if (aPtr.IsAtom()) {
315 return ResolveCounterStyle(aPtr.AsAtom());
317 return aPtr.AsAnonymous();
320 static CounterStyle* GetBuiltinStyle(ListStyle aStyle);
321 static CounterStyle* GetNoneStyle() {
322 return GetBuiltinStyle(ListStyle::None);
324 static CounterStyle* GetDecimalStyle() {
325 return GetBuiltinStyle(ListStyle::Decimal);
327 static CounterStyle* GetDiscStyle() {
328 return GetBuiltinStyle(ListStyle::Disc);
331 // This method will scan all existing counter styles generated by this
332 // manager, and remove or mark data dirty accordingly. It returns true
333 // if any counter style is changed, false elsewise. This method should
334 // be called when any counter style may be affected.
335 bool NotifyRuleChanged();
336 // NotifyRuleChanged will evict no longer needed counter styles into
337 // mRetiredStyles, and this function destroys all objects listed there.
338 // It should be called only after no one may ever use those objects.
339 void CleanRetiredStyles();
341 nsPresContext* PresContext() const { return mPresContext; }
343 NS_INLINE_DECL_REFCOUNTING(CounterStyleManager)
345 private:
346 void DestroyCounterStyle(CounterStyle* aCounterStyle);
348 nsPresContext* mPresContext;
349 nsTHashMap<RefPtr<nsAtom>, CounterStyle*> mStyles;
350 nsTArray<CounterStyle*> mRetiredStyles;
353 } // namespace mozilla
355 #endif /* !defined(mozilla_CounterStyleManager_h_) */