~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/editing/FrameSelection.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004, 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
#include "config.h"
 
27
#include "FrameSelection.h"
 
28
 
 
29
#include "CharacterData.h"
 
30
#include "DeleteSelectionCommand.h"
 
31
#include "Document.h"
 
32
#include "Editor.h"
 
33
#include "EditorClient.h"
 
34
#include "Element.h"
 
35
#include "EventHandler.h"
 
36
#include "ExceptionCode.h"
 
37
#include "FloatQuad.h"
 
38
#include "FocusController.h"
 
39
#include "Frame.h"
 
40
#include "FrameTree.h"
 
41
#include "FrameView.h"
 
42
#include "GraphicsContext.h"
 
43
#include "HTMLFormElement.h"
 
44
#include "HTMLFrameElementBase.h"
 
45
#include "HTMLInputElement.h"
 
46
#include "HTMLSelectElement.h"
 
47
#include "HTMLNames.h"
 
48
#include "HitTestRequest.h"
 
49
#include "HitTestResult.h"
 
50
#include "InlineTextBox.h"
 
51
#include "Page.h"
 
52
#include "Range.h"
 
53
#include "RenderText.h"
 
54
#include "RenderTextControl.h"
 
55
#include "RenderTheme.h"
 
56
#include "RenderView.h"
 
57
#include "RenderWidget.h"
 
58
#include "RenderedPosition.h"
 
59
#include "SecureTextInput.h"
 
60
#include "Settings.h"
 
61
#include "SpatialNavigation.h"
 
62
#include "TextIterator.h"
 
63
#include "TypingCommand.h"
 
64
#include "htmlediting.h"
 
65
#include "visible_units.h"
 
66
#include <limits.h>
 
67
#include <stdio.h>
 
68
#include <wtf/text/CString.h>
 
69
 
 
70
#define EDIT_DEBUG 0
 
71
 
 
72
namespace WebCore {
 
73
 
 
74
using namespace HTMLNames;
 
75
 
 
76
static inline LayoutUnit NoXPosForVerticalArrowNavigation()
 
77
{
 
78
    return LayoutUnit::min();
 
79
}
 
80
 
 
81
CaretBase::CaretBase(CaretVisibility visibility)
 
82
    : m_caretRectNeedsUpdate(true)
 
83
    , m_caretVisibility(visibility)
 
84
{
 
85
}
 
86
 
 
87
DragCaretController::DragCaretController()
 
88
    : CaretBase(Visible)
 
89
{
 
90
}
 
91
 
 
92
PassOwnPtr<DragCaretController> DragCaretController::create()
 
93
{
 
94
    return adoptPtr(new DragCaretController);
 
95
}
 
96
 
 
97
bool DragCaretController::isContentRichlyEditable() const
 
98
{
 
99
    return isRichlyEditablePosition(m_position.deepEquivalent());
 
100
}
 
101
 
 
102
static inline bool shouldAlwaysUseDirectionalSelection(Frame* frame)
 
103
{
 
104
    return !frame || frame->editor()->behavior().shouldConsiderSelectionAsDirectional();
 
105
}
 
106
 
 
107
FrameSelection::FrameSelection(Frame* frame)
 
108
    : m_frame(frame)
 
109
    , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation())
 
110
    , m_granularity(CharacterGranularity)
 
111
    , m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired)
 
112
    , m_absCaretBoundsDirty(true)
 
113
    , m_caretPaint(true)
 
114
    , m_isCaretBlinkingSuspended(false)
 
115
    , m_focused(frame && frame->page() && frame->page()->focusController()->focusedFrame() == frame)
 
116
{
 
117
    if (shouldAlwaysUseDirectionalSelection(m_frame))
 
118
        m_selection.setIsDirectional(true);
 
119
}
 
120
 
 
121
Element* FrameSelection::rootEditableElementOrDocumentElement() const
 
122
{
 
123
    Element* selectionRoot = m_selection.rootEditableElement();
 
124
    return selectionRoot ? selectionRoot : m_frame->document()->documentElement();
 
125
}
 
126
 
 
127
Element* FrameSelection::rootEditableElementRespectingShadowTree() const
 
128
{
 
129
    Element* selectionRoot = m_selection.rootEditableElement();
 
130
    if (selectionRoot && selectionRoot->isInShadowTree())
 
131
        selectionRoot = selectionRoot->shadowHost();
 
132
    return selectionRoot;
 
133
}
 
134
 
 
135
void FrameSelection::moveTo(const VisiblePosition &pos, EUserTriggered userTriggered, CursorAlignOnScroll align)
 
136
{
 
137
    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
 
138
    setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity(), m_selection.isDirectional()), options, align);
 
139
}
 
140
 
 
141
void FrameSelection::moveTo(const VisiblePosition &base, const VisiblePosition &extent, EUserTriggered userTriggered)
 
142
{
 
143
    const bool selectionHasDirection = true;
 
144
    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
 
145
    setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity(), selectionHasDirection), options);
 
146
}
 
147
 
 
148
void FrameSelection::moveTo(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
 
149
{
 
150
    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
 
151
    setSelection(VisibleSelection(pos, affinity, m_selection.isDirectional()), options);
 
152
}
 
153
 
 
154
void FrameSelection::moveTo(const Range *r, EAffinity affinity, EUserTriggered userTriggered)
 
155
{
 
156
    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
 
157
    VisibleSelection selection = r ? VisibleSelection(r->startPosition(), r->endPosition(), affinity) : VisibleSelection(Position(), Position(), affinity);
 
158
    setSelection(selection, options);
 
159
}
 
160
 
 
161
void FrameSelection::moveTo(const Position &base, const Position &extent, EAffinity affinity, EUserTriggered userTriggered)
 
162
{
 
163
    const bool selectionHasDirection = true;
 
164
    SetSelectionOptions options = CloseTyping | ClearTypingStyle | userTriggered;
 
165
    setSelection(VisibleSelection(base, extent, affinity, selectionHasDirection), options);
 
166
}
 
167
 
 
168
void DragCaretController::setCaretPosition(const VisiblePosition& position)
 
169
{
 
170
    if (Node* node = m_position.deepEquivalent().deprecatedNode())
 
171
        invalidateCaretRect(node);
 
172
    m_position = position;
 
173
    setCaretRectNeedsUpdate();
 
174
    Document* document = 0;
 
175
    if (Node* node = m_position.deepEquivalent().deprecatedNode()) {
 
176
        invalidateCaretRect(node);
 
177
        document = node->document();
 
178
    }
 
179
    if (m_position.isNull() || m_position.isOrphan())
 
180
        clearCaretRect();
 
181
    else
 
182
        updateCaretRect(document, m_position);
 
183
}
 
184
 
 
185
static void adjustEndpointsAtBidiBoundary(VisiblePosition& visibleBase, VisiblePosition& visibleExtent)
 
186
{
 
187
    RenderedPosition base(visibleBase);
 
188
    RenderedPosition extent(visibleExtent);
 
189
 
 
190
    if (base.isNull() || extent.isNull() || base.isEquivalent(extent))
 
191
        return;
 
192
 
 
193
    if (base.atLeftBoundaryOfBidiRun()) {
 
194
        if (!extent.atRightBoundaryOfBidiRun(base.bidiLevelOnRight())
 
195
            && base.isEquivalent(extent.leftBoundaryOfBidiRun(base.bidiLevelOnRight()))) {
 
196
            visibleBase = base.positionAtLeftBoundaryOfBiDiRun();
 
197
            return;
 
198
        }
 
199
        return;
 
200
    }
 
201
 
 
202
    if (base.atRightBoundaryOfBidiRun()) {
 
203
        if (!extent.atLeftBoundaryOfBidiRun(base.bidiLevelOnLeft())
 
204
            && base.isEquivalent(extent.rightBoundaryOfBidiRun(base.bidiLevelOnLeft()))) {
 
205
            visibleBase = base.positionAtRightBoundaryOfBiDiRun();
 
206
            return;
 
207
        }
 
208
        return;
 
209
    }
 
210
 
 
211
    if (extent.atLeftBoundaryOfBidiRun() && extent.isEquivalent(base.leftBoundaryOfBidiRun(extent.bidiLevelOnRight()))) {
 
212
        visibleExtent = extent.positionAtLeftBoundaryOfBiDiRun();
 
213
        return;
 
214
    }
 
215
 
 
216
    if (extent.atRightBoundaryOfBidiRun() && extent.isEquivalent(base.rightBoundaryOfBidiRun(extent.bidiLevelOnLeft()))) {
 
217
        visibleExtent = extent.positionAtRightBoundaryOfBiDiRun();
 
218
        return;
 
219
    }
 
220
}
 
221
 
 
222
void FrameSelection::setNonDirectionalSelectionIfNeeded(const VisibleSelection& passedNewSelection, TextGranularity granularity,
 
223
    EndPointsAdjustmentMode endpointsAdjustmentMode)
 
224
{
 
225
    VisibleSelection newSelection = passedNewSelection;
 
226
    bool isDirectional = shouldAlwaysUseDirectionalSelection(m_frame) || newSelection.isDirectional();
 
227
 
 
228
    VisiblePosition base = m_originalBase.isNotNull() ? m_originalBase : newSelection.visibleBase();
 
229
    VisiblePosition newBase = base;
 
230
    VisiblePosition newExtent = newSelection.visibleExtent();
 
231
    if (endpointsAdjustmentMode == AdjustEndpointsAtBidiBoundary)
 
232
        adjustEndpointsAtBidiBoundary(newBase, newExtent);
 
233
 
 
234
    if (newBase != base || newExtent != newSelection.visibleExtent()) {
 
235
        m_originalBase = base;
 
236
        newSelection.setBase(newBase);
 
237
        newSelection.setExtent(newExtent);
 
238
    } else if (m_originalBase.isNotNull()) {
 
239
        if (m_selection.base() == newSelection.base())
 
240
            newSelection.setBase(m_originalBase);
 
241
        m_originalBase.clear();
 
242
    }
 
243
 
 
244
    newSelection.setIsDirectional(isDirectional); // Adjusting base and extent will make newSelection always directional
 
245
    if (m_selection == newSelection || !shouldChangeSelection(newSelection))
 
246
        return;
 
247
 
 
248
    setSelection(newSelection, granularity);
 
249
}
 
250
 
 
251
void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity)
 
