CounterStyleManager.h (6941B)
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 "mozilla/Attributes.h" 10 #include "nsGkAtoms.h" 11 #include "nsHashKeys.h" 12 #include "nsStringFwd.h" 13 #include "nsStyleConsts.h" 14 #include "nsTHashMap.h" 15 16 class nsPresContext; 17 18 namespace mozilla { 19 20 enum class SpeakAs : uint8_t { 21 Bullets = 0, 22 Numbers = 1, 23 Words = 2, 24 Spellout = 3, 25 Other = 255 26 }; 27 28 class WritingMode; 29 30 typedef int32_t CounterValue; 31 32 class CounterStyleManager; 33 class AnonymousCounterStyle; 34 35 struct NegativeType; 36 struct PadType; 37 38 class CounterStyle { 39 protected: 40 explicit constexpr CounterStyle(ListStyle aStyle) : mStyle(aStyle) {} 41 42 private: 43 CounterStyle(const CounterStyle& aOther) = delete; 44 void operator=(const CounterStyle& other) = delete; 45 46 public: 47 constexpr ListStyle GetStyle() const { return mStyle; } 48 bool IsNone() const { return mStyle == ListStyle::None; } 49 bool IsCustomStyle() const { return mStyle == ListStyle::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 GetPrefix(nsAString& aResult) = 0; 56 virtual void GetSuffix(nsAString& aResult) = 0; 57 void GetCounterText(CounterValue aOrdinal, WritingMode aWritingMode, 58 nsAString& aResult, bool& aIsRTL); 59 virtual void GetSpokenCounterText(CounterValue aOrdinal, 60 WritingMode aWritingMode, 61 nsAString& aResult, bool& aIsBullet); 62 63 // XXX This method could be removed once ::-moz-list-bullet and 64 // ::-moz-list-number are completely merged into ::marker. 65 virtual bool IsBullet() = 0; 66 67 virtual void GetNegative(NegativeType& aResult) = 0; 68 /** 69 * This method returns whether an ordinal is in the range of this 70 * counter style. Note that, it is possible that an ordinal in range 71 * is rejected by the generating algorithm. 72 */ 73 virtual bool IsOrdinalInRange(CounterValue aOrdinal) = 0; 74 /** 75 * This method returns whether an ordinal is in the default range of 76 * this counter style. This is the effective range when no 'range' 77 * descriptor is specified. 78 */ 79 virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) = 0; 80 virtual void GetPad(PadType& aResult) = 0; 81 virtual CounterStyle* GetFallback() = 0; 82 virtual SpeakAs GetSpeakAs() = 0; 83 virtual bool UseNegativeSign() = 0; 84 85 virtual void CallFallbackStyle(CounterValue aOrdinal, 86 WritingMode aWritingMode, nsAString& aResult, 87 bool& aIsRTL); 88 virtual bool GetInitialCounterText(CounterValue aOrdinal, 89 WritingMode aWritingMode, 90 nsAString& aResult, bool& aIsRTL) = 0; 91 92 virtual AnonymousCounterStyle* AsAnonymous() { return nullptr; } 93 94 protected: 95 const ListStyle mStyle; 96 }; 97 98 class MOZ_STACK_CLASS AnonymousCounterStyle final : public CounterStyle { 99 public: 100 explicit AnonymousCounterStyle(const nsAString& aContent); 101 AnonymousCounterStyle(StyleSymbolsType, Span<const StyleSymbol> aSymbols); 102 103 void GetPrefix(nsAString& aResult) override; 104 void GetSuffix(nsAString& aResult) override; 105 bool IsBullet() override; 106 107 void GetNegative(NegativeType& aResult) override; 108 bool IsOrdinalInRange(CounterValue aOrdinal) override; 109 bool IsOrdinalInAutoRange(CounterValue aOrdinal) override; 110 void GetPad(PadType& aResult) override; 111 CounterStyle* GetFallback() override; 112 SpeakAs GetSpeakAs() override; 113 bool UseNegativeSign() override; 114 115 bool GetInitialCounterText(CounterValue aOrdinal, WritingMode aWritingMode, 116 nsAString& aResult, bool& aIsRTL) override; 117 118 AnonymousCounterStyle* AsAnonymous() override { return this; } 119 120 auto GetSymbols() const { return mSymbols; } 121 122 StyleCounterSystem GetSystem() const; 123 124 ~AnonymousCounterStyle() = default; 125 126 StyleSymbolsType mSymbolsType; 127 Span<const StyleSymbol> mSymbols; 128 }; 129 130 class CounterStyleManager final { 131 private: 132 ~CounterStyleManager(); 133 134 public: 135 explicit CounterStyleManager(nsPresContext* aPresContext); 136 137 void Disconnect(); 138 139 bool IsInitial() const { 140 // only 'none', 'decimal', and 'disc' 141 return mStyles.Count() == 3; 142 } 143 144 // Returns the counter style object for the given name from the style 145 // table if it is already built, and nullptr otherwise. 146 CounterStyle* GetCounterStyle(nsAtom* aName) const { 147 return mStyles.Get(aName); 148 } 149 // Same as GetCounterStyle but try to build the counter style object 150 // rather than returning nullptr if that hasn't been built. 151 CounterStyle* ResolveCounterStyle(nsAtom* aName); 152 template <typename F> 153 void WithCounterStyleNameOrSymbols(const StyleCounterStyle& aStyle, 154 F&& aCallback) { 155 using Tag = StyleCounterStyle::Tag; 156 switch (aStyle.tag) { 157 case Tag::None: 158 case Tag::String: 159 MOZ_CRASH("Unexpected counter style"); 160 case Tag::Symbols: { 161 AnonymousCounterStyle s(aStyle.AsSymbols().ty, 162 aStyle.AsSymbols().symbols._0.AsSpan()); 163 return aCallback(&s); 164 } 165 case Tag::Name: { 166 return aCallback(ResolveCounterStyle(aStyle.AsName().AsAtom())); 167 } 168 } 169 } 170 171 static CounterStyle* GetBuiltinStyle(ListStyle aStyle); 172 static CounterStyle* GetNoneStyle() { 173 return GetBuiltinStyle(ListStyle::None); 174 } 175 static CounterStyle* GetDecimalStyle() { 176 return GetBuiltinStyle(ListStyle::Decimal); 177 } 178 static CounterStyle* GetDiscStyle() { 179 return GetBuiltinStyle(ListStyle::Disc); 180 } 181 182 // This method will scan all existing counter styles generated by this 183 // manager, and remove or mark data dirty accordingly. It returns true 184 // if any counter style is changed, false elsewise. This method should 185 // be called when any counter style may be affected. 186 bool NotifyRuleChanged(); 187 // NotifyRuleChanged will evict no longer needed counter styles into 188 // mRetiredStyles, and this function destroys all objects listed there. 189 // It should be called only after no one may ever use those objects. 190 void CleanRetiredStyles(); 191 192 nsPresContext* PresContext() const { return mPresContext; } 193 194 NS_INLINE_DECL_REFCOUNTING(CounterStyleManager) 195 196 private: 197 void DestroyCounterStyle(CounterStyle* aCounterStyle); 198 199 nsPresContext* mPresContext; 200 nsTHashMap<RefPtr<nsAtom>, CounterStyle*> mStyles; 201 nsTArray<CounterStyle*> mRetiredStyles; 202 }; 203 204 } // namespace mozilla 205 206 #endif /* !defined(mozilla_CounterStyleManager_h_) */