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