252
{
 
253
    bool closeTyping = options & CloseTyping;
 
254
    bool shouldClearTypingStyle = options & ClearTypingStyle;
 
255
    EUserTriggered userTriggered = selectionOptionsToUserTriggered(options);
 
256
 
 
257
    VisibleSelection s = newSelection;
 
258
    if (shouldAlwaysUseDirectionalSelection(m_frame))
 
259
        s.setIsDirectional(true);
 
260
 
 
261
    if (!m_frame) {
 
262
        m_selection = s;
 
263
        return;
 
264
    }
 
265
 
 
266
    // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at FrameSelection::setSelection
 
267
    // if document->frame() == m_frame we can get into an infinite loop
 
268
    if (s.base().anchorNode()) {
 
269
        Document* document = s.base().anchorNode()->document();
 
270
        if (document && document->frame() && document->frame() != m_frame && document != m_frame->document()) {
 
271
            document->frame()->selection()->setSelection(s, options, align, granularity);
 
272
            return;
 
273
        }
 
274
    }
 
275
 
 
276
    m_granularity = granularity;
 
277
 
 
278
    if (closeTyping)
 
279
        TypingCommand::closeTyping(m_frame);
 
280
 
 
281
    if (shouldClearTypingStyle)
 
282
        clearTypingStyle();
 
283
 
 
284
    if (m_selection == s) {
 
285
        // Even if selection was not changed, selection offsets may have been changed.
 
286
        notifyRendererOfSelectionChange(userTriggered);
 
287
        return;
 
288
    }
 
289
 
 
290
    VisibleSelection oldSelection = m_selection;
 
291
 
 
292
    m_selection = s;
 
293
    setCaretRectNeedsUpdate();
 
294
    
 
295
    if (!s.isNone() && !(options & DoNotSetFocus))
 
296
        setFocusedNodeIfNeeded();
 
297
 
 
298
    if (!(options & DoNotUpdateAppearance)) {
 
299
#if ENABLE(TEXT_CARET)
 
300
        m_frame->document()->updateLayoutIgnorePendingStylesheets();
 
301
#else
 
302
        m_frame->document()->updateStyleIfNeeded();
 
303
#endif
 
304
        updateAppearance();
 
305
    }
 
306
 
 
307
    // Always clear the x position used for vertical arrow navigation.
 
308
    // It will be restored by the vertical arrow navigation code if necessary.
 
309
    m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation();
 
310
    selectFrameElementInParentIfFullySelected();
 
311
    notifyRendererOfSelectionChange(userTriggered);
 
312
    m_frame->editor()->respondToChangedSelection(oldSelection, options);
 
313
    if (userTriggered == UserTriggered) {
 
314
        ScrollAlignment alignment;
 
315
 
 
316
        if (m_frame->editor()->behavior().shouldCenterAlignWhenSelectionIsRevealed())
 
317
            alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
 
318
        else
 
319
            alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
 
320
 
 
321
        revealSelection(alignment, RevealExtent);
 
322
    }
 
323
 
 
324
    notifyAccessibilityForSelectionChange();
 
325
    m_frame->document()->enqueueDocumentEvent(Event::create(eventNames().selectionchangeEvent, false, false));
 
326
}
 
327
 
 
328
static bool removingNodeRemovesPosition(Node* node, const Position& position)
 
329
{
 
330
    if (!position.anchorNode())
 
331
        return false;
 
332
 
 
333
    if (position.anchorNode() == node)
 
334
        return true;
 
335
 
 
336
    if (!node->isElementNode())
 
337
        return false;
 
338
 
 
339
    Element* element = static_cast<Element*>(node);
 
340
    return element->contains(position.anchorNode()) || element->contains(position.anchorNode()->shadowAncestorNode());
 
341
}
 
342
 
 
343
static void clearRenderViewSelection(const Position& position)
 
344
{
 
345
    RefPtr<Document> document = position.anchorNode()->document();
 
346
    document->updateStyleIfNeeded();
 
347
    if (RenderView* view = document->renderView())
 
348
        view->clearSelection();
 
349
}
 
350
 
 
351
void DragCaretController::nodeWillBeRemoved(Node* node)
 
352
{
 
353
    if (!hasCaret() || (node && !node->inDocument()))
 
354
        return;
 
355
 
 
356
    if (!removingNodeRemovesPosition(node, m_position.deepEquivalent()))
 
357
        return;
 
358
 
 
359
    clearRenderViewSelection(m_position.deepEquivalent());
 
360
    clear();
 
361
}
 
362
 
 
363
void FrameSelection::nodeWillBeRemoved(Node* node)
 
364
{
 
365
    // There can't be a selection inside a fragment, so if a fragment's node is being removed,
 
366
    // the selection in the document that created the fragment needs no adjustment.
 
367
    if (isNone() || (node && !node->inDocument()))
 
368
        return;
 
369
 
 
370
    respondToNodeModification(node, removingNodeRemovesPosition(node, m_selection.base()), removingNodeRemovesPosition(node, m_selection.extent()),
 
371
        removingNodeRemovesPosition(node, m_selection.start()), removingNodeRemovesPosition(node, m_selection.end()));
 
372
}
 
373
 
 
374
void FrameSelection::respondToNodeModification(Node* node, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved)
 
375
{
 
376
    bool clearRenderTreeSelection = false;
 
377
    bool clearDOMTreeSelection = false;
 
378
 
 
379
    if (startRemoved || endRemoved) {
 
380
        Position start = m_selection.start();
 
381
        Position end = m_selection.end();
 
382
        if (startRemoved)
 
383
            updatePositionForNodeRemoval(start, node);
 
384
        if (endRemoved)
 
385
            updatePositionForNodeRemoval(end, node);
 
386
 
 
387
        if (start.isNotNull() && end.isNotNull()) {
 
388
            if (m_selection.isBaseFirst())
 
389
                m_selection.setWithoutValidation(start, end);
 
390
            else
 
391
                m_selection.setWithoutValidation(end, start);
 
392
        } else
 
393
            clearDOMTreeSelection = true;
 
394
 
 
395
        clearRenderTreeSelection = true;
 
396
    } else if (baseRemoved || extentRemoved) {
 
397
        // The base and/or extent are about to be removed, but the start and end aren't.
 
398
        // Change the base and extent to the start and end, but don't re-validate the
 
399
        // selection, since doing so could move the start and end into the node
 
400
        // that is about to be removed.
 
401
        if (m_selection.isBaseFirst())
 
402
            m_selection.setWithoutValidation(m_selection.start(), m_selection.end());
 
403
        else
 
404
            m_selection.setWithoutValidation(m_selection.end(), m_selection.start());
 
405
    } else if (RefPtr<Range> range = m_selection.firstRange()) {
 
406
        ExceptionCode ec = 0;
 
407
        Range::CompareResults compareResult = range->compareNode(node, ec);
 
408
        if (!ec && (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE)) {
 
409
            // If we did nothing here, when this node's renderer was destroyed, the rect that it 
 
410
            // occupied would be invalidated, but, selection gaps that change as a result of 
 
411
            // the removal wouldn't be invalidated.
 
412
            // FIXME: Don't do so much unnecessary invalidation.
 
413
            clearRenderTreeSelection = true;
 
414
        }
 
415
    }
 
416
 
 
417
    if (clearRenderTreeSelection)
 
418
        clearRenderViewSelection(m_selection.start());
 
419
 
 
420
    if (clearDOMTreeSelection)
 
421
        setSelection(VisibleSelection(), DoNotSetFocus);
 
422
}
 
423
 
 
424
static void updatePositionAfterAdoptingTextReplacement(Position& position, CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
 
425
{
 
426
    if (!position.anchorNode() || position.anchorNode() != node || position.anchorType() != Position::PositionIsOffsetInAnchor)
 
427
        return;
 
428
 
 
429
    // See: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Mutation
 
430
    ASSERT(position.offsetInContainerNode() >= 0);
 
431
    unsigned positionOffset = static_cast<unsigned>(position.offsetInContainerNode());
 
432
    // Replacing text can be viewed as a deletion followed by insertion.
 
433
    if (positionOffset >= offset && positionOffset <= offset + oldLength)
 
434
        position.moveToOffset(offset);
 
435
 
 
436
    // Adjust the offset if the position is after the end of the deleted contents
 
437
    // (positionOffset > offset + oldLength) to avoid having a stale offset.
 
438
    if (positionOffset > offset + oldLength)
 
439
        position.moveToOffset(positionOffset - oldLength + newLength);
 
440
 
 
441
    ASSERT(static_cast<unsigned>(position.offsetInContainerNode()) <= node->length());
 
442
}
 
443
 
 
444
static inline bool nodeIsDetachedFromDocument(Node* node)
 
445
{
 
446
    ASSERT(node);
 
447
    Node* highest = highestAncestor(node);
 
448
    return highest->nodeType() == Node::DOCUMENT_FRAGMENT_NODE && !highest->isShadowRoot();
 
449
}
 
450
 
 
451
void FrameSelection::textWasReplaced(CharacterData* node, unsigned offset, unsigned oldLength, unsigned newLength)
 
452
{
 
453
    // The fragment check is a performance optimization. See http://trac.webkit.org/changeset/30062.
 
454
    if (isNone() || !node || nodeIsDetachedFromDocument(node))
 
455
        return;
 
456
 
 
457
    Position base = m_selection.base();
 
458
    Position extent = m_selection.extent();
 
459
    Position start = m_selection.start();
 
460
    Position end = m_selection.end();
 
461
    updatePositionAfterAdoptingTextReplacement(base, node, offset, oldLength, newLength);
 
462
    updatePositionAfterAdoptingTextReplacement(extent, node, offset, oldLength, newLength);
 
463
    updatePositionAfterAdoptingTextReplacement(start, node, offset, oldLength, newLength);
 
464
    updatePositionAfterAdoptingTextReplacement(end, node, offset, oldLength, newLength);
 
465
 
 
466
    if (base != m_selection.base() || extent != m_selection.extent() || start != m_selection.start() || end != m_selection.end()) {
 
467
        VisibleSelection newSelection;
 
468
        newSelection.setWithoutValidation(base, extent);
 
469
        m_frame->document()->updateLayout();
 
470
        setSelection(newSelection, DoNotSetFocus);
 
471
    }
 
472
}
 
473
 
 
474
TextDirection FrameSelection::directionOfEnclosingBlock()
 
475
{
 
476
    return WebCore::directionOfEnclosingBlock(m_selection.extent());
 
477
}
 
478
 
 
479
TextDirection FrameSelection::directionOfSelection()
 
480
{
 
481
    InlineBox* startBox = 0;
 
482
    InlineBox* endBox = 0;
 
483
    int unusedOffset;
 
484
    if (m_selection.start().isNotNull())
 
485
        m_selection.visibleStart().getInlineBoxAndOffset(startBox, unusedOffset);
 
486
    if (m_selection.end().isNotNull())
 
487
        m_selection.visibleEnd().getInlineBoxAndOffset(endBox, unusedOffset);
 
488
    if (startBox && endBox && startBox->direction() == endBox->direction())
 
489
        return startBox->direction();
 
490
 
 
491
    return directionOfEnclosingBlock();
 
492
}
 
493
 
 
494
void FrameSelection::willBeModified(EAlteration alter, SelectionDirection direction)
 
495
{
 
496
    if (alter != AlterationExtend)
 
497
        return;
 
498
 
 
499
    Position start = m_selection.start();
 
500
    Position end = m_selection.end();
 
501
 
 
502
    bool baseIsStart = true;
 
503
 
 
504
    if (m_selection.isDirectional()) {
 
505
        // Make base and extent match start and end so we extend the user-visible selection.
 
506
        // This only matters for cases where base and extend point to different positions than
 
507
        // start and end (e.g. after a double-click to select a word).
 
508
        if (m_selection.isBaseFirst())
 
509
            baseIsStart = true;
 
510
        else
 
511
            baseIsStart = false;
 
512
    } else {
 
513
        switch (direction) {
 
514
        case DirectionRight:
 
515
            if (directionOfSelection() == LTR)
 
516
                baseIsStart = true;
 
517
            else
 
518
                baseIsStart = false;
 
519
            break;
 
520
        case DirectionForward:
 
521
            baseIsStart = true;
 
522
            break;
 
523
        case DirectionLeft:
 
524
            if (directionOfSelection() == LTR)
 
525
                baseIsStart = false;
 
526
            else
 
527
                baseIsStart = true;
 
528
            break;
 
529
        case DirectionBackward:
 
530
            baseIsStart = false;
 
531
            break;
 
532
        }
 
533
    }
 
534
    if (baseIsStart) {
 
535
        m_selection.setBase(start);
 
536
        m_selection.setExtent(end);
 
537
    } else {
 
538
        m_selection.setBase(end);
 
539
        m_selection.setExtent(start);
 
540
    }
 
541
}
 
542
 
 
543
VisiblePosition FrameSelection::positionForPlatform(bool isGetStart) const
 
544
{
 
545
    Settings* settings = m_frame ? m_frame->settings() : 0;
 
546
    if (settings && settings->editingBehaviorType() == EditingMacBehavior)
 
547
        return isGetStart ? m_selection.visibleStart() : m_selection.visibleEnd();
 
548
    // Linux and Windows always extend selections from the extent endpoint.
 
549
    // FIXME: VisibleSelection should be fixed to ensure as an invariant that
 
550
    // base/extent always point to the same nodes as start/end, but which points
 
551
    // to which depends on the value of isBaseFirst. Then this can be changed
 
552
    // to just return m_sel.extent().
 
553
    return m_selection.isBaseFirst() ? m_selection.visibleEnd() : m_selection.visibleStart();
 
554
}
 
555
 
 
556
VisiblePosition FrameSelection::startForPlatform() const
 
557
{
 
558
    return positionForPlatform(true);
 
559
}
 
560
 
 
561
VisiblePosition FrameSelection::endForPlatform() const
 
562
{
 
563
    return positionForPlatform(false);
 
564
}
 
565
 
 
566
#if ENABLE(USERSELECT_ALL)
 
567
static void adjustPositionForUserSelectAll(VisiblePosition& pos, bool isForward)
 
568
{
 
569
    if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(pos.deepEquivalent().anchorNode()))
 
570
        pos = isForward ? positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary) : positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary);
 
