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

Side by Side Diff: third_party/WebKit/Source/core/editing/VisibleUnits.cpp

Issue 2923153002: Move "paragraph" granularity related functions to VisibleUnitParagraph.cpp (Closed)
Patch Set: 2017-06-06T15:30:01 Created 3 years, 6 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) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights
3 * reserved. 3 * reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 798 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 // TODO(xiaochengh): |sentenceStart > range.startPosition()| is possible, 809 // TODO(xiaochengh): |sentenceStart > range.startPosition()| is possible,
810 // which would trigger a DCHECK in EphemeralRange's constructor if we return 810 // which would trigger a DCHECK in EphemeralRange's constructor if we return
811 // it directly. However, this shouldn't happen and needs to be fixed. 811 // it directly. However, this shouldn't happen and needs to be fixed.
812 return ExpandEndToSentenceBoundary(EphemeralRange( 812 return ExpandEndToSentenceBoundary(EphemeralRange(
813 sentence_start.IsNotNull() && sentence_start < range.StartPosition() 813 sentence_start.IsNotNull() && sentence_start < range.StartPosition()
814 ? sentence_start 814 ? sentence_start
815 : range.StartPosition(), 815 : range.StartPosition(),
816 range.EndPosition())); 816 range.EndPosition()));
817 } 817 }
818 818
819 static bool NodeIsUserSelectAll(const Node* node) {
820 return node && node->GetLayoutObject() &&
821 node->GetLayoutObject()->Style()->UserSelect() == EUserSelect::kAll;
822 }
823
824 template <typename Strategy>
825 PositionTemplate<Strategy> StartOfParagraphAlgorithm(
826 const PositionTemplate<Strategy>& position,
827 EditingBoundaryCrossingRule boundary_crossing_rule) {
828 Node* const start_node = position.AnchorNode();
829
830 if (!start_node)
831 return PositionTemplate<Strategy>();
832
833 if (IsRenderedAsNonInlineTableImageOrHR(start_node))
834 return PositionTemplate<Strategy>::BeforeNode(start_node);
835
836 Element* const start_block = EnclosingBlock(
837 PositionTemplate<Strategy>::FirstPositionInOrBeforeNode(start_node),
838 kCannotCrossEditingBoundary);
839 ContainerNode* const highest_root = HighestEditableRoot(position);
840 const bool start_node_is_editable = HasEditableStyle(*start_node);
841
842 Node* candidate_node = start_node;
843 PositionAnchorType candidate_type = position.AnchorType();
844 int candidate_offset = position.ComputeEditingOffset();
845
846 Node* previous_node_iterator = start_node;
847 while (previous_node_iterator) {
848 if (boundary_crossing_rule == kCannotCrossEditingBoundary &&
849 !NodeIsUserSelectAll(previous_node_iterator) &&
850 HasEditableStyle(*previous_node_iterator) != start_node_is_editable)
851 break;
852 if (boundary_crossing_rule == kCanSkipOverEditingBoundary) {
853 while (previous_node_iterator &&
854 HasEditableStyle(*previous_node_iterator) !=
855 start_node_is_editable) {
856 previous_node_iterator =
857 Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
858 }
859 if (!previous_node_iterator ||
860 !previous_node_iterator->IsDescendantOf(highest_root))
861 break;
862 }
863
864 const LayoutItem layout_item =
865 LayoutItem(previous_node_iterator->GetLayoutObject());
866 if (layout_item.IsNull()) {
867 previous_node_iterator =
868 Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
869 continue;
870 }
871 const ComputedStyle& style = layout_item.StyleRef();
872 if (style.Visibility() != EVisibility::kVisible) {
873 previous_node_iterator =
874 Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
875 continue;
876 }
877
878 if (layout_item.IsBR() || IsEnclosingBlock(previous_node_iterator))
879 break;
880
881 if (layout_item.IsText() &&
882 ToLayoutText(previous_node_iterator->GetLayoutObject())
883 ->ResolvedTextLength()) {
884 SECURITY_DCHECK(previous_node_iterator->IsTextNode());
885 if (style.PreserveNewline()) {
886 LayoutText* text =
887 ToLayoutText(previous_node_iterator->GetLayoutObject());
888 int index = text->TextLength();
889 if (previous_node_iterator == start_node && candidate_offset < index)
890 index = max(0, candidate_offset);
891 while (--index >= 0) {
892 if ((*text)[index] == '\n')
893 return PositionTemplate<Strategy>(ToText(previous_node_iterator),
894 index + 1);
895 }
896 }
897 candidate_node = previous_node_iterator;
898 candidate_type = PositionAnchorType::kOffsetInAnchor;
899 candidate_offset = 0;
900 previous_node_iterator =
901 Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
902 } else if (EditingIgnoresContent(*previous_node_iterator) ||
903 IsDisplayInsideTable(previous_node_iterator)) {
904 candidate_node = previous_node_iterator;
905 candidate_type = PositionAnchorType::kBeforeAnchor;
906 previous_node_iterator = previous_node_iterator->previousSibling()
907 ? previous_node_iterator->previousSibling()
908 : Strategy::PreviousPostOrder(
909 *previous_node_iterator, start_block);
910 } else {
911 previous_node_iterator =
912 Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
913 }
914 }
915
916 if (candidate_type == PositionAnchorType::kOffsetInAnchor)
917 return PositionTemplate<Strategy>(candidate_node, candidate_offset);
918
919 return PositionTemplate<Strategy>(candidate_node, candidate_type);
920 }
921
922 template <typename Strategy>
923 VisiblePositionTemplate<Strategy> StartOfParagraphAlgorithm(
924 const VisiblePositionTemplate<Strategy>& visible_position,
925 EditingBoundaryCrossingRule boundary_crossing_rule) {
926 DCHECK(visible_position.IsValid()) << visible_position;
927 return CreateVisiblePosition(StartOfParagraphAlgorithm(
928 visible_position.DeepEquivalent(), boundary_crossing_rule));
929 }
930
931 VisiblePosition StartOfParagraph(
932 const VisiblePosition& c,
933 EditingBoundaryCrossingRule boundary_crossing_rule) {
934 return StartOfParagraphAlgorithm<EditingStrategy>(c, boundary_crossing_rule);
935 }
936
937 VisiblePositionInFlatTree StartOfParagraph(
938 const VisiblePositionInFlatTree& c,
939 EditingBoundaryCrossingRule boundary_crossing_rule) {
940 return StartOfParagraphAlgorithm<EditingInFlatTreeStrategy>(
941 c, boundary_crossing_rule);
942 }
943
944 template <typename Strategy>
945 static PositionTemplate<Strategy> EndOfParagraphAlgorithm(
946 const PositionTemplate<Strategy>& position,
947 EditingBoundaryCrossingRule boundary_crossing_rule) {
948 Node* const start_node = position.AnchorNode();
949
950 if (!start_node)
951 return PositionTemplate<Strategy>();
952
953 if (IsRenderedAsNonInlineTableImageOrHR(start_node))
954 return PositionTemplate<Strategy>::AfterNode(start_node);
955
956 Element* const start_block = EnclosingBlock(
957 PositionTemplate<Strategy>::FirstPositionInOrBeforeNode(start_node),
958 kCannotCrossEditingBoundary);
959 ContainerNode* const highest_root = HighestEditableRoot(position);
960 const bool start_node_is_editable = HasEditableStyle(*start_node);
961
962 Node* candidate_node = start_node;
963 PositionAnchorType candidate_type = position.AnchorType();
964 int candidate_offset = position.ComputeEditingOffset();
965
966 Node* next_node_iterator = start_node;
967 while (next_node_iterator) {
968 if (boundary_crossing_rule == kCannotCrossEditingBoundary &&
969 !NodeIsUserSelectAll(next_node_iterator) &&
970 HasEditableStyle(*next_node_iterator) != start_node_is_editable)
971 break;
972 if (boundary_crossing_rule == kCanSkipOverEditingBoundary) {
973 while (next_node_iterator &&
974 HasEditableStyle(*next_node_iterator) != start_node_is_editable)
975 next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
976 if (!next_node_iterator ||
977 !next_node_iterator->IsDescendantOf(highest_root))
978 break;
979 }
980
981 LayoutObject* const layout_object = next_node_iterator->GetLayoutObject();
982 if (!layout_object) {
983 next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
984 continue;
985 }
986 const ComputedStyle& style = layout_object->StyleRef();
987 if (style.Visibility() != EVisibility::kVisible) {
988 next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
989 continue;
990 }
991
992 if (layout_object->IsBR() || IsEnclosingBlock(next_node_iterator))
993 break;
994
995 // FIXME: We avoid returning a position where the layoutObject can't accept
996 // the caret.
997 if (layout_object->IsText() &&
998 ToLayoutText(layout_object)->ResolvedTextLength()) {
999 SECURITY_DCHECK(next_node_iterator->IsTextNode());
1000 LayoutText* const text = ToLayoutText(layout_object);
1001 if (style.PreserveNewline()) {
1002 const int length = ToLayoutText(layout_object)->TextLength();
1003 for (int i = (next_node_iterator == start_node ? candidate_offset : 0);
1004 i < length; ++i) {
1005 if ((*text)[i] == '\n')
1006 return PositionTemplate<Strategy>(ToText(next_node_iterator),
1007 i + text->TextStartOffset());
1008 }
1009 }
1010
1011 candidate_node = next_node_iterator;
1012 candidate_type = PositionAnchorType::kOffsetInAnchor;
1013 candidate_offset =
1014 layout_object->CaretMaxOffset() + text->TextStartOffset();
1015 next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
1016 } else if (EditingIgnoresContent(*next_node_iterator) ||
1017 IsDisplayInsideTable(next_node_iterator)) {
1018 candidate_node = next_node_iterator;
1019 candidate_type = PositionAnchorType::kAfterAnchor;
1020 next_node_iterator =
1021 Strategy::NextSkippingChildren(*next_node_iterator, start_block);
1022 } else {
1023 next_node_iterator = Strategy::Next(*next_node_iterator, start_block);
1024 }
1025 }
1026
1027 if (candidate_type == PositionAnchorType::kOffsetInAnchor)
1028 return PositionTemplate<Strategy>(candidate_node, candidate_offset);
1029
1030 return PositionTemplate<Strategy>(candidate_node, candidate_type);
1031 }
1032
1033 template <typename Strategy>
1034 static VisiblePositionTemplate<Strategy> EndOfParagraphAlgorithm(
1035 const VisiblePositionTemplate<Strategy>& visible_position,
1036 EditingBoundaryCrossingRule boundary_crossing_rule) {
1037 DCHECK(visible_position.IsValid()) << visible_position;
1038 return CreateVisiblePosition(EndOfParagraphAlgorithm(
1039 visible_position.DeepEquivalent(), boundary_crossing_rule));
1040 }
1041
1042 VisiblePosition EndOfParagraph(
1043 const VisiblePosition& c,
1044 EditingBoundaryCrossingRule boundary_crossing_rule) {
1045 return EndOfParagraphAlgorithm<EditingStrategy>(c, boundary_crossing_rule);
1046 }
1047
1048 VisiblePositionInFlatTree EndOfParagraph(
1049 const VisiblePositionInFlatTree& c,
1050 EditingBoundaryCrossingRule boundary_crossing_rule) {
1051 return EndOfParagraphAlgorithm<EditingInFlatTreeStrategy>(
1052 c, boundary_crossing_rule);
1053 }
1054
1055 // FIXME: isStartOfParagraph(startOfNextParagraph(pos)) is not always true
1056 VisiblePosition StartOfNextParagraph(const VisiblePosition& visible_position) {
1057 DCHECK(visible_position.IsValid()) << visible_position;
1058 VisiblePosition paragraph_end(
1059 EndOfParagraph(visible_position, kCanSkipOverEditingBoundary));
1060 VisiblePosition after_paragraph_end(
1061 NextPositionOf(paragraph_end, kCannotCrossEditingBoundary));
1062 // The position after the last position in the last cell of a table
1063 // is not the start of the next paragraph.
1064 if (TableElementJustBefore(after_paragraph_end))
1065 return NextPositionOf(after_paragraph_end, kCannotCrossEditingBoundary);
1066 return after_paragraph_end;
1067 }
1068
1069 // FIXME: isStartOfParagraph(startOfNextParagraph(pos)) is not always true
1070 bool InSameParagraph(const VisiblePosition& a,
1071 const VisiblePosition& b,
1072 EditingBoundaryCrossingRule boundary_crossing_rule) {
1073 DCHECK(a.IsValid()) << a;
1074 DCHECK(b.IsValid()) << b;
1075 return a.IsNotNull() &&
1076 StartOfParagraph(a, boundary_crossing_rule).DeepEquivalent() ==
1077 StartOfParagraph(b, boundary_crossing_rule).DeepEquivalent();
1078 }
1079
1080 template <typename Strategy>
1081 static bool IsStartOfParagraphAlgorithm(
1082 const VisiblePositionTemplate<Strategy>& pos,
1083 EditingBoundaryCrossingRule boundary_crossing_rule) {
1084 DCHECK(pos.IsValid()) << pos;
1085 return pos.IsNotNull() &&
1086 pos.DeepEquivalent() ==
1087 StartOfParagraph(pos, boundary_crossing_rule).DeepEquivalent();
1088 }
1089
1090 bool IsStartOfParagraph(const VisiblePosition& pos,
1091 EditingBoundaryCrossingRule boundary_crossing_rule) {
1092 return IsStartOfParagraphAlgorithm<EditingStrategy>(pos,
1093 boundary_crossing_rule);
1094 }
1095
1096 bool IsStartOfParagraph(const VisiblePositionInFlatTree& pos,
1097 EditingBoundaryCrossingRule boundary_crossing_rule) {
1098 return IsStartOfParagraphAlgorithm<EditingInFlatTreeStrategy>(
1099 pos, boundary_crossing_rule);
1100 }
1101
1102 template <typename Strategy>
1103 static bool IsEndOfParagraphAlgorithm(
1104 const VisiblePositionTemplate<Strategy>& pos,
1105 EditingBoundaryCrossingRule boundary_crossing_rule) {
1106 DCHECK(pos.IsValid()) << pos;
1107 return pos.IsNotNull() &&
1108 pos.DeepEquivalent() ==
1109 EndOfParagraph(pos, boundary_crossing_rule).DeepEquivalent();
1110 }
1111
1112 bool IsEndOfParagraph(const VisiblePosition& pos,
1113 EditingBoundaryCrossingRule boundary_crossing_rule) {
1114 return IsEndOfParagraphAlgorithm<EditingStrategy>(pos,
1115 boundary_crossing_rule);
1116 }
1117
1118 bool IsEndOfParagraph(const VisiblePositionInFlatTree& pos,
1119 EditingBoundaryCrossingRule boundary_crossing_rule) {
1120 return IsEndOfParagraphAlgorithm<EditingInFlatTreeStrategy>(
1121 pos, boundary_crossing_rule);
1122 }
1123
1124 VisiblePosition PreviousParagraphPosition(const VisiblePosition& p,
1125 LayoutUnit x) {
1126 DCHECK(p.IsValid()) << p;
1127 VisiblePosition pos = p;
1128 do {
1129 VisiblePosition n = PreviousLinePosition(pos, x);
1130 if (n.IsNull() || n.DeepEquivalent() == pos.DeepEquivalent())
1131 break;
1132 pos = n;
1133 } while (InSameParagraph(p, pos));
1134 return pos;
1135 }
1136
1137 VisiblePosition NextParagraphPosition(const VisiblePosition& p, LayoutUnit x) {
1138 DCHECK(p.IsValid()) << p;
1139 VisiblePosition pos = p;
1140 do {
1141 VisiblePosition n = NextLinePosition(pos, x);
1142 if (n.IsNull() || n.DeepEquivalent() == pos.DeepEquivalent())
1143 break;
1144 pos = n;
1145 } while (InSameParagraph(p, pos));
1146 return pos;
1147 }
1148
1149 EphemeralRange ExpandToParagraphBoundary(const EphemeralRange& range) {
1150 const VisiblePosition& start = CreateVisiblePosition(range.StartPosition());
1151 DCHECK(start.IsNotNull()) << range.StartPosition();
1152 const Position& paragraph_start = StartOfParagraph(start).DeepEquivalent();
1153 DCHECK(paragraph_start.IsNotNull()) << range.StartPosition();
1154
1155 const VisiblePosition& end = CreateVisiblePosition(range.EndPosition());
1156 DCHECK(end.IsNotNull()) << range.EndPosition();
1157 const Position& paragraph_end = EndOfParagraph(end).DeepEquivalent();
1158 DCHECK(paragraph_end.IsNotNull()) << range.EndPosition();
1159
1160 // TODO(xiaochengh): There are some cases (crbug.com/640112) where we get
1161 // |paragraphStart > paragraphEnd|, which is the reason we cannot directly
1162 // return |EphemeralRange(paragraphStart, paragraphEnd)|. This is not
1163 // desired, though. We should do more investigation to ensure that why
1164 // |paragraphStart <= paragraphEnd| is violated.
1165 const Position& result_start =
1166 paragraph_start.IsNotNull() && paragraph_start <= range.StartPosition()
1167 ? paragraph_start
1168 : range.StartPosition();
1169 const Position& result_end =
1170 paragraph_end.IsNotNull() && paragraph_end >= range.EndPosition()
1171 ? paragraph_end
1172 : range.EndPosition();
1173 return EphemeralRange(result_start, result_end);
1174 }
1175
1176 // --------- 819 // ---------
1177 820
1178 VisiblePosition StartOfBlock(const VisiblePosition& visible_position, 821 VisiblePosition StartOfBlock(const VisiblePosition& visible_position,
1179 EditingBoundaryCrossingRule rule) { 822 EditingBoundaryCrossingRule rule) {
1180 DCHECK(visible_position.IsValid()) << visible_position; 823 DCHECK(visible_position.IsValid()) << visible_position;
1181 Position position = visible_position.DeepEquivalent(); 824 Position position = visible_position.DeepEquivalent();
1182 Element* start_block = 825 Element* start_block =
1183 position.ComputeContainerNode() 826 position.ComputeContainerNode()
1184 ? EnclosingBlock(position.ComputeContainerNode(), rule) 827 ? EnclosingBlock(position.ComputeContainerNode(), rule)
1185 : 0; 828 : 0;
(...skipping 1951 matching lines...) Expand 10 before | Expand all | Expand 10 after
3137 2780
3138 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) { 2781 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) {
3139 return EnclosingIntRect(ComputeTextRectTemplate(range)); 2782 return EnclosingIntRect(ComputeTextRectTemplate(range));
3140 } 2783 }
3141 2784
3142 FloatRect ComputeTextFloatRect(const EphemeralRange& range) { 2785 FloatRect ComputeTextFloatRect(const EphemeralRange& range) {
3143 return ComputeTextRectTemplate(range); 2786 return ComputeTextRectTemplate(range);
3144 } 2787 }
3145 2788
3146 } // namespace blink 2789 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/BUILD.gn ('k') | third_party/WebKit/Source/core/editing/VisibleUnitsParagraph.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698