tor-browser

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

ContentEventHandler.h (28396B)


      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 
      7 #ifndef mozilla_ContentEventHandler_h_
      8 #define mozilla_ContentEventHandler_h_
      9 
     10 #include "js/GCAPI.h"
     11 #include "mozilla/Assertions.h"
     12 #include "mozilla/EventForwards.h"
     13 #include "mozilla/RangeBoundary.h"
     14 #include "mozilla/dom/Selection.h"
     15 #include "mozilla/dom/Text.h"
     16 #include "nsCOMPtr.h"
     17 #include "nsIFrame.h"
     18 #include "nsINode.h"
     19 
     20 class nsPresContext;
     21 class nsRange;
     22 
     23 struct nsRect;
     24 
     25 namespace mozilla {
     26 
     27 namespace dom {
     28 class Element;
     29 }  // namespace dom
     30 
     31 enum LineBreakType { LINE_BREAK_TYPE_NATIVE, LINE_BREAK_TYPE_XP };
     32 
     33 /*
     34 * Query Content Event Handler
     35 *   ContentEventHandler is a helper class for EventStateManager.
     36 *   The platforms request some content informations, e.g., the selected text,
     37 *   the offset of the selected text and the text for specified range.
     38 *   This class answers to NS_QUERY_* events from actual contents.
     39 */
     40 
     41 class MOZ_STACK_CLASS ContentEventHandler {
     42 private:
     43  /**
     44   * SimpleRangeBase is a helper template class of ContentEventHandler class
     45   * that stores 2 DOM points as a range without observing the mutation.  I.e.,
     46   * similar to dom::StaticRange, but can only be on the stack and does not have
     47   * unnecessary features for ContentEventHandler so it is fast.
     48   * Therefore, initializers are responsible for making sure the start/end nodes
     49   * are in document order. This is enforced by assertions in DEBUG builds.
     50   */
     51  template <typename NodeType, typename RangeBoundaryType>
     52  class MOZ_STACK_CLASS SimpleRangeBase final {
     53   public:
     54    SimpleRangeBase();
     55    SimpleRangeBase(SimpleRangeBase<NodeType, RangeBoundaryType>&&) noexcept;
     56    template <typename OtherNodeType, typename OtherRangeBoundaryType>
     57    explicit SimpleRangeBase(
     58        const SimpleRangeBase<OtherNodeType, OtherRangeBoundaryType>& aOther);
     59 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     60    ~SimpleRangeBase();
     61 #endif
     62 
     63    void Clear() {
     64      mRoot = nullptr;
     65      mStart = RangeBoundaryType{};
     66      mEnd = RangeBoundaryType{};
     67    }
     68 
     69    bool IsPositioned() const { return mStart.IsSet() && mEnd.IsSet(); }
     70    bool Collapsed() const { return mStart == mEnd && IsPositioned(); }
     71    nsINode* GetStartContainer() const { return mStart.GetContainer(); }
     72    nsINode* GetEndContainer() const { return mEnd.GetContainer(); }
     73    uint32_t StartOffset() const {
     74      return *mStart.Offset(
     75          RangeBoundaryType::OffsetFilter::kValidOrInvalidOffsets);
     76    }
     77    uint32_t EndOffset() const {
     78      return *mEnd.Offset(
     79          RangeBoundaryType::OffsetFilter::kValidOrInvalidOffsets);
     80    }
     81    nsIContent* StartRef() const { return mStart.Ref(); }
     82    nsIContent* EndRef() const { return mEnd.Ref(); }
     83 
     84    const RangeBoundaryType& Start() const { return mStart; }
     85    const RangeBoundaryType& End() const { return mEnd; }
     86 
     87    nsINode* GetRoot() const { return mRoot; }
     88 
     89    // XXX: Make these use RangeBoundaries...
     90    nsresult CollapseTo(const RawRangeBoundary& aBoundary) {
     91      return SetStartAndEnd(aBoundary, aBoundary);
     92    }
     93    nsresult SetStart(const RawRangeBoundary& aStart);
     94    nsresult SetEnd(const RawRangeBoundary& aEnd);
     95 
     96    // NOTE: These helpers can hide performance problems, as they perform a
     97    // search to find aStartOffset in aStartContainer.
     98    nsresult SetStart(nsINode* aStartContainer, uint32_t aStartOffset) {
     99      return SetStart(RawRangeBoundary(aStartContainer, aStartOffset));
    100    }
    101    nsresult SetEnd(nsINode* aEndContainer, uint32_t aEndOffset) {
    102      return SetEnd(RawRangeBoundary(aEndContainer, aEndOffset));
    103    }
    104 
    105    nsresult SetEndAfter(nsINode* aEndContainer);
    106    void SetStartAndEnd(const nsRange* aRange);
    107    nsresult SetStartAndEnd(const RawRangeBoundary& aStart,
    108                            const RawRangeBoundary& aEnd);
    109 
    110    nsresult SelectNodeContents(const nsINode* aNodeToSelectContents);
    111 
    112   private:
    113    inline void AssertStartIsBeforeOrEqualToEnd();
    114 
    115    NodeType mRoot;
    116 
    117    RangeBoundaryType mStart;
    118    RangeBoundaryType mEnd;
    119 
    120 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    121    nsMutationGuard mMutationGuard;
    122    Maybe<JS::AutoAssertNoGC> mAssertNoGC;
    123 #endif
    124  };
    125 
    126  using SimpleRange = SimpleRangeBase<RefPtr<nsINode>, RangeBoundary>;
    127  using UnsafeSimpleRange = SimpleRangeBase<nsINode*, RawRangeBoundary>;
    128 
    129 public:
    130  using Element = dom::Element;
    131  using Selection = dom::Selection;
    132 
    133  explicit ContentEventHandler(nsPresContext* aPresContext);
    134 
    135  // Handle aEvent in the current process.
    136  MOZ_CAN_RUN_SCRIPT nsresult
    137  HandleQueryContentEvent(WidgetQueryContentEvent* aEvent);
    138 
    139  // eQuerySelectedText event handler
    140  MOZ_CAN_RUN_SCRIPT nsresult
    141  OnQuerySelectedText(WidgetQueryContentEvent* aEvent);
    142  // eQueryTextContent event handler
    143  MOZ_CAN_RUN_SCRIPT nsresult
    144  OnQueryTextContent(WidgetQueryContentEvent* aEvent);
    145  // eQueryCaretRect event handler
    146  MOZ_CAN_RUN_SCRIPT nsresult OnQueryCaretRect(WidgetQueryContentEvent* aEvent);
    147  // eQueryTextRect event handler
    148  MOZ_CAN_RUN_SCRIPT nsresult OnQueryTextRect(WidgetQueryContentEvent* aEvent);
    149  // eQueryTextRectArray event handler
    150  MOZ_CAN_RUN_SCRIPT nsresult
    151  OnQueryTextRectArray(WidgetQueryContentEvent* aEvent);
    152  // eQueryEditorRect event handler
    153  MOZ_CAN_RUN_SCRIPT nsresult
    154  OnQueryEditorRect(WidgetQueryContentEvent* aEvent);
    155  // eQueryContentState event handler
    156  MOZ_CAN_RUN_SCRIPT nsresult
    157  OnQueryContentState(WidgetQueryContentEvent* aEvent);
    158  // eQuerySelectionAsTransferable event handler
    159  MOZ_CAN_RUN_SCRIPT nsresult
    160  OnQuerySelectionAsTransferable(WidgetQueryContentEvent* aEvent);
    161  // eQueryCharacterAtPoint event handler
    162  MOZ_CAN_RUN_SCRIPT nsresult
    163  OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent);
    164  // eQueryDOMWidgetHittest event handler
    165  MOZ_CAN_RUN_SCRIPT nsresult
    166  OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent);
    167  // eQueryDropTargetHittest event handler
    168  MOZ_CAN_RUN_SCRIPT nsresult
    169  OnQueryDropTargetHittest(WidgetQueryContentEvent* aEvent);
    170 
    171  // NS_SELECTION_* event
    172  MOZ_CAN_RUN_SCRIPT nsresult OnSelectionEvent(WidgetSelectionEvent* aEvent);
    173 
    174 protected:
    175  RefPtr<dom::Document> mDocument;
    176  // mSelection is typically normal selection but if OnQuerySelectedText()
    177  // is called, i.e., handling eQuerySelectedText, it's the specified selection
    178  // by WidgetQueryContentEvent::mInput::mSelectionType.
    179  RefPtr<Selection> mSelection;
    180  // mFirstSelectedSimpleRange is initialized from the first range of
    181  // mSelection, if it exists.  Otherwise, it is reset by Clear().
    182  SimpleRange mFirstSelectedSimpleRange;
    183  RefPtr<Element> mRootElement;
    184 
    185  MOZ_CAN_RUN_SCRIPT nsresult Init(WidgetQueryContentEvent* aEvent);
    186  MOZ_CAN_RUN_SCRIPT nsresult Init(WidgetSelectionEvent* aEvent);
    187 
    188  nsresult InitBasic(bool aRequireFlush = true);
    189  MOZ_CAN_RUN_SCRIPT nsresult
    190  InitCommon(EventMessage aEventMessage,
    191             SelectionType aSelectionType = SelectionType::eNormal,
    192             bool aRequireFlush = true);
    193  /**
    194   * InitRootContent() computes the root content of current focused editor.
    195   *
    196   * @param aNormalSelection    This must be a Selection instance whose type is
    197   *                            SelectionType::eNormal.
    198   */
    199  MOZ_CAN_RUN_SCRIPT nsresult
    200  InitRootContent(const Selection& aNormalSelection);
    201 
    202 public:
    203  // FlatText means the text that is generated from DOM tree. The BR elements
    204  // are replaced to native linefeeds. Other elements are ignored.
    205 
    206  // RawNodePosition stores a pair of node and offset in the node.
    207  // When mNode is an element and mOffset is 0, the start position means after
    208  // the open tag of mNode.
    209  // This is useful to receive one or more sets of them instead of nsRange.
    210  // This type is intended to be used for short-lived operations, and is thus
    211  // marked MOZ_STACK_CLASS.
    212  struct MOZ_STACK_CLASS RawNodePosition : public RawRangeBoundary {
    213    // Only when mNode is an element node and mOffset is 0, mAfterOpenTag is
    214    // referred.
    215    bool mAfterOpenTag = true;
    216 
    217    RawNodePosition() = default;
    218    MOZ_IMPLICIT RawNodePosition(const RawNodePosition& aOther)
    219        : RawRangeBoundary(aOther),
    220          mAfterOpenTag(aOther.mAfterOpenTag)
    221    // Don't use the copy constructor of mAssertNoGC.
    222    {}
    223 
    224    /**
    225     * Factory method returning a RawNodePosition object which points start of
    226     * first content of aContainer (first child or first character in the data).
    227     * I.e., if aContainer is an element node, the result points before the
    228     * first child but after the open tag, e.g., <div>{}abc</div> if aContainer
    229     * is the <div>.  This is important to understand the difference with the
    230     * result of Before().
    231     */
    232    static RawNodePosition BeforeFirstContentOf(const nsINode& aContainer) {
    233      return RawNodePosition(const_cast<nsINode*>(&aContainer), 0u);
    234    }
    235 
    236    /**
    237     * Factory method returning a RawNodePosition object which points after
    238     * aContent.  I.e., if aContent is an element node, the result points after
    239     * its close tag, e.g., `<div>abc</div>{}` if aContent is the <div>.
    240     */
    241    static RawNodePosition After(const nsIContent& aContent) {
    242      RawNodePosition it(aContent.GetParentNode(),
    243                         const_cast<nsIContent*>(&aContent));
    244      it.mAfterOpenTag = false;
    245      return it;
    246    }
    247 
    248    /**
    249     * Factory method returning a RawNodePosition object which points end of
    250     * aContainer.  If aContainer is an element node, the result points before
    251     * its close tag, e.g., `<div>abc{}</div>` if aContainer is the <div>.
    252     */
    253    static RawNodePosition AtEndOf(const nsINode& aContainer) {
    254      return RawNodePosition(const_cast<nsINode*>(&aContainer),
    255                             aContainer.IsText()
    256                                 ? aContainer.AsText()->TextDataLength()
    257                                 : aContainer.GetChildCount());
    258    }
    259 
    260    /**
    261     * Factory method returning a RawNodePosition object which points before
    262     * aContent.  I.e., if aContent is an element node, the result points
    263     * before its open tag, e.g., `{}<div>abc</div>` if aContent is the <div>.
    264     * Note that this sets different containers whether aContent is being
    265     * removed or not.  If aContent is being removed, i.e., this is used in
    266     * nsIMutationObserver::ContentRemoved(), aContent is already not a child
    267     * of its ex-parent.  Therefore, the container becomes aContent, but
    268     * indicates that it points before the container with mAfterOpenTag.
    269     * On the other hand, if it's not being removed, the container is set to
    270     * the parent node of aContent.  So, in this case, it points after the
    271     * previous sibling of aContent actually.
    272     */
    273    static RawNodePosition Before(const nsIContent& aContent) {
    274      return RawNodePosition(aContent.GetParentNode(),
    275                             aContent.GetPreviousSibling());
    276    }
    277 
    278    RawNodePosition(nsINode* aContainer, uint32_t aOffset)
    279        : RawRangeBoundary(aContainer, aOffset) {}
    280 
    281    RawNodePosition(nsINode* aContainer, nsIContent* aRef)
    282        : RawRangeBoundary(aContainer, aRef) {}
    283 
    284    explicit RawNodePosition(const nsIFrame::ContentOffsets& aContentOffsets)
    285        : RawRangeBoundary(aContentOffsets.content, aContentOffsets.offset) {}
    286 
    287 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    288    ~RawNodePosition() { MOZ_DIAGNOSTIC_ASSERT(!mMutationGuard.Mutated(0)); }
    289 #endif  // #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    290 
    291   public:
    292    const RawNodePosition& operator=(const RawNodePosition& aOther) {
    293      if (this != &aOther) {
    294        RawRangeBoundary::operator=(aOther);
    295        mAfterOpenTag = aOther.mAfterOpenTag;
    296      }
    297      return *this;
    298    }
    299 
    300    bool operator==(const RawNodePosition& aOther) const {
    301      return RawRangeBoundary::operator==(aOther) &&
    302             mAfterOpenTag == aOther.mAfterOpenTag;
    303    }
    304 
    305    bool IsBeforeOpenTag() const {
    306      return IsSet() && GetContainer()->IsElement() && !Ref() && !mAfterOpenTag;
    307    }
    308    bool IsImmediatelyAfterOpenTag() const {
    309      return IsSet() && GetContainer()->IsElement() && !Ref() && mAfterOpenTag;
    310    }
    311 
    312 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    313   private:
    314    nsMutationGuard mMutationGuard;
    315    JS::AutoAssertNoGC mAssertNoGC;
    316 #endif  // #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    317  };
    318 
    319  /**
    320   * Get the flatten text length in the range.
    321   * @param aStartPosition      Start node and offset in the node of the range.
    322   *                            If the container is an element node, it's
    323   *                            important to start from before or after its open
    324   *                            tag because open tag of some elements causes a
    325   *                            line break in the result.  If you need the line
    326   *                            break, you need to use
    327   *                            RawNodePosition::Before().
    328   * @param aEndPosition        End node and offset in the node of the range.
    329   *                            If you don't want to include line break which is
    330   *                            caused by the open tag of the container when
    331   *                            you specify start of an element node, you need
    332   *                            to use RawNodePosition::Before().
    333   * @param aRootElement        The root element of the editor or document.
    334   *                            aRootElement won't cause any text including
    335   *                            line breaks.
    336   * @param aLength             The result of the flatten text length of the
    337   *                            range.
    338   * @param aLineBreakType      Whether this computes flatten text length with
    339   *                            native line breakers on the platform or
    340   *                            with XP line breaker (\n).
    341   * @param aIsRemovingNode     Should be true only when this is called from
    342   *                            nsIMutationObserver::ContentRemoved().
    343   *                            When this is true, the container of
    344   *                            aStartPosition should be the removing node and
    345   *                            points start of it and the container of
    346   *                            aEndPosition must be same as the container of
    347   *                            aStartPosition and points end of the container.
    348   */
    349  static nsresult GetFlatTextLengthInRange(
    350      const RawNodePosition& aStartPosition,
    351      const RawNodePosition& aEndPosition, const Element* aRootElement,
    352      uint32_t* aLength, LineBreakType aLineBreakType,
    353      bool aIsRemovingNode = false);
    354 
    355  // Computes the native text length between aStartOffset and aEndOffset of
    356  // aTextNode.
    357  static uint32_t GetNativeTextLength(const dom::Text& aTextNode,
    358                                      uint32_t aStartOffset,
    359                                      uint32_t aEndOffset);
    360  // Get the native text length of aTextNode.
    361  static uint32_t GetNativeTextLength(const dom::Text& aTextNode,
    362                                      uint32_t aMaxLength = UINT32_MAX);
    363 
    364  static uint32_t GetNativeTextLength(const nsAString& aText);
    365 
    366  // Get the range between start offset and end offset
    367  MOZ_CAN_RUN_SCRIPT
    368  already_AddRefed<nsRange> GetRangeFromFlatTextOffset(
    369      WidgetContentCommandEvent* aEvent, uint32_t aOffset, uint32_t aLength);
    370 
    371  // Get the contents of aRange as plain text.
    372  nsresult GenerateFlatTextContent(const nsRange* aRange, nsString& aString);
    373 
    374 protected:
    375  // Get the text length of aTextNode.
    376  static uint32_t GetTextLength(const dom::Text& aTextNode,
    377                                LineBreakType aLineBreakType,
    378                                uint32_t aMaxLength = UINT32_MAX);
    379  // Get the text length of a given range of a content node in
    380  // the given line break type.
    381  static uint32_t GetTextLengthInRange(const dom::Text& aTextNode,
    382                                       uint32_t aXPStartOffset,
    383                                       uint32_t aXPEndOffset,
    384                                       LineBreakType aLineBreakType);
    385  // Get the contents in aElement (meaning all children of aElement) as plain
    386  // text.  E.g., specifying mRootElement gets whole text in it.
    387  // Note that the result is not same as .textContent.  The result is
    388  // optimized for native IMEs.  For example, <br> element and some block
    389  // elements causes "\n" (or "\r\n"), see also ShouldBreakLineBefore().
    390  nsresult GenerateFlatTextContent(const Element* aElement, nsString& aString,
    391                                   LineBreakType aLineBreakType);
    392  // Get the contents of aRange as plain text.
    393  template <typename NodeType, typename RangeBoundaryType>
    394  nsresult GenerateFlatTextContent(
    395      const SimpleRangeBase<NodeType, RangeBoundaryType>& aSimpleRange,
    396      nsString& aString, LineBreakType aLineBreakType);
    397  // Get offset of start of aRange.  Note that the result includes the length
    398  // of line breaker caused by the start of aContent because aRange never
    399  // includes the line breaker caused by its start node.
    400  template <typename SimpleRangeType>
    401  nsresult GetStartOffset(const SimpleRangeType& aSimpleRange,
    402                          uint32_t* aOffset, LineBreakType aLineBreakType);
    403  // Check if we should insert a line break before aContent.
    404  // This should return false only when aContent is an html element which
    405  // is typically used in a paragraph like <em>.
    406  static bool ShouldBreakLineBefore(const nsIContent& aContent,
    407                                    const Element* aRootElement);
    408  // Get the line breaker length.
    409  static inline uint32_t GetBRLength(LineBreakType aLineBreakType);
    410  static LineBreakType GetLineBreakType(WidgetQueryContentEvent* aEvent);
    411  static LineBreakType GetLineBreakType(WidgetSelectionEvent* aEvent);
    412  static LineBreakType GetLineBreakType(bool aUseNativeLineBreak);
    413  // Returns focused content (including its descendant documents).
    414  nsIContent* GetFocusedContent();
    415  // QueryContentRect() sets the rect of aContent's frame(s) to aEvent.
    416  nsresult QueryContentRect(nsIContent* aContent,
    417                            WidgetQueryContentEvent* aEvent);
    418 
    419  template <typename RangeType, typename TextNodeType>
    420  struct MOZ_STACK_CLASS DOMRangeAndAdjustedOffsetInFlattenedTextBase {
    421    bool RangeStartsFromLastTextNode() const {
    422      return mLastTextNode && mRange.GetStartContainer() == mLastTextNode;
    423    }
    424    bool RangeStartsFromEndOfContainer() const {
    425      return mRange.GetStartContainer() &&
    426             mRange.GetStartContainer()->Length() == mRange.StartOffset();
    427    }
    428    bool RangeStartsFromContent() const {
    429      return mRange.GetStartContainer() &&
    430             mRange.GetStartContainer()->IsContent();
    431    }
    432 
    433    // The range in the DOM tree.
    434    RangeType mRange;
    435    // Actual start offset of the range in the flattened text.  If aOffset
    436    // of ConvertFlatTextOffsetToDOMRange() is middle of a surrogate pair,
    437    // a CRLF or a complex character of some languages, this may be set to
    438    // different offset.
    439    uint32_t mAdjustedOffset = 0;
    440    // The last text node which is found while walking the tree.
    441    // If the range ends in a text node, this is the text node.  Otherwise,
    442    // the last found text node before the end container of mRange.
    443    TextNodeType mLastTextNode = nullptr;
    444  };
    445  using DOMRangeAndAdjustedOffsetInFlattenedText =
    446      DOMRangeAndAdjustedOffsetInFlattenedTextBase<SimpleRange,
    447                                                   RefPtr<dom::Text>>;
    448  using UnsafeDOMRangeAndAdjustedOffsetInFlattenedText =
    449      DOMRangeAndAdjustedOffsetInFlattenedTextBase<UnsafeSimpleRange,
    450                                                   dom::Text*>;
    451 
    452  /**
    453   * Scans the DOM tree and set mRange as same as from aOffset to aOffset +
    454   * aLength in the flattened text.
    455   * NOTE: Use ConvertFlatTextOffsetToDOMRange() or
    456   * ConvertFlatTextOffsetToUnsafeDOMRange() instead of
    457   * ConvertFlatTextOffsetToDOMRangeBase<RangeType, TextNodeType>().
    458   */
    459  template <typename RangeType, typename TextNodeType>
    460  Result<DOMRangeAndAdjustedOffsetInFlattenedTextBase<RangeType, TextNodeType>,
    461         nsresult>
    462  ConvertFlatTextOffsetToDOMRangeBase(uint32_t aOffset, uint32_t aLength,
    463                                      LineBreakType aLineBreakType,
    464                                      bool aExpandToClusterBoundaries);
    465  MOZ_ALWAYS_INLINE Result<DOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
    466  ConvertFlatTextOffsetToDOMRange(uint32_t aOffset, uint32_t aLength,
    467                                  LineBreakType aLineBreakType,
    468                                  bool aExpandToClusterBoundaries) {
    469    return ConvertFlatTextOffsetToDOMRangeBase<SimpleRange, RefPtr<dom::Text>>(
    470        aOffset, aLength, aLineBreakType, aExpandToClusterBoundaries);
    471  }
    472  MOZ_ALWAYS_INLINE
    473  Result<UnsafeDOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
    474  ConvertFlatTextOffsetToUnsafeDOMRange(uint32_t aOffset, uint32_t aLength,
    475                                        LineBreakType aLineBreakType,
    476                                        bool aExpandToClusterBoundaries) {
    477    return ConvertFlatTextOffsetToDOMRangeBase<UnsafeSimpleRange, dom::Text*>(
    478        aOffset, aLength, aLineBreakType, aExpandToClusterBoundaries);
    479  }
    480 
    481  // If the aSimpleRange isn't in text node but next to a text node,
    482  // this method modifies it in the text node.  Otherwise, not modified.
    483  // Note that aSimpleRange must be collapsed.
    484  nsresult AdjustCollapsedRangeMaybeIntoTextNode(SimpleRange& aSimpleRange);
    485  // Convert the frame relative offset to be relative to the root frame of the
    486  // root presContext (but still measured in appUnits of aFrame's presContext).
    487  nsresult ConvertToRootRelativeOffset(nsIFrame* aFrame, nsRect& aRect);
    488  // Expand aXPOffset to the nearest offset in cluster boundary. aForward is
    489  // true, it is expanded to forward.
    490  // FYI: Due to `nsFrameSelection::GetFrameForNodeOffset()`, this cannot
    491  //      take `const dom::Text&`.
    492  nsresult ExpandToClusterBoundary(dom::Text& aTextNode, bool aForward,
    493                                   uint32_t* aXPOffset) const;
    494 
    495  using FontRangeArray = nsTArray<mozilla::FontRange>;
    496  static void AppendFontRanges(FontRangeArray& aFontRanges,
    497                               const dom::Text& aTextNode, uint32_t aBaseOffset,
    498                               uint32_t aXPStartOffset, uint32_t aXPEndOffset,
    499                               LineBreakType aLineBreakType);
    500  nsresult GenerateFlatFontRanges(const UnsafeSimpleRange& aSimpleRange,
    501                                  FontRangeArray& aFontRanges,
    502                                  uint32_t& aLength,
    503                                  LineBreakType aLineBreakType);
    504  nsresult QueryTextRectByRange(const SimpleRange& aSimpleRange,
    505                                LayoutDeviceIntRect& aRect,
    506                                WritingMode& aWritingMode);
    507 
    508  struct MOZ_STACK_CLASS FrameAndNodeOffset final {
    509    // mFrame is safe since this can live in only stack class and
    510    // ContentEventHandler doesn't modify layout after
    511    // ContentEventHandler::Init() flushes pending layout.  In other words,
    512    // this struct shouldn't be used before calling
    513    // ContentEventHandler::Init().
    514    nsIFrame* mFrame;
    515    // offset in the node of mFrame
    516    int32_t mOffsetInNode;
    517 
    518    FrameAndNodeOffset() : mFrame(nullptr), mOffsetInNode(-1) {}
    519 
    520    FrameAndNodeOffset(nsIFrame* aFrame, int32_t aStartOffsetInNode)
    521        : mFrame(aFrame), mOffsetInNode(aStartOffsetInNode) {}
    522 
    523    nsIFrame* operator->() { return mFrame; }
    524    const nsIFrame* operator->() const { return mFrame; }
    525    operator nsIFrame*() { return mFrame; }
    526    operator const nsIFrame*() const { return mFrame; }
    527    bool IsValid() const { return mFrame && mOffsetInNode >= 0; }
    528  };
    529  // Get first frame after the start of the given range for computing text rect.
    530  // This returns invalid FrameAndNodeOffset if there is no content which
    531  // should affect to computing text rect in the range.  mOffsetInNode is start
    532  // offset in the frame.
    533  template <typename NodeType, typename RangeBoundaryType>
    534  FrameAndNodeOffset GetFirstFrameInRangeForTextRect(
    535      const SimpleRangeBase<NodeType, RangeBoundaryType>& aSimpleRange);
    536 
    537  // Get last frame before the end of the given range for computing text rect.
    538  // This returns invalid FrameAndNodeOffset if there is no content which
    539  // should affect to computing text rect in the range.  mOffsetInNode is end
    540  // offset in the frame.
    541  template <typename NodeType, typename RangeBoundaryType>
    542  FrameAndNodeOffset GetLastFrameInRangeForTextRect(
    543      const SimpleRangeBase<NodeType, RangeBoundaryType>& aSimpleRange);
    544 
    545  struct MOZ_STACK_CLASS FrameRelativeRect final {
    546    // mRect is relative to the mBaseFrame's position.
    547    nsRect mRect;
    548    nsIFrame* mBaseFrame;
    549 
    550    FrameRelativeRect() : mBaseFrame(nullptr) {}
    551 
    552    explicit FrameRelativeRect(nsIFrame* aBaseFrame) : mBaseFrame(aBaseFrame) {}
    553 
    554    FrameRelativeRect(const nsRect& aRect, nsIFrame* aBaseFrame)
    555        : mRect(aRect), mBaseFrame(aBaseFrame) {}
    556 
    557    bool IsValid() const { return mBaseFrame != nullptr; }
    558 
    559    // Returns an nsRect relative to aBaseFrame instead of mBaseFrame.
    560    nsRect RectRelativeTo(nsIFrame* aBaseFrame) const;
    561  };
    562 
    563  // Returns a rect for line breaker before the node of aFrame (If aFrame is
    564  // a <br> frame or a block level frame, it causes a line break at its
    565  // element's open tag, see also ShouldBreakLineBefore()).  Note that this
    566  // doesn't check if aFrame should cause line break in non-debug build.
    567  FrameRelativeRect GetLineBreakerRectBefore(nsIFrame* aFrame);
    568 
    569  // Returns a line breaker rect after aTextNode as there is a line breaker
    570  // immediately after aTextNode.  This is useful when following block
    571  // element causes a line break before it and it needs to compute the line
    572  // breaker's rect.  For example, if there is |<p>abc</p><p>def</p>|, the
    573  // rect of 2nd <p>'s line breaker should be at right of "c" in the first
    574  // <p>, not the start of 2nd <p>.  The result is relative to the last text
    575  // frame which represents the last character of aTextNode.
    576  FrameRelativeRect GuessLineBreakerRectAfter(const dom::Text& aTextNode);
    577 
    578  // Returns a guessed first rect.  I.e., it may be different from actual
    579  // caret when selection is collapsed at start of aFrame.  For example, this
    580  // guess the caret rect only with the content box of aFrame and its font
    581  // height like:
    582  // +-aFrame----------------- (border box)
    583  // |
    584  // |  +--------------------- (content box)
    585  // |  | I
    586  //      ^ guessed caret rect
    587  // However, actual caret is computed with more information like line-height,
    588  // child frames of aFrame etc.  But this does not emulate actual caret
    589  // behavior exactly for simpler and faster code because it's difficult and
    590  // we're not sure it's worthwhile to do it with complicated implementation.
    591  FrameRelativeRect GuessFirstCaretRectIn(nsIFrame* aFrame);
    592 
    593  // Make aRect non-empty.  If width and/or height is 0, these methods set them
    594  // to 1.  Note that it doesn't set nsRect's width nor height to one device
    595  // pixel because using nsRect::ToOutsidePixels() makes actual width or height
    596  // to 2 pixels because x and y may not be aligned to device pixels.
    597  void EnsureNonEmptyRect(nsRect& aRect) const;
    598  void EnsureNonEmptyRect(LayoutDeviceIntRect& aRect) const;
    599 
    600  /**
    601   * Compute caret rect before or after a character rect.
    602   */
    603  static LayoutDeviceIntRect GetCaretRectBefore(
    604      const LayoutDeviceIntRect& aCharRect, const WritingMode& aWritingMode);
    605  static LayoutDeviceIntRect GetCaretRectAfter(
    606      const LayoutDeviceIntRect& aCharRect, const WritingMode& aWritingMode);
    607  static nsRect GetCaretRectBefore(const nsRect& aCharRect,
    608                                   const WritingMode& aWritingMode);
    609  static nsRect GetCaretRectAfter(nsPresContext& aPresContext,
    610                                  const nsRect& aCharRect,
    611                                  const WritingMode& aWritingMode);
    612 
    613  nsresult QueryHittestImpl(WidgetQueryContentEvent* aEvent, bool aFlushLayout,
    614                            bool aPerformRetargeting,
    615                            Element** aContentUnderMouse);
    616 };
    617 
    618 }  // namespace mozilla
    619 
    620 #endif  // mozilla_ContentEventHandler_h_