571
}
 
572
#endif
 
573
 
 
574
VisiblePosition FrameSelection::modifyExtendingRight(TextGranularity granularity)
 
575
{
 
576
    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
 
577
 
 
578
    // The difference between modifyExtendingRight and modifyExtendingForward is:
 
579
    // modifyExtendingForward always extends forward logically.
 
580
    // modifyExtendingRight behaves the same as modifyExtendingForward except for extending character or word,
 
581
    // it extends forward logically if the enclosing block is LTR direction,
 
582
    // but it extends backward logically if the enclosing block is RTL direction.
 
583
    switch (granularity) {
 
584
    case CharacterGranularity:
 
585
        if (directionOfEnclosingBlock() == LTR)
 
586
            pos = pos.next(CannotCrossEditingBoundary);
 
587
        else
 
588
            pos = pos.previous(CannotCrossEditingBoundary);
 
589
        break;
 
590
    case WordGranularity:
 
591
        if (directionOfEnclosingBlock() == LTR)
 
592
            pos = nextWordPosition(pos);
 
593
        else
 
594
            pos = previousWordPosition(pos);
 
595
        break;
 
596
    case LineBoundary:
 
597
        if (directionOfEnclosingBlock() == LTR)
 
598
            pos = modifyExtendingForward(granularity);
 
599
        else
 
600
            pos = modifyExtendingBackward(granularity);
 
601
        break;
 
602
    case SentenceGranularity:
 
603
    case LineGranularity:
 
604
    case ParagraphGranularity:
 
605
    case SentenceBoundary:
 
606
    case ParagraphBoundary:
 
607
    case DocumentBoundary:
 
608
        // FIXME: implement all of the above?
 
609
        pos = modifyExtendingForward(granularity);
 
610
        break;
 
611
    }
 
612
#if ENABLE(USERSELECT_ALL)
 
613
    adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
 
614
#endif
 
615
    return pos;
 
616
}
 
617
 
 
618
VisiblePosition FrameSelection::modifyExtendingForward(TextGranularity granularity)
 
619
{
 
620
    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
 
621
    switch (granularity) {
 
622
    case CharacterGranularity:
 
623
        pos = pos.next(CannotCrossEditingBoundary);
 
624
        break;
 
625
    case WordGranularity:
 
626
        pos = nextWordPosition(pos);
 
627
        break;
 
628
    case SentenceGranularity:
 
629
        pos = nextSentencePosition(pos);
 
630
        break;
 
631
    case LineGranularity:
 
632
        pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
 
633
        break;
 
634
    case ParagraphGranularity:
 
635
        pos = nextParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
 
636
        break;
 
637
    case SentenceBoundary:
 
638
        pos = endOfSentence(endForPlatform());
 
639
        break;
 
640
    case LineBoundary:
 
641
        pos = logicalEndOfLine(endForPlatform());
 
642
        break;
 
643
    case ParagraphBoundary:
 
644
        pos = endOfParagraph(endForPlatform());
 
645
        break;
 
646
    case DocumentBoundary:
 
647
        pos = endForPlatform();
 
648
        if (isEditablePosition(pos.deepEquivalent()))
 
649
            pos = endOfEditableContent(pos);
 
650
        else
 
651
            pos = endOfDocument(pos);
 
652
        break;
 
653
    }
 
654
#if ENABLE(USERSELECT_ALL)
 
655
     adjustPositionForUserSelectAll(pos, directionOfEnclosingBlock() == LTR);
 
656
#endif
 
657
    return pos;
 
658
}
 
659
 
 
660
VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity)
 
661
{
 
662
    VisiblePosition pos;
 
663
    switch (granularity) {
 
664
    case CharacterGranularity:
 
665
        if (isRange()) {
 
666
            if (directionOfSelection() == LTR)
 
667
                pos = VisiblePosition(m_selection.end(), m_selection.affinity());
 
668
            else
 
669
                pos = VisiblePosition(m_selection.start(), m_selection.affinity());
 
670
        } else
 
671
            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
 
672
        break;
 
673
    case WordGranularity: {
 
674
#if USE(ICU_UNICODE)
 
675
        // Visual word movement relies on isWordTextBreak which is not implemented in WinCE and QT.
 
676
        // https://bugs.webkit.org/show_bug.cgi?id=81136.
 
677
        bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor()->behavior().shouldSkipSpaceWhenMovingRight();
 
678
        pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
 
679
        break;
 
680
#endif
 
681
    }
 
682
    case SentenceGranularity:
 
683
    case LineGranularity:
 
684
    case ParagraphGranularity:
 
685
    case SentenceBoundary:
 
686
    case ParagraphBoundary:
 
687
    case DocumentBoundary:
 
688
        // FIXME: Implement all of the above.
 
689
        pos = modifyMovingForward(granularity);
 
690
        break;
 
691
    case LineBoundary:
 
692
        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
 
693
        break;
 
694
    }
 
695
    return pos;
 
696
}
 
697
 
 
698
VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity)
 
699
{
 
700
    VisiblePosition pos;
 
701
    // FIXME: Stay in editable content for the less common granularities.
 
702
    switch (granularity) {
 
703
    case CharacterGranularity:
 
704
        if (isRange())
 
705
            pos = VisiblePosition(m_selection.end(), m_selection.affinity());
 
706
        else
 
707
            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
 
708
        break;
 
709
    case WordGranularity:
 
710
        pos = nextWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
 
711
        break;
 
712
    case SentenceGranularity:
 
713
        pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
 
714
        break;
 
715
    case LineGranularity: {
 
716
        // down-arrowing from a range selection that ends at the start of a line needs
 
717
        // to leave the selection at that line start (no need to call nextLinePosition!)
 
718
        pos = endForPlatform();
 
719
        if (!isRange() || !isStartOfLine(pos))
 
720
            pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(START));
 
721
        break;
 
722
    }
 
723
    case ParagraphGranularity:
 
724
        pos = nextParagraphPosition(endForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
 
725
        break;
 
726
    case SentenceBoundary:
 
727
        pos = endOfSentence(endForPlatform());
 
728
        break;
 
729
    case LineBoundary:
 
730
        pos = logicalEndOfLine(endForPlatform());
 
731
        break;
 
732
    case ParagraphBoundary:
 
733
        pos = endOfParagraph(endForPlatform());
 
734
        break;
 
735
    case DocumentBoundary:
 
736
        pos = endForPlatform();
 
737
        if (isEditablePosition(pos.deepEquivalent()))
 
738
            pos = endOfEditableContent(pos);
 
739
        else
 
740
            pos = endOfDocument(pos);
 
741
        break;
 
742
    }
 
743
    return pos;
 
744
}
 
745
 
 
746
VisiblePosition FrameSelection::modifyExtendingLeft(TextGranularity granularity)
 
747
{
 
748
    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
 
749
 
 
750
    // The difference between modifyExtendingLeft and modifyExtendingBackward is:
 
751
    // modifyExtendingBackward always extends backward logically.
 
752
    // modifyExtendingLeft behaves the same as modifyExtendingBackward except for extending character or word,
 
753
    // it extends backward logically if the enclosing block is LTR direction,
 
754
    // but it extends forward logically if the enclosing block is RTL direction.
 
755
    switch (granularity) {
 
756
    case CharacterGranularity:
 
757
        if (directionOfEnclosingBlock() == LTR)
 
758
            pos = pos.previous(CannotCrossEditingBoundary);
 
759
        else
 
760
            pos = pos.next(CannotCrossEditingBoundary);
 
761
        break;
 
762
    case WordGranularity:
 
763
        if (directionOfEnclosingBlock() == LTR)
 
764
            pos = previousWordPosition(pos);
 
765
        else
 
766
            pos = nextWordPosition(pos);
 
767
        break;
 
768
    case LineBoundary:
 
769
        if (directionOfEnclosingBlock() == LTR)
 
770
            pos = modifyExtendingBackward(granularity);
 
771
        else
 
772
            pos = modifyExtendingForward(granularity);
 
773
        break;
 
774
    case SentenceGranularity:
 
775
    case LineGranularity:
 
776
    case ParagraphGranularity:
 
777
    case SentenceBoundary:
 
778
    case ParagraphBoundary:
 
779
    case DocumentBoundary:
 
780
        pos = modifyExtendingBackward(granularity);
 
781
        break;
 
782
    }
 
783
#if ENABLE(USERSELECT_ALL)
 
784
    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
 
785
#endif
 
786
    return pos;
 
787
}
 
788
       
 
789
VisiblePosition FrameSelection::modifyExtendingBackward(TextGranularity granularity)
 
