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