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

« back to all changes in this revision

Viewing changes to Source/WebCore/editing/VisibleSelection.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, 2005, 2006 Apple Computer, 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 "VisibleSelection.h"
 
28
 
 
29
#include "Document.h"
 
30
#include "Element.h"
 
31
#include "htmlediting.h"
 
32
#include "TextIterator.h"
 
33
#include "VisiblePosition.h"
 
34
#include "visible_units.h"
 
35
#include "Range.h"
 
36
#include <stdio.h>
 
37
#include <wtf/Assertions.h>
 
38
#include <wtf/text/CString.h>
 
39
#include <wtf/text/StringBuilder.h>
 
40
#include <wtf/unicode/CharacterNames.h>
 
41
 
 
42
namespace WebCore {
 
43
 
 
44
VisibleSelection::VisibleSelection()
 
45
    : m_affinity(DOWNSTREAM)
 
46
    , m_selectionType(NoSelection)
 
47
    , m_baseIsFirst(true)
 
48
    , m_isDirectional(false)
 
49
{
 
50
}
 
51
 
 
52
VisibleSelection::VisibleSelection(const Position& pos, EAffinity affinity, bool isDirectional)
 
53
    : m_base(pos)
 
54
    , m_extent(pos)
 
55
    , m_affinity(affinity)
 
56
    , m_isDirectional(isDirectional)
 
57
{
 
58
    validate();
 
59
}
 
60
 
 
61
VisibleSelection::VisibleSelection(const Position& base, const Position& extent, EAffinity affinity, bool isDirectional)
 
62
    : m_base(base)
 
63
    , m_extent(extent)
 
64
    , m_affinity(affinity)
 
65
    , m_isDirectional(isDirectional)
 
66
{
 
67
    validate();
 
68
}
 
69
 
 
70
VisibleSelection::VisibleSelection(const VisiblePosition& pos, bool isDirectional)
 
71
    : m_base(pos.deepEquivalent())
 
72
    , m_extent(pos.deepEquivalent())
 
73
    , m_affinity(pos.affinity())
 
74
    , m_isDirectional(isDirectional)
 
75
{
 
76
    validate();
 
77
}
 
78
 
 
79
VisibleSelection::VisibleSelection(const VisiblePosition& base, const VisiblePosition& extent, bool isDirectional)
 
80
    : m_base(base.deepEquivalent())
 
81
    , m_extent(extent.deepEquivalent())
 
82
    , m_affinity(base.affinity())
 
83
    , m_isDirectional(isDirectional)
 
84
{
 
85
    validate();
 
86
}
 
87
 
 
88
VisibleSelection::VisibleSelection(const Range* range, EAffinity affinity, bool isDirectional)
 
89
    : m_base(range->startPosition())
 
90
    , m_extent(range->endPosition())
 
91
    , m_affinity(affinity)
 
92
    , m_isDirectional(isDirectional)
 
93
{
 
94
    validate();
 
95
}
 
96
 
 
97
VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node)
 
98
{
 
99
    ASSERT(!editingIgnoresContent(node));
 
100
    return VisibleSelection(firstPositionInNode(node), lastPositionInNode(node), DOWNSTREAM);
 
101
}
 
102
 
 
103
void VisibleSelection::setBase(const Position& position)
 
104
{
 
105
    m_base = position;
 
106
    validate();
 
107
}
 
108
 
 
109
void VisibleSelection::setBase(const VisiblePosition& visiblePosition)
 
110
{
 
111
    m_base = visiblePosition.deepEquivalent();
 
112
    validate();
 
113
}
 
114
 
 
115
void VisibleSelection::setExtent(const Position& position)
 
116
{
 
117
    m_extent = position;
 
118
    validate();
 
119
}
 
120
 
 
121
void VisibleSelection::setExtent(const VisiblePosition& visiblePosition)
 
122
{
 
123
    m_extent = visiblePosition.deepEquivalent();
 
124
    validate();
 
125
}
 
126
 
 
127
PassRefPtr<Range> VisibleSelection::firstRange() const
 
128
{
 
129
    if (isNone())
 
130
        return 0;
 
131
    Position start = m_start.parentAnchoredEquivalent();
 
132
    Position end = m_end.parentAnchoredEquivalent();
 
133
    return Range::create(start.anchorNode()->document(), start, end);
 
134
}
 
135
 
 
136
PassRefPtr<Range> VisibleSelection::toNormalizedRange() const
 
