ContentEventHandler.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef mozilla_ContentEventHandler_h_
  6. #define mozilla_ContentEventHandler_h_
  7. #include "mozilla/EventForwards.h"
  8. #include "mozilla/dom/Selection.h"
  9. #include "nsCOMPtr.h"
  10. #include "nsIFrame.h"
  11. #include "nsINode.h"
  12. #include "nsISelectionController.h"
  13. #include "nsRange.h"
  14. class nsPresContext;
  15. struct nsRect;
  16. namespace mozilla {
  17. enum LineBreakType
  18. {
  19. LINE_BREAK_TYPE_NATIVE,
  20. LINE_BREAK_TYPE_XP
  21. };
  22. /*
  23. * Query Content Event Handler
  24. * ContentEventHandler is a helper class for EventStateManager.
  25. * The platforms request some content informations, e.g., the selected text,
  26. * the offset of the selected text and the text for specified range.
  27. * This class answers to NS_QUERY_* events from actual contents.
  28. */
  29. class MOZ_STACK_CLASS ContentEventHandler
  30. {
  31. public:
  32. typedef dom::Selection Selection;
  33. explicit ContentEventHandler(nsPresContext* aPresContext);
  34. // Handle aEvent in the current process.
  35. nsresult HandleQueryContentEvent(WidgetQueryContentEvent* aEvent);
  36. // eQuerySelectedText event handler
  37. nsresult OnQuerySelectedText(WidgetQueryContentEvent* aEvent);
  38. // eQueryTextContent event handler
  39. nsresult OnQueryTextContent(WidgetQueryContentEvent* aEvent);
  40. // eQueryCaretRect event handler
  41. nsresult OnQueryCaretRect(WidgetQueryContentEvent* aEvent);
  42. // eQueryTextRect event handler
  43. nsresult OnQueryTextRect(WidgetQueryContentEvent* aEvent);
  44. // eQueryTextRectArray event handler
  45. nsresult OnQueryTextRectArray(WidgetQueryContentEvent* aEvent);
  46. // eQueryEditorRect event handler
  47. nsresult OnQueryEditorRect(WidgetQueryContentEvent* aEvent);
  48. // eQueryContentState event handler
  49. nsresult OnQueryContentState(WidgetQueryContentEvent* aEvent);
  50. // eQuerySelectionAsTransferable event handler
  51. nsresult OnQuerySelectionAsTransferable(WidgetQueryContentEvent* aEvent);
  52. // eQueryCharacterAtPoint event handler
  53. nsresult OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent);
  54. // eQueryDOMWidgetHittest event handler
  55. nsresult OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent);
  56. // NS_SELECTION_* event
  57. nsresult OnSelectionEvent(WidgetSelectionEvent* aEvent);
  58. protected:
  59. nsPresContext* mPresContext;
  60. nsCOMPtr<nsIPresShell> mPresShell;
  61. // mSelection is typically normal selection but if OnQuerySelectedText()
  62. // is called, i.e., handling eQuerySelectedText, it's the specified selection
  63. // by WidgetQueryContentEvent::mInput::mSelectionType.
  64. RefPtr<Selection> mSelection;
  65. // mFirstSelectedRange is the first selected range of mSelection. If
  66. // mSelection is normal selection, this must not be nullptr if Init()
  67. // succeed. Otherwise, this may be nullptr if there are no selection
  68. // ranges.
  69. RefPtr<nsRange> mFirstSelectedRange;
  70. nsCOMPtr<nsIContent> mRootContent;
  71. nsresult Init(WidgetQueryContentEvent* aEvent);
  72. nsresult Init(WidgetSelectionEvent* aEvent);
  73. nsresult InitBasic();
  74. nsresult InitCommon(SelectionType aSelectionType = SelectionType::eNormal);
  75. /**
  76. * InitRootContent() computes the root content of current focused editor.
  77. *
  78. * @param aNormalSelection This must be a Selection instance whose type is
  79. * SelectionType::eNormal.
  80. */
  81. nsresult InitRootContent(Selection* aNormalSelection);
  82. public:
  83. // FlatText means the text that is generated from DOM tree. The BR elements
  84. // are replaced to native linefeeds. Other elements are ignored.
  85. // NodePosition stores a pair of node and offset in the node.
  86. // When mNode is an element and mOffset is 0, the start position means after
  87. // the open tag of mNode.
  88. // This is useful to receive one or more sets of them instead of nsRange.
  89. struct NodePosition
  90. {
  91. nsCOMPtr<nsINode> mNode;
  92. int32_t mOffset;
  93. // Only when mNode is an element node and mOffset is 0, mAfterOpenTag is
  94. // referred.
  95. bool mAfterOpenTag;
  96. NodePosition()
  97. : mOffset(-1)
  98. , mAfterOpenTag(true)
  99. {
  100. }
  101. NodePosition(nsINode* aNode, int32_t aOffset)
  102. : mNode(aNode)
  103. , mOffset(aOffset)
  104. , mAfterOpenTag(true)
  105. {
  106. }
  107. explicit NodePosition(const nsIFrame::ContentOffsets& aContentOffsets)
  108. : mNode(aContentOffsets.content)
  109. , mOffset(aContentOffsets.offset)
  110. , mAfterOpenTag(true)
  111. {
  112. }
  113. protected:
  114. NodePosition(nsINode* aNode, int32_t aOffset, bool aAfterOpenTag)
  115. : mNode(aNode)
  116. , mOffset(aOffset)
  117. , mAfterOpenTag(aAfterOpenTag)
  118. {
  119. }
  120. public:
  121. bool operator==(const NodePosition& aOther) const
  122. {
  123. return mNode == aOther.mNode &&
  124. mOffset == aOther.mOffset &&
  125. mAfterOpenTag == aOther.mAfterOpenTag;
  126. }
  127. bool IsValid() const
  128. {
  129. return mNode && mOffset >= 0;
  130. }
  131. bool OffsetIsValid() const
  132. {
  133. return IsValid() && static_cast<uint32_t>(mOffset) <= mNode->Length();
  134. }
  135. bool IsBeforeOpenTag() const
  136. {
  137. return IsValid() && mNode->IsElement() && !mOffset && !mAfterOpenTag;
  138. }
  139. bool IsImmediatelyAfterOpenTag() const
  140. {
  141. return IsValid() && mNode->IsElement() && !mOffset && mAfterOpenTag;
  142. }
  143. nsresult SetToRangeStart(nsRange* aRange) const
  144. {
  145. nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
  146. return aRange->SetStart(domNode, mOffset);
  147. }
  148. nsresult SetToRangeEnd(nsRange* aRange) const
  149. {
  150. nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
  151. return aRange->SetEnd(domNode, mOffset);
  152. }
  153. nsresult SetToRangeEndAfter(nsRange* aRange) const
  154. {
  155. nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mNode));
  156. return aRange->SetEndAfter(domNode);
  157. }
  158. };
  159. // NodePositionBefore isn't good name if mNode isn't an element node nor
  160. // mOffset is not 0, though, when mNode is an element node and mOffset is 0,
  161. // this is treated as before the open tag of mNode.
  162. struct NodePositionBefore final : public NodePosition
  163. {
  164. NodePositionBefore(nsINode* aNode, int32_t aOffset)
  165. : NodePosition(aNode, aOffset, false)
  166. {
  167. }
  168. };
  169. // Get the flatten text length in the range.
  170. // @param aStartPosition Start node and offset in the node of the range.
  171. // @param aEndPosition End node and offset in the node of the range.
  172. // @param aRootContent The root content of the editor or document.
  173. // aRootContent won't cause any text including
  174. // line breaks.
  175. // @param aLength The result of the flatten text length of the
  176. // range.
  177. // @param aLineBreakType Whether this computes flatten text length with
  178. // native line breakers on the platform or
  179. // with XP line breaker (\n).
  180. // @param aIsRemovingNode Should be true only when this is called from
  181. // nsIMutationObserver::ContentRemoved().
  182. // When this is true, aStartPosition.mNode should
  183. // be the root node of removing nodes and mOffset
  184. // should be 0 and aEndPosition.mNode should be
  185. // same as aStartPosition.mNode and mOffset should
  186. // be number of the children of mNode.
  187. static nsresult GetFlatTextLengthInRange(const NodePosition& aStartPosition,
  188. const NodePosition& aEndPosition,
  189. nsIContent* aRootContent,
  190. uint32_t* aLength,
  191. LineBreakType aLineBreakType,
  192. bool aIsRemovingNode = false);
  193. // Computes the native text length between aStartOffset and aEndOffset of
  194. // aContent. aContent must be a text node.
  195. static uint32_t GetNativeTextLength(nsIContent* aContent,
  196. uint32_t aStartOffset,
  197. uint32_t aEndOffset);
  198. // Get the native text length of aContent. aContent must be a text node.
  199. static uint32_t GetNativeTextLength(nsIContent* aContent,
  200. uint32_t aMaxLength = UINT32_MAX);
  201. // Get the native text length which is inserted before aContent.
  202. // aContent should be an element.
  203. static uint32_t GetNativeTextLengthBefore(nsIContent* aContent,
  204. nsINode* aRootNode);
  205. protected:
  206. // Get the text length of aContent. aContent must be a text node.
  207. static uint32_t GetTextLength(nsIContent* aContent,
  208. LineBreakType aLineBreakType,
  209. uint32_t aMaxLength = UINT32_MAX);
  210. // Get the text length of a given range of a content node in
  211. // the given line break type.
  212. static uint32_t GetTextLengthInRange(nsIContent* aContent,
  213. uint32_t aXPStartOffset,
  214. uint32_t aXPEndOffset,
  215. LineBreakType aLineBreakType);
  216. // Get the contents in aContent (meaning all children of aContent) as plain
  217. // text. E.g., specifying mRootContent gets whole text in it.
  218. // Note that the result is not same as .textContent. The result is
  219. // optimized for native IMEs. For example, <br> element and some block
  220. // elements causes "\n" (or "\r\n"), see also ShouldBreakLineBefore().
  221. nsresult GenerateFlatTextContent(nsIContent* aContent,
  222. nsAFlatString& aString,
  223. LineBreakType aLineBreakType);
  224. // Get the contents of aRange as plain text.
  225. nsresult GenerateFlatTextContent(nsRange* aRange,
  226. nsAFlatString& aString,
  227. LineBreakType aLineBreakType);
  228. // Get offset of start of aRange. Note that the result includes the length
  229. // of line breaker caused by the start of aContent because aRange never
  230. // includes the line breaker caused by its start node.
  231. nsresult GetStartOffset(nsRange* aRange,
  232. uint32_t* aOffset,
  233. LineBreakType aLineBreakType);
  234. // Check if we should insert a line break before aContent.
  235. // This should return false only when aContent is an html element which
  236. // is typically used in a paragraph like <em>.
  237. static bool ShouldBreakLineBefore(nsIContent* aContent,
  238. nsINode* aRootNode);
  239. // Get the line breaker length.
  240. static inline uint32_t GetBRLength(LineBreakType aLineBreakType);
  241. static LineBreakType GetLineBreakType(WidgetQueryContentEvent* aEvent);
  242. static LineBreakType GetLineBreakType(WidgetSelectionEvent* aEvent);
  243. static LineBreakType GetLineBreakType(bool aUseNativeLineBreak);
  244. // Returns focused content (including its descendant documents).
  245. nsIContent* GetFocusedContent();
  246. // Returns true if the content is a plugin host.
  247. bool IsPlugin(nsIContent* aContent);
  248. // QueryContentRect() sets the rect of aContent's frame(s) to aEvent.
  249. nsresult QueryContentRect(nsIContent* aContent,
  250. WidgetQueryContentEvent* aEvent);
  251. // Make the DOM range from the offset of FlatText and the text length.
  252. // If aExpandToClusterBoundaries is true, the start offset and the end one are
  253. // expanded to nearest cluster boundaries.
  254. nsresult SetRangeFromFlatTextOffset(nsRange* aRange,
  255. uint32_t aOffset,
  256. uint32_t aLength,
  257. LineBreakType aLineBreakType,
  258. bool aExpandToClusterBoundaries,
  259. uint32_t* aNewOffset = nullptr,
  260. nsIContent** aLastTextNode = nullptr);
  261. // If the aRange isn't in text node but next to a text node, this method
  262. // modifies it in the text node. Otherwise, not modified.
  263. nsresult AdjustCollapsedRangeMaybeIntoTextNode(nsRange* aCollapsedRange);
  264. // Find the first frame for the range and get the start offset in it.
  265. nsresult GetStartFrameAndOffset(const nsRange* aRange,
  266. nsIFrame*& aFrame,
  267. int32_t& aOffsetInFrame);
  268. // Convert the frame relative offset to be relative to the root frame of the
  269. // root presContext (but still measured in appUnits of aFrame's presContext).
  270. nsresult ConvertToRootRelativeOffset(nsIFrame* aFrame,
  271. nsRect& aRect);
  272. // Expand aXPOffset to the nearest offset in cluster boundary. aForward is
  273. // true, it is expanded to forward.
  274. nsresult ExpandToClusterBoundary(nsIContent* aContent, bool aForward,
  275. uint32_t* aXPOffset);
  276. typedef nsTArray<mozilla::FontRange> FontRangeArray;
  277. static void AppendFontRanges(FontRangeArray& aFontRanges,
  278. nsIContent* aContent,
  279. int32_t aBaseOffset,
  280. int32_t aXPStartOffset,
  281. int32_t aXPEndOffset,
  282. LineBreakType aLineBreakType);
  283. nsresult GenerateFlatFontRanges(nsRange* aRange,
  284. FontRangeArray& aFontRanges,
  285. uint32_t& aLength,
  286. LineBreakType aLineBreakType);
  287. nsresult QueryTextRectByRange(nsRange* aRange,
  288. LayoutDeviceIntRect& aRect,
  289. WritingMode& aWritingMode);
  290. // Returns a node and position in the node for computing text rect.
  291. NodePosition GetNodePositionHavingFlatText(const NodePosition& aNodePosition);
  292. NodePosition GetNodePositionHavingFlatText(nsINode* aNode,
  293. int32_t aNodeOffset);
  294. struct MOZ_STACK_CLASS FrameAndNodeOffset final
  295. {
  296. // mFrame is safe since this can live in only stack class and
  297. // ContentEventHandler doesn't modify layout after
  298. // ContentEventHandler::Init() flushes pending layout. In other words,
  299. // this struct shouldn't be used before calling
  300. // ContentEventHandler::Init().
  301. nsIFrame* mFrame;
  302. // offset in the node of mFrame
  303. int32_t mOffsetInNode;
  304. FrameAndNodeOffset()
  305. : mFrame(nullptr)
  306. , mOffsetInNode(-1)
  307. {
  308. }
  309. FrameAndNodeOffset(nsIFrame* aFrame, int32_t aStartOffsetInNode)
  310. : mFrame(aFrame)
  311. , mOffsetInNode(aStartOffsetInNode)
  312. {
  313. }
  314. nsIFrame* operator->() { return mFrame; }
  315. const nsIFrame* operator->() const { return mFrame; }
  316. operator nsIFrame*() { return mFrame; }
  317. operator const nsIFrame*() const { return mFrame; }
  318. bool IsValid() const { return mFrame && mOffsetInNode >= 0; }
  319. };
  320. // Get first frame after the start of the given range for computing text rect.
  321. // This returns invalid FrameAndNodeOffset if there is no content which
  322. // should affect to computing text rect in the range. mOffsetInNode is start
  323. // offset in the frame.
  324. FrameAndNodeOffset GetFirstFrameInRangeForTextRect(nsRange* aRange);
  325. // Get last frame before the end of the given range for computing text rect.
  326. // This returns invalid FrameAndNodeOffset if there is no content which
  327. // should affect to computing text rect in the range. mOffsetInNode is end
  328. // offset in the frame.
  329. FrameAndNodeOffset GetLastFrameInRangeForTextRect(nsRange* aRange);
  330. struct MOZ_STACK_CLASS FrameRelativeRect final
  331. {
  332. // mRect is relative to the mBaseFrame's position.
  333. nsRect mRect;
  334. nsIFrame* mBaseFrame;
  335. FrameRelativeRect()
  336. : mBaseFrame(nullptr)
  337. {
  338. }
  339. explicit FrameRelativeRect(nsIFrame* aBaseFrame)
  340. : mBaseFrame(aBaseFrame)
  341. {
  342. }
  343. FrameRelativeRect(const nsRect& aRect, nsIFrame* aBaseFrame)
  344. : mRect(aRect)
  345. , mBaseFrame(aBaseFrame)
  346. {
  347. }
  348. bool IsValid() const { return mBaseFrame != nullptr; }
  349. // Returns an nsRect relative to aBaseFrame instead of mBaseFrame.
  350. nsRect RectRelativeTo(nsIFrame* aBaseFrame) const;
  351. };
  352. // Returns a rect for line breaker before the node of aFrame (If aFrame is
  353. // a <br> frame or a block level frame, it causes a line break at its
  354. // element's open tag, see also ShouldBreakLineBefore()). Note that this
  355. // doesn't check if aFrame should cause line break in non-debug build.
  356. FrameRelativeRect GetLineBreakerRectBefore(nsIFrame* aFrame);
  357. // Returns a line breaker rect after aTextContent as there is a line breaker
  358. // immediately after aTextContent. This is useful when following block
  359. // element causes a line break before it and it needs to compute the line
  360. // breaker's rect. For example, if there is |<p>abc</p><p>def</p>|, the
  361. // rect of 2nd <p>'s line breaker should be at right of "c" in the first
  362. // <p>, not the start of 2nd <p>. The result is relative to the last text
  363. // frame which represents the last character of aTextContent.
  364. FrameRelativeRect GuessLineBreakerRectAfter(nsIContent* aTextContent);
  365. // Returns a guessed first rect. I.e., it may be different from actual
  366. // caret when selection is collapsed at start of aFrame. For example, this
  367. // guess the caret rect only with the content box of aFrame and its font
  368. // height like:
  369. // +-aFrame----------------- (border box)
  370. // |
  371. // | +--------------------- (content box)
  372. // | | I
  373. // ^ guessed caret rect
  374. // However, actual caret is computed with more information like line-height,
  375. // child frames of aFrame etc. But this does not emulate actual caret
  376. // behavior exactly for simpler and faster code because it's difficult and
  377. // we're not sure it's worthwhile to do it with complicated implementation.
  378. FrameRelativeRect GuessFirstCaretRectIn(nsIFrame* aFrame);
  379. // Make aRect non-empty. If width and/or height is 0, these methods set them
  380. // to 1. Note that it doesn't set nsRect's width nor height to one device
  381. // pixel because using nsRect::ToOutsidePixels() makes actual width or height
  382. // to 2 pixels because x and y may not be aligned to device pixels.
  383. void EnsureNonEmptyRect(nsRect& aRect) const;
  384. void EnsureNonEmptyRect(LayoutDeviceIntRect& aRect) const;
  385. };
  386. } // namespace mozilla
  387. #endif // mozilla_ContentEventHandler_h_