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