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

Side by Side Diff: Source/core/html/HTMLTextFormControlElement.cpp

Issue 357603003: Add functions searching a word boundary without VisualPosition to HTMLTextFormControlElement. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Remove the SpellChecker change Created 6 years, 5 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
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public 9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 12 matching lines...) Expand all
23 */ 23 */
24 24
25 #include "config.h" 25 #include "config.h"
26 #include "core/html/HTMLTextFormControlElement.h" 26 #include "core/html/HTMLTextFormControlElement.h"
27 27
28 #include "bindings/core/v8/ExceptionState.h" 28 #include "bindings/core/v8/ExceptionState.h"
29 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 29 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
30 #include "core/HTMLNames.h" 30 #include "core/HTMLNames.h"
31 #include "core/accessibility/AXObjectCache.h" 31 #include "core/accessibility/AXObjectCache.h"
32 #include "core/dom/Document.h" 32 #include "core/dom/Document.h"
33 #include "core/dom/NodeList.h"
33 #include "core/dom/NodeTraversal.h" 34 #include "core/dom/NodeTraversal.h"
34 #include "core/dom/Text.h" 35 #include "core/dom/Text.h"
35 #include "core/dom/shadow/ShadowRoot.h" 36 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/editing/FrameSelection.h" 37 #include "core/editing/FrameSelection.h"
37 #include "core/editing/TextIterator.h" 38 #include "core/editing/TextIterator.h"
38 #include "core/events/Event.h" 39 #include "core/events/Event.h"
39 #include "core/frame/LocalFrame.h" 40 #include "core/frame/LocalFrame.h"
40 #include "core/frame/UseCounter.h" 41 #include "core/frame/UseCounter.h"
41 #include "core/html/HTMLBRElement.h" 42 #include "core/html/HTMLBRElement.h"
42 #include "core/html/shadow/ShadowElementNames.h" 43 #include "core/html/shadow/ShadowElementNames.h"
43 #include "core/rendering/RenderBlock.h" 44 #include "core/rendering/RenderBlock.h"
44 #include "core/rendering/RenderTheme.h" 45 #include "core/rendering/RenderTheme.h"
45 #include "platform/heap/Handle.h" 46 #include "platform/heap/Handle.h"
47 #include "platform/text/TextBoundaries.h"
46 #include "wtf/text/StringBuilder.h" 48 #include "wtf/text/StringBuilder.h"
47 49
48 namespace WebCore { 50 namespace WebCore {
49 51
50 using namespace HTMLNames; 52 using namespace HTMLNames;
51 53
52 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagN ame, Document& doc, HTMLFormElement* form) 54 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagN ame, Document& doc, HTMLFormElement* form)
53 : HTMLFormControlElementWithState(tagName, doc, form) 55 : HTMLFormControlElementWithState(tagName, doc, form)
54 , m_lastChangeWasUserEdit(false) 56 , m_lastChangeWasUserEdit(false)
55 , m_cachedSelectionStart(0) 57 , m_cachedSelectionStart(0)
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 } 654 }
653 655
654 return "ltr"; 656 return "ltr";
655 } 657 }
656 658
657 HTMLElement* HTMLTextFormControlElement::innerEditorElement() const 659 HTMLElement* HTMLTextFormControlElement::innerEditorElement() const
658 { 660 {
659 return toHTMLElement(userAgentShadowRoot()->getElementById(ShadowElementName s::innerEditor())); 661 return toHTMLElement(userAgentShadowRoot()->getElementById(ShadowElementName s::innerEditor()));
660 } 662 }
661 663
664 static Position innerNodePosition(const Position& innerPosition)
665 {
666 HTMLElement* element = toHTMLElement(innerPosition.anchorNode());
667 RefPtrWillBeRawPtr<NodeList> childNodes = element->childNodes();
668 if (!childNodes->length())
669 return Position(element, 0, Position::PositionIsOffsetInAnchor);
670
671 unsigned offset = 0;
672
673 switch (innerPosition.anchorType()) {
674 case Position::PositionIsOffsetInAnchor:
675 {
676 offset = std::max(0, std::min(innerPosition.computeOffsetInContainer Node(), (int)childNodes->length()));
677 break;
678 }
679 case Position::PositionIsAfterChildren:
680 {
681 offset = childNodes->length();
682 break;
683 }
684 default:
685 break;
686 }
687
688 if (offset == childNodes->length()) {
689 return Position(childNodes->item(childNodes->length() - 1), Position::Po sitionIsAfterAnchor);
690 }
691
692 Node* node = childNodes->item(offset);
693 if (node->isTextNode())
694 return Position(toText(node), 0);
695
696 return Position(node, Position::PositionIsBeforeAnchor);
697 }
698
699 static Position findWordBoundary(const HTMLElement* innerText, const Position& s tartPosition, const Position endPosition, bool findStart)
yosin_UTC9 2014/07/03 04:05:10 nit: |innerText| => |innerEditor|
yoichio 2014/07/03 04:32:19 Done.
700 {
701 Vector<UChar> characters;
702 Vector<unsigned> lengthList;
703 Vector<Text*> textList;
704 // Trace text nodes.
705 for (Node* node = startPosition.anchorNode(); node; node = NodeTraversal::ne xt(*node, innerText)) {
706 bool isStartNode = node == startPosition.anchorNode();
707 bool isEndNode = node == endPosition.anchorNode();
708 if (node->isTextNode()) {
709 Text* text = toText(node);
710 const unsigned start = isStartNode ? startPosition.computeOffsetInCo ntainerNode() : 0;
711 const unsigned end = isEndNode ? endPosition.computeOffsetInContaine rNode() : text->data().length();
712 for (unsigned offset = start; offset < end; ++offset)
713 characters.append(text->data()[offset]);
714 const unsigned length = end - start;
715
716 lengthList.append(length);
717 textList.append(text);
718 }
719
720 if (isEndNode)
721 break;
722 }
723
724 if (!characters.size())
725 return startPosition;
726
727 int start, end;
728 if (!findStart && characters.data()[0] == '\n') {
729 // findWordBoundary("\ntext", 0, &start, &end) assigns 1 to |end| but we expect 0 at the case.
730 start = 0;
731 end = 0;
732 } else {
733 findWordBoundary(characters.data(), characters.size(), findStart ? chara cters.size() : 0, &start, &end);
734 }
735 ASSERT(start >= 0);
736 ASSERT(end >= 0);
737 unsigned restOffset = findStart ? start : end;
738 // Find position.
739 for (unsigned i = 0; i < lengthList.size(); ++i) {
740 if (restOffset <= lengthList[i])
741 return Position(textList[i], (textList[i] == startPosition.anchorNod e()) ? restOffset + startPosition.computeOffsetInContainerNode() : restOffset);
742 restOffset -= lengthList[i];
743 }
744
745 ASSERT_NOT_REACHED();
746 return Position();
747 }
748
749 Position HTMLTextFormControlElement::startOfWord(const Position& position)
750 {
751 const HTMLTextFormControlElement* textForm = enclosingTextFormControl(positi on);
752 ASSERT(textForm);
753 HTMLElement* innerText = textForm->innerEditorElement();
754
755 const Position startPosition = startOfSentence(position);
756 if (startPosition == position)
757 return position;
758 const Position endPosition = (position.anchorNode() == innerText) ? innerNod ePosition(position): position;
759
760 return findWordBoundary(innerText, startPosition, endPosition, true);
761 }
762
763 Position HTMLTextFormControlElement::endOfWord(const Position& position)
764 {
765 const HTMLTextFormControlElement* textForm = enclosingTextFormControl(positi on);
766 ASSERT(textForm);
767 HTMLElement* innerText = textForm->innerEditorElement();
768
769
770 const Position endPosition = endOfSentence(position);
771 if (endPosition == position)
772 return position;
773 const Position startPosition = (position.anchorNode() == innerText) ? innerN odePosition(position) : position;
774
775 return findWordBoundary(innerText, startPosition, endPosition, false);
776 }
777
778 static int findLastLineBreak(const Text& text, int offset)
779 {
780 for (; offset >= 0; offset--) {
yosin_UTC9 2014/07/03 04:05:10 nit: |--offset|
yoichio 2014/07/03 04:32:19 Done.
781 if (text.data()[offset] == '\n')
782 return offset;
783 }
784 return -1;
785 }
786
787 static Position endOfPrevious(const Node& node, HTMLElement* innerText)
788 {
789 Node* prev = NodeTraversal::previous(node, innerText);
790 if (!prev)
791 return Position();
792
793 if (prev->hasTagName(brTag))
794 return Position(prev, Position::PositionIsAfterAnchor);
795
796 if (prev->isTextNode()) {
797 Text* textNode = toText(prev);
798 return Position(textNode, textNode->length());
799 }
800
801 return Position();
802 }
803
804 static Position previousIfPositionIsAfterLineBreak(const Position& position, HTM LElement* innerText)
805 {
806 if (position.isNull())
807 return Position();
808
809 // Move back if position is just after line break.
810 if (isHTMLBRElement(*position.anchorNode())) {
811 switch (position.anchorType()) {
812 case Position::PositionIsAfterAnchor:
813 return Position(position.anchorNode(), Position::PositionIsBeforeAnc hor);
814 case Position::PositionIsBeforeAnchor:
815 return previousIfPositionIsAfterLineBreak(endOfPrevious(*position.an chorNode(), innerText), innerText);
816 default:
817 ASSERT_NOT_REACHED();
818 }
819 } else if (position.anchorNode()->isTextNode()) {
820 Text* textNode = toText(position.anchorNode());
821 unsigned offset = position.offsetInContainerNode();
822 if (textNode->length() == 0 || offset <= 0) {
823 return previousIfPositionIsAfterLineBreak(endOfPrevious(*position.an chorNode(), innerText), innerText);
824 }
825
826 if (offset <= textNode->length() && textNode->data()[offset - 1] == '\n' ) {
827 return Position(textNode, offset - 1);
828 }
829 }
830
831 return position;
832 }
833
834 static inline Position startOfInnerText(const HTMLTextFormControlElement* textFo rm)
yosin_UTC9 2014/07/03 04:05:10 nit: |textForm| => |textFormControl|
yoichio 2014/07/03 04:32:19 Done.
835 {
836 return Position(textForm->innerEditorElement(), 0, Position::PositionIsOffse tInAnchor);
837 }
838
839 Position HTMLTextFormControlElement::startOfSentence(const Position& position)
840 {
841 HTMLTextFormControlElement* textForm = enclosingTextFormControl(position);
yosin_UTC9 2014/07/03 04:05:10 nit: |textForm| => |textFormControl|
yoichio 2014/07/03 04:32:19 Done.
842 ASSERT(textForm);
843
844 HTMLElement* innerText = textForm->innerEditorElement();
845 if (!innerText->childNodes()->length())
846 return startOfInnerText(textForm);
847
848 const Position innerPosition = position.anchorNode() == innerText ? innerNod ePosition(position): position;
849 const Position pivotPosition = previousIfPositionIsAfterLineBreak(innerPosit ion, innerText);
850 if (pivotPosition.isNull())
851 return startOfInnerText(textForm);
852
853 for (Node* node = pivotPosition.anchorNode(); node; node = NodeTraversal::pr evious(*node, innerText)) {
854 bool isPivotNode = (node == pivotPosition.anchorNode());
855
856 if (node->isTextNode()) {
857 Text* textNode = toText(node);
858 int lastLineBreak = findLastLineBreak(*textNode, isPivotNode ? pivot Position.offsetInContainerNode() - 1 : (int)textNode->length() - 1);
859 if (lastLineBreak >= 0)
860 return Position(textNode, lastLineBreak + 1);
861 } else if (isHTMLBRElement(node) && (!isPivotNode || pivotPosition.ancho rType() == Position::PositionIsAfterAnchor)) {
862 return Position(node, Position::PositionIsAfterAnchor);
863 }
864 }
865 return startOfInnerText(textForm);
866 }
867
868 static int findFirstLineBreak(const Text& text, int offset)
869 {
870 for (; (unsigned)offset < text.length(); offset++) {
871 if (text.data()[offset] == '\n')
872 return offset;
873 }
874 return -1;
875 }
876
877 static Position endOfInnerText(const HTMLTextFormControlElement* textForm)
yosin_UTC9 2014/07/03 04:05:10 nit: |textForm| => |textFormControl|
yoichio 2014/07/03 04:32:19 Done.
878 {
879 HTMLElement* innerText = textForm->innerEditorElement();
yosin_UTC9 2014/07/03 04:05:10 nit: |innerText|=>|innerEditor|
yoichio 2014/07/03 04:32:19 Done.
880 return Position(innerText, innerText->childNodes()->length(), Position::Posi tionIsOffsetInAnchor);
881 }
882
883 Position HTMLTextFormControlElement::endOfSentence(const Position& position)
884 {
885 HTMLTextFormControlElement* textForm = enclosingTextFormControl(position);
886 ASSERT(textForm);
887
888 HTMLElement* innerText = textForm->innerEditorElement();
889 if (!innerText->childNodes()->length())
890 return startOfInnerText(textForm);
891
892 const Position pivotPosition = position.anchorNode() == innerText ? innerNod ePosition(position) : position;
893 if (pivotPosition.isNull())
894 return startOfInnerText(textForm);
895
896 for (Node* node = pivotPosition.anchorNode(); node; node = NodeTraversal::ne xt(*node, innerText)) {
897 bool isPivotNode = (node == pivotPosition.anchorNode());
898
899 if (node->isTextNode()) {
900 Text* textNode = toText(node);
901 int firstLineBreak = findFirstLineBreak(*textNode, isPivotNode ? piv otPosition.offsetInContainerNode() : 0);
902 if (firstLineBreak >= 0)
903 return Position(textNode, firstLineBreak + 1);
904 } else if (isHTMLBRElement(node)) {
905 return Position(node, Position::PositionIsAfterAnchor);
906 }
907 }
908 return endOfInnerText(textForm);
909 }
910
662 } // namespace Webcore 911 } // namespace Webcore
OLDNEW
« no previous file with comments | « Source/core/html/HTMLTextFormControlElement.h ('k') | Source/core/html/HTMLTextFormControlElementTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698