790
{
 
791
    VisiblePosition pos(m_selection.extent(), m_selection.affinity());
 
792
 
 
793
    // Extending a selection backward by word or character from just after a table selects
 
794
    // the table.  This "makes sense" from the user perspective, esp. when deleting.
 
795
    // It was done here instead of in VisiblePosition because we want VPs to iterate
 
796
    // over everything.
 
797
    switch (granularity) {
 
798
    case CharacterGranularity:
 
799
        pos = pos.previous(CannotCrossEditingBoundary);
 
800
        break;
 
801
    case WordGranularity:
 
802
        pos = previousWordPosition(pos);
 
803
        break;
 
804
    case SentenceGranularity:
 
805
        pos = previousSentencePosition(pos);
 
806
        break;
 
807
    case LineGranularity:
 
808
        pos = previousLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
 
809
        break;
 
810
    case ParagraphGranularity:
 
811
        pos = previousParagraphPosition(pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
 
812
        break;
 
813
    case SentenceBoundary:
 
814
        pos = startOfSentence(startForPlatform());
 
815
        break;
 
816
    case LineBoundary:
 
817
        pos = logicalStartOfLine(startForPlatform());
 
818
        break;
 
819
    case ParagraphBoundary:
 
820
        pos = startOfParagraph(startForPlatform());
 
821
        break;
 
822
    case DocumentBoundary:
 
823
        pos = startForPlatform();
 
824
        if (isEditablePosition(pos.deepEquivalent()))
 
825
            pos = startOfEditableContent(pos);
 
826
        else
 
827
            pos = startOfDocument(pos);
 
828
        break;
 
829
    }
 
830
#if ENABLE(USERSELECT_ALL)
 
831
    adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
 
832
#endif
 
833
    return pos;
 
834
}
 
835
 
 
836
VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity)
 
837
{
 
838
    VisiblePosition pos;
 
839
    switch (granularity) {
 
840
    case CharacterGranularity:
 
841
        if (isRange())
 
842
            if (directionOfSelection() == LTR)
 
843
                pos = VisiblePosition(m_selection.start(), m_selection.affinity());
 
844
            else
 
845
                pos = VisiblePosition(m_selection.end(), m_selection.affinity());
 
846
        else
 
847
            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
 
848
        break;
 
849
    case WordGranularity: {
 
850
#if USE(ICU_UNICODE)
 
851
        bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor()->behavior().shouldSkipSpaceWhenMovingRight();
 
852
        pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
 
853
        break;
 
854
#endif
 
855
    }
 
856
    case SentenceGranularity:
 
857
    case LineGranularity:
 
858
    case ParagraphGranularity:
 
859
    case SentenceBoundary:
 
860
    case ParagraphBoundary:
 
861
    case DocumentBoundary:
 
862
        // FIXME: Implement all of the above.
 
863
        pos = modifyMovingBackward(granularity);
 
864
        break;
 
865
    case LineBoundary:
 
866
        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
 
867
        break;
 
868
    }
 
869
    return pos;
 
870
}
 
871
 
 
872
VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity)
 
873
{
 
874
    VisiblePosition pos;
 
875
    switch (granularity) {
 
876
    case CharacterGranularity:
 
877
        if (isRange())
 
878
            pos = VisiblePosition(m_selection.start(), m_selection.affinity());
 
879
        else
 
880
            pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
 
881
        break;
 
882
    case WordGranularity:
 
883
        pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
 
884
        break;
 
885
    case SentenceGranularity:
 
886
        pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
 
887
        break;
 
888
    case LineGranularity:
 
889
        pos = previousLinePosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
 
890
        break;
 
891
    case ParagraphGranularity:
 
892
        pos = previousParagraphPosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
 
893
        break;
 
894
    case SentenceBoundary:
 
895
        pos = startOfSentence(startForPlatform());
 
896
        break;
 
897
    case LineBoundary:
 
898
        pos = logicalStartOfLine(startForPlatform());
 
899
        break;
 
900
    case ParagraphBoundary:
 
901
        pos = startOfParagraph(startForPlatform());
 
902
        break;
 
903
    case DocumentBoundary:
 
904
        pos = startForPlatform();
 
905
        if (isEditablePosition(pos.deepEquivalent()))
 
906
            pos = startOfEditableContent(pos);
 
907
        else
 
908
            pos = startOfDocument(pos);
 
909
        break;
 
910
    }
 
911
    return pos;
 
912
}
 
913
 
 
914
static bool isBoundary(TextGranularity granularity)
 
915
{
 
916
    return granularity == LineBoundary || granularity == ParagraphBoundary || granularity == DocumentBoundary;
 
917
}    
 
918
 
 
919
bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
 
920
{
 
921
    if (userTriggered == UserTriggered) {
 
922
        FrameSelection trialFrameSelection;
 
923
        trialFrameSelection.setSelection(m_selection);
 
924
        trialFrameSelection.modify(alter, direction, granularity, NotUserTriggered);
 
925
 
 
926
        bool change = shouldChangeSelection(trialFrameSelection.selection());
 
927
        if (!change)
 
928
            return false;
 
929
 
 
930
        if (trialFrameSelection.selection().isRange() && m_selection.isCaret() && !dispatchSelectStart())
 
931
            return false;
 
932
    }
 
933
 
 
934
    willBeModified(alter, direction);
 
935
 
 
936
    bool wasRange = m_selection.isRange();
 
937
    Position originalStartPosition = m_selection.start();
 
938
    VisiblePosition position;
 
939
    switch (direction) {
 
940
    case DirectionRight:
 
941
        if (alter == AlterationMove)
 
942
            position = modifyMovingRight(granularity);
 
943
        else
 
944
            position = modifyExtendingRight(granularity);
 
945
        break;
 
946
    case DirectionForward:
 
947
        if (alter == AlterationExtend)
 
948
            position = modifyExtendingForward(granularity);
 
949
        else
 
950
            position = modifyMovingForward(granularity);
 
951
        break;
 
952
    case DirectionLeft:
 
953
        if (alter == AlterationMove)
 
954
            position = modifyMovingLeft(granularity);
 
955
        else
 
956
            position = modifyExtendingLeft(granularity);
 
957
        break;
 
958
    case DirectionBackward:
 
959
        if (alter == AlterationExtend)
 
960
            position = modifyExtendingBackward(granularity);
 
961
        else
 
962
            position = modifyMovingBackward(granularity);
 
963
        break;
 
964
    }
 
965
 
 
966
    if (position.isNull())
 
967
        return false;
 
968
 
 
969
    if (isSpatialNavigationEnabled(m_frame))
 
970
        if (!wasRange && alter == AlterationMove && position == originalStartPosition)
 
971
            return false;
 
972
 
 
973
    // Some of the above operations set an xPosForVerticalArrowNavigation.
 
974
    // Setting a selection will clear it, so save it to possibly restore later.
 
975
    // Note: the START position type is arbitrary because it is unused, it would be
 
976
    // the requested position type if there were no xPosForVerticalArrowNavigation set.
 
977
    LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START);
 
978
    m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_frame) || alter == AlterationExtend);
 
979
 
 
980
    switch (alter) {
 
981
    case AlterationMove:
 
982
        moveTo(position, userTriggered);
 
983
        break;
 
984
    case AlterationExtend:
 
985
 
 
986
        if (!m_selection.isCaret()
 
987
            && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity)
 
988
            && m_frame && !m_frame->editor()->behavior().shouldExtendSelectionByWordOrLineAcrossCaret()) {
 
989
            // Don't let the selection go across the base position directly. Needed to match mac
 
990
            // behavior when, for instance, word-selecting backwards starting with the caret in
 
991
            // the middle of a word and then word-selecting forward, leaving the caret in the
 
992
            // same place where it was, instead of directly selecting to the end of the word.
 
993
            VisibleSelection newSelection = m_selection;
 
994
            newSelection.setExtent(position);
 
995
            if (m_selection.isBaseFirst() != newSelection.isBaseFirst())
 
996
                position = m_selection.base();
 
997
        }
 
998
 
 
999
        // Standard Mac behavior when extending to a boundary is grow the selection rather than leaving the
 
1000
        // base in place and moving the extent. Matches NSTextView.
 
1001
        if (!m_frame || !m_frame->editor()->behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity))
 
1002
            setExtent(position, userTriggered);
 
1003
        else {
 
1004
            TextDirection textDirection = directionOfEnclosingBlock();
 
1005
            if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft))
 
1006
                setEnd(position, userTriggered);
 
1007
            else
 
1008
                setStart(position, userTriggered);
 
1009
        }
 
1010
        break;
 
1011
    }
 
1012
    
 
1013
    if (granularity == LineGranularity || granularity == ParagraphGranularity)
 
1014
        m_xPosForVerticalArrowNavigation = x;
 
1015
 
 
1016
    if (userTriggered == UserTriggered)
 
1017
        m_granularity = CharacterGranularity;
 
1018
 
 
1019
    setCaretRectNeedsUpdate();
 
1020
 
 
1021
    return true;
 
1022
}
 
1023
 
 
1024
// FIXME: Maybe baseline would be better?
 
1025
static bool absoluteCaretY(const VisiblePosition &c, int &y)
 
1026
{
 
1027
    IntRect rect = c.absoluteCaretBounds();
 
1028
    if (rect.isEmpty())
 
1029
        return false;
 
1030
    y = rect.y() + rect.height() / 2;
 
1031
    return true;
 
1032
}
 
1033
 
 
1034
bool FrameSelection::modify(EAlteration alter, unsigned verticalDistance, VerticalDirection direction, EUserTriggered userTriggered, CursorAlignOnScroll align)
 
1035
{
 
1036
    if (!verticalDistance)
 
1037
        return false;
 
1038
 
 
1039
    if (userTriggered == UserTriggered) {
 
1040
        FrameSelection trialFrameSelection;
 
1041
        trialFrameSelection.setSelection(m_selection);
 
1042
        trialFrameSelection.modify(alter, verticalDistance, direction, NotUserTriggered);
 
1043
 
 
1044
        bool change = shouldChangeSelection(trialFrameSelection.selection());
 
1045
        if (!change)
 
1046
            return false;
 
1047
    }
 
1048
 
 
1049
    willBeModified(alter, direction == DirectionUp ? DirectionBackward : DirectionForward);
 
1050
 
 
1051
    VisiblePosition pos;
 
1052
    LayoutUnit xPos = 0;
 
1053
    switch (alter) {
 
1054
    case AlterationMove:
 
1055
        pos = VisiblePosition(direction == DirectionUp ? m_selection.start() : m_selection.end(), m_selection.affinity());
 
1056
        xPos = lineDirectionPointForBlockDirectionNavigation(direction == DirectionUp ? START : END);
 
1057
        m_selection.setAffinity(direction == DirectionUp ? UPSTREAM : DOWNSTREAM);
 
1058
        break;
 
1059
    case AlterationExtend:
 
1060
        pos = VisiblePosition(m_selection.extent(), m_selection.affinity());
 
1061
        xPos = lineDirectionPointForBlockDirectionNavigation(EXTENT);
 
1062
        m_selection.setAffinity(DOWNSTREAM);
 
1063
        break;
 
1064
    }
 
1065
 
 
1066
    int startY;
 
1067
    if (!absoluteCaretY(pos, startY))
 
1068
        return false;
 
1069
    if (direction == DirectionUp)
 
1070
        startY = -startY;
 
1071
    int lastY = startY;
 
1072
 
 
1073
    VisiblePosition result;
 
1074
    VisiblePosition next;
 
1075
    for (VisiblePosition p = pos; ; p = next) {
 
1076
        if (direction == DirectionUp)
 
1077
            next = previousLinePosition(p, xPos);
 
1078
        else
 
1079
            next = nextLinePosition(p, xPos);
 
1080
 
 
1081
        if (next.isNull() || next == p)
 
1082
            break;
 
1083
        int nextY;
 
1084
        if (!absoluteCaretY(next, nextY))
 
1085
            break;
 
1086
        if (direction == DirectionUp)
 
1087
            nextY = -nextY;
 
1088
        if (nextY - startY > static_cast<int>(verticalDistance))
 
1089
            break;
 
1090
        if (nextY >= lastY) {
 
1091
            lastY = nextY;
 
1092
            result = next;
 
1093
        }
 
1094
    }
 
1095
 
 
1096
    if (result.isNull())
 
1097
        return false;
 
1098
 
 
1099
    switch (alter) {
 
1100
    case AlterationMove:
 
1101
        moveTo(result, userTriggered, align);
 
1102
        break;
 
1103
    case AlterationExtend:
 
1104
        setExtent(result, userTriggered);
 
1105
        break;
 
1106
    }
 
1107
 
 
1108
    if (userTriggered == UserTriggered)
 
1109
        m_granularity = CharacterGranularity;
 
1110
 
 
1111
    m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(m_frame) || alter == AlterationExtend);
 
