Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / editor / libeditor / PendingStyles.h
blobb41e383e80770fb3b36d1f025c0ac2cc3111783a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_PendingStyles_h
7 #define mozilla_PendingStyles_h
9 #include "mozilla/EditorDOMPoint.h"
10 #include "mozilla/EditorForwards.h"
11 #include "mozilla/EventForwards.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/UniquePtr.h"
14 #include "nsAtom.h"
15 #include "nsCOMPtr.h"
16 #include "nsCycleCollectionParticipant.h"
17 #include "nsGkAtoms.h"
18 #include "nsISupportsImpl.h"
19 #include "nsString.h"
20 #include "nsTArray.h"
21 #include "nscore.h"
23 class nsINode;
25 namespace mozilla {
26 namespace dom {
27 class MouseEvent;
28 class Selection;
29 } // namespace dom
31 enum class SpecifiedStyle : uint8_t { Preserve, Discard };
33 class PendingStyle final {
34 public:
35 PendingStyle() = delete;
36 PendingStyle(nsStaticAtom* aTag, nsAtom* aAttribute, const nsAString& aValue,
37 SpecifiedStyle aSpecifiedStyle = SpecifiedStyle::Preserve)
38 : mTag(aTag),
39 mAttribute(aAttribute != nsGkAtoms::_empty ? aAttribute : nullptr),
40 mAttributeValueOrCSSValue(aValue),
41 mSpecifiedStyle(aSpecifiedStyle) {
42 MOZ_COUNT_CTOR(PendingStyle);
44 MOZ_COUNTED_DTOR(PendingStyle)
46 MOZ_KNOWN_LIVE nsStaticAtom* GetTag() const { return mTag; }
47 MOZ_KNOWN_LIVE nsAtom* GetAttribute() const { return mAttribute; }
48 const nsString& AttributeValueOrCSSValueRef() const {
49 return mAttributeValueOrCSSValue;
51 void UpdateAttributeValueOrCSSValue(const nsAString& aNewValue) {
52 mAttributeValueOrCSSValue = aNewValue;
54 SpecifiedStyle GetSpecifiedStyle() const { return mSpecifiedStyle; }
56 EditorInlineStyle ToInlineStyle() const;
57 EditorInlineStyleAndValue ToInlineStyleAndValue() const;
59 private:
60 MOZ_KNOWN_LIVE nsStaticAtom* const mTag = nullptr;
61 // TODO: Once we stop using `HTMLEditor::SetInlinePropertiesAsSubAction` to
62 // add any attributes of <a href>, we can make this `nsStaticAtom*`.
63 MOZ_KNOWN_LIVE const RefPtr<nsAtom> mAttribute;
64 // If the editor is in CSS mode, this value is the property value.
65 // If the editor is in HTML mode, this value is not empty only when
66 // - mAttribute is not nullptr
67 // - mTag is CSS invertible style and "-moz-editor-invert-value"
68 nsString mAttributeValueOrCSSValue;
69 // Whether the class and style attribute should be preserved or discarded.
70 const SpecifiedStyle mSpecifiedStyle = SpecifiedStyle::Preserve;
73 class PendingStyleCache final {
74 public:
75 PendingStyleCache() = delete;
76 PendingStyleCache(const nsStaticAtom& aTag, const nsStaticAtom* aAttribute,
77 const nsAString& aValue)
78 // Needs const_cast hack here because the this class users may want
79 // non-const nsStaticAtom reference/pointer due to bug 1794954
80 : mTag(const_cast<nsStaticAtom&>(aTag)),
81 mAttribute(const_cast<nsStaticAtom*>(aAttribute)),
82 mAttributeValueOrCSSValue(aValue) {}
83 PendingStyleCache(const nsStaticAtom& aTag, const nsStaticAtom* aAttribute,
84 nsAString&& aValue)
85 // Needs const_cast hack here because the this class users may want
86 // non-const nsStaticAtom reference/pointer due to bug 1794954
87 : mTag(const_cast<nsStaticAtom&>(aTag)),
88 mAttribute(const_cast<nsStaticAtom*>(aAttribute)),
89 mAttributeValueOrCSSValue(std::move(aValue)) {}
91 MOZ_KNOWN_LIVE nsStaticAtom& TagRef() const { return mTag; }
92 MOZ_KNOWN_LIVE nsStaticAtom* GetAttribute() const { return mAttribute; }
93 const nsString& AttributeValueOrCSSValueRef() const {
94 return mAttributeValueOrCSSValue;
97 EditorInlineStyle ToInlineStyle() const;
99 private:
100 MOZ_KNOWN_LIVE nsStaticAtom& mTag;
101 MOZ_KNOWN_LIVE nsStaticAtom* const mAttribute;
102 const nsString mAttributeValueOrCSSValue;
105 class MOZ_STACK_CLASS AutoPendingStyleCacheArray final
106 : public AutoTArray<PendingStyleCache, 21> {
107 public:
108 [[nodiscard]] index_type IndexOf(const nsStaticAtom& aTag,
109 const nsStaticAtom* aAttribute) const {
110 for (index_type index = 0; index < Length(); ++index) {
111 const PendingStyleCache& styleCache = ElementAt(index);
112 if (&styleCache.TagRef() == &aTag &&
113 styleCache.GetAttribute() == aAttribute) {
114 return index;
117 return NoIndex;
120 [[nodiscard]] bool Contains(const nsStaticAtom& aTag,
121 const nsStaticAtom* aAttribute) const {
122 return IndexOf(aTag, aAttribute) != NoIndex;
126 enum class PendingStyleState {
127 // Will be not changed in new content
128 NotUpdated,
129 // Will be applied to new content
130 BeingPreserved,
131 // Will be cleared from new content
132 BeingCleared,
135 /******************************************************************************
136 * PendingStyles stores pending inline styles which WILL be applied to new
137 * content when it'll be inserted. I.e., updating styles of this class means
138 * that it does NOT update the DOM tree immediately.
139 ******************************************************************************/
140 class PendingStyles final {
141 public:
142 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingStyles)
143 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingStyles)
145 PendingStyles() = default;
147 void Reset() {
148 mClearingStyles.Clear();
149 mPreservingStyles.Clear();
152 nsresult UpdateSelState(const HTMLEditor& aHTMLEditor);
155 * PreHandleMouseEvent() is called when `HTMLEditorEventListener` receives
156 * "mousedown" and "mouseup" events. Note that `aMouseDownOrUpEvent` may not
157 * be acceptable event for the `HTMLEditor`, but this is called even in
158 * the case because the event may cause a following `OnSelectionChange()`
159 * call.
161 void PreHandleMouseEvent(const dom::MouseEvent& aMouseDownOrUpEvent);
163 void PreHandleSelectionChangeCommand(Command aCommand);
164 void PostHandleSelectionChangeCommand(const HTMLEditor& aHTMLEditor,
165 Command aCommand);
167 void OnSelectionChange(const HTMLEditor& aHTMLEditor, int16_t aReason);
170 * Preserve the style for next inserting content. E.g., when user types next
171 * character, an inline element which provides the style will be inserted
172 * and the typing character will appear in it.
174 * @param aHTMLProperty The HTML tag name which represents the style.
175 * For example, nsGkAtoms::b for bold text.
176 * @param aAttribute nullptr or attribute name which represents the
177 * style with aHTMLProperty. E.g., nsGkAtoms::size
178 * for nsGkAtoms::font.
179 * @param aAttributeValueOrCSSValue
180 * New value of aAttribute or new CSS value if the
181 * editor is in the CSS mode.
183 void PreserveStyle(nsStaticAtom& aHTMLProperty, nsAtom* aAttribute,
184 const nsAString& aAttributeValueOrCSSValue);
187 * Preserve the styles with new values in aStylesToPreserve.
188 * See above for the detail.
190 void PreserveStyles(
191 const nsTArray<EditorInlineStyleAndValue>& aStylesToPreserve);
194 * Preserve the style with new value specified with aStyleToPreserve.
195 * See above for the detail.
197 void PreserveStyle(const PendingStyleCache& aStyleToPreserve) {
198 PreserveStyle(aStyleToPreserve.TagRef(), aStyleToPreserve.GetAttribute(),
199 aStyleToPreserve.AttributeValueOrCSSValueRef());
203 * Clear the style when next content is inserted. E.g., when user types next
204 * character, it'll will be inserted after parent element which provides the
205 * style and clones element which represents other styles in the parent
206 * element.
208 * @param aHTMLProperty The HTML tag name which represents the style.
209 * For example, nsGkAtoms::b for bold text.
210 * @param aAttribute nullptr or attribute name which represents the
211 * style with aHTMLProperty. E.g., nsGkAtoms::size
212 * for nsGkAtoms::font.
214 void ClearStyle(nsStaticAtom& aHTMLProperty, nsAtom* aAttribute) {
215 ClearStyleInternal(&aHTMLProperty, aAttribute);
219 * Clear all styles specified by aStylesToClear when next content is inserted.
220 * See above for the detail.
222 void ClearStyles(const nsTArray<EditorInlineStyle>& aStylesToClear);
225 * Clear all styles when next inserting content. E.g., when user types next
226 * character, it will be inserted outside any inline parents which provides
227 * current text style.
229 void ClearAllStyles() {
230 // XXX Why don't we clear mClearingStyles first?
231 ClearStyleInternal(nullptr, nullptr);
235 * Clear <a> element and discard styles which is applied by it.
237 void ClearLinkAndItsSpecifiedStyle() {
238 ClearStyleInternal(nsGkAtoms::a, nullptr, SpecifiedStyle::Discard);
242 * TakeClearingStyle() hands back next property item on the clearing styles.
243 * This must be used only for handling to clear the styles from inserting
244 * content.
246 UniquePtr<PendingStyle> TakeClearingStyle() {
247 if (mClearingStyles.IsEmpty()) {
248 return nullptr;
250 return mClearingStyles.PopLastElement();
254 * TakeAllPreservedStyles() moves all preserved styles and values to
255 * aOutStylesAndValues.
257 void TakeAllPreservedStyles(
258 nsTArray<EditorInlineStyleAndValue>& aOutStylesAndValues);
261 * TakeRelativeFontSize() hands back relative font value, which is then
262 * cleared out.
264 int32_t TakeRelativeFontSize();
267 * GetStyleState() returns whether the style will be applied to new content,
268 * removed from new content or not changed.
270 * @param aHTMLProperty The HTML tag name which represents the style.
271 * For example, nsGkAtoms::b for bold text.
272 * @param aAttribute nullptr or attribute name which represents the
273 * style with aHTMLProperty. E.g., nsGkAtoms::size
274 * for nsGkAtoms::font.
275 * @param aOutNewAttributeValueOrCSSValue
276 * [out, optional] If applied to new content, this
277 * is set to the new value.
279 PendingStyleState GetStyleState(
280 nsStaticAtom& aHTMLProperty, nsAtom* aAttribute = nullptr,
281 nsString* aOutNewAttributeValueOrCSSValue = nullptr) const;
283 protected:
284 virtual ~PendingStyles() { Reset(); };
286 void ClearStyleInternal(
287 nsStaticAtom* aHTMLProperty, nsAtom* aAttribute,
288 SpecifiedStyle aSpecifiedStyle = SpecifiedStyle::Preserve);
290 void CancelPreservingStyle(nsStaticAtom* aHTMLProperty, nsAtom* aAttribute);
291 void CancelClearingStyle(nsStaticAtom& aHTMLProperty, nsAtom* aAttribute);
293 Maybe<size_t> IndexOfPreservingStyle(nsStaticAtom& aHTMLProperty,
294 nsAtom* aAttribute,
295 nsAString* aOutValue = nullptr) const {
296 return IndexOfStyleInArray(&aHTMLProperty, aAttribute, aOutValue,
297 mPreservingStyles);
299 Maybe<size_t> IndexOfClearingStyle(nsStaticAtom* aHTMLProperty,
300 nsAtom* aAttribute) const {
301 return IndexOfStyleInArray(aHTMLProperty, aAttribute, nullptr,
302 mClearingStyles);
305 bool IsLinkStyleSet() const {
306 return IndexOfPreservingStyle(*nsGkAtoms::a, nullptr).isSome();
308 bool IsExplicitlyLinkStyleCleared() const {
309 return IndexOfClearingStyle(nsGkAtoms::a, nullptr).isSome();
311 bool IsOnlyLinkStyleCleared() const {
312 return mClearingStyles.Length() == 1 && IsExplicitlyLinkStyleCleared();
314 bool IsStyleCleared(nsStaticAtom* aHTMLProperty, nsAtom* aAttribute) const {
315 return IndexOfClearingStyle(aHTMLProperty, aAttribute).isSome() ||
316 AreAllStylesCleared();
318 bool AreAllStylesCleared() const {
319 return IndexOfClearingStyle(nullptr, nullptr).isSome();
321 bool AreSomeStylesSet() const { return !mPreservingStyles.IsEmpty(); }
322 bool AreSomeStylesCleared() const { return !mClearingStyles.IsEmpty(); }
324 static Maybe<size_t> IndexOfStyleInArray(
325 nsStaticAtom* aHTMLProperty, nsAtom* aAttribute, nsAString* aOutValue,
326 const nsTArray<UniquePtr<PendingStyle>>& aArray);
328 nsTArray<UniquePtr<PendingStyle>> mPreservingStyles;
329 nsTArray<UniquePtr<PendingStyle>> mClearingStyles;
330 EditorDOMPoint mLastSelectionPoint;
331 int32_t mRelativeFontSize = 0;
332 Command mLastSelectionCommand = Command::DoNothing;
333 bool mMouseDownFiredInLinkElement = false;
334 bool mMouseUpFiredInLinkElement = false;
337 } // namespace mozilla
339 #endif // #ifndef mozilla_PendingStyles_h