tor-browser

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

ContentEventHandler.cpp (135706B)


      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 #include "ContentEventHandler.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "mozilla/Assertions.h"
     12 #include "mozilla/CheckedInt.h"
     13 #include "mozilla/ContentIterator.h"
     14 #include "mozilla/IMEStateManager.h"
     15 #include "mozilla/IntegerRange.h"
     16 #include "mozilla/Maybe.h"
     17 #include "mozilla/MiscEvents.h"
     18 #include "mozilla/PresShell.h"
     19 #include "mozilla/RangeBoundary.h"
     20 #include "mozilla/RangeUtils.h"
     21 #include "mozilla/SelectionMovementUtils.h"
     22 #include "mozilla/TextComposition.h"
     23 #include "mozilla/TextEditor.h"
     24 #include "mozilla/TextEvents.h"
     25 #include "mozilla/ViewportUtils.h"
     26 #include "mozilla/dom/CharacterDataBuffer.h"
     27 #include "mozilla/dom/Element.h"
     28 #include "mozilla/dom/HTMLBRElement.h"
     29 #include "mozilla/dom/HTMLUnknownElement.h"
     30 #include "mozilla/dom/Selection.h"
     31 #include "mozilla/dom/StaticRange.h"
     32 #include "mozilla/dom/Text.h"
     33 #include "nsCOMPtr.h"
     34 #include "nsCaret.h"
     35 #include "nsContentUtils.h"
     36 #include "nsCopySupport.h"
     37 #include "nsElementTable.h"
     38 #include "nsFocusManager.h"
     39 #include "nsFontMetrics.h"
     40 #include "nsFrameSelection.h"
     41 #include "nsHTMLTags.h"
     42 #include "nsIFrame.h"
     43 #include "nsLayoutUtils.h"
     44 #include "nsPresContext.h"
     45 #include "nsQueryObject.h"
     46 #include "nsRange.h"
     47 #include "nsTextFrame.h"
     48 
     49 // Work around conflicting define in rpcndr.h
     50 #if defined(small)
     51 #  undef small
     52 #endif  // defined(small)
     53 
     54 #if defined(XP_WIN) && 0
     55 #  define TRANSLATE_NEW_LINES
     56 #endif
     57 
     58 namespace mozilla {
     59 
     60 using namespace dom;
     61 using namespace widget;
     62 
     63 /******************************************************************/
     64 /* ContentEventHandler::SimpleRangeBase                           */
     65 /******************************************************************/
     66 template <>
     67 ContentEventHandler::SimpleRangeBase<
     68    RefPtr<nsINode>, RangeBoundary>::SimpleRangeBase() = default;
     69 
     70 template <>
     71 ContentEventHandler::SimpleRangeBase<nsINode*,
     72                                     RawRangeBoundary>::SimpleRangeBase()
     73    : mRoot(nullptr) {
     74 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     75  mAssertNoGC.emplace();
     76 #endif  // #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     77 }
     78 
     79 template <>
     80 template <typename OtherNodeType, typename OtherRangeBoundaryType>
     81 ContentEventHandler::SimpleRangeBase<RefPtr<nsINode>, RangeBoundary>::
     82    SimpleRangeBase(
     83        const SimpleRangeBase<OtherNodeType, OtherRangeBoundaryType>& aOther)
     84    : mRoot(aOther.GetRoot()),
     85      mStart{aOther.Start().AsRaw()},
     86      mEnd{aOther.End().AsRaw()}
     87 // Don't use the copy constructor of mAssertNoGC
     88 {}
     89 
     90 template <>
     91 template <typename OtherNodeType, typename OtherRangeBoundaryType>
     92 ContentEventHandler::SimpleRangeBase<nsINode*, RawRangeBoundary>::
     93    SimpleRangeBase(
     94        const SimpleRangeBase<OtherNodeType, OtherRangeBoundaryType>& aOther)
     95    : mRoot(aOther.GetRoot()),
     96      mStart{aOther.Start().AsRaw()},
     97      mEnd{aOther.End().AsRaw()} {
     98 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     99  mAssertNoGC.emplace();
    100 #endif  // #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    101 }
    102 
    103 template <>
    104 ContentEventHandler::SimpleRangeBase<RefPtr<nsINode>, RangeBoundary>::
    105    SimpleRangeBase(
    106        SimpleRangeBase<RefPtr<nsINode>, RangeBoundary>&& aOther) noexcept
    107    : mRoot(std::move(aOther.GetRoot())),
    108      mStart(std::move(aOther.mStart)),
    109      mEnd(std::move(aOther.mEnd)) {}
    110 
    111 template <>
    112 ContentEventHandler::SimpleRangeBase<nsINode*, RawRangeBoundary>::
    113    SimpleRangeBase(
    114        SimpleRangeBase<nsINode*, RawRangeBoundary>&& aOther) noexcept
    115    : mRoot(std::move(aOther.GetRoot())),
    116      mStart(std::move(aOther.mStart)),
    117      mEnd(std::move(aOther.mEnd)) {
    118 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    119  mAssertNoGC.emplace();
    120 #endif  // #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    121 }
    122 
    123 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    124 template <>
    125 ContentEventHandler::SimpleRangeBase<
    126    RefPtr<nsINode>, RangeBoundary>::~SimpleRangeBase() = default;
    127 
    128 template <>
    129 ContentEventHandler::SimpleRangeBase<nsINode*,
    130                                     RawRangeBoundary>::~SimpleRangeBase() {
    131  MOZ_DIAGNOSTIC_ASSERT(!mMutationGuard.Mutated(0));
    132 }
    133 #endif  // #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    134 
    135 template <typename NodeType, typename RangeBoundaryType>
    136 void ContentEventHandler::SimpleRangeBase<
    137    NodeType, RangeBoundaryType>::AssertStartIsBeforeOrEqualToEnd() {
    138  MOZ_ASSERT(*nsContentUtils::ComparePoints(mStart, mEnd) <= 0);
    139 }
    140 
    141 template <typename NodeType, typename RangeBoundaryType>
    142 nsresult
    143 ContentEventHandler::SimpleRangeBase<NodeType, RangeBoundaryType>::SetStart(
    144    const RawRangeBoundary& aStart) {
    145  nsINode* newRoot = RangeUtils::ComputeRootNode(aStart.GetContainer());
    146  if (!newRoot) {
    147    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    148  }
    149 
    150  if (!aStart.IsSetAndValid()) {
    151    return NS_ERROR_DOM_INDEX_SIZE_ERR;
    152  }
    153 
    154  // Collapse if not positioned yet, or if positioned in another document.
    155  if (!IsPositioned() || newRoot != mRoot) {
    156    mRoot = newRoot;
    157    mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes);
    158    mEnd.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes);
    159    return NS_OK;
    160  }
    161 
    162  mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes);
    163  AssertStartIsBeforeOrEqualToEnd();
    164  return NS_OK;
    165 }
    166 
    167 template <typename NodeType, typename RangeBoundaryType>
    168 nsresult
    169 ContentEventHandler::SimpleRangeBase<NodeType, RangeBoundaryType>::SetEnd(
    170    const RawRangeBoundary& aEnd) {
    171  nsINode* newRoot = RangeUtils::ComputeRootNode(aEnd.GetContainer());
    172  if (!newRoot) {
    173    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    174  }
    175 
    176  if (!aEnd.IsSetAndValid()) {
    177    return NS_ERROR_DOM_INDEX_SIZE_ERR;
    178  }
    179 
    180  // Collapse if not positioned yet, or if positioned in another document.
    181  if (!IsPositioned() || newRoot != mRoot) {
    182    mRoot = newRoot;
    183    mStart.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes);
    184    mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes);
    185    return NS_OK;
    186  }
    187 
    188  mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes);
    189  AssertStartIsBeforeOrEqualToEnd();
    190  return NS_OK;
    191 }
    192 
    193 template <typename NodeType, typename RangeBoundaryType>
    194 nsresult
    195 ContentEventHandler::SimpleRangeBase<NodeType, RangeBoundaryType>::SetEndAfter(
    196    nsINode* aEndContainer) {
    197  return SetEnd(RangeUtils::GetRawRangeBoundaryAfter(aEndContainer));
    198 }
    199 
    200 template <typename NodeType, typename RangeBoundaryType>
    201 void ContentEventHandler::SimpleRangeBase<
    202    NodeType, RangeBoundaryType>::SetStartAndEnd(const nsRange* aRange) {
    203  DebugOnly<nsresult> rv =
    204      SetStartAndEnd(aRange->StartRef().AsRaw(), aRange->EndRef().AsRaw());
    205  MOZ_ASSERT(!aRange->IsPositioned() || NS_SUCCEEDED(rv));
    206 }
    207 
    208 template <typename NodeType, typename RangeBoundaryType>
    209 nsresult ContentEventHandler::SimpleRangeBase<
    210    NodeType, RangeBoundaryType>::SetStartAndEnd(const RawRangeBoundary& aStart,
    211                                                 const RawRangeBoundary& aEnd) {
    212  nsINode* newStartRoot = RangeUtils::ComputeRootNode(aStart.GetContainer());
    213  if (!newStartRoot) {
    214    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    215  }
    216  if (!aStart.IsSetAndValid()) {
    217    return NS_ERROR_DOM_INDEX_SIZE_ERR;
    218  }
    219 
    220  if (aStart.GetContainer() == aEnd.GetContainer()) {
    221    if (!aEnd.IsSetAndValid()) {
    222      return NS_ERROR_DOM_INDEX_SIZE_ERR;
    223    }
    224    MOZ_ASSERT(*aStart.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets) <=
    225               *aEnd.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets));
    226    mRoot = newStartRoot;
    227    mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes);
    228    mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes);
    229    return NS_OK;
    230  }
    231 
    232  nsINode* newEndRoot = RangeUtils::ComputeRootNode(aEnd.GetContainer());
    233  if (!newEndRoot) {
    234    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    235  }
    236  if (!aEnd.IsSetAndValid()) {
    237    return NS_ERROR_DOM_INDEX_SIZE_ERR;
    238  }
    239 
    240  // If they have different root, this should be collapsed at the end point.
    241  if (newStartRoot != newEndRoot) {
    242    mRoot = newEndRoot;
    243    mStart.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes);
    244    mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes);
    245    return NS_OK;
    246  }
    247 
    248  // Otherwise, set the range as specified.
    249  mRoot = newStartRoot;
    250  mStart.CopyFrom(aStart, RangeBoundaryIsMutationObserved::Yes);
    251  mEnd.CopyFrom(aEnd, RangeBoundaryIsMutationObserved::Yes);
    252  AssertStartIsBeforeOrEqualToEnd();
    253  return NS_OK;
    254 }
    255 
    256 template <typename NodeType, typename RangeBoundaryType>
    257 nsresult ContentEventHandler::SimpleRangeBase<NodeType, RangeBoundaryType>::
    258    SelectNodeContents(const nsINode* aNodeToSelectContents) {
    259  nsINode* const newRoot =
    260      RangeUtils::ComputeRootNode(const_cast<nsINode*>(aNodeToSelectContents));
    261  if (!newRoot) {
    262    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
    263  }
    264  mRoot = newRoot;
    265  mStart =
    266      RangeBoundaryType(const_cast<nsINode*>(aNodeToSelectContents), nullptr);
    267  mEnd = RangeBoundaryType(const_cast<nsINode*>(aNodeToSelectContents),
    268                           aNodeToSelectContents->GetLastChild());
    269  return NS_OK;
    270 }
    271 
    272 /******************************************************************/
    273 /* ContentEventHandler                                            */
    274 /******************************************************************/
    275 
    276 // NOTE
    277 //
    278 // ContentEventHandler *creates* ranges as following rules:
    279 // 1. Start of range:
    280 //   1.1. Cases: [textNode or text[Node or textNode[
    281 //        When text node is start of a range, start node is the text node and
    282 //        start offset is any number between 0 and the length of the text.
    283 //   1.2. Case: [<element>:
    284 //        When start of an element node is start of a range, start node is
    285 //        parent of the element and start offset is the element's index in the
    286 //        parent.
    287 //   1.3. Case: <element/>[
    288 //        When after an empty element node is start of a range, start node is
    289 //        parent of the element and start offset is the element's index in the
    290 //        parent + 1.
    291 //   1.4. Case: <element>[
    292 //        When start of a non-empty element is start of a range, start node is
    293 //        the element and start offset is 0.
    294 //   1.5. Case: <root>[
    295 //        When start of a range is 0 and there are no nodes causing text,
    296 //        start node is the root node and start offset is 0.
    297 //   1.6. Case: [</root>
    298 //        When start of a range is out of bounds, start node is the root node
    299 //        and start offset is number of the children.
    300 // 2. End of range:
    301 //   2.1. Cases: ]textNode or text]Node or textNode]
    302 //        When a text node is end of a range, end node is the text node and
    303 //        end offset is any number between 0 and the length of the text.
    304 //   2.2. Case: ]<element>
    305 //        When before an element node (meaning before the open tag of the
    306 //        element) is end of a range, end node is previous node causing text.
    307 //        Note that this case shouldn't be handled directly.  If rule 2.1 and
    308 //        2.3 are handled correctly, the loop with ContentIterator shouldn't
    309 //        reach the element node since the loop should've finished already at
    310 //        handling the last node which caused some text.
    311 //   2.3. Case: <element>]
    312 //        When a line break is caused before a non-empty element node and it's
    313 //        end of a range, end node is the element and end offset is 0.
    314 //        (i.e., including open tag of the element)
    315 //   2.4. Cases: <element/>]
    316 //        When after an empty element node is end of a range, end node is
    317 //        parent of the element node and end offset is the element's index in
    318 //        the parent + 1.  (i.e., including close tag of the element or empty
    319 //        element)
    320 //   2.5. Case: ]</root>
    321 //        When end of a range is out of bounds, end node is the root node and
    322 //        end offset is number of the children.
    323 //
    324 // ContentEventHandler *treats* ranges as following additional rules:
    325 // 1. When the start node is an element node which doesn't have children,
    326 //    it includes a line break caused before itself (i.e., includes its open
    327 //    tag).  For example, if start position is { <br>, 0 }, the line break
    328 //    caused by <br> should be included into the flatten text.
    329 // 2. When the end node is an element node which doesn't have children,
    330 //    it includes the end (i.e., includes its close tag except empty element).
    331 //    Although, currently, any close tags don't cause line break, this also
    332 //    includes its open tag.  For example, if end position is { <br>, 0 }, the
    333 //    line break caused by the <br> should be included into the flatten text.
    334 
    335 ContentEventHandler::ContentEventHandler(nsPresContext* aPresContext)
    336    : mDocument(aPresContext->Document()) {}
    337 
    338 nsresult ContentEventHandler::InitBasic(bool aRequireFlush) {
    339  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
    340  if (aRequireFlush) {
    341    // If text frame which has overflowing selection underline is dirty,
    342    // we need to flush the pending reflow here.
    343    mDocument->FlushPendingNotifications(FlushType::Layout);
    344  }
    345  return NS_OK;
    346 }
    347 
    348 nsresult ContentEventHandler::InitRootContent(
    349    const Selection& aNormalSelection) {
    350  // Root content should be computed with normal selection because normal
    351  // selection is typically has at least one range but the other selections
    352  // not so.  If there is a range, computing its root is easy, but if
    353  // there are no ranges, we need to use ancestor limit instead.
    354  MOZ_ASSERT(aNormalSelection.Type() == SelectionType::eNormal);
    355 
    356  if (!aNormalSelection.RangeCount()) {
    357    // If there is no selection range, we should compute the selection root
    358    // from ancestor limiter or root content of the document.
    359    mRootElement = aNormalSelection.GetAncestorLimiter();
    360    if (!mRootElement) {
    361      mRootElement = mDocument->GetRootElement();
    362      if (NS_WARN_IF(!mRootElement)) {
    363        return NS_ERROR_NOT_AVAILABLE;
    364      }
    365    }
    366    return NS_OK;
    367  }
    368 
    369  RefPtr<const nsRange> range(aNormalSelection.GetRangeAt(0));
    370  if (NS_WARN_IF(!range)) {
    371    return NS_ERROR_UNEXPECTED;
    372  }
    373 
    374  // If there is a selection, we should retrieve the selection root from
    375  // the range since when the window is inactivated, the ancestor limiter
    376  // of selection was cleared by blur event handler of EditorBase but the
    377  // selection range still keeps storing the nodes.  If the active element of
    378  // the deactive window is <input> or <textarea>, we can compute the
    379  // selection root from them.
    380  nsCOMPtr<nsINode> startNode = range->GetStartContainer();
    381  nsINode* endNode = range->GetEndContainer();
    382  if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode)) {
    383    return NS_ERROR_FAILURE;
    384  }
    385 
    386  // See bug 537041 comment 5, the range could have removed node.
    387  if (NS_WARN_IF(startNode->GetComposedDoc() != mDocument)) {
    388    return NS_ERROR_FAILURE;
    389  }
    390 
    391  NS_ASSERTION(startNode->GetComposedDoc() == endNode->GetComposedDoc(),
    392               "firstNormalSelectionRange crosses the document boundary");
    393 
    394  RefPtr<PresShell> presShell = mDocument->GetPresShell();
    395  mRootElement = Element::FromNodeOrNull(startNode->GetSelectionRootContent(
    396      presShell, nsINode::IgnoreOwnIndependentSelection::Yes,
    397      nsINode::AllowCrossShadowBoundary::No));
    398  if (NS_WARN_IF(!mRootElement)) {
    399    return NS_ERROR_FAILURE;
    400  }
    401 
    402  return NS_OK;
    403 }
    404 
    405 nsresult ContentEventHandler::InitCommon(EventMessage aEventMessage,
    406                                         SelectionType aSelectionType,
    407                                         bool aRequireFlush) {
    408  if (mSelection && mSelection->Type() == aSelectionType) {
    409    return NS_OK;
    410  }
    411 
    412  mSelection = nullptr;
    413  mRootElement = nullptr;
    414  mFirstSelectedSimpleRange.Clear();
    415 
    416  nsresult rv = InitBasic(aRequireFlush);
    417  NS_ENSURE_SUCCESS(rv, rv);
    418 
    419  RefPtr<nsFrameSelection> frameSel;
    420  if (PresShell* presShell = mDocument->GetPresShell()) {
    421    frameSel = presShell->GetLastFocusedFrameSelection();
    422  }
    423  if (NS_WARN_IF(!frameSel)) {
    424    return NS_ERROR_NOT_AVAILABLE;
    425  }
    426 
    427  mSelection = frameSel->GetSelection(aSelectionType);
    428  if (NS_WARN_IF(!mSelection)) {
    429    return NS_ERROR_NOT_AVAILABLE;
    430  }
    431 
    432  RefPtr<Selection> normalSelection;
    433  if (mSelection->Type() == SelectionType::eNormal) {
    434    normalSelection = mSelection;
    435  } else {
    436    normalSelection = &frameSel->NormalSelection();
    437    MOZ_ASSERT(normalSelection);
    438  }
    439 
    440  rv = InitRootContent(*normalSelection);
    441  if (NS_WARN_IF(NS_FAILED(rv))) {
    442    return rv;
    443  }
    444 
    445  if (mSelection->RangeCount()) {
    446    mFirstSelectedSimpleRange.SetStartAndEnd(mSelection->GetRangeAt(0));
    447    return NS_OK;
    448  }
    449 
    450  // Even if there are no selection ranges, it's usual case if aSelectionType
    451  // is a special selection or we're handling eQuerySelectedText.
    452  if (aSelectionType != SelectionType::eNormal ||
    453      aEventMessage == eQuerySelectedText) {
    454    MOZ_ASSERT(!mFirstSelectedSimpleRange.IsPositioned());
    455    return NS_OK;
    456  }
    457 
    458  // But otherwise, we need to assume that there is a selection range at the
    459  // beginning of the root content if aSelectionType is eNormal.
    460  rv = mFirstSelectedSimpleRange.CollapseTo(RawRangeBoundary(mRootElement, 0u));
    461  if (NS_WARN_IF(NS_FAILED(rv))) {
    462    return NS_ERROR_UNEXPECTED;
    463  }
    464  return NS_OK;
    465 }
    466 
    467 nsresult ContentEventHandler::Init(WidgetQueryContentEvent* aEvent) {
    468  NS_ASSERTION(aEvent, "aEvent must not be null");
    469  MOZ_ASSERT(aEvent->mMessage == eQuerySelectedText ||
    470             aEvent->mInput.mSelectionType == SelectionType::eNormal);
    471 
    472  if (NS_WARN_IF(!aEvent->mInput.IsValidOffset()) ||
    473      NS_WARN_IF(!aEvent->mInput.IsValidEventMessage(aEvent->mMessage))) {
    474    return NS_ERROR_FAILURE;
    475  }
    476 
    477  // Note that we should ignore WidgetQueryContentEvent::Input::mSelectionType
    478  // if the event isn't eQuerySelectedText.
    479  SelectionType selectionType = aEvent->mMessage == eQuerySelectedText
    480                                    ? aEvent->mInput.mSelectionType
    481                                    : SelectionType::eNormal;
    482  if (NS_WARN_IF(selectionType == SelectionType::eNone)) {
    483    return NS_ERROR_FAILURE;
    484  }
    485 
    486  nsresult rv = InitCommon(aEvent->mMessage, selectionType,
    487                           aEvent->AllowFlushingPendingNotifications());
    488  NS_ENSURE_SUCCESS(rv, rv);
    489 
    490  // Be aware, WidgetQueryContentEvent::mInput::mOffset should be made absolute
    491  // offset before sending it to ContentEventHandler because querying selection
    492  // every time may be expensive.  So, if the caller caches selection, it
    493  // should initialize the event with the cached value.
    494  if (aEvent->mInput.mRelativeToInsertionPoint) {
    495    MOZ_ASSERT(selectionType == SelectionType::eNormal);
    496    TextComposition* composition =
    497        IMEStateManager::GetTextCompositionFor(aEvent->mWidget);
    498    if (composition) {
    499      uint32_t compositionStart = composition->NativeOffsetOfStartComposition();
    500      if (NS_WARN_IF(!aEvent->mInput.MakeOffsetAbsolute(compositionStart))) {
    501        return NS_ERROR_FAILURE;
    502      }
    503    } else {
    504      LineBreakType lineBreakType = GetLineBreakType(aEvent);
    505      uint32_t selectionStart = 0;
    506      rv = GetStartOffset(mFirstSelectedSimpleRange, &selectionStart,
    507                          lineBreakType);
    508      if (NS_WARN_IF(NS_FAILED(rv))) {
    509        return NS_ERROR_FAILURE;
    510      }
    511      if (NS_WARN_IF(!aEvent->mInput.MakeOffsetAbsolute(selectionStart))) {
    512        return NS_ERROR_FAILURE;
    513      }
    514    }
    515  }
    516 
    517  // Ideally, we should emplace only when we return succeeded event.
    518  // However, we need to emplace here since it's hard to store the various
    519  // result.  Intead, `HandleQueryContentEvent()` will reset `mReply` if
    520  // corresponding handler returns error.
    521  aEvent->EmplaceReply();
    522 
    523  aEvent->mReply->mContentsRoot = mRootElement.get();
    524  aEvent->mReply->mIsEditableContent =
    525      mRootElement && mRootElement->IsEditable();
    526 
    527  nsRect r;
    528  nsIFrame* frame = nsCaret::GetGeometry(mSelection, &r);
    529  if (!frame) {
    530    frame = mRootElement->GetPrimaryFrame();
    531    if (NS_WARN_IF(!frame)) {
    532      return NS_ERROR_FAILURE;
    533    }
    534  }
    535  aEvent->mReply->mFocusedWidget = frame->GetNearestWidget();
    536 
    537  return NS_OK;
    538 }
    539 
    540 nsresult ContentEventHandler::Init(WidgetSelectionEvent* aEvent) {
    541  NS_ASSERTION(aEvent, "aEvent must not be null");
    542 
    543  nsresult rv = InitCommon(aEvent->mMessage);
    544  NS_ENSURE_SUCCESS(rv, rv);
    545 
    546  aEvent->mSucceeded = false;
    547 
    548  return NS_OK;
    549 }
    550 
    551 nsIContent* ContentEventHandler::GetFocusedContent() {
    552  nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
    553  nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    554  return nsFocusManager::GetFocusedDescendant(
    555      window, nsFocusManager::eIncludeAllDescendants,
    556      getter_AddRefs(focusedWindow));
    557 }
    558 
    559 nsresult ContentEventHandler::QueryContentRect(
    560    nsIContent* aContent, WidgetQueryContentEvent* aEvent) {
    561  MOZ_ASSERT(aContent, "aContent must not be null");
    562 
    563  nsIFrame* frame = aContent->GetPrimaryFrame();
    564  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
    565 
    566  // get rect for first frame
    567  nsRect resultRect(nsPoint(0, 0), frame->GetRect().Size());
    568  nsresult rv = ConvertToRootRelativeOffset(frame, resultRect);
    569  NS_ENSURE_SUCCESS(rv, rv);
    570 
    571  nsPresContext* presContext = frame->PresContext();
    572 
    573  // account for any additional frames
    574  while ((frame = frame->GetNextContinuation())) {
    575    nsRect frameRect(nsPoint(0, 0), frame->GetRect().Size());
    576    rv = ConvertToRootRelativeOffset(frame, frameRect);
    577    NS_ENSURE_SUCCESS(rv, rv);
    578    resultRect.UnionRect(resultRect, frameRect);
    579  }
    580 
    581  aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
    582      resultRect, presContext->AppUnitsPerDevPixel());
    583  // Returning empty rect may cause native IME confused, let's make sure to
    584  // return non-empty rect.
    585  EnsureNonEmptyRect(aEvent->mReply->mRect);
    586 
    587  return NS_OK;
    588 }
    589 
    590 // Editor places a padding <br> element under its root content if the editor
    591 // doesn't have any text. This happens even for single line editors.
    592 // When we get text content and when we change the selection,
    593 // we don't want to include the padding <br> elements at the end.
    594 static bool IsContentBR(const nsIContent& aContent) {
    595  const HTMLBRElement* brElement = HTMLBRElement::FromNode(aContent);
    596  return brElement && !brElement->IsPaddingForEmptyLastLine() &&
    597         !brElement->IsPaddingForEmptyEditor();
    598 }
    599 
    600 static bool IsPaddingBR(const nsIContent& aContent) {
    601  return aContent.IsHTMLElement(nsGkAtoms::br) && !IsContentBR(aContent);
    602 }
    603 
    604 static void ConvertToNativeNewlines(nsString& aString) {
    605 #if defined(TRANSLATE_NEW_LINES)
    606  aString.ReplaceSubstring(u"\n"_ns, u"\r\n"_ns);
    607 #endif
    608 }
    609 
    610 static void AppendString(nsString& aString, const Text& aTextNode) {
    611  const uint32_t oldXPLength = aString.Length();
    612  aTextNode.DataBuffer().AppendTo(aString);
    613  if (aTextNode.HasFlag(NS_MAYBE_MASKED)) {
    614    TextEditor::MaskString(aString, aTextNode, oldXPLength, 0);
    615  }
    616 }
    617 
    618 static void AppendSubString(nsString& aString, const Text& aTextNode,
    619                            uint32_t aXPOffset, uint32_t aXPLength) {
    620  const uint32_t oldXPLength = aString.Length();
    621  aTextNode.DataBuffer().AppendTo(aString, aXPOffset, aXPLength);
    622  if (aTextNode.HasFlag(NS_MAYBE_MASKED)) {
    623    TextEditor::MaskString(aString, aTextNode, oldXPLength, aXPOffset);
    624  }
    625 }
    626 
    627 #if defined(TRANSLATE_NEW_LINES)
    628 template <typename StringType>
    629 static uint32_t CountNewlinesInXPLength(const StringType& aString) {
    630  uint32_t count = 0;
    631  const auto* end = aString.EndReading();
    632  for (const auto* iter = aString.BeginReading(); iter < end; ++iter) {
    633    if (*iter == '\n') {
    634      count++;
    635    }
    636  }
    637  return count;
    638 }
    639 
    640 static uint32_t CountNewlinesInXPLength(const Text& aTextNode,
    641                                        uint32_t aXPLength) {
    642  const CharacterDataBuffer& characterDataBuffer = aTextNode.DataBuffer();
    643  // For automated tests, we should abort on debug build.
    644  MOZ_ASSERT(
    645      aXPLength == UINT32_MAX || aXPLength <= characterDataBuffer.GetLength(),
    646      "aXPLength is out-of-bounds");
    647  const uint32_t length = std::min(aXPLength, characterDataBuffer.GetLength());
    648  if (!length) {
    649    return 0;
    650  }
    651  if (characterDataBuffer.Is2b()) {
    652    nsDependentSubstring str(characterDataBuffer.Get2b(), length);
    653    return CountNewlinesInXPLength(str);
    654  }
    655  nsDependentCSubstring str(characterDataBuffer.Get1b(), length);
    656  return CountNewlinesInXPLength(str);
    657 }
    658 
    659 template <typename StringType>
    660 static uint32_t CountNewlinesInNativeLength(const StringType& aString,
    661                                            uint32_t aNativeLength) {
    662  MOZ_ASSERT(
    663      (aNativeLength == UINT32_MAX || aNativeLength <= aString.Length() * 2),
    664      "aNativeLength is unexpected value");
    665  uint32_t count = 0;
    666  uint32_t nativeOffset = 0;
    667  const auto* end = aString.EndReading();
    668  for (const auto* iter = aString.BeginReading();
    669       iter < end && nativeOffset < aNativeLength; ++iter, ++nativeOffset) {
    670    if (*iter == '\n') {
    671      count++;
    672      nativeOffset++;
    673    }
    674  }
    675  return count;
    676 }
    677 
    678 static uint32_t CountNewlinesInNativeLength(const Text& aTextNode,
    679                                            uint32_t aNativeLength) {
    680  const CharacterDataBuffer& characterDataBuffer = aTextNode.DataBuffer();
    681  const uint32_t xpLength = characterDataBuffer.GetLength();
    682  if (!xpLength) {
    683    return 0;
    684  }
    685  if (characterDataBuffer.Is2b()) {
    686    nsDependentSubstring str(characterDataBuffer.Get2b(), xpLength);
    687    return CountNewlinesInNativeLength(str, aNativeLength);
    688  }
    689  nsDependentCSubstring str(characterDataBuffer.Get1b(), xpLength);
    690  return CountNewlinesInNativeLength(str, aNativeLength);
    691 }
    692 #endif
    693 
    694 /* static */
    695 uint32_t ContentEventHandler::GetNativeTextLength(const Text& aTextNode,
    696                                                  uint32_t aStartOffset,
    697                                                  uint32_t aEndOffset) {
    698  MOZ_ASSERT(aEndOffset >= aStartOffset,
    699             "aEndOffset must be equals or larger than aStartOffset");
    700  if (aStartOffset == aEndOffset) {
    701    return 0;
    702  }
    703  return GetTextLength(aTextNode, LINE_BREAK_TYPE_NATIVE, aEndOffset) -
    704         GetTextLength(aTextNode, LINE_BREAK_TYPE_NATIVE, aStartOffset);
    705 }
    706 
    707 /* static */
    708 uint32_t ContentEventHandler::GetNativeTextLength(const Text& aTextNode,
    709                                                  uint32_t aMaxLength) {
    710  return GetTextLength(aTextNode, LINE_BREAK_TYPE_NATIVE, aMaxLength);
    711 }
    712 
    713 /* static inline */
    714 uint32_t ContentEventHandler::GetBRLength(LineBreakType aLineBreakType) {
    715 #if defined(TRANSLATE_NEW_LINES)
    716  // Length of \r\n
    717  return (aLineBreakType == LINE_BREAK_TYPE_NATIVE) ? 2 : 1;
    718 #else
    719  return 1;
    720 #endif
    721 }
    722 
    723 /* static */
    724 uint32_t ContentEventHandler::GetTextLength(const Text& aTextNode,
    725                                            LineBreakType aLineBreakType,
    726                                            uint32_t aMaxLength) {
    727  const uint32_t textLengthDifference =
    728 #if defined(TRANSLATE_NEW_LINES)
    729      // On Windows, the length of a native newline ("\r\n") is twice the length
    730      // of the XP newline ("\n"), so XP length is equal to the length of the
    731      // native offset plus the number of newlines encountered in the string.
    732      (aLineBreakType == LINE_BREAK_TYPE_NATIVE)
    733          ? CountNewlinesInXPLength(aTextNode, aMaxLength)
    734          : 0;
    735 #else
    736      // On other platforms, the native and XP newlines are the same.
    737      0;
    738 #endif
    739 
    740  const uint32_t length =
    741      std::min(aTextNode.DataBuffer().GetLength(), aMaxLength);
    742  return length + textLengthDifference;
    743 }
    744 
    745 static uint32_t ConvertToXPOffset(const Text& aTextNode,
    746                                  uint32_t aNativeOffset) {
    747 #if defined(TRANSLATE_NEW_LINES)
    748  // On Windows, the length of a native newline ("\r\n") is twice the length of
    749  // the XP newline ("\n"), so XP offset is equal to the length of the native
    750  // offset minus the number of newlines encountered in the string.
    751  return aNativeOffset - CountNewlinesInNativeLength(aTextNode, aNativeOffset);
    752 #else
    753  // On other platforms, the native and XP newlines are the same.
    754  return aNativeOffset;
    755 #endif
    756 }
    757 
    758 /* static */
    759 uint32_t ContentEventHandler::GetNativeTextLength(const nsAString& aText) {
    760  const uint32_t textLengthDifference =
    761 #if defined(TRANSLATE_NEW_LINES)
    762      // On Windows, the length of a native newline ("\r\n") is twice the length
    763      // of the XP newline ("\n"), so XP length is equal to the length of the
    764      // native offset plus the number of newlines encountered in the string.
    765      CountNewlinesInXPLength(aText);
    766 #else
    767      // On other platforms, the native and XP newlines are the same.
    768      0;
    769 #endif
    770  return aText.Length() + textLengthDifference;
    771 }
    772 
    773 /* static */
    774 bool ContentEventHandler::ShouldBreakLineBefore(const nsIContent& aContent,
    775                                                const Element* aRootElement) {
    776  // We don't need to append linebreak at the start of the root element.
    777  if (&aContent == aRootElement) {
    778    return false;
    779  }
    780 
    781  // If it's not an HTML element (including other markup language's elements),
    782  // we shouldn't insert like break before that for now.  Becoming this is a
    783  // problem must be edge case.  E.g., when ContentEventHandler is used with
    784  // MathML or SVG elements.
    785  if (!aContent.IsHTMLElement()) {
    786    return false;
    787  }
    788 
    789  switch (
    790      nsHTMLTags::CaseSensitiveAtomTagToId(aContent.NodeInfo()->NameAtom())) {
    791    case eHTMLTag_br:
    792      // If the element is <br>, we need to check if the <br> is caused by web
    793      // content.  Otherwise, i.e., it's caused by internal reason of Gecko,
    794      // it shouldn't be exposed as a line break to flatten text.
    795      return IsContentBR(aContent);
    796    case eHTMLTag_a:
    797    case eHTMLTag_abbr:
    798    case eHTMLTag_acronym:
    799    case eHTMLTag_b:
    800    case eHTMLTag_bdi:
    801    case eHTMLTag_bdo:
    802    case eHTMLTag_big:
    803    case eHTMLTag_cite:
    804    case eHTMLTag_code:
    805    case eHTMLTag_data:
    806    case eHTMLTag_del:
    807    case eHTMLTag_dfn:
    808    case eHTMLTag_em:
    809    case eHTMLTag_font:
    810    case eHTMLTag_i:
    811    case eHTMLTag_ins:
    812    case eHTMLTag_kbd:
    813    case eHTMLTag_mark:
    814    case eHTMLTag_s:
    815    case eHTMLTag_samp:
    816    case eHTMLTag_small:
    817    case eHTMLTag_span:
    818    case eHTMLTag_strike:
    819    case eHTMLTag_strong:
    820    case eHTMLTag_sub:
    821    case eHTMLTag_sup:
    822    case eHTMLTag_time:
    823    case eHTMLTag_tt:
    824    case eHTMLTag_u:
    825    case eHTMLTag_var:
    826      // Note that ideally, we should refer the style of the primary frame of
    827      // aContent for deciding if it's an inline.  However, it's difficult
    828      // IMEContentObserver to notify IME of text change caused by style change.
    829      // Therefore, currently, we should check only from the tag for now.
    830      return false;
    831    case eHTMLTag_userdefined:
    832    case eHTMLTag_unknown:
    833      // If the element is unknown element, we shouldn't insert line breaks
    834      // before it since unknown elements should be ignored.
    835      return false;
    836    default:
    837      return true;
    838  }
    839 }
    840 
    841 nsresult ContentEventHandler::GenerateFlatTextContent(
    842    const Element* aElement, nsString& aString, LineBreakType aLineBreakType) {
    843  MOZ_ASSERT(aString.IsEmpty());
    844 
    845  UnsafeSimpleRange rawRange;
    846  nsresult rv = rawRange.SelectNodeContents(aElement);
    847  if (NS_WARN_IF(NS_FAILED(rv))) {
    848    return rv;
    849  }
    850  return GenerateFlatTextContent(rawRange, aString, aLineBreakType);
    851 }
    852 
    853 nsresult ContentEventHandler::GenerateFlatTextContent(const nsRange* aRange,
    854                                                      nsString& aString) {
    855  MOZ_ASSERT(aString.IsEmpty());
    856 
    857  if (NS_WARN_IF(!aRange)) {
    858    return NS_ERROR_FAILURE;
    859  }
    860 
    861  UnsafeSimpleRange rawRange;
    862  rawRange.SetStartAndEnd(aRange);
    863 
    864  return GenerateFlatTextContent(rawRange, aString, LINE_BREAK_TYPE_NATIVE);
    865 }
    866 
    867 template <typename NodeType, typename RangeBoundaryType>
    868 nsresult ContentEventHandler::GenerateFlatTextContent(
    869    const SimpleRangeBase<NodeType, RangeBoundaryType>& aSimpleRange,
    870    nsString& aString, LineBreakType aLineBreakType) {
    871  MOZ_ASSERT(aString.IsEmpty());
    872 
    873  if (aSimpleRange.Collapsed()) {
    874    return NS_OK;
    875  }
    876 
    877  nsINode* startNode = aSimpleRange.GetStartContainer();
    878  nsINode* endNode = aSimpleRange.GetEndContainer();
    879  if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode)) {
    880    return NS_ERROR_FAILURE;
    881  }
    882 
    883  if (startNode == endNode && startNode->IsText()) {
    884    AppendSubString(aString, *startNode->AsText(), aSimpleRange.StartOffset(),
    885                    aSimpleRange.EndOffset() - aSimpleRange.StartOffset());
    886    ConvertToNativeNewlines(aString);
    887    return NS_OK;
    888  }
    889 
    890  UnsafePreContentIterator preOrderIter;
    891  nsresult rv = preOrderIter.Init(aSimpleRange.Start().AsRaw(),
    892                                  aSimpleRange.End().AsRaw());
    893  if (NS_WARN_IF(NS_FAILED(rv))) {
    894    return rv;
    895  }
    896  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
    897    nsINode* node = preOrderIter.GetCurrentNode();
    898    if (NS_WARN_IF(!node)) {
    899      break;
    900    }
    901    if (!node->IsContent()) {
    902      continue;
    903    }
    904 
    905    if (const Text* textNode = Text::FromNode(node)) {
    906      if (textNode == startNode) {
    907        AppendSubString(aString, *textNode, aSimpleRange.StartOffset(),
    908                        textNode->TextLength() - aSimpleRange.StartOffset());
    909      } else if (textNode == endNode) {
    910        AppendSubString(aString, *textNode, 0, aSimpleRange.EndOffset());
    911      } else {
    912        AppendString(aString, *textNode);
    913      }
    914    } else if (ShouldBreakLineBefore(*node->AsContent(), mRootElement)) {
    915      aString.Append(char16_t('\n'));
    916    }
    917  }
    918  if (aLineBreakType == LINE_BREAK_TYPE_NATIVE) {
    919    ConvertToNativeNewlines(aString);
    920  }
    921  return NS_OK;
    922 }
    923 
    924 static FontRange* AppendFontRange(nsTArray<FontRange>& aFontRanges,
    925                                  uint32_t aBaseOffset) {
    926  FontRange* fontRange = aFontRanges.AppendElement();
    927  fontRange->mStartOffset = aBaseOffset;
    928  return fontRange;
    929 }
    930 
    931 /* static */
    932 uint32_t ContentEventHandler::GetTextLengthInRange(
    933    const Text& aTextNode, uint32_t aXPStartOffset, uint32_t aXPEndOffset,
    934    LineBreakType aLineBreakType) {
    935  return aLineBreakType == LINE_BREAK_TYPE_NATIVE
    936             ? GetNativeTextLength(aTextNode, aXPStartOffset, aXPEndOffset)
    937             : aXPEndOffset - aXPStartOffset;
    938 }
    939 
    940 /* static */
    941 void ContentEventHandler::AppendFontRanges(FontRangeArray& aFontRanges,
    942                                           const Text& aTextNode,
    943                                           uint32_t aBaseOffset,
    944                                           uint32_t aXPStartOffset,
    945                                           uint32_t aXPEndOffset,
    946                                           LineBreakType aLineBreakType) {
    947  nsIFrame* frame = aTextNode.GetPrimaryFrame();
    948  if (!frame) {
    949    // It is a non-rendered content, create an empty range for it.
    950    AppendFontRange(aFontRanges, aBaseOffset);
    951    return;
    952  }
    953 
    954  uint32_t baseOffset = aBaseOffset;
    955 #ifdef DEBUG
    956  {
    957    nsTextFrame* text = do_QueryFrame(frame);
    958    MOZ_ASSERT(text, "Not a text frame");
    959  }
    960 #endif
    961  auto* curr = static_cast<nsTextFrame*>(frame);
    962  while (curr) {
    963    uint32_t frameXPStart = std::max(
    964        static_cast<uint32_t>(curr->GetContentOffset()), aXPStartOffset);
    965    uint32_t frameXPEnd =
    966        std::min(static_cast<uint32_t>(curr->GetContentEnd()), aXPEndOffset);
    967    if (frameXPStart >= frameXPEnd) {
    968      curr = curr->GetNextContinuation();
    969      continue;
    970    }
    971 
    972    gfxSkipCharsIterator iter = curr->EnsureTextRun(nsTextFrame::eInflated);
    973    gfxTextRun* textRun = curr->GetTextRun(nsTextFrame::eInflated);
    974 
    975    nsTextFrame* next = nullptr;
    976    if (frameXPEnd < aXPEndOffset) {
    977      next = curr->GetNextContinuation();
    978      while (next && next->GetTextRun(nsTextFrame::eInflated) == textRun) {
    979        frameXPEnd = std::min(static_cast<uint32_t>(next->GetContentEnd()),
    980                              aXPEndOffset);
    981        next =
    982            frameXPEnd < aXPEndOffset ? next->GetNextContinuation() : nullptr;
    983      }
    984    }
    985 
    986    gfxTextRun::Range skipRange(iter.ConvertOriginalToSkipped(frameXPStart),
    987                                iter.ConvertOriginalToSkipped(frameXPEnd));
    988    uint32_t lastXPEndOffset = frameXPStart;
    989    for (gfxTextRun::GlyphRunIterator runIter(textRun, skipRange);
    990         !runIter.AtEnd(); runIter.NextRun()) {
    991      gfxFont* font = runIter.GlyphRun()->mFont.get();
    992      uint32_t startXPOffset =
    993          iter.ConvertSkippedToOriginal(runIter.StringStart());
    994      // It is possible that the first glyph run has exceeded the frame,
    995      // because the whole frame is filled by skipped chars.
    996      if (startXPOffset >= frameXPEnd) {
    997        break;
    998      }
    999 
   1000      if (startXPOffset > lastXPEndOffset) {
   1001        // Create range for skipped leading chars.
   1002        AppendFontRange(aFontRanges, baseOffset);
   1003        baseOffset += GetTextLengthInRange(aTextNode, lastXPEndOffset,
   1004                                           startXPOffset, aLineBreakType);
   1005      }
   1006 
   1007      FontRange* fontRange = AppendFontRange(aFontRanges, baseOffset);
   1008      fontRange->mFontName.Append(NS_ConvertUTF8toUTF16(font->GetName()));
   1009 
   1010      ParentLayerToScreenScale2D cumulativeResolution =
   1011          ParentLayerToParentLayerScale(
   1012              frame->PresShell()->GetCumulativeResolution()) *
   1013          nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
   1014              frame);
   1015      float scale =
   1016          std::max(cumulativeResolution.xScale, cumulativeResolution.yScale);
   1017 
   1018      fontRange->mFontSize = font->GetAdjustedSize() * scale;
   1019 
   1020      // The converted original offset may exceed the range,
   1021      // hence we need to clamp it.
   1022      uint32_t endXPOffset = iter.ConvertSkippedToOriginal(runIter.StringEnd());
   1023      endXPOffset = std::min(frameXPEnd, endXPOffset);
   1024      baseOffset += GetTextLengthInRange(aTextNode, startXPOffset, endXPOffset,
   1025                                         aLineBreakType);
   1026      lastXPEndOffset = endXPOffset;
   1027    }
   1028    if (lastXPEndOffset < frameXPEnd) {
   1029      // Create range for skipped trailing chars. It also handles case
   1030      // that the whole frame contains only skipped chars.
   1031      AppendFontRange(aFontRanges, baseOffset);
   1032      baseOffset += GetTextLengthInRange(aTextNode, lastXPEndOffset, frameXPEnd,
   1033                                         aLineBreakType);
   1034    }
   1035 
   1036    curr = next;
   1037  }
   1038 }
   1039 
   1040 nsresult ContentEventHandler::GenerateFlatFontRanges(
   1041    const UnsafeSimpleRange& aSimpleRange, FontRangeArray& aFontRanges,
   1042    uint32_t& aLength, LineBreakType aLineBreakType) {
   1043  MOZ_ASSERT(aFontRanges.IsEmpty(), "aRanges must be empty array");
   1044 
   1045  if (aSimpleRange.Collapsed()) {
   1046    return NS_OK;
   1047  }
   1048 
   1049  nsINode* startNode = aSimpleRange.GetStartContainer();
   1050  nsINode* endNode = aSimpleRange.GetEndContainer();
   1051  if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode)) {
   1052    return NS_ERROR_FAILURE;
   1053  }
   1054 
   1055  // baseOffset is the flattened offset of each content node.
   1056  uint32_t baseOffset = 0;
   1057  UnsafePreContentIterator preOrderIter;
   1058  nsresult rv = preOrderIter.Init(aSimpleRange.Start().AsRaw(),
   1059                                  aSimpleRange.End().AsRaw());
   1060  if (NS_WARN_IF(NS_FAILED(rv))) {
   1061    return rv;
   1062  }
   1063  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
   1064    nsINode* node = preOrderIter.GetCurrentNode();
   1065    if (NS_WARN_IF(!node)) {
   1066      break;
   1067    }
   1068    if (!node->IsContent()) {
   1069      continue;
   1070    }
   1071    nsIContent* content = node->AsContent();
   1072 
   1073    if (const Text* textNode = Text::FromNode(content)) {
   1074      const uint32_t startOffset =
   1075          textNode != startNode ? 0 : aSimpleRange.StartOffset();
   1076      const uint32_t endOffset = textNode != endNode ? textNode->TextLength()
   1077                                                     : aSimpleRange.EndOffset();
   1078      AppendFontRanges(aFontRanges, *textNode, baseOffset, startOffset,
   1079                       endOffset, aLineBreakType);
   1080      baseOffset += GetTextLengthInRange(*textNode, startOffset, endOffset,
   1081                                         aLineBreakType);
   1082    } else if (ShouldBreakLineBefore(*content, mRootElement)) {
   1083      if (aFontRanges.IsEmpty()) {
   1084        MOZ_ASSERT(baseOffset == 0);
   1085        FontRange* fontRange = AppendFontRange(aFontRanges, baseOffset);
   1086        if (nsIFrame* frame = content->GetPrimaryFrame()) {
   1087          const nsFont& font = frame->GetParent()->StyleFont()->mFont;
   1088          const StyleFontFamilyList& fontList = font.family.families;
   1089          MOZ_ASSERT(!fontList.list.IsEmpty(), "Empty font family?");
   1090          const StyleSingleFontFamily* fontName =
   1091              fontList.list.IsEmpty() ? nullptr : &fontList.list.AsSpan()[0];
   1092          nsAutoCString name;
   1093          if (fontName) {
   1094            fontName->AppendToString(name, false);
   1095          }
   1096          AppendUTF8toUTF16(name, fontRange->mFontName);
   1097 
   1098          ParentLayerToScreenScale2D cumulativeResolution =
   1099              ParentLayerToParentLayerScale(
   1100                  frame->PresShell()->GetCumulativeResolution()) *
   1101              nsLayoutUtils::
   1102                  GetTransformToAncestorScaleCrossProcessForFrameMetrics(frame);
   1103 
   1104          float scale = std::max(cumulativeResolution.xScale,
   1105                                 cumulativeResolution.yScale);
   1106 
   1107          fontRange->mFontSize = frame->PresContext()->CSSPixelsToDevPixels(
   1108              font.size.ToCSSPixels() * scale);
   1109        }
   1110      }
   1111      baseOffset += GetBRLength(aLineBreakType);
   1112    }
   1113  }
   1114 
   1115  aLength = baseOffset;
   1116  return NS_OK;
   1117 }
   1118 
   1119 nsresult ContentEventHandler::ExpandToClusterBoundary(
   1120    Text& aTextNode, bool aForward, uint32_t* aXPOffset) const {
   1121  // XXX This method assumes that the frame boundaries must be cluster
   1122  // boundaries. It's false, but no problem now, maybe.
   1123  if (*aXPOffset == 0 || *aXPOffset == aTextNode.TextLength()) {
   1124    return NS_OK;
   1125  }
   1126 
   1127  NS_ASSERTION(*aXPOffset <= aTextNode.TextLength(), "offset is out of range.");
   1128 
   1129  MOZ_DIAGNOSTIC_ASSERT(mDocument->GetPresShell());
   1130  CaretAssociationHint hint =
   1131      aForward ? CaretAssociationHint::Before : CaretAssociationHint::After;
   1132  FrameAndOffset frameAndOffset = SelectionMovementUtils::GetFrameForNodeOffset(
   1133      &aTextNode, int32_t(*aXPOffset), hint);
   1134  if (frameAndOffset) {
   1135    auto [startOffset, endOffset] = frameAndOffset->GetOffsets();
   1136    if (*aXPOffset == static_cast<uint32_t>(startOffset) ||
   1137        *aXPOffset == static_cast<uint32_t>(endOffset)) {
   1138      return NS_OK;
   1139    }
   1140    if (!frameAndOffset->IsTextFrame()) {
   1141      return NS_ERROR_FAILURE;
   1142    }
   1143    nsTextFrame* textFrame = static_cast<nsTextFrame*>(frameAndOffset.mFrame);
   1144    int32_t newOffsetInFrame = *aXPOffset - startOffset;
   1145    newOffsetInFrame += aForward ? -1 : 1;
   1146    // PeekOffsetCharacter() should respect cluster but ignore user-select
   1147    // style.  If it returns "FOUND", we should use the result.  Otherwise,
   1148    // we shouldn't use the result because the offset was moved to reversed
   1149    // direction.
   1150    nsTextFrame::PeekOffsetCharacterOptions options;
   1151    options.mRespectClusters = true;
   1152    options.mIgnoreUserStyleAll = true;
   1153    if (textFrame->PeekOffsetCharacter(aForward, &newOffsetInFrame, options) ==
   1154        nsIFrame::FOUND) {
   1155      *aXPOffset = startOffset + newOffsetInFrame;
   1156      return NS_OK;
   1157    }
   1158  }
   1159 
   1160  // If the frame isn't available, we only can check surrogate pair...
   1161  if (aTextNode.DataBuffer().IsLowSurrogateFollowingHighSurrogateAt(
   1162          *aXPOffset)) {
   1163    *aXPOffset += aForward ? 1 : -1;
   1164  }
   1165  return NS_OK;
   1166 }
   1167 
   1168 already_AddRefed<nsRange> ContentEventHandler::GetRangeFromFlatTextOffset(
   1169    WidgetContentCommandEvent* aEvent, uint32_t aOffset, uint32_t aLength) {
   1170  nsresult rv = InitCommon(aEvent->mMessage);
   1171  if (NS_WARN_IF(NS_FAILED(rv))) {
   1172    return nullptr;
   1173  }
   1174 
   1175  Result<DOMRangeAndAdjustedOffsetInFlattenedText, nsresult> result =
   1176      ConvertFlatTextOffsetToDOMRange(aOffset, aLength, LINE_BREAK_TYPE_NATIVE,
   1177                                      false);
   1178  if (NS_WARN_IF(result.isErr())) {
   1179    return nullptr;
   1180  }
   1181 
   1182  DOMRangeAndAdjustedOffsetInFlattenedText domRangeAndAdjustOffset =
   1183      result.unwrap();
   1184 
   1185  return nsRange::Create(domRangeAndAdjustOffset.mRange.Start(),
   1186                         domRangeAndAdjustOffset.mRange.End(), IgnoreErrors());
   1187 }
   1188 
   1189 template <typename RangeType, typename TextNodeType>
   1190 Result<ContentEventHandler::DOMRangeAndAdjustedOffsetInFlattenedTextBase<
   1191           RangeType, TextNodeType>,
   1192       nsresult>
   1193 ContentEventHandler::ConvertFlatTextOffsetToDOMRangeBase(
   1194    uint32_t aOffset, uint32_t aLength, LineBreakType aLineBreakType,
   1195    bool aExpandToClusterBoundaries) {
   1196  DOMRangeAndAdjustedOffsetInFlattenedTextBase<RangeType, TextNodeType> result;
   1197  result.mAdjustedOffset = aOffset;
   1198 
   1199  // Special case like <br contenteditable>
   1200  if (!mRootElement->HasChildren()) {
   1201    nsresult rv = result.mRange.CollapseTo(RawRangeBoundary(mRootElement, 0u));
   1202    if (NS_WARN_IF(NS_FAILED(rv))) {
   1203      return Err(rv);
   1204    }
   1205  }
   1206 
   1207  UnsafePreContentIterator preOrderIter;
   1208  nsresult rv = preOrderIter.Init(mRootElement);
   1209  if (NS_WARN_IF(NS_FAILED(rv))) {
   1210    return Err(rv);
   1211  }
   1212 
   1213  uint32_t offset = 0;
   1214  uint32_t endOffset = aOffset + aLength;
   1215  bool startSet = false;
   1216  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
   1217    nsINode* node = preOrderIter.GetCurrentNode();
   1218    if (NS_WARN_IF(!node)) {
   1219      break;
   1220    }
   1221    // FYI: mRootElement shouldn't cause any text. So, we can skip it simply.
   1222    if (node == mRootElement || !node->IsContent()) {
   1223      continue;
   1224    }
   1225    nsIContent* const content = node->AsContent();
   1226    Text* const contentAsText = Text::FromNode(content);
   1227 
   1228    if (contentAsText) {
   1229      result.mLastTextNode = contentAsText;
   1230    }
   1231 
   1232    uint32_t textLength = contentAsText
   1233                              ? GetTextLength(*contentAsText, aLineBreakType)
   1234                              : (ShouldBreakLineBefore(*content, mRootElement)
   1235                                     ? GetBRLength(aLineBreakType)
   1236                                     : 0);
   1237    if (!textLength) {
   1238      continue;
   1239    }
   1240 
   1241    // When the start offset is in between accumulated offset and the last
   1242    // offset of the node, the node is the start node of the range.
   1243    if (!startSet && aOffset <= offset + textLength) {
   1244      nsINode* startNode = nullptr;
   1245      Maybe<uint32_t> startNodeOffset;
   1246      if (contentAsText) {
   1247        // Rule #1.1: [textNode or text[Node or textNode[
   1248        uint32_t xpOffset = aOffset - offset;
   1249        if (aLineBreakType == LINE_BREAK_TYPE_NATIVE) {
   1250          xpOffset = ConvertToXPOffset(*contentAsText, xpOffset);
   1251        }
   1252 
   1253        if (aExpandToClusterBoundaries) {
   1254          const uint32_t oldXPOffset = xpOffset;
   1255          nsresult rv =
   1256              ExpandToClusterBoundary(*contentAsText, false, &xpOffset);
   1257          if (NS_WARN_IF(NS_FAILED(rv))) {
   1258            return Err(rv);
   1259          }
   1260          // This is correct since a cluster shouldn't include line break.
   1261          result.mAdjustedOffset -= (oldXPOffset - xpOffset);
   1262        }
   1263        startNode = contentAsText;
   1264        startNodeOffset = Some(xpOffset);
   1265      } else if (aOffset < offset + textLength) {
   1266        // Rule #1.2 [<element>
   1267        startNode = content->GetParent();
   1268        if (NS_WARN_IF(!startNode)) {
   1269          return Err(NS_ERROR_FAILURE);
   1270        }
   1271        startNodeOffset = startNode->ComputeIndexOf(content);
   1272        if (NS_WARN_IF(startNodeOffset.isNothing())) {
   1273          // The content is being removed from the parent!
   1274          return Err(NS_ERROR_FAILURE);
   1275        }
   1276      } else if (!content->HasChildren()) {
   1277        // Rule #1.3: <element/>[
   1278        startNode = content->GetParent();
   1279        if (NS_WARN_IF(!startNode)) {
   1280          return Err(NS_ERROR_FAILURE);
   1281        }
   1282        startNodeOffset = startNode->ComputeIndexOf(content);
   1283        if (NS_WARN_IF(startNodeOffset.isNothing())) {
   1284          // The content is being removed from the parent!
   1285          return Err(NS_ERROR_FAILURE);
   1286        }
   1287        MOZ_ASSERT(*startNodeOffset != UINT32_MAX);
   1288        ++(*startNodeOffset);
   1289      } else {
   1290        // Rule #1.4: <element>[
   1291        startNode = content;
   1292        startNodeOffset = Some(0);
   1293      }
   1294      NS_ASSERTION(startNode, "startNode must not be nullptr");
   1295      MOZ_ASSERT(startNodeOffset.isSome(),
   1296                 "startNodeOffset must not be Nothing");
   1297      rv = result.mRange.SetStart(startNode, *startNodeOffset);
   1298      if (NS_WARN_IF(NS_FAILED(rv))) {
   1299        return Err(rv);
   1300      }
   1301      startSet = true;
   1302 
   1303      if (!aLength) {
   1304        rv = result.mRange.SetEnd(startNode, *startNodeOffset);
   1305        if (NS_WARN_IF(NS_FAILED(rv))) {
   1306          return Err(rv);
   1307        }
   1308        return result;
   1309      }
   1310    }
   1311 
   1312    // When the end offset is in the content, the node is the end node of the
   1313    // range.
   1314    if (endOffset <= offset + textLength) {
   1315      MOZ_ASSERT(startSet, "The start of the range should've been set already");
   1316      if (contentAsText) {
   1317        // Rule #2.1: ]textNode or text]Node or textNode]
   1318        uint32_t xpOffset = endOffset - offset;
   1319        if (aLineBreakType == LINE_BREAK_TYPE_NATIVE) {
   1320          const uint32_t xpOffsetCurrent =
   1321              ConvertToXPOffset(*contentAsText, xpOffset);
   1322          if (xpOffset && GetBRLength(aLineBreakType) > 1) {
   1323            MOZ_ASSERT(GetBRLength(aLineBreakType) == 2);
   1324            const uint32_t xpOffsetPre =
   1325                ConvertToXPOffset(*contentAsText, xpOffset - 1);
   1326            // If previous character's XP offset is same as current character's,
   1327            // it means that the end offset is between \r and \n.  So, the
   1328            // range end should be after the \n.
   1329            if (xpOffsetPre == xpOffsetCurrent) {
   1330              xpOffset = xpOffsetCurrent + 1;
   1331            } else {
   1332              xpOffset = xpOffsetCurrent;
   1333            }
   1334          }
   1335        }
   1336        if (aExpandToClusterBoundaries) {
   1337          nsresult rv =
   1338              ExpandToClusterBoundary(*contentAsText, true, &xpOffset);
   1339          if (NS_WARN_IF(NS_FAILED(rv))) {
   1340            return Err(rv);
   1341          }
   1342        }
   1343        NS_ASSERTION(xpOffset <= INT32_MAX, "The end node offset is too large");
   1344        nsresult rv = result.mRange.SetEnd(contentAsText, xpOffset);
   1345        if (NS_WARN_IF(NS_FAILED(rv))) {
   1346          return Err(rv);
   1347        }
   1348        return result;
   1349      }
   1350 
   1351      if (endOffset == offset) {
   1352        // Rule #2.2: ]<element>
   1353        // NOTE: Please don't crash on release builds because it must be
   1354        //       overreaction but we shouldn't allow this bug when some
   1355        //       automated tests find this.
   1356        MOZ_ASSERT(false,
   1357                   "This case should've already been handled at "
   1358                   "the last node which caused some text");
   1359        return Err(NS_ERROR_FAILURE);
   1360      }
   1361 
   1362      if (content->HasChildren() &&
   1363          ShouldBreakLineBefore(*content, mRootElement)) {
   1364        // Rule #2.3: </element>]
   1365        rv = result.mRange.SetEnd(content, 0);
   1366        if (NS_WARN_IF(NS_FAILED(rv))) {
   1367          return Err(rv);
   1368        }
   1369        return result;
   1370      }
   1371 
   1372      // Rule #2.4: <element/>]
   1373      nsINode* endNode = content->GetParent();
   1374      if (NS_WARN_IF(!endNode)) {
   1375        return Err(NS_ERROR_FAILURE);
   1376      }
   1377      const Maybe<uint32_t> indexInParent = endNode->ComputeIndexOf(content);
   1378      if (NS_WARN_IF(indexInParent.isNothing())) {
   1379        // The content is being removed from the parent!
   1380        return Err(NS_ERROR_FAILURE);
   1381      }
   1382      MOZ_ASSERT(*indexInParent != UINT32_MAX);
   1383      rv = result.mRange.SetEnd(endNode, *indexInParent + 1);
   1384      if (NS_WARN_IF(NS_FAILED(rv))) {
   1385        return Err(rv);
   1386      }
   1387      return result;
   1388    }
   1389 
   1390    offset += textLength;
   1391  }
   1392 
   1393  if (!startSet) {
   1394    if (!offset) {
   1395      // Rule #1.5: <root>[</root>
   1396      // When there are no nodes causing text, the start of the DOM range
   1397      // should be start of the root node since clicking on such editor (e.g.,
   1398      // <div contenteditable><span></span></div>) sets caret to the start of
   1399      // the editor (i.e., before <span> in the example).
   1400      rv = result.mRange.SetStart(mRootElement, 0);
   1401      if (NS_WARN_IF(NS_FAILED(rv))) {
   1402        return Err(rv);
   1403      }
   1404      if (!aLength) {
   1405        rv = result.mRange.SetEnd(mRootElement, 0);
   1406        if (NS_WARN_IF(NS_FAILED(rv))) {
   1407          return Err(rv);
   1408        }
   1409        return result;
   1410      }
   1411    } else {
   1412      // Rule #1.5: [</root>
   1413      rv = result.mRange.SetStart(mRootElement, mRootElement->GetChildCount());
   1414      if (NS_WARN_IF(NS_FAILED(rv))) {
   1415        return result;
   1416      }
   1417    }
   1418    result.mAdjustedOffset = offset;
   1419  }
   1420  // Rule #2.5: ]</root>
   1421  rv = result.mRange.SetEnd(mRootElement, mRootElement->GetChildCount());
   1422  if (NS_WARN_IF(NS_FAILED(rv))) {
   1423    return Err(rv);
   1424  }
   1425  return result;
   1426 }
   1427 
   1428 /* static */
   1429 LineBreakType ContentEventHandler::GetLineBreakType(
   1430    WidgetQueryContentEvent* aEvent) {
   1431  return GetLineBreakType(aEvent->mUseNativeLineBreak);
   1432 }
   1433 
   1434 /* static */
   1435 LineBreakType ContentEventHandler::GetLineBreakType(
   1436    WidgetSelectionEvent* aEvent) {
   1437  return GetLineBreakType(aEvent->mUseNativeLineBreak);
   1438 }
   1439 
   1440 /* static */
   1441 LineBreakType ContentEventHandler::GetLineBreakType(bool aUseNativeLineBreak) {
   1442  return aUseNativeLineBreak ? LINE_BREAK_TYPE_NATIVE : LINE_BREAK_TYPE_XP;
   1443 }
   1444 
   1445 nsresult ContentEventHandler::HandleQueryContentEvent(
   1446    WidgetQueryContentEvent* aEvent) {
   1447  nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
   1448  switch (aEvent->mMessage) {
   1449    case eQuerySelectedText:
   1450      rv = OnQuerySelectedText(aEvent);
   1451      break;
   1452    case eQueryTextContent:
   1453      rv = OnQueryTextContent(aEvent);
   1454      break;
   1455    case eQueryCaretRect:
   1456      rv = OnQueryCaretRect(aEvent);
   1457      break;
   1458    case eQueryTextRect:
   1459      rv = OnQueryTextRect(aEvent);
   1460      break;
   1461    case eQueryTextRectArray:
   1462      rv = OnQueryTextRectArray(aEvent);
   1463      break;
   1464    case eQueryEditorRect:
   1465      rv = OnQueryEditorRect(aEvent);
   1466      break;
   1467    case eQueryContentState:
   1468      rv = OnQueryContentState(aEvent);
   1469      break;
   1470    case eQuerySelectionAsTransferable:
   1471      rv = OnQuerySelectionAsTransferable(aEvent);
   1472      break;
   1473    case eQueryCharacterAtPoint:
   1474      rv = OnQueryCharacterAtPoint(aEvent);
   1475      break;
   1476    case eQueryDOMWidgetHittest:
   1477      rv = OnQueryDOMWidgetHittest(aEvent);
   1478      break;
   1479    case eQueryDropTargetHittest:
   1480      rv = OnQueryDropTargetHittest(aEvent);
   1481      break;
   1482    default:
   1483      break;
   1484  }
   1485  if (NS_FAILED(rv)) {
   1486    aEvent->mReply.reset();  // Mark the query failed.
   1487    return rv;
   1488  }
   1489 
   1490  MOZ_ASSERT(aEvent->Succeeded());
   1491  return NS_OK;
   1492 }
   1493 
   1494 // Similar to nsFrameSelection::GetFrameForNodeOffset,
   1495 // but this is more flexible for OnQueryTextRect to use
   1496 static Result<nsIFrame*, nsresult> GetFrameForTextRect(const nsINode* aNode,
   1497                                                       int32_t aNodeOffset,
   1498                                                       bool aHint) {
   1499  const nsIContent* content = nsIContent::FromNodeOrNull(aNode);
   1500  if (NS_WARN_IF(!content)) {
   1501    return Err(NS_ERROR_UNEXPECTED);
   1502  }
   1503  nsIFrame* frame = content->GetPrimaryFrame();
   1504  // The node may be invisible, e.g., `display: none`, invisible text node
   1505  // around block elements, etc.  Therefore, don't warn when we don't find
   1506  // a primary frame.
   1507  if (!frame) {
   1508    return nullptr;
   1509  }
   1510  int32_t childNodeOffset = 0;
   1511  nsIFrame* returnFrame = nullptr;
   1512  nsresult rv = frame->GetChildFrameContainingOffset(
   1513      aNodeOffset, aHint, &childNodeOffset, &returnFrame);
   1514  if (NS_FAILED(rv)) {
   1515    return Err(rv);
   1516  }
   1517  return returnFrame;
   1518 }
   1519 
   1520 nsresult ContentEventHandler::OnQuerySelectedText(
   1521    WidgetQueryContentEvent* aEvent) {
   1522  nsresult rv = Init(aEvent);
   1523  if (NS_FAILED(rv)) {
   1524    return rv;
   1525  }
   1526 
   1527  MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
   1528 
   1529  if (!mFirstSelectedSimpleRange.IsPositioned()) {
   1530    MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
   1531    MOZ_ASSERT_IF(mSelection, !mSelection->RangeCount());
   1532    // This is special case that `mReply` is emplaced, but mOffsetAndData is
   1533    // not emplaced but treated as succeeded because of no selection ranges
   1534    // is a usual case.
   1535    return NS_OK;
   1536  }
   1537 
   1538  const UnsafeSimpleRange firstSelectedSimpleRange(mFirstSelectedSimpleRange);
   1539  nsINode* const startNode = firstSelectedSimpleRange.GetStartContainer();
   1540  nsINode* const endNode = firstSelectedSimpleRange.GetEndContainer();
   1541 
   1542  // Make sure the selection is within the root content range.
   1543  if (!startNode->IsInclusiveDescendantOf(mRootElement) ||
   1544      !endNode->IsInclusiveDescendantOf(mRootElement)) {
   1545    return NS_ERROR_NOT_AVAILABLE;
   1546  }
   1547 
   1548  LineBreakType lineBreakType = GetLineBreakType(aEvent);
   1549  uint32_t startOffset = 0;
   1550  if (NS_WARN_IF(NS_FAILED(GetStartOffset(firstSelectedSimpleRange,
   1551                                          &startOffset, lineBreakType)))) {
   1552    return NS_ERROR_FAILURE;
   1553  }
   1554 
   1555  const RawRangeBoundary anchorRef = mSelection->RangeCount() > 0
   1556                                         ? mSelection->AnchorRef().AsRaw()
   1557                                         : firstSelectedSimpleRange.Start();
   1558  const RawRangeBoundary focusRef = mSelection->RangeCount() > 0
   1559                                        ? mSelection->FocusRef().AsRaw()
   1560                                        : firstSelectedSimpleRange.End();
   1561  if (NS_WARN_IF(!anchorRef.IsSet()) || NS_WARN_IF(!focusRef.IsSet())) {
   1562    return NS_ERROR_FAILURE;
   1563  }
   1564 
   1565  if (mSelection->RangeCount()) {
   1566    // If there is only one selection range, the anchor/focus node and offset
   1567    // are the information of the range.  Therefore, we have the direction
   1568    // information.
   1569    if (mSelection->RangeCount() == 1) {
   1570      // The selection's points should always be comparable, independent of the
   1571      // selection (see nsISelectionController.idl).
   1572      Maybe<int32_t> compare =
   1573          nsContentUtils::ComparePoints(anchorRef, focusRef);
   1574      if (compare.isNothing()) {
   1575        return NS_ERROR_FAILURE;
   1576      }
   1577 
   1578      aEvent->mReply->mReversed = compare.value() > 0;
   1579    }
   1580    // However, if there are 2 or more selection ranges, we have no information
   1581    // of that.
   1582    else {
   1583      aEvent->mReply->mReversed = false;
   1584    }
   1585 
   1586    nsString selectedString;
   1587    if (!firstSelectedSimpleRange.Collapsed() &&
   1588        NS_WARN_IF(NS_FAILED(GenerateFlatTextContent(
   1589            firstSelectedSimpleRange, selectedString, lineBreakType)))) {
   1590      return NS_ERROR_FAILURE;
   1591    }
   1592    aEvent->mReply->mOffsetAndData.emplace(startOffset, selectedString,
   1593                                           OffsetAndDataFor::SelectedString);
   1594  } else {
   1595    NS_ASSERTION(anchorRef == focusRef,
   1596                 "When mSelection doesn't have selection, "
   1597                 "mFirstSelectedRawRange must be collapsed");
   1598 
   1599    aEvent->mReply->mReversed = false;
   1600    aEvent->mReply->mOffsetAndData.emplace(startOffset, EmptyString(),
   1601                                           OffsetAndDataFor::SelectedString);
   1602  }
   1603 
   1604  Result<nsIFrame*, nsresult> frameForTextRectOrError = GetFrameForTextRect(
   1605      focusRef.GetContainer(),
   1606      focusRef.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets).valueOr(0),
   1607      true);
   1608  if (NS_WARN_IF(frameForTextRectOrError.isErr()) ||
   1609      !frameForTextRectOrError.inspect()) {
   1610    aEvent->mReply->mWritingMode = WritingMode();
   1611  } else {
   1612    aEvent->mReply->mWritingMode =
   1613        frameForTextRectOrError.inspect()->GetWritingMode();
   1614  }
   1615 
   1616  MOZ_ASSERT(aEvent->Succeeded());
   1617  return NS_OK;
   1618 }
   1619 
   1620 nsresult ContentEventHandler::OnQueryTextContent(
   1621    WidgetQueryContentEvent* aEvent) {
   1622  nsresult rv = Init(aEvent);
   1623  if (NS_FAILED(rv)) {
   1624    return rv;
   1625  }
   1626 
   1627  MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
   1628 
   1629  LineBreakType lineBreakType = GetLineBreakType(aEvent);
   1630 
   1631  Result<UnsafeDOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
   1632      domRangeAndAdjustedOffsetOrError = ConvertFlatTextOffsetToUnsafeDOMRange(
   1633          aEvent->mInput.mOffset, aEvent->mInput.mLength, lineBreakType, false);
   1634  if (MOZ_UNLIKELY(domRangeAndAdjustedOffsetOrError.isErr())) {
   1635    NS_WARNING(
   1636        "ContentEventHandler::ConvertFlatTextOffsetToDOMRangeBase() failed");
   1637    return NS_ERROR_FAILURE;
   1638  }
   1639  const UnsafeDOMRangeAndAdjustedOffsetInFlattenedText
   1640      domRangeAndAdjustedOffset = domRangeAndAdjustedOffsetOrError.unwrap();
   1641 
   1642  nsString textInRange;
   1643  if (NS_WARN_IF(NS_FAILED(GenerateFlatTextContent(
   1644          domRangeAndAdjustedOffset.mRange, textInRange, lineBreakType)))) {
   1645    return NS_ERROR_FAILURE;
   1646  }
   1647 
   1648  aEvent->mReply->mOffsetAndData.emplace(
   1649      domRangeAndAdjustedOffset.mAdjustedOffset, textInRange,
   1650      OffsetAndDataFor::EditorString);
   1651 
   1652  if (aEvent->mWithFontRanges) {
   1653    uint32_t fontRangeLength;
   1654    if (NS_WARN_IF(NS_FAILED(GenerateFlatFontRanges(
   1655            domRangeAndAdjustedOffset.mRange, aEvent->mReply->mFontRanges,
   1656            fontRangeLength, lineBreakType)))) {
   1657      return NS_ERROR_FAILURE;
   1658    }
   1659 
   1660    MOZ_ASSERT(fontRangeLength == aEvent->mReply->DataLength(),
   1661               "Font ranges doesn't match the string");
   1662  }
   1663 
   1664  MOZ_ASSERT(aEvent->Succeeded());
   1665  return NS_OK;
   1666 }
   1667 
   1668 void ContentEventHandler::EnsureNonEmptyRect(nsRect& aRect) const {
   1669  // See the comment in ContentEventHandler.h why this doesn't set them to
   1670  // one device pixel.
   1671  aRect.height = std::max(1, aRect.height);
   1672  aRect.width = std::max(1, aRect.width);
   1673 }
   1674 
   1675 void ContentEventHandler::EnsureNonEmptyRect(LayoutDeviceIntRect& aRect) const {
   1676  aRect.height = std::max(1, aRect.height);
   1677  aRect.width = std::max(1, aRect.width);
   1678 }
   1679 
   1680 template <typename NodeType, typename RangeBoundaryType>
   1681 ContentEventHandler::FrameAndNodeOffset
   1682 ContentEventHandler::GetFirstFrameInRangeForTextRect(
   1683    const SimpleRangeBase<NodeType, RangeBoundaryType>& aSimpleRange) {
   1684  RawNodePosition nodePosition;
   1685  UnsafePreContentIterator preOrderIter;
   1686  nsresult rv = preOrderIter.Init(aSimpleRange.Start().AsRaw(),
   1687                                  aSimpleRange.End().AsRaw());
   1688  if (NS_WARN_IF(NS_FAILED(rv))) {
   1689    return FrameAndNodeOffset();
   1690  }
   1691  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
   1692    nsINode* node = preOrderIter.GetCurrentNode();
   1693    if (NS_WARN_IF(!node)) {
   1694      break;
   1695    }
   1696 
   1697    auto* content = nsIContent::FromNode(node);
   1698    if (MOZ_UNLIKELY(!content)) {
   1699      continue;
   1700    }
   1701 
   1702    // If the node is invisible (e.g., the node is or is in an invisible node or
   1703    // it's a white-space only text node around a block boundary), we should
   1704    // ignore it.
   1705    if (!content->GetPrimaryFrame()) {
   1706      continue;
   1707    }
   1708 
   1709    if (auto* textNode = Text::FromNode(content)) {
   1710      // If the range starts at the end of a text node, we need to find
   1711      // next node which causes text.
   1712      const uint32_t offsetInNode = textNode == aSimpleRange.GetStartContainer()
   1713                                        ? aSimpleRange.StartOffset()
   1714                                        : 0u;
   1715      if (offsetInNode < textNode->TextDataLength()) {
   1716        nodePosition = {textNode, offsetInNode};
   1717        break;
   1718      }
   1719      continue;
   1720    }
   1721 
   1722    // If the element node causes a line break before it, it's the first
   1723    // node causing text.
   1724    if (ShouldBreakLineBefore(*content, mRootElement) ||
   1725        IsPaddingBR(*content)) {
   1726      nodePosition = {content, 0u};
   1727    }
   1728  }
   1729 
   1730  if (!nodePosition.IsSetAndValid()) {
   1731    return FrameAndNodeOffset();
   1732  }
   1733 
   1734  Result<nsIFrame*, nsresult> firstFrameOrError = GetFrameForTextRect(
   1735      nodePosition.GetContainer(),
   1736      *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets), true);
   1737  if (NS_WARN_IF(firstFrameOrError.isErr()) || !firstFrameOrError.inspect()) {
   1738    return FrameAndNodeOffset();
   1739  }
   1740  return FrameAndNodeOffset(
   1741      firstFrameOrError.inspect(),
   1742      *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets));
   1743 }
   1744 
   1745 template <typename NodeType, typename RangeBoundaryType>
   1746 ContentEventHandler::FrameAndNodeOffset
   1747 ContentEventHandler::GetLastFrameInRangeForTextRect(
   1748    const SimpleRangeBase<NodeType, RangeBoundaryType>& aSimpleRange) {
   1749  RawNodePosition nodePosition;
   1750  UnsafePreContentIterator preOrderIter;
   1751  nsresult rv = preOrderIter.Init(aSimpleRange.Start().AsRaw(),
   1752                                  aSimpleRange.End().AsRaw());
   1753  if (NS_WARN_IF(NS_FAILED(rv))) {
   1754    return FrameAndNodeOffset();
   1755  }
   1756 
   1757  const RangeBoundaryType& endPoint = aSimpleRange.End();
   1758  MOZ_ASSERT(endPoint.IsSetAndValid());
   1759  // If the end point is start of a text node or specified by its parent and
   1760  // index, the node shouldn't be included into the range.  For example,
   1761  // with this case, |<p>abc[<br>]def</p>|, the range ends at 3rd children of
   1762  // <p> (see the range creation rules, "2.4. Cases: <element/>]"). This causes
   1763  // following frames:
   1764  // +----+-----+
   1765  // | abc|[<br>|
   1766  // +----+-----+
   1767  // +----+
   1768  // |]def|
   1769  // +----+
   1770  // So, if this method includes the 2nd text frame's rect to its result, the
   1771  // caller will return too tall rect which includes 2 lines in this case isn't
   1772  // expected by native IME  (e.g., popup of IME will be positioned at bottom
   1773  // of "d" instead of right-bottom of "c").  Therefore, this method shouldn't
   1774  // include the last frame when its content isn't really in aSimpleRange.
   1775  nsINode* nextNodeOfRangeEnd = nullptr;
   1776  if (endPoint.GetContainer()->IsText()) {
   1777    // Don't set nextNodeOfRangeEnd to the start node of aSimpleRange because if
   1778    // the container of the end is same as start node of the range, the text
   1779    // node shouldn't be next of range end even if the offset is 0.  This
   1780    // could occur with empty text node.
   1781    if (endPoint.IsStartOfContainer() &&
   1782        aSimpleRange.GetStartContainer() != endPoint.GetContainer()) {
   1783      nextNodeOfRangeEnd = endPoint.GetContainer();
   1784    }
   1785  } else if (endPoint.IsSetAndValid()) {
   1786    nextNodeOfRangeEnd = endPoint.GetChildAtOffset();
   1787  }
   1788 
   1789  for (preOrderIter.Last(); !preOrderIter.IsDone(); preOrderIter.Prev()) {
   1790    nsINode* node = preOrderIter.GetCurrentNode();
   1791    if (NS_WARN_IF(!node)) {
   1792      break;
   1793    }
   1794 
   1795    if (node == nextNodeOfRangeEnd) {
   1796      continue;
   1797    }
   1798 
   1799    auto* content = nsIContent::FromNode(node);
   1800    if (MOZ_UNLIKELY(!content)) {
   1801      continue;
   1802    }
   1803 
   1804    // If the node is invisible (e.g., the node is or is in an invisible node or
   1805    // it's a white-space only text node around a block boundary), we should
   1806    // ignore it.
   1807    if (!content->GetPrimaryFrame()) {
   1808      continue;
   1809    }
   1810 
   1811    if (auto* textNode = Text::FromNode(node)) {
   1812      nodePosition = {textNode, textNode == aSimpleRange.GetEndContainer()
   1813                                    ? aSimpleRange.EndOffset()
   1814                                    : textNode->TextDataLength()};
   1815 
   1816      // If the text node is empty or the last node of the range but the index
   1817      // is 0, we should store current position but continue looking for
   1818      // previous node (If there are no nodes before it, we should use current
   1819      // node position for returning its frame).
   1820      if (*nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets) ==
   1821          0) {
   1822        continue;
   1823      }
   1824      break;
   1825    }
   1826 
   1827    if (ShouldBreakLineBefore(*content, mRootElement) ||
   1828        IsPaddingBR(*content)) {
   1829      nodePosition = {content, 0u};
   1830      break;
   1831    }
   1832  }
   1833 
   1834  if (!nodePosition.IsSet()) {
   1835    return FrameAndNodeOffset();
   1836  }
   1837 
   1838  Result<nsIFrame*, nsresult> lastFrameOrError = GetFrameForTextRect(
   1839      nodePosition.GetContainer(),
   1840      *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets), true);
   1841  if (NS_WARN_IF(lastFrameOrError.isErr()) || !lastFrameOrError.inspect()) {
   1842    return FrameAndNodeOffset();
   1843  }
   1844 
   1845  // If the last frame is a text frame, we need to check if the range actually
   1846  // includes at least one character in the range.  Therefore, if it's not a
   1847  // text frame, we need to do nothing anymore.
   1848  if (!lastFrameOrError.inspect()->IsTextFrame()) {
   1849    return FrameAndNodeOffset(
   1850        lastFrameOrError.inspect(),
   1851        *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets));
   1852  }
   1853 
   1854  int32_t start = lastFrameOrError.inspect()->GetOffsets().first;
   1855 
   1856  // If the start offset in the node is same as the computed offset in the
   1857  // node and it's not 0, the frame shouldn't be added to the text rect.  So,
   1858  // this should return previous text frame and its last offset if there is
   1859  // at least one text frame.
   1860  if (*nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets) &&
   1861      *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets) ==
   1862          static_cast<uint32_t>(start)) {
   1863    const uint32_t newNodePositionOffset =
   1864        *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets);
   1865    MOZ_ASSERT(newNodePositionOffset != 0);
   1866    nodePosition = {nodePosition.GetContainer(), newNodePositionOffset - 1u};
   1867    lastFrameOrError = GetFrameForTextRect(
   1868        nodePosition.GetContainer(),
   1869        *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets),
   1870        true);
   1871    if (NS_WARN_IF(lastFrameOrError.isErr()) || !lastFrameOrError.inspect()) {
   1872      return FrameAndNodeOffset();
   1873    }
   1874  }
   1875 
   1876  return FrameAndNodeOffset(
   1877      lastFrameOrError.inspect(),
   1878      *nodePosition.Offset(RawNodePosition::OffsetFilter::kValidOffsets));
   1879 }
   1880 
   1881 ContentEventHandler::FrameRelativeRect
   1882 ContentEventHandler::GetLineBreakerRectBefore(nsIFrame* aFrame) {
   1883  // Note that this method should be called only with an element's frame whose
   1884  // open tag causes a line break or moz-<br> for computing empty last line's
   1885  // rect.
   1886  MOZ_ASSERT(aFrame->GetContent());
   1887  MOZ_ASSERT(ShouldBreakLineBefore(*aFrame->GetContent(), mRootElement) ||
   1888             IsPaddingBR(*aFrame->GetContent()));
   1889 
   1890  nsIFrame* frameForFontMetrics = aFrame;
   1891 
   1892  // If it's not a <br> frame, this method computes the line breaker's rect
   1893  // outside the frame.  Therefore, we need to compute with parent frame's
   1894  // font metrics in such case.
   1895  if (!aFrame->IsBrFrame() && aFrame->GetParent()) {
   1896    frameForFontMetrics = aFrame->GetParent();
   1897  }
   1898 
   1899  // Note that <br> element's rect is decided with line-height but we need
   1900  // a rect only with font height.  Additionally, <br> frame's width and
   1901  // height are 0 in quirks mode if it's not an empty line.  So, we cannot
   1902  // use frame rect information even if it's a <br> frame.
   1903 
   1904  RefPtr<nsFontMetrics> fontMetrics =
   1905      nsLayoutUtils::GetInflatedFontMetricsForFrame(frameForFontMetrics);
   1906  if (NS_WARN_IF(!fontMetrics)) {
   1907    return FrameRelativeRect();
   1908  }
   1909 
   1910  const WritingMode kWritingMode = frameForFontMetrics->GetWritingMode();
   1911 
   1912  auto caretBlockAxisMetrics =
   1913      aFrame->GetCaretBlockAxisMetrics(kWritingMode, *fontMetrics);
   1914  nscoord inlineOffset = 0;
   1915 
   1916  // If aFrame isn't a <br> frame, caret should be at outside of it because
   1917  // the line break is before its open tag.  For example, case of
   1918  // |<div><p>some text</p></div>|, caret is before <p> element and in <div>
   1919  // element, the caret should be left of top-left corner of <p> element like:
   1920  //
   1921  // +-<div>-------------------  <div>'s border box
   1922  // | I +-<p>-----------------  <p>'s border box
   1923  // | I |
   1924  // | I |
   1925  // |   |
   1926  //   ^- caret
   1927  //
   1928  // However, this is a hack for unusual scenario.  This hack shouldn't be
   1929  // used as far as possible.
   1930  if (!aFrame->IsBrFrame()) {
   1931    if (kWritingMode.IsVertical() && !kWritingMode.IsLineInverted()) {
   1932      // above of top-right corner of aFrame.
   1933      caretBlockAxisMetrics.mOffset =
   1934          aFrame->GetRect().XMost() - caretBlockAxisMetrics.mExtent;
   1935    } else {
   1936      // above (For vertical) or left (For horizontal) of top-left corner of
   1937      // aFrame.
   1938      caretBlockAxisMetrics.mOffset = 0;
   1939    }
   1940    inlineOffset = -aFrame->PresContext()->AppUnitsPerDevPixel();
   1941  }
   1942  FrameRelativeRect result(aFrame);
   1943  if (kWritingMode.IsVertical()) {
   1944    result.mRect.x = caretBlockAxisMetrics.mOffset;
   1945    result.mRect.y = inlineOffset;
   1946    result.mRect.width = caretBlockAxisMetrics.mExtent;
   1947  } else {
   1948    result.mRect.x = inlineOffset;
   1949    result.mRect.y = caretBlockAxisMetrics.mOffset;
   1950    result.mRect.height = caretBlockAxisMetrics.mExtent;
   1951  }
   1952  return result;
   1953 }
   1954 
   1955 ContentEventHandler::FrameRelativeRect
   1956 ContentEventHandler::GuessLineBreakerRectAfter(const Text& aTextNode) {
   1957  FrameRelativeRect result;
   1958  const int32_t length = static_cast<int32_t>(aTextNode.TextLength());
   1959  if (NS_WARN_IF(length < 0)) {
   1960    return result;
   1961  }
   1962  // Get the last nsTextFrame which is caused by aTextNode.  Note that
   1963  // a text node can cause multiple text frames, e.g., the text is too long
   1964  // and wrapped by its parent block or the text has line breakers and its
   1965  // white-space property respects the line breakers (e.g., |pre|).
   1966  Result<nsIFrame*, nsresult> lastTextFrameOrError =
   1967      GetFrameForTextRect(&aTextNode, length, true);
   1968  if (NS_WARN_IF(lastTextFrameOrError.isErr()) ||
   1969      !lastTextFrameOrError.inspect()) {
   1970    return result;
   1971  }
   1972  const nsRect kLastTextFrameRect = lastTextFrameOrError.inspect()->GetRect();
   1973  if (lastTextFrameOrError.inspect()->GetWritingMode().IsVertical()) {
   1974    // Below of the last text frame.
   1975    result.mRect.SetRect(0, kLastTextFrameRect.height, kLastTextFrameRect.width,
   1976                         0);
   1977  } else {
   1978    // Right of the last text frame (not bidi-aware).
   1979    result.mRect.SetRect(kLastTextFrameRect.width, 0, 0,
   1980                         kLastTextFrameRect.height);
   1981  }
   1982  result.mBaseFrame = lastTextFrameOrError.unwrap();
   1983  return result;
   1984 }
   1985 
   1986 ContentEventHandler::FrameRelativeRect
   1987 ContentEventHandler::GuessFirstCaretRectIn(nsIFrame* aFrame) {
   1988  const WritingMode kWritingMode = aFrame->GetWritingMode();
   1989  nsPresContext* presContext = aFrame->PresContext();
   1990 
   1991  // Computes the font height, but if it's not available, we should use
   1992  // default font size of Firefox.  The default font size in default settings
   1993  // is 16px.
   1994  RefPtr<nsFontMetrics> fontMetrics =
   1995      nsLayoutUtils::GetInflatedFontMetricsForFrame(aFrame);
   1996  const nscoord kMaxHeight = fontMetrics
   1997                                 ? fontMetrics->MaxHeight()
   1998                                 : 16 * presContext->AppUnitsPerDevPixel();
   1999 
   2000  nsRect caretRect;
   2001  const nsRect kContentRect = aFrame->GetContentRect() - aFrame->GetPosition();
   2002  caretRect.y = kContentRect.y;
   2003  if (!kWritingMode.IsVertical()) {
   2004    if (kWritingMode.IsBidiLTR()) {
   2005      caretRect.x = kContentRect.x;
   2006    } else {
   2007      // Move 1px left for the space of caret itself.
   2008      const nscoord kOnePixel = presContext->AppUnitsPerDevPixel();
   2009      caretRect.x = kContentRect.XMost() - kOnePixel;
   2010    }
   2011    caretRect.height = kMaxHeight;
   2012    // However, don't add kOnePixel here because it may cause 2px width at
   2013    // aligning the edge to device pixels.
   2014    caretRect.width = 1;
   2015  } else {
   2016    if (kWritingMode.IsVerticalLR()) {
   2017      caretRect.x = kContentRect.x;
   2018    } else {
   2019      caretRect.x = kContentRect.XMost() - kMaxHeight;
   2020    }
   2021    caretRect.width = kMaxHeight;
   2022    // Don't add app units for a device pixel because it may cause 2px height
   2023    // at aligning the edge to device pixels.
   2024    caretRect.height = 1;
   2025  }
   2026  return FrameRelativeRect(caretRect, aFrame);
   2027 }
   2028 
   2029 //  static
   2030 LayoutDeviceIntRect ContentEventHandler::GetCaretRectBefore(
   2031    const LayoutDeviceIntRect& aCharRect, const WritingMode& aWritingMode) {
   2032  LayoutDeviceIntRect caretRectBefore(aCharRect);
   2033  if (aWritingMode.IsVertical()) {
   2034    caretRectBefore.height = 1;
   2035  } else {
   2036    // TODO: Make here bidi-aware.
   2037    caretRectBefore.width = 1;
   2038  }
   2039  return caretRectBefore;
   2040 }
   2041 
   2042 //  static
   2043 nsRect ContentEventHandler::GetCaretRectBefore(
   2044    const nsRect& aCharRect, const WritingMode& aWritingMode) {
   2045  nsRect caretRectBefore(aCharRect);
   2046  if (aWritingMode.IsVertical()) {
   2047    // For making the height 1 device pixel after aligning the rect edges to
   2048    // device pixels, don't add one device pixel in app units here.
   2049    caretRectBefore.height = 1;
   2050  } else {
   2051    // TODO: Make here bidi-aware.
   2052    // For making the width 1 device pixel after aligning the rect edges to
   2053    // device pixels, don't add one device pixel in app units here.
   2054    caretRectBefore.width = 1;
   2055  }
   2056  return caretRectBefore;
   2057 }
   2058 
   2059 //  static
   2060 LayoutDeviceIntRect ContentEventHandler::GetCaretRectAfter(
   2061    const LayoutDeviceIntRect& aCharRect, const WritingMode& aWritingMode) {
   2062  LayoutDeviceIntRect caretRectAfter(aCharRect);
   2063  if (aWritingMode.IsVertical()) {
   2064    caretRectAfter.y = aCharRect.YMost() + 1;
   2065    caretRectAfter.height = 1;
   2066  } else {
   2067    // TODO: Make here bidi-aware.
   2068    caretRectAfter.x = aCharRect.XMost() + 1;
   2069    caretRectAfter.width = 1;
   2070  }
   2071  return caretRectAfter;
   2072 }
   2073 
   2074 //  static
   2075 nsRect ContentEventHandler::GetCaretRectAfter(nsPresContext& aPresContext,
   2076                                              const nsRect& aCharRect,
   2077                                              const WritingMode& aWritingMode) {
   2078  nsRect caretRectAfter(aCharRect);
   2079  const nscoord onePixel = aPresContext.AppUnitsPerDevPixel();
   2080  if (aWritingMode.IsVertical()) {
   2081    caretRectAfter.y = aCharRect.YMost() + onePixel;
   2082    // For making the height 1 device pixel after aligning the rect edges to
   2083    // device pixels, don't add one device pixel in app units here.
   2084    caretRectAfter.height = 1;
   2085  } else {
   2086    // TODO: Make here bidi-aware.
   2087    caretRectAfter.x = aCharRect.XMost() + onePixel;
   2088    // For making the width 1 device pixel after aligning the rect edges to
   2089    // device pixels, don't add one device pixel in app units here.
   2090    caretRectAfter.width = 1;
   2091  }
   2092  return caretRectAfter;
   2093 }
   2094 
   2095 nsresult ContentEventHandler::OnQueryTextRectArray(
   2096    WidgetQueryContentEvent* aEvent) {
   2097  nsresult rv = Init(aEvent);
   2098  if (NS_WARN_IF(NS_FAILED(rv))) {
   2099    return rv;
   2100  }
   2101 
   2102  MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
   2103 
   2104  LineBreakType lineBreakType = GetLineBreakType(aEvent);
   2105  const uint32_t kBRLength = GetBRLength(lineBreakType);
   2106 
   2107  WritingMode lastVisibleFrameWritingMode;
   2108  LayoutDeviceIntRect rect;
   2109  uint32_t offset = aEvent->mInput.mOffset;
   2110  const uint32_t kEndOffset = aEvent->mInput.EndOffset();
   2111  bool wasLineBreaker = false;
   2112  // lastCharRect stores the last charRect value (see below for the detail of
   2113  // charRect).
   2114  nsRect lastCharRect;
   2115  // lastFrame is base frame of lastCharRect.
   2116  // TODO: We should look for this if the first text is not visible.  However,
   2117  //       users cannot put caret invisible text and users cannot type in it
   2118  //       at least only with user's operations.  Therefore, we don't need to
   2119  //       fix this immediately.
   2120  nsIFrame* lastFrame = nullptr;
   2121  nsAutoString flattenedAllText;
   2122  flattenedAllText.SetIsVoid(true);
   2123  while (offset < kEndOffset) {
   2124    Result<DOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
   2125        domRangeAndAdjustedOffsetOrError =
   2126            ConvertFlatTextOffsetToDOMRange(offset, 1, lineBreakType, true);
   2127    if (MOZ_UNLIKELY(domRangeAndAdjustedOffsetOrError.isErr())) {
   2128      NS_WARNING(
   2129          "ContentEventHandler::ConvertFlatTextOffsetToDOMRangeBase() failed");
   2130      return domRangeAndAdjustedOffsetOrError.unwrapErr();
   2131    }
   2132    const DOMRangeAndAdjustedOffsetInFlattenedText domRangeAndAdjustedOffset =
   2133        domRangeAndAdjustedOffsetOrError.unwrap();
   2134 
   2135    // TODO: When we crossed parent block boundary now, we should fill pending
   2136    //       character rects with caret rect after the last visible character
   2137    //       rect.
   2138 
   2139    // If the range is collapsed, offset has already reached the end of the
   2140    // contents.
   2141    if (domRangeAndAdjustedOffset.mRange.Collapsed()) {
   2142      break;
   2143    }
   2144 
   2145    // Get the first frame which causes some text after the offset.
   2146    FrameAndNodeOffset firstFrame =
   2147        GetFirstFrameInRangeForTextRect(domRangeAndAdjustedOffset.mRange);
   2148 
   2149    // If GetFirstFrameInRangeForTextRect() does not return valid frame, that
   2150    // means that the offset reached the end of contents or there is no visible
   2151    // frame in the range generating flattened text.
   2152    if (!firstFrame.IsValid()) {
   2153      if (flattenedAllText.IsVoid()) {
   2154        flattenedAllText.SetIsVoid(false);
   2155        if (NS_WARN_IF(NS_FAILED(GenerateFlatTextContent(
   2156                mRootElement, flattenedAllText, lineBreakType)))) {
   2157          NS_WARNING("ContentEventHandler::GenerateFlatTextContent() failed");
   2158          return NS_ERROR_FAILURE;
   2159        }
   2160      }
   2161      // If we've reached end of the root, append caret rect at the end of
   2162      // the root later.
   2163      if (offset >= flattenedAllText.Length()) {
   2164        break;
   2165      }
   2166      // Otherwise, we're in an invisible node. If the node is followed by a
   2167      // block boundary causing a line break, we can use the boundary.
   2168      // Otherwise, if the node follows a block boundary of a parent block, we
   2169      // can use caret rect at previous visible frame causing flattened text.
   2170      const uint32_t remainingLengthInCurrentRange = [&]() {
   2171        if (domRangeAndAdjustedOffset.mLastTextNode) {
   2172          if (domRangeAndAdjustedOffset.RangeStartsFromLastTextNode()) {
   2173            if (!domRangeAndAdjustedOffset.RangeStartsFromEndOfContainer()) {
   2174              return domRangeAndAdjustedOffset.mLastTextNode->TextDataLength() -
   2175                     domRangeAndAdjustedOffset.mRange.StartOffset();
   2176            }
   2177            return 0u;
   2178          }
   2179          // Must be there are not nodes which may cause generating text.
   2180          // Therefore, we can skip all nodes before the last found text node
   2181          // and all text in the last text node.
   2182          return domRangeAndAdjustedOffset.mLastTextNode->TextDataLength();
   2183        }
   2184        if (domRangeAndAdjustedOffset.RangeStartsFromContent() &&
   2185            ShouldBreakLineBefore(
   2186                *domRangeAndAdjustedOffset.mRange.GetStartContainer()
   2187                     ->AsContent(),
   2188                mRootElement)) {
   2189          if (kBRLength != 1u && offset - aEvent->mInput.mOffset < kBRLength) {
   2190            // Don't return kBRLength if start position is less than the length
   2191            // of a line-break because the offset may be between CRLF on
   2192            // Windows.  In the case, we will be again here and gets same
   2193            // result and we need to pay the penalty only once.  Therefore, we
   2194            // can keep going without complicated check.
   2195            return 1u;
   2196          }
   2197          return kBRLength;
   2198        }
   2199        return 0u;
   2200      }();
   2201      offset += std::max(1u, remainingLengthInCurrentRange);
   2202      continue;
   2203    }
   2204 
   2205    nsIContent* firstContent = firstFrame.mFrame->GetContent();
   2206    if (NS_WARN_IF(!firstContent)) {
   2207      return NS_ERROR_FAILURE;
   2208    }
   2209 
   2210    bool startsBetweenLineBreaker = false;
   2211    nsAutoString chars;
   2212    lastVisibleFrameWritingMode = firstFrame->GetWritingMode();
   2213 
   2214    nsIFrame* baseFrame = firstFrame;
   2215    // charRect should have each character rect or line breaker rect relative
   2216    // to the base frame.
   2217    AutoTArray<nsRect, 16> charRects;
   2218 
   2219    // If the first frame is a text frame, the result should be computed with
   2220    // the frame's API.
   2221    if (firstFrame->IsTextFrame()) {
   2222      rv = firstFrame->GetCharacterRectsInRange(firstFrame.mOffsetInNode,
   2223                                                kEndOffset - offset, charRects);
   2224      if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(charRects.IsEmpty())) {
   2225        return rv;
   2226      }
   2227      // Assign the characters whose rects are computed by the call of
   2228      // nsTextFrame::GetCharacterRectsInRange().
   2229      AppendSubString(chars, *firstContent->AsText(), firstFrame.mOffsetInNode,
   2230                      charRects.Length());
   2231      if (NS_WARN_IF(chars.Length() != charRects.Length())) {
   2232        return NS_ERROR_UNEXPECTED;
   2233      }
   2234      if (kBRLength > 1 && chars[0] == '\n' &&
   2235          offset == aEvent->mInput.mOffset && offset) {
   2236        // If start of range starting from previous offset of query range is
   2237        // same as the start of query range, the query range starts from
   2238        // between a line breaker (i.e., the range starts between "\r" and
   2239        // "\n").
   2240        Result<UnsafeDOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
   2241            domRangeAndAdjustedOffsetOrError =
   2242                ConvertFlatTextOffsetToUnsafeDOMRange(
   2243                    aEvent->mInput.mOffset - 1, 1, lineBreakType, true);
   2244        if (MOZ_UNLIKELY(domRangeAndAdjustedOffsetOrError.isErr())) {
   2245          NS_WARNING(
   2246              "ContentEventHandler::ConvertFlatTextOffsetToDOMRangeBase() "
   2247              "failed");
   2248          return domRangeAndAdjustedOffsetOrError.unwrapErr();
   2249        }
   2250        const UnsafeDOMRangeAndAdjustedOffsetInFlattenedText
   2251            domRangeAndAdjustedOffsetOfPreviousChar =
   2252                domRangeAndAdjustedOffsetOrError.unwrap();
   2253        startsBetweenLineBreaker =
   2254            domRangeAndAdjustedOffset.mRange.GetStartContainer() ==
   2255                domRangeAndAdjustedOffsetOfPreviousChar.mRange
   2256                    .GetStartContainer() &&
   2257            domRangeAndAdjustedOffset.mRange.StartOffset() ==
   2258                domRangeAndAdjustedOffsetOfPreviousChar.mRange.StartOffset();
   2259      }
   2260    }
   2261    // Other contents should cause a line breaker rect before it.
   2262    // Note that moz-<br> element does not cause any text, however,
   2263    // it represents empty line at the last of current block.  Therefore,
   2264    // we need to compute its rect too.
   2265    else if (ShouldBreakLineBefore(*firstContent, mRootElement) ||
   2266             IsPaddingBR(*firstContent)) {
   2267      nsRect brRect;
   2268      // If the frame is not a <br> frame, we need to compute the caret rect
   2269      // with last character's rect before firstContent if there is.
   2270      // For example, if caret is after "c" of |<p>abc</p><p>def</p>|, IME may
   2271      // query a line breaker's rect after "c".  Then, if we compute it only
   2272      // with the 2nd <p>'s block frame, the result will be:
   2273      //  +-<p>--------------------------------+
   2274      //  |abc                                 |
   2275      //  +------------------------------------+
   2276      //
   2277      // I+-<p>--------------------------------+
   2278      //  |def                                 |
   2279      //  +------------------------------------+
   2280      // However, users expect popup windows of IME should be positioned at
   2281      // right-bottom of "c" like this:
   2282      //  +-<p>--------------------------------+
   2283      //  |abcI                                |
   2284      //  +------------------------------------+
   2285      //
   2286      //  +-<p>--------------------------------+
   2287      //  |def                                 |
   2288      //  +------------------------------------+
   2289      // Therefore, if the first frame isn't a <br> frame and there is a text
   2290      // node before the first node in the queried range, we should compute the
   2291      // first rect with the previous character's rect.
   2292      // If we already compute a character's rect in the queried range, we can
   2293      // compute it with the cached last character's rect.  (However, don't
   2294      // use this path if it's a <br> frame because trusting <br> frame's rect
   2295      // is better than guessing the rect from the previous character.)
   2296      if (!firstFrame->IsBrFrame() && !aEvent->mReply->mRectArray.IsEmpty()) {
   2297        baseFrame = lastFrame;
   2298        brRect = lastCharRect;
   2299        if (!wasLineBreaker) {
   2300          brRect = GetCaretRectAfter(*baseFrame->PresContext(), brRect,
   2301                                     lastVisibleFrameWritingMode);
   2302        }
   2303      }
   2304      // If it's not a <br> frame and it's the first character rect at the
   2305      // queried range, we need the previous character rect of the start of
   2306      // the queried range if there is a visible text node.
   2307      else if (!firstFrame->IsBrFrame() &&
   2308               domRangeAndAdjustedOffset.mLastTextNode &&
   2309               domRangeAndAdjustedOffset.mLastTextNode->GetPrimaryFrame()) {
   2310        FrameRelativeRect brRectRelativeToLastTextFrame =
   2311            GuessLineBreakerRectAfter(*domRangeAndAdjustedOffset.mLastTextNode);
   2312        if (NS_WARN_IF(!brRectRelativeToLastTextFrame.IsValid())) {
   2313          return NS_ERROR_FAILURE;
   2314        }
   2315        // Look for the last text frame for the last text node.
   2316        nsIFrame* primaryFrame =
   2317            domRangeAndAdjustedOffset.mLastTextNode->GetPrimaryFrame();
   2318        if (NS_WARN_IF(!primaryFrame)) {
   2319          return NS_ERROR_FAILURE;
   2320        }
   2321        baseFrame = primaryFrame->LastContinuation();
   2322        if (NS_WARN_IF(!baseFrame)) {
   2323          return NS_ERROR_FAILURE;
   2324        }
   2325        brRect = brRectRelativeToLastTextFrame.RectRelativeTo(baseFrame);
   2326      }
   2327      // Otherwise, we need to compute the line breaker's rect only with the
   2328      // first frame's rect.  But this may be unexpected.  For example,
   2329      // |<div contenteditable>[<p>]abc</p></div>|.  In this case, caret is
   2330      // before "a", therefore, users expect the rect left of "a".  However,
   2331      // we don't have enough information about the next character here and
   2332      // this isn't usual case (e.g., IME typically tries to query the rect
   2333      // of "a" or caret rect for computing its popup position).  Therefore,
   2334      // we shouldn't do more complicated hack here unless we'll get some bug
   2335      // reports actually.
   2336      else {
   2337        FrameRelativeRect relativeBRRect = GetLineBreakerRectBefore(firstFrame);
   2338        brRect = relativeBRRect.RectRelativeTo(firstFrame);
   2339      }
   2340      charRects.AppendElement(brRect);
   2341      chars.AssignLiteral("\n");
   2342      if (kBRLength > 1 && offset == aEvent->mInput.mOffset && offset) {
   2343        // If the first frame for the previous offset of the query range and
   2344        // the first frame for the start of query range are same, that means
   2345        // the start offset is between the first line breaker (i.e., the range
   2346        // starts between "\r" and "\n").
   2347        Result<UnsafeDOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
   2348            domRangeAndAdjustedOffsetOrError =
   2349                ConvertFlatTextOffsetToUnsafeDOMRange(
   2350                    aEvent->mInput.mOffset - 1, 1, lineBreakType, true);
   2351        if (MOZ_UNLIKELY(domRangeAndAdjustedOffsetOrError.isErr())) {
   2352          NS_WARNING(
   2353              "ContentEventHandler::ConvertFlatTextOffsetToDOMRangeBase() "
   2354              "failed");
   2355          return NS_ERROR_UNEXPECTED;
   2356        }
   2357        const UnsafeDOMRangeAndAdjustedOffsetInFlattenedText
   2358            domRangeAndAdjustedOffset =
   2359                domRangeAndAdjustedOffsetOrError.unwrap();
   2360        FrameAndNodeOffset frameForPrevious =
   2361            GetFirstFrameInRangeForTextRect(domRangeAndAdjustedOffset.mRange);
   2362        startsBetweenLineBreaker = frameForPrevious.mFrame == firstFrame.mFrame;
   2363      }
   2364    } else {
   2365      NS_WARNING(
   2366          "The frame is neither a text frame nor a frame whose content "
   2367          "causes a line break");
   2368      return NS_ERROR_FAILURE;
   2369    }
   2370 
   2371    for (size_t i = 0; i < charRects.Length() && offset < kEndOffset; i++) {
   2372      nsRect charRect = charRects[i];
   2373      // Store lastCharRect before applying CSS transform because it may be
   2374      // used for computing a line breaker rect.  Then, the computed line
   2375      // breaker rect will be applied CSS transform again.  Therefore,
   2376      // the value of lastCharRect should be raw rect value relative to the
   2377      // base frame.
   2378      lastCharRect = charRect;
   2379      lastFrame = baseFrame;
   2380      rv = ConvertToRootRelativeOffset(baseFrame, charRect);
   2381      if (NS_WARN_IF(NS_FAILED(rv))) {
   2382        return rv;
   2383      }
   2384 
   2385      nsPresContext* presContext = baseFrame->PresContext();
   2386      rect = LayoutDeviceIntRect::FromAppUnitsToOutside(
   2387          charRect, presContext->AppUnitsPerDevPixel());
   2388      if (nsPresContext* rootContext =
   2389              presContext->GetInProcessRootContentDocumentPresContext()) {
   2390        rect = RoundedOut(ViewportUtils::DocumentRelativeLayoutToVisual(
   2391            rect, rootContext->PresShell()));
   2392      }
   2393      // Returning empty rect may cause native IME confused, let's make sure to
   2394      // return non-empty rect.
   2395      EnsureNonEmptyRect(rect);
   2396 
   2397      // If we found some invisible characters followed by current visible
   2398      // character, make their rects same as caret rect before the first visible
   2399      // character because IME may want to put their UI next to the rect of the
   2400      // invisible character for next input.
   2401      // Note that chars do not contain the invisible characters.
   2402      if (i == 0u && MOZ_LIKELY(offset > aEvent->mInput.mOffset)) {
   2403        const uint32_t offsetInRange =
   2404            offset - CheckedInt<uint32_t>(aEvent->mInput.mOffset).value();
   2405        if (offsetInRange > aEvent->mReply->mRectArray.Length()) {
   2406          LayoutDeviceIntRect caretRectBefore =
   2407              GetCaretRectBefore(rect, lastVisibleFrameWritingMode);
   2408          for ([[maybe_unused]] uint32_t index : IntegerRange<uint32_t>(
   2409                   offsetInRange - aEvent->mReply->mRectArray.Length())) {
   2410            aEvent->mReply->mRectArray.AppendElement(caretRectBefore);
   2411          }
   2412          MOZ_ASSERT(aEvent->mReply->mRectArray.Length() == offsetInRange);
   2413        }
   2414      }
   2415 
   2416      aEvent->mReply->mRectArray.AppendElement(rect);
   2417      offset++;
   2418 
   2419      // If it's not a line breaker or the line breaker length is same as
   2420      // XP line breaker's, we need to do nothing for current character.
   2421      wasLineBreaker = chars[i] == '\n';
   2422      if (!wasLineBreaker || kBRLength == 1) {
   2423        continue;
   2424      }
   2425 
   2426      MOZ_ASSERT(kBRLength == 2);
   2427 
   2428      // If it's already reached the end of query range, we don't need to do
   2429      // anymore.
   2430      if (offset == kEndOffset) {
   2431        break;
   2432      }
   2433 
   2434      // If the query range starts from between a line breaker, i.e., it starts
   2435      // between "\r" and "\n", the appended rect was for the "\n".  Therefore,
   2436      // we don't need to append same rect anymore for current "\r\n".
   2437      if (startsBetweenLineBreaker) {
   2438        continue;
   2439      }
   2440 
   2441      // The appended rect was for "\r" of "\r\n".  Therefore, we need to
   2442      // append same rect for "\n" too because querying rect of "\r" and "\n"
   2443      // should return same rect.  E.g., IME may query previous character's
   2444      // rect of first character of a line.
   2445      aEvent->mReply->mRectArray.AppendElement(rect);
   2446      offset++;
   2447    }
   2448  }
   2449 
   2450  // If we've not handled some invisible character rects, fill them as caret
   2451  // rect after the last visible character.
   2452  if (!aEvent->mReply->mRectArray.IsEmpty()) {
   2453    const uint32_t offsetInRange =
   2454        offset - CheckedInt<uint32_t>(aEvent->mInput.mOffset).value();
   2455    if (offsetInRange > aEvent->mReply->mRectArray.Length()) {
   2456      LayoutDeviceIntRect caretRectAfter =
   2457          GetCaretRectAfter(aEvent->mReply->mRectArray.LastElement(),
   2458                            lastVisibleFrameWritingMode);
   2459      for ([[maybe_unused]] uint32_t index : IntegerRange<uint32_t>(
   2460               offsetInRange - aEvent->mReply->mRectArray.Length())) {
   2461        aEvent->mReply->mRectArray.AppendElement(caretRectAfter);
   2462      }
   2463      MOZ_ASSERT(aEvent->mReply->mRectArray.Length() == offsetInRange);
   2464    }
   2465  }
   2466 
   2467  // If the query range is longer than actual content length, we should append
   2468  // caret rect at the end of the content as the last character rect because
   2469  // native IME may want to query character rect at the end of contents for
   2470  // deciding the position of a popup window (e.g., suggest window for next
   2471  // word).  Note that when this method hasn't appended character rects, it
   2472  // means that the offset is too large or the query range is collapsed.
   2473  if (offset < kEndOffset || aEvent->mReply->mRectArray.IsEmpty()) {
   2474    // If we've already retrieved some character rects before current offset,
   2475    // we can guess the last rect from the last character's rect unless it's a
   2476    // line breaker.  (If it's a line breaker, the caret rect is in next line.)
   2477    if (!aEvent->mReply->mRectArray.IsEmpty() && !wasLineBreaker) {
   2478      rect = GetCaretRectAfter(aEvent->mReply->mRectArray.LastElement(),
   2479                               lastVisibleFrameWritingMode);
   2480      aEvent->mReply->mRectArray.AppendElement(rect);
   2481    } else {
   2482      // Note that don't use eQueryCaretRect here because if caret is at the
   2483      // end of the content, it returns actual caret rect instead of computing
   2484      // the rect itself.  It means that the result depends on caret position.
   2485      // So, we shouldn't use it for consistency result in automated tests.
   2486      WidgetQueryContentEvent queryTextRectEvent(eQueryTextRect, *aEvent);
   2487      WidgetQueryContentEvent::Options options(*aEvent);
   2488      queryTextRectEvent.InitForQueryTextRect(offset, 1, options);
   2489      if (NS_WARN_IF(NS_FAILED(OnQueryTextRect(&queryTextRectEvent))) ||
   2490          NS_WARN_IF(queryTextRectEvent.Failed())) {
   2491        return NS_ERROR_FAILURE;
   2492      }
   2493      if (queryTextRectEvent.mReply->mWritingMode.IsVertical()) {
   2494        queryTextRectEvent.mReply->mRect.height = 1;
   2495      } else {
   2496        queryTextRectEvent.mReply->mRect.width = 1;
   2497      }
   2498      aEvent->mReply->mRectArray.AppendElement(
   2499          queryTextRectEvent.mReply->mRect);
   2500    }
   2501  }
   2502 
   2503  MOZ_ASSERT(aEvent->Succeeded());
   2504  return NS_OK;
   2505 }
   2506 
   2507 nsresult ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent) {
   2508  // If mLength is 0 (this may be caused by bug of native IME), we should
   2509  // redirect this event to OnQueryCaretRect().
   2510  if (!aEvent->mInput.mLength) {
   2511    return OnQueryCaretRect(aEvent);
   2512  }
   2513 
   2514  nsresult rv = Init(aEvent);
   2515  if (NS_FAILED(rv)) {
   2516    return rv;
   2517  }
   2518 
   2519  MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
   2520 
   2521  LineBreakType lineBreakType = GetLineBreakType(aEvent);
   2522  Result<DOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
   2523      domRangeAndAdjustedOffsetOrError = ConvertFlatTextOffsetToDOMRange(
   2524          aEvent->mInput.mOffset, aEvent->mInput.mLength, lineBreakType, true);
   2525  if (MOZ_UNLIKELY(domRangeAndAdjustedOffsetOrError.isErr())) {
   2526    NS_WARNING("ContentEventHandler::ConvertFlatTextOffsetToDOMRange() failed");
   2527    return NS_ERROR_FAILURE;
   2528  }
   2529  DOMRangeAndAdjustedOffsetInFlattenedText domRangeAndAdjustedOffset =
   2530      domRangeAndAdjustedOffsetOrError.unwrap();
   2531  nsString string;
   2532  if (NS_WARN_IF(NS_FAILED(GenerateFlatTextContent(
   2533          domRangeAndAdjustedOffset.mRange, string, lineBreakType)))) {
   2534    return NS_ERROR_FAILURE;
   2535  }
   2536  aEvent->mReply->mOffsetAndData.emplace(
   2537      domRangeAndAdjustedOffset.mAdjustedOffset, string,
   2538      OffsetAndDataFor::EditorString);
   2539 
   2540  // used to iterate over all contents and their frames
   2541  PostContentIterator postOrderIter;
   2542  rv = postOrderIter.Init(domRangeAndAdjustedOffset.mRange.Start().AsRaw(),
   2543                          domRangeAndAdjustedOffset.mRange.End().AsRaw());
   2544  if (NS_WARN_IF(NS_FAILED(rv))) {
   2545    return NS_ERROR_FAILURE;
   2546  }
   2547 
   2548  // Get the first frame which causes some text after the offset.
   2549  FrameAndNodeOffset firstFrame =
   2550      GetFirstFrameInRangeForTextRect(domRangeAndAdjustedOffset.mRange);
   2551 
   2552  // If GetFirstFrameInRangeForTextRect() does not return valid frame, that
   2553  // means that there are no visible frames having text or the offset reached
   2554  // the end of contents.
   2555  if (!firstFrame.IsValid()) {
   2556    nsAutoString allText;
   2557    rv = GenerateFlatTextContent(mRootElement, allText, lineBreakType);
   2558    // If the offset doesn't reach the end of contents but there is no frames
   2559    // for the node, that means that current offset's node is hidden by CSS or
   2560    // something.  Ideally, we should handle it with the last visible text
   2561    // node's last character's rect, but it's not usual cases in actual web
   2562    // services.  Therefore, currently, we should make this case fail.
   2563    if (NS_WARN_IF(NS_FAILED(rv)) ||
   2564        static_cast<uint32_t>(aEvent->mInput.mOffset) < allText.Length()) {
   2565      return NS_ERROR_FAILURE;
   2566    }
   2567 
   2568    // Look for the last frame which should be included text rects.
   2569    rv = domRangeAndAdjustedOffset.mRange.SelectNodeContents(mRootElement);
   2570    if (NS_WARN_IF(NS_FAILED(rv))) {
   2571      return NS_ERROR_UNEXPECTED;
   2572    }
   2573    nsRect rect;
   2574    FrameAndNodeOffset lastFrame =
   2575        GetLastFrameInRangeForTextRect(domRangeAndAdjustedOffset.mRange);
   2576    // If there is at least one frame which can be used for computing a rect
   2577    // for a character or a line breaker, we should use it for guessing the
   2578    // caret rect at the end of the contents.
   2579    nsPresContext* presContext;
   2580    if (lastFrame) {
   2581      presContext = lastFrame->PresContext();
   2582      if (NS_WARN_IF(!lastFrame->GetContent())) {
   2583        return NS_ERROR_FAILURE;
   2584      }
   2585      FrameRelativeRect relativeRect;
   2586      // If there is a <br> frame at the end, it represents an empty line at
   2587      // the end with moz-<br> or content <br> in a block level element.
   2588      if (lastFrame->IsBrFrame()) {
   2589        relativeRect = GetLineBreakerRectBefore(lastFrame);
   2590      }
   2591      // If there is a text frame at the end, use its information.
   2592      else if (lastFrame->IsTextFrame()) {
   2593        const Text* textNode = Text::FromNode(lastFrame->GetContent());
   2594        MOZ_ASSERT(textNode);
   2595        if (textNode) {
   2596          relativeRect = GuessLineBreakerRectAfter(*textNode);
   2597        }
   2598      }
   2599      // If there is an empty frame which is neither a text frame nor a <br>
   2600      // frame at the end, guess caret rect in it.
   2601      else {
   2602        relativeRect = GuessFirstCaretRectIn(lastFrame);
   2603      }
   2604      if (NS_WARN_IF(!relativeRect.IsValid())) {
   2605        return NS_ERROR_FAILURE;
   2606      }
   2607      rect = relativeRect.RectRelativeTo(lastFrame);
   2608      rv = ConvertToRootRelativeOffset(lastFrame, rect);
   2609      if (NS_WARN_IF(NS_FAILED(rv))) {
   2610        return rv;
   2611      }
   2612      aEvent->mReply->mWritingMode = lastFrame->GetWritingMode();
   2613    }
   2614    // Otherwise, if there are no contents in mRootElement, guess caret rect in
   2615    // its frame (with its font height and content box).
   2616    else {
   2617      nsIFrame* rootContentFrame = mRootElement->GetPrimaryFrame();
   2618      if (NS_WARN_IF(!rootContentFrame)) {
   2619        return NS_ERROR_FAILURE;
   2620      }
   2621      presContext = rootContentFrame->PresContext();
   2622      FrameRelativeRect relativeRect = GuessFirstCaretRectIn(rootContentFrame);
   2623      if (NS_WARN_IF(!relativeRect.IsValid())) {
   2624        return NS_ERROR_FAILURE;
   2625      }
   2626      rect = relativeRect.RectRelativeTo(rootContentFrame);
   2627      rv = ConvertToRootRelativeOffset(rootContentFrame, rect);
   2628      if (NS_WARN_IF(NS_FAILED(rv))) {
   2629        return rv;
   2630      }
   2631      aEvent->mReply->mWritingMode = rootContentFrame->GetWritingMode();
   2632    }
   2633    aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
   2634        rect, presContext->AppUnitsPerDevPixel());
   2635    if (nsPresContext* rootContext =
   2636            presContext->GetInProcessRootContentDocumentPresContext()) {
   2637      aEvent->mReply->mRect =
   2638          RoundedOut(ViewportUtils::DocumentRelativeLayoutToVisual(
   2639              aEvent->mReply->mRect, rootContext->PresShell()));
   2640    }
   2641    EnsureNonEmptyRect(aEvent->mReply->mRect);
   2642 
   2643    MOZ_ASSERT(aEvent->Succeeded());
   2644    return NS_OK;
   2645  }
   2646 
   2647  nsRect rect, frameRect;
   2648  nsPoint ptOffset;
   2649 
   2650  // If the first frame is a text frame, the result should be computed with
   2651  // the frame's rect but not including the rect before start point of the
   2652  // queried range.
   2653  if (firstFrame->IsTextFrame()) {
   2654    rect.SetRect(nsPoint(0, 0), firstFrame->GetRect().Size());
   2655    rv = ConvertToRootRelativeOffset(firstFrame, rect);
   2656    if (NS_WARN_IF(NS_FAILED(rv))) {
   2657      return rv;
   2658    }
   2659    frameRect = rect;
   2660    // Exclude the rect before start point of the queried range.
   2661    firstFrame->GetPointFromOffset(firstFrame.mOffsetInNode, &ptOffset);
   2662    if (firstFrame->GetWritingMode().IsVertical()) {
   2663      rect.y += ptOffset.y;
   2664      rect.height -= ptOffset.y;
   2665    } else {
   2666      rect.x += ptOffset.x;
   2667      rect.width -= ptOffset.x;
   2668    }
   2669  }
   2670  // If first frame causes a line breaker but it's not a <br> frame, we cannot
   2671  // compute proper rect only with the frame because typically caret is at
   2672  // right of the last character of it.  For example, if caret is after "c" of
   2673  // |<p>abc</p><p>def</p>|, IME may query a line breaker's rect after "c".
   2674  // Then, if we compute it only with the 2nd <p>'s block frame, the result
   2675  // will be:
   2676  //  +-<p>--------------------------------+
   2677  //  |abc                                 |
   2678  //  +------------------------------------+
   2679  //
   2680  // I+-<p>--------------------------------+
   2681  //  |def                                 |
   2682  //  +------------------------------------+
   2683  // However, users expect popup windows of IME should be positioned at
   2684  // right-bottom of "c" like this:
   2685  //  +-<p>--------------------------------+
   2686  //  |abcI                                |
   2687  //  +------------------------------------+
   2688  //
   2689  //  +-<p>--------------------------------+
   2690  //  |def                                 |
   2691  //  +------------------------------------+
   2692  // Therefore, if the first frame isn't a <br> frame and there is a visible
   2693  // text node before the first node in the queried range, we should compute the
   2694  // first rect with the previous character's rect.
   2695  else if (!firstFrame->IsBrFrame() &&
   2696           domRangeAndAdjustedOffset.mLastTextNode &&
   2697           domRangeAndAdjustedOffset.mLastTextNode->GetPrimaryFrame()) {
   2698    FrameRelativeRect brRectAfterLastChar =
   2699        GuessLineBreakerRectAfter(*domRangeAndAdjustedOffset.mLastTextNode);
   2700    if (NS_WARN_IF(!brRectAfterLastChar.IsValid())) {
   2701      return NS_ERROR_FAILURE;
   2702    }
   2703    rect = brRectAfterLastChar.mRect;
   2704    rv = ConvertToRootRelativeOffset(brRectAfterLastChar.mBaseFrame, rect);
   2705    if (NS_WARN_IF(NS_FAILED(rv))) {
   2706      return rv;
   2707    }
   2708    frameRect = rect;
   2709  }
   2710  // Otherwise, we need to compute the line breaker's rect only with the
   2711  // first frame's rect.  But this may be unexpected.  For example,
   2712  // |<div contenteditable>[<p>]abc</p></div>|.  In this case, caret is before
   2713  // "a", therefore, users expect the rect left of "a".  However, we don't
   2714  // have enough information about the next character here and this isn't
   2715  // usual case (e.g., IME typically tries to query the rect of "a" or caret
   2716  // rect for computing its popup position).  Therefore, we shouldn't do
   2717  // more complicated hack here unless we'll get some bug reports actually.
   2718  else {
   2719    FrameRelativeRect relativeRect = GetLineBreakerRectBefore(firstFrame);
   2720    if (NS_WARN_IF(!relativeRect.IsValid())) {
   2721      return NS_ERROR_FAILURE;
   2722    }
   2723    rect = relativeRect.RectRelativeTo(firstFrame);
   2724    rv = ConvertToRootRelativeOffset(firstFrame, rect);
   2725    if (NS_WARN_IF(NS_FAILED(rv))) {
   2726      return rv;
   2727    }
   2728    frameRect = rect;
   2729  }
   2730  // UnionRect() requires non-empty rect.  So, let's make sure to get non-emtpy
   2731  // rect from the first frame.
   2732  EnsureNonEmptyRect(rect);
   2733 
   2734  // Get the last frame which causes some text in the range.
   2735  FrameAndNodeOffset lastFrame =
   2736      GetLastFrameInRangeForTextRect(domRangeAndAdjustedOffset.mRange);
   2737  if (NS_WARN_IF(!lastFrame.IsValid())) {
   2738    return NS_ERROR_FAILURE;
   2739  }
   2740 
   2741  // iterate over all covered frames
   2742  for (nsIFrame* frame = firstFrame; frame != lastFrame;) {
   2743    frame = frame->GetNextContinuation();
   2744    if (!frame) {
   2745      do {
   2746        postOrderIter.Next();
   2747        nsINode* node = postOrderIter.GetCurrentNode();
   2748        if (!node) {
   2749          break;
   2750        }
   2751        if (!node->IsContent()) {
   2752          continue;
   2753        }
   2754        nsIFrame* primaryFrame = node->AsContent()->GetPrimaryFrame();
   2755        // The node may be hidden by CSS.
   2756        if (!primaryFrame) {
   2757          continue;
   2758        }
   2759        // We should take only text frame's rect and br frame's rect.  We can
   2760        // always use frame rect of text frame and GetLineBreakerRectBefore()
   2761        // can return exactly correct rect only for <br> frame for now.  On the
   2762        // other hand, GetLineBreakRectBefore() returns guessed caret rect for
   2763        // the other frames.  We shouldn't include such odd rect to the result.
   2764        if (primaryFrame->IsTextFrame() || primaryFrame->IsBrFrame()) {
   2765          frame = primaryFrame;
   2766        }
   2767      } while (!frame && !postOrderIter.IsDone());
   2768      if (!frame) {
   2769        break;
   2770      }
   2771    }
   2772    if (frame->IsTextFrame()) {
   2773      frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size());
   2774    } else {
   2775      MOZ_ASSERT(frame->IsBrFrame());
   2776      FrameRelativeRect relativeRect = GetLineBreakerRectBefore(frame);
   2777      if (NS_WARN_IF(!relativeRect.IsValid())) {
   2778        return NS_ERROR_FAILURE;
   2779      }
   2780      frameRect = relativeRect.RectRelativeTo(frame);
   2781    }
   2782    rv = ConvertToRootRelativeOffset(frame, frameRect);
   2783    if (NS_WARN_IF(NS_FAILED(rv))) {
   2784      return rv;
   2785    }
   2786    // UnionRect() requires non-empty rect.  So, let's make sure to get
   2787    // non-emtpy rect from the frame.
   2788    EnsureNonEmptyRect(frameRect);
   2789    if (frame != lastFrame) {
   2790      // not last frame, so just add rect to previous result
   2791      rect.UnionRect(rect, frameRect);
   2792    }
   2793  }
   2794 
   2795  // Get the ending frame rect.
   2796  // FYI: If first frame and last frame are same, frameRect is already set
   2797  //      to the rect excluding the text before the query range.
   2798  if (firstFrame.mFrame != lastFrame.mFrame) {
   2799    frameRect.SetRect(nsPoint(0, 0), lastFrame->GetRect().Size());
   2800    rv = ConvertToRootRelativeOffset(lastFrame, frameRect);
   2801    if (NS_WARN_IF(NS_FAILED(rv))) {
   2802      return rv;
   2803    }
   2804  }
   2805 
   2806  // Shrink the last frame for cutting off the text after the query range.
   2807  if (lastFrame->IsTextFrame()) {
   2808    lastFrame->GetPointFromOffset(lastFrame.mOffsetInNode, &ptOffset);
   2809    if (lastFrame->GetWritingMode().IsVertical()) {
   2810      frameRect.height -= lastFrame->GetRect().height - ptOffset.y;
   2811    } else {
   2812      frameRect.width -= lastFrame->GetRect().width - ptOffset.x;
   2813    }
   2814    // UnionRect() requires non-empty rect.  So, let's make sure to get
   2815    // non-empty rect from the last frame.
   2816    EnsureNonEmptyRect(frameRect);
   2817 
   2818    if (firstFrame.mFrame == lastFrame.mFrame) {
   2819      rect.IntersectRect(rect, frameRect);
   2820    } else {
   2821      rect.UnionRect(rect, frameRect);
   2822    }
   2823  }
   2824 
   2825  nsPresContext* presContext = lastFrame->PresContext();
   2826  aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
   2827      rect, presContext->AppUnitsPerDevPixel());
   2828  if (nsPresContext* rootContext =
   2829          presContext->GetInProcessRootContentDocumentPresContext()) {
   2830    aEvent->mReply->mRect =
   2831        RoundedOut(ViewportUtils::DocumentRelativeLayoutToVisual(
   2832            aEvent->mReply->mRect, rootContext->PresShell()));
   2833  }
   2834  // Returning empty rect may cause native IME confused, let's make sure to
   2835  // return non-empty rect.
   2836  EnsureNonEmptyRect(aEvent->mReply->mRect);
   2837  aEvent->mReply->mWritingMode = lastFrame->GetWritingMode();
   2838 
   2839  MOZ_ASSERT(aEvent->Succeeded());
   2840  return NS_OK;
   2841 }
   2842 
   2843 nsresult ContentEventHandler::OnQueryEditorRect(
   2844    WidgetQueryContentEvent* aEvent) {
   2845  nsresult rv = Init(aEvent);
   2846  if (NS_FAILED(rv)) {
   2847    return rv;
   2848  }
   2849 
   2850  if (NS_WARN_IF(NS_FAILED(QueryContentRect(mRootElement, aEvent)))) {
   2851    return NS_ERROR_FAILURE;
   2852  }
   2853 
   2854  MOZ_ASSERT(aEvent->Succeeded());
   2855  return NS_OK;
   2856 }
   2857 
   2858 nsresult ContentEventHandler::OnQueryCaretRect(
   2859    WidgetQueryContentEvent* aEvent) {
   2860  nsresult rv = Init(aEvent);
   2861  if (NS_FAILED(rv)) {
   2862    return rv;
   2863  }
   2864 
   2865  // When the selection is collapsed and the queried offset is current caret
   2866  // position, we should return the "real" caret rect.
   2867  if (mSelection->IsCollapsed()) {
   2868    nsRect caretRect;
   2869    nsIFrame* caretFrame = nsCaret::GetGeometry(mSelection, &caretRect);
   2870    if (caretFrame) {
   2871      uint32_t offset;
   2872      rv = GetStartOffset(mFirstSelectedSimpleRange, &offset,
   2873                          GetLineBreakType(aEvent));
   2874      NS_ENSURE_SUCCESS(rv, rv);
   2875      if (offset == aEvent->mInput.mOffset) {
   2876        rv = ConvertToRootRelativeOffset(caretFrame, caretRect);
   2877        NS_ENSURE_SUCCESS(rv, rv);
   2878        nsPresContext* presContext = caretFrame->PresContext();
   2879        aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
   2880            caretRect, presContext->AppUnitsPerDevPixel());
   2881        if (nsPresContext* rootContext =
   2882                presContext->GetInProcessRootContentDocumentPresContext()) {
   2883          aEvent->mReply->mRect =
   2884              RoundedOut(ViewportUtils::DocumentRelativeLayoutToVisual(
   2885                  aEvent->mReply->mRect, rootContext->PresShell()));
   2886        }
   2887        // Returning empty rect may cause native IME confused, let's make sure
   2888        // to return non-empty rect.
   2889        EnsureNonEmptyRect(aEvent->mReply->mRect);
   2890        aEvent->mReply->mWritingMode = caretFrame->GetWritingMode();
   2891        aEvent->mReply->mOffsetAndData.emplace(
   2892            aEvent->mInput.mOffset, EmptyString(),
   2893            OffsetAndDataFor::SelectedString);
   2894 
   2895        MOZ_ASSERT(aEvent->Succeeded());
   2896        return NS_OK;
   2897      }
   2898    }
   2899  }
   2900 
   2901  // Otherwise, we should guess the caret rect from the character's rect.
   2902  WidgetQueryContentEvent queryTextRectEvent(eQueryTextRect, *aEvent);
   2903  WidgetQueryContentEvent::Options options(*aEvent);
   2904  queryTextRectEvent.InitForQueryTextRect(aEvent->mInput.mOffset, 1, options);
   2905  if (NS_WARN_IF(NS_FAILED(OnQueryTextRect(&queryTextRectEvent))) ||
   2906      NS_WARN_IF(queryTextRectEvent.Failed())) {
   2907    return NS_ERROR_FAILURE;
   2908  }
   2909  queryTextRectEvent.mReply->TruncateData();
   2910  aEvent->mReply->mOffsetAndData =
   2911      std::move(queryTextRectEvent.mReply->mOffsetAndData);
   2912  aEvent->mReply->mWritingMode =
   2913      std::move(queryTextRectEvent.mReply->mWritingMode);
   2914  aEvent->mReply->mRect = GetCaretRectBefore(queryTextRectEvent.mReply->mRect,
   2915                                             aEvent->mReply->mWritingMode);
   2916 
   2917  MOZ_ASSERT(aEvent->Succeeded());
   2918  return NS_OK;
   2919 }
   2920 
   2921 nsresult ContentEventHandler::OnQueryContentState(
   2922    WidgetQueryContentEvent* aEvent) {
   2923  if (NS_FAILED(Init(aEvent))) {
   2924    return NS_ERROR_FAILURE;
   2925  }
   2926  MOZ_ASSERT(aEvent->mReply.isSome());
   2927  MOZ_ASSERT(aEvent->Succeeded());
   2928  return NS_OK;
   2929 }
   2930 
   2931 nsresult ContentEventHandler::OnQuerySelectionAsTransferable(
   2932    WidgetQueryContentEvent* aEvent) {
   2933  nsresult rv = Init(aEvent);
   2934  if (NS_FAILED(rv)) {
   2935    return rv;
   2936  }
   2937 
   2938  MOZ_ASSERT(aEvent->mReply.isSome());
   2939 
   2940  if (mSelection->IsCollapsed()) {
   2941    MOZ_ASSERT(!aEvent->mReply->mTransferable);
   2942    return NS_OK;
   2943  }
   2944 
   2945  if (NS_WARN_IF(NS_FAILED(nsCopySupport::GetTransferableForSelection(
   2946          mSelection, mDocument,
   2947          getter_AddRefs(aEvent->mReply->mTransferable))))) {
   2948    return NS_ERROR_FAILURE;
   2949  }
   2950 
   2951  MOZ_ASSERT(aEvent->Succeeded());
   2952  return NS_OK;
   2953 }
   2954 
   2955 nsresult ContentEventHandler::OnQueryCharacterAtPoint(
   2956    WidgetQueryContentEvent* aEvent) {
   2957  nsresult rv = Init(aEvent);
   2958  if (NS_FAILED(rv)) {
   2959    return rv;
   2960  }
   2961 
   2962  MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
   2963  MOZ_ASSERT(aEvent->mReply->mTentativeCaretOffset.isNothing());
   2964 
   2965  PresShell* presShell = mDocument->GetPresShell();
   2966  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
   2967  nsIFrame* rootFrame = presShell->GetRootFrame();
   2968  NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
   2969  nsIWidget* rootWidget = rootFrame->GetNearestWidget();
   2970  NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
   2971 
   2972  // The root frame's widget might be different, e.g., the event was fired on
   2973  // a popup but the rootFrame is the document root.
   2974  if (rootWidget != aEvent->mWidget) {
   2975    MOZ_ASSERT(aEvent->mWidget, "The event must have the widget");
   2976    rootFrame = aEvent->mWidget->GetFrame();
   2977    NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
   2978    rootWidget = rootFrame->GetNearestWidget();
   2979    NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
   2980  }
   2981 
   2982  WidgetQueryContentEvent queryCharAtPointOnRootWidgetEvent(
   2983      true, eQueryCharacterAtPoint, rootWidget);
   2984  queryCharAtPointOnRootWidgetEvent.mUseNativeLineBreak =
   2985      aEvent->mUseNativeLineBreak;
   2986  queryCharAtPointOnRootWidgetEvent.mRefPoint = aEvent->mRefPoint;
   2987  if (rootWidget != aEvent->mWidget) {
   2988    queryCharAtPointOnRootWidgetEvent.mRefPoint +=
   2989        aEvent->mWidget->WidgetToScreenOffset() -
   2990        rootWidget->WidgetToScreenOffset();
   2991  }
   2992  nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(
   2993      &queryCharAtPointOnRootWidgetEvent, RelativeTo{rootFrame});
   2994 
   2995  nsIFrame* targetFrame =
   2996      nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
   2997  if (!targetFrame || !targetFrame->GetContent() ||
   2998      !targetFrame->GetContent()->IsInclusiveDescendantOf(mRootElement)) {
   2999    // There is no character at the point.
   3000    MOZ_ASSERT(aEvent->Succeeded());
   3001    return NS_OK;
   3002  }
   3003  nsPoint ptInTarget = ptInRoot + rootFrame->GetOffsetToCrossDoc(targetFrame);
   3004  int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
   3005  int32_t targetAPD = targetFrame->PresContext()->AppUnitsPerDevPixel();
   3006  ptInTarget = ptInTarget.ScaleToOtherAppUnits(rootAPD, targetAPD);
   3007 
   3008  nsIFrame::ContentOffsets tentativeCaretOffsets =
   3009      targetFrame->GetContentOffsetsFromPoint(ptInTarget);
   3010  if (!tentativeCaretOffsets.content ||
   3011      !tentativeCaretOffsets.content->IsInclusiveDescendantOf(mRootElement)) {
   3012    // There is no character nor tentative caret point at the point.
   3013    MOZ_ASSERT(aEvent->Succeeded());
   3014    return NS_OK;
   3015  }
   3016 
   3017  uint32_t tentativeCaretOffset = 0;
   3018  if (NS_WARN_IF(NS_FAILED(GetFlatTextLengthInRange(
   3019          RawNodePosition(mRootElement, 0u),
   3020          RawNodePosition(tentativeCaretOffsets), mRootElement,
   3021          &tentativeCaretOffset, GetLineBreakType(aEvent))))) {
   3022    return NS_ERROR_FAILURE;
   3023  }
   3024 
   3025  aEvent->mReply->mTentativeCaretOffset.emplace(tentativeCaretOffset);
   3026  if (!targetFrame->IsTextFrame()) {
   3027    // There is no character at the point but there is tentative caret point.
   3028    MOZ_ASSERT(aEvent->Succeeded());
   3029    return NS_OK;
   3030  }
   3031 
   3032  nsTextFrame* textframe = static_cast<nsTextFrame*>(targetFrame);
   3033  nsIFrame::ContentOffsets contentOffsets =
   3034      textframe->GetCharacterOffsetAtFramePoint(ptInTarget);
   3035  NS_ENSURE_TRUE(contentOffsets.content, NS_ERROR_FAILURE);
   3036  uint32_t offset = 0;
   3037  if (NS_WARN_IF(NS_FAILED(GetFlatTextLengthInRange(
   3038          RawNodePosition(mRootElement, 0u), RawNodePosition(contentOffsets),
   3039          mRootElement, &offset, GetLineBreakType(aEvent))))) {
   3040    return NS_ERROR_FAILURE;
   3041  }
   3042 
   3043  WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect,
   3044                                             aEvent->mWidget);
   3045  WidgetQueryContentEvent::Options options(*aEvent);
   3046  queryTextRectEvent.InitForQueryTextRect(offset, 1, options);
   3047  if (NS_WARN_IF(NS_FAILED(OnQueryTextRect(&queryTextRectEvent))) ||
   3048      NS_WARN_IF(queryTextRectEvent.Failed())) {
   3049    return NS_ERROR_FAILURE;
   3050  }
   3051 
   3052  aEvent->mReply->mOffsetAndData =
   3053      std::move(queryTextRectEvent.mReply->mOffsetAndData);
   3054  aEvent->mReply->mRect = queryTextRectEvent.mReply->mRect;
   3055 
   3056  MOZ_ASSERT(aEvent->Succeeded());
   3057  return NS_OK;
   3058 }
   3059 
   3060 nsresult ContentEventHandler::QueryHittestImpl(WidgetQueryContentEvent* aEvent,
   3061                                               bool aFlushLayout,
   3062                                               bool aPerformRetargeting,
   3063                                               Element** aContentUnderMouse) {
   3064  NS_ASSERTION(aEvent, "aEvent must not be null");
   3065 
   3066  nsresult rv = InitBasic();
   3067  if (NS_FAILED(rv)) {
   3068    return rv;
   3069  }
   3070 
   3071  NS_ENSURE_TRUE(aEvent->mWidget, NS_ERROR_FAILURE);
   3072 
   3073  PresShell* presShell = mDocument->GetPresShell();
   3074  NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
   3075  nsIFrame* docFrame = presShell->GetRootFrame();
   3076  NS_ENSURE_TRUE(docFrame, NS_ERROR_FAILURE);
   3077 
   3078  LayoutDeviceIntPoint eventLoc =
   3079      aEvent->mRefPoint + aEvent->mWidget->WidgetToScreenOffset();
   3080  CSSIntRect docFrameRect = docFrame->GetScreenRect();
   3081  CSSIntPoint eventLocCSS(
   3082      docFrame->PresContext()->DevPixelsToIntCSSPixels(eventLoc.x) -
   3083          docFrameRect.x,
   3084      docFrame->PresContext()->DevPixelsToIntCSSPixels(eventLoc.y) -
   3085          docFrameRect.y);
   3086  RefPtr<Element> contentUnderMouse = mDocument->ElementFromPointHelper(
   3087      eventLocCSS.x, eventLocCSS.y, false, false, ViewportType::Visual,
   3088      aPerformRetargeting);
   3089 
   3090  contentUnderMouse.forget(aContentUnderMouse);
   3091  return NS_OK;
   3092 }
   3093 
   3094 nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
   3095    WidgetQueryContentEvent* aEvent) {
   3096  aEvent->mReply->mWidgetIsHit = false;
   3097  RefPtr<Element> contentUnderMouse;
   3098  nsresult rv = QueryHittestImpl(aEvent, true /* flushLayout */,
   3099                                 true /* performRetargeting */,
   3100                                 getter_AddRefs(contentUnderMouse));
   3101  NS_ENSURE_SUCCESS(rv, rv);
   3102  if (contentUnderMouse) {
   3103    if (nsIFrame* targetFrame = contentUnderMouse->GetPrimaryFrame()) {
   3104      if (aEvent->mWidget == targetFrame->GetNearestWidget()) {
   3105        aEvent->mReply->mWidgetIsHit = true;
   3106      }
   3107    }
   3108  }
   3109 
   3110  MOZ_ASSERT(aEvent->Succeeded());
   3111  return NS_OK;
   3112 }
   3113 
   3114 nsresult ContentEventHandler::OnQueryDropTargetHittest(
   3115    WidgetQueryContentEvent* aEvent) {
   3116  RefPtr<Element> contentUnderMouse;
   3117  nsresult rv = QueryHittestImpl(aEvent, true /* flushLayout */,
   3118                                 false /* performRetargeting */,
   3119                                 getter_AddRefs(contentUnderMouse));
   3120  NS_ENSURE_SUCCESS(rv, rv);
   3121  aEvent->EmplaceReply();
   3122  aEvent->mReply->mDropElement = contentUnderMouse;
   3123  aEvent->mReply->mDropFrame =
   3124      mDocument->GetPresShell()->GetCurrentEventFrame();
   3125  return NS_OK;
   3126 }
   3127 
   3128 /* static */
   3129 nsresult ContentEventHandler::GetFlatTextLengthInRange(
   3130    const RawNodePosition& aStartPosition, const RawNodePosition& aEndPosition,
   3131    const Element* aRootElement, uint32_t* aLength,
   3132    LineBreakType aLineBreakType, bool aIsRemovingNode /* = false */) {
   3133  if (NS_WARN_IF(!aRootElement) || NS_WARN_IF(!aStartPosition.IsSet()) ||
   3134      NS_WARN_IF(!aEndPosition.IsSet()) || NS_WARN_IF(!aLength)) {
   3135    return NS_ERROR_INVALID_ARG;
   3136  }
   3137 
   3138  if (aStartPosition == aEndPosition) {
   3139    *aLength = 0;
   3140    return NS_OK;
   3141  }
   3142 
   3143  UnsafePreContentIterator preOrderIter;
   3144 
   3145  // Working with ContentIterator, we may need to adjust the end position for
   3146  // including it forcibly.
   3147  RawNodePosition endPosition(aEndPosition);
   3148 
   3149  // This may be called for retrieving the text of removed nodes. So, be careful
   3150  // to handle this case. FIXME: Do we need this special-case now?
   3151  if (aIsRemovingNode) {
   3152    MOZ_ASSERT(aStartPosition.GetContainer() == endPosition.GetContainer(),
   3153               "At removing the node, start and end node should be same");
   3154    MOZ_ASSERT(*aStartPosition.Offset(
   3155                   RawNodePosition::OffsetFilter::kValidOrInvalidOffsets) == 0,
   3156               "When the node is being removed, the start offset should be 0");
   3157    MOZ_ASSERT(
   3158        static_cast<uint32_t>(*endPosition.Offset(
   3159            RawNodePosition::OffsetFilter::kValidOrInvalidOffsets)) ==
   3160            endPosition.GetContainer()->GetChildCount(),
   3161        "When the node is being removed, the end offset should be child count");
   3162    nsresult rv = preOrderIter.Init(aStartPosition.GetContainer());
   3163    if (NS_WARN_IF(NS_FAILED(rv))) {
   3164      return rv;
   3165    }
   3166  } else {
   3167    SimpleRange prevSimpleRange;
   3168    nsresult rv = prevSimpleRange.SetStart(aStartPosition.AsRaw());
   3169    if (NS_WARN_IF(NS_FAILED(rv))) {
   3170      return rv;
   3171    }
   3172 
   3173    // When the end position is immediately after non-root element's open tag,
   3174    // we need to include a line break caused by the open tag.
   3175    if (endPosition.GetContainer() != aRootElement &&
   3176        endPosition.IsImmediatelyAfterOpenTag()) {
   3177      if (endPosition.GetContainer()->HasChildren()) {
   3178        // When the end node has some children, move the end position to before
   3179        // the open tag of its first child.
   3180        nsIContent* const firstChild =
   3181            endPosition.GetContainer()->GetFirstChild();
   3182        if (NS_WARN_IF(!firstChild)) {
   3183          return NS_ERROR_FAILURE;
   3184        }
   3185        endPosition = RawNodePosition::Before(*firstChild);
   3186      } else {
   3187        // When the end node is empty, move the end position after the node.
   3188        if (NS_WARN_IF(!endPosition.GetContainer()->IsContent())) {
   3189          return NS_ERROR_FAILURE;
   3190        }
   3191        nsIContent* const parentContent =
   3192            endPosition.GetContainer()->GetParent();
   3193        if (NS_WARN_IF(!parentContent)) {
   3194          return NS_ERROR_FAILURE;
   3195        }
   3196        endPosition =
   3197            RawNodePosition::After(*endPosition.GetContainer()->AsContent());
   3198      }
   3199    }
   3200 
   3201    if (endPosition.IsSetAndValid()) {
   3202      // Offset is within node's length; set end of range to that offset
   3203      rv = prevSimpleRange.SetEnd(endPosition.AsRaw());
   3204      if (NS_WARN_IF(NS_FAILED(rv))) {
   3205        return rv;
   3206      }
   3207      rv = preOrderIter.Init(prevSimpleRange.Start().AsRaw(),
   3208                             prevSimpleRange.End().AsRaw());
   3209      if (NS_WARN_IF(NS_FAILED(rv))) {
   3210        return rv;
   3211      }
   3212    } else if (endPosition.GetContainer() != aRootElement) {
   3213      // Offset is past node's length; set end of range to end of node
   3214      rv = prevSimpleRange.SetEndAfter(endPosition.GetContainer());
   3215      if (NS_WARN_IF(NS_FAILED(rv))) {
   3216        return rv;
   3217      }
   3218      rv = preOrderIter.Init(prevSimpleRange.Start().AsRaw(),
   3219                             prevSimpleRange.End().AsRaw());
   3220      if (NS_WARN_IF(NS_FAILED(rv))) {
   3221        return rv;
   3222      }
   3223    } else {
   3224      // Offset is past the root node; set end of range to end of root node
   3225      rv = preOrderIter.Init(const_cast<Element*>(aRootElement));
   3226      if (NS_WARN_IF(NS_FAILED(rv))) {
   3227        return rv;
   3228      }
   3229    }
   3230  }
   3231 
   3232  *aLength = 0;
   3233  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
   3234    nsINode* node = preOrderIter.GetCurrentNode();
   3235    if (NS_WARN_IF(!node)) {
   3236      break;
   3237    }
   3238    if (!node->IsContent()) {
   3239      continue;
   3240    }
   3241    nsIContent* content = node->AsContent();
   3242 
   3243    if (const Text* textNode = Text::FromNode(content)) {
   3244      // Note: our range always starts from offset 0
   3245      if (node == endPosition.GetContainer()) {
   3246        // NOTE: We should have an offset here, as endPosition.GetContainer() is
   3247        // a nsINode::eTEXT, which always has an offset.
   3248        *aLength += GetTextLength(
   3249            *textNode, aLineBreakType,
   3250            *endPosition.Offset(
   3251                RawNodePosition::OffsetFilter::kValidOrInvalidOffsets));
   3252      } else {
   3253        *aLength += GetTextLength(*textNode, aLineBreakType);
   3254      }
   3255    } else if (ShouldBreakLineBefore(*content, aRootElement)) {
   3256      // If the start position is start of this node but doesn't include the
   3257      // open tag, don't append the line break length.
   3258      if (node == aStartPosition.GetContainer() &&
   3259          !aStartPosition.IsBeforeOpenTag()) {
   3260        continue;
   3261      }
   3262      // If the end position is before the open tag, don't append the line
   3263      // break length.
   3264      if (node == endPosition.GetContainer() && endPosition.IsBeforeOpenTag()) {
   3265        continue;
   3266      }
   3267      *aLength += GetBRLength(aLineBreakType);
   3268    }
   3269  }
   3270  return NS_OK;
   3271 }
   3272 
   3273 template <typename SimpleRangeType>
   3274 nsresult ContentEventHandler::GetStartOffset(
   3275    const SimpleRangeType& aSimpleRange, uint32_t* aOffset,
   3276    LineBreakType aLineBreakType) {
   3277  // To match the "no skip start" hack in ContentIterator::Init, when range
   3278  // offset is 0 and the range node is not a container, we have to assume the
   3279  // range _includes_ the node, which means the start offset should _not_
   3280  // include the node.
   3281  //
   3282  // For example, for this content: <br>abc, and range (<br>, 0)-("abc", 1), the
   3283  // range includes the linebreak from <br>, so the start offset should _not_
   3284  // include <br>, and the start offset should be 0.
   3285  //
   3286  // However, for this content: <p/>abc, and range (<p>, 0)-("abc", 1), the
   3287  // range does _not_ include the linebreak from <p> because <p> is a container,
   3288  // so the start offset _should_ include <p>, and the start offset should be 1.
   3289 
   3290  nsINode* startNode = aSimpleRange.GetStartContainer();
   3291  bool startIsContainer = true;
   3292  if (startNode->IsHTMLElement()) {
   3293    nsAtom* name = startNode->NodeInfo()->NameAtom();
   3294    startIsContainer =
   3295        nsHTMLElement::IsContainer(nsHTMLTags::AtomTagToId(name));
   3296  }
   3297  RawNodePosition startPos(startNode, aSimpleRange.StartOffset());
   3298  startPos.mAfterOpenTag = startIsContainer;
   3299  return GetFlatTextLengthInRange(RawNodePosition(mRootElement, 0u), startPos,
   3300                                  mRootElement, aOffset, aLineBreakType);
   3301 }
   3302 
   3303 nsresult ContentEventHandler::AdjustCollapsedRangeMaybeIntoTextNode(
   3304    SimpleRange& aSimpleRange) {
   3305  MOZ_ASSERT(aSimpleRange.Collapsed());
   3306 
   3307  if (!aSimpleRange.Collapsed()) {
   3308    return NS_ERROR_INVALID_ARG;
   3309  }
   3310 
   3311  const RangeBoundary& startPoint = aSimpleRange.Start();
   3312  if (NS_WARN_IF(!startPoint.IsSet())) {
   3313    return NS_ERROR_INVALID_ARG;
   3314  }
   3315 
   3316  // If the node does not have children like a text node, we don't need to
   3317  // modify aSimpleRange.
   3318  if (!startPoint.GetContainer()->HasChildren()) {
   3319    return NS_OK;
   3320  }
   3321 
   3322  // If the container is not a text node but it has a text node at the offset,
   3323  // we should adjust the range into the text node.
   3324  // NOTE: This is emulating similar situation of EditorBase.
   3325  if (startPoint.IsStartOfContainer()) {
   3326    // If the range is the start of the container, adjusted the range to the
   3327    // start of the first child.
   3328    if (!startPoint.GetContainer()->GetFirstChild()->IsText()) {
   3329      return NS_OK;
   3330    }
   3331    nsresult rv = aSimpleRange.CollapseTo(
   3332        RawRangeBoundary(startPoint.GetContainer()->GetFirstChild(), 0u));
   3333    if (NS_WARN_IF(NS_FAILED(rv))) {
   3334      return rv;
   3335    }
   3336    return NS_OK;
   3337  }
   3338 
   3339  if (!startPoint.IsSetAndValid()) {
   3340    return NS_OK;
   3341  }
   3342 
   3343  // If start of the range is next to a child node, adjust the range to the
   3344  // end of the previous child (i.e., startPoint.Ref()).
   3345  if (!startPoint.Ref()->IsText()) {
   3346    return NS_OK;
   3347  }
   3348  nsresult rv = aSimpleRange.CollapseTo(
   3349      RawRangeBoundary(startPoint.Ref(), startPoint.Ref()->Length()));
   3350  if (NS_WARN_IF(NS_FAILED(rv))) {
   3351    return rv;
   3352  }
   3353  return NS_OK;
   3354 }
   3355 
   3356 nsresult ContentEventHandler::ConvertToRootRelativeOffset(nsIFrame* aFrame,
   3357                                                          nsRect& aRect) {
   3358  NS_ASSERTION(aFrame, "aFrame must not be null");
   3359 
   3360  nsPresContext* thisPC = aFrame->PresContext();
   3361  nsPresContext* rootPC = thisPC->GetRootPresContext();
   3362  if (NS_WARN_IF(!rootPC)) {
   3363    return NS_ERROR_FAILURE;
   3364  }
   3365  nsIFrame* rootFrame = rootPC->PresShell()->GetRootFrame();
   3366  if (NS_WARN_IF(!rootFrame)) {
   3367    return NS_ERROR_FAILURE;
   3368  }
   3369 
   3370  aRect = nsLayoutUtils::TransformFrameRectToAncestor(aFrame, aRect, rootFrame);
   3371 
   3372  // TransformFrameRectToAncestor returned the rect in the ancestor's appUnits,
   3373  // but we want it in aFrame's units (in case of different full-zoom factors),
   3374  // so convert back.
   3375  aRect = aRect.ScaleToOtherAppUnitsRoundOut(rootPC->AppUnitsPerDevPixel(),
   3376                                             thisPC->AppUnitsPerDevPixel());
   3377 
   3378  return NS_OK;
   3379 }
   3380 
   3381 static void AdjustRangeForSelection(const Element* aRootElement,
   3382                                    nsINode** aNode,
   3383                                    Maybe<uint32_t>* aNodeOffset) {
   3384  nsINode* node = *aNode;
   3385  Maybe<uint32_t> nodeOffset = *aNodeOffset;
   3386  if (aRootElement == node || NS_WARN_IF(!node->GetParent()) ||
   3387      !node->IsText()) {
   3388    return;
   3389  }
   3390 
   3391  // When the offset is at the end of the text node, set it to after the
   3392  // text node, to make sure the caret is drawn on a new line when the last
   3393  // character of the text node is '\n' in <textarea>.
   3394  const uint32_t textLength = node->AsContent()->TextLength();
   3395  MOZ_ASSERT(nodeOffset.isNothing() || *nodeOffset <= textLength,
   3396             "Offset is past length of text node");
   3397  if (nodeOffset.isNothing() || *nodeOffset != textLength) {
   3398    return;
   3399  }
   3400 
   3401  Element* rootParentElement = aRootElement->GetParentElement();
   3402  if (NS_WARN_IF(!rootParentElement)) {
   3403    return;
   3404  }
   3405  // If the root node is not an anonymous div of <textarea>, we don't need to
   3406  // do this hack.  If you did this, ContentEventHandler couldn't distinguish
   3407  // if the range includes open tag of the next node in some cases, e.g.,
   3408  // textNode]<p></p> vs. textNode<p>]</p>
   3409  if (!rootParentElement->IsHTMLElement(nsGkAtoms::textarea)) {
   3410    return;
   3411  }
   3412 
   3413  // If the node is being removed from its parent, it holds the ex-parent,
   3414  // but the parent have already removed the child from its child chain.
   3415  // Therefore `ComputeIndexOf` may fail, but I don't want to make Beta/Nightly
   3416  // crash at accessing `Maybe::operator*` so that here checks `isSome`, but
   3417  // crashing only in debug builds may help to debug something complicated
   3418  // situation, therefore, `MOZ_ASSERT` is put here.
   3419  *aNode = node->GetParent();
   3420  Maybe<uint32_t> index = (*aNode)->ComputeIndexOf(node);
   3421  MOZ_ASSERT(index.isSome());
   3422  if (index.isSome()) {
   3423    MOZ_ASSERT(*index != UINT32_MAX);
   3424    *aNodeOffset = Some(*index + 1u);
   3425  } else {
   3426    *aNodeOffset = Some(0u);
   3427  }
   3428 }
   3429 
   3430 nsresult ContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent) {
   3431  aEvent->mSucceeded = false;
   3432 
   3433  // Get selection to manipulate
   3434  // XXX why do we need to get them from ISM? This method should work fine
   3435  //     without ISM.
   3436  nsresult rv = IMEStateManager::GetFocusSelectionAndRootElement(
   3437      getter_AddRefs(mSelection), getter_AddRefs(mRootElement));
   3438  if (rv != NS_ERROR_NOT_AVAILABLE) {
   3439    NS_ENSURE_SUCCESS(rv, rv);
   3440  } else {
   3441    rv = Init(aEvent);
   3442    NS_ENSURE_SUCCESS(rv, rv);
   3443  }
   3444 
   3445  // Get range from offset and length
   3446  nsINode* startNode = nullptr;
   3447  nsINode* endNode = nullptr;
   3448  Maybe<uint32_t> startNodeOffset;
   3449  Maybe<uint32_t> endNodeOffset;
   3450  {
   3451    Result<UnsafeDOMRangeAndAdjustedOffsetInFlattenedText, nsresult>
   3452        domRangeAndAdjustedOffsetOrError =
   3453            ConvertFlatTextOffsetToUnsafeDOMRange(
   3454                aEvent->mOffset, aEvent->mLength, GetLineBreakType(aEvent),
   3455                aEvent->mExpandToClusterBoundary);
   3456    if (MOZ_UNLIKELY(domRangeAndAdjustedOffsetOrError.isErr())) {
   3457      NS_WARNING(
   3458          "ContentEventHandler::ConvertFlatTextOffsetToDOMRangeBase() failed");
   3459      return domRangeAndAdjustedOffsetOrError.unwrapErr();
   3460    }
   3461    const UnsafeDOMRangeAndAdjustedOffsetInFlattenedText
   3462        domRangeAndAdjustedOffset = domRangeAndAdjustedOffsetOrError.unwrap();
   3463    startNode = domRangeAndAdjustedOffset.mRange.GetStartContainer();
   3464    endNode = domRangeAndAdjustedOffset.mRange.GetEndContainer();
   3465    startNodeOffset = Some(domRangeAndAdjustedOffset.mRange.StartOffset());
   3466    endNodeOffset = Some(domRangeAndAdjustedOffset.mRange.EndOffset());
   3467    AdjustRangeForSelection(mRootElement, &startNode, &startNodeOffset);
   3468    AdjustRangeForSelection(mRootElement, &endNode, &endNodeOffset);
   3469    if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode) ||
   3470        NS_WARN_IF(startNodeOffset.isNothing()) ||
   3471        NS_WARN_IF(endNodeOffset.isNothing())) {
   3472      return NS_ERROR_UNEXPECTED;
   3473    }
   3474  }
   3475 
   3476  if (aEvent->mReversed) {
   3477    nsCOMPtr<nsINode> startNodeStrong(startNode);
   3478    nsCOMPtr<nsINode> endNodeStrong(endNode);
   3479    ErrorResult error;
   3480    MOZ_KnownLive(mSelection)
   3481        ->SetBaseAndExtentInLimiter(*endNodeStrong, *endNodeOffset,
   3482                                    *startNodeStrong, *startNodeOffset, error);
   3483    if (NS_WARN_IF(error.Failed())) {
   3484      return error.StealNSResult();
   3485    }
   3486  } else {
   3487    nsCOMPtr<nsINode> startNodeStrong(startNode);
   3488    nsCOMPtr<nsINode> endNodeStrong(endNode);
   3489    ErrorResult error;
   3490    MOZ_KnownLive(mSelection)
   3491        ->SetBaseAndExtentInLimiter(*startNodeStrong, *startNodeOffset,
   3492                                    *endNodeStrong, *endNodeOffset, error);
   3493    if (NS_WARN_IF(error.Failed())) {
   3494      return error.StealNSResult();
   3495    }
   3496  }
   3497 
   3498  // `ContentEventHandler` is a `MOZ_STACK_CLASS`, so `mSelection` is known to
   3499  // be alive.
   3500  MOZ_KnownLive(mSelection)
   3501      ->ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION);
   3502  aEvent->mSucceeded = true;
   3503  return NS_OK;
   3504 }
   3505 
   3506 nsRect ContentEventHandler::FrameRelativeRect::RectRelativeTo(
   3507    nsIFrame* aDestFrame) const {
   3508  if (!mBaseFrame || NS_WARN_IF(!aDestFrame)) {
   3509    return nsRect();
   3510  }
   3511 
   3512  if (NS_WARN_IF(aDestFrame->PresContext() != mBaseFrame->PresContext())) {
   3513    return nsRect();
   3514  }
   3515 
   3516  if (aDestFrame == mBaseFrame) {
   3517    return mRect;
   3518  }
   3519 
   3520  nsIFrame* rootFrame = mBaseFrame->PresShell()->GetRootFrame();
   3521  nsRect baseFrameRectInRootFrame = nsLayoutUtils::TransformFrameRectToAncestor(
   3522      mBaseFrame, nsRect(), rootFrame);
   3523  nsRect destFrameRectInRootFrame = nsLayoutUtils::TransformFrameRectToAncestor(
   3524      aDestFrame, nsRect(), rootFrame);
   3525  nsPoint difference =
   3526      destFrameRectInRootFrame.TopLeft() - baseFrameRectInRootFrame.TopLeft();
   3527  return mRect - difference;
   3528 }
   3529 
   3530 }  // namespace mozilla