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 "core/dom/Range.h" 30 #include "core/editing/Caret.h" 31 #include "core/editing/EditingStyle.h" 32 #include "core/editing/VisibleSelection.h" 33 #include "core/rendering/ScrollAlignment.h" 34 #include "platform/Timer.h" 35 #include "platform/geometry/IntRect.h" 36 #include "platform/geometry/LayoutRect.h" 37 #include "platform/heap/Handle.h" 38 #include "wtf/Noncopyable.h" 39 40 namespace blink { 41 42 class CharacterData; 43 class LocalFrame; 44 class GraphicsContext; 45 class HTMLFormElement; 46 class Text; 47 class VisiblePosition; 48 49 enum EUserTriggered { NotUserTriggered = 0, UserTriggered = 1 }; 50 51 enum RevealExtentOption { 52 RevealExtent, 53 DoNotRevealExtent 54 }; 55 56 class FrameSelection FINAL : public NoBaseWillBeGarbageCollectedFinalized<FrameSelection>, public VisibleSelection::ChangeObserver, private CaretBase { 57 WTF_MAKE_NONCOPYABLE(FrameSelection); 58 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED; 59 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(FrameSelection); 60 public: 61 static PassOwnPtrWillBeRawPtr<FrameSelection> create(LocalFrame* frame = 0) 62 { 63 return adoptPtrWillBeNoop(new FrameSelection(frame)); 64 } 65 virtual ~FrameSelection(); 66 67 enum EAlteration { AlterationMove, AlterationExtend }; 68 enum CursorAlignOnScroll { AlignCursorOnScrollIfNeeded, 69 AlignCursorOnScrollAlways }; 70 enum SetSelectionOption { 71 // 1 << 0 is reserved for EUserTriggered 72 CloseTyping = 1 << 1, 73 ClearTypingStyle = 1 << 2, 74 SpellCorrectionTriggered = 1 << 3, 75 DoNotSetFocus = 1 << 4, 76 DoNotUpdateAppearance = 1 << 5, 77 }; 78 typedef unsigned SetSelectionOptions; // Union of values in SetSelectionOption and EUserTriggered 79 static inline EUserTriggered selectionOptionsToUserTriggered(SetSelectionOptions options) 80 { 81 return static_cast<EUserTriggered>(options & UserTriggered); 82 } 83 84 enum DirectoinalOption { 85 NonDirectional, 86 Directional 87 }; 88 enum ResetCaretBlinkOption { 89 None, 90 ResetCaretBlink 91 }; 92 93 Element* rootEditableElement() const { return m_selection.rootEditableElement(); } 94 Element* rootEditableElementOrDocumentElement() const; 95 ContainerNode* rootEditableElementOrTreeScopeRootNode() const; 96 97 bool hasEditableStyle() const { return m_selection.hasEditableStyle(); } 98 bool isContentEditable() const { return m_selection.isContentEditable(); } 99 bool isContentRichlyEditable() const { return m_selection.isContentRichlyEditable(); } 100 101 void moveTo(const VisiblePosition&, EUserTriggered = NotUserTriggered, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded); 102 void moveTo(const VisiblePosition&, const VisiblePosition&, EUserTriggered = NotUserTriggered); 103 void moveTo(const Position&, EAffinity, EUserTriggered = NotUserTriggered); 104 105 const VisibleSelection& selection() const { return m_selection; } 106 void setSelection(const VisibleSelection&, SetSelectionOptions = CloseTyping | ClearTypingStyle, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity); 107 void setSelection(const VisibleSelection& selection, TextGranularity granularity) { setSelection(selection, CloseTyping | ClearTypingStyle, AlignCursorOnScrollIfNeeded, granularity); } 108 bool setSelectedRange(Range*, EAffinity, DirectoinalOption directional = NonDirectional, SetSelectionOptions = CloseTyping | ClearTypingStyle); 109 void selectAll(); 110 void clear(); 111 void prepareForDestruction(); 112 113 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected. 114 void selectFrameElementInParentIfFullySelected(); 115 116 bool contains(const LayoutPoint&); 117 118 SelectionType selectionType() const { return m_selection.selectionType(); } 119 120 EAffinity affinity() const { return m_selection.affinity(); } 121 122 bool modify(EAlteration, SelectionDirection, TextGranularity, EUserTriggered = NotUserTriggered); 123 enum VerticalDirection { DirectionUp, DirectionDown }; 124 bool modify(EAlteration, unsigned verticalDistance, VerticalDirection, EUserTriggered = NotUserTriggered, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded); 125 126 TextGranularity granularity() const { return m_granularity; } 127 128 void setStart(const VisiblePosition &, EUserTriggered = NotUserTriggered); 129 void setEnd(const VisiblePosition &, EUserTriggered = NotUserTriggered); 130 131 void setBase(const VisiblePosition&, EUserTriggered = NotUserTriggered); 132 void setExtent(const VisiblePosition&, EUserTriggered = NotUserTriggered); 133 134 Position base() const { return m_selection.base(); } 135 Position extent() const { return m_selection.extent(); } 136 Position start() const { return m_selection.start(); } 137 Position end() const { return m_selection.end(); } 138 139 // Return the renderer that is responsible for painting the caret (in the selection start node) 140 RenderBlock* caretRenderer() const; 141 142 // Bounds of (possibly transformed) caret in absolute coords 143 IntRect absoluteCaretBounds(); 144 145 void didChangeFocus(); 146 void willBeModified(EAlteration, SelectionDirection); 147 148 bool isNone() const { return m_selection.isNone(); } 149 bool isCaret() const { return m_selection.isCaret(); } 150 bool isRange() const { return m_selection.isRange(); } 151 bool isCaretOrRange() const { return m_selection.isCaretOrRange(); } 152 bool isInPasswordField() const; 153 bool isDirectional() const { return m_selection.isDirectional(); } 154 155 // If this FrameSelection has a logical range which is still valid, this function return its clone. Otherwise, 156 // the return value from underlying VisibleSelection's firstRange() is returned. 157 PassRefPtrWillBeRawPtr<Range> firstRange() const; 158 159 PassRefPtrWillBeRawPtr<Range> toNormalizedRange() const { return m_selection.toNormalizedRange(); } 160 161 void nodeWillBeRemoved(Node&); 162 void didUpdateCharacterData(CharacterData*, unsigned offset, unsigned oldLength, unsigned newLength); 163 void didMergeTextNodes(const Text& oldNode, unsigned offset); 164 void didSplitTextNode(const Text& oldNode); 165 166 void updateAppearance(ResetCaretBlinkOption = None); 167 void setCaretVisible(bool caretIsVisible) { setCaretVisibility(caretIsVisible ? Visible : Hidden); } 168 bool isCaretBoundsDirty() const { return m_caretRectDirty; } 169 void setCaretRectNeedsUpdate(); 170 void scheduleVisualUpdate() const; 171 void invalidateCaretRect(); 172 void paintCaret(GraphicsContext*, const LayoutPoint&, const LayoutRect& clipRect); 173 bool ShouldPaintCaretForTesting() const { return m_shouldPaintCaret; } 174 175 // Used to suspend caret blinking while the mouse is down. 176 void setCaretBlinkingSuspended(bool suspended) { m_isCaretBlinkingSuspended = suspended; } 177 bool isCaretBlinkingSuspended() const { return m_isCaretBlinkingSuspended; } 178 179 // Focus 180 void setFocused(bool); 181 bool isFocused() const { return m_focused; } 182 bool isFocusedAndActive() const; 183 void pageActivationChanged(); 184 185 void updateSecureKeyboardEntryIfActive(); 186 187 #ifndef NDEBUG 188 void formatForDebugger(char* buffer, unsigned length) const; 189 void showTreeForThis() const; 190 #endif 191 192 enum EndPointsAdjustmentMode { AdjustEndpointsAtBidiBoundary, DoNotAdjsutEndpoints }; 193 void setNonDirectionalSelectionIfNeeded(const VisibleSelection&, TextGranularity, EndPointsAdjustmentMode = DoNotAdjsutEndpoints); 194 void setFocusedNodeIfNeeded(); 195 void notifyRendererOfSelectionChange(EUserTriggered); 196 197 EditingStyle* typingStyle() const; 198 void setTypingStyle(PassRefPtrWillBeRawPtr<EditingStyle>); 199 void clearTypingStyle(); 200 201 String selectedText() const; 202 String selectedTextForClipboard() const; 203 204 FloatRect bounds() const; 205 206 HTMLFormElement* currentForm() const; 207 208 void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, RevealExtentOption = DoNotRevealExtent); 209 void setSelectionFromNone(); 210 211 void setShouldShowBlockCursor(bool); 212 213 // VisibleSelection::ChangeObserver interface. 214 virtual void didChangeVisibleSelection() OVERRIDE; 215 216 virtual void trace(Visitor*) OVERRIDE; 217 218 private: 219 explicit FrameSelection(LocalFrame*); 220 221 enum EPositionType { START, END, BASE, EXTENT }; 222 223 void respondToNodeModification(Node&, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved); 224 TextDirection directionOfEnclosingBlock(); 225 TextDirection directionOfSelection(); 226 227 VisiblePosition positionForPlatform(bool isGetStart) const; 228 VisiblePosition startForPlatform() const; 229 VisiblePosition endForPlatform() const; 230 VisiblePosition nextWordPositionForPlatform(const VisiblePosition&); 231 232 VisiblePosition modifyExtendingRight(TextGranularity); 233 VisiblePosition modifyExtendingForward(TextGranularity); 234 VisiblePosition modifyMovingRight(TextGranularity); 235 VisiblePosition modifyMovingForward(TextGranularity); 236 VisiblePosition modifyExtendingLeft(TextGranularity); 237 VisiblePosition modifyExtendingBackward(TextGranularity); 238 VisiblePosition modifyMovingLeft(TextGranularity); 239 VisiblePosition modifyMovingBackward(TextGranularity); 240 241 LayoutUnit lineDirectionPointForBlockDirectionNavigation(EPositionType); 242 243 void notifyAccessibilityForSelectionChange(); 244 void notifyCompositorForSelectionChange(); 245 void notifyEventHandlerForSelectionChange(); 246 247 void focusedOrActiveStateChanged(); 248 249 void caretBlinkTimerFired(Timer<FrameSelection>*); 250 251 void setUseSecureKeyboardEntry(bool); 252 253 void setCaretVisibility(CaretVisibility); 254 bool shouldBlinkCaret() const; 255 256 bool dispatchSelectStart(); 257 258 void updateSelectionIfNeeded(const Position& base, const Position& extent, const Position& start, const Position& end); 259 260 void startObservingVisibleSelectionChange(); 261 void stopObservingVisibleSelectionChangeIfNecessary(); 262 263 VisibleSelection validateSelection(const VisibleSelection&); 264 265 RawPtrWillBeMember<LocalFrame> m_frame; 266 267 LayoutUnit m_xPosForVerticalArrowNavigation; 268 269 VisibleSelection m_selection; 270 bool m_observingVisibleSelection; 271 VisiblePosition m_originalBase; // Used to store base before the adjustment at bidi boundary 272 TextGranularity m_granularity; 273 274 // The range specified by the user, which may not be visually canonicalized (hence "logical"). 275 // This will be invalidated if the underlying VisibleSelection changes. If that happens, this variable will 276 // become null, in which case logical positions == visible positions. 277 RefPtrWillBeMember<Range> m_logicalRange; 278 279 RefPtrWillBeMember<Node> m_previousCaretNode; // The last node which painted the caret. Retained for clearing the old caret when it moves. 280 LayoutRect m_previousCaretRect; 281 282 RefPtrWillBeMember<EditingStyle> m_typingStyle; 283 284 Timer<FrameSelection> m_caretBlinkTimer; 285 286 bool m_caretRectDirty : 1; 287 bool m_shouldPaintCaret : 1; 288 bool m_isCaretBlinkingSuspended : 1; 289 bool m_focused : 1; 290 bool m_shouldShowBlockCursor : 1; 291 }; 292 293 inline EditingStyle* FrameSelection::typingStyle() const 294 { 295 return m_typingStyle.get(); 296 } 297 298 inline void FrameSelection::clearTypingStyle() 299 { 300 m_typingStyle.clear(); 301 } 302 303 inline void FrameSelection::setTypingStyle(PassRefPtrWillBeRawPtr<EditingStyle> style) 304 { 305 m_typingStyle = style; 306 } 307 } // namespace blink 308 309 #ifndef NDEBUG 310 // Outside the WebCore namespace for ease of invocation from gdb. 311 void showTree(const blink::FrameSelection&); 312 void showTree(const blink::FrameSelection*); 313 #endif 314 315 #endif // FrameSelection_h 316