| OLD | NEW |
| 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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 if (!highest_root) | 192 if (!highest_root) |
| 193 return PositionWithAffinityTemplate<Strategy>(); | 193 return PositionWithAffinityTemplate<Strategy>(); |
| 194 | 194 |
| 195 // Return the last position before |pos| that is in the same editable region | 195 // Return the last position before |pos| that is in the same editable region |
| 196 // as this position | 196 // as this position |
| 197 return LastEditablePositionBeforePositionInRoot(pos.GetPosition(), | 197 return LastEditablePositionBeforePositionInRoot(pos.GetPosition(), |
| 198 *highest_root); | 198 *highest_root); |
| 199 } | 199 } |
| 200 | 200 |
| 201 template <typename Strategy> | 201 template <typename Strategy> |
| 202 static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrBefore( | 202 VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrBeforeAlgorithm( |
| 203 const VisiblePositionTemplate<Strategy>& pos, | 203 const VisiblePositionTemplate<Strategy>& pos, |
| 204 const PositionTemplate<Strategy>& anchor) { | 204 const PositionTemplate<Strategy>& anchor) { |
| 205 DCHECK(pos.IsValid()) << pos; | 205 DCHECK(pos.IsValid()) << pos; |
| 206 return CreateVisiblePosition( | 206 return CreateVisiblePosition( |
| 207 HonorEditingBoundaryAtOrBefore(pos.ToPositionWithAffinity(), anchor)); | 207 HonorEditingBoundaryAtOrBefore(pos.ToPositionWithAffinity(), anchor)); |
| 208 } | 208 } |
| 209 | 209 |
| 210 VisiblePosition HonorEditingBoundaryAtOrBefore( |
| 211 const VisiblePosition& visiblePosition, |
| 212 const Position& anchor) { |
| 213 return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor); |
| 214 } |
| 215 |
| 216 VisiblePositionInFlatTree HonorEditingBoundaryAtOrBefore( |
| 217 const VisiblePositionInFlatTree& visiblePosition, |
| 218 const PositionInFlatTree& anchor) { |
| 219 return HonorEditingBoundaryAtOrBeforeAlgorithm(visiblePosition, anchor); |
| 220 } |
| 221 |
| 210 template <typename Strategy> | 222 template <typename Strategy> |
| 211 static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrAfter( | 223 static VisiblePositionTemplate<Strategy> HonorEditingBoundaryAtOrAfter( |
| 212 const VisiblePositionTemplate<Strategy>& pos, | 224 const VisiblePositionTemplate<Strategy>& pos, |
| 213 const PositionTemplate<Strategy>& anchor) { | 225 const PositionTemplate<Strategy>& anchor) { |
| 214 DCHECK(pos.IsValid()) << pos; | 226 DCHECK(pos.IsValid()) << pos; |
| 215 if (pos.IsNull()) | 227 if (pos.IsNull()) |
| 216 return pos; | 228 return pos; |
| 217 | 229 |
| 218 ContainerNode* highest_root = HighestEditableRoot(anchor); | 230 ContainerNode* highest_root = HighestEditableRoot(anchor); |
| 219 | 231 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 node = NextAtomicLeafNode(*node); | 322 node = NextAtomicLeafNode(*node); |
| 311 while (node) { | 323 while (node) { |
| 312 if (editable == HasEditableStyle(*node, editable_type)) | 324 if (editable == HasEditableStyle(*node, editable_type)) |
| 313 return node; | 325 return node; |
| 314 node = NextAtomicLeafNode(*node); | 326 node = NextAtomicLeafNode(*node); |
| 315 } | 327 } |
| 316 return 0; | 328 return 0; |
| 317 } | 329 } |
| 318 | 330 |
| 319 // FIXME: consolidate with code in previousLinePosition. | 331 // FIXME: consolidate with code in previousLinePosition. |
| 320 static Position PreviousRootInlineBoxCandidatePosition( | 332 Position PreviousRootInlineBoxCandidatePosition( |
| 321 Node* node, | 333 Node* node, |
| 322 const VisiblePosition& visible_position, | 334 const VisiblePosition& visible_position, |
| 323 EditableType editable_type) { | 335 EditableType editable_type) { |
| 324 DCHECK(visible_position.IsValid()) << visible_position; | 336 DCHECK(visible_position.IsValid()) << visible_position; |
| 325 ContainerNode* highest_root = | 337 ContainerNode* highest_root = |
| 326 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type); | 338 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type); |
| 327 Node* previous_node = PreviousLeafWithSameEditability(node, editable_type); | 339 Node* previous_node = PreviousLeafWithSameEditability(node, editable_type); |
| 328 | 340 |
| 329 while (previous_node && | 341 while (previous_node && |
| 330 (!previous_node->GetLayoutObject() || | 342 (!previous_node->GetLayoutObject() || |
| (...skipping 15 matching lines...) Expand all Loading... |
| 346 | 358 |
| 347 if (IsVisuallyEquivalentCandidate(pos)) | 359 if (IsVisuallyEquivalentCandidate(pos)) |
| 348 return pos; | 360 return pos; |
| 349 | 361 |
| 350 previous_node = | 362 previous_node = |
| 351 PreviousLeafWithSameEditability(previous_node, editable_type); | 363 PreviousLeafWithSameEditability(previous_node, editable_type); |
| 352 } | 364 } |
| 353 return Position(); | 365 return Position(); |
| 354 } | 366 } |
| 355 | 367 |
| 356 static Position NextRootInlineBoxCandidatePosition( | 368 Position NextRootInlineBoxCandidatePosition( |
| 357 Node* node, | 369 Node* node, |
| 358 const VisiblePosition& visible_position, | 370 const VisiblePosition& visible_position, |
| 359 EditableType editable_type) { | 371 EditableType editable_type) { |
| 360 DCHECK(visible_position.IsValid()) << visible_position; | 372 DCHECK(visible_position.IsValid()) << visible_position; |
| 361 ContainerNode* highest_root = | 373 ContainerNode* highest_root = |
| 362 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type); | 374 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type); |
| 363 Node* next_node = NextLeafWithSameEditability(node, editable_type); | 375 Node* next_node = NextLeafWithSameEditability(node, editable_type); |
| 364 while (next_node && (!next_node->GetLayoutObject() || | 376 while (next_node && (!next_node->GetLayoutObject() || |
| 365 InSameLine(CreateVisiblePosition( | 377 InSameLine(CreateVisiblePosition( |
| 366 FirstPositionInOrBeforeNode(next_node)), | 378 FirstPositionInOrBeforeNode(next_node)), |
| 367 visible_position))) | 379 visible_position))) |
| 368 next_node = NextLeafWithSameEditability(next_node, kContentIsEditable); | 380 next_node = NextLeafWithSameEditability(next_node, kContentIsEditable); |
| 369 | 381 |
| 370 while (next_node && !next_node->IsShadowRoot()) { | 382 while (next_node && !next_node->IsShadowRoot()) { |
| 371 if (HighestEditableRoot(FirstPositionInOrBeforeNode(next_node), | 383 if (HighestEditableRoot(FirstPositionInOrBeforeNode(next_node), |
| 372 editable_type) != highest_root) | 384 editable_type) != highest_root) |
| 373 break; | 385 break; |
| 374 | 386 |
| 375 Position pos; | 387 Position pos; |
| 376 pos = Position::EditingPositionOf(next_node, CaretMinOffset(next_node)); | 388 pos = Position::EditingPositionOf(next_node, CaretMinOffset(next_node)); |
| 377 | 389 |
| 378 if (IsVisuallyEquivalentCandidate(pos)) | 390 if (IsVisuallyEquivalentCandidate(pos)) |
| 379 return pos; | 391 return pos; |
| 380 | 392 |
| 381 next_node = NextLeafWithSameEditability(next_node, editable_type); | 393 next_node = NextLeafWithSameEditability(next_node, editable_type); |
| 382 } | 394 } |
| 383 return Position(); | 395 return Position(); |
| 384 } | 396 } |
| 385 | 397 |
| 386 class CachedLogicallyOrderedLeafBoxes { | |
| 387 public: | |
| 388 CachedLogicallyOrderedLeafBoxes(); | |
| 389 | |
| 390 const InlineTextBox* PreviousTextBox(const RootInlineBox*, | |
| 391 const InlineTextBox*); | |
| 392 const InlineTextBox* NextTextBox(const RootInlineBox*, const InlineTextBox*); | |
| 393 | |
| 394 size_t size() const { return leaf_boxes_.size(); } | |
| 395 const InlineBox* FirstBox() const { return leaf_boxes_[0]; } | |
| 396 | |
| 397 private: | |
| 398 const Vector<InlineBox*>& CollectBoxes(const RootInlineBox*); | |
| 399 int BoxIndexInLeaves(const InlineTextBox*) const; | |
| 400 | |
| 401 const RootInlineBox* root_inline_box_; | |
| 402 Vector<InlineBox*> leaf_boxes_; | |
| 403 }; | |
| 404 | |
| 405 CachedLogicallyOrderedLeafBoxes::CachedLogicallyOrderedLeafBoxes() | |
| 406 : root_inline_box_(0) {} | |
| 407 | |
| 408 const InlineTextBox* CachedLogicallyOrderedLeafBoxes::PreviousTextBox( | |
| 409 const RootInlineBox* root, | |
| 410 const InlineTextBox* box) { | |
| 411 if (!root) | |
| 412 return 0; | |
| 413 | |
| 414 CollectBoxes(root); | |
| 415 | |
| 416 // If box is null, root is box's previous RootInlineBox, and previousBox is | |
| 417 // the last logical box in root. | |
| 418 int box_index = leaf_boxes_.size() - 1; | |
| 419 if (box) | |
| 420 box_index = BoxIndexInLeaves(box) - 1; | |
| 421 | |
| 422 for (int i = box_index; i >= 0; --i) { | |
| 423 if (leaf_boxes_[i]->IsInlineTextBox()) | |
| 424 return ToInlineTextBox(leaf_boxes_[i]); | |
| 425 } | |
| 426 | |
| 427 return 0; | |
| 428 } | |
| 429 | |
| 430 const InlineTextBox* CachedLogicallyOrderedLeafBoxes::NextTextBox( | |
| 431 const RootInlineBox* root, | |
| 432 const InlineTextBox* box) { | |
| 433 if (!root) | |
| 434 return 0; | |
| 435 | |
| 436 CollectBoxes(root); | |
| 437 | |
| 438 // If box is null, root is box's next RootInlineBox, and nextBox is the first | |
| 439 // logical box in root. Otherwise, root is box's RootInlineBox, and nextBox is | |
| 440 // the next logical box in the same line. | |
| 441 size_t next_box_index = 0; | |
| 442 if (box) | |
| 443 next_box_index = BoxIndexInLeaves(box) + 1; | |
| 444 | |
| 445 for (size_t i = next_box_index; i < leaf_boxes_.size(); ++i) { | |
| 446 if (leaf_boxes_[i]->IsInlineTextBox()) | |
| 447 return ToInlineTextBox(leaf_boxes_[i]); | |
| 448 } | |
| 449 | |
| 450 return 0; | |
| 451 } | |
| 452 | |
| 453 const Vector<InlineBox*>& CachedLogicallyOrderedLeafBoxes::CollectBoxes( | |
| 454 const RootInlineBox* root) { | |
| 455 if (root_inline_box_ != root) { | |
| 456 root_inline_box_ = root; | |
| 457 leaf_boxes_.clear(); | |
| 458 root->CollectLeafBoxesInLogicalOrder(leaf_boxes_); | |
| 459 } | |
| 460 return leaf_boxes_; | |
| 461 } | |
| 462 | |
| 463 int CachedLogicallyOrderedLeafBoxes::BoxIndexInLeaves( | |
| 464 const InlineTextBox* box) const { | |
| 465 for (size_t i = 0; i < leaf_boxes_.size(); ++i) { | |
| 466 if (box == leaf_boxes_[i]) | |
| 467 return i; | |
| 468 } | |
| 469 return 0; | |
| 470 } | |
| 471 | |
| 472 static const InlineTextBox* LogicallyPreviousBox( | |
| 473 const VisiblePosition& visible_position, | |
| 474 const InlineTextBox* text_box, | |
| 475 bool& previous_box_in_different_block, | |
| 476 CachedLogicallyOrderedLeafBoxes& leaf_boxes) { | |
| 477 DCHECK(visible_position.IsValid()) << visible_position; | |
| 478 const InlineBox* start_box = text_box; | |
| 479 | |
| 480 const InlineTextBox* previous_box = | |
| 481 leaf_boxes.PreviousTextBox(&start_box->Root(), text_box); | |
| 482 if (previous_box) | |
| 483 return previous_box; | |
| 484 | |
| 485 previous_box = leaf_boxes.PreviousTextBox(start_box->Root().PrevRootBox(), 0); | |
| 486 if (previous_box) | |
| 487 return previous_box; | |
| 488 | |
| 489 while (1) { | |
| 490 Node* start_node = start_box->GetLineLayoutItem().NonPseudoNode(); | |
| 491 if (!start_node) | |
| 492 break; | |
| 493 | |
| 494 Position position = PreviousRootInlineBoxCandidatePosition( | |
| 495 start_node, visible_position, kContentIsEditable); | |
| 496 if (position.IsNull()) | |
| 497 break; | |
| 498 | |
| 499 RenderedPosition rendered_position(position, TextAffinity::kDownstream); | |
| 500 RootInlineBox* previous_root = rendered_position.RootBox(); | |
| 501 if (!previous_root) | |
| 502 break; | |
| 503 | |
| 504 previous_box = leaf_boxes.PreviousTextBox(previous_root, 0); | |
| 505 if (previous_box) { | |
| 506 previous_box_in_different_block = true; | |
| 507 return previous_box; | |
| 508 } | |
| 509 | |
| 510 if (!leaf_boxes.size()) | |
| 511 break; | |
| 512 start_box = leaf_boxes.FirstBox(); | |
| 513 } | |
| 514 return 0; | |
| 515 } | |
| 516 | |
| 517 static const InlineTextBox* LogicallyNextBox( | |
| 518 const VisiblePosition& visible_position, | |
| 519 const InlineTextBox* text_box, | |
| 520 bool& next_box_in_different_block, | |
| 521 CachedLogicallyOrderedLeafBoxes& leaf_boxes) { | |
| 522 DCHECK(visible_position.IsValid()) << visible_position; | |
| 523 const InlineBox* start_box = text_box; | |
| 524 | |
| 525 const InlineTextBox* next_box = | |
| 526 leaf_boxes.NextTextBox(&start_box->Root(), text_box); | |
| 527 if (next_box) | |
| 528 return next_box; | |
| 529 | |
| 530 next_box = leaf_boxes.NextTextBox(start_box->Root().NextRootBox(), 0); | |
| 531 if (next_box) | |
| 532 return next_box; | |
| 533 | |
| 534 while (1) { | |
| 535 Node* start_node = start_box->GetLineLayoutItem().NonPseudoNode(); | |
| 536 if (!start_node) | |
| 537 break; | |
| 538 | |
| 539 Position position = NextRootInlineBoxCandidatePosition( | |
| 540 start_node, visible_position, kContentIsEditable); | |
| 541 if (position.IsNull()) | |
| 542 break; | |
| 543 | |
| 544 RenderedPosition rendered_position(position, TextAffinity::kDownstream); | |
| 545 RootInlineBox* next_root = rendered_position.RootBox(); | |
| 546 if (!next_root) | |
| 547 break; | |
| 548 | |
| 549 next_box = leaf_boxes.NextTextBox(next_root, 0); | |
| 550 if (next_box) { | |
| 551 next_box_in_different_block = true; | |
| 552 return next_box; | |
| 553 } | |
| 554 | |
| 555 if (!leaf_boxes.size()) | |
| 556 break; | |
| 557 start_box = leaf_boxes.FirstBox(); | |
| 558 } | |
| 559 return 0; | |
| 560 } | |
| 561 | |
| 562 static TextBreakIterator* WordBreakIteratorForMinOffsetBoundary( | |
| 563 const VisiblePosition& visible_position, | |
| 564 const InlineTextBox* text_box, | |
| 565 int& previous_box_length, | |
| 566 bool& previous_box_in_different_block, | |
| 567 Vector<UChar, 1024>& string, | |
| 568 CachedLogicallyOrderedLeafBoxes& leaf_boxes) { | |
| 569 DCHECK(visible_position.IsValid()) << visible_position; | |
| 570 previous_box_in_different_block = false; | |
| 571 | |
| 572 // FIXME: Handle the case when we don't have an inline text box. | |
| 573 const InlineTextBox* previous_box = LogicallyPreviousBox( | |
| 574 visible_position, text_box, previous_box_in_different_block, leaf_boxes); | |
| 575 | |
| 576 int len = 0; | |
| 577 string.clear(); | |
| 578 if (previous_box) { | |
| 579 previous_box_length = previous_box->Len(); | |
| 580 previous_box->GetLineLayoutItem().GetText().AppendTo( | |
| 581 string, previous_box->Start(), previous_box_length); | |
| 582 len += previous_box_length; | |
| 583 } | |
| 584 text_box->GetLineLayoutItem().GetText().AppendTo(string, text_box->Start(), | |
| 585 text_box->Len()); | |
| 586 len += text_box->Len(); | |
| 587 | |
| 588 return WordBreakIterator(string.data(), len); | |
| 589 } | |
| 590 | |
| 591 static TextBreakIterator* WordBreakIteratorForMaxOffsetBoundary( | |
| 592 const VisiblePosition& visible_position, | |
| 593 const InlineTextBox* text_box, | |
| 594 bool& next_box_in_different_block, | |
| 595 Vector<UChar, 1024>& string, | |
| 596 CachedLogicallyOrderedLeafBoxes& leaf_boxes) { | |
| 597 DCHECK(visible_position.IsValid()) << visible_position; | |
| 598 next_box_in_different_block = false; | |
| 599 | |
| 600 // FIXME: Handle the case when we don't have an inline text box. | |
| 601 const InlineTextBox* next_box = LogicallyNextBox( | |
| 602 visible_position, text_box, next_box_in_different_block, leaf_boxes); | |
| 603 | |
| 604 int len = 0; | |
| 605 string.clear(); | |
| 606 text_box->GetLineLayoutItem().GetText().AppendTo(string, text_box->Start(), | |
| 607 text_box->Len()); | |
| 608 len += text_box->Len(); | |
| 609 if (next_box) { | |
| 610 next_box->GetLineLayoutItem().GetText().AppendTo(string, next_box->Start(), | |
| 611 next_box->Len()); | |
| 612 len += next_box->Len(); | |
| 613 } | |
| 614 | |
| 615 return WordBreakIterator(string.data(), len); | |
| 616 } | |
| 617 | |
| 618 static bool IsLogicalStartOfWord(TextBreakIterator* iter, | |
| 619 int position, | |
| 620 bool hard_line_break) { | |
| 621 bool boundary = hard_line_break ? true : iter->isBoundary(position); | |
| 622 if (!boundary) | |
| 623 return false; | |
| 624 | |
| 625 iter->following(position); | |
| 626 // isWordTextBreak returns true after moving across a word and false after | |
| 627 // moving across a punctuation/space. | |
| 628 return IsWordTextBreak(iter); | |
| 629 } | |
| 630 | |
| 631 static bool IslogicalEndOfWord(TextBreakIterator* iter, | |
| 632 int position, | |
| 633 bool hard_line_break) { | |
| 634 bool boundary = iter->isBoundary(position); | |
| 635 return (hard_line_break || boundary) && IsWordTextBreak(iter); | |
| 636 } | |
| 637 | |
| 638 enum CursorMovementDirection { kMoveLeft, kMoveRight }; | |
| 639 | |
| 640 static VisiblePosition VisualWordPosition( | |
| 641 const VisiblePosition& visible_position, | |
| 642 CursorMovementDirection direction, | |
| 643 bool skips_space_when_moving_right) { | |
| 644 DCHECK(visible_position.IsValid()) << visible_position; | |
| 645 if (visible_position.IsNull()) | |
| 646 return VisiblePosition(); | |
| 647 | |
| 648 TextDirection block_direction = | |
| 649 DirectionOfEnclosingBlock(visible_position.DeepEquivalent()); | |
| 650 InlineBox* previously_visited_box = 0; | |
| 651 VisiblePosition current = visible_position; | |
| 652 TextBreakIterator* iter = 0; | |
| 653 | |
| 654 CachedLogicallyOrderedLeafBoxes leaf_boxes; | |
| 655 Vector<UChar, 1024> string; | |
| 656 | |
| 657 while (1) { | |
| 658 VisiblePosition adjacent_character_position = direction == kMoveRight | |
| 659 ? RightPositionOf(current) | |
| 660 : LeftPositionOf(current); | |
| 661 if (adjacent_character_position.DeepEquivalent() == | |
| 662 current.DeepEquivalent() || | |
| 663 adjacent_character_position.IsNull()) | |
| 664 return VisiblePosition(); | |
| 665 | |
| 666 InlineBoxPosition box_position = ComputeInlineBoxPosition( | |
| 667 adjacent_character_position.DeepEquivalent(), TextAffinity::kUpstream); | |
| 668 InlineBox* box = box_position.inline_box; | |
| 669 int offset_in_box = box_position.offset_in_box; | |
| 670 | |
| 671 if (!box) | |
| 672 break; | |
| 673 if (!box->IsInlineTextBox()) { | |
| 674 current = adjacent_character_position; | |
| 675 continue; | |
| 676 } | |
| 677 | |
| 678 InlineTextBox* text_box = ToInlineTextBox(box); | |
| 679 int previous_box_length = 0; | |
| 680 bool previous_box_in_different_block = false; | |
| 681 bool next_box_in_different_block = false; | |
| 682 bool moving_into_new_box = previously_visited_box != box; | |
| 683 | |
| 684 if (offset_in_box == box->CaretMinOffset()) { | |
| 685 iter = WordBreakIteratorForMinOffsetBoundary( | |
| 686 visible_position, text_box, previous_box_length, | |
| 687 previous_box_in_different_block, string, leaf_boxes); | |
| 688 } else if (offset_in_box == box->CaretMaxOffset()) { | |
| 689 iter = WordBreakIteratorForMaxOffsetBoundary(visible_position, text_box, | |
| 690 next_box_in_different_block, | |
| 691 string, leaf_boxes); | |
| 692 } else if (moving_into_new_box) { | |
| 693 iter = WordBreakIterator(text_box->GetLineLayoutItem().GetText(), | |
| 694 text_box->Start(), text_box->Len()); | |
| 695 previously_visited_box = box; | |
| 696 } | |
| 697 | |
| 698 if (!iter) | |
| 699 break; | |
| 700 | |
| 701 iter->first(); | |
| 702 int offset_in_iterator = | |
| 703 offset_in_box - text_box->Start() + previous_box_length; | |
| 704 | |
| 705 bool is_word_break; | |
| 706 bool box_has_same_directionality_as_block = | |
| 707 box->Direction() == block_direction; | |
| 708 bool moving_backward = | |
| 709 (direction == kMoveLeft && box->Direction() == TextDirection::kLtr) || | |
| 710 (direction == kMoveRight && box->Direction() == TextDirection::kRtl); | |
| 711 if ((skips_space_when_moving_right && | |
| 712 box_has_same_directionality_as_block) || | |
| 713 (!skips_space_when_moving_right && moving_backward)) { | |
| 714 bool logical_start_in_layout_object = | |
| 715 offset_in_box == static_cast<int>(text_box->Start()) && | |
| 716 previous_box_in_different_block; | |
| 717 is_word_break = IsLogicalStartOfWord(iter, offset_in_iterator, | |
| 718 logical_start_in_layout_object); | |
| 719 } else { | |
| 720 bool logical_end_in_layout_object = | |
| 721 offset_in_box == | |
| 722 static_cast<int>(text_box->Start() + text_box->Len()) && | |
| 723 next_box_in_different_block; | |
| 724 is_word_break = IslogicalEndOfWord(iter, offset_in_iterator, | |
| 725 logical_end_in_layout_object); | |
| 726 } | |
| 727 | |
| 728 if (is_word_break) | |
| 729 return adjacent_character_position; | |
| 730 | |
| 731 current = adjacent_character_position; | |
| 732 } | |
| 733 return VisiblePosition(); | |
| 734 } | |
| 735 | |
| 736 VisiblePosition LeftWordPosition(const VisiblePosition& visible_position, | |
| 737 bool skips_space_when_moving_right) { | |
| 738 DCHECK(visible_position.IsValid()) << visible_position; | |
| 739 VisiblePosition left_word_break = VisualWordPosition( | |
| 740 visible_position, kMoveLeft, skips_space_when_moving_right); | |
| 741 left_word_break = HonorEditingBoundaryAtOrBefore( | |
| 742 left_word_break, visible_position.DeepEquivalent()); | |
| 743 | |
| 744 // FIXME: How should we handle a non-editable position? | |
| 745 if (left_word_break.IsNull() && | |
| 746 IsEditablePosition(visible_position.DeepEquivalent())) { | |
| 747 TextDirection block_direction = | |
| 748 DirectionOfEnclosingBlock(visible_position.DeepEquivalent()); | |
| 749 left_word_break = block_direction == TextDirection::kLtr | |
| 750 ? StartOfEditableContent(visible_position) | |
| 751 : EndOfEditableContent(visible_position); | |
| 752 } | |
| 753 return left_word_break; | |
| 754 } | |
| 755 | |
| 756 VisiblePosition RightWordPosition(const VisiblePosition& visible_position, | |
| 757 bool skips_space_when_moving_right) { | |
| 758 DCHECK(visible_position.IsValid()) << visible_position; | |
| 759 VisiblePosition right_word_break = VisualWordPosition( | |
| 760 visible_position, kMoveRight, skips_space_when_moving_right); | |
| 761 right_word_break = HonorEditingBoundaryAtOrBefore( | |
| 762 right_word_break, visible_position.DeepEquivalent()); | |
| 763 | |
| 764 // FIXME: How should we handle a non-editable position? | |
| 765 if (right_word_break.IsNull() && | |
| 766 IsEditablePosition(visible_position.DeepEquivalent())) { | |
| 767 TextDirection block_direction = | |
| 768 DirectionOfEnclosingBlock(visible_position.DeepEquivalent()); | |
| 769 right_word_break = block_direction == TextDirection::kLtr | |
| 770 ? EndOfEditableContent(visible_position) | |
| 771 : StartOfEditableContent(visible_position); | |
| 772 } | |
| 773 return right_word_break; | |
| 774 } | |
| 775 | |
| 776 template <typename Strategy> | 398 template <typename Strategy> |
| 777 static ContainerNode* NonShadowBoundaryParentNode(Node* node) { | 399 static ContainerNode* NonShadowBoundaryParentNode(Node* node) { |
| 778 ContainerNode* parent = Strategy::Parent(*node); | 400 ContainerNode* parent = Strategy::Parent(*node); |
| 779 return parent && !parent->IsShadowRoot() ? parent : nullptr; | 401 return parent && !parent->IsShadowRoot() ? parent : nullptr; |
| 780 } | 402 } |
| 781 | 403 |
| 782 template <typename Strategy> | 404 template <typename Strategy> |
| 783 static Node* ParentEditingBoundary(const PositionTemplate<Strategy>& position) { | 405 static Node* ParentEditingBoundary(const PositionTemplate<Strategy>& position) { |
| 784 Node* const anchor_node = position.AnchorNode(); | 406 Node* const anchor_node = position.AnchorNode(); |
| 785 if (!anchor_node) | 407 if (!anchor_node) |
| (...skipping 3361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4147 | 3769 |
| 4148 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) { | 3770 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) { |
| 4149 return EnclosingIntRect(ComputeTextRectTemplate(range)); | 3771 return EnclosingIntRect(ComputeTextRectTemplate(range)); |
| 4150 } | 3772 } |
| 4151 | 3773 |
| 4152 FloatRect ComputeTextFloatRect(const EphemeralRange& range) { | 3774 FloatRect ComputeTextFloatRect(const EphemeralRange& range) { |
| 4153 return ComputeTextRectTemplate(range); | 3775 return ComputeTextRectTemplate(range); |
| 4154 } | 3776 } |
| 4155 | 3777 |
| 4156 } // namespace blink | 3778 } // namespace blink |
| OLD | NEW |