OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2009 Apple 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 26 matching lines...) Expand all Loading... | |
37 #include "core/editing/htmlediting.h" | 37 #include "core/editing/htmlediting.h" |
38 #include "core/html/HTMLHtmlElement.h" | 38 #include "core/html/HTMLHtmlElement.h" |
39 #include "core/html/HTMLTableElement.h" | 39 #include "core/html/HTMLTableElement.h" |
40 #include "core/page/Frame.h" | 40 #include "core/page/Frame.h" |
41 #include "core/page/Settings.h" | 41 #include "core/page/Settings.h" |
42 #include "core/platform/Logging.h" | 42 #include "core/platform/Logging.h" |
43 #include "core/rendering/InlineIterator.h" | 43 #include "core/rendering/InlineIterator.h" |
44 #include "core/rendering/InlineTextBox.h" | 44 #include "core/rendering/InlineTextBox.h" |
45 #include "core/rendering/RenderBlock.h" | 45 #include "core/rendering/RenderBlock.h" |
46 #include "core/rendering/RenderInline.h" | 46 #include "core/rendering/RenderInline.h" |
47 #include "core/rendering/RenderText.h" | 47 #include "core/rendering/RenderTextFragment.h" |
48 #include "wtf/text/CString.h" | 48 #include "wtf/text/CString.h" |
49 #include "wtf/unicode/CharacterNames.h" | 49 #include "wtf/unicode/CharacterNames.h" |
50 | 50 |
51 namespace WebCore { | 51 namespace WebCore { |
52 | 52 |
53 using namespace HTMLNames; | 53 using namespace HTMLNames; |
54 | 54 |
55 static Node* nextRenderedEditable(Node* node) | 55 static Node* nextRenderedEditable(Node* node) |
56 { | 56 { |
57 while ((node = node->nextLeafNode())) { | 57 while ((node = node->nextLeafNode())) { |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
446 return !deprecatedNode()->parentNode() && m_offset <= 0; | 446 return !deprecatedNode()->parentNode() && m_offset <= 0; |
447 } | 447 } |
448 | 448 |
449 bool Position::atEndOfTree() const | 449 bool Position::atEndOfTree() const |
450 { | 450 { |
451 if (isNull()) | 451 if (isNull()) |
452 return true; | 452 return true; |
453 return !deprecatedNode()->parentNode() && m_offset >= lastOffsetForEditing(d eprecatedNode()); | 453 return !deprecatedNode()->parentNode() && m_offset >= lastOffsetForEditing(d eprecatedNode()); |
454 } | 454 } |
455 | 455 |
456 RenderObject* Position::rendererOfAnchorNode() const | |
457 { | |
458 if (!m_anchorNode) | |
459 return 0; | |
460 RenderObject* renderer = m_anchorNode->renderer(); | |
461 if (!renderer || !renderer->isText() || !toRenderText(renderer)->isTextFragm ent()) | |
462 return renderer; | |
463 if (m_offset >= static_cast<int>(toRenderTextFragment(renderer)->textStartOf fset())) | |
464 return renderer; | |
465 return toRenderTextFragment(renderer)->firstRenderTextInFirstLetter(); | |
466 } | |
467 | |
468 // Position::deprecatedOffsetInRendererOfAnchorNode() is replacement of usage of | |
469 // deprecatedEditingOffset() in FrameSelection::updateAppearance(). | |
470 int Position::deprecatedOffsetInRendererOfAnchorNode() const | |
471 { | |
472 switch (m_isLegacyEditingPosition ? PositionIsOffsetInAnchor : m_anchorType) { | |
473 case PositionIsBeforeChildren: | |
474 case PositionIsBeforeAnchor: | |
475 case PositionIsOffsetInAnchor: { | |
476 RenderObject* renderer = rendererOfAnchorNode(); | |
477 if (!renderer || !renderer->isText()) | |
478 return m_offset; | |
479 return m_offset - toRenderText(renderer)->textStartOffset(); | |
480 } | |
481 case PositionIsAfterChildren: | |
482 case PositionIsAfterAnchor: | |
483 return offsetForPositionAfterAnchor(); | |
484 } | |
485 ASSERT_NOT_REACHED(); | |
486 return m_offset; | |
487 } | |
488 | |
456 int Position::renderedOffset() const | 489 int Position::renderedOffset() const |
457 { | 490 { |
458 if (!deprecatedNode()->isTextNode()) | 491 RenderObject* renderer = rendererOfAnchorNode(); |
492 if (!renderer || !renderer->isText()) | |
459 return m_offset; | 493 return m_offset; |
460 | 494 |
461 if (!deprecatedNode()->renderer()) | 495 RenderText* textRenderer = toRenderText(renderer); |
462 return m_offset; | 496 int result = textRenderer->textStartOffset(); |
463 | |
464 int result = 0; | |
465 RenderText* textRenderer = toRenderText(deprecatedNode()->renderer()); | |
466 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next TextBox()) { | 497 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next TextBox()) { |
467 int start = box->start(); | 498 int start = box->start(); |
468 int end = box->start() + box->len(); | 499 int end = box->start() + box->len(); |
469 if (m_offset < start) | 500 if (m_offset < start) |
470 return result; | 501 return result; |
471 if (m_offset <= end) { | 502 if (m_offset <= end) { |
472 result += m_offset - start; | 503 result += m_offset - start; |
473 return result; | 504 return result; |
474 } | 505 } |
475 result += box->len(); | 506 result += box->len(); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
585 Node* startNode = deprecatedNode(); | 616 Node* startNode = deprecatedNode(); |
586 if (!startNode) | 617 if (!startNode) |
587 return Position(); | 618 return Position(); |
588 | 619 |
589 // iterate backward from there, looking for a qualified position | 620 // iterate backward from there, looking for a qualified position |
590 Node* boundary = enclosingVisualBoundary(startNode); | 621 Node* boundary = enclosingVisualBoundary(startNode); |
591 // FIXME: PositionIterator should respect Before and After positions. | 622 // FIXME: PositionIterator should respect Before and After positions. |
592 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat eLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this; | 623 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat eLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this; |
593 PositionIterator currentPos = lastVisible; | 624 PositionIterator currentPos = lastVisible; |
594 bool startEditable = startNode->rendererIsEditable(); | 625 bool startEditable = startNode->rendererIsEditable(); |
626 RenderObject* startRenderer = rendererOfAnchorNode(); | |
595 Node* lastNode = startNode; | 627 Node* lastNode = startNode; |
628 RenderObject* lastRenderer = startRenderer; | |
596 bool boundaryCrossed = false; | 629 bool boundaryCrossed = false; |
597 for (; !currentPos.atStart(); currentPos.decrement()) { | 630 for (; !currentPos.atStart(); currentPos.decrement()) { |
598 Node* currentNode = currentPos.node(); | 631 Node* currentNode = currentPos.node(); |
632 RenderObject* currentRenderer = currentPos.renderer(); | |
599 | 633 |
600 // Don't check for an editability change if we haven't moved to a differ ent node, | 634 // Don't check for an editability change if we haven't moved to a differ ent node, |
601 // to avoid the expense of computing rendererIsEditable(). | 635 // to avoid the expense of computing rendererIsEditable(). |
602 if (currentNode != lastNode) { | 636 if (currentRenderer != lastRenderer) { |
603 // Don't change editability. | 637 // Don't change editability. |
604 bool currentEditable = currentNode->rendererIsEditable(); | 638 bool currentEditable = currentNode->rendererIsEditable(); |
605 if (startEditable != currentEditable) { | 639 if (startEditable != currentEditable) { |
606 if (rule == CannotCrossEditingBoundary) | 640 if (rule == CannotCrossEditingBoundary) |
607 break; | 641 break; |
608 boundaryCrossed = true; | 642 boundaryCrossed = true; |
609 } | 643 } |
610 lastNode = currentNode; | 644 lastNode = currentNode; |
645 lastRenderer = currentPos.renderer(); | |
611 } | 646 } |
612 | 647 |
613 // If we've moved to a position that is visually distinct, return the la st saved position. There | 648 // If we've moved to a position that is visually distinct, return the la st saved position. There |
614 // is code below that terminates early if we're *about* to move to a vis ually distinct position. | 649 // is code below that terminates early if we're *about* to move to a vis ually distinct position. |
615 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary) | 650 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary) |
616 return lastVisible; | 651 return lastVisible; |
617 | 652 |
618 // skip position in unrendered or invisible node | 653 // skip position in unrendered or invisible node |
619 RenderObject* renderer = currentNode->renderer(); | 654 if (!currentRenderer || currentRenderer->style()->visibility() != VISIBL E) |
620 if (!renderer || renderer->style()->visibility() != VISIBLE) | |
621 continue; | 655 continue; |
622 | 656 |
623 if (rule == CanCrossEditingBoundary && boundaryCrossed) { | 657 if (rule == CanCrossEditingBoundary && boundaryCrossed) { |
624 lastVisible = currentPos; | 658 lastVisible = currentPos; |
625 break; | 659 break; |
626 } | 660 } |
627 | 661 |
628 // track last visible streamer position | 662 // track last visible streamer position |
629 if (isStreamer(currentPos)) | 663 if (isStreamer(currentPos)) |
630 lastVisible = currentPos; | 664 lastVisible = currentPos; |
631 | 665 |
632 // Don't move past a position that is visually distinct. We could rely on code above to terminate and | 666 // Don't move past a position that is visually distinct. We could rely on code above to terminate and |
633 // return lastVisible on the next iteration, but we terminate early to a void doing a nodeIndex() call. | 667 // return lastVisible on the next iteration, but we terminate early to a void doing a nodeIndex() call. |
634 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.at StartOfNode()) | 668 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.at StartOfNode()) |
635 return lastVisible; | 669 return lastVisible; |
636 | 670 |
637 // Return position after tables and nodes which have content that can be ignored. | 671 // Return position after tables and nodes which have content that can be ignored. |
638 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) { | 672 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) { |
639 if (currentPos.atEndOfNode()) | 673 if (currentPos.atEndOfNode()) |
640 return positionAfterNode(currentNode); | 674 return positionAfterNode(currentNode); |
641 continue; | 675 continue; |
642 } | 676 } |
643 | 677 |
644 // return current position if it is in rendered text | 678 // return current position if it is in rendered text |
645 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { | 679 if (currentRenderer->isText() && toRenderText(currentRenderer)->firstTex tBox()) { |
646 if (currentNode != startNode) { | 680 RenderText* textRenderer = toRenderText(currentRenderer); |
647 // This assertion fires in layout tests in the case-transform.ht ml test because | 681 if (currentRenderer != startRenderer) |
648 // of a mix-up between offsets in the text in the DOM tree with text in the | 682 return createLegacyEditingPosition(currentNode, textRenderer->ca retMaxOffset() + textRenderer->textStartOffset()); |
649 // render tree which can have a different length due to case tra nsformation. | |
650 // Until we resolve that, disable this so we can run the layout tests! | |
651 //ASSERT(currentOffset >= renderer->caretMaxOffset()); | |
652 return createLegacyEditingPosition(currentNode, renderer->caretM axOffset()); | |
653 } | |
654 | 683 |
655 unsigned textOffset = currentPos.offsetInLeafNode(); | 684 unsigned textOffset = currentPos.offsetInLeafNode() - textRenderer-> textStartOffset(); |
656 RenderText* textRenderer = toRenderText(renderer); | |
657 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); | 685 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); |
658 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b ox->nextTextBox()) { | 686 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b ox->nextTextBox()) { |
659 if (textOffset <= box->start() + box->len()) { | 687 if (textOffset <= box->start() + box->len()) { |
660 if (textOffset > box->start()) | 688 if (textOffset > box->start()) |
661 return currentPos; | 689 return currentPos; |
662 continue; | 690 continue; |
663 } | 691 } |
664 | 692 |
665 if (box == lastTextBox || textOffset != box->start() + box->len( ) + 1) | 693 if (box == lastTextBox || textOffset != box->start() + box->len( ) + 1) |
666 continue; | 694 continue; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
708 Node* startNode = deprecatedNode(); | 736 Node* startNode = deprecatedNode(); |
709 if (!startNode) | 737 if (!startNode) |
710 return Position(); | 738 return Position(); |
711 | 739 |
712 // iterate forward from there, looking for a qualified position | 740 // iterate forward from there, looking for a qualified position |
713 Node* boundary = enclosingVisualBoundary(startNode); | 741 Node* boundary = enclosingVisualBoundary(startNode); |
714 // FIXME: PositionIterator should respect Before and After positions. | 742 // FIXME: PositionIterator should respect Before and After positions. |
715 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat eLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this; | 743 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat eLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this; |
716 PositionIterator currentPos = lastVisible; | 744 PositionIterator currentPos = lastVisible; |
717 bool startEditable = startNode->rendererIsEditable(); | 745 bool startEditable = startNode->rendererIsEditable(); |
746 RenderObject* startRenderer = rendererOfAnchorNode(); | |
718 Node* lastNode = startNode; | 747 Node* lastNode = startNode; |
748 RenderObject* lastRenderer = startRenderer; | |
719 bool boundaryCrossed = false; | 749 bool boundaryCrossed = false; |
720 for (; !currentPos.atEnd(); currentPos.increment()) { | 750 for (; !currentPos.atEnd(); currentPos.increment()) { |
721 Node* currentNode = currentPos.node(); | 751 Node* currentNode = currentPos.node(); |
752 RenderObject* currentRenderer = currentPos.renderer(); | |
722 | 753 |
723 // Don't check for an editability change if we haven't moved to a differ ent node, | 754 // Don't check for an editability change if we haven't moved to a differ ent node, |
724 // to avoid the expense of computing rendererIsEditable(). | 755 // to avoid the expense of computing rendererIsEditable(). |
725 if (currentNode != lastNode) { | 756 if (currentRenderer!= lastRenderer) { |
726 // Don't change editability. | 757 // Don't change editability. |
727 bool currentEditable = currentNode->rendererIsEditable(); | 758 bool currentEditable = currentNode->rendererIsEditable(); |
728 if (startEditable != currentEditable) { | 759 if (startEditable != currentEditable) { |
729 if (rule == CannotCrossEditingBoundary) | 760 if (rule == CannotCrossEditingBoundary) |
730 break; | 761 break; |
731 boundaryCrossed = true; | 762 boundaryCrossed = true; |
732 } | 763 } |
733 | 764 |
734 lastNode = currentNode; | 765 lastNode = currentNode; |
766 lastRenderer = currentRenderer; | |
735 } | 767 } |
736 | 768 |
737 // stop before going above the body, up into the head | 769 // stop before going above the body, up into the head |
738 // return the last visible streamer position | 770 // return the last visible streamer position |
739 if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode()) | 771 if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode()) |
740 break; | 772 break; |
741 | 773 |
742 // Do not move to a visually distinct position. | 774 // Do not move to a visually distinct position. |
743 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary) | 775 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary) |
744 return lastVisible; | 776 return lastVisible; |
745 // Do not move past a visually disinct position. | 777 // Do not move past a visually disinct position. |
746 // Note: The first position after the last in a node whose ends are visu ally distinct | 778 // Note: The first position after the last in a node whose ends are visu ally distinct |
747 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1]. | 779 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1]. |
748 if (boundary && boundary->parentNode() == currentNode) | 780 if (boundary && boundary->parentNode() == currentNode) |
749 return lastVisible; | 781 return lastVisible; |
750 | 782 |
751 // skip position in unrendered or invisible node | 783 // skip position in unrendered or invisible node |
752 RenderObject* renderer = currentNode->renderer(); | 784 if (!currentRenderer || currentRenderer->style()->visibility() != VISIBL E) |
753 if (!renderer || renderer->style()->visibility() != VISIBLE) | |
754 continue; | 785 continue; |
755 | 786 |
756 if (rule == CanCrossEditingBoundary && boundaryCrossed) { | 787 if (rule == CanCrossEditingBoundary && boundaryCrossed) { |
757 lastVisible = currentPos; | 788 lastVisible = currentPos; |
758 break; | 789 break; |
759 } | 790 } |
760 | 791 |
761 // track last visible streamer position | 792 // track last visible streamer position |
762 if (isStreamer(currentPos)) | 793 if (isStreamer(currentPos)) |
763 lastVisible = currentPos; | 794 lastVisible = currentPos; |
764 | 795 |
765 // Return position before tables and nodes which have content that can b e ignored. | 796 // Return position before tables and nodes which have content that can b e ignored. |
766 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) { | 797 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) { |
767 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset()) | 798 if (currentPos.offsetInLeafNode() <= currentRenderer->caretMinOffset ()) |
768 return createLegacyEditingPosition(currentNode, renderer->caretM inOffset()); | 799 return createLegacyEditingPosition(currentNode, currentRenderer- >caretMinOffset()); |
769 continue; | 800 continue; |
770 } | 801 } |
771 | 802 |
772 // return current position if it is in rendered text | 803 // return current position if it is in rendered text |
773 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { | 804 if (currentRenderer->isText() && toRenderText(currentRenderer)->firstTex tBox()) { |
774 if (currentNode != startNode) { | 805 RenderText* textRenderer = toRenderText(currentRenderer); |
775 ASSERT(currentPos.atStartOfNode()); | 806 if (currentRenderer != startRenderer) |
776 return createLegacyEditingPosition(currentNode, renderer->caretM inOffset()); | 807 return createLegacyEditingPosition(currentNode, textRenderer->ca retMinOffset() + textRenderer->textStartOffset()); |
777 } | |
778 | 808 |
779 unsigned textOffset = currentPos.offsetInLeafNode(); | 809 unsigned textOffset = currentPos.offsetInLeafNode() - textRenderer-> textStartOffset(); |
780 RenderText* textRenderer = toRenderText(renderer); | |
781 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); | 810 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); |
782 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b ox->nextTextBox()) { | 811 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b ox->nextTextBox()) { |
783 if (textOffset <= box->end()) { | 812 if (textOffset <= box->end()) { |
784 if (textOffset >= box->start()) | 813 if (textOffset >= box->start()) |
785 return currentPos; | 814 return currentPos; |
786 continue; | 815 continue; |
787 } | 816 } |
788 | 817 |
789 if (box == lastTextBox || textOffset != box->start() + box->len( )) | 818 if (box == lastTextBox || textOffset != box->start() + box->len( )) |
790 continue; | 819 continue; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
831 for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextIn PreOrder()) | 860 for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextIn PreOrder()) |
832 if (o->nonPseudoNode()) { | 861 if (o->nonPseudoNode()) { |
833 if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->lin esBoundingBox())) | 862 if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->lin esBoundingBox())) |
834 || (o->isBox() && toRenderBox(o)->pixelSnappedLogicalHeight()) | 863 || (o->isBox() && toRenderBox(o)->pixelSnappedLogicalHeight()) |
835 || (o->isRenderInline() && isEmptyInline(o) && boundingBoxLogica lHeight(o, toRenderInline(o)->linesBoundingBox()))) | 864 || (o->isRenderInline() && isEmptyInline(o) && boundingBoxLogica lHeight(o, toRenderInline(o)->linesBoundingBox()))) |
836 return true; | 865 return true; |
837 } | 866 } |
838 return false; | 867 return false; |
839 } | 868 } |
840 | 869 |
870 static bool rendererIsUserSelectNone(RenderObject* renderer) | |
871 { | |
872 return renderer && renderer->style()->userSelect() == SELECT_NONE && rendere r->style()->userModify() == READ_ONLY; | |
873 } | |
874 | |
875 // FIXME: Caller of nodeIsUserSelectNode() should consider first letter and | |
876 // remaining text have different user-select CSS property. | |
841 bool Position::nodeIsUserSelectNone(Node* node) | 877 bool Position::nodeIsUserSelectNone(Node* node) |
842 { | 878 { |
843 return node && node->renderer() && !node->renderer()->isSelectable(); | 879 return node && rendererIsUserSelectNone(node->renderer()); |
880 } | |
881 | |
882 ContainerNode* Position::findParent(const Node* node) | |
ojan
2013/09/23 23:01:45
This looks unused.
| |
883 { | |
884 return node->parentNode(); | |
844 } | 885 } |
845 | 886 |
846 bool Position::nodeIsUserSelectAll(const Node* node) | 887 bool Position::nodeIsUserSelectAll(const Node* node) |
847 { | 888 { |
848 return RuntimeEnabledFeatures::userSelectAllEnabled() && node && node->rende rer() && node->renderer()->style()->userSelect() == SELECT_ALL; | 889 return RuntimeEnabledFeatures::userSelectAllEnabled() && node && node->rende rer() && node->renderer()->style()->userSelect() == SELECT_ALL; |
849 } | 890 } |
850 | 891 |
851 Node* Position::rootUserSelectAllForNode(Node* node) | 892 Node* Position::rootUserSelectAllForNode(Node* node) |
852 { | 893 { |
853 if (!node || !nodeIsUserSelectAll(node)) | 894 if (!node || !nodeIsUserSelectAll(node)) |
(...skipping 11 matching lines...) Expand all Loading... | |
865 if (!nodeIsUserSelectAll(parent)) | 906 if (!nodeIsUserSelectAll(parent)) |
866 break; | 907 break; |
867 candidateRoot = parent; | 908 candidateRoot = parent; |
868 parent = candidateRoot->parentNode(); | 909 parent = candidateRoot->parentNode(); |
869 } | 910 } |
870 return candidateRoot; | 911 return candidateRoot; |
871 } | 912 } |
872 | 913 |
873 bool Position::isCandidate() const | 914 bool Position::isCandidate() const |
874 { | 915 { |
875 if (isNull()) | 916 RenderObject* renderer = rendererOfAnchorNode(); |
876 return false; | |
877 | |
878 RenderObject* renderer = deprecatedNode()->renderer(); | |
879 if (!renderer) | 917 if (!renderer) |
880 return false; | 918 return false; |
881 | 919 |
882 if (renderer->style()->visibility() != VISIBLE) | 920 if (renderer->style()->visibility() != VISIBLE) |
883 return false; | 921 return false; |
884 | 922 |
885 if (renderer->isBR()) | 923 if (renderer->isBR()) |
886 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor , but for now we still need to support legacy positions. | 924 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor , but for now we still need to support legacy positions. |
887 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUser SelectNone(deprecatedNode()->parentNode()); | 925 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUser SelectNone(deprecatedNode()->parentNode()); |
888 | 926 |
889 if (renderer->isText()) | 927 if (renderer->isText()) |
890 return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText(); | 928 return !rendererIsUserSelectNone(renderer) && inRenderedText(); |
891 | 929 |
892 if (isTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode ())) | 930 if (isTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode ())) |
893 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode( )) && !nodeIsUserSelectNone(deprecatedNode()->parentNode()); | 931 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode( )) && !nodeIsUserSelectNone(deprecatedNode()->parentNode()); |
894 | 932 |
895 if (isHTMLHtmlElement(m_anchorNode.get())) | 933 if (isHTMLHtmlElement(m_anchorNode.get())) |
896 return false; | 934 return false; |
897 | 935 |
898 if (renderer->isRenderBlockFlow()) { | 936 if (renderer->isRenderBlockFlow()) { |
899 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName (bodyTag)) { | 937 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName (bodyTag)) { |
900 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer )) | 938 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer )) |
901 return atFirstEditingPositionForNode() && !Position::nodeIsUserS electNone(deprecatedNode()); | 939 return atFirstEditingPositionForNode() && !Position::nodeIsUserS electNone(deprecatedNode()); |
902 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSe lectNone(deprecatedNode()) && atEditingBoundary(); | 940 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSe lectNone(deprecatedNode()) && atEditingBoundary(); |
903 } | 941 } |
904 } else { | 942 } else { |
905 Frame* frame = m_anchorNode->document().frame(); | 943 Frame* frame = m_anchorNode->document().frame(); |
906 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsi ngEnabled(); | 944 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsi ngEnabled(); |
907 return (caretBrowsing || m_anchorNode->rendererIsEditable()) && !Positio n::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary(); | 945 return (caretBrowsing || m_anchorNode->rendererIsEditable()) && !Positio n::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary(); |
908 } | 946 } |
909 | 947 |
910 return false; | 948 return false; |
911 } | 949 } |
912 | 950 |
913 bool Position::inRenderedText() const | 951 bool Position::inRenderedText() const |
914 { | 952 { |
915 if (isNull() || !deprecatedNode()->isTextNode()) | 953 RenderObject* renderer = rendererOfAnchorNode(); |
954 if (!renderer || !renderer->isText()) | |
916 return false; | 955 return false; |
917 | 956 |
918 RenderObject* renderer = deprecatedNode()->renderer(); | 957 RenderText* textRenderer = toRenderText(renderer); |
919 if (!renderer) | 958 int offset = m_offset - textRenderer->textStartOffset(); |
920 return false; | |
921 | |
922 RenderText *textRenderer = toRenderText(renderer); | |
923 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next TextBox()) { | 959 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next TextBox()) { |
924 if (m_offset < static_cast<int>(box->start()) && !textRenderer->contains ReversedText()) { | 960 if (offset < static_cast<int>(box->start()) && !textRenderer->containsRe versedText()) { |
925 // The offset we're looking for is before this node | 961 // The offset we're looking for is before this node |
926 // this means the offset must be in content that is | 962 // this means the offset must be in content that is |
927 // not rendered. Return false. | 963 // not rendered. Return false. |
928 return false; | 964 return false; |
929 } | 965 } |
930 if (box->containsCaretOffset(m_offset)) | 966 if (box->containsCaretOffset(offset)) { |
931 // Return false for offsets inside composed characters. | 967 // Return false for offsets inside composed characters. |
932 return m_offset == 0 || m_offset == textRenderer->nextOffset(textRen derer->previousOffset(m_offset)); | 968 return !offset || offset == textRenderer->nextOffset(textRenderer->p reviousOffset(offset)); |
969 } | |
933 } | 970 } |
934 | 971 |
935 return false; | 972 return false; |
936 } | 973 } |
937 | 974 |
938 bool Position::isRenderedCharacter() const | 975 bool Position::isRenderedCharacter() const |
939 { | 976 { |
940 if (isNull() || !deprecatedNode()->isTextNode()) | 977 RenderObject* renderer = rendererOfAnchorNode(); |
941 return false; | 978 if (!renderer || !renderer->isText()) |
942 | |
943 RenderObject* renderer = deprecatedNode()->renderer(); | |
944 if (!renderer) | |
945 return false; | 979 return false; |
946 | 980 |
947 RenderText* textRenderer = toRenderText(renderer); | 981 RenderText* textRenderer = toRenderText(renderer); |
982 int offset = m_offset - textRenderer->textStartOffset(); | |
948 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->next TextBox()) { | 983 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->next TextBox()) { |
949 if (m_offset < static_cast<int>(box->start()) && !textRenderer->contains ReversedText()) { | 984 if (offset < static_cast<int>(box->start()) && !textRenderer->containsRe versedText()) { |
950 // The offset we're looking for is before this node | 985 // The offset we're looking for is before this node |
951 // this means the offset must be in content that is | 986 // this means the offset must be in content that is |
952 // not rendered. Return false. | 987 // not rendered. Return false. |
953 return false; | 988 return false; |
954 } | 989 } |
955 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast <int>(box->start() + box->len())) | 990 if (offset >= static_cast<int>(box->start()) && offset < static_cast<int >(box->start() + box->len())) |
956 return true; | 991 return true; |
957 } | 992 } |
958 | 993 |
959 return false; | 994 return false; |
960 } | 995 } |
961 | 996 |
962 bool Position::rendersInDifferentPosition(const Position &pos) const | 997 bool Position::rendersInDifferentPosition(const Position &pos) const |
963 { | 998 { |
964 if (isNull() || pos.isNull()) | 999 RenderObject* renderer = rendererOfAnchorNode(); |
965 return false; | |
966 | |
967 RenderObject* renderer = deprecatedNode()->renderer(); | |
968 if (!renderer) | 1000 if (!renderer) |
969 return false; | 1001 return false; |
970 | 1002 |
971 RenderObject* posRenderer = pos.deprecatedNode()->renderer(); | 1003 RenderObject* posRenderer = pos.rendererOfAnchorNode(); |
972 if (!posRenderer) | 1004 if (!posRenderer) |
973 return false; | 1005 return false; |
974 | 1006 |
975 if (renderer->style()->visibility() != VISIBLE || | 1007 if (renderer->style()->visibility() != VISIBLE || |
976 posRenderer->style()->visibility() != VISIBLE) | 1008 posRenderer->style()->visibility() != VISIBLE) |
977 return false; | 1009 return false; |
978 | 1010 |
979 if (deprecatedNode() == pos.deprecatedNode()) { | 1011 if (deprecatedNode() == pos.deprecatedNode()) { |
980 if (deprecatedNode()->hasTagName(brTag)) | 1012 if (deprecatedNode()->hasTagName(brTag)) |
981 return false; | 1013 return false; |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1142 while (position != lastPosition) { | 1174 while (position != lastPosition) { |
1143 lastPosition = position; | 1175 lastPosition = position; |
1144 position = position.upstream(CanCrossEditingBoundary); | 1176 position = position.upstream(CanCrossEditingBoundary); |
1145 } | 1177 } |
1146 return position; | 1178 return position; |
1147 } | 1179 } |
1148 | 1180 |
1149 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi rection, InlineBox*& inlineBox, int& caretOffset) const | 1181 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi rection, InlineBox*& inlineBox, int& caretOffset) const |
1150 { | 1182 { |
1151 caretOffset = deprecatedEditingOffset(); | 1183 caretOffset = deprecatedEditingOffset(); |
1152 RenderObject* renderer = deprecatedNode()->renderer(); | 1184 RenderObject* renderer = rendererOfAnchorNode(); |
1153 | 1185 |
1154 if (!renderer->isText()) { | 1186 if (!renderer->isText()) { |
1155 inlineBox = 0; | 1187 inlineBox = 0; |
1156 if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isRenderBlo ckFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) { | 1188 if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isRenderBlo ckFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) { |
1157 // Try a visually equivalent position with possibly opposite editabi lity. This helps in case |this| is in | 1189 // Try a visually equivalent position with possibly opposite editabi lity. This helps in case |this| is in |
1158 // an editable block but surrounded by non-editable positions. It ac ts to negate the logic at the beginning | 1190 // an editable block but surrounded by non-editable positions. It ac ts to negate the logic at the beginning |
1159 // of RenderObject::createVisiblePosition(). | 1191 // of RenderObject::createVisiblePosition(). |
1160 Position equivalent = downstreamIgnoringEditingBoundaries(*this); | 1192 Position equivalent = downstreamIgnoringEditingBoundaries(*this); |
1161 if (equivalent == *this) { | 1193 if (equivalent == *this) { |
1162 equivalent = upstreamIgnoringEditingBoundaries(*this); | 1194 equivalent = upstreamIgnoringEditingBoundaries(*this); |
1163 if (equivalent == *this || downstreamIgnoringEditingBoundaries(e quivalent) == *this) | 1195 if (equivalent == *this || downstreamIgnoringEditingBoundaries(e quivalent) == *this) |
1164 return; | 1196 return; |
1165 } | 1197 } |
1166 | 1198 |
1167 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineB ox, caretOffset); | 1199 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineB ox, caretOffset); |
1168 return; | 1200 return; |
1169 } | 1201 } |
1170 if (renderer->isBox()) { | 1202 if (renderer->isBox()) { |
1171 inlineBox = toRenderBox(renderer)->inlineBoxWrapper(); | 1203 inlineBox = toRenderBox(renderer)->inlineBoxWrapper(); |
1172 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care tOffset < inlineBox->caretMaxOffset())) | 1204 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care tOffset < inlineBox->caretMaxOffset())) |
1173 return; | 1205 return; |
1174 } | 1206 } |
1175 } else { | 1207 } else { |
1176 RenderText* textRenderer = toRenderText(renderer); | 1208 RenderText* textRenderer = toRenderText(renderer); |
1177 | 1209 |
1178 InlineTextBox* box; | 1210 InlineTextBox* box; |
1179 InlineTextBox* candidate = 0; | 1211 InlineTextBox* candidate = 0; |
1180 | 1212 |
1213 if (textRenderer->isTextFragment() && toRenderTextFragment(textRenderer) ->firstLetter()) { | |
1214 if (caretOffset) { | |
1215 caretOffset -= textRenderer->textStartOffset(); | |
1216 } else { | |
1217 textRenderer = toRenderTextFragment(textRenderer)->firstRenderTe xtInFirstLetter(); | |
1218 if (!textRenderer) | |
1219 return; | |
1220 } | |
1221 } | |
1222 | |
1181 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { | 1223 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { |
1182 int caretMinOffset = box->caretMinOffset(); | 1224 int caretMinOffset = box->caretMinOffset(); |
1183 int caretMaxOffset = box->caretMaxOffset(); | 1225 int caretMaxOffset = box->caretMaxOffset(); |
1184 | 1226 |
1185 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak())) | 1227 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak())) |
1186 continue; | 1228 continue; |
1187 | 1229 |
1188 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) { | 1230 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) { |
1189 inlineBox = box; | 1231 inlineBox = box; |
1190 return; | 1232 return; |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1384 pos.showTreeForThis(); | 1426 pos.showTreeForThis(); |
1385 } | 1427 } |
1386 | 1428 |
1387 void showTree(const WebCore::Position* pos) | 1429 void showTree(const WebCore::Position* pos) |
1388 { | 1430 { |
1389 if (pos) | 1431 if (pos) |
1390 pos->showTreeForThis(); | 1432 pos->showTreeForThis(); |
1391 } | 1433 } |
1392 | 1434 |
1393 #endif | 1435 #endif |
OLD | NEW |