1112
 
 
1113
    return true;
 
1114
}
 
1115
 
 
1116
LayoutUnit FrameSelection::lineDirectionPointForBlockDirectionNavigation(EPositionType type)
 
1117
{
 
1118
    LayoutUnit x = 0;
 
1119
 
 
1120
    if (isNone())
 
1121
        return x;
 
1122
 
 
1123
    Position pos;
 
1124
    switch (type) {
 
1125
    case START:
 
1126
        pos = m_selection.start();
 
1127
        break;
 
1128
    case END:
 
1129
        pos = m_selection.end();
 
1130
        break;
 
1131
    case BASE:
 
1132
        pos = m_selection.base();
 
1133
        break;
 
1134
    case EXTENT:
 
1135
        pos = m_selection.extent();
 
1136
        break;
 
1137
    }
 
1138
 
 
1139
    Frame* frame = pos.anchorNode()->document()->frame();
 
1140
    if (!frame)
 
1141
        return x;
 
1142
        
 
1143
    if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation()) {
 
1144
        VisiblePosition visiblePosition(pos, m_selection.affinity());
 
1145
        // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
 
1146
        // after the selection is created and before this function is called.
 
1147
        x = visiblePosition.isNotNull() ? visiblePosition.lineDirectionPointForBlockDirectionNavigation() : 0;
 
1148
        m_xPosForVerticalArrowNavigation = x;
 
1149
    } else
 
1150
        x = m_xPosForVerticalArrowNavigation;
 
1151
        
 
1152
    return x;
 
1153
}
 
1154
 
 
1155
void FrameSelection::clear()
 
1156
{
 
1157
    m_granularity = CharacterGranularity;
 
1158
    setSelection(VisibleSelection());
 
1159
}
 
1160
 
 
1161
void FrameSelection::prepareForDestruction()
 
1162
{
 
1163
    m_granularity = CharacterGranularity;
 
1164
 
 
1165
#if ENABLE(TEXT_CARET)
 
1166
    m_caretBlinkTimer.stop();
 
1167
#endif
 
1168
 
 
1169
    RenderView* view = m_frame->contentRenderer();
 
1170
    if (view)
 
1171
        view->clearSelection();
 
1172
 
 
1173
    setSelection(VisibleSelection(), CloseTyping | ClearTypingStyle | DoNotUpdateAppearance);
 
1174
}
 
1175
 
 
1176
void FrameSelection::setStart(const VisiblePosition &pos, EUserTriggered trigger)
 
1177
{
 
1178
    if (m_selection.isBaseFirst())
 
1179
        setBase(pos, trigger);
 
1180
    else
 
1181
        setExtent(pos, trigger);
 
1182
}
 
1183
 
 
1184
void FrameSelection::setEnd(const VisiblePosition &pos, EUserTriggered trigger)
 
1185
{
 
1186
    if (m_selection.isBaseFirst())
 
1187
        setExtent(pos, trigger);
 
1188
    else
 
1189
        setBase(pos, trigger);
 
1190
}
 
1191
 
 
1192
void FrameSelection::setBase(const VisiblePosition &pos, EUserTriggered userTriggered)
 
1193
{
 
1194
    const bool selectionHasDirection = true;
 
1195
    setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity(), selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
 
1196
}
 
1197
 
 
1198
void FrameSelection::setExtent(const VisiblePosition &pos, EUserTriggered userTriggered)
 
