DOMSelection.cpp 15.5 KB
Newer Older
weinig's avatar
weinig committed
1
/*
2
 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3
 * Copyright (C) 2012 Google Inc. All rights reserved.
weinig's avatar
weinig committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer. 
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution. 
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#include "config.h"
#include "DOMSelection.h"

34
#include "Document.h"
ap@webkit.org's avatar
ap@webkit.org committed
35
#include "ExceptionCode.h"
weinig's avatar
weinig committed
36
#include "Frame.h"
37
#include "FrameSelection.h"
weinig's avatar
weinig committed
38
#include "Node.h"
weinig's avatar
weinig committed
39
#include "Range.h"
ap@webkit.org's avatar
ap@webkit.org committed
40
#include "TextIterator.h"
41
#include "TreeScope.h"
42
#include "htmlediting.h"
43
#include <wtf/text/WTFString.h>
weinig's avatar
weinig committed
44 45 46

namespace WebCore {

47 48
static Node* selectionShadowAncestor(Frame* frame)
{
49
    Node* node = frame->selection().selection().base().anchorNode();
50 51
    if (!node)
        return 0;
52 53

    if (!node->isInShadowTree())
54
        return 0;
55

56
    return frame->document()->ancestorInThisScope(node);
57 58
}

59
DOMSelection::DOMSelection(const TreeScope* treeScope)
60
    : DOMWindowProperty(treeScope->rootNode()->document().frame())
61
    , m_treeScope(treeScope)
weinig's avatar
weinig committed
62 63 64
{
}

65 66 67 68 69
void DOMSelection::clearTreeScope()
{
    m_treeScope = 0;
}

eric@webkit.org's avatar
eric@webkit.org committed
70
const VisibleSelection& DOMSelection::visibleSelection() const
weinig's avatar
weinig committed
71
{
eric@webkit.org's avatar
eric@webkit.org committed
72
    ASSERT(m_frame);
73
    return m_frame->selection().selection();
eric@webkit.org's avatar
eric@webkit.org committed
74
}
ap@webkit.org's avatar
ap@webkit.org committed
75

eric@webkit.org's avatar
eric@webkit.org committed
76 77
static Position anchorPosition(const VisibleSelection& selection)
{
ap@webkit.org's avatar
ap@webkit.org committed
78
    Position anchor = selection.isBaseFirst() ? selection.start() : selection.end();
79
    return anchor.parentAnchoredEquivalent();
weinig's avatar
weinig committed
80 81
}

eric@webkit.org's avatar
eric@webkit.org committed
82 83 84
static Position focusPosition(const VisibleSelection& selection)
{
    Position focus = selection.isBaseFirst() ? selection.end() : selection.start();
85
    return focus.parentAnchoredEquivalent();
eric@webkit.org's avatar
eric@webkit.org committed
86 87 88 89
}

static Position basePosition(const VisibleSelection& selection)
{
90
    return selection.base().parentAnchoredEquivalent();
eric@webkit.org's avatar
eric@webkit.org committed
91 92 93 94
}

static Position extentPosition(const VisibleSelection& selection)
{
95
    return selection.extent().parentAnchoredEquivalent();
eric@webkit.org's avatar
eric@webkit.org committed
96 97 98
}

Node* DOMSelection::anchorNode() const
weinig's avatar
weinig committed
99 100 101
{
    if (!m_frame)
        return 0;
102 103

    return shadowAdjustedNode(anchorPosition(visibleSelection()));
weinig's avatar
weinig committed
104 105 106 107 108 109
}

int DOMSelection::anchorOffset() const
{
    if (!m_frame)
        return 0;
110 111

    return shadowAdjustedOffset(anchorPosition(visibleSelection()));
weinig's avatar
weinig committed
112 113
}

eric@webkit.org's avatar
eric@webkit.org committed
114
Node* DOMSelection::focusNode() const
weinig's avatar
weinig committed
115 116 117
{
    if (!m_frame)
        return 0;
118 119

    return shadowAdjustedNode(focusPosition(visibleSelection()));
weinig's avatar
weinig committed
120 121
}

eric@webkit.org's avatar
eric@webkit.org committed
122
int DOMSelection::focusOffset() const
weinig's avatar
weinig committed
123 124 125
{
    if (!m_frame)
        return 0;
126 127

    return shadowAdjustedOffset(focusPosition(visibleSelection()));
weinig's avatar
weinig committed
128 129
}

eric@webkit.org's avatar
eric@webkit.org committed
130
Node* DOMSelection::baseNode() const
weinig's avatar
weinig committed
131 132 133
{
    if (!m_frame)
        return 0;
134 135

    return shadowAdjustedNode(basePosition(visibleSelection()));
weinig's avatar
weinig committed
136 137
}

eric@webkit.org's avatar
eric@webkit.org committed
138
int DOMSelection::baseOffset() const
weinig's avatar
weinig committed
139 140 141
{
    if (!m_frame)
        return 0;
142 143

    return shadowAdjustedOffset(basePosition(visibleSelection()));
eric@webkit.org's avatar
eric@webkit.org committed
144
}
ap@webkit.org's avatar
ap@webkit.org committed
145

eric@webkit.org's avatar
eric@webkit.org committed
146 147 148 149
Node* DOMSelection::extentNode() const
{
    if (!m_frame)
        return 0;
150 151

    return shadowAdjustedNode(extentPosition(visibleSelection()));
weinig's avatar
weinig committed
152 153 154 155 156 157
}

int DOMSelection::extentOffset() const
{
    if (!m_frame)
        return 0;
158 159

    return shadowAdjustedOffset(extentPosition(visibleSelection()));
weinig's avatar
weinig committed
160 161 162 163
}

bool DOMSelection::isCollapsed() const
{
164 165
    if (!m_frame || selectionShadowAncestor(m_frame))
        return true;
166
    return !m_frame->selection().isRange();
weinig's avatar
weinig committed
167 168 169 170 171 172
}

String DOMSelection::type() const
{
    if (!m_frame)
        return String();
ap@webkit.org's avatar
ap@webkit.org committed
173

174
    FrameSelection& selection = m_frame->selection();
ap@webkit.org's avatar
ap@webkit.org committed
175

eric@webkit.org's avatar
eric@webkit.org committed
176 177 178
    // This is a WebKit DOM extension, incompatible with an IE extension
    // IE has this same attribute, but returns "none", "text" and "control"
    // http://msdn.microsoft.com/en-us/library/ms534692(VS.85).aspx
179
    if (selection.isNone())
ap@webkit.org's avatar
ap@webkit.org committed
180
        return "None";
181
    if (selection.isCaret())
ap@webkit.org's avatar
ap@webkit.org committed
182 183
        return "Caret";
    return "Range";
weinig's avatar
weinig committed
184 185 186 187 188 189
}

int DOMSelection::rangeCount() const
{
    if (!m_frame)
        return 0;
190
    return m_frame->selection().isNone() ? 0 : 1;
weinig's avatar
weinig committed
191 192 193 194
}

void DOMSelection::collapse(Node* node, int offset, ExceptionCode& ec)
{
195
    if (!m_frame)
weinig's avatar
weinig committed
196
        return;
ap@webkit.org's avatar
ap@webkit.org committed
197 198 199 200 201

    if (offset < 0) {
        ec = INDEX_SIZE_ERR;
        return;
    }
202 203 204 205

    if (!isValidForPosition(node))
        return;

206
    // FIXME: Eliminate legacy editing positions
207
    m_frame->selection().moveTo(VisiblePosition(createLegacyEditingPosition(node, offset), DOWNSTREAM));
weinig's avatar
weinig committed
208 209
}

210
void DOMSelection::collapseToEnd(ExceptionCode& ec)
weinig's avatar
weinig committed
211 212 213
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
214

215
    const VisibleSelection& selection = m_frame->selection().selection();
216 217 218 219 220 221

    if (selection.isNone()) {
        ec = INVALID_STATE_ERR;
        return;
    }

222
    m_frame->selection().moveTo(VisiblePosition(selection.end(), DOWNSTREAM));
weinig's avatar
weinig committed
223 224
}

225
void DOMSelection::collapseToStart(ExceptionCode& ec)
weinig's avatar
weinig committed
226 227 228
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
229

230
    const VisibleSelection& selection = m_frame->selection().selection();
231 232 233 234 235 236

    if (selection.isNone()) {
        ec = INVALID_STATE_ERR;
        return;
    }

237
    m_frame->selection().moveTo(VisiblePosition(selection.start(), DOWNSTREAM));
weinig's avatar
weinig committed
238 239 240 241 242 243
}

void DOMSelection::empty()
{
    if (!m_frame)
        return;
244
    m_frame->selection().clear();
weinig's avatar
weinig committed
245 246 247 248 249 250
}

void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode& ec)
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
251 252 253 254 255

    if (baseOffset < 0 || extentOffset < 0) {
        ec = INDEX_SIZE_ERR;
        return;
    }
256 257 258 259

    if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode))
        return;

260
    // FIXME: Eliminate legacy editing positions
261 262
    VisiblePosition visibleBase = VisiblePosition(createLegacyEditingPosition(baseNode, baseOffset), DOWNSTREAM);
    VisiblePosition visibleExtent = VisiblePosition(createLegacyEditingPosition(extentNode, extentOffset), DOWNSTREAM);
263

264
    m_frame->selection().moveTo(visibleBase, visibleExtent);
weinig's avatar
weinig committed
265 266 267 268 269 270
}

void DOMSelection::setPosition(Node* node, int offset, ExceptionCode& ec)
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
271 272 273 274
    if (offset < 0) {
        ec = INDEX_SIZE_ERR;
        return;
    }
275 276 277 278

    if (!isValidForPosition(node))
        return;

279
    // FIXME: Eliminate legacy editing positions
280
    m_frame->selection().moveTo(VisiblePosition(createLegacyEditingPosition(node, offset), DOWNSTREAM));
weinig's avatar
weinig committed
281 282
}

ap@webkit.org's avatar
ap@webkit.org committed
283
void DOMSelection::modify(const String& alterString, const String& directionString, const String& granularityString)
weinig's avatar
weinig committed
284 285 286
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
287

288
    FrameSelection::EAlteration alter;
289
    if (equalIgnoringCase(alterString, "extend"))
290
        alter = FrameSelection::AlterationExtend;
291
    else if (equalIgnoringCase(alterString, "move"))
292
        alter = FrameSelection::AlterationMove;
293
    else
ap@webkit.org's avatar
ap@webkit.org committed
294
        return;
295

296
    SelectionDirection direction;
297
    if (equalIgnoringCase(directionString, "forward"))
298
        direction = DirectionForward;
299
    else if (equalIgnoringCase(directionString, "backward"))
300
        direction = DirectionBackward;
301
    else if (equalIgnoringCase(directionString, "left"))
302
        direction = DirectionLeft;
303
    else if (equalIgnoringCase(directionString, "right"))
304
        direction = DirectionRight;
ap@webkit.org's avatar
ap@webkit.org committed
305 306
    else
        return;
307

ap@webkit.org's avatar
ap@webkit.org committed
308
    TextGranularity granularity;
309
    if (equalIgnoringCase(granularityString, "character"))
ap@webkit.org's avatar
ap@webkit.org committed
310
        granularity = CharacterGranularity;
311
    else if (equalIgnoringCase(granularityString, "word"))
ap@webkit.org's avatar
ap@webkit.org committed
312
        granularity = WordGranularity;
313
    else if (equalIgnoringCase(granularityString, "sentence"))
ap@webkit.org's avatar
ap@webkit.org committed
314
        granularity = SentenceGranularity;
315
    else if (equalIgnoringCase(granularityString, "line"))
ap@webkit.org's avatar
ap@webkit.org committed
316
        granularity = LineGranularity;
317
    else if (equalIgnoringCase(granularityString, "paragraph"))
ap@webkit.org's avatar
ap@webkit.org committed
318
        granularity = ParagraphGranularity;
319
    else if (equalIgnoringCase(granularityString, "lineboundary"))
ap@webkit.org's avatar
ap@webkit.org committed
320
        granularity = LineBoundary;
321
    else if (equalIgnoringCase(granularityString, "sentenceboundary"))
ap@webkit.org's avatar
ap@webkit.org committed
322
        granularity = SentenceBoundary;
323
    else if (equalIgnoringCase(granularityString, "paragraphboundary"))
ap@webkit.org's avatar
ap@webkit.org committed
324
        granularity = ParagraphBoundary;
325
    else if (equalIgnoringCase(granularityString, "documentboundary"))
ap@webkit.org's avatar
ap@webkit.org committed
326 327 328 329
        granularity = DocumentBoundary;
    else
        return;

330
    m_frame->selection().modify(alter, direction, granularity);
weinig's avatar
weinig committed
331 332
}

ap@webkit.org's avatar
ap@webkit.org committed
333
void DOMSelection::extend(Node* node, int offset, ExceptionCode& ec)
ap@webkit.org's avatar
ap@webkit.org committed
334 335 336
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
337 338

    if (!node) {
339
        ec = TYPE_MISMATCH_ERR;
ap@webkit.org's avatar
ap@webkit.org committed
340 341
        return;
    }
342

ap@webkit.org's avatar
ap@webkit.org committed
343 344 345 346 347
    if (offset < 0 || offset > (node->offsetInCharacters() ? caretMaxOffset(node) : (int)node->childNodeCount())) {
        ec = INDEX_SIZE_ERR;
        return;
    }

348 349 350
    if (!isValidForPosition(node))
        return;

351
    // FIXME: Eliminate legacy editing positions
352
    m_frame->selection().setExtent(VisiblePosition(createLegacyEditingPosition(node, offset), DOWNSTREAM));
ap@webkit.org's avatar
ap@webkit.org committed
353 354
}

weinig's avatar
weinig committed
355 356 357 358
PassRefPtr<Range> DOMSelection::getRangeAt(int index, ExceptionCode& ec)
{
    if (!m_frame)
        return 0;
ap@webkit.org's avatar
ap@webkit.org committed
359 360 361 362 363 364

    if (index < 0 || index >= rangeCount()) {
        ec = INDEX_SIZE_ERR;
        return 0;
    }

eric@webkit.org's avatar
eric@webkit.org committed
365 366 367
    // If you're hitting this, you've added broken multi-range selection support
    ASSERT(rangeCount() == 1);

368
    if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) {
369
        ContainerNode* container = shadowAncestor->parentNodeGuaranteedHostFree();
370
        int offset = shadowAncestor->nodeIndex();
371
        return Range::create(shadowAncestor->document(), container, offset, container, offset);
372 373
    }

374
    const VisibleSelection& selection = m_frame->selection().selection();
eric@webkit.org's avatar
eric@webkit.org committed
375
    return selection.firstRange();
weinig's avatar
weinig committed
376 377 378 379 380 381
}

void DOMSelection::removeAllRanges()
{
    if (!m_frame)
        return;
382
    m_frame->selection().clear();
weinig's avatar
weinig committed
383 384
}

ap@webkit.org's avatar
ap@webkit.org committed
385
void DOMSelection::addRange(Range* r)
weinig's avatar
weinig committed
386 387 388
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
389 390 391
    if (!r)
        return;

392
    FrameSelection& selection = m_frame->selection();
393

394 395
    if (selection.isNone()) {
        selection.setSelection(VisibleSelection(r));
ap@webkit.org's avatar
ap@webkit.org committed
396 397 398
        return;
    }

399
    RefPtr<Range> range = selection.selection().toNormalizedRange();
400
    if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), IGNORE_EXCEPTION) == -1) {
ap@webkit.org's avatar
ap@webkit.org committed
401
        // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
402 403
        if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), IGNORE_EXCEPTION) > -1) {
            if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), IGNORE_EXCEPTION) == -1)
ap@webkit.org's avatar
ap@webkit.org committed
404
                // The original range and r intersect.
405
                selection.setSelection(VisibleSelection(r->startPosition(), range->endPosition(), DOWNSTREAM));
ap@webkit.org's avatar
ap@webkit.org committed
406 407
            else
                // r contains the original range.
408
                selection.setSelection(VisibleSelection(r));
ap@webkit.org's avatar
ap@webkit.org committed
409 410 411
        }
    } else {
        // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
412
        ExceptionCode ec = 0;
413
        if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) < 1 && !ec) {
414
            if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), IGNORE_EXCEPTION) == -1)
ap@webkit.org's avatar
ap@webkit.org committed
415
                // The original range contains r.
416
                selection.setSelection(VisibleSelection(range.get()));
ap@webkit.org's avatar
ap@webkit.org committed
417 418
            else
                // The original range and r intersect.
419
                selection.setSelection(VisibleSelection(range->startPosition(), r->endPosition(), DOWNSTREAM));
ap@webkit.org's avatar
ap@webkit.org committed
420 421
        }
    }
weinig's avatar
weinig committed
422 423
}

ap@webkit.org's avatar
ap@webkit.org committed
424 425 426 427
void DOMSelection::deleteFromDocument()
{
    if (!m_frame)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
428

429
    FrameSelection& selection = m_frame->selection();
ap@webkit.org's avatar
ap@webkit.org committed
430

431
    if (selection.isNone())
ap@webkit.org's avatar
ap@webkit.org committed
432 433 434
        return;

    if (isCollapsed())
435
        selection.modify(FrameSelection::AlterationExtend, DirectionBackward, CharacterGranularity);
ap@webkit.org's avatar
ap@webkit.org committed
436

437
    RefPtr<Range> selectedRange = selection.selection().toNormalizedRange();
438 439
    if (!selectedRange)
        return;
ap@webkit.org's avatar
ap@webkit.org committed
440

441
    selectedRange->deleteContents(ASSERT_NO_EXCEPTION);
442

443
    setBaseAndExtent(selectedRange->startContainer(ASSERT_NO_EXCEPTION), selectedRange->startOffset(), selectedRange->startContainer(), selectedRange->startOffset(), ASSERT_NO_EXCEPTION);
ap@webkit.org's avatar
ap@webkit.org committed
444 445
}

446
bool DOMSelection::containsNode(Node* n, bool allowPartial) const
ap@webkit.org's avatar
ap@webkit.org committed
447 448 449
{
    if (!m_frame)
        return false;
ap@webkit.org's avatar
ap@webkit.org committed
450

451
    FrameSelection& selection = m_frame->selection();
ap@webkit.org's avatar
ap@webkit.org committed
452

453
    if (!n || m_frame->document() != &n->document() || selection.isNone())
ap@webkit.org's avatar
ap@webkit.org committed
454 455
        return false;

456
    RefPtr<Node> node = n;
457
    RefPtr<Range> selectedRange = selection.selection().toNormalizedRange();
ap@webkit.org's avatar
ap@webkit.org committed
458

459 460
    ContainerNode* parentNode = node->parentNode();
    if (!parentNode || !parentNode->inDocument())
ap@webkit.org's avatar
ap@webkit.org committed
461
        return false;
462
    unsigned nodeIndex = node->nodeIndex();
ap@webkit.org's avatar
ap@webkit.org committed
463 464

    ExceptionCode ec = 0;
465 466
    bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(), selectedRange->startOffset(), ec) >= 0 && !ec
        && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(), selectedRange->endOffset(), ec) <= 0 && !ec;
ap@webkit.org's avatar
ap@webkit.org committed
467 468 469 470
    ASSERT(!ec);
    if (nodeFullySelected)
        return true;

471 472
    bool nodeFullyUnselected = (Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(), selectedRange->endOffset(), ec) > 0 && !ec)
        || (Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(), selectedRange->startOffset(), ec) < 0 && !ec);
ap@webkit.org's avatar
ap@webkit.org committed
473 474 475 476
    ASSERT(!ec);
    if (nodeFullyUnselected)
        return false;

477
    return allowPartial || node->isTextNode();
ap@webkit.org's avatar
ap@webkit.org committed
478 479 480 481
}

void DOMSelection::selectAllChildren(Node* n, ExceptionCode& ec)
{
ap@webkit.org's avatar
ap@webkit.org committed
482
    if (!n)
ap@webkit.org's avatar
ap@webkit.org committed
483
        return;
ap@webkit.org's avatar
ap@webkit.org committed
484 485 486

    // This doesn't (and shouldn't) select text node characters.
    setBaseAndExtent(n, 0, n, n->childNodeCount(), ec);
ap@webkit.org's avatar
ap@webkit.org committed
487 488
}

weinig's avatar
weinig committed
489 490 491 492
String DOMSelection::toString()
{
    if (!m_frame)
        return String();
ap@webkit.org's avatar
ap@webkit.org committed
493

494
    return plainText(m_frame->selection().selection().toNormalizedRange().get());
weinig's avatar
weinig committed
495 496
}

497 498 499 500 501 502
Node* DOMSelection::shadowAdjustedNode(const Position& position) const
{
    if (position.isNull())
        return 0;

    Node* containerNode = position.containerNode();
503
    Node* adjustedNode = m_treeScope->ancestorInThisScope(containerNode);
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519

    if (!adjustedNode)
        return 0;

    if (containerNode == adjustedNode)
        return containerNode;

    return adjustedNode->parentNodeGuaranteedHostFree();
}

int DOMSelection::shadowAdjustedOffset(const Position& position) const
{
    if (position.isNull())
        return 0;

    Node* containerNode = position.containerNode();
520
    Node* adjustedNode = m_treeScope->ancestorInThisScope(containerNode);
521 522 523 524 525 526 527 528 529 530

    if (!adjustedNode)
        return 0;

    if (containerNode == adjustedNode)
        return position.computeOffsetInContainerNode();

    return adjustedNode->nodeIndex();
}

531 532 533 534 535
bool DOMSelection::isValidForPosition(Node* node) const
{
    ASSERT(m_frame);
    if (!node)
        return true;
536
    return &node->document() == m_frame->document();
537 538
}

weinig's avatar
weinig committed
539
} // namespace WebCore