| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 : m_base(range->startPosition()) | 89 : m_base(range->startPosition()) |
| 90 , m_extent(range->endPosition()) | 90 , m_extent(range->endPosition()) |
| 91 , m_affinity(affinity) | 91 , m_affinity(affinity) |
| 92 , m_isDirectional(isDirectional) | 92 , m_isDirectional(isDirectional) |
| 93 { | 93 { |
| 94 validate(); | 94 validate(); |
| 95 } | 95 } |
| 96 | 96 |
| 97 VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node) | 97 VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node) |
| 98 { | 98 { |
| 99 ASSERT(!editingIgnoresContent(node)); | 99 ASSERT(!editingIgnoresContent(adoptRawResult(node))); |
| 100 return VisibleSelection(firstPositionInNode(adoptRawResult(node)), lastPosit
ionInNode(adoptRawResult(node)), DOWNSTREAM); | 100 return VisibleSelection(firstPositionInNode(adoptRawResult(node)), lastPosit
ionInNode(adoptRawResult(node)), DOWNSTREAM); |
| 101 } | 101 } |
| 102 | 102 |
| 103 void VisibleSelection::setBase(const Position& position) | 103 void VisibleSelection::setBase(const Position& position) |
| 104 { | 104 { |
| 105 m_base = position; | 105 m_base = position; |
| 106 validate(); | 106 validate(); |
| 107 } | 107 } |
| 108 | 108 |
| 109 void VisibleSelection::setBase(const VisiblePosition& visiblePosition) | 109 void VisibleSelection::setBase(const VisiblePosition& visiblePosition) |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 if (isEndOfEditableOrNonEditableContent(start) || (isEndOfLine(start
) && !isStartOfLine(start) && !isEndOfParagraph(start))) | 297 if (isEndOfEditableOrNonEditableContent(start) || (isEndOfLine(start
) && !isStartOfLine(start) && !isEndOfParagraph(start))) |
| 298 side = LeftWordIfOnBoundary; | 298 side = LeftWordIfOnBoundary; |
| 299 m_start = startOfWord(start, side).deepEquivalent(); | 299 m_start = startOfWord(start, side).deepEquivalent(); |
| 300 side = RightWordIfOnBoundary; | 300 side = RightWordIfOnBoundary; |
| 301 if (isEndOfEditableOrNonEditableContent(originalEnd) || (isEndOfLine
(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd))) | 301 if (isEndOfEditableOrNonEditableContent(originalEnd) || (isEndOfLine
(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd))) |
| 302 side = LeftWordIfOnBoundary; | 302 side = LeftWordIfOnBoundary; |
| 303 | 303 |
| 304 VisiblePosition wordEnd(endOfWord(originalEnd, side)); | 304 VisiblePosition wordEnd(endOfWord(originalEnd, side)); |
| 305 VisiblePosition end(wordEnd); | 305 VisiblePosition end(wordEnd); |
| 306 | 306 |
| 307 if (isEndOfParagraph(originalEnd) && !isEmptyTableCell(m_start.depre
catedNode().handle().raw())) { | 307 if (isEndOfParagraph(originalEnd) && !isEmptyTableCell(m_start.depre
catedNode())) { |
| 308 // Select the paragraph break (the space from the end of a parag
raph to the start of | 308 // Select the paragraph break (the space from the end of a parag
raph to the start of |
| 309 // the next one) to match TextEdit. | 309 // the next one) to match TextEdit. |
| 310 end = wordEnd.next(); | 310 end = wordEnd.next(); |
| 311 | 311 |
| 312 if (Node* table = isFirstPositionAfterTable(end)) { | 312 if (Handle<Node> table = isFirstPositionAfterTable(end)) { |
| 313 // The paragraph break after the last paragraph in the last
cell of a block table ends | 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. | 314 // at the start of the paragraph after the table. |
| 315 if (isBlock(table)) | 315 if (isBlock(table)) |
| 316 end = end.next(CannotCrossEditingBoundary); | 316 end = end.next(CannotCrossEditingBoundary); |
| 317 else | 317 else |
| 318 end = wordEnd; | 318 end = wordEnd; |
| 319 } | 319 } |
| 320 | 320 |
| 321 if (end.isNull()) | 321 if (end.isNull()) |
| 322 end = wordEnd; | 322 end = wordEnd; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 352 VisiblePosition pos(m_start, m_affinity); | 352 VisiblePosition pos(m_start, m_affinity); |
| 353 if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos)) | 353 if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos)) |
| 354 pos = pos.previous(); | 354 pos = pos.previous(); |
| 355 m_start = startOfParagraph(pos).deepEquivalent(); | 355 m_start = startOfParagraph(pos).deepEquivalent(); |
| 356 VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition
(m_end, m_affinity)); | 356 VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition
(m_end, m_affinity)); |
| 357 | 357 |
| 358 // Include the "paragraph break" (the space from the end of this par
agraph to the start | 358 // Include the "paragraph break" (the space from the end of this par
agraph to the start |
| 359 // of the next one) in the selection. | 359 // of the next one) in the selection. |
| 360 VisiblePosition end(visibleParagraphEnd.next()); | 360 VisiblePosition end(visibleParagraphEnd.next()); |
| 361 | 361 |
| 362 if (Node* table = isFirstPositionAfterTable(end)) { | 362 if (Handle<Node> table = isFirstPositionAfterTable(end)) { |
| 363 // The paragraph break after the last paragraph in the last cell
of a block table ends | 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 pos
ition just after the table. | 364 // at the start of the paragraph after the table, not at the pos
ition just after the table. |
| 365 if (isBlock(table)) | 365 if (isBlock(table)) |
| 366 end = end.next(CannotCrossEditingBoundary); | 366 end = end.next(CannotCrossEditingBoundary); |
| 367 // There is no parargraph break after the last paragraph in the
last cell of an inline table. | 367 // There is no parargraph break after the last paragraph in the
last cell of an inline table. |
| 368 else | 368 else |
| 369 end = visibleParagraphEnd; | 369 end = visibleParagraphEnd; |
| 370 } | 370 } |
| 371 | 371 |
| 372 if (end.isNull()) | 372 if (end.isNull()) |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 } | 515 } |
| 516 | 516 |
| 517 ASSERT(m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope())
; | 517 ASSERT(m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope())
; |
| 518 } | 518 } |
| 519 | 519 |
| 520 void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries() | 520 void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries() |
| 521 { | 521 { |
| 522 if (m_base.isNull() || m_start.isNull() || m_end.isNull()) | 522 if (m_base.isNull() || m_start.isNull() || m_end.isNull()) |
| 523 return; | 523 return; |
| 524 | 524 |
| 525 Node* baseRoot = highestEditableRoot(m_base); | 525 Handle<Node> baseRoot = highestEditableRoot(m_base); |
| 526 Node* startRoot = highestEditableRoot(m_start); | 526 Handle<Node> startRoot = highestEditableRoot(m_start); |
| 527 Node* endRoot = highestEditableRoot(m_end); | 527 Handle<Node> endRoot = highestEditableRoot(m_end); |
| 528 | 528 |
| 529 Node* baseEditableAncestor = lowestEditableAncestor(m_base.containerNode().h
andle().raw()); | 529 Handle<Node> baseEditableAncestor = lowestEditableAncestor(m_base.containerN
ode()); |
| 530 | 530 |
| 531 // The base, start and end are all in the same region. No adjustment necess
ary. | 531 // The base, start and end are all in the same region. No adjustment necess
ary. |
| 532 if (baseRoot == startRoot && baseRoot == endRoot) | 532 if (baseRoot == startRoot && baseRoot == endRoot) |
| 533 return; | 533 return; |
| 534 | 534 |
| 535 // The selection is based in editable content. | 535 // The selection is based in editable content. |
| 536 if (baseRoot) { | 536 if (baseRoot) { |
| 537 // If the start is outside the base's editable root, cap it at the start
of that root. | 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 edi
table root, put it | 538 // If the start is in non-editable content that is inside the base's edi
table root, put it |
| 539 // at the first editable position after start inside the base's editable
root. | 539 // at the first editable position after start inside the base's editable
root. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 554 if (m_end.isNull()) | 554 if (m_end.isNull()) |
| 555 m_end = m_start; | 555 m_end = m_start; |
| 556 } | 556 } |
| 557 // The selection is based in non-editable content. | 557 // The selection is based in non-editable content. |
| 558 } else { | 558 } else { |
| 559 // FIXME: Non-editable pieces inside editable content should be atomic,
in the same way that editable | 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. | 560 // pieces in non-editable content are atomic. |
| 561 | 561 |
| 562 // The selection ends in editable content or non-editable content inside
a different editable ancestor, | 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 edita
ble ancestor is reached. | 563 // move backward until non-editable content inside the same lowest edita
ble ancestor is reached. |
| 564 Node* endEditableAncestor = lowestEditableAncestor(m_end.containerNode()
.handle().raw()); | 564 Handle<Node> endEditableAncestor = lowestEditableAncestor(m_end.containe
rNode()); |
| 565 if (endRoot || endEditableAncestor != baseEditableAncestor) { | 565 if (endRoot || endEditableAncestor != baseEditableAncestor) { |
| 566 | 566 |
| 567 Position p = previousVisuallyDistinctCandidate(m_end); | 567 Position p = previousVisuallyDistinctCandidate(m_end); |
| 568 Handle<Node> shadowAncestor = endRoot ? endRoot->shadowHost() : null
ptr; | 568 Handle<Node> shadowAncestor = endRoot ? endRoot->shadowHost() : null
ptr; |
| 569 if (p.isNull() && shadowAncestor) | 569 if (p.isNull() && shadowAncestor) |
| 570 p = positionAfterNode(shadowAncestor); | 570 p = positionAfterNode(shadowAncestor); |
| 571 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode().h
andle().raw()) == baseEditableAncestor && !isEditablePosition(p))) { | 571 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode())
== baseEditableAncestor && !isEditablePosition(p))) { |
| 572 HandleScope scope; | 572 HandleScope scope; |
| 573 Handle<Node> root = editableRootForPosition(p); | 573 Handle<Node> root = editableRootForPosition(p); |
| 574 shadowAncestor = root ? root->shadowHost() : nullptr; | 574 shadowAncestor = root ? root->shadowHost() : nullptr; |
| 575 p = isAtomicNode(p.containerNode().handle().raw()) ? positionInP
arentBeforeNode(p.containerNode()) : previousVisuallyDistinctCandidate(p); | 575 p = isAtomicNode(p.containerNode()) ? positionInParentBeforeNode
(p.containerNode()) : previousVisuallyDistinctCandidate(p); |
| 576 if (p.isNull() && shadowAncestor) | 576 if (p.isNull() && shadowAncestor) |
| 577 p = positionAfterNode(shadowAncestor); | 577 p = positionAfterNode(shadowAncestor); |
| 578 } | 578 } |
| 579 VisiblePosition previous(p); | 579 VisiblePosition previous(p); |
| 580 | 580 |
| 581 if (previous.isNull()) { | 581 if (previous.isNull()) { |
| 582 // The selection crosses an Editing boundary. This is a | 582 // The selection crosses an Editing boundary. This is a |
| 583 // programmer error in the editing code. Happy debugging! | 583 // programmer error in the editing code. Happy debugging! |
| 584 ASSERT_NOT_REACHED(); | 584 ASSERT_NOT_REACHED(); |
| 585 m_base = Position(); | 585 m_base = Position(); |
| 586 m_extent = Position(); | 586 m_extent = Position(); |
| 587 validate(); | 587 validate(); |
| 588 return; | 588 return; |
| 589 } | 589 } |
| 590 m_end = previous.deepEquivalent(); | 590 m_end = previous.deepEquivalent(); |
| 591 } | 591 } |
| 592 | 592 |
| 593 // The selection starts in editable content or non-editable content insi
de a different editable ancestor, | 593 // The selection starts in editable content or non-editable content insi
de a different editable ancestor, |
| 594 // move forward until non-editable content inside the same lowest editab
le ancestor is reached. | 594 // move forward until non-editable content inside the same lowest editab
le ancestor is reached. |
| 595 Node* startEditableAncestor = lowestEditableAncestor(m_start.containerNo
de().handle().raw()); | 595 Handle<Node> startEditableAncestor = lowestEditableAncestor(m_start.cont
ainerNode()); |
| 596 if (startRoot || startEditableAncestor != baseEditableAncestor) { | 596 if (startRoot || startEditableAncestor != baseEditableAncestor) { |
| 597 Position p = nextVisuallyDistinctCandidate(m_start); | 597 Position p = nextVisuallyDistinctCandidate(m_start); |
| 598 Handle<Node> shadowAncestor = startRoot ? startRoot->shadowHost() :
nullptr; | 598 Handle<Node> shadowAncestor = startRoot ? startRoot->shadowHost() :
nullptr; |
| 599 if (p.isNull() && shadowAncestor) | 599 if (p.isNull() && shadowAncestor) |
| 600 p = positionBeforeNode(shadowAncestor); | 600 p = positionBeforeNode(shadowAncestor); |
| 601 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode().h
andle().raw()) == baseEditableAncestor && !isEditablePosition(p))) { | 601 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode())
== baseEditableAncestor && !isEditablePosition(p))) { |
| 602 HandleScope scope; | 602 HandleScope scope; |
| 603 Handle<Node> root = editableRootForPosition(p); | 603 Handle<Node> root = editableRootForPosition(p); |
| 604 shadowAncestor = root ? root->shadowHost() : nullptr; | 604 shadowAncestor = root ? root->shadowHost() : nullptr; |
| 605 p = isAtomicNode(p.containerNode().handle().raw()) ? positionInP
arentAfterNode(p.containerNode()) : nextVisuallyDistinctCandidate(p); | 605 p = isAtomicNode(p.containerNode()) ? positionInParentAfterNode(
p.containerNode()) : nextVisuallyDistinctCandidate(p); |
| 606 if (p.isNull() && shadowAncestor) | 606 if (p.isNull() && shadowAncestor) |
| 607 p = positionBeforeNode(shadowAncestor); | 607 p = positionBeforeNode(shadowAncestor); |
| 608 } | 608 } |
| 609 VisiblePosition next(p); | 609 VisiblePosition next(p); |
| 610 | 610 |
| 611 if (next.isNull()) { | 611 if (next.isNull()) { |
| 612 // The selection crosses an Editing boundary. This is a | 612 // The selection crosses an Editing boundary. This is a |
| 613 // programmer error in the editing code. Happy debugging! | 613 // programmer error in the editing code. Happy debugging! |
| 614 ASSERT_NOT_REACHED(); | 614 ASSERT_NOT_REACHED(); |
| 615 m_base = Position(); | 615 m_base = Position(); |
| 616 m_extent = Position(); | 616 m_extent = Position(); |
| 617 validate(); | 617 validate(); |
| 618 return; | 618 return; |
| 619 } | 619 } |
| 620 m_start = next.deepEquivalent(); | 620 m_start = next.deepEquivalent(); |
| 621 } | 621 } |
| 622 } | 622 } |
| 623 | 623 |
| 624 // Correct the extent if necessary. | 624 // Correct the extent if necessary. |
| 625 if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode().
handle().raw())) | 625 if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode())
) |
| 626 m_extent = m_baseIsFirst ? m_end : m_start; | 626 m_extent = m_baseIsFirst ? m_end : m_start; |
| 627 } | 627 } |
| 628 | 628 |
| 629 bool VisibleSelection::isContentEditable() const | 629 bool VisibleSelection::isContentEditable() const |
| 630 { | 630 { |
| 631 return isEditablePosition(start()); | 631 return isEditablePosition(start()); |
| 632 } | 632 } |
| 633 | 633 |
| 634 bool VisibleSelection::rendererIsEditable() const | 634 bool VisibleSelection::rendererIsEditable() const |
| 635 { | 635 { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 sel.showTreeForThis(); | 715 sel.showTreeForThis(); |
| 716 } | 716 } |
| 717 | 717 |
| 718 void showTree(const WebCore::VisibleSelection* sel) | 718 void showTree(const WebCore::VisibleSelection* sel) |
| 719 { | 719 { |
| 720 if (sel) | 720 if (sel) |
| 721 sel->showTreeForThis(); | 721 sel->showTreeForThis(); |
| 722 } | 722 } |
| 723 | 723 |
| 724 #endif | 724 #endif |
| OLD | NEW |