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 WebCore { 41 42 class CharacterData; 43 class LocalFrame; 44 class GraphicsContext; 45 class HTMLFormElement; 46 class MutableStylePropertySet; 47 class RenderObject; 48 class RenderView; 49 class Settings; 50 class Text; 51 class VisiblePosition; 52 53 enum EUserTriggered { NotUserTriggered = 0, UserTriggered = 1 }; 54 55 enum RevealExtentOption { 56 RevealExtent, 57 DoNotRevealExtent 58 }; 59 60 class FrameSelection FINAL : public NoBaseWillBeGarbageCollectedFinalized<FrameSelection>, public VisibleSelection::ChangeObserver, private CaretBase { 61 WTF_MAKE_NONCOPYABLE(FrameSelection); 62 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED; 63 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(FrameSelection); 64 public: 65 static PassOwnPtrWillBeRawPtr<FrameSelection> create(LocalFrame* frame = 0) 66 { 67 return adoptPtrWillBeNoop(new FrameSelection(frame)); 68 } 69 virtual ~FrameSelection(); 70 71 enum EAlteration { AlterationMove, AlterationExtend }; 72 enum CursorAlignOnScroll { AlignCursorOnScrollIfNeeded, 73 AlignCursorOnScrollAlways }; 74 enum SetSelectionOption { 75 // 1 << 0 is reserved for EUserTriggered 76 CloseTyping = 1 << 1, 77 ClearTypingStyle = 1 << 2, 78 SpellCorrectionTriggered = 1 << 3, 79 DoNotSetFocus = 1 << 4, 80 DoNotUpdateAppearance = 1 << 5, 81 }; 82 typedef unsigned SetSelectionOptions; // Union of values in SetSelectionOption and EUserTriggered 83 static inline EUserTriggered selectionOptionsToUserTriggered(SetSelectionOptions options) 84 { 85 return static_cast<EUserTriggered>(options & UserTriggered); 86 } 87 88 enum DirectoinalOption { 89 NonDirectional, 90 Directional 91 }; 92 93 Element* rootEditableElement() const { return m_selection.rootEditableElement(); } 94 Element* rootEditableElementOrDocumentElement() const; 95 Node* rootEditableElementOrTreeScopeRootNode() const; 96 97 bool rendererIsEditable() const { return m_selection.rendererIsEditable(); } 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 RenderObject* caretRenderer() const; 141 142 // Caret rect local to the caret's renderer 143 LayoutRect localCaretRect(); 144 145 // Bounds of (possibly transformed) caret in absolute coords 146 IntRect absoluteCaretBounds(); 147 void setCaretRectNeedsUpdate() { CaretBase::setCaretRectNeedsUpdate(); } 148 149 void didChangeFocus(); 150 void willBeModified(EAlteration, SelectionDirection); 151 152 bool isNone() const { return m_selection.isNone(); } 153 bool isCaret() const { return m_selection.isCaret(); } 154 bool isRange() const { return m_selection.isRange(); } 155 bool isCaretOrRange() const { return m_selection.isCaretOrRange(); } 156 bool isInPasswordField() const; 157 bool isDirectional() const { return m_selection.isDirectional(); } 158 159 // If this FrameSelection has a logical range which is still valid, this function return its clone. Otherwise, 160 // the return value from underlying VisibleSelection's firstRange() is returned. 161 PassRefPtrWillBeRawPtr<Range> firstRange() const; 162 163 PassRefPtrWillBeRawPtr<Range> toNormalizedRange() const { return m_selection.toNormalizedRange(); } 164 165 void nodeWillBeRemoved(Node&); 166 void didUpdateCharacterData(CharacterData*, unsigned offset, unsigned oldLength, unsigned newLength); 167 void didMergeTextNodes(const Text& oldNode, unsigned offset); 168 void didSplitTextNode(const Text& oldNode); 169 170 void setCaretVisible(bool caretIsVisible) { setCaretVisibility(caretIsVisible ? Visible : Hidden); } 171 bool recomputeCaretRect(); 172 void invalidateCaretRect(); 173 void paintCaret(GraphicsContext*, const LayoutPoint&, const LayoutRect& clipRect); 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 // Painting. 186 void updateAppearance(); 187 188 void updateSecureKeyboardEntryIfActive(); 189 190 #ifndef NDEBUG 191 void formatForDebugger(char* buffer, unsigned length) const; 192 void showTreeForThis() const; 193 #endif 194 195 enum EndPointsAdjustmentMode { AdjustEndpointsAtBidiBoundary, DoNotAdjsutEndpoints }; 196 void setNonDirectionalSelectionIfNeeded(const VisibleSelection&, TextGranularity, EndPointsAdjustmentMode = DoNotAdjsutEndpoints); 197 void setFocusedNodeIfNeeded(); 198 void notifyRendererOfSelectionChange(EUserTriggered); 199 200 EditingStyle* typingStyle() const; 201 void setTypingStyle(PassRefPtrWillBeRawPtr<EditingStyle>); 202 void clearTypingStyle(); 203 204 String selectedText() const; 205 String selectedTextForClipboard() const; 206 207 FloatRect bounds(bool clipToVisibleContent = true) const; 208 209 HTMLFormElement* currentForm() const; 210 211 void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, RevealExtentOption = DoNotRevealExtent); 212 void setSelectionFromNone(); 213 214 void setShouldShowBlockCursor(bool); 215 216 // VisibleSelection::ChangeObserver interface. 217 virtual void didChangeVisibleSelection() OVERRIDE; 218 219 virtual void trace(Visitor*) OVERRIDE; 220 221 private: 222 explicit FrameSelection(LocalFrame*); 223 224 enum EPositionType { START, END, BASE, EXTENT }; 225 226 void respondToNodeModification(Node&, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved); 227 TextDirection directionOfEnclosingBlock(); 228 TextDirection directionOfSelection(); 229 230 VisiblePosition positionForPlatform(bool isGetStart) const; 231 VisiblePosition startForPlatform() const; 232 VisiblePosition endForPlatform() const; 233 VisiblePosition nextWordPositionForPlatform(const VisiblePosition&); 234 235 VisiblePosition modifyExtendingRight(TextGranularity); 236 VisiblePosition modifyExtendingForward(TextGranularity); 237 VisiblePosition modifyMovingRight(TextGranularity); 238 VisiblePosition modifyMovingForward(TextGranularity); 239 VisiblePosition modifyExtendingLeft(TextGranularity); 240 VisiblePosition modifyExtendingBackward(TextGranularity); 241 VisiblePosition modifyMovingLeft(TextGranularity); 242 VisiblePosition modifyMovingBackward(TextGranularity); 243 244 LayoutUnit lineDirectionPointForBlockDirectionNavigation(EPositionType); 245 246 void notifyAccessibilityForSelectionChange(); 247 248 void focusedOrActiveStateChanged(); 249 250 void caretBlinkTimerFired(Timer<FrameSelection>*); 251 252 void setUseSecureKeyboardEntry(bool); 253 254 void setCaretVisibility(CaretVisibility); 255 bool shouldBlinkCaret() const; 256 257 bool dispatchSelectStart(); 258 259 void updateSelectionIfNeeded(const Position& base, const Position& extent, const Position& start, const Position& end); 260 261 void startObservingVisibleSelectionChange(); 262 void stopObservingVisibleSelectionChangeIfNecessary(); 263 264 VisibleSelection validateSelection(const VisibleSelection&); 265 266 LocalFrame* m_frame; 267 268 LayoutUnit m_xPosForVerticalArrowNavigation; 269 270 VisibleSelection m_selection; 271 bool m_observingVisibleSelection; 272 VisiblePosition m_originalBase; // Used to store base before the adjustment at bidi boundary 273 TextGranularity m_granularity; 274 275 // The range specified by the user, which may not be visually canonicalized (hence "logical"). 276 // This will be invalidated if the underlying VisibleSelection changes. If that happens, this variable will 277 // become null, in which case logical positions == visible positions. 278 RefPtrWillBeMember<Range> m_logicalRange; 279 280 RefPtrWillBeMember<Node> m_previousCaretNode; // The last node which painted the caret. Retained for clearing the old caret when it moves. 281 282 RefPtrWillBeMember<EditingStyle> m_typingStyle; 283 284 Timer<FrameSelection> m_caretBlinkTimer; 285 // The painted bounds of the caret in absolute coordinates 286 IntRect m_absCaretBounds; 287 bool m_absCaretBoundsDirty : 1; 288 bool m_caretPaint : 1; 289 bool m_isCaretBlinkingSuspended : 1; 290 bool m_focused : 1; 291 bool m_shouldShowBlockCursor : 1; 292 }; 293 294 inline EditingStyle* FrameSelection::typingStyle() const 295 { 296 return m_typingStyle.get(); 297 } 298 299 inline void FrameSelection::clearTypingStyle() 300 { 301 m_typingStyle.clear(); 302 } 303 304 inline void FrameSelection::setTypingStyle(PassRefPtrWillBeRawPtr<EditingStyle> style) 305 { 306 m_typingStyle = style; 307 } 308 } // namespace WebCore 309 310 #ifndef NDEBUG 311 // Outside the WebCore namespace for ease of invocation from gdb. 312 void showTree(const WebCore::FrameSelection&); 313 void showTree(const WebCore::FrameSelection*); 314 #endif 315 316 #endif // FrameSelection_h 317