1199
{
 
1200
    const bool selectionHasDirection = true;
 
1201
    setSelection(VisibleSelection(m_selection.base(), pos.deepEquivalent(), pos.affinity(), selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
 
1202
}
 
1203
 
 
1204
void FrameSelection::setBase(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
 
1205
{
 
1206
    const bool selectionHasDirection = true;
 
1207
    setSelection(VisibleSelection(pos, m_selection.extent(), affinity, selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
 
1208
}
 
1209
 
 
1210
void FrameSelection::setExtent(const Position &pos, EAffinity affinity, EUserTriggered userTriggered)
 
1211
{
 
1212
    const bool selectionHasDirection = true;
 
1213
    setSelection(VisibleSelection(m_selection.base(), pos, affinity, selectionHasDirection), CloseTyping | ClearTypingStyle | userTriggered);
 
1214
}
 
1215
 
 
1216
void CaretBase::clearCaretRect()
 
1217
{
 
1218
    m_caretLocalRect = LayoutRect();
 
1219
}
 
1220
 
 
1221
bool CaretBase::updateCaretRect(Document* document, const VisiblePosition& caretPosition)
 
1222
{
 
1223
    document->updateStyleIfNeeded();
 
1224
    m_caretLocalRect = LayoutRect();
 
1225
 
 
1226
    m_caretRectNeedsUpdate = false;
 
1227
 
 
1228
    if (caretPosition.isNull())
 
1229
        return false;
 
1230
 
 
1231
    ASSERT(caretPosition.deepEquivalent().deprecatedNode()->renderer());
 
1232
 
 
1233
    // First compute a rect local to the renderer at the selection start.
 
1234
    RenderObject* renderer;
 
1235
    LayoutRect localRect = caretPosition.localCaretRect(renderer);
 
1236
 
 
1237
    // Get the renderer that will be responsible for painting the caret
 
1238
    // (which is either the renderer we just found, or one of its containers).
 
1239
    RenderObject* caretPainter = caretRenderer(caretPosition.deepEquivalent().deprecatedNode());
 
1240
 
 
1241
    // Compute an offset between the renderer and the caretPainter.
 
1242
    bool unrooted = false;
 
1243
    while (renderer != caretPainter) {
 
1244
        RenderObject* containerObject = renderer->container();
 
1245
        if (!containerObject) {
 
1246
            unrooted = true;
 
1247
            break;
 
1248
        }
 
1249
        localRect.move(renderer->offsetFromContainer(containerObject, localRect.location()));
 
1250
        renderer = containerObject;
 
1251
    }
 
1252
 
 
1253
    if (!unrooted)
 
1254
        m_caretLocalRect = localRect;
 
1255
 
 
1256
    return true;
 
1257
}
 
1258
 
 
1259
static inline bool caretRendersInsideNode(Node* node)
 
1260
{
 
1261
    return node && !isTableElement(node) && !editingIgnoresContent(node);
 
1262
}
 
1263
 
 
1264
RenderObject* CaretBase::caretRenderer(Node* node) const
 
1265
{
 
1266
    if (!node)
 
1267
        return 0;
 
1268
 
 
1269
    RenderObject* renderer = node->renderer();
 
1270
    if (!renderer)
 
1271
        return 0;
 
1272
 
 
1273
    // if caretNode is a block and caret is inside it then caret should be painted by that block
 
1274
    bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node);
 
1275
    return paintedByBlock ? renderer : renderer->containingBlock();
 
1276
}
 
1277
 
 
1278
RenderObject* FrameSelection::caretRenderer() const
 
1279
{
 
1280
    return CaretBase::caretRenderer(m_selection.start().deprecatedNode());
 
1281
}
 
1282
 
 
1283
RenderObject* DragCaretController::caretRenderer() const
 
1284
{
 
1285
    return CaretBase::caretRenderer(m_position.deepEquivalent().deprecatedNode());
 
1286
}
 
1287
 
 
1288
static bool isNonOrphanedCaret(const VisibleSelection& selection)
 
1289
{
 
1290
    return selection.isCaret() && !selection.start().isOrphan() && !selection.end().isOrphan();
 
1291
}
 
1292
 
 
1293
LayoutRect FrameSelection::localCaretRect()
 
1294
{
 
1295
    if (shouldUpdateCaretRect()) {
 
1296
        if (!isNonOrphanedCaret(m_selection))
 
1297
            clearCaretRect();
 
1298
        else if (updateCaretRect(m_frame->document(), VisiblePosition(m_selection.start(), m_selection.affinity())))
 
1299
            m_absCaretBoundsDirty = true;
 
1300
    }
 
1301
 
 
1302
    return localCaretRectWithoutUpdate();
 
1303
}
 
1304
 
 
1305
IntRect CaretBase::absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect) const
 
1306
{
 
1307
    RenderObject* caretPainter = caretRenderer(node);
 
1308
    if (!caretPainter)
 
1309
        return IntRect();
 
1310
    
 
1311
    LayoutRect localRect(rect);
 
1312
    if (caretPainter->isBox())
 
1313
        toRenderBox(caretPainter)->flipForWritingMode(localRect);
 
1314
    return caretPainter->localToAbsoluteQuad(FloatRect(localRect), SnapOffsetForTransforms).enclosingBoundingBox();
 
1315
}
 
1316
 
 
1317
IntRect FrameSelection::absoluteCaretBounds()
 
1318
{
 
1319
    recomputeCaretRect();
 
1320
    return m_absCaretBounds;
 
1321
}
 
1322
 
 
1323
static LayoutRect repaintRectForCaret(LayoutRect caret)
 
1324
{
 
1325
    if (caret.isEmpty())
 
1326
        return LayoutRect();
 
1327
    // Ensure that the dirty rect intersects the block that paints the caret even in the case where
 
1328
    // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>.
 
1329
    caret.inflateX(1);
 
1330
    caret.inflateY(1);
 
1331
    return caret;
 
1332
}
 
1333
 
 
1334
IntRect CaretBase::caretRepaintRect(Node* node) const
 
1335
{
 
1336
    return absoluteBoundsForLocalRect(node, repaintRectForCaret(localCaretRectWithoutUpdate()));
 
1337
}
 
1338
 
 
1339
bool FrameSelection::recomputeCaretRect()
 
1340
{
 
1341
    if (!shouldUpdateCaretRect())
 
1342
        return false;
 
1343
 
 
1344
    if (!m_frame)
 
1345
        return false;
 
1346
 
 
1347
    FrameView* v = m_frame->document()->view();
 
1348
    if (!v)
 
1349
        return false;
 
1350
 
 
1351
    LayoutRect oldRect = localCaretRectWithoutUpdate();
 
1352
    LayoutRect newRect = localCaretRect();
 
1353
    if (oldRect == newRect && !m_absCaretBoundsDirty)
 
1354
        return false;
 
1355
 
 
1356
    IntRect oldAbsCaretBounds = m_absCaretBounds;
 
1357
    // FIXME: Rename m_caretRect to m_localCaretRect.
 
1358
    m_absCaretBounds = absoluteBoundsForLocalRect(m_selection.start().deprecatedNode(), localCaretRectWithoutUpdate());
 
1359
    m_absCaretBoundsDirty = false;
 
1360
    
 
1361
    if (oldAbsCaretBounds == m_absCaretBounds)
 
1362
        return false;
 
1363
 
 
1364
#if ENABLE(TEXT_CARET)
 
1365
    IntRect oldAbsoluteCaretRepaintBounds = m_absoluteCaretRepaintBounds;
 
1366
#endif
 
1367
 
 
1368
    // We believe that we need to inflate the local rect before transforming it to obtain the repaint bounds.
 
1369
    m_absoluteCaretRepaintBounds = caretRepaintRect(m_selection.start().deprecatedNode());
 
1370
 
 
1371
#if ENABLE(TEXT_CARET)
 
1372
    if (RenderView* view = m_frame->document()->renderView()) {
 
1373
        // FIXME: make caret repainting container-aware.
 
1374
        view->repaintRectangleInViewAndCompositedLayers(oldAbsoluteCaretRepaintBounds, false);
 
1375
        if (shouldRepaintCaret(view, isContentEditable()))
 
1376
            view->repaintRectangleInViewAndCompositedLayers(m_absoluteCaretRepaintBounds, false);
 
1377
    }
 
1378
#endif
 
1379
    return true;
 
1380
}
 
1381
 
 
1382
bool CaretBase::shouldRepaintCaret(const RenderView* view, bool isContentEditable) const
 
1383
{
 
1384
    ASSERT(view);
 
1385
    Frame* frame = view->frameView() ? view->frameView()->frame() : 0; // The frame where the selection started.
 
1386
    bool caretBrowsing = frame && frame->settings() && frame->settings()->caretBrowsingEnabled();
 
1387
    return (caretBrowsing || isContentEditable);
 
1388
}
 
1389
 
 
1390
void FrameSelection::invalidateCaretRect()
 
1391
{
 
1392
    if (!isCaret())
 
1393
        return;
 
1394
 
 
1395
    CaretBase::invalidateCaretRect(m_selection.start().deprecatedNode(), recomputeCaretRect());
 
1396
}
 
1397
 
 
1398
void CaretBase::invalidateCaretRect(Node* node, bool caretRectChanged)
 
1399
{
 
1400
    // EDIT FIXME: This is an unfortunate hack.
 
1401
    // Basically, we can't trust this layout position since we 
 
1402
    // can't guarantee that the check to see if we are in unrendered 
 
1403
    // content will work at this point. We may have to wait for
 
1404
    // a layout and re-render of the document to happen. So, resetting this
 
1405
    // flag will cause another caret layout to happen the first time
 
1406
    // that we try to paint the caret after this call. That one will work since
 
1407
    // it happens after the document has accounted for any editing
 
1408
    // changes which may have been done.
 
1409
    // And, we need to leave this layout here so the caret moves right 
 
1410
    // away after clicking.
 
1411
    m_caretRectNeedsUpdate = true;
 
1412
 
 
1413
    if (caretRectChanged)
 
1414
        return;
 
1415
 
 
1416
    if (RenderView* view = node->document()->renderView()) {
 
1417
        if (shouldRepaintCaret(view, node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)))
 
1418
            view->repaintRectangleInViewAndCompositedLayers(caretRepaintRect(node), false);
 
1419
    }
 
1420
}
 
1421
 
 
1422
void FrameSelection::paintCaret(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect)
 
1423
{
 
1424
    if (m_selection.isCaret() && m_caretPaint)
 
1425
        CaretBase::paintCaret(m_selection.start().deprecatedNode(), context, paintOffset, clipRect);
 
1426
}
 
1427
 
 
1428
void CaretBase::paintCaret(Node* node, GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
 
1429
{
 
1430
#if ENABLE(TEXT_CARET)
 
1431
    if (m_caretVisibility == Hidden)
 
1432
        return;
 
1433
 
 
1434
    LayoutRect drawingRect = localCaretRectWithoutUpdate();
 
1435
    RenderObject* renderer = caretRenderer(node);
 
1436
    if (renderer && renderer->isBox())
 
1437
        toRenderBox(renderer)->flipForWritingMode(drawingRect);
 
1438
    drawingRect.moveBy(paintOffset);
 
1439
    LayoutRect caret = intersection(drawingRect, clipRect);
 
1440
    if (caret.isEmpty())
 
1441
        return;
 
1442
 
 
1443
    Color caretColor = Color::black;
 
1444
    ColorSpace colorSpace = ColorSpaceDeviceRGB;
 
1445
    Element* element = node->rootEditableElement();
 
1446
    if (element && element->renderer()) {
 
1447
        caretColor = element->renderer()->style()->visitedDependentColor(CSSPropertyColor);
 
1448
        colorSpace = element->renderer()->style()->colorSpace();
 
1449
    }
 
1450
 
 
1451
    context->fillRect(caret, caretColor, colorSpace);
 
1452
#else
 
1453
    UNUSED_PARAM(node);
 
1454
    UNUSED_PARAM(context);
 
1455
    UNUSED_PARAM(paintOffset);
 
1456
    UNUSED_PARAM(clipRect);
 
1457
#endif
 
1458
}
 
1459
 
 
1460
void FrameSelection::debugRenderer(RenderObject *r, bool selected) const
 
1461
{
 
1462
    if (r->node()->isElementNode()) {
 
1463
        Element* element = static_cast<Element *>(r->node());
 
1464
        fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element->localName().string().utf8().data());
 
1465
    } else if (r->isText()) {
 
1466
        RenderText* textRenderer = toRenderText(r);
 
1467
        if (!textRenderer->textLength() || !textRenderer->firstTextBox()) {
 
1468
            fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
 
1469
            return;
 
1470
        }
 
1471
        
 
1472
        static const int max = 36;
 
1473
        String text = textRenderer->text();
 
1474
        int textLength = text.length();
 
1475
        if (selected) {
 
1476
            int offset = 0;
 
1477
            if (r->node() == m_selection.start().containerNode())
 
1478
                offset = m_selection.start().computeOffsetInContainerNode();
 
1479
            else if (r->node() == m_selection.end().containerNode())
 
1480
                offset = m_selection.end().computeOffsetInContainerNode();
 
1481
 
 
1482
            int pos;
 
1483
            InlineTextBox* box = textRenderer->findNextInlineTextBox(offset, pos);
 
1484
            text = text.substring(box->start(), box->len());
 
1485
            
 
1486
            String show;
 
1487
            int mid = max / 2;
 
1488
            int caret = 0;
 
1489
            
 
1490
            // text is shorter than max
 
1491
            if (textLength < max) {
 
1492
                show = text;
 
1493
                caret = pos;
 
1494
            } else if (pos - mid < 0) {
 
1495
                // too few characters to left
 
1496
                show = text.left(max - 3) + "...";
 
1497
                caret = pos;
 
1498
            } else if (pos - mid >= 0 && pos + mid <= textLength) {
 
1499
                // enough characters on each side
 
1500
                show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
 
1501
                caret = mid;
 
1502
            } else {
 
1503
                // too few characters on right
 
1504
                show = "..." + text.right(max - 3);
 
1505
                caret = pos - (textLength - show.length());
 
1506
            }
 
1507
            
 
1508
            show.replace('\n', ' ');
 
1509
            show.replace('\r', ' ');
 
1510
            fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
 
1511
            fprintf(stderr, "           ");
 
1512
            for (int i = 0; i < caret; i++)
 
1513
                fprintf(stderr, " ");
 
1514
            fprintf(stderr, "^\n");
 
1515
        } else {
 
1516
            if ((int)text.length() > max)
 
1517
                text = text.left(max - 3) + "...";
 
1518
            else
 
1519
                text = text.left(max);
 
1520
            fprintf(stderr, "    #text : \"%s\"\n", text.utf8().data());
 
1521
        }
 
1522
    }
 
1523
}
 
1524
 
 
1525
bool FrameSelection::contains(const LayoutPoint& point)
 
1526
{
 
1527
    Document* document = m_frame->document();
 
1528
    
 
1529
    // Treat a collapsed selection like no selection.
 
1530
    if (!isRange())
 
1531
        return false;
 
1532
    if (!document->renderer()) 
 
1533
        return false;
 
1534
    
 
1535
    HitTestRequest request(HitTestRequest::ReadOnly |
 
1536
                           HitTestRequest::Active);
 
1537
    HitTestResult result(point);
 
1538
    document->renderView()->hitTest(request, result);
 
1539
    Node* innerNode = result.innerNode();
 
1540
    if (!innerNode || !innerNode->renderer())
 
1541
        return false;
 
1542
    
 
1543
    VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
 
1544
    if (visiblePos.isNull())
 
1545
        return false;
 
1546
        
 
1547
    if (m_selection.visibleStart().isNull() || m_selection.visibleEnd().isNull())
 
1548
        return false;
 
1549
        
 
1550
    Position start(m_selection.visibleStart().deepEquivalent());
 
1551
    Position end(m_selection.visibleEnd().deepEquivalent());
 
1552
    Position p(visiblePos.deepEquivalent());
 
1553
 
 
1554
    return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
 
1555
}
 
1556
 
 
1557
// Workaround for the fact that it's hard to delete a frame.
 
1558
// Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
 
1559
// Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
 
1560
// for the focus to move to another frame. So instead we call it from places where we are selecting with the
 
1561
// mouse or the keyboard after setting the selection.
 
1562
void FrameSelection::selectFrameElementInParentIfFullySelected()
 
1563
{
 
1564
    // Find the parent frame; if there is none, then we have nothing to do.
 
1565
    Frame* parent = m_frame->tree()->parent();
 
1566
    if (!parent)
 
1567
        return;
 
1568
    Page* page = m_frame->page();
 
1569
    if (!page)
 
1570
        return;
 
1571
 
 
1572
    // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
 
1573
    if (!isRange())
 
1574
        return;
 
1575
    if (!isStartOfDocument(selection().visibleStart()))
 
1576
        return;
 
1577
    if (!isEndOfDocument(selection().visibleEnd()))
 
1578
        return;
 
1579
 
 
1580
    // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
 
1581
    Element* ownerElement = m_frame->ownerElement();
 
1582
    if (!ownerElement)
 
1583
        return;
 
1584
    ContainerNode* ownerElementParent = ownerElement->parentNode();
 
1585
    if (!ownerElementParent)
 
1586
        return;
 
1587
        
 
1588
    // This method's purpose is it to make it easier to select iframes (in order to delete them).  Don't do anything if the iframe isn't deletable.
 
1589
    if (!ownerElementParent->rendererIsEditable())
 
1590
        return;
 
1591
 
 
1592
    // Create compute positions before and after the element.
 
1593
    unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
 
1594
    VisiblePosition beforeOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex, Position::PositionIsOffsetInAnchor)));
 
