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

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

Issue 2920193003: Move "word" granularity related functions to VisibleUnitWord.cpp (Closed)
Patch Set: 2017-06-07T11:28:29 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 21 matching lines...) Expand all
32 #include "core/dom/FirstLetterPseudoElement.h" 32 #include "core/dom/FirstLetterPseudoElement.h"
33 #include "core/dom/NodeTraversal.h" 33 #include "core/dom/NodeTraversal.h"
34 #include "core/dom/Text.h" 34 #include "core/dom/Text.h"
35 #include "core/editing/EditingUtilities.h" 35 #include "core/editing/EditingUtilities.h"
36 #include "core/editing/FrameSelection.h" 36 #include "core/editing/FrameSelection.h"
37 #include "core/editing/Position.h" 37 #include "core/editing/Position.h"
38 #include "core/editing/PositionIterator.h" 38 #include "core/editing/PositionIterator.h"
39 #include "core/editing/RenderedPosition.h" 39 #include "core/editing/RenderedPosition.h"
40 #include "core/editing/TextAffinity.h" 40 #include "core/editing/TextAffinity.h"
41 #include "core/editing/VisiblePosition.h" 41 #include "core/editing/VisiblePosition.h"
42 #include "core/editing/iterators/BackwardsCharacterIterator.h"
43 #include "core/editing/iterators/BackwardsTextBuffer.h"
44 #include "core/editing/iterators/CharacterIterator.h" 42 #include "core/editing/iterators/CharacterIterator.h"
45 #include "core/editing/iterators/ForwardsTextBuffer.h"
46 #include "core/editing/iterators/SimplifiedBackwardsTextIterator.h"
47 #include "core/editing/iterators/TextIterator.h" 43 #include "core/editing/iterators/TextIterator.h"
48 #include "core/frame/LocalFrame.h" 44 #include "core/frame/LocalFrame.h"
49 #include "core/frame/Settings.h" 45 #include "core/frame/Settings.h"
50 #include "core/html/HTMLBRElement.h" 46 #include "core/html/HTMLBRElement.h"
51 #include "core/html/TextControlElement.h" 47 #include "core/html/TextControlElement.h"
52 #include "core/layout/HitTestRequest.h" 48 #include "core/layout/HitTestRequest.h"
53 #include "core/layout/HitTestResult.h" 49 #include "core/layout/HitTestResult.h"
54 #include "core/layout/LayoutInline.h" 50 #include "core/layout/LayoutInline.h"
55 #include "core/layout/LayoutObject.h" 51 #include "core/layout/LayoutObject.h"
56 #include "core/layout/LayoutTextFragment.h" 52 #include "core/layout/LayoutTextFragment.h"
57 #include "core/layout/LayoutView.h" 53 #include "core/layout/LayoutView.h"
58 #include "core/layout/api/LayoutItem.h" 54 #include "core/layout/api/LayoutItem.h"
59 #include "core/layout/api/LayoutViewItem.h" 55 #include "core/layout/api/LayoutViewItem.h"
60 #include "core/layout/api/LineLayoutAPIShim.h" 56 #include "core/layout/api/LineLayoutAPIShim.h"
61 #include "core/layout/api/LineLayoutItem.h" 57 #include "core/layout/api/LineLayoutItem.h"
62 #include "core/layout/line/InlineIterator.h" 58 #include "core/layout/line/InlineIterator.h"
63 #include "core/layout/line/InlineTextBox.h" 59 #include "core/layout/line/InlineTextBox.h"
64 #include "platform/heap/Handle.h" 60 #include "platform/heap/Handle.h"
65 #include "platform/text/TextBoundaries.h"
66 #include "platform/text/TextBreakIterator.h" 61 #include "platform/text/TextBreakIterator.h"
67 62
68 namespace blink { 63 namespace blink {
69 64
70 template <typename PositionType> 65 template <typename PositionType>
71 static PositionType CanonicalizeCandidate(const PositionType& candidate) { 66 static PositionType CanonicalizeCandidate(const PositionType& candidate) {
72 if (candidate.IsNull()) 67 if (candidate.IsNull())
73 return PositionType(); 68 return PositionType();
74 DCHECK(IsVisuallyEquivalentCandidate(candidate)); 69 DCHECK(IsVisuallyEquivalentCandidate(candidate));
75 PositionType upstream = MostBackwardCaretPosition(candidate); 70 PositionType upstream = MostBackwardCaretPosition(candidate);
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 const Position& anchor) { 267 const Position& anchor) {
273 return HonorEditingBoundaryAtOrAfterTemplate(pos, anchor); 268 return HonorEditingBoundaryAtOrAfterTemplate(pos, anchor);
274 } 269 }
275 270
276 VisiblePositionInFlatTree HonorEditingBoundaryAtOrAfter( 271 VisiblePositionInFlatTree HonorEditingBoundaryAtOrAfter(
277 const VisiblePositionInFlatTree& pos, 272 const VisiblePositionInFlatTree& pos,
278 const PositionInFlatTree& anchor) { 273 const PositionInFlatTree& anchor) {
279 return HonorEditingBoundaryAtOrAfterTemplate(pos, anchor); 274 return HonorEditingBoundaryAtOrAfterTemplate(pos, anchor);
280 } 275 }
281 276
282 template <typename Strategy>
283 static ContainerNode* NonShadowBoundaryParentNode(Node* node) {
284 ContainerNode* parent = Strategy::Parent(*node);
285 return parent && !parent->IsShadowRoot() ? parent : nullptr;
286 }
287
288 template <typename Strategy>
289 static Node* ParentEditingBoundary(const PositionTemplate<Strategy>& position) {
290 Node* const anchor_node = position.AnchorNode();
291 if (!anchor_node)
292 return nullptr;
293
294 Node* document_element = anchor_node->GetDocument().documentElement();
295 if (!document_element)
296 return nullptr;
297
298 Node* boundary = position.ComputeContainerNode();
299 while (boundary != document_element &&
300 NonShadowBoundaryParentNode<Strategy>(boundary) &&
301 HasEditableStyle(*anchor_node) ==
302 HasEditableStyle(*Strategy::Parent(*boundary)))
303 boundary = NonShadowBoundaryParentNode<Strategy>(boundary);
304
305 return boundary;
306 }
307
308 enum BoundarySearchContextAvailability {
309 kDontHaveMoreContext,
310 kMayHaveMoreContext
311 };
312
313 typedef unsigned (*BoundarySearchFunction)(const UChar*,
314 unsigned length,
315 unsigned offset,
316 BoundarySearchContextAvailability,
317 bool& need_more_context);
318
319 template <typename Strategy>
320 static PositionTemplate<Strategy> PreviousBoundary(
321 const VisiblePositionTemplate<Strategy>& c,
322 BoundarySearchFunction search_function) {
323 DCHECK(c.IsValid()) << c;
324 const PositionTemplate<Strategy> pos = c.DeepEquivalent();
325 Node* boundary = ParentEditingBoundary(pos);
326 if (!boundary)
327 return PositionTemplate<Strategy>();
328
329 const PositionTemplate<Strategy> start =
330 PositionTemplate<Strategy>::EditingPositionOf(boundary, 0)
331 .ParentAnchoredEquivalent();
332 const PositionTemplate<Strategy> end = pos.ParentAnchoredEquivalent();
333
334 ForwardsTextBuffer suffix_string;
335 if (RequiresContextForWordBoundary(CharacterBefore(c))) {
336 TextIteratorAlgorithm<Strategy> forwards_iterator(
337 end, PositionTemplate<Strategy>::AfterNode(boundary));
338 while (!forwards_iterator.AtEnd()) {
339 forwards_iterator.CopyTextTo(&suffix_string);
340 int context_end_index = EndOfFirstWordBoundaryContext(
341 suffix_string.Data() + suffix_string.Size() -
342 forwards_iterator.length(),
343 forwards_iterator.length());
344 if (context_end_index < forwards_iterator.length()) {
345 suffix_string.Shrink(forwards_iterator.length() - context_end_index);
346 break;
347 }
348 forwards_iterator.Advance();
349 }
350 }
351
352 unsigned suffix_length = suffix_string.Size();
353 BackwardsTextBuffer string;
354 string.PushRange(suffix_string.Data(), suffix_string.Size());
355
356 SimplifiedBackwardsTextIteratorAlgorithm<Strategy> it(start, end);
357 int remaining_length = 0;
358 unsigned next = 0;
359 bool need_more_context = false;
360 while (!it.AtEnd()) {
361 bool in_text_security_mode = it.IsInTextSecurityMode();
362 // iterate to get chunks until the searchFunction returns a non-zero
363 // value.
364 if (!in_text_security_mode) {
365 int run_offset = 0;
366 do {
367 run_offset += it.CopyTextTo(&string, run_offset, string.Capacity());
368 // TODO(xiaochengh): The following line takes O(string.size()) time,
369 // which makes quadratic overall running time in the worst case.
370 // Should improve it in some way.
371 next = search_function(string.Data(), string.Size(),
372 string.Size() - suffix_length,
373 kMayHaveMoreContext, need_more_context);
374 } while (!next && run_offset < it.length());
375 if (next) {
376 remaining_length = it.length() - run_offset;
377 break;
378 }
379 } else {
380 // Treat bullets used in the text security mode as regular
381 // characters when looking for boundaries
382 string.PushCharacters('x', it.length());
383 next = 0;
384 }
385 it.Advance();
386 }
387 if (need_more_context) {
388 // The last search returned the beginning of the buffer and asked for
389 // more context, but there is no earlier text. Force a search with
390 // what's available.
391 // TODO(xiaochengh): Do we have to search the whole string?
392 next = search_function(string.Data(), string.Size(),
393 string.Size() - suffix_length, kDontHaveMoreContext,
394 need_more_context);
395 DCHECK(!need_more_context);
396 }
397
398 if (!next)
399 return it.AtEnd() ? it.StartPosition() : pos;
400
401 Node* node = it.StartContainer();
402 int boundary_offset = remaining_length + next;
403 if (node->IsTextNode() && boundary_offset <= node->MaxCharacterOffset()) {
404 // The next variable contains a usable index into a text node
405 return PositionTemplate<Strategy>(node, boundary_offset);
406 }
407
408 // Use the character iterator to translate the next value into a DOM
409 // position.
410 BackwardsCharacterIteratorAlgorithm<Strategy> char_it(start, end);
411 char_it.Advance(string.Size() - suffix_length - next);
412 // TODO(yosin) charIt can get out of shadow host.
413 return char_it.EndPosition();
414 }
415
416 template <typename Strategy>
417 static PositionTemplate<Strategy> NextBoundary(
418 const VisiblePositionTemplate<Strategy>& c,
419 BoundarySearchFunction search_function) {
420 DCHECK(c.IsValid()) << c;
421 PositionTemplate<Strategy> pos = c.DeepEquivalent();
422 Node* boundary = ParentEditingBoundary(pos);
423 if (!boundary)
424 return PositionTemplate<Strategy>();
425
426 Document& d = boundary->GetDocument();
427 const PositionTemplate<Strategy> start(pos.ParentAnchoredEquivalent());
428
429 BackwardsTextBuffer prefix_string;
430 if (RequiresContextForWordBoundary(CharacterAfter(c))) {
431 SimplifiedBackwardsTextIteratorAlgorithm<Strategy> backwards_iterator(
432 PositionTemplate<Strategy>::FirstPositionInNode(&d), start);
433 while (!backwards_iterator.AtEnd()) {
434 backwards_iterator.CopyTextTo(&prefix_string);
435 int context_start_index = StartOfLastWordBoundaryContext(
436 prefix_string.Data(), backwards_iterator.length());
437 if (context_start_index > 0) {
438 prefix_string.Shrink(context_start_index);
439 break;
440 }
441 backwards_iterator.Advance();
442 }
443 }
444
445 unsigned prefix_length = prefix_string.Size();
446 ForwardsTextBuffer string;
447 string.PushRange(prefix_string.Data(), prefix_string.Size());
448
449 const PositionTemplate<Strategy> search_start =
450 PositionTemplate<Strategy>::EditingPositionOf(
451 start.AnchorNode(), start.OffsetInContainerNode());
452 const PositionTemplate<Strategy> search_end =
453 PositionTemplate<Strategy>::LastPositionInNode(boundary);
454 TextIteratorAlgorithm<Strategy> it(
455 search_start, search_end,
456 TextIteratorBehavior::Builder()
457 .SetEmitsCharactersBetweenAllVisiblePositions(true)
458 .Build());
459 const unsigned kInvalidOffset = static_cast<unsigned>(-1);
460 unsigned next = kInvalidOffset;
461 unsigned offset = prefix_length;
462 bool need_more_context = false;
463 while (!it.AtEnd()) {
464 // Keep asking the iterator for chunks until the search function
465 // returns an end value not equal to the length of the string passed to
466 // it.
467 bool in_text_security_mode = it.IsInTextSecurityMode();
468 if (!in_text_security_mode) {
469 int run_offset = 0;
470 do {
471 run_offset += it.CopyTextTo(&string, run_offset, string.Capacity());
472 next = search_function(string.Data(), string.Size(), offset,
473 kMayHaveMoreContext, need_more_context);
474 if (!need_more_context) {
475 // When the search does not need more context, skip all examined
476 // characters except the last one, in case it is a boundary.
477 offset = string.Size();
478 U16_BACK_1(string.Data(), 0, offset);
479 }
480 } while (next == string.Size() && run_offset < it.length());
481 if (next != string.Size())
482 break;
483 } else {
484 // Treat bullets used in the text security mode as regular
485 // characters when looking for boundaries
486 string.PushCharacters('x', it.length());
487 next = string.Size();
488 }
489 it.Advance();
490 }
491 if (need_more_context) {
492 // The last search returned the end of the buffer and asked for more
493 // context, but there is no further text. Force a search with what's
494 // available.
495 // TODO(xiaochengh): Do we still have to search the whole string?
496 next = search_function(string.Data(), string.Size(), prefix_length,
497 kDontHaveMoreContext, need_more_context);
498 DCHECK(!need_more_context);
499 }
500
501 if (it.AtEnd() && next == string.Size()) {
502 pos = it.StartPositionInCurrentContainer();
503 } else if (next != kInvalidOffset && next != prefix_length) {
504 // Use the character iterator to translate the next value into a DOM
505 // position.
506 CharacterIteratorAlgorithm<Strategy> char_it(
507 search_start, search_end,
508 TextIteratorBehavior::Builder()
509 .SetEmitsCharactersBetweenAllVisiblePositions(true)
510 .Build());
511 char_it.Advance(next - prefix_length - 1);
512 pos = char_it.EndPosition();
513
514 if (char_it.CharacterAt(0) == '\n') {
515 // TODO(yosin) workaround for collapsed range (where only start
516 // position is correct) emitted for some emitted newlines
517 // (see rdar://5192593)
518 const VisiblePositionTemplate<Strategy> vis_pos =
519 CreateVisiblePosition(pos);
520 if (vis_pos.DeepEquivalent() ==
521 CreateVisiblePosition(char_it.StartPosition()).DeepEquivalent()) {
522 char_it.Advance(1);
523 pos = char_it.StartPosition();
524 }
525 }
526 }
527
528 return pos;
529 }
530
531 // ---------
Xiaocheng 2017/06/07 17:45:38 Functions above this line shouldn't be moved. They
yosin_UTC9 2017/06/08 04:09:14 Done.
532
533 static unsigned StartWordBoundary(
534 const UChar* characters,
535 unsigned length,
536 unsigned offset,
537 BoundarySearchContextAvailability may_have_more_context,
538 bool& need_more_context) {
539 TRACE_EVENT0("blink", "startWordBoundary");
540 DCHECK(offset);
541 if (may_have_more_context &&
542 !StartOfLastWordBoundaryContext(characters, offset)) {
543 need_more_context = true;
544 return 0;
545 }
546 need_more_context = false;
547 int start, end;
548 U16_BACK_1(characters, 0, offset);
549 FindWordBoundary(characters, length, offset, &start, &end);
550 return start;
551 }
552
553 template <typename Strategy>
554 static PositionTemplate<Strategy> StartOfWordAlgorithm(
555 const VisiblePositionTemplate<Strategy>& c,
556 EWordSide side) {
557 DCHECK(c.IsValid()) << c;
558 // TODO(yosin) This returns a null VP for c at the start of the document
559 // and |side| == |LeftWordIfOnBoundary|
560 VisiblePositionTemplate<Strategy> p = c;
561 if (side == kRightWordIfOnBoundary) {
562 // at paragraph end, the startofWord is the current position
563 if (IsEndOfParagraph(c))
564 return c.DeepEquivalent();
565
566 p = NextPositionOf(c);
567 if (p.IsNull())
568 return c.DeepEquivalent();
569 }
570 return PreviousBoundary(p, StartWordBoundary);
571 }
572
573 Position StartOfWordPosition(const VisiblePosition& position, EWordSide side) {
574 return StartOfWordAlgorithm<EditingStrategy>(position, side);
575 }
576
577 VisiblePosition StartOfWord(const VisiblePosition& position, EWordSide side) {
578 return CreateVisiblePosition(StartOfWordPosition(position, side));
579 }
580
581 PositionInFlatTree StartOfWordPosition(
582 const VisiblePositionInFlatTree& position,
583 EWordSide side) {
584 return StartOfWordAlgorithm<EditingInFlatTreeStrategy>(position, side);
585 }
586
587 VisiblePositionInFlatTree StartOfWord(const VisiblePositionInFlatTree& position,
588 EWordSide side) {
589 return CreateVisiblePosition(StartOfWordPosition(position, side));
590 }
591
592 static unsigned EndWordBoundary(
593 const UChar* characters,
594 unsigned length,
595 unsigned offset,
596 BoundarySearchContextAvailability may_have_more_context,
597 bool& need_more_context) {
598 DCHECK_LE(offset, length);
599 if (may_have_more_context &&
600 EndOfFirstWordBoundaryContext(characters + offset, length - offset) ==
601 static_cast<int>(length - offset)) {
602 need_more_context = true;
603 return length;
604 }
605 need_more_context = false;
606 return FindWordEndBoundary(characters, length, offset);
607 }
608
609 template <typename Strategy>
610 static PositionTemplate<Strategy> EndOfWordAlgorithm(
611 const VisiblePositionTemplate<Strategy>& c,
612 EWordSide side) {
613 DCHECK(c.IsValid()) << c;
614 VisiblePositionTemplate<Strategy> p = c;
615 if (side == kLeftWordIfOnBoundary) {
616 if (IsStartOfParagraph(c))
617 return c.DeepEquivalent();
618
619 p = PreviousPositionOf(c);
620 if (p.IsNull())
621 return c.DeepEquivalent();
622 } else if (IsEndOfParagraph(c)) {
623 return c.DeepEquivalent();
624 }
625
626 return NextBoundary(p, EndWordBoundary);
627 }
628
629 Position EndOfWordPosition(const VisiblePosition& position, EWordSide side) {
630 return EndOfWordAlgorithm<EditingStrategy>(position, side);
631 }
632
633 VisiblePosition EndOfWord(const VisiblePosition& position, EWordSide side) {
634 return CreateVisiblePosition(EndOfWordPosition(position, side),
635 VP_UPSTREAM_IF_POSSIBLE);
636 }
637
638 PositionInFlatTree EndOfWordPosition(const VisiblePositionInFlatTree& position,
639 EWordSide side) {
640 return EndOfWordAlgorithm<EditingInFlatTreeStrategy>(position, side);
641 }
642
643 VisiblePositionInFlatTree EndOfWord(const VisiblePositionInFlatTree& position,
644 EWordSide side) {
645 return CreateVisiblePosition(EndOfWordPosition(position, side),
646 VP_UPSTREAM_IF_POSSIBLE);
647 }
648
649 static unsigned PreviousWordPositionBoundary(
650 const UChar* characters,
651 unsigned length,
652 unsigned offset,
653 BoundarySearchContextAvailability may_have_more_context,
654 bool& need_more_context) {
655 if (may_have_more_context &&
656 !StartOfLastWordBoundaryContext(characters, offset)) {
657 need_more_context = true;
658 return 0;
659 }
660 need_more_context = false;
661 return FindNextWordFromIndex(characters, length, offset, false);
662 }
663
664 VisiblePosition PreviousWordPosition(const VisiblePosition& c) {
665 DCHECK(c.IsValid()) << c;
666 VisiblePosition prev =
667 CreateVisiblePosition(PreviousBoundary(c, PreviousWordPositionBoundary));
668 return HonorEditingBoundaryAtOrBefore(prev, c.DeepEquivalent());
669 }
670
671 static unsigned NextWordPositionBoundary(
672 const UChar* characters,
673 unsigned length,
674 unsigned offset,
675 BoundarySearchContextAvailability may_have_more_context,
676 bool& need_more_context) {
677 if (may_have_more_context &&
678 EndOfFirstWordBoundaryContext(characters + offset, length - offset) ==
679 static_cast<int>(length - offset)) {
680 need_more_context = true;
681 return length;
682 }
683 need_more_context = false;
684 return FindNextWordFromIndex(characters, length, offset, true);
685 }
686
687 VisiblePosition NextWordPosition(const VisiblePosition& c) {
688 DCHECK(c.IsValid()) << c;
689 VisiblePosition next = CreateVisiblePosition(
690 NextBoundary(c, NextWordPositionBoundary), VP_UPSTREAM_IF_POSSIBLE);
691 return HonorEditingBoundaryAtOrAfter(next, c.DeepEquivalent());
692 }
693
694 // --------- 277 // ---------
695 278
696 static unsigned StartSentenceBoundary(const UChar* characters, 279 static unsigned StartSentenceBoundary(const UChar* characters,
697 unsigned length, 280 unsigned length,
698 unsigned, 281 unsigned,
699 BoundarySearchContextAvailability, 282 BoundarySearchContextAvailability,
700 bool&) { 283 bool&) {
701 TextBreakIterator* iterator = SentenceBreakIterator(characters, length); 284 TextBreakIterator* iterator = SentenceBreakIterator(characters, length);
702 // FIXME: The following function can return -1; we don't handle that. 285 // FIXME: The following function can return -1; we don't handle that.
703 return iterator->preceding(length); 286 return iterator->preceding(length);
(...skipping 2068 matching lines...) Expand 10 before | Expand all | Expand 10 after
2772 2355
2773 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) { 2356 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) {
2774 return EnclosingIntRect(ComputeTextRectTemplate(range)); 2357 return EnclosingIntRect(ComputeTextRectTemplate(range));
2775 } 2358 }
2776 2359
2777 FloatRect ComputeTextFloatRect(const EphemeralRange& range) { 2360 FloatRect ComputeTextFloatRect(const EphemeralRange& range) {
2778 return ComputeTextRectTemplate(range); 2361 return ComputeTextRectTemplate(range);
2779 } 2362 }
2780 2363
2781 } // namespace blink 2364 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/VisibleUnits.h ('k') | third_party/WebKit/Source/core/editing/VisibleUnitsWord.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698