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 42namespace WebCore { 43 44class CharacterData; 45class Frame; 46class GraphicsContext; 47class HTMLFormElement; 48class MutableStyleProperties; 49class RenderObject; 50class RenderView; 51class Settings; 52class VisiblePosition; 53 54enum EUserTriggered { NotUserTriggered = 0, UserTriggered = 1 }; 55 56enum RevealExtentOption { 57 RevealExtent, 58 DoNotRevealExtent 59}; 60 61class CaretBase { 62 WTF_MAKE_NONCOPYABLE(CaretBase); 63 WTF_MAKE_FAST_ALLOCATED; 64protected: 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 83private: 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 89class DragCaretController : private CaretBase { 90 WTF_MAKE_NONCOPYABLE(DragCaretController); 91 WTF_MAKE_FAST_ALLOCATED; 92public: 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 void clear() { setCaretPosition(VisiblePosition()); } 105 106 void nodeWillBeRemoved(Node*); 107 108private: 109 VisiblePosition m_position; 110}; 111 112class FrameSelection : private CaretBase { 113 WTF_MAKE_NONCOPYABLE(FrameSelection); 114 WTF_MAKE_FAST_ALLOCATED; 115public: 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 explicit FrameSelection(Frame* = 0); 135 136 Element* rootEditableElementOrDocumentElement() const; 137 138 void moveTo(const Range*); 139 void moveTo(const VisiblePosition&, EUserTriggered = NotUserTriggered, CursorAlignOnScroll = AlignCursorOnScrollIfNeeded); 140 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 void setSelection(const VisibleSelection&, SetSelectionOptions = defaultSetSelectionOptions(), CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity); 147 bool setSelectedRange(Range*, EAffinity, bool closeTyping); 148 void selectAll(); 149 void clear(); 150 void prepareForDestruction(); 151 152 void didLayout(); 153 void setNeedsSelectionUpdate(); 154 155 bool contains(const LayoutPoint&); 156 157 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 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 void setFocused(bool); 202 bool isFocused() const { return m_focused; } 203 bool isFocusedAndActive() const; 204 void pageActivationChanged(); 205 206 // Painting. 207 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) 215public: 216 void expandSelectionToElementContainingCaretSelection(); 217 PassRefPtr<Range> elementRangeContainingCaretSelection() const; 218 void expandSelectionToWordContainingCaretSelection(); 219 PassRefPtr<Range> wordRangeContainingCaretSelection(); 220 void expandSelectionToStartOfWordContainingCaretSelection(); 221 UChar characterInRelationToCaretSelection(int amount) const; 222 UChar characterBeforeCaretSelection() const; 223 UChar characterAfterCaretSelection() const; 224 int wordOffsetInRange(const Range*) const; 225 bool spaceFollowsWordInRange(const Range*) const; 226 bool selectionAtDocumentStart() const; 227 bool selectionAtSentenceStart() const; 228 bool selectionAtWordStart() const; 229 PassRefPtr<Range> rangeByMovingCurrentSelection(int amount) const; 230 PassRefPtr<Range> rangeByExtendingCurrentSelection(int amount) const; 231 void selectRangeOnElement(unsigned location, unsigned length, Node*); 232 void clearCurrentSelection(); 233 void setCaretBlinks(bool caretBlinks = true); 234 void setCaretColor(const Color&); 235 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 } 243private: 244 bool actualSelectionAtSentenceStart(const VisibleSelection&) const; 245 PassRefPtr<Range> rangeByAlteringCurrentSelection(EAlteration, int amount) const; 246public: 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 PassRefPtr<MutableStyleProperties> copyTypingStyle() const; 256 void setTypingStyle(PassRefPtr<EditingStyle>); 257 void clearTypingStyle(); 258 259 FloatRect selectionBounds(bool clipToVisibleContent = true) const; 260 261 void getClippedVisibleTextRectangles(Vector<FloatRect>&) const; 262 263 HTMLFormElement* currentForm() const; 264 265 void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, RevealExtentOption = DoNotRevealExtent); 266 void setSelectionFromNone(); 267 268 bool shouldShowBlockCursor() const { return m_shouldShowBlockCursor; } 269 void setShouldShowBlockCursor(bool); 270 271private: 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<FrameSelection>&); 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<FrameSelection> 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 352inline EditingStyle* FrameSelection::typingStyle() const 353{ 354 return m_typingStyle.get(); 355} 356 357inline void FrameSelection::clearTypingStyle() 358{ 359 m_typingStyle.clear(); 360} 361 362inline 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) 369inline 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. 379void showTree(const WebCore::FrameSelection&); 380void showTree(const WebCore::FrameSelection*); 381#endif 382 383#endif // FrameSelection_h 384