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_
10 #include "nsStringFwd.h"
11 #include "nsTHashMap.h"
12 #include "nsHashKeys.h"
14 #include "nsStyleConsts.h"
16 #include "mozilla/Attributes.h"
22 enum class SpeakAs
: uint8_t {
32 typedef int32_t CounterValue
;
34 class CounterStyleManager
;
35 class AnonymousCounterStyle
;
42 explicit constexpr CounterStyle(ListStyle aStyle
) : mStyle(aStyle
) {}
45 CounterStyle(const CounterStyle
& aOther
) = delete;
46 void operator=(const CounterStyle
& other
) = delete;
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;
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;
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
,
90 virtual bool GetInitialCounterText(CounterValue aOrdinal
,
91 WritingMode aWritingMode
,
92 nsAString
& aResult
, bool& aIsRTL
) = 0;
94 virtual AnonymousCounterStyle
* AsAnonymous() { return nullptr; }
97 const ListStyle mStyle
;
100 class AnonymousCounterStyle final
: public CounterStyle
{
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
)
131 ~AnonymousCounterStyle() = default;
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
{
143 CounterStylePtr() : mRaw(0) {}
144 CounterStylePtr(const CounterStylePtr
& aOther
) : mRaw(aOther
.mRaw
) {
149 case eAnonymousCounterStyle
:
150 AsAnonymous()->AddRef();
156 MOZ_ASSERT_UNREACHABLE("Unknown type");
160 CounterStylePtr(CounterStylePtr
&& aOther
) : mRaw(aOther
.mRaw
) {
163 ~CounterStylePtr() { Reset(); }
165 CounterStylePtr
& operator=(const CounterStylePtr
& aOther
) {
166 if (this != &aOther
) {
168 new (this) CounterStylePtr(aOther
);
172 CounterStylePtr
& operator=(CounterStylePtr
&& aOther
) {
173 if (this != &aOther
) {
180 CounterStylePtr
& operator=(decltype(nullptr)) {
184 CounterStylePtr
& operator=(nsStaticAtom
* aStaticAtom
) {
186 mRaw
= reinterpret_cast<uintptr_t>(aStaticAtom
) | eAtom
;
189 CounterStylePtr
& operator=(already_AddRefed
<nsAtom
> aAtom
) {
191 mRaw
= reinterpret_cast<uintptr_t>(aAtom
.take()) | eAtom
;
194 CounterStylePtr
& operator=(AnonymousCounterStyle
* aCounterStyle
) {
197 CounterStyle
* raw
= do_AddRef(aCounterStyle
).take();
198 mRaw
= reinterpret_cast<uintptr_t>(raw
) | eAnonymousCounterStyle
;
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
) {
207 if (aStyle
.IsName()) {
208 ret
= do_AddRef(aStyle
.AsName().AsAtom());
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
));
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
; }
251 enum Type
: uintptr_t {
252 eAnonymousCounterStyle
= 0,
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
); }
269 case eAnonymousCounterStyle
:
270 AsAnonymous()->Release();
276 MOZ_ASSERT_UNREACHABLE("Unknown type");
282 // mRaw contains the pointer, and its last bit is used to store the type of
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).
291 class CounterStyleManager final
{
293 ~CounterStyleManager();
296 explicit CounterStyleManager(nsPresContext
* aPresContext
);
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
) {
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
)
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_) */