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