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

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

Issue 2914793002: Move "line" granularity related functions to VisibleUnitLine.cpp (Closed)
Patch Set: 2017-05-31T18:13:41 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 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 158
159 Position CanonicalPositionOf(const Position& position) { 159 Position CanonicalPositionOf(const Position& position) {
160 return CanonicalPosition(position); 160 return CanonicalPosition(position);
161 } 161 }
162 162
163 PositionInFlatTree CanonicalPositionOf(const PositionInFlatTree& position) { 163 PositionInFlatTree CanonicalPositionOf(const PositionInFlatTree& position) {
164 return CanonicalPosition(position); 164 return CanonicalPosition(position);
165 } 165 }
166 166
167 template <typename Strategy> 167 template <typename Strategy>
168 static PositionWithAffinityTemplate<Strategy> HonorEditingBoundaryAtOrBefore( 168 static PositionWithAffinityTemplate<Strategy>
169 HonorEditingBoundaryAtOrBeforeTemplate(
169 const PositionWithAffinityTemplate<Strategy>& pos, 170 const PositionWithAffinityTemplate<Strategy>& pos,
170 const PositionTemplate<Strategy>& anchor) { 171 const PositionTemplate<Strategy>& anchor) {
171 if (pos.IsNull()) 172 if (pos.IsNull())
172 return pos; 173 return pos;
173 174
174 ContainerNode* highest_root = HighestEditableRoot(anchor); 175 ContainerNode* highest_root = HighestEditableRoot(anchor);
175 176
176 // Return empty position if |pos| is not somewhere inside the editable 177 // Return empty position if |pos| is not somewhere inside the editable
177 // region containing this position 178 // region containing this position
178 if (highest_root && !pos.AnchorNode()->IsDescendantOf(highest_root)) 179 if (highest_root && !pos.AnchorNode()->IsDescendantOf(highest_root))
(...skipping 12 matching lines...) Expand all
191 // TODO(yosin) Move to the previous non-editable region. 192 // TODO(yosin) Move to the previous non-editable region.
192 if (!highest_root) 193 if (!highest_root)
193 return PositionWithAffinityTemplate<Strategy>(); 194 return PositionWithAffinityTemplate<Strategy>();
194 195
195 // Return the last position before |pos| that is in the same editable region 196 // Return the last position before |pos| that is in the same editable region
196 // as this position 197 // as this position
197 return LastEditablePositionBeforePositionInRoot(pos.GetPosition(), 198 return LastEditablePositionBeforePositionInRoot(pos.GetPosition(),
198 *highest_root); 199 *highest_root);
199 } 200 }
200 201
202 PositionWithAffinity HonorEditingBoundaryAtOrBefore(
203 const PositionWithAffinity& pos,
204 const Position& anchor) {
205 return HonorEditingBoundaryAtOrBeforeTemplate(pos, anchor);
206 }
207
208 PositionInFlatTreeWithAffinity HonorEditingBoundaryAtOrBefore(
209 const PositionInFlatTreeWithAffinity& pos,
210 const PositionInFlatTree& anchor) {
211 return HonorEditingBoundaryAtOrBeforeTemplate(pos, anchor);
212 }
213
201 template <typename Strategy> 214 template <typename Strategy>
202 VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrBeforeAlgorithm( 215 VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrBeforeAlgorithm(
203 const VisiblePositionTemplate<Strategy>& pos, 216 const VisiblePositionTemplate<Strategy>& pos,
204 const PositionTemplate<Strategy>& anchor) { 217 const PositionTemplate<Strategy>& anchor) {
205 DCHECK(pos.IsValid()) << pos; 218 DCHECK(pos.IsValid()) << pos;
206 return CreateVisiblePosition( 219 return CreateVisiblePosition(
207 HonorEditingBoundaryAtOrBefore(pos.ToPositionWithAffinity(), anchor)); 220 HonorEditingBoundaryAtOrBefore(pos.ToPositionWithAffinity(), anchor));
208 } 221 }
209 222
210 VisiblePosition HonorEditingBoundaryAtOrBefore( 223 VisiblePosition HonorEditingBoundaryAtOrBefore(
211 const VisiblePosition& visiblePosition, 224 const VisiblePosition& visiblePosition,
212 const Position& anchor) { 225 const Position& anchor) {
213 return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor); 226 return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor);
214 } 227 }
215 228
216 VisiblePositionInFlatTree HonorEditingBoundaryAtOrBefore( 229 VisiblePositionInFlatTree HonorEditingBoundaryAtOrBefore(
217 const VisiblePositionInFlatTree& visiblePosition, 230 const VisiblePositionInFlatTree& visiblePosition,
218 const PositionInFlatTree& anchor) { 231 const PositionInFlatTree& anchor) {
219 return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor); 232 return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor);
220 } 233 }
221 234
222 template <typename Strategy> 235 template <typename Strategy>
223 static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrAfter( 236 static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrAfterTemplate(
224 const VisiblePositionTemplate<Strategy>& pos, 237 const VisiblePositionTemplate<Strategy>& pos,
225 const PositionTemplate<Strategy>& anchor) { 238 const PositionTemplate<Strategy>& anchor) {
226 DCHECK(pos.IsValid()) << pos; 239 DCHECK(pos.IsValid()) << pos;
227 if (pos.IsNull()) 240 if (pos.IsNull())
228 return pos; 241 return pos;
229 242
230 ContainerNode* highest_root = HighestEditableRoot(anchor); 243 ContainerNode* highest_root = HighestEditableRoot(anchor);
231 244
232 // Return empty position if |pos| is not somewhere inside the editable 245 // Return empty position if |pos| is not somewhere inside the editable
233 // region containing this position 246 // region containing this position
(...skipping 14 matching lines...) Expand all
248 // TODO(yosin) Move to the next non-editable region. 261 // TODO(yosin) Move to the next non-editable region.
249 if (!highest_root) 262 if (!highest_root)
250 return VisiblePositionTemplate<Strategy>(); 263 return VisiblePositionTemplate<Strategy>();
251 264
252 // Return the next position after |pos| that is in the same editable region 265 // Return the next position after |pos| that is in the same editable region
253 // as this position 266 // as this position
254 return FirstEditableVisiblePositionAfterPositionInRoot(pos.DeepEquivalent(), 267 return FirstEditableVisiblePositionAfterPositionInRoot(pos.DeepEquivalent(),
255 *highest_root); 268 *highest_root);
256 } 269 }
257 270
258 static bool HasEditableStyle(const Node& node, EditableType editable_type) { 271 VisiblePosition HonorEditingBoundaryAtOrAfter(const VisiblePosition& pos,
259 if (editable_type == kHasEditableAXRole) { 272 const Position& anchor) {
260 if (AXObjectCache* cache = node.GetDocument().ExistingAXObjectCache()) { 273 return HonorEditingBoundaryAtOrAfterTemplate(pos, anchor);
261 if (cache->RootAXEditableElement(&node))
262 return true;
263 }
264 }
265
266 return HasEditableStyle(node);
267 } 274 }
268 275
269 static Element* RootEditableElement(const Node& node, 276 VisiblePositionInFlatTree HonorEditingBoundaryAtOrAfter(
270 EditableType editable_type) { 277 const VisiblePositionInFlatTree& pos,
271 if (editable_type == kHasEditableAXRole) { 278 const PositionInFlatTree& anchor) {
272 if (AXObjectCache* cache = node.GetDocument().ExistingAXObjectCache()) 279 return HonorEditingBoundaryAtOrAfterTemplate(pos, anchor);
273 return const_cast<Element*>(cache->RootAXEditableElement(&node));
274 }
275
276 return RootEditableElement(node);
277 }
278
279 static Element* RootAXEditableElementOf(const Position& position) {
280 Node* node = position.ComputeContainerNode();
281 if (!node)
282 return 0;
283
284 if (IsDisplayInsideTable(node))
285 node = node->parentNode();
286
287 return RootEditableElement(*node, kHasEditableAXRole);
288 }
289
290 static bool HasAXEditableStyle(const Node& node) {
291 return HasEditableStyle(node, kHasEditableAXRole);
292 }
293
294 static ContainerNode* HighestEditableRoot(const Position& position,
295 EditableType editable_type) {
296 if (editable_type == kHasEditableAXRole)
297 return HighestEditableRoot(position, RootAXEditableElementOf,
298 HasAXEditableStyle);
299
300 return HighestEditableRoot(position);
301 }
302
303 static Node* PreviousLeafWithSameEditability(Node* node,
304 EditableType editable_type) {
305 bool editable = HasEditableStyle(*node, editable_type);
306 node = PreviousAtomicLeafNode(*node);
307 while (node) {
308 if (editable == HasEditableStyle(*node, editable_type))
309 return node;
310 node = PreviousAtomicLeafNode(*node);
311 }
312 return 0;
313 }
314
315 static Node* NextLeafWithSameEditability(
316 Node* node,
317 EditableType editable_type = kContentIsEditable) {
318 if (!node)
319 return 0;
320
321 bool editable = HasEditableStyle(*node, editable_type);
322 node = NextAtomicLeafNode(*node);
323 while (node) {
324 if (editable == HasEditableStyle(*node, editable_type))
325 return node;
326 node = NextAtomicLeafNode(*node);
327 }
328 return 0;
329 }
330
331 // FIXME: consolidate with code in previousLinePosition.
332 Position PreviousRootInlineBoxCandidatePosition(
333 Node* node,
334 const VisiblePosition& visible_position,
335 EditableType editable_type) {
336 DCHECK(visible_position.IsValid()) << visible_position;
337 ContainerNode* highest_root =
338 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type);
339 Node* previous_node = PreviousLeafWithSameEditability(node, editable_type);
340
341 while (previous_node &&
342 (!previous_node->GetLayoutObject() ||
343 InSameLine(
344 CreateVisiblePosition(FirstPositionInOrBeforeNode(previous_node)),
345 visible_position)))
346 previous_node =
347 PreviousLeafWithSameEditability(previous_node, editable_type);
348
349 while (previous_node && !previous_node->IsShadowRoot()) {
350 if (HighestEditableRoot(FirstPositionInOrBeforeNode(previous_node),
351 editable_type) != highest_root)
352 break;
353
354 Position pos = isHTMLBRElement(*previous_node)
355 ? Position::BeforeNode(previous_node)
356 : Position::EditingPositionOf(
357 previous_node, CaretMaxOffset(previous_node));
358
359 if (IsVisuallyEquivalentCandidate(pos))
360 return pos;
361
362 previous_node =
363 PreviousLeafWithSameEditability(previous_node, editable_type);
364 }
365 return Position();
366 }
367
368 Position NextRootInlineBoxCandidatePosition(
369 Node* node,
370 const VisiblePosition& visible_position,
371 EditableType editable_type) {
372 DCHECK(visible_position.IsValid()) << visible_position;
373 ContainerNode* highest_root =
374 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type);
375 Node* next_node = NextLeafWithSameEditability(node, editable_type);
376 while (next_node && (!next_node->GetLayoutObject() ||
377 InSameLine(CreateVisiblePosition(
378 FirstPositionInOrBeforeNode(next_node)),
379 visible_position)))
380 next_node = NextLeafWithSameEditability(next_node, kContentIsEditable);
381
382 while (next_node && !next_node->IsShadowRoot()) {
383 if (HighestEditableRoot(FirstPositionInOrBeforeNode(next_node),
384 editable_type) != highest_root)
385 break;
386
387 Position pos;
388 pos = Position::EditingPositionOf(next_node, CaretMinOffset(next_node));
389
390 if (IsVisuallyEquivalentCandidate(pos))
391 return pos;
392
393 next_node = NextLeafWithSameEditability(next_node, editable_type);
394 }
395 return Position();
396 } 280 }
397 281
398 template <typename Strategy> 282 template <typename Strategy>
399 static ContainerNode* NonShadowBoundaryParentNode(Node* node) { 283 static ContainerNode* NonShadowBoundaryParentNode(Node* node) {
400 ContainerNode* parent = Strategy::Parent(*node); 284 ContainerNode* parent = Strategy::Parent(*node);
401 return parent && !parent->IsShadowRoot() ? parent : nullptr; 285 return parent && !parent->IsShadowRoot() ? parent : nullptr;
402 } 286 }
403 287
404 template <typename Strategy> 288 template <typename Strategy>
405 static Node* ParentEditingBoundary(const PositionTemplate<Strategy>& position) { 289 static Node* ParentEditingBoundary(const PositionTemplate<Strategy>& position) {
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 686
803 VisiblePosition NextWordPosition(const VisiblePosition& c) { 687 VisiblePosition NextWordPosition(const VisiblePosition& c) {
804 DCHECK(c.IsValid()) << c; 688 DCHECK(c.IsValid()) << c;
805 VisiblePosition next = CreateVisiblePosition( 689 VisiblePosition next = CreateVisiblePosition(
806 NextBoundary(c, NextWordPositionBoundary), VP_UPSTREAM_IF_POSSIBLE); 690 NextBoundary(c, NextWordPositionBoundary), VP_UPSTREAM_IF_POSSIBLE);
807 return HonorEditingBoundaryAtOrAfter(next, c.DeepEquivalent()); 691 return HonorEditingBoundaryAtOrAfter(next, c.DeepEquivalent());
808 } 692 }
809 693
810 // --------- 694 // ---------
811 695
812 enum LineEndpointComputationMode { kUseLogicalOrdering, kUseInlineBoxOrdering };
813 template <typename Strategy>
814 static PositionWithAffinityTemplate<Strategy> StartPositionForLine(
815 const PositionWithAffinityTemplate<Strategy>& c,
816 LineEndpointComputationMode mode) {
817 if (c.IsNull())
818 return PositionWithAffinityTemplate<Strategy>();
819
820 RootInlineBox* root_box =
821 RenderedPosition(c.GetPosition(), c.Affinity()).RootBox();
822 if (!root_box) {
823 // There are VisiblePositions at offset 0 in blocks without
824 // RootInlineBoxes, like empty editable blocks and bordered blocks.
825 PositionTemplate<Strategy> p = c.GetPosition();
826 if (p.AnchorNode()->GetLayoutObject() &&
827 p.AnchorNode()->GetLayoutObject()->IsLayoutBlock() &&
828 !p.ComputeEditingOffset())
829 return c;
830
831 return PositionWithAffinityTemplate<Strategy>();
832 }
833
834 Node* start_node;
835 InlineBox* start_box;
836 if (mode == kUseLogicalOrdering) {
837 start_node = root_box->GetLogicalStartBoxWithNode(start_box);
838 if (!start_node)
839 return PositionWithAffinityTemplate<Strategy>();
840 } else {
841 // Generated content (e.g. list markers and CSS :before and :after
842 // pseudoelements) have no corresponding DOM element, and so cannot be
843 // represented by a VisiblePosition. Use whatever follows instead.
844 start_box = root_box->FirstLeafChild();
845 while (true) {
846 if (!start_box)
847 return PositionWithAffinityTemplate<Strategy>();
848
849 start_node = start_box->GetLineLayoutItem().NonPseudoNode();
850 if (start_node)
851 break;
852
853 start_box = start_box->NextLeafChild();
854 }
855 }
856
857 return PositionWithAffinityTemplate<Strategy>(
858 start_node->IsTextNode()
859 ? PositionTemplate<Strategy>(ToText(start_node),
860 ToInlineTextBox(start_box)->Start())
861 : PositionTemplate<Strategy>::BeforeNode(start_node));
862 }
863
864 template <typename Strategy>
865 static PositionWithAffinityTemplate<Strategy> StartOfLineAlgorithm(
866 const PositionWithAffinityTemplate<Strategy>& c) {
867 // TODO: this is the current behavior that might need to be fixed.
868 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
869 PositionWithAffinityTemplate<Strategy> vis_pos =
870 StartPositionForLine(c, kUseInlineBoxOrdering);
871 return HonorEditingBoundaryAtOrBefore(vis_pos, c.GetPosition());
872 }
873
874 static PositionWithAffinity StartOfLine(
875 const PositionWithAffinity& current_position) {
876 return StartOfLineAlgorithm<EditingStrategy>(current_position);
877 }
878
879 static PositionInFlatTreeWithAffinity StartOfLine(
880 const PositionInFlatTreeWithAffinity& current_position) {
881 return StartOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
882 }
883
884 // FIXME: Rename this function to reflect the fact it ignores bidi levels.
885 VisiblePosition StartOfLine(const VisiblePosition& current_position) {
886 DCHECK(current_position.IsValid()) << current_position;
887 return CreateVisiblePosition(
888 StartOfLine(current_position.ToPositionWithAffinity()));
889 }
890
891 VisiblePositionInFlatTree StartOfLine(
892 const VisiblePositionInFlatTree& current_position) {
893 DCHECK(current_position.IsValid()) << current_position;
894 return CreateVisiblePosition(
895 StartOfLine(current_position.ToPositionWithAffinity()));
896 }
897
898 template <typename Strategy>
899 static PositionWithAffinityTemplate<Strategy> LogicalStartOfLineAlgorithm(
900 const PositionWithAffinityTemplate<Strategy>& c) {
901 // TODO: this is the current behavior that might need to be fixed.
902 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
903 PositionWithAffinityTemplate<Strategy> vis_pos =
904 StartPositionForLine(c, kUseLogicalOrdering);
905
906 if (ContainerNode* editable_root = HighestEditableRoot(c.GetPosition())) {
907 if (!editable_root->contains(vis_pos.GetPosition().ComputeContainerNode()))
908 return PositionWithAffinityTemplate<Strategy>(
909 PositionTemplate<Strategy>::FirstPositionInNode(editable_root));
910 }
911
912 return HonorEditingBoundaryAtOrBefore(vis_pos, c.GetPosition());
913 }
914
915 VisiblePosition LogicalStartOfLine(const VisiblePosition& current_position) {
916 DCHECK(current_position.IsValid()) << current_position;
917 return CreateVisiblePosition(LogicalStartOfLineAlgorithm<EditingStrategy>(
918 current_position.ToPositionWithAffinity()));
919 }
920
921 VisiblePositionInFlatTree LogicalStartOfLine(
922 const VisiblePositionInFlatTree& current_position) {
923 DCHECK(current_position.IsValid()) << current_position;
924 return CreateVisiblePosition(
925 LogicalStartOfLineAlgorithm<EditingInFlatTreeStrategy>(
926 current_position.ToPositionWithAffinity()));
927 }
928
929 template <typename Strategy>
930 static VisiblePositionTemplate<Strategy> EndPositionForLine(
931 const VisiblePositionTemplate<Strategy>& c,
932 LineEndpointComputationMode mode) {
933 DCHECK(c.IsValid()) << c;
934 if (c.IsNull())
935 return VisiblePositionTemplate<Strategy>();
936
937 RootInlineBox* root_box = RenderedPosition(c).RootBox();
938 if (!root_box) {
939 // There are VisiblePositions at offset 0 in blocks without
940 // RootInlineBoxes, like empty editable blocks and bordered blocks.
941 const PositionTemplate<Strategy> p = c.DeepEquivalent();
942 if (p.AnchorNode()->GetLayoutObject() &&
943 p.AnchorNode()->GetLayoutObject()->IsLayoutBlock() &&
944 !p.ComputeEditingOffset())
945 return c;
946 return VisiblePositionTemplate<Strategy>();
947 }
948
949 Node* end_node;
950 InlineBox* end_box;
951 if (mode == kUseLogicalOrdering) {
952 end_node = root_box->GetLogicalEndBoxWithNode(end_box);
953 if (!end_node)
954 return VisiblePositionTemplate<Strategy>();
955 } else {
956 // Generated content (e.g. list markers and CSS :before and :after
957 // pseudo elements) have no corresponding DOM element, and so cannot be
958 // represented by a VisiblePosition. Use whatever precedes instead.
959 end_box = root_box->LastLeafChild();
960 while (true) {
961 if (!end_box)
962 return VisiblePositionTemplate<Strategy>();
963
964 end_node = end_box->GetLineLayoutItem().NonPseudoNode();
965 if (end_node)
966 break;
967
968 end_box = end_box->PrevLeafChild();
969 }
970 }
971
972 PositionTemplate<Strategy> pos;
973 if (isHTMLBRElement(*end_node)) {
974 pos = PositionTemplate<Strategy>::BeforeNode(end_node);
975 } else if (end_box->IsInlineTextBox() && end_node->IsTextNode()) {
976 InlineTextBox* end_text_box = ToInlineTextBox(end_box);
977 int end_offset = end_text_box->Start();
978 if (!end_text_box->IsLineBreak())
979 end_offset += end_text_box->Len();
980 pos = PositionTemplate<Strategy>(ToText(end_node), end_offset);
981 } else {
982 pos = PositionTemplate<Strategy>::AfterNode(end_node);
983 }
984
985 return CreateVisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
986 }
987
988 // TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
989 template <typename Strategy>
990 static VisiblePositionTemplate<Strategy> EndOfLineAlgorithm(
991 const VisiblePositionTemplate<Strategy>& current_position) {
992 DCHECK(current_position.IsValid()) << current_position;
993 // TODO(yosin) this is the current behavior that might need to be fixed.
994 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
995 VisiblePositionTemplate<Strategy> vis_pos =
996 EndPositionForLine(current_position, kUseInlineBoxOrdering);
997
998 // Make sure the end of line is at the same line as the given input
999 // position. Else use the previous position to obtain end of line. This
1000 // condition happens when the input position is before the space character
1001 // at the end of a soft-wrapped non-editable line. In this scenario,
1002 // |endPositionForLine()| would incorrectly hand back a position in the next
1003 // line instead. This fix is to account for the discrepancy between lines
1004 // with "webkit-line-break:after-white-space" style versus lines without
1005 // that style, which would break before a space by default.
1006 if (!InSameLine(current_position, vis_pos)) {
1007 vis_pos = PreviousPositionOf(current_position);
1008 if (vis_pos.IsNull())
1009 return VisiblePositionTemplate<Strategy>();
1010 vis_pos = EndPositionForLine(vis_pos, kUseInlineBoxOrdering);
1011 }
1012
1013 return HonorEditingBoundaryAtOrAfter(vis_pos,
1014 current_position.DeepEquivalent());
1015 }
1016
1017 // TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
1018 VisiblePosition EndOfLine(const VisiblePosition& current_position) {
1019 return EndOfLineAlgorithm<EditingStrategy>(current_position);
1020 }
1021
1022 VisiblePositionInFlatTree EndOfLine(
1023 const VisiblePositionInFlatTree& current_position) {
1024 return EndOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
1025 }
1026
1027 template <typename Strategy>
1028 static bool InSameLogicalLine(const VisiblePositionTemplate<Strategy>& a,
1029 const VisiblePositionTemplate<Strategy>& b) {
1030 DCHECK(a.IsValid()) << a;
1031 DCHECK(b.IsValid()) << b;
1032 return a.IsNotNull() && LogicalStartOfLine(a).DeepEquivalent() ==
1033 LogicalStartOfLine(b).DeepEquivalent();
1034 }
1035
1036 template <typename Strategy>
1037 VisiblePositionTemplate<Strategy> LogicalEndOfLineAlgorithm(
1038 const VisiblePositionTemplate<Strategy>& current_position) {
1039 DCHECK(current_position.IsValid()) << current_position;
1040 // TODO(yosin) this is the current behavior that might need to be fixed.
1041 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
1042 VisiblePositionTemplate<Strategy> vis_pos =
1043 EndPositionForLine(current_position, kUseLogicalOrdering);
1044
1045 // Make sure the end of line is at the same line as the given input
1046 // position. For a wrapping line, the logical end position for the
1047 // not-last-2-lines might incorrectly hand back the logical beginning of the
1048 // next line. For example,
1049 // <div contenteditable dir="rtl" style="line-break:before-white-space">xyz
1050 // a xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz </div>
1051 // In this case, use the previous position of the computed logical end
1052 // position.
1053 if (!InSameLogicalLine(current_position, vis_pos))
1054 vis_pos = PreviousPositionOf(vis_pos);
1055
1056 if (ContainerNode* editable_root =
1057 HighestEditableRoot(current_position.DeepEquivalent())) {
1058 if (!editable_root->contains(
1059 vis_pos.DeepEquivalent().ComputeContainerNode()))
1060 return CreateVisiblePosition(
1061 PositionTemplate<Strategy>::LastPositionInNode(editable_root));
1062 }
1063
1064 return HonorEditingBoundaryAtOrAfter(vis_pos,
1065 current_position.DeepEquivalent());
1066 }
1067
1068 VisiblePosition LogicalEndOfLine(const VisiblePosition& current_position) {
1069 return LogicalEndOfLineAlgorithm<EditingStrategy>(current_position);
1070 }
1071
1072 VisiblePositionInFlatTree LogicalEndOfLine(
1073 const VisiblePositionInFlatTree& current_position) {
1074 return LogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
1075 }
1076
1077 template <typename Strategy>
1078 bool InSameLineAlgorithm(
1079 const PositionWithAffinityTemplate<Strategy>& position1,
1080 const PositionWithAffinityTemplate<Strategy>& position2) {
1081 if (position1.IsNull() || position2.IsNull())
1082 return false;
1083 DCHECK_EQ(position1.GetDocument(), position2.GetDocument());
1084 DCHECK(!position1.GetDocument()->NeedsLayoutTreeUpdate());
1085
1086 PositionWithAffinityTemplate<Strategy> start_of_line1 =
1087 StartOfLine(position1);
1088 PositionWithAffinityTemplate<Strategy> start_of_line2 =
1089 StartOfLine(position2);
1090 if (start_of_line1 == start_of_line2)
1091 return true;
1092 PositionTemplate<Strategy> canonicalized1 =
1093 CanonicalPositionOf(start_of_line1.GetPosition());
1094 if (canonicalized1 == start_of_line2.GetPosition())
1095 return true;
1096 return canonicalized1 == CanonicalPositionOf(start_of_line2.GetPosition());
1097 }
1098
1099 bool InSameLine(const PositionWithAffinity& a, const PositionWithAffinity& b) {
1100 return InSameLineAlgorithm<EditingStrategy>(a, b);
1101 }
1102
1103 bool InSameLine(const PositionInFlatTreeWithAffinity& position1,
1104 const PositionInFlatTreeWithAffinity& position2) {
1105 return InSameLineAlgorithm<EditingInFlatTreeStrategy>(position1, position2);
1106 }
1107
1108 bool InSameLine(const VisiblePosition& position1,
1109 const VisiblePosition& position2) {
1110 DCHECK(position1.IsValid()) << position1;
1111 DCHECK(position2.IsValid()) << position2;
1112 return InSameLine(position1.ToPositionWithAffinity(),
1113 position2.ToPositionWithAffinity());
1114 }
1115
1116 bool InSameLine(const VisiblePositionInFlatTree& position1,
1117 const VisiblePositionInFlatTree& position2) {
1118 DCHECK(position1.IsValid()) << position1;
1119 DCHECK(position2.IsValid()) << position2;
1120 return InSameLine(position1.ToPositionWithAffinity(),
1121 position2.ToPositionWithAffinity());
1122 }
1123
1124 template <typename Strategy>
1125 bool IsStartOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
1126 DCHECK(p.IsValid()) << p;
1127 return p.IsNotNull() && p.DeepEquivalent() == StartOfLine(p).DeepEquivalent();
1128 }
1129
1130 bool IsStartOfLine(const VisiblePosition& p) {
1131 return IsStartOfLineAlgorithm<EditingStrategy>(p);
1132 }
1133
1134 bool IsStartOfLine(const VisiblePositionInFlatTree& p) {
1135 return IsStartOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
1136 }
1137
1138 template <typename Strategy>
1139 bool IsEndOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
1140 DCHECK(p.IsValid()) << p;
1141 return p.IsNotNull() && p.DeepEquivalent() == EndOfLine(p).DeepEquivalent();
1142 }
1143
1144 bool IsEndOfLine(const VisiblePosition& p) {
1145 return IsEndOfLineAlgorithm<EditingStrategy>(p);
1146 }
1147
1148 bool IsEndOfLine(const VisiblePositionInFlatTree& p) {
1149 return IsEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
1150 }
1151
1152 template <typename Strategy>
1153 static bool IsLogicalEndOfLineAlgorithm(
1154 const VisiblePositionTemplate<Strategy>& p) {
1155 DCHECK(p.IsValid()) << p;
1156 return p.IsNotNull() &&
1157 p.DeepEquivalent() == LogicalEndOfLine(p).DeepEquivalent();
1158 }
1159
1160 bool IsLogicalEndOfLine(const VisiblePosition& p) {
1161 return IsLogicalEndOfLineAlgorithm<EditingStrategy>(p);
1162 }
1163
1164 bool IsLogicalEndOfLine(const VisiblePositionInFlatTree& p) {
1165 return IsLogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
1166 }
1167
1168 static inline LayoutPoint AbsoluteLineDirectionPointToLocalPointInBlock(
1169 RootInlineBox* root,
1170 LayoutUnit line_direction_point) {
1171 DCHECK(root);
1172 LineLayoutBlockFlow containing_block = root->Block();
1173 FloatPoint absolute_block_point =
1174 containing_block.LocalToAbsolute(FloatPoint());
1175 if (containing_block.HasOverflowClip())
1176 absolute_block_point -= FloatSize(containing_block.ScrolledContentOffset());
1177
1178 if (root->Block().IsHorizontalWritingMode())
1179 return LayoutPoint(
1180 LayoutUnit(line_direction_point - absolute_block_point.X()),
1181 root->BlockDirectionPointInLine());
1182
1183 return LayoutPoint(
1184 root->BlockDirectionPointInLine(),
1185 LayoutUnit(line_direction_point - absolute_block_point.Y()));
1186 }
1187
1188 VisiblePosition PreviousLinePosition(const VisiblePosition& visible_position,
1189 LayoutUnit line_direction_point,
1190 EditableType editable_type) {
1191 DCHECK(visible_position.IsValid()) << visible_position;
1192
1193 Position p = visible_position.DeepEquivalent();
1194 Node* node = p.AnchorNode();
1195
1196 if (!node)
1197 return VisiblePosition();
1198
1199 LayoutObject* layout_object = node->GetLayoutObject();
1200 if (!layout_object)
1201 return VisiblePosition();
1202
1203 RootInlineBox* root = 0;
1204 InlineBox* box = ComputeInlineBoxPosition(visible_position).inline_box;
1205 if (box) {
1206 root = box->Root().PrevRootBox();
1207 // We want to skip zero height boxes.
1208 // This could happen in case it is a TrailingFloatsRootInlineBox.
1209 if (!root || !root->LogicalHeight() || !root->FirstLeafChild())
1210 root = 0;
1211 }
1212
1213 if (!root) {
1214 Position position = PreviousRootInlineBoxCandidatePosition(
1215 node, visible_position, editable_type);
1216 if (position.IsNotNull()) {
1217 RenderedPosition rendered_position((CreateVisiblePosition(position)));
1218 root = rendered_position.RootBox();
1219 if (!root)
1220 return CreateVisiblePosition(position);
1221 }
1222 }
1223
1224 if (root) {
1225 // FIXME: Can be wrong for multi-column layout and with transforms.
1226 LayoutPoint point_in_line = AbsoluteLineDirectionPointToLocalPointInBlock(
1227 root, line_direction_point);
1228 LineLayoutItem line_layout_item =
1229 root->ClosestLeafChildForPoint(point_in_line, IsEditablePosition(p))
1230 ->GetLineLayoutItem();
1231 Node* node = line_layout_item.GetNode();
1232 if (node && EditingIgnoresContent(*node))
1233 return VisiblePosition::InParentBeforeNode(*node);
1234 return CreateVisiblePosition(
1235 line_layout_item.PositionForPoint(point_in_line));
1236 }
1237
1238 // Could not find a previous line. This means we must already be on the first
1239 // line. Move to the start of the content in this block, which effectively
1240 // moves us to the start of the line we're on.
1241 Element* root_element = HasEditableStyle(*node, editable_type)
1242 ? RootEditableElement(*node, editable_type)
1243 : node->GetDocument().documentElement();
1244 if (!root_element)
1245 return VisiblePosition();
1246 return VisiblePosition::FirstPositionInNode(root_element);
1247 }
1248
1249 VisiblePosition NextLinePosition(const VisiblePosition& visible_position,
1250 LayoutUnit line_direction_point,
1251 EditableType editable_type) {
1252 DCHECK(visible_position.IsValid()) << visible_position;
1253
1254 Position p = visible_position.DeepEquivalent();
1255 Node* node = p.AnchorNode();
1256
1257 if (!node)
1258 return VisiblePosition();
1259
1260 LayoutObject* layout_object = node->GetLayoutObject();
1261 if (!layout_object)
1262 return VisiblePosition();
1263
1264 RootInlineBox* root = 0;
1265 InlineBox* box = ComputeInlineBoxPosition(visible_position).inline_box;
1266 if (box) {
1267 root = box->Root().NextRootBox();
1268 // We want to skip zero height boxes.
1269 // This could happen in case it is a TrailingFloatsRootInlineBox.
1270 if (!root || !root->LogicalHeight() || !root->FirstLeafChild())
1271 root = 0;
1272 }
1273
1274 if (!root) {
1275 // FIXME: We need do the same in previousLinePosition.
1276 Node* child = NodeTraversal::ChildAt(*node, p.ComputeEditingOffset());
1277 node = child ? child : &NodeTraversal::LastWithinOrSelf(*node);
1278 Position position = NextRootInlineBoxCandidatePosition(
1279 node, visible_position, editable_type);
1280 if (position.IsNotNull()) {
1281 RenderedPosition rendered_position((CreateVisiblePosition(position)));
1282 root = rendered_position.RootBox();
1283 if (!root)
1284 return CreateVisiblePosition(position);
1285 }
1286 }
1287
1288 if (root) {
1289 // FIXME: Can be wrong for multi-column layout and with transforms.
1290 LayoutPoint point_in_line = AbsoluteLineDirectionPointToLocalPointInBlock(
1291 root, line_direction_point);
1292 LineLayoutItem line_layout_item =
1293 root->ClosestLeafChildForPoint(point_in_line, IsEditablePosition(p))
1294 ->GetLineLayoutItem();
1295 Node* node = line_layout_item.GetNode();
1296 if (node && EditingIgnoresContent(*node))
1297 return VisiblePosition::InParentBeforeNode(*node);
1298 return CreateVisiblePosition(
1299 line_layout_item.PositionForPoint(point_in_line));
1300 }
1301
1302 // Could not find a next line. This means we must already be on the last line.
1303 // Move to the end of the content in this block, which effectively moves us
1304 // to the end of the line we're on.
1305 Element* root_element = HasEditableStyle(*node, editable_type)
1306 ? RootEditableElement(*node, editable_type)
1307 : node->GetDocument().documentElement();
1308 if (!root_element)
1309 return VisiblePosition();
1310 return VisiblePosition::LastPositionInNode(root_element);
1311 }
1312
1313 // ---------
1314
1315 static unsigned StartSentenceBoundary(const UChar* characters, 696 static unsigned StartSentenceBoundary(const UChar* characters,
1316 unsigned length, 697 unsigned length,
1317 unsigned, 698 unsigned,
1318 BoundarySearchContextAvailability, 699 BoundarySearchContextAvailability,
1319 bool&) { 700 bool&) {
1320 TextBreakIterator* iterator = SentenceBreakIterator(characters, length); 701 TextBreakIterator* iterator = SentenceBreakIterator(characters, length);
1321 // FIXME: The following function can return -1; we don't handle that. 702 // FIXME: The following function can return -1; we don't handle that.
1322 return iterator->preceding(length); 703 return iterator->preceding(length);
1323 } 704 }
1324 705
(...skipping 2445 matching lines...) Expand 10 before | Expand all | Expand 10 after
3770 3151
3771 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) { 3152 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) {
3772 return EnclosingIntRect(ComputeTextRectTemplate(range)); 3153 return EnclosingIntRect(ComputeTextRectTemplate(range));
3773 } 3154 }
3774 3155
3775 FloatRect ComputeTextFloatRect(const EphemeralRange& range) { 3156 FloatRect ComputeTextFloatRect(const EphemeralRange& range) {
3776 return ComputeTextRectTemplate(range); 3157 return ComputeTextRectTemplate(range);
3777 } 3158 }
3778 3159
3779 } // namespace blink 3160 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698