1595
    VisiblePosition afterOwnerElement(VisiblePosition(Position(ownerElementParent, ownerElementNodeIndex + 1, Position::PositionIsOffsetInAnchor), VP_UPSTREAM_IF_POSSIBLE));
 
1596
 
 
1597
    // Focus on the parent frame, and then select from before this element to after.
 
1598
    VisibleSelection newSelection(beforeOwnerElement, afterOwnerElement);
 
1599
    if (parent->selection()->shouldChangeSelection(newSelection)) {
 
1600
        page->focusController()->setFocusedFrame(parent);
 
1601
        parent->selection()->setSelection(newSelection);
 
1602
    }
 
1603
}
 
1604
 
 
1605
void FrameSelection::selectAll()
 
1606
{
 
1607
    Document* document = m_frame->document();
 
1608
 
 
1609
    if (document->focusedNode() && document->focusedNode()->hasTagName(selectTag)) {
 
1610
        HTMLSelectElement* selectElement = toHTMLSelectElement(document->focusedNode());
 
1611
        if (selectElement->canSelectAll()) {
 
1612
            selectElement->selectAll();
 
1613
            return;
 
1614
        }
 
1615
    }
 
1616
 
 
1617
    RefPtr<Node> root = 0;
 
1618
    Node* selectStartTarget = 0;
 
1619
    if (isContentEditable()) {
 
1620
        root = highestEditableRoot(m_selection.start());
 
1621
        if (Node* shadowRoot = m_selection.nonBoundaryShadowTreeRootNode())
 
1622
            selectStartTarget = shadowRoot->shadowAncestorNode();
 
1623
        else
 
1624
            selectStartTarget = root.get();
 
1625
    } else {
 
1626
        root = m_selection.nonBoundaryShadowTreeRootNode();
 
1627
        if (root)
 
1628
            selectStartTarget = root->shadowAncestorNode();
 
1629
        else {
 
1630
            root = document->documentElement();
 
1631
            selectStartTarget = document->body();
 
1632
        }
 
1633
    }
 
1634
    if (!root)
 
1635
        return;
 
1636
 
 
1637
    if (selectStartTarget && !selectStartTarget->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)))
 
1638
        return;
 
1639
 
 
1640
    VisibleSelection newSelection(VisibleSelection::selectionFromContentsOfNode(root.get()));
 
1641
 
 
1642
    if (shouldChangeSelection(newSelection))
 
1643
        setSelection(newSelection);
 
1644
 
 
1645
    selectFrameElementInParentIfFullySelected();
 
1646
    notifyRendererOfSelectionChange(UserTriggered);
 
1647
}
 
1648
 
 
1649
bool FrameSelection::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
 
1650
{
 
1651
    if (!range || !range->startContainer() || !range->endContainer())
 
1652
        return false;
 
1653
    ASSERT(range->startContainer()->document() == range->endContainer()->document());
 
1654
 
 
1655
    m_frame->document()->updateLayoutIgnorePendingStylesheets();
 
1656
 
 
1657
    // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
 
1658
    // they start at the beginning of the next line instead
 
1659
    ExceptionCode ec = 0;
 
1660
    bool collapsed = range->collapsed(ec);
 
1661
    if (ec)
 
1662
        return false;
 
1663
 
 
1664
    // FIXME: Can we provide extentAffinity?
 
1665
    VisiblePosition visibleStart(range->startPosition(), collapsed ? affinity : DOWNSTREAM);
 
1666
    VisiblePosition visibleEnd(range->endPosition(), SEL_DEFAULT_AFFINITY);
 
1667
    setSelection(VisibleSelection(visibleStart, visibleEnd), ClearTypingStyle | (closeTyping ? CloseTyping : 0));
 
1668
    return true;
 
1669
}
 
1670
 
 
1671
bool FrameSelection::isInPasswordField() const
 
1672
{
 
1673
    HTMLTextFormControlElement* textControl = enclosingTextFormControl(start());
 
1674
    return textControl && textControl->hasTagName(inputTag) && static_cast<HTMLInputElement*>(textControl)->isPasswordField();
 
1675
}
 
1676
 
 
1677
void FrameSelection::focusedOrActiveStateChanged()
 
1678
{
 
1679
    bool activeAndFocused = isFocusedAndActive();
 
1680
 
 
1681
    // Because RenderObject::selectionBackgroundColor() and
 
1682
    // RenderObject::selectionForegroundColor() check if the frame is active,
 
1683
    // we have to update places those colors were painted.
 
1684
    if (RenderView* view = m_frame->document()->renderView())
 
1685
        view->repaintRectangleInViewAndCompositedLayers(enclosingIntRect(bounds()));
 
1686
 
 
1687
    // Caret appears in the active frame.
 
1688
    if (activeAndFocused)
 
1689
        setSelectionFromNone();
 
1690
    setCaretVisibility(activeAndFocused ? Visible : Hidden);
 
1691
 
 
1692
    // Update for caps lock state
 
1693
    m_frame->eventHandler()->capsLockStateMayHaveChanged();
 
1694
 
 
1695
    // Because StyleResolver::checkOneSelector() and
 
1696
    // RenderTheme::isFocused() check if the frame is active, we have to
 
1697
    // update style and theme state that depended on those.
 
1698
    if (Node* node = m_frame->document()->focusedNode()) {
 
1699
        node->setNeedsStyleRecalc();
 
1700
        if (RenderObject* renderer = node->renderer())
 
1701
            if (renderer && renderer->style()->hasAppearance())
 
1702
                renderer->theme()->stateChanged(renderer, FocusState);
 
1703
    }
 
1704
 
 
1705
    // Secure keyboard entry is set by the active frame.
 
1706
    if (m_frame->document()->useSecureKeyboardEntryWhenActive())
 
1707
        setUseSecureKeyboardEntry(activeAndFocused);
 
1708
}
 
1709
 
 
1710
void FrameSelection::pageActivationChanged()
 
1711
{
 
1712
    focusedOrActiveStateChanged();
 
1713
}
 
1714
 
 
1715
void FrameSelection::updateSecureKeyboardEntryIfActive()
 
1716
{
 
1717
    if (m_frame->document() && isFocusedAndActive())
 
1718
        setUseSecureKeyboardEntry(m_frame->document()->useSecureKeyboardEntryWhenActive());
 
1719
}
 
1720
 
 
1721
void FrameSelection::setUseSecureKeyboardEntry(bool enable)
 
1722
{
 
1723
    if (enable)
 
1724
        enableSecureTextInput();
 
1725
    else
 
1726
        disableSecureTextInput();
 
1727
}
 
1728
 
 
1729
void FrameSelection::setFocused(bool flag)
 
1730
{
 
1731
    if (m_focused == flag)
 
1732
        return;
 
1733
    m_focused = flag;
 
1734
 
 
1735
    focusedOrActiveStateChanged();
 
1736
}
 
1737
 
 
1738
bool FrameSelection::isFocusedAndActive() const
 
1739
{
 
1740
    return m_focused && m_frame->page() && m_frame->page()->focusController()->isActive();
 
1741
}
 
1742
 
 
1743
inline static bool shouldStopBlinkingDueToTypingCommand(Frame* frame)
 
1744
{
 
1745
    return frame->editor()->lastEditCommand() && frame->editor()->lastEditCommand()->shouldStopCaretBlinking();
 
1746
}
 
1747
 
 
1748
void FrameSelection::updateAppearance()
 
1749
{
 
1750
#if ENABLE(TEXT_CARET)
 
1751
    bool caretRectChangedOrCleared = recomputeCaretRect();
 
1752
 
 
1753
    bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
 
1754
    bool shouldBlink = caretIsVisible() && isCaret() && (isContentEditable() || caretBrowsing);
 
1755
 
 
1756
    // If the caret moved, stop the blink timer so we can restart with a
 
1757
    // black caret in the new location.
 
1758
    if (caretRectChangedOrCleared || !shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame))
 
1759
        m_caretBlinkTimer.stop();
 
1760
 
 
1761
    // Start blinking with a black caret. Be sure not to restart if we're
 
1762
    // already blinking in the right location.
 
1763
    if (shouldBlink && !m_caretBlinkTimer.isActive()) {
 
1764
        if (double blinkInterval = m_frame->page()->theme()->caretBlinkInterval())
 
1765
            m_caretBlinkTimer.startRepeating(blinkInterval);
 
1766
 
 
1767
        if (!m_caretPaint) {
 
1768
            m_caretPaint = true;
 
1769
            invalidateCaretRect();
 
1770
        }
 
1771
    }
 
1772
#endif
 
1773
 
 
1774
    RenderView* view = m_frame->contentRenderer();
 
1775
    if (!view)
 
1776
        return;
 
1777
 
 
1778
    // Construct a new VisibleSolution, since m_selection is not necessarily valid, and the following steps
 
1779
    // assume a valid selection. See <https://bugs.webkit.org/show_bug.cgi?id=69563> and <rdar://problem/10232866>.
 
1780
    VisibleSelection selection(m_selection.visibleStart(), m_selection.visibleEnd());
 
1781
 
 
1782
    if (!selection.isRange()) {
 
1783
        view->clearSelection();
 
1784
        return;
 
1785
    }
 
1786
 
 
1787
    // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
 
1788
    // Example: foo <a>bar</a>.  Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.   If we pass [foo, 3]
 
1789
    // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
 
1790
    // and will fill the gap before 'bar'.
 
1791
    Position startPos = selection.start();
 
1792
    Position candidate = startPos.downstream();
 
1793
    if (candidate.isCandidate())
 
1794
        startPos = candidate;
 
1795
    Position endPos = selection.end();
 
1796
    candidate = endPos.upstream();
 
1797
    if (candidate.isCandidate())
 
1798
        endPos = candidate;
 
1799
 
 
1800
    // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
 
1801
    // because we don't yet notify the FrameSelection of text removal.
 
1802
    if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
 
1803
        RenderObject* startRenderer = startPos.deprecatedNode()->renderer();
 
1804
        RenderObject* endRenderer = endPos.deprecatedNode()->renderer();
 
1805
        view->setSelection(startRenderer, startPos.deprecatedEditingOffset(), endRenderer, endPos.deprecatedEditingOffset());
 
1806
    }
 
1807
}
 
1808
 
 
1809
void FrameSelection::setCaretVisibility(CaretVisibility visibility)
 
1810
{
 
1811
    if (caretVisibility() == visibility)
 
1812
        return;
 
1813
 
 
1814
#if ENABLE(TEXT_CARET)
 
1815
    m_frame->document()->updateLayoutIgnorePendingStylesheets();
 
1816
    if (m_caretPaint) {
 
1817
        m_caretPaint = false;
 
1818
        invalidateCaretRect();
 
1819
    }
 
1820
    CaretBase::setCaretVisibility(visibility);
 
1821
#else
 
1822
    m_frame->document()->updateStyleIfNeeded();
 
1823
#endif
 
1824
 
 
1825
    updateAppearance();
 
1826
}
 
1827
 
 
1828
void FrameSelection::caretBlinkTimerFired(Timer<FrameSelection>*)
 
