Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Side by Side Diff: Source/core/dom/Position.cpp

Issue 20681004: Make first-letter style to work with editing Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: 2013-09-20T18:27:32 Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698