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 SelectionController_h
27#define SelectionController_h
28
29#include "EditingStyle.h"
30#include "IntRect.h"
31#include "Range.h"
32#include "ScrollBehavior.h"
33#include "Timer.h"
34#include "VisibleSelection.h"
35#include <wtf/Noncopyable.h>
36
37namespace WebCore {
38
39class CharacterData;
40class CSSMutableStyleDeclaration;
41class Frame;
42class GraphicsContext;
43class HTMLFormElement;
44class RenderObject;
45class RenderView;
46class Settings;
47class VisiblePosition;
48
49enum DirectionalityPolicy { MakeNonDirectionalSelection, MakeDirectionalSelection };
50
51class SelectionController {
52    WTF_MAKE_NONCOPYABLE(SelectionController); WTF_MAKE_FAST_ALLOCATED;
53public:
54    enum EAlteration { AlterationMove, AlterationExtend };
55    enum CursorAlignOnScroll { AlignCursorOnScrollIfNeeded,
56                               AlignCursorOnScrollAlways };
57    enum SetSelectionOption {
58        CloseTyping = 1 << 0,
59        ClearTypingStyle = 1 << 1,
60        UserTriggered = 1 << 2,
61        SpellCorrectionTriggered = 1 << 3,
62    };
63    typedef unsigned SetSelectionOptions;
64
65    SelectionController(Frame* = 0, bool isDragCaretController = false);
66
67    Element* rootEditableElement() const { return m_selection.rootEditableElement(); }
68    bool isContentEditable() const { return m_selection.isContentEditable(); }
69    bool isContentRichlyEditable() const { return m_selection.isContentRichlyEditable(); }
70    Node* shadowTreeRootNode() const { return m_selection.shadowTreeRootNode(); }
71
72    void moveTo(const Range*, EAffinity, bool userTriggered = false);
73    void moveTo(const VisiblePosition&, bool userTriggered = false, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded);
74    void moveTo(const VisiblePosition&, const VisiblePosition&, bool userTriggered = false);
75    void moveTo(const Position&, EAffinity, bool userTriggered = false);
76    void moveTo(const Position&, const Position&, EAffinity, bool userTriggered = false);
77
78    const VisibleSelection& selection() const { return m_selection; }
79    void setSelection(const VisibleSelection&, SetSelectionOptions = CloseTyping | ClearTypingStyle, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity, DirectionalityPolicy = MakeDirectionalSelection);
80    void setSelection(const VisibleSelection& selection, TextGranularity granularity, DirectionalityPolicy directionality = MakeDirectionalSelection) { setSelection(selection, CloseTyping | ClearTypingStyle, AlignCursorOnScrollIfNeeded, granularity, directionality); }
81    bool setSelectedRange(Range*, EAffinity, bool closeTyping);
82    void selectAll();
83    void clear();
84
85    // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
86    void selectFrameElementInParentIfFullySelected();
87
88    bool contains(const IntPoint&);
89
90    VisibleSelection::SelectionType selectionType() const { return m_selection.selectionType(); }
91
92    EAffinity affinity() const { return m_selection.affinity(); }
93
94    bool modify(EAlteration, SelectionDirection, TextGranularity, bool userTriggered = false);
95    bool modify(EAlteration, int verticalDistance, bool userTriggered = false, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded);
96    TextGranularity granularity() const { return m_granularity; }
97
98    void setStart(const VisiblePosition &, bool userTriggered = false);
99    void setEnd(const VisiblePosition &, bool userTriggered = false);
100
101    void setBase(const VisiblePosition&, bool userTriggered = false);
102    void setBase(const Position&, EAffinity, bool userTriggered = false);
103    void setExtent(const VisiblePosition&, bool userTriggered = false);
104    void setExtent(const Position&, EAffinity, bool userTriggered = false);
105
106    Position base() const { return m_selection.base(); }
107    Position extent() const { return m_selection.extent(); }
108    Position start() const { return m_selection.start(); }
109    Position end() const { return m_selection.end(); }
110
111    // Return the renderer that is responsible for painting the caret (in the selection start node)
112    RenderObject* caretRenderer() const;
113
114    // Caret rect local to the caret's renderer
115    IntRect localCaretRect();
116    IntRect localCaretRectForPainting() const { return m_caretRect; }
117
118    // Bounds of (possibly transformed) caret in absolute coords
119    IntRect absoluteCaretBounds();
120    void setCaretRectNeedsUpdate(bool flag = true);
121
122    void setIsDirectional(bool);
123    void willBeModified(EAlteration, SelectionDirection);
124
125    bool isNone() const { return m_selection.isNone(); }
126    bool isCaret() const { return m_selection.isCaret(); }
127    bool isRange() const { return m_selection.isRange(); }
128    bool isCaretOrRange() const { return m_selection.isCaretOrRange(); }
129    bool isInPasswordField() const;
130    bool isAll(EditingBoundaryCrossingRule rule = CannotCrossEditingBoundary) const { return m_selection.isAll(rule); }
131
132    PassRefPtr<Range> toNormalizedRange() const { return m_selection.toNormalizedRange(); }
133
134    void debugRenderer(RenderObject*, bool selected) const;
135
136    void nodeWillBeRemoved(Node*);
137    void textWillBeReplaced(CharacterData*, unsigned offset, unsigned oldLength, unsigned newLength);
138
139    void setCaretVisible(bool = true);
140    void clearCaretRectIfNeeded();
141    bool recomputeCaretRect(); // returns true if caret rect moved
142    void invalidateCaretRect();
143    void paintCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect);
144
145    // Used to suspend caret blinking while the mouse is down.
146    void setCaretBlinkingSuspended(bool suspended) { m_isCaretBlinkingSuspended = suspended; }
147    bool isCaretBlinkingSuspended() const { return m_isCaretBlinkingSuspended; }
148
149    // Focus
150    void setFocused(bool);
151    bool isFocused() const { return m_focused; }
152    bool isFocusedAndActive() const;
153    void pageActivationChanged();
154
155    // Painting.
156    void updateAppearance();
157
158    void updateSecureKeyboardEntryIfActive();
159
160#ifndef NDEBUG
161    void formatForDebugger(char* buffer, unsigned length) const;
162    void showTreeForThis() const;
163#endif
164
165    bool shouldChangeSelection(const VisibleSelection&) const;
166    bool shouldDeleteSelection(const VisibleSelection&) const;
167    void setFocusedNodeIfNeeded();
168    void notifyRendererOfSelectionChange(bool userTriggered);
169
170    void paintDragCaret(GraphicsContext*, int tx, int ty, const IntRect& clipRect) const;
171
172    EditingStyle* typingStyle() const;
173    PassRefPtr<CSSMutableStyleDeclaration> copyTypingStyle() const;
174    void setTypingStyle(PassRefPtr<EditingStyle>);
175    void clearTypingStyle();
176
177    FloatRect bounds(bool clipToVisibleContent = true) const;
178
179    void getClippedVisibleTextRectangles(Vector<FloatRect>&) const;
180
181    HTMLFormElement* currentForm() const;
182
183    void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false);
184    void setSelectionFromNone();
185
186private:
187    enum EPositionType { START, END, BASE, EXTENT };
188
189    void respondToNodeModification(Node*, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved);
190    TextDirection directionOfEnclosingBlock();
191
192    VisiblePosition positionForPlatform(bool isGetStart) const;
193    VisiblePosition startForPlatform() const;
194    VisiblePosition endForPlatform() const;
195
196    VisiblePosition modifyExtendingRight(TextGranularity);
197    VisiblePosition modifyExtendingForward(TextGranularity);
198    VisiblePosition modifyMovingRight(TextGranularity);
199    VisiblePosition modifyMovingForward(TextGranularity);
200    VisiblePosition modifyExtendingLeft(TextGranularity);
201    VisiblePosition modifyExtendingBackward(TextGranularity);
202    VisiblePosition modifyMovingLeft(TextGranularity);
203    VisiblePosition modifyMovingBackward(TextGranularity);
204
205    void updateCaretRect();
206    IntRect caretRepaintRect() const;
207    bool shouldRepaintCaret(const RenderView* view) const;
208
209    int xPosForVerticalArrowNavigation(EPositionType);
210
211    void notifyAccessibilityForSelectionChange();
212
213    void focusedOrActiveStateChanged();
214    bool caretRendersInsideNode(Node*) const;
215
216    IntRect absoluteBoundsForLocalRect(const IntRect&) const;
217
218    void caretBlinkTimerFired(Timer<SelectionController>*);
219
220    void setUseSecureKeyboardEntry(bool);
221
222    Frame* m_frame;
223
224    int m_xPosForVerticalArrowNavigation;
225
226    VisibleSelection m_selection;
227    TextGranularity m_granularity;
228
229    RefPtr<EditingStyle> m_typingStyle;
230
231    Timer<SelectionController> m_caretBlinkTimer;
232
233    IntRect m_caretRect; // caret rect in coords local to the renderer responsible for painting the caret
234    IntRect m_absCaretBounds; // absolute bounding rect for the caret
235    IntRect m_absoluteCaretRepaintBounds;
236
237    bool m_caretRectNeedsUpdate; // true if m_caretRect and m_absCaretBounds need to be calculated
238    bool m_absCaretBoundsDirty;
239    bool m_isDirectional;
240    bool m_isDragCaretController;
241    bool m_isCaretBlinkingSuspended;
242    bool m_focused;
243    bool m_caretVisible;
244    bool m_caretPaint;
245};
246
247inline EditingStyle* SelectionController::typingStyle() const
248{
249    return m_typingStyle.get();
250}
251
252inline void SelectionController::clearTypingStyle()
253{
254    m_typingStyle.clear();
255}
256
257inline void SelectionController::setTypingStyle(PassRefPtr<EditingStyle> style)
258{
259    m_typingStyle = style;
260}
261
262#if !(PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(CHROMIUM))
263inline void SelectionController::notifyAccessibilityForSelectionChange()
264{
265}
266#endif
267
268} // namespace WebCore
269
270#ifndef NDEBUG
271// Outside the WebCore namespace for ease of invocation from gdb.
272void showTree(const WebCore::SelectionController&);
273void showTree(const WebCore::SelectionController*);
274#endif
275
276#endif // SelectionController_h
277
278