LCOV - code coverage report
Current view: top level - dom/events - ContentEventHandler.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 67 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13