f78f8725263626cc52ad14003be1c4f14bab8c08
[WebKit-https.git] / Source / WebCore / editing / FrameSelection.h
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef FrameSelection_h
27 #define FrameSelection_h
28
29 #include "AXTextStateChangeIntent.h"
30 #include "EditingStyle.h"
31 #include "Element.h"
32 #include "IntRect.h"
33 #include "LayoutRect.h"
34 #include "Range.h"
35 #include "ScrollBehavior.h"
36 #include "Timer.h"
37 #include "VisibleSelection.h"
38 #include <wtf/Noncopyable.h>
39
40 #if PLATFORM(IOS)
41 #include "Color.h"
42 #endif
43
44 namespace WebCore {
45
46 class CharacterData;
47 class Frame;
48 class GraphicsContext;
49 class HTMLFormElement;
50 class MutableStyleProperties;
51 class RenderBlock;
52 class RenderObject;
53 class RenderView;
54 class Settings;
55 class VisiblePosition;
56
57 enum EUserTriggered { NotUserTriggered = 0, UserTriggered = 1 };
58
59 enum RevealExtentOption {
60     RevealExtent,
61     DoNotRevealExtent
62 };
63
64 class CaretBase {
65     WTF_MAKE_NONCOPYABLE(CaretBase);
66     WTF_MAKE_FAST_ALLOCATED;
67 protected:
68     enum CaretVisibility { Visible, Hidden };
69     explicit CaretBase(CaretVisibility = Hidden);
70
71     void invalidateCaretRect(Node*, bool caretRectChanged = false);
72     void clearCaretRect();
73     bool updateCaretRect(Document*, const VisiblePosition& caretPosition);
74     bool shouldRepaintCaret(const RenderView*, bool isContentEditable) const;
75     void paintCaret(Node*, GraphicsContext&, const LayoutPoint&, const LayoutRect& clipRect) const;
76
77     const LayoutRect& localCaretRectWithoutUpdate() const { return m_caretLocalRect; }
78
79     bool shouldUpdateCaretRect() const { return m_caretRectNeedsUpdate; }
80     void setCaretRectNeedsUpdate() { m_caretRectNeedsUpdate = true; }
81
82     void setCaretVisibility(CaretVisibility visibility) { m_caretVisibility = visibility; }
83     bool caretIsVisible() const { return m_caretVisibility == Visible; }
84     CaretVisibility caretVisibility() const { return m_caretVisibility; }
85
86 private:
87     LayoutRect m_caretLocalRect; // caret rect in coords local to the renderer responsible for painting the caret
88     bool m_caretRectNeedsUpdate; // true if m_caretRect (and m_absCaretBounds in FrameSelection) need to be calculated
89     CaretVisibility m_caretVisibility;
90 };
91
92 class DragCaretController : private CaretBase {
93     WTF_MAKE_NONCOPYABLE(DragCaretController);
94     WTF_MAKE_FAST_ALLOCATED;
95 public:
96     DragCaretController();
97
98     RenderBlock* caretRenderer() const;
99     void paintDragCaret(Frame*, GraphicsContext&, const LayoutPoint&, const LayoutRect& clipRect) const;
100
101     bool isContentEditable() const { return m_position.rootEditableElement(); }
102     bool isContentRichlyEditable() const;
103
104     bool hasCaret() const { return m_position.isNotNull(); }
105     const VisiblePosition& caretPosition() { return m_position; }
106     void setCaretPosition(const VisiblePosition&);
107     void clear() { setCaretPosition(VisiblePosition()); }
108
109     void nodeWillBeRemoved(Node&);
110
111 private:
112     VisiblePosition m_position;
113 };
114
115 class FrameSelection : private CaretBase {
116     WTF_MAKE_NONCOPYABLE(FrameSelection);
117     WTF_MAKE_FAST_ALLOCATED;
118 public:
119     enum EAlteration { AlterationMove, AlterationExtend };
120     enum CursorAlignOnScroll { AlignCursorOnScrollIfNeeded,
121                                AlignCursorOnScrollAlways };
122     enum SetSelectionOption {
123         FireSelectEvent = 1 << 0,
124         CloseTyping = 1 << 1,
125         ClearTypingStyle = 1 << 2,
126         SpellCorrectionTriggered = 1 << 3,
127         DoNotSetFocus = 1 << 4,
128         DictationTriggered = 1 << 5,
129         RevealSelection = 1 << 6,
130     };
131     typedef unsigned SetSelectionOptions; // Union of values in SetSelectionOption and EUserTriggered
132     static inline SetSelectionOptions defaultSetSelectionOptions(EUserTriggered userTriggered = NotUserTriggered)
133     {
134         return CloseTyping | ClearTypingStyle | (userTriggered ? (RevealSelection | FireSelectEvent) : 0);
135     }
136
137     WEBCORE_EXPORT explicit FrameSelection(Frame* = nullptr);
138
139     WEBCORE_EXPORT Element* rootEditableElementOrDocumentElement() const;
140      
141     void moveTo(const Range*);
142     WEBCORE_EXPORT void moveTo(const VisiblePosition&, EUserTriggered = NotUserTriggered, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded);
143     WEBCORE_EXPORT void moveTo(const VisiblePosition&, const VisiblePosition&, EUserTriggered = NotUserTriggered);
144     void moveTo(const Position&, EAffinity, EUserTriggered = NotUserTriggered);
145     void moveTo(const Position&, const Position&, EAffinity, EUserTriggered = NotUserTriggered);
146     void moveWithoutValidationTo(const Position&, const Position&, bool selectionHasDirection, bool shouldSetFocus, const AXTextStateChangeIntent& = AXTextStateChangeIntent());
147
148     const VisibleSelection& selection() const { return m_selection; }
149     WEBCORE_EXPORT void setSelection(const VisibleSelection&, SetSelectionOptions = defaultSetSelectionOptions(), AXTextStateChangeIntent = AXTextStateChangeIntent(), CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity);
150     WEBCORE_EXPORT bool setSelectedRange(Range*, EAffinity, bool closeTyping);
151     WEBCORE_EXPORT void selectAll();
152     WEBCORE_EXPORT void clear();
153     void prepareForDestruction();
154
155     void updateAppearanceAfterLayout();
156     void setNeedsSelectionUpdate();
157
158     bool contains(const LayoutPoint&);
159
160     WEBCORE_EXPORT bool modify(EAlteration, SelectionDirection, TextGranularity, EUserTriggered = NotUserTriggered);
161     enum VerticalDirection { DirectionUp, DirectionDown };
162     bool modify(EAlteration, unsigned verticalDistance, VerticalDirection, EUserTriggered = NotUserTriggered, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded);
163
164     TextGranularity granularity() const { return m_granularity; }
165
166     void setStart(const VisiblePosition &, EUserTriggered = NotUserTriggered);
167     void setEnd(const VisiblePosition &, EUserTriggered = NotUserTriggered);
168     
169     void setBase(const VisiblePosition&, EUserTriggered = NotUserTriggered);
170     void setBase(const Position&, EAffinity, EUserTriggered = NotUserTriggered);
171     void setExtent(const VisiblePosition&, EUserTriggered = NotUserTriggered);
172     void setExtent(const Position&, EAffinity, EUserTriggered = NotUserTriggered);
173
174     // Return the renderer that is responsible for painting the caret (in the selection start node)
175     RenderBlock* caretRendererWithoutUpdatingLayout() const;
176
177     // Bounds of (possibly transformed) caret in absolute coords
178     WEBCORE_EXPORT IntRect absoluteCaretBounds();
179     void setCaretRectNeedsUpdate() { CaretBase::setCaretRectNeedsUpdate(); }
180
181     void willBeModified(EAlteration, SelectionDirection);
182
183     bool isNone() const { return m_selection.isNone(); }
184     bool isCaret() const { return m_selection.isCaret(); }
185     bool isRange() const { return m_selection.isRange(); }
186     bool isCaretOrRange() const { return m_selection.isCaretOrRange(); }
187     bool isAll(EditingBoundaryCrossingRule rule = CannotCrossEditingBoundary) const { return m_selection.isAll(rule); }
188     
189     RefPtr<Range> toNormalizedRange() const { return m_selection.toNormalizedRange(); }
190
191     void debugRenderer(RenderObject*, bool selected) const;
192
193     void nodeWillBeRemoved(Node&);
194     void textWasReplaced(CharacterData*, unsigned offset, unsigned oldLength, unsigned newLength);
195
196     void setCaretVisible(bool caretIsVisible) { setCaretVisibility(caretIsVisible ? Visible : Hidden); }
197     void paintCaret(GraphicsContext&, const LayoutPoint&, const LayoutRect& clipRect);
198
199     // Used to suspend caret blinking while the mouse is down.
200     void setCaretBlinkingSuspended(bool suspended) { m_isCaretBlinkingSuspended = suspended; }
201     bool isCaretBlinkingSuspended() const { return m_isCaretBlinkingSuspended; }
202
203     // Focus
204     void setFocused(bool);
205     bool isFocused() const { return m_focused; }
206     WEBCORE_EXPORT bool isFocusedAndActive() const;
207     void pageActivationChanged();
208
209     // Painting.
210     WEBCORE_EXPORT void updateAppearance();
211
212 #if ENABLE(TREE_DEBUGGING)
213     void formatForDebugger(char* buffer, unsigned length) const;
214     void showTreeForThis() const;
215 #endif
216
217 #if PLATFORM(IOS)
218 public:
219     WEBCORE_EXPORT void expandSelectionToElementContainingCaretSelection();
220     WEBCORE_EXPORT PassRefPtr<Range> elementRangeContainingCaretSelection() const;
221     WEBCORE_EXPORT void expandSelectionToWordContainingCaretSelection();
222     WEBCORE_EXPORT PassRefPtr<Range> wordRangeContainingCaretSelection();
223     WEBCORE_EXPORT void expandSelectionToStartOfWordContainingCaretSelection();
224     WEBCORE_EXPORT UChar characterInRelationToCaretSelection(int amount) const;
225     WEBCORE_EXPORT UChar characterBeforeCaretSelection() const;
226     WEBCORE_EXPORT UChar characterAfterCaretSelection() const;
227     WEBCORE_EXPORT int wordOffsetInRange(const Range*) const;
228     WEBCORE_EXPORT bool spaceFollowsWordInRange(const Range*) const;
229     WEBCORE_EXPORT bool selectionAtDocumentStart() const;
230     WEBCORE_EXPORT bool selectionAtSentenceStart() const;
231     WEBCORE_EXPORT bool selectionAtWordStart() const;
232     WEBCORE_EXPORT PassRefPtr<Range> rangeByMovingCurrentSelection(int amount) const;
233     WEBCORE_EXPORT PassRefPtr<Range> rangeByExtendingCurrentSelection(int amount) const;
234     WEBCORE_EXPORT void selectRangeOnElement(unsigned location, unsigned length, Node&);
235     WEBCORE_EXPORT void clearCurrentSelection();
236     void setCaretBlinks(bool caretBlinks = true);
237     WEBCORE_EXPORT void setCaretColor(const Color&);
238     WEBCORE_EXPORT static VisibleSelection wordSelectionContainingCaretSelection(const VisibleSelection&);
239     void setUpdateAppearanceEnabled(bool enabled) { m_updateAppearanceEnabled = enabled; }
240     void suppressScrolling() { ++m_scrollingSuppressCount; }
241     void restoreScrolling()
242     {
243         ASSERT(m_scrollingSuppressCount);
244         --m_scrollingSuppressCount;
245     }
246 private:
247     bool actualSelectionAtSentenceStart(const VisibleSelection&) const;
248     PassRefPtr<Range> rangeByAlteringCurrentSelection(EAlteration, int amount) const;
249 public:
250 #endif
251
252     bool shouldChangeSelection(const VisibleSelection&) const;
253     bool shouldDeleteSelection(const VisibleSelection&) const;
254     enum EndPointsAdjustmentMode { AdjustEndpointsAtBidiBoundary, DoNotAdjsutEndpoints };
255     void setSelectionByMouseIfDifferent(const VisibleSelection&, TextGranularity, EndPointsAdjustmentMode = DoNotAdjsutEndpoints);
256
257     EditingStyle* typingStyle() const;
258     WEBCORE_EXPORT PassRefPtr<MutableStyleProperties> copyTypingStyle() const;
259     void setTypingStyle(PassRefPtr<EditingStyle>);
260     void clearTypingStyle();
261
262     WEBCORE_EXPORT FloatRect selectionBounds(bool clipToVisibleContent = true) const;
263
264     enum class TextRectangleHeight { TextHeight, SelectionHeight };
265     WEBCORE_EXPORT void getClippedVisibleTextRectangles(Vector<FloatRect>&, TextRectangleHeight = TextRectangleHeight::SelectionHeight) const;
266     WEBCORE_EXPORT void getTextRectangles(Vector<FloatRect>&, TextRectangleHeight = TextRectangleHeight::SelectionHeight) const;
267
268     WEBCORE_EXPORT HTMLFormElement* currentForm() const;
269
270     WEBCORE_EXPORT void revealSelection(SelectionRevealMode = SelectionRevealMode::Reveal, const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, RevealExtentOption = DoNotRevealExtent);
271     WEBCORE_EXPORT void setSelectionFromNone();
272
273     bool shouldShowBlockCursor() const { return m_shouldShowBlockCursor; }
274     void setShouldShowBlockCursor(bool);
275
276 private:
277     enum EPositionType { START, END, BASE, EXTENT };
278
279     void updateAndRevealSelection(const AXTextStateChangeIntent&);
280     void updateDataDetectorsForSelection();
281
282     bool setSelectionWithoutUpdatingAppearance(const VisibleSelection&, SetSelectionOptions, CursorAlignOnScroll, TextGranularity);
283
284     void respondToNodeModification(Node&, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved);
285     TextDirection directionOfEnclosingBlock();
286     TextDirection directionOfSelection();
287
288     VisiblePosition positionForPlatform(bool isGetStart) const;
289     VisiblePosition startForPlatform() const;
290     VisiblePosition endForPlatform() const;
291     VisiblePosition nextWordPositionForPlatform(const VisiblePosition&);
292
293     VisiblePosition modifyExtendingRight(TextGranularity);
294     VisiblePosition modifyExtendingForward(TextGranularity);
295     VisiblePosition modifyMovingRight(TextGranularity, bool* reachedBoundary = nullptr);
296     VisiblePosition modifyMovingForward(TextGranularity, bool* reachedBoundary = nullptr);
297     VisiblePosition modifyExtendingLeft(TextGranularity);
298     VisiblePosition modifyExtendingBackward(TextGranularity);
299     VisiblePosition modifyMovingLeft(TextGranularity, bool* reachedBoundary = nullptr);
300     VisiblePosition modifyMovingBackward(TextGranularity, bool* reachedBoundary = nullptr);
301
302     LayoutUnit lineDirectionPointForBlockDirectionNavigation(EPositionType);
303
304     AXTextStateChangeIntent textSelectionIntent(EAlteration, SelectionDirection, TextGranularity);
305 #if HAVE(ACCESSIBILITY)
306     void notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&);
307 #else
308     void notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&) { }
309 #endif
310
311     void updateSelectionCachesIfSelectionIsInsideTextFormControl(EUserTriggered);
312
313     void selectFrameElementInParentIfFullySelected();
314
315     void setFocusedElementIfNeeded();
316     void focusedOrActiveStateChanged();
317
318     void caretBlinkTimerFired();
319
320     void setCaretVisibility(CaretVisibility);
321     bool recomputeCaretRect();
322     void invalidateCaretRect();
323
324     bool dispatchSelectStart();
325
326     Frame* m_frame;
327
328     LayoutUnit m_xPosForVerticalArrowNavigation;
329
330     VisibleSelection m_selection;
331     VisiblePosition m_originalBase; // Used to store base before the adjustment at bidi boundary
332     TextGranularity m_granularity;
333
334     RefPtr<Node> m_previousCaretNode; // The last node which painted the caret. Retained for clearing the old caret when it moves.
335
336     RefPtr<EditingStyle> m_typingStyle;
337
338     Timer m_caretBlinkTimer;
339     // The painted bounds of the caret in absolute coordinates
340     IntRect m_absCaretBounds;
341     bool m_absCaretBoundsDirty : 1;
342     bool m_caretPaint : 1;
343     bool m_isCaretBlinkingSuspended : 1;
344     bool m_focused : 1;
345     bool m_shouldShowBlockCursor : 1;
346     bool m_pendingSelectionUpdate : 1;
347     bool m_shouldRevealSelection : 1;
348     bool m_alwaysAlignCursorOnScrollWhenRevealingSelection : 1;
349
350 #if PLATFORM(IOS)
351     bool m_updateAppearanceEnabled : 1;
352     bool m_caretBlinks : 1;
353     Color m_caretColor;
354     int m_scrollingSuppressCount { 0 };
355 #endif
356 };
357
358 inline EditingStyle* FrameSelection::typingStyle() const
359 {
360     return m_typingStyle.get();
361 }
362
363 inline void FrameSelection::clearTypingStyle()
364 {
365     m_typingStyle = nullptr;
366 }
367
368 inline void FrameSelection::setTypingStyle(PassRefPtr<EditingStyle> style)
369 {
370     m_typingStyle = style;
371 }
372
373 #if !(PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(EFL))
374 #if HAVE(ACCESSIBILITY)
375 inline void FrameSelection::notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&)
376 {
377 }
378 #endif
379 #endif
380
381 } // namespace WebCore
382
383 #if ENABLE(TREE_DEBUGGING)
384 // Outside the WebCore namespace for ease of invocation from gdb.
385 void showTree(const WebCore::FrameSelection&);
386 void showTree(const WebCore::FrameSelection*);
387 #endif
388
389 #endif // FrameSelection_h