tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PendingStyles.h (12912B)


      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/. */
      5 
      6 #ifndef mozilla_PendingStyles_h
      7 #define mozilla_PendingStyles_h
      8 
      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"
     22 
     23 class nsINode;
     24 
     25 namespace mozilla {
     26 namespace dom {
     27 class MouseEvent;
     28 class Selection;
     29 }  // namespace dom
     30 
     31 enum class SpecifiedStyle : uint8_t { Preserve, Discard };
     32 
     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);
     43  }
     44  MOZ_COUNTED_DTOR(PendingStyle)
     45 
     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;
     50  }
     51  void UpdateAttributeValueOrCSSValue(const nsAString& aNewValue) {
     52    mAttributeValueOrCSSValue = aNewValue;
     53  }
     54  SpecifiedStyle GetSpecifiedStyle() const { return mSpecifiedStyle; }
     55 
     56  EditorInlineStyle ToInlineStyle() const;
     57  EditorInlineStyleAndValue ToInlineStyleAndValue() const;
     58 
     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;
     71 };
     72 
     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)) {}
     90 
     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;
     95  }
     96 
     97  EditorInlineStyle ToInlineStyle() const;
     98 
     99 private:
    100  MOZ_KNOWN_LIVE nsStaticAtom& mTag;
    101  MOZ_KNOWN_LIVE nsStaticAtom* const mAttribute;
    102  const nsString mAttributeValueOrCSSValue;
    103 };
    104 
    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;
    115      }
    116    }
    117    return NoIndex;
    118  }
    119 
    120  [[nodiscard]] bool Contains(const nsStaticAtom& aTag,
    121                              const nsStaticAtom* aAttribute) const {
    122    return IndexOf(aTag, aAttribute) != NoIndex;
    123  }
    124 };
    125 
    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,
    133 };
    134 
    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)
    144 
    145  PendingStyles() = default;
    146 
    147  void Reset() {
    148    mClearingStyles.Clear();
    149    mPreservingStyles.Clear();
    150  }
    151 
    152  nsresult UpdateSelState(const HTMLEditor& aHTMLEditor);
    153 
    154  /**
    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.
    160   */
    161  void PreHandleMouseEvent(const dom::MouseEvent& aMouseDownOrUpEvent);
    162 
    163  void PreHandleSelectionChangeCommand(Command aCommand);
    164  void PostHandleSelectionChangeCommand(const HTMLEditor& aHTMLEditor,
    165                                        Command aCommand);
    166 
    167  void OnSelectionChange(const HTMLEditor& aHTMLEditor, int16_t aReason);
    168 
    169  /**
    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.
    173   *
    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.
    182   */
    183  void PreserveStyle(nsStaticAtom& aHTMLProperty, nsAtom* aAttribute,
    184                     const nsAString& aAttributeValueOrCSSValue);
    185 
    186  /**
    187   * Preserve the styles with new values in aStylesToPreserve.
    188   * See above for the detail.
    189   */
    190  void PreserveStyles(
    191      const nsTArray<EditorInlineStyleAndValue>& aStylesToPreserve);
    192 
    193  /**
    194   * Preserve the style with new value specified with aStyleToPreserve.
    195   * See above for the detail.
    196   */
    197  void PreserveStyle(const PendingStyleCache& aStyleToPreserve) {
    198    PreserveStyle(aStyleToPreserve.TagRef(), aStyleToPreserve.GetAttribute(),
    199                  aStyleToPreserve.AttributeValueOrCSSValueRef());
    200  }
    201 
    202  /**
    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.
    207   *
    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.
    213   */
    214  void ClearStyle(nsStaticAtom& aHTMLProperty, nsAtom* aAttribute) {
    215    ClearStyleInternal(&aHTMLProperty, aAttribute);
    216  }
    217 
    218  /**
    219   * Clear all styles specified by aStylesToClear when next content is inserted.
    220   * See above for the detail.
    221   */
    222  void ClearStyles(const nsTArray<EditorInlineStyle>& aStylesToClear);
    223 
    224  /**
    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.
    228   */
    229  void ClearAllStyles() {
    230    // XXX Why don't we clear mClearingStyles first?
    231    ClearStyleInternal(nullptr, nullptr);
    232  }
    233 
    234  /**
    235   * Clear <a> element and discard styles which is applied by it.
    236   */
    237  void ClearLinkAndItsSpecifiedStyle() {
    238    ClearStyleInternal(nsGkAtoms::a, nullptr, SpecifiedStyle::Discard);
    239  }
    240 
    241  /**
    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.
    245   */
    246  UniquePtr<PendingStyle> TakeClearingStyle() {
    247    if (mClearingStyles.IsEmpty()) {
    248      return nullptr;
    249    }
    250    return mClearingStyles.PopLastElement();
    251  }
    252 
    253  /**
    254   * TakeAllPreservedStyles() moves all preserved styles and values to
    255   * aOutStylesAndValues.
    256   */
    257  void TakeAllPreservedStyles(
    258      nsTArray<EditorInlineStyleAndValue>& aOutStylesAndValues);
    259 
    260  /**
    261   * TakeRelativeFontSize() hands back relative font value, which is then
    262   * cleared out.
    263   */
    264  int32_t TakeRelativeFontSize();
    265 
    266  /**
    267   * GetStyleState() returns whether the style will be applied to new content,
    268   * removed from new content or not changed.
    269   *
    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.
    278   */
    279  PendingStyleState GetStyleState(
    280      nsStaticAtom& aHTMLProperty, nsAtom* aAttribute = nullptr,
    281      nsString* aOutNewAttributeValueOrCSSValue = nullptr) const;
    282 
    283 protected:
    284  virtual ~PendingStyles() { Reset(); };
    285 
    286  void ClearStyleInternal(
    287      nsStaticAtom* aHTMLProperty, nsAtom* aAttribute,
    288      SpecifiedStyle aSpecifiedStyle = SpecifiedStyle::Preserve);
    289 
    290  void CancelPreservingStyle(nsStaticAtom* aHTMLProperty, nsAtom* aAttribute);
    291  void CancelClearingStyle(nsStaticAtom& aHTMLProperty, nsAtom* aAttribute);
    292 
    293  Maybe<size_t> IndexOfPreservingStyle(nsStaticAtom& aHTMLProperty,
    294                                       nsAtom* aAttribute,
    295                                       nsAString* aOutValue = nullptr) const {
    296    return IndexOfStyleInArray(&aHTMLProperty, aAttribute, aOutValue,
    297                               mPreservingStyles);
    298  }
    299  Maybe<size_t> IndexOfClearingStyle(nsStaticAtom* aHTMLProperty,
    300                                     nsAtom* aAttribute) const {
    301    return IndexOfStyleInArray(aHTMLProperty, aAttribute, nullptr,
    302                               mClearingStyles);
    303  }
    304 
    305  bool IsLinkStyleSet() const {
    306    return IndexOfPreservingStyle(*nsGkAtoms::a, nullptr).isSome();
    307  }
    308  bool IsExplicitlyLinkStyleCleared() const {
    309    return IndexOfClearingStyle(nsGkAtoms::a, nullptr).isSome();
    310  }
    311  bool IsOnlyLinkStyleCleared() const {
    312    return mClearingStyles.Length() == 1 && IsExplicitlyLinkStyleCleared();
    313  }
    314  bool IsStyleCleared(nsStaticAtom* aHTMLProperty, nsAtom* aAttribute) const {
    315    return IndexOfClearingStyle(aHTMLProperty, aAttribute).isSome() ||
    316           AreAllStylesCleared();
    317  }
    318  bool AreAllStylesCleared() const {
    319    return IndexOfClearingStyle(nullptr, nullptr).isSome();
    320  }
    321  bool AreSomeStylesSet() const { return !mPreservingStyles.IsEmpty(); }
    322  bool AreSomeStylesCleared() const { return !mClearingStyles.IsEmpty(); }
    323 
    324  static Maybe<size_t> IndexOfStyleInArray(
    325      nsStaticAtom* aHTMLProperty, nsAtom* aAttribute, nsAString* aOutValue,
    326      const nsTArray<UniquePtr<PendingStyle>>& aArray);
    327 
    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;
    335 };
    336 
    337 }  // namespace mozilla
    338 
    339 #endif  // #ifndef mozilla_PendingStyles_h