1829
{
 
1830
#if ENABLE(TEXT_CARET)
 
1831
    ASSERT(caretIsVisible());
 
1832
    ASSERT(isCaret());
 
1833
    bool caretPaint = m_caretPaint;
 
1834
    if (isCaretBlinkingSuspended() && caretPaint)
 
1835
        return;
 
1836
    m_caretPaint = !caretPaint;
 
1837
    invalidateCaretRect();
 
1838
#endif
 
1839
}
 
1840
 
 
1841
void FrameSelection::notifyRendererOfSelectionChange(EUserTriggered userTriggered)
 
1842
{
 
1843
    m_frame->document()->updateStyleIfNeeded();
 
1844
 
 
1845
    if (!rootEditableElement())
 
1846
        return;
 
1847
 
 
1848
    if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(start()))
 
1849
        textControl->selectionChanged(userTriggered == UserTriggered);
 
1850
}
 
1851
 
 
1852
// Helper function that tells whether a particular node is an element that has an entire
 
1853
// Frame and FrameView, a <frame>, <iframe>, or <object>.
 
1854
static bool isFrameElement(const Node* n)
 
1855
{
 
1856
    if (!n)
 
1857
        return false;
 
1858
    RenderObject* renderer = n->renderer();
 
1859
    if (!renderer || !renderer->isWidget())
 
1860
        return false;
 
1861
    Widget* widget = toRenderWidget(renderer)->widget();
 
1862
    return widget && widget->isFrameView();
 
1863
}
 
1864
 
 
1865
void FrameSelection::setFocusedNodeIfNeeded()
 
1866
{
 
1867
    if (isNone() || !isFocused())
 
1868
        return;
 
1869
 
 
1870
    bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
 
1871
    if (caretBrowsing) {
 
1872
        if (Node* anchor = enclosingAnchorElement(base())) {
 
1873
            m_frame->page()->focusController()->setFocusedNode(anchor, m_frame);
 
1874
            return;
 
1875
        }
 
1876
    }
 
1877
 
 
1878
    if (Node* target = rootEditableElement()) {
 
1879
        // Walk up the DOM tree to search for a node to focus. 
 
1880
        while (target) {
 
1881
            // We don't want to set focus on a subframe when selecting in a parent frame,
 
1882
            // so add the !isFrameElement check here. There's probably a better way to make this
 
1883
            // work in the long term, but this is the safest fix at this time.
 
1884
            if (target && target->isMouseFocusable() && !isFrameElement(target)) {
 
1885
                m_frame->page()->focusController()->setFocusedNode(target, m_frame);
 
1886
                return;
 
1887
            }
 
1888
            target = target->parentOrHostNode(); 
 
1889
        }
 
1890
        m_frame->document()->setFocusedNode(0);
 
1891
    }
 
1892
 
 
1893
    if (caretBrowsing)
 
1894
        m_frame->page()->focusController()->setFocusedNode(0, m_frame);
 
1895
}
 
1896
 
 
1897
void DragCaretController::paintDragCaret(Frame* frame, GraphicsContext* p, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
 
1898
{
 
1899
#if ENABLE(TEXT_CARET)
 
1900
    if (m_position.deepEquivalent().deprecatedNode()->document()->frame() == frame)
 
1901
        paintCaret(m_position.deepEquivalent().deprecatedNode(), p, paintOffset, clipRect);
 
1902
#else
 
1903
    UNUSED_PARAM(frame);
 
1904
    UNUSED_PARAM(p);
 
1905
    UNUSED_PARAM(paintOffset);
 
1906
    UNUSED_PARAM(clipRect);
 
1907
#endif
 
1908
}
 
1909
 
 
1910
PassRefPtr<StylePropertySet> FrameSelection::copyTypingStyle() const
 
1911
{
 
1912
    if (!m_typingStyle || !m_typingStyle->style())
 
1913
        return 0;
 
1914
    return m_typingStyle->style()->copy();
 
1915
}
 
1916
 
 
1917
bool FrameSelection::shouldDeleteSelection(const VisibleSelection& selection) const
 
1918
{
 
1919
    return m_frame->editor()->client()->shouldDeleteRange(selection.toNormalizedRange().get());
 
1920
}
 
1921
 
 
1922
FloatRect FrameSelection::bounds(bool clipToVisibleContent) const
 
1923
{
 
1924
    RenderView* root = m_frame->contentRenderer();
 
1925
    FrameView* view = m_frame->view();
 
1926
    if (!root || !view)
 
1927
        return LayoutRect();
 
1928
 
 
1929
    LayoutRect selectionRect = root->selectionBounds(clipToVisibleContent);
 
1930
    return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect;
 
1931
}
 
1932
 
 
1933
void FrameSelection::getClippedVisibleTextRectangles(Vector<FloatRect>& rectangles) const
 
1934
{
 
1935
    RenderView* root = m_frame->contentRenderer();
 
1936
    if (!root)
 
1937
        return;
 
1938
 
 
1939
    FloatRect visibleContentRect = m_frame->view()->visibleContentRect();
 
1940
 
 
1941
    Vector<FloatQuad> quads;
 
1942
    toNormalizedRange()->textQuads(quads, true);
 
1943
 
 
1944
    size_t size = quads.size();
 
1945
    for (size_t i = 0; i < size; ++i) {
 
1946
        FloatRect intersectionRect = intersection(quads[i].enclosingBoundingBox(), visibleContentRect);
 
1947
        if (!intersectionRect.isEmpty())
 
1948
            rectangles.append(intersectionRect);
 
1949
    }
 
1950
}
 
1951
 
 
1952
// Scans logically forward from "start", including any child frames.
 
1953
static HTMLFormElement* scanForForm(Node* start)
 
1954
{
 
1955
    for (Node* node = start; node; node = node->traverseNextNode()) {
 
1956
        if (node->hasTagName(formTag))
 
1957
            return static_cast<HTMLFormElement*>(node);
 
1958
        if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
 
1959
            return static_cast<HTMLFormControlElement*>(node)->form();
 
1960
        if (node->hasTagName(frameTag) || node->hasTagName(iframeTag)) {
 
1961
            Node* childDocument = static_cast<HTMLFrameElementBase*>(node)->contentDocument();
 
1962
            if (HTMLFormElement* frameResult = scanForForm(childDocument))
 
1963
                return frameResult;
 
1964
        }
 
1965
    }
 
1966
    return 0;
 
1967
}
 
1968
 
 
1969
// We look for either the form containing the current focus, or for one immediately after it
 
1970
HTMLFormElement* FrameSelection::currentForm() const
 
1971
{
 
1972
    // Start looking either at the active (first responder) node, or where the selection is.
 
1973
    Node* start = m_frame->document()->focusedNode();
 
1974
    if (!start)
 
1975
        start = this->start().deprecatedNode();
 
1976
 
 
1977
    // Try walking up the node tree to find a form element.
 
1978
    Node* node;
 
1979
    for (node = start; node; node = node->parentNode()) {
 
1980
        if (node->hasTagName(formTag))
 
1981
            return static_cast<HTMLFormElement*>(node);
 
1982
        if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
 
1983
            return static_cast<HTMLFormControlElement*>(node)->form();
 
1984
    }
 
1985
 
 
1986
    // Try walking forward in the node tree to find a form element.
 
1987
    return scanForForm(start);
 
1988
}
 
1989
 
 
1990
void FrameSelection::revealSelection(const ScrollAlignment& alignment, RevealExtentOption revealExtentOption)
 
1991
{
 
1992
    LayoutRect rect;
 
1993
 
 
1994
    switch (selectionType()) {
 
1995
    case VisibleSelection::NoSelection:
 
1996
        return;
 
1997
    case VisibleSelection::CaretSelection:
 
1998
        rect = absoluteCaretBounds();
 
1999
        break;
 
2000
    case VisibleSelection::RangeSelection:
 
2001
        rect = revealExtentOption == RevealExtent ? VisiblePosition(extent()).absoluteCaretBounds() : enclosingIntRect(bounds(false));
 
2002
        break;
 
2003
    }
 
2004
 
 
2005
    Position start = this->start();
 
2006
    ASSERT(start.deprecatedNode());
 
2007
    if (start.deprecatedNode() && start.deprecatedNode()->renderer()) {
 
2008
        // FIXME: This code only handles scrolling the startContainer's layer, but
 
2009
        // the selection rect could intersect more than just that.
 
2010
        // See <rdar://problem/4799899>.
 
2011
        if (start.deprecatedNode()->renderer()->scrollRectToVisible(rect, alignment, alignment))
 
2012
            updateAppearance();
 
2013
    }
 
2014
}
 
2015
 
 
2016
void FrameSelection::setSelectionFromNone()
 
2017
{
 
2018
    // Put a caret inside the body if the entire frame is editable (either the
 
2019
    // entire WebView is editable or designMode is on for this document).
 
2020
 
 
2021
    Document* document = m_frame->document();
 
2022
    bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
 
2023
    if (!isNone() || !(document->rendererIsEditable() || caretBrowsing))
 
2024
        return;
 
2025
 
 
2026
    Node* node = document->documentElement();
 
2027
    while (node && !node->hasTagName(bodyTag))
 
2028
        node = node->traverseNextNode();
 
2029
    if (node)
 
2030
        setSelection(VisibleSelection(firstPositionInOrBeforeNode(node), DOWNSTREAM));
 
2031
}
 
2032
 
 
2033
bool FrameSelection::shouldChangeSelection(const VisibleSelection& newSelection) const
 
2034
{
 
2035
    return m_frame->editor()->shouldChangeSelection(selection(), newSelection, newSelection.affinity(), false);
 
2036
}
 
2037
 
 
2038
bool FrameSelection::dispatchSelectStart()
 
2039
{
 
2040
    Node* selectStartTarget = m_selection.extent().containerNode();
 
2041
    if (!selectStartTarget)
 
2042
        return true;
 
2043
 
 
2044
    return selectStartTarget->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
 
2045
}
 
2046
 
 
2047
inline bool FrameSelection::visualWordMovementEnabled() const
 
2048
{
 
2049
    Settings* settings = m_frame ? m_frame->settings() : 0;
 
2050
    return settings && settings->visualWordMovementEnabled();
 
2051
}
 
2052
 
 
2053
#ifndef NDEBUG
 
2054
 
 
2055
void FrameSelection::formatForDebugger(char* buffer, unsigned length) const
 
2056
{
 
2057
    m_selection.formatForDebugger(buffer, length);
 
2058
}
 
2059
 
 
2060
void FrameSelection::showTreeForThis() const
 
2061
{
 
2062
    m_selection.showTreeForThis();
 
2063
}
 
2064
 
 
2065
#endif
 
2066
 
 
2067
}
 
2068
 
 
2069
#ifndef NDEBUG
 
2070
 
 
2071
void showTree(const WebCore::FrameSelection& sel)
 
2072
{
 
2073
    sel.showTreeForThis();
 
2074
}
 
2075
 
 
2076
void showTree(const WebCore::FrameSelection* sel)
 
2077
{
 
2078
    if (sel)
 
2079
        sel->showTreeForThis();
 
2080
}
 
2081
 
 
2082
#endif