137
{
 
138
    if (isNone())
 
139
        return 0;
 
140
 
 
141
    // Make sure we have an updated layout since this function is called
 
142
    // in the course of running edit commands which modify the DOM.
 
143
    // Failing to call this can result in equivalentXXXPosition calls returning
 
144
    // incorrect results.
 
145
    m_start.anchorNode()->document()->updateLayout();
 
146
 
 
147
    // Check again, because updating layout can clear the selection.
 
148
    if (isNone())
 
149
        return 0;
 
150
 
 
151
    Position s, e;
 
152
    if (isCaret()) {
 
153
        // If the selection is a caret, move the range start upstream. This helps us match
 
154
        // the conventions of text editors tested, which make style determinations based
 
155
        // on the character before the caret, if any. 
 
156
        s = m_start.upstream().parentAnchoredEquivalent();
 
157
        e = s;
 
158
    } else {
 
159
        // If the selection is a range, select the minimum range that encompasses the selection.
 
160
        // Again, this is to match the conventions of text editors tested, which make style 
 
161
        // determinations based on the first character of the selection. 
 
162
        // For instance, this operation helps to make sure that the "X" selected below is the 
 
163
        // only thing selected. The range should not be allowed to "leak" out to the end of the 
 
164
        // previous text node, or to the beginning of the next text node, each of which has a 
 
165
        // different style.
 
166
        // 
 
167
        // On a treasure map, <b>X</b> marks the spot.
 
168
        //                       ^ selected
 
169
        //
 
170
        ASSERT(isRange());
 
171
        s = m_start.downstream();
 
172
        e = m_end.upstream();
 
173
        if (comparePositions(s, e) > 0) {
 
174
            // Make sure the start is before the end.
 
175
            // The end can wind up before the start if collapsed whitespace is the only thing selected.
 
176
            Position tmp = s;
 
177
            s = e;
 
178
            e = tmp;
 
179
        }
 
180
        s = s.parentAnchoredEquivalent();
 
181
        e = e.parentAnchoredEquivalent();
 
182
    }
 
183
 
 
184
    if (!s.containerNode() || !e.containerNode())
 
185
        return 0;
 
186
 
 
187
    // VisibleSelections are supposed to always be valid.  This constructor will ASSERT
 
188
    // if a valid range could not be created, which is fine for this callsite.
 
189
    return Range::create(s.anchorNode()->document(), s, e);
 
190
}
 
191
 
 
192
bool VisibleSelection::expandUsingGranularity(TextGranularity granularity)
 
193
{
 
194
    if (isNone())
 
195
        return false;
 
196
 
 
197
    validate(granularity);
 
198
    return true;
 
199
}
 
200
 
 
201
static PassRefPtr<Range> makeSearchRange(const Position& pos)
 
202
{
 
203
    Node* n = pos.deprecatedNode();
 
204
    if (!n)
 
205
        return 0;
 
206
    Document* d = n->document();
 
207
    Node* de = d->documentElement();
 
208
    if (!de)
 
209
        return 0;
 
210
    Node* boundary = n->enclosingBlockFlowElement();
 
211
    if (!boundary)
 
212
        return 0;
 
213
 
 
214
    RefPtr<Range> searchRange(Range::create(d));
 
215
    ExceptionCode ec = 0;
 
216
 
 
217
    Position start(pos.parentAnchoredEquivalent());
 
218
    searchRange->selectNodeContents(boundary, ec);
 
219
    searchRange->setStart(start.containerNode(), start.offsetInContainerNode(), ec);
 
220
 
 
221
    ASSERT(!ec);
 
222
    if (ec)
 
223
        return 0;
 
224
 
 
225
    return searchRange.release();
 
226
}
 
227
 
 
228
bool VisibleSelection::isAll(EditingBoundaryCrossingRule rule) const
 
229
{
 
230
    return !nonBoundaryShadowTreeRootNode() && visibleStart().previous(rule).isNull() && visibleEnd().next(rule).isNull();
 
231
}
 
232
 
 
233
void VisibleSelection::appendTrailingWhitespace()
 
234
{
 
235
    RefPtr<Range> searchRange = makeSearchRange(m_end);
 
236
    if (!searchRange)
 
237
        return;
 
238
 
 
239
    CharacterIterator charIt(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
 
240
 
 
241
    for (; charIt.length(); charIt.advance(1)) {
 
242
        UChar c = charIt.characters()[0];
 
243
        if ((!isSpaceOrNewline(c) && c != noBreakSpace) || c == '\n')
 
244
            break;
 
245
        m_end = charIt.range()->endPosition();
 
246
    }
 
247
}
 
248
 
 
249
void VisibleSelection::setBaseAndExtentToDeepEquivalents()
 
250
{
 
251
    // Move the selection to rendered positions, if possible.
 
252
    bool baseAndExtentEqual = m_base == m_extent;
 
253
    if (m_base.isNotNull()) {
 
254
        m_base = VisiblePosition(m_base, m_affinity).deepEquivalent();
 
255
        if (baseAndExtentEqual)
 
256
            m_extent = m_base;
 
257
    }
 
258
    if (m_extent.isNotNull() && !baseAndExtentEqual)
 
259
        m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
 
260
 
 
261
    // Make sure we do not have a dangling base or extent.
 
262
    if (m_base.isNull() && m_extent.isNull())
 
263
        m_baseIsFirst = true;
 
264
    else if (m_base.isNull()) {
 
265
        m_base = m_extent;
 
266
        m_baseIsFirst = true;
 
267
    } else if (m_extent.isNull()) {
 
268
        m_extent = m_base;
 
269
        m_baseIsFirst = true;
 
270
    } else
 
271
        m_baseIsFirst = comparePositions(m_base, m_extent) <= 0;
 
272
}
 
273
 
 
274
void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity granularity)
 
275
{
 
276
    if (m_baseIsFirst) {
 
277
        m_start = m_base;
 
278
        m_end = m_extent;
 
279
    } else {
 
280
        m_start = m_extent;
 
281
        m_end = m_base;
 
282
    }
 
283
 
 
284
    switch (granularity) {
 
285
        case CharacterGranularity:
 
286
            // Don't do any expansion.
 
287
            break;
 
288
        case WordGranularity: {
 
289
            // General case: Select the word the caret is positioned inside of, or at the start of (RightWordIfOnBoundary).
 
290
            // Edge case: If the caret is after the last word in a soft-wrapped line or the last word in
 
291
            // the document, select that last word (LeftWordIfOnBoundary).
 
292
            // Edge case: If the caret is after the last word in a paragraph, select from the the end of the
 
293
            // last word to the line break (also RightWordIfOnBoundary);
 
294
            VisiblePosition start = VisiblePosition(m_start, m_affinity);
 
295
            VisiblePosition originalEnd(m_end, m_affinity);
 
296
            EWordSide side = RightWordIfOnBoundary;
 
297
            if (isEndOfEditableOrNonEditableContent(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start)))
 
298
                side = LeftWordIfOnBoundary;
 
299
            m_start = startOfWord(start, side).deepEquivalent();
 
300
            side = RightWordIfOnBoundary;
 
301
            if (isEndOfEditableOrNonEditableContent(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd)))
 
302
                side = LeftWordIfOnBoundary;
 
303
                
 
304
            VisiblePosition wordEnd(endOfWord(originalEnd, side));
 
305
            VisiblePosition end(wordEnd);
 
306
            
 
307
            if (isEndOfParagraph(originalEnd) && !isEmptyTableCell(m_start.deprecatedNode())) {
 
308
                // Select the paragraph break (the space from the end of a paragraph to the start of 
 
309
                // the next one) to match TextEdit.
 
310
                end = wordEnd.next();
 
311
                
 
312
                if (Node* table = isFirstPositionAfterTable(end)) {
 
313
                    // The paragraph break after the last paragraph in the last cell of a block table ends
 
314
                    // at the start of the paragraph after the table.
 
315
                    if (isBlock(table))
 
316
                        end = end.next(CannotCrossEditingBoundary);
 
317
                    else
 
318
                        end = wordEnd;
 
319
                }
 
320
                
 
321
                if (end.isNull())
 
322
                    end = wordEnd;
 
323
                    
 
324
            }
 
325
                
 
326
            m_end = end.deepEquivalent();
 
327
            break;
 
328
        }
 
329
        case SentenceGranularity: {
 
330
            m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
 
331
            m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
 
332
            break;
 
333
        }
 
334
        case LineGranularity: {
 
335
            m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
 
336
            VisiblePosition end = endOfLine(VisiblePosition(m_end, m_affinity));
 
337
            // If the end of this line is at the end of a paragraph, include the space 
 
338
            // after the end of the line in the selection.
 
339
            if (isEndOfParagraph(end)) {
 
340
                VisiblePosition next = end.next();
 
341
                if (next.isNotNull())
 
342
                    end = next;
 
343
            }
 
344
            m_end = end.deepEquivalent();
 
345
            break;
 
346
        }
 
347
        case LineBoundary:
 
348
            m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
 
349
            m_end = endOfLine(VisiblePosition(m_end, m_affinity)).deepEquivalent();
 
350
            break;
 
351
        case ParagraphGranularity: {
 
352
            VisiblePosition pos(m_start, m_affinity);
 
353
            if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos))
 
354
                pos = pos.previous();
 
355
            m_start = startOfParagraph(pos).deepEquivalent();
 
356
            VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition(m_end, m_affinity));
 
357
            
 
358
            // Include the "paragraph break" (the space from the end of this paragraph to the start
 
359
            // of the next one) in the selection.
 
360
            VisiblePosition end(visibleParagraphEnd.next());
 
361
             
 
362
            if (Node* table = isFirstPositionAfterTable(end)) {
 
363
                // The paragraph break after the last paragraph in the last cell of a block table ends
 
364
                // at the start of the paragraph after the table, not at the position just after the table.
 
365
                if (isBlock(table))
 
366
                    end = end.next(CannotCrossEditingBoundary);
 
367
                // There is no parargraph break after the last paragraph in the last cell of an inline table.
 
368
                else
 
369
                    end = visibleParagraphEnd;
 
370
            }
 
371
             
 
372
            if (end.isNull())
 
373
                end = visibleParagraphEnd;
 
374
                
 
375
            m_end = end.deepEquivalent();
 
376
            break;
 
377
        }
 
378
        case DocumentBoundary:
 
379
            m_start = startOfDocument(VisiblePosition(m_start, m_affinity)).deepEquivalent();
 
380
            m_end = endOfDocument(VisiblePosition(m_end, m_affinity)).deepEquivalent();
 
381
            break;
 
382
        case ParagraphBoundary:
 
383
            m_start = startOfParagraph(VisiblePosition(m_start, m_affinity)).deepEquivalent();
 
384
            m_end = endOfParagraph(VisiblePosition(m_end, m_affinity)).deepEquivalent();
 
385
            break;
 
386
        case SentenceBoundary:
 
387
            m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
 
388
            m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
 
389
            break;
 
390
    }
 
391
    
 
392
    // Make sure we do not have a dangling start or end.
 
393
    if (m_start.isNull())
 
394
        m_start = m_end;
 
395
    if (m_end.isNull())
 
396
        m_end = m_start;
 
397
}
 
398
 
 
399
void VisibleSelection::updateSelectionType()
 
400
{
 
401
    if (m_start.isNull()) {
 
402
        ASSERT(m_end.isNull());
 
403
        m_selectionType = NoSelection;
 
404
    } else if (m_start == m_end || m_start.upstream() == m_end.upstream()) {
 
405
        m_selectionType = CaretSelection;
 
406
    } else
 
407
        m_selectionType = RangeSelection;
 
408
 
 
409
    // Affinity only makes sense for a caret
 
410
    if (m_selectionType != CaretSelection)
 
411
        m_affinity = DOWNSTREAM;
 
412
}
 
413
 
 
414
void VisibleSelection::validate(TextGranularity granularity)
 
415
{
 
416
    setBaseAndExtentToDeepEquivalents();
 
417
    setStartAndEndFromBaseAndExtentRespectingGranularity(granularity);
 
418
    adjustSelectionToAvoidCrossingShadowBoundaries();
 
419
    adjustSelectionToAvoidCrossingEditingBoundaries();
 
420
    updateSelectionType();
 
421
 
 
422
    if (selectionType() == RangeSelection) {
 
423
        // "Constrain" the selection to be the smallest equivalent range of nodes.
 
424
        // This is a somewhat arbitrary choice, but experience shows that it is
 
425
        // useful to make to make the selection "canonical" (if only for
 
426
        // purposes of comparing selections). This is an ideal point of the code
 
427
        // to do this operation, since all selection changes that result in a RANGE 
 
428
        // come through here before anyone uses it.
 
429
        // FIXME: Canonicalizing is good, but haven't we already done it (when we
 
430
        // set these two positions to VisiblePosition deepEquivalent()s above)?
 
431
        m_start = m_start.downstream();
 
432
        m_end = m_end.upstream();
 
433
 
 
434
        // FIXME: Position::downstream() or Position::upStream() might violate editing boundaries
 
435
        // if an anchor node has a Shadow DOM. So we adjust selection to avoid crossing editing
 
436
        // boundaries again. See https://bugs.webkit.org/show_bug.cgi?id=87463
 
437
        adjustSelectionToAvoidCrossingEditingBoundaries();
 
438
    }
 
439
}
 
440
 
 
441
// FIXME: This function breaks the invariant of this class.
 
442
// But because we use VisibleSelection to store values in editing commands for use when
 
443
// undoing the command, we need to be able to create a selection that while currently
 
444
// invalid, will be valid once the changes are undone. This is a design problem.
 
445
// To fix it we either need to change the invariants of VisibleSelection or create a new
 
446
// class for editing to use that can manipulate selections that are not currently valid.
 
447
void VisibleSelection::setWithoutValidation(const Position& base, const Position& extent)
 
448
{
 
449
    ASSERT(!base.isNull());
 
450
    ASSERT(!extent.isNull());
 
451
    ASSERT(m_affinity == DOWNSTREAM);
 
452
    m_base = base;
 
453
    m_extent = extent;
 
454
    m_baseIsFirst = comparePositions(base, extent) <= 0;
 
455
    if (m_baseIsFirst) {
 
456
        m_start = base;
 
457
        m_end = extent;
 
458
    } else {
 
459
        m_start = extent;
 
460
        m_end = base;
 
461
    }
 
462
    m_selectionType = base == extent ? CaretSelection : RangeSelection;
 
463
}
 
464
 
 
465
static Position adjustPositionForEnd(const Position& currentPosition, Node* startContainerNode)
 
466
{
 
467
    TreeScope* treeScope = startContainerNode->treeScope();
 
468
 
 
469
    ASSERT(currentPosition.containerNode()->treeScope() != treeScope);
 
470
 
 
471
    if (Node* ancestor = treeScope->ancestorInThisScope(currentPosition.containerNode())) {
 
472
        if (ancestor->contains(startContainerNode))
 
473
            return positionAfterNode(ancestor);
 
474
        return positionBeforeNode(ancestor);
 
475
    }
 
476
 
 
477
    if (Node* lastChild = treeScope->rootNode()->lastChild())
 
478
        return positionAfterNode(lastChild);
 
479
 
 
480
    return Position();
 
481
}
 
482
 
 
483
static Position adjustPositionForStart(const Position& currentPosition, Node* endContainerNode)
 
484
{
 
485
    TreeScope* treeScope = endContainerNode->treeScope();
 
486
 
 
487
    ASSERT(currentPosition.containerNode()->treeScope() != treeScope);
 
488
    
 
489
    if (Node* ancestor = treeScope->ancestorInThisScope(currentPosition.containerNode())) {
 
490
        if (ancestor->contains(endContainerNode))
 
491
            return positionBeforeNode(ancestor);
 
492
        return positionAfterNode(ancestor);
 
493
    }
 
494
 
 
495
    if (Node* firstChild = treeScope->rootNode()->firstChild())
 
496
        return positionBeforeNode(firstChild);
 
497
 
 
498
    return Position();
 
499
}
 
500
 
 
501
void VisibleSelection::adjustSelectionToAvoidCrossingShadowBoundaries()
 
502
{
 
503
    if (m_base.isNull() || m_start.isNull() || m_end.isNull())
 
504
        return;
 
505
 
 
506
    if (m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope())
 
507
        return;
 
508
 
 
509
    if (m_baseIsFirst) {
 
510
        m_extent = adjustPositionForEnd(m_end, m_start.containerNode());
 
511
        m_end = m_extent;
 
512
    } else {
 
513
        m_extent = adjustPositionForStart(m_start, m_end.containerNode());
 
514
        m_start = m_extent;
 
515
    }
 
516
 
 
517
    ASSERT(m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope());
 
518
}
 
519
 
 
520
void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
 
521
{
 
522
    if (m_base.isNull() || m_start.isNull() || m_end.isNull())
 
523
        return;
 
524
 
 
525
    Node* baseRoot = highestEditableRoot(m_base);
 
526
    Node* startRoot = highestEditableRoot(m_start);
 
527
    Node* endRoot = highestEditableRoot(m_end);
 
528
    
 
529
    Node* baseEditableAncestor = lowestEditableAncestor(m_base.containerNode());
 
530
    
 
531
    // The base, start and end are all in the same region.  No adjustment necessary.
 
532
    if (baseRoot == startRoot && baseRoot == endRoot)
 
533
        return;
 
534
    
 
535
    // The selection is based in editable content.
 
536
    if (baseRoot) {
 
537
        // If the start is outside the base's editable root, cap it at the start of that root.
 
538
        // If the start is in non-editable content that is inside the base's editable root, put it
 
539
        // at the first editable position after start inside the base's editable root.
 
540
        if (startRoot != baseRoot) {
 
541
            VisiblePosition first = firstEditablePositionAfterPositionInRoot(m_start, baseRoot);
 
542
            m_start = first.deepEquivalent();
 
543
            if (m_start.isNull()) {
 
544
                ASSERT_NOT_REACHED();
 
545
                m_start = m_end;
 
546
            }
 
547
        }
 
548
        // If the end is outside the base's editable root, cap it at the end of that root.
 
549
        // If the end is in non-editable content that is inside the base's root, put it
 
550
        // at the last editable position before the end inside the base's root.
 
551
        if (endRoot != baseRoot) {
 
552
            VisiblePosition last = lastEditablePositionBeforePositionInRoot(m_end, baseRoot);
 
553
            m_end = last.deepEquivalent();
 
554
            if (m_end.isNull())
 
555
                m_end = m_start;
 
556
        }
 
557
    // The selection is based in non-editable content.
 
558
    } else {
 
559
        // FIXME: Non-editable pieces inside editable content should be atomic, in the same way that editable
 
560
        // pieces in non-editable content are atomic.
 
561
    
 
562
        // The selection ends in editable content or non-editable content inside a different editable ancestor, 
 
563
        // move backward until non-editable content inside the same lowest editable ancestor is reached.
 
564
        Node* endEditableAncestor = lowestEditableAncestor(m_end.containerNode());
 
565
        if (endRoot || endEditableAncestor != baseEditableAncestor) {
 
566
            
 
567
            Position p = previousVisuallyDistinctCandidate(m_end);
 
568
            Node* shadowAncestor = endRoot ? endRoot->shadowHost() : 0;
 
569
            if (p.isNull() && shadowAncestor)
 
570
                p = positionAfterNode(shadowAncestor);
 
571
            while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) {
 
572
                Node* root = editableRootForPosition(p);
 
573
                shadowAncestor = root ? root->shadowHost() : 0;
 
574
                p = isAtomicNode(p.containerNode()) ? positionInParentBeforeNode(p.containerNode()) : previousVisuallyDistinctCandidate(p);
 
575
                if (p.isNull() && shadowAncestor)
 
576
                    p = positionAfterNode(shadowAncestor);
 
577
            }
 
578
            VisiblePosition previous(p);
 
579
 
 
580
            if (previous.isNull()) {
 
581
                // The selection crosses an Editing boundary.  This is a
 
582
                // programmer error in the editing code.  Happy debugging!
 
583
                ASSERT_NOT_REACHED();
 
584
                m_base = Position();
 
585
                m_extent = Position();
 
586
                validate();
 
587
                return;
 
588
            }
 
589
            m_end = previous.deepEquivalent();
 
590
        }
 
591
 
 
592
        // The selection starts in editable content or non-editable content inside a different editable ancestor, 
 
593
        // move forward until non-editable content inside the same lowest editable ancestor is reached.
 
594
        Node* startEditableAncestor = lowestEditableAncestor(m_start.containerNode());      
 
595
        if (startRoot || startEditableAncestor != baseEditableAncestor) {
 
596
            Position p = nextVisuallyDistinctCandidate(m_start);
 
597
            Node* shadowAncestor = startRoot ? startRoot->shadowHost() : 0;
 
598
            if (p.isNull() && shadowAncestor)
 
599
                p = positionBeforeNode(shadowAncestor);
 
600
            while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) {
 
601
                Node* root = editableRootForPosition(p);
 
602
                shadowAncestor = root ? root->shadowHost() : 0;
 
603
                p = isAtomicNode(p.containerNode()) ? positionInParentAfterNode(p.containerNode()) : nextVisuallyDistinctCandidate(p);
 
604
                if (p.isNull() && shadowAncestor)
 
605
                    p = positionBeforeNode(shadowAncestor);
 
606
            }
 
607
            VisiblePosition next(p);
 
608
            
 
609
            if (next.isNull()) {
 
610
                // The selection crosses an Editing boundary.  This is a
 
611
                // programmer error in the editing code.  Happy debugging!
 
612
                ASSERT_NOT_REACHED();
 
613
                m_base = Position();
 
614
                m_extent = Position();
 
615
                validate();
 
616
                return;
 
617
            }
 
618
            m_start = next.deepEquivalent();
 
619
        }
 
620
    }
 
621
    
 
622
    // Correct the extent if necessary.
 
623
    if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode()))
 
624
        m_extent = m_baseIsFirst ? m_end : m_start;
 
625
}
 
626
 
 
627
bool VisibleSelection::isContentEditable() const
 
628
{
 
629
    return isEditablePosition(start());
 
630
}
 
631
 
 
632
bool VisibleSelection::rendererIsEditable() const
 
633
{
 
634
    return isEditablePosition(start(), ContentIsEditable, DoNotUpdateStyle);
 
635
}
 
636
 
 
637
bool VisibleSelection::isContentRichlyEditable() const
 
638
{
 
639
    return isRichlyEditablePosition(start());
 
640
}
 
641
 
 
642
Element* VisibleSelection::rootEditableElement() const
 
643
{
 
644
    return editableRootForPosition(start());
 
645
}
 
646
 
 
647
Node* VisibleSelection::nonBoundaryShadowTreeRootNode() const
 
648
{
 
649
    return start().deprecatedNode() ? start().deprecatedNode()->nonBoundaryShadowTreeRootNode() : 0;
 
650
}
 
651
 
 
652
#ifndef NDEBUG
 
653
 
 
654
void VisibleSelection::debugPosition() const
 
655
{
 
656
    fprintf(stderr, "VisibleSelection ===============\n");
 
657
 
 
658
    if (!m_start.anchorNode())
 
659
        fputs("pos:   null", stderr);
 
660
    else if (m_start == m_end) {
 
661
        fprintf(stderr, "pos:   %s ", m_start.anchorNode()->nodeName().utf8().data());
 
662
        m_start.showAnchorTypeAndOffset();
 
663
    } else {
 
664
        fprintf(stderr, "start: %s ", m_start.anchorNode()->nodeName().utf8().data());
 
665
        m_start.showAnchorTypeAndOffset();
 
666
        fprintf(stderr, "end:   %s ", m_end.anchorNode()->nodeName().utf8().data());
 
667
        m_end.showAnchorTypeAndOffset();
 
668
    }
 
669
 
 
670
    fprintf(stderr, "================================\n");
 
671
}
 
672
 
 
673
void VisibleSelection::formatForDebugger(char* buffer, unsigned length) const
 
674
{
 
675
    StringBuilder result;
 
676
    String s;
 
677
 
 
678
    if (isNone()) {
 
679
        result.appendLiteral("<none>");
 
680
    } else {
 
681
        const int FormatBufferSize = 1024;
 
682
        char s[FormatBufferSize];
 
683
        result.appendLiteral("from ");
 
684
        start().formatForDebugger(s, FormatBufferSize);
 
685
        result.append(s);
 
686
        result.appendLiteral(" to ");
 
687
        end().formatForDebugger(s, FormatBufferSize);
 
688
        result.append(s);
 
689
    }
 
690
 
 
691
    strncpy(buffer, result.toString().utf8().data(), length - 1);
 
692
}
 
693
 
 
694
void VisibleSelection::showTreeForThis() const
 
695
{
 
696
    if (start().anchorNode()) {
 
697
        start().anchorNode()->showTreeAndMark(start().anchorNode(), "S", end().anchorNode(), "E");
 
698
        fputs("start: ", stderr);
 
699
        start().showAnchorTypeAndOffset();
 
700
        fputs("end: ", stderr);
 
701
        end().showAnchorTypeAndOffset();
 
702
    }
 
703
}
 
704
 
 
705
#endif
 
706
 
 
707
} // namespace WebCore
 
708
 
 
709
#ifndef NDEBUG
 
710
 
 
711
void showTree(const WebCore::VisibleSelection& sel)
 
712
{
 
713
    sel.showTreeForThis();
 
714
}
 
715
 
 
716
void showTree(const WebCore::VisibleSelection* sel)
 
717
{
 
718
    if (sel)
 
719
        sel->showTreeForThis();
 
720
}
 
721
 
 
722
#endif