OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/editing/FrameSelection.h" | 5 #include "core/editing/FrameSelection.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include "bindings/core/v8/ExceptionState.h" | 8 #include "bindings/core/v8/ExceptionState.h" |
9 #include "core/dom/Document.h" | 9 #include "core/dom/Document.h" |
10 #include "core/dom/Element.h" | 10 #include "core/dom/Element.h" |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 .Build()); | 343 .Build()); |
344 // Should not crash inside. | 344 // Should not crash inside. |
345 const VisibleSelectionInFlatTree& selection = | 345 const VisibleSelectionInFlatTree& selection = |
346 Selection().ComputeVisibleSelectionInFlatTree(); | 346 Selection().ComputeVisibleSelectionInFlatTree(); |
347 | 347 |
348 // This only records the current behavior. It might be changed in the future. | 348 // This only records the current behavior. It might be changed in the future. |
349 EXPECT_EQ(PositionInFlatTree(foo, 0), selection.Base()); | 349 EXPECT_EQ(PositionInFlatTree(foo, 0), selection.Base()); |
350 EXPECT_EQ(PositionInFlatTree(foo, 0), selection.Extent()); | 350 EXPECT_EQ(PositionInFlatTree(foo, 0), selection.Extent()); |
351 } | 351 } |
352 | 352 |
| 353 TEST_F(FrameSelectionTest, CaretInShadowTree) { |
| 354 SetBodyContent("<p id=host></p>bar"); |
| 355 ShadowRoot* shadow_root = |
| 356 SetShadowContent("<div contenteditable id='ce'>foo</div>", "host"); |
| 357 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 358 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 359 EXPECT_TRUE(Selection().IsHidden()); |
| 360 |
| 361 Element* const ce = shadow_root->getElementById("ce"); |
| 362 ce->focus(); |
| 363 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 364 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 365 EXPECT_FALSE(Selection().IsHidden()); |
| 366 |
| 367 ce->blur(); // Move focus to document body. |
| 368 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 369 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 370 EXPECT_TRUE(Selection().IsHidden()); // Caret is now hidden. |
| 371 } |
| 372 |
| 373 TEST_F(FrameSelectionTest, CaretInTextControl) { |
| 374 SetBodyContent("<input id='field'>"); // <input> hosts a shadow tree. |
| 375 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 376 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 377 EXPECT_TRUE(Selection().IsHidden()); |
| 378 |
| 379 Element* const field = GetDocument().getElementById("field"); |
| 380 field->focus(); |
| 381 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 382 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 383 EXPECT_FALSE(Selection().IsHidden()); |
| 384 |
| 385 field->blur(); // Move focus to document body. |
| 386 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 387 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 388 EXPECT_TRUE(Selection().IsHidden()); // Caret is now hidden. |
| 389 } |
| 390 |
| 391 TEST_F(FrameSelectionTest, RangeInShadowTree) { |
| 392 SetBodyContent("<p id='host'></p>"); |
| 393 ShadowRoot* shadow_root = SetShadowContent("hey", "host"); |
| 394 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 395 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 396 EXPECT_TRUE(Selection().IsHidden()); |
| 397 |
| 398 Node* text_node = shadow_root->firstChild(); |
| 399 Selection().SetSelection( |
| 400 SelectionInFlatTree::Builder() |
| 401 .SetBaseAndExtent(PositionInFlatTree(text_node, 0), |
| 402 PositionInFlatTree(text_node, 3)) |
| 403 .Build()); |
| 404 EXPECT_EQ_SELECTED_TEXT("hey"); |
| 405 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 406 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 407 EXPECT_FALSE(Selection().IsHidden()); |
| 408 |
| 409 GetDocument().body()->focus(); // Move focus to document body. |
| 410 EXPECT_EQ_SELECTED_TEXT("hey"); |
| 411 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 412 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 413 EXPECT_FALSE(Selection().IsHidden()); |
| 414 } |
| 415 |
| 416 TEST_F(FrameSelectionTest, RangeInTextControl) { |
| 417 SetBodyContent("<input id='field' value='hola'>"); |
| 418 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 419 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 420 EXPECT_TRUE(Selection().IsHidden()); |
| 421 |
| 422 Element* const field = GetDocument().getElementById("field"); |
| 423 field->focus(); |
| 424 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 425 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 426 EXPECT_FALSE(Selection().IsHidden()); |
| 427 |
| 428 Selection().SelectAll(); |
| 429 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 430 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 431 EXPECT_FALSE(Selection().IsHidden()); |
| 432 |
| 433 field->blur(); |
| 434 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 435 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 436 EXPECT_TRUE(Selection().IsHidden()); |
| 437 } |
| 438 |
| 439 // crbug.com/692898 |
| 440 TEST_F(FrameSelectionTest, FocusingLinkHidesCaretInTextControl) { |
| 441 SetBodyContent( |
| 442 "<input id='field'>" |
| 443 "<a href='www' id='alink'>link</a>"); |
| 444 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 445 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 446 EXPECT_TRUE(Selection().IsHidden()); |
| 447 |
| 448 Element* const field = GetDocument().getElementById("field"); |
| 449 field->focus(); |
| 450 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 451 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 452 EXPECT_FALSE(Selection().IsHidden()); |
| 453 |
| 454 Element* const alink = GetDocument().getElementById("alink"); |
| 455 alink->focus(); |
| 456 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 457 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 458 EXPECT_TRUE(Selection().IsHidden()); |
| 459 } |
| 460 |
| 461 // crbug.com/692898 |
| 462 TEST_F(FrameSelectionTest, FocusingLinkHidesRangeInTextControl) { |
| 463 SetBodyContent( |
| 464 "<input id='field' value='hola'>" |
| 465 "<a href='www' id='alink'>link</a>"); |
| 466 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 467 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 468 EXPECT_TRUE(Selection().IsHidden()); |
| 469 |
| 470 Element* const field = GetDocument().getElementById("field"); |
| 471 field->focus(); |
| 472 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 473 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 474 EXPECT_FALSE(Selection().IsHidden()); |
| 475 |
| 476 Selection().SelectAll(); |
| 477 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 478 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 479 EXPECT_FALSE(Selection().IsHidden()); |
| 480 |
| 481 Element* const alink = GetDocument().getElementById("alink"); |
| 482 alink->focus(); |
| 483 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 484 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 485 EXPECT_TRUE(Selection().IsHidden()); |
| 486 } |
| 487 |
| 488 TEST_F(FrameSelectionTest, FocusingButtonHidesRangeInReadOnlyTextControl) { |
| 489 SetBodyContent( |
| 490 "<textarea readonly>Berlin</textarea>" |
| 491 "<input type='submit' value='Submit'>"); |
| 492 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 493 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 494 EXPECT_TRUE(Selection().IsHidden()); |
| 495 |
| 496 Element* const textarea = GetDocument().QuerySelector("textarea"); |
| 497 textarea->focus(); |
| 498 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 499 |
| 500 Selection().SelectAll(); |
| 501 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 502 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 503 EXPECT_FALSE(Selection().IsHidden()); |
| 504 |
| 505 Element* const submit = GetDocument().QuerySelector("input"); |
| 506 submit->focus(); |
| 507 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 508 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 509 EXPECT_TRUE(Selection().IsHidden()); |
| 510 } |
| 511 |
| 512 TEST_F(FrameSelectionTest, FocusingButtonHidesRangeInDisabledTextControl) { |
| 513 SetBodyContent( |
| 514 "<textarea disabled>Berlin</textarea>" |
| 515 "<input type='submit' value='Submit'>"); |
| 516 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 517 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 518 EXPECT_TRUE(Selection().IsHidden()); |
| 519 |
| 520 Element* const textarea = GetDocument().QuerySelector("textarea"); |
| 521 textarea->focus(); |
| 522 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 523 |
| 524 // We use a double click to create the selection [Berlin]. |
| 525 // FrameSelection::SelectAll (= textarea.select() in JavaScript) would have |
| 526 // been shorter, but currently that doesn't work on a *disabled* text control. |
| 527 const IntRect elem_bounds = textarea->BoundsInViewport(); |
| 528 WebMouseEvent double_click(WebMouseEvent::kMouseDown, 0, |
| 529 WebInputEvent::kTimeStampForTesting); |
| 530 double_click.SetPositionInWidget(elem_bounds.X(), elem_bounds.Y()); |
| 531 double_click.SetPositionInScreen(elem_bounds.X(), elem_bounds.Y()); |
| 532 double_click.button = WebMouseEvent::Button::kLeft; |
| 533 double_click.click_count = 2; |
| 534 double_click.SetFrameScale(1); |
| 535 |
| 536 GetFrame().GetEventHandler().HandleMousePressEvent(double_click); |
| 537 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 538 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 539 EXPECT_FALSE(Selection().IsHidden()); |
| 540 |
| 541 Element* const submit = GetDocument().QuerySelector("input"); |
| 542 submit->focus(); |
| 543 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 544 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 545 EXPECT_TRUE(Selection().IsHidden()); |
| 546 } |
| 547 |
| 548 // crbug.com/713051 |
| 549 TEST_F(FrameSelectionTest, FocusingNonEditableParentHidesCaretInTextControl) { |
| 550 SetBodyContent( |
| 551 "<div tabindex='-1' id='parent'>" |
| 552 " <input id='field'>" |
| 553 "</div>"); |
| 554 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 555 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 556 EXPECT_TRUE(Selection().IsHidden()); |
| 557 |
| 558 Element* const field = GetDocument().getElementById("field"); |
| 559 field->focus(); |
| 560 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 561 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 562 EXPECT_FALSE(Selection().IsHidden()); |
| 563 |
| 564 // Here the selection belongs to <input>'s shadow tree and that tree has a |
| 565 // non-editable parent that is focused. |
| 566 Element* const parent = GetDocument().getElementById("parent"); |
| 567 parent->focus(); |
| 568 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 569 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 570 EXPECT_TRUE(Selection().IsHidden()); // Focus is outside <input> |
| 571 // so caret should not be visible. |
| 572 |
| 573 parent->blur(); // Move focus to document body. |
| 574 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 575 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 576 EXPECT_TRUE(Selection().IsHidden()); // Caret is still hidden. |
| 577 } |
| 578 |
| 579 // crbug.com/713051 |
| 580 TEST_F(FrameSelectionTest, FocusingNonEditableParentHidesRangeInTextControl) { |
| 581 SetBodyContent( |
| 582 "<div tabindex='-1' id='parent'>" |
| 583 " <input id='field' value='hola'>" |
| 584 "</div>"); |
| 585 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 586 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 587 EXPECT_TRUE(Selection().IsHidden()); |
| 588 |
| 589 Element* const field = GetDocument().getElementById("field"); |
| 590 field->focus(); |
| 591 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 592 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 593 EXPECT_FALSE(Selection().IsHidden()); |
| 594 |
| 595 Selection().SelectAll(); |
| 596 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 597 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 598 EXPECT_FALSE(Selection().IsHidden()); |
| 599 |
| 600 // Here the selection belongs to <input>'s shadow tree and that tree has a |
| 601 // non-editable parent that is focused. |
| 602 Element* const parent = GetDocument().getElementById("parent"); |
| 603 parent->focus(); |
| 604 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 605 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 606 EXPECT_TRUE(Selection().IsHidden()); // Focus is outside <input> |
| 607 // so range should not be visible. |
| 608 |
| 609 parent->blur(); // Move focus to document body. |
| 610 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 611 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 612 EXPECT_TRUE(Selection().IsHidden()); // Range is still hidden. |
| 613 } |
| 614 |
| 615 TEST_F(FrameSelectionTest, CaretInEditableDiv) { |
| 616 SetBodyContent("<div contenteditable id='ce'>blabla</div>"); |
| 617 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 618 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 619 EXPECT_TRUE(Selection().IsHidden()); |
| 620 |
| 621 Element* const ce = GetDocument().getElementById("ce"); |
| 622 ce->focus(); |
| 623 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 624 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 625 EXPECT_FALSE(Selection().IsHidden()); |
| 626 |
| 627 ce->blur(); // Move focus to document body. |
| 628 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 629 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 630 EXPECT_TRUE(Selection().IsHidden()); // Caret is now hidden. |
| 631 } |
| 632 |
| 633 TEST_F(FrameSelectionTest, RangeInEditableDiv) { |
| 634 SetBodyContent("<div contenteditable id='ce'>blabla</div>"); |
| 635 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 636 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 637 EXPECT_TRUE(Selection().IsHidden()); |
| 638 |
| 639 Element* const ce = GetDocument().getElementById("ce"); |
| 640 ce->focus(); |
| 641 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 642 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 643 EXPECT_FALSE(Selection().IsHidden()); |
| 644 |
| 645 Selection().SelectAll(); |
| 646 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 647 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 648 EXPECT_FALSE(Selection().IsHidden()); |
| 649 |
| 650 ce->blur(); // Move focus to document body. |
| 651 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 652 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 653 EXPECT_FALSE(Selection().IsHidden()); // Range is still visible. |
| 654 } |
| 655 |
| 656 TEST_F(FrameSelectionTest, RangeInEditableDivInShadowTree) { |
| 657 SetBodyContent("<p id='host'></p>"); |
| 658 ShadowRoot* shadow_root = |
| 659 SetShadowContent("<div id='ce' contenteditable>foo</div>", "host"); |
| 660 |
| 661 Element* const ce = shadow_root->getElementById("ce"); |
| 662 ce->focus(); |
| 663 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 664 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 665 EXPECT_FALSE(Selection().IsHidden()); |
| 666 |
| 667 Selection().SelectAll(); |
| 668 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 669 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 670 EXPECT_FALSE(Selection().IsHidden()); |
| 671 |
| 672 ce->blur(); |
| 673 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 674 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 675 EXPECT_FALSE(Selection().IsHidden()); // Range is still visible. |
| 676 } |
| 677 |
| 678 TEST_F(FrameSelectionTest, FocusingLinkHidesCaretInContentEditable) { |
| 679 SetBodyContent( |
| 680 "<div contenteditable id='ce'>blabla</div>" |
| 681 "<a href='www' id='alink'>link</a>"); |
| 682 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 683 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 684 EXPECT_TRUE(Selection().IsHidden()); |
| 685 |
| 686 Element* const ce = GetDocument().getElementById("ce"); |
| 687 ce->focus(); |
| 688 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 689 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 690 EXPECT_FALSE(Selection().IsHidden()); |
| 691 |
| 692 Element* const alink = GetDocument().getElementById("alink"); |
| 693 alink->focus(); |
| 694 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 695 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 696 EXPECT_TRUE(Selection().IsHidden()); |
| 697 } |
| 698 |
| 699 TEST_F(FrameSelectionTest, FocusingLinkKeepsRangeInContentEditable) { |
| 700 SetBodyContent( |
| 701 "<div contenteditable id='ce'>blabla</div>" |
| 702 "<a href='www' id='alink'>link</a>"); |
| 703 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 704 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 705 EXPECT_TRUE(Selection().IsHidden()); |
| 706 |
| 707 Element* const ce = GetDocument().getElementById("ce"); |
| 708 ce->focus(); |
| 709 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 710 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 711 EXPECT_FALSE(Selection().IsHidden()); |
| 712 |
| 713 Selection().SelectAll(); |
| 714 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 715 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 716 EXPECT_FALSE(Selection().IsHidden()); |
| 717 |
| 718 Element* const alink = GetDocument().getElementById("alink"); |
| 719 alink->focus(); |
| 720 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 721 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 722 EXPECT_FALSE(Selection().IsHidden()); |
| 723 } |
| 724 |
| 725 TEST_F(FrameSelectionTest, FocusingEditableParentKeepsEditableCaret) { |
| 726 SetBodyContent( |
| 727 "<div contenteditable tabindex='-1' id='parent'>" |
| 728 "<div contenteditable id='ce'>blabla</div>" |
| 729 "</div>"); |
| 730 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 731 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 732 EXPECT_TRUE(Selection().IsHidden()); |
| 733 |
| 734 // TODO(editing-dev): Blink should be able to focus the inner <div>. |
| 735 // Element* const ce = GetDocument().getElementById("ce"); |
| 736 // ce->focus(); |
| 737 // EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 738 // EXPECT_FALSE(Selection().IsHidden()); |
| 739 |
| 740 Element* const parent = GetDocument().getElementById("parent"); |
| 741 parent->focus(); |
| 742 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 743 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 744 EXPECT_FALSE(Selection().IsHidden()); // Focus is within editing boundary, |
| 745 // caret should be visible. |
| 746 |
| 747 parent->blur(); // Move focus to document body. |
| 748 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 749 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 750 EXPECT_TRUE(Selection().IsHidden()); // Focus is outside editing boundary |
| 751 // so caret should be hidden. |
| 752 } |
| 753 |
| 754 TEST_F(FrameSelectionTest, FocusingEditableParentKeepsEditableRange) { |
| 755 SetBodyContent( |
| 756 "<div contenteditable tabindex='-1' id='parent'>" |
| 757 "<div contenteditable id='ce'>blabla</div>" |
| 758 "</div>"); |
| 759 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 760 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 761 EXPECT_TRUE(Selection().IsHidden()); |
| 762 |
| 763 // TODO(editing-dev): Blink should be able to focus the inner <div>. |
| 764 // Element* const ce = GetDocument().getElementById("ce"); |
| 765 // ce->focus(); |
| 766 // EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 767 // EXPECT_FALSE(Selection().IsHidden()); |
| 768 |
| 769 // Selection().SelectAll(); |
| 770 // EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 771 // EXPECT_FALSE(Selection().IsHidden()); |
| 772 |
| 773 Element* const parent = GetDocument().getElementById("parent"); |
| 774 parent->focus(); |
| 775 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 776 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 777 EXPECT_FALSE(Selection().IsHidden()); // Focus is within editing boundary, |
| 778 // range should be visible. |
| 779 |
| 780 Selection().SelectAll(); |
| 781 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 782 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 783 EXPECT_FALSE(Selection().IsHidden()); |
| 784 |
| 785 parent->blur(); // Move focus to document body. |
| 786 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 787 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 788 EXPECT_FALSE(Selection().IsHidden()); // Focus is outside editing boundary |
| 789 // but range should still be visible. |
| 790 } |
| 791 |
| 792 TEST_F(FrameSelectionTest, FocusingNonEditableParentHidesEditableCaret) { |
| 793 SetBodyContent( |
| 794 "<div tabindex='-1' id='parent'>" |
| 795 "<div contenteditable id='ce'>blabla</div>" |
| 796 "</div>"); |
| 797 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 798 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 799 EXPECT_TRUE(Selection().IsHidden()); |
| 800 |
| 801 Element* const ce = GetDocument().getElementById("ce"); |
| 802 ce->focus(); |
| 803 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 804 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 805 EXPECT_FALSE(Selection().IsHidden()); |
| 806 |
| 807 // Here the selection belongs to <div>'s shadow tree and that tree has a |
| 808 // non-editable parent that is focused. |
| 809 Element* const parent = GetDocument().getElementById("parent"); |
| 810 parent->focus(); |
| 811 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 812 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 813 EXPECT_TRUE(Selection().IsHidden()); // Focus is outside editing boundary |
| 814 // so caret should be hidden. |
| 815 |
| 816 parent->blur(); // Move focus to document body. |
| 817 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 818 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 819 EXPECT_TRUE(Selection().IsHidden()); // Caret is still hidden. |
| 820 } |
| 821 |
| 822 TEST_F(FrameSelectionTest, FocusingNonEditableParentKeepsEditableRange) { |
| 823 SetBodyContent( |
| 824 "<div tabindex='-1' id='parent'>" |
| 825 "<div contenteditable id='ce'>blabla</div>" |
| 826 "</div>"); |
| 827 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 828 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 829 EXPECT_TRUE(Selection().IsHidden()); |
| 830 |
| 831 Element* const ce = GetDocument().getElementById("ce"); |
| 832 ce->focus(); |
| 833 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsCaret()); |
| 834 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 835 EXPECT_FALSE(Selection().IsHidden()); |
| 836 |
| 837 Selection().SelectAll(); |
| 838 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 839 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 840 EXPECT_FALSE(Selection().IsHidden()); |
| 841 |
| 842 // Here the selection belongs to <div>'s shadow tree and that tree has a |
| 843 // non-editable parent that is focused. |
| 844 Element* const parent = GetDocument().getElementById("parent"); |
| 845 parent->focus(); |
| 846 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 847 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 848 EXPECT_FALSE(Selection().IsHidden()); // Focus is outside editing boundary |
| 849 // but range should still be visible. |
| 850 |
| 851 parent->blur(); // Move focus to document body. |
| 852 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 853 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 854 EXPECT_FALSE(Selection().IsHidden()); // Range is still visible. |
| 855 } |
| 856 |
| 857 // crbug.com/707143 |
| 858 TEST_F(FrameSelectionTest, RangeContainsFocus) { |
| 859 SetBodyContent( |
| 860 "<div>" |
| 861 " <div>" |
| 862 " <span id='start'>start</span>" |
| 863 " </div>" |
| 864 " <a href='www' id='alink'>link</a>" |
| 865 " <div>line 1</div>" |
| 866 " <div>line 2</div>" |
| 867 " <div>line 3</div>" |
| 868 " <div>line 4</div>" |
| 869 " <span id='end'>end</span>" |
| 870 " <div></div>" |
| 871 "</div>"); |
| 872 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 873 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 874 EXPECT_TRUE(Selection().IsHidden()); |
| 875 |
| 876 Element* const start = GetDocument().getElementById("start"); |
| 877 Element* const end = GetDocument().getElementById("end"); |
| 878 Selection().SetSelection( |
| 879 SelectionInDOMTree::Builder() |
| 880 .SetBaseAndExtent(Position(start, 0), Position(end, 3)) |
| 881 .Build()); |
| 882 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 883 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 884 EXPECT_FALSE(Selection().IsHidden()); |
| 885 |
| 886 Element* const alink = GetDocument().getElementById("alink"); |
| 887 alink->focus(); |
| 888 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 889 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 890 EXPECT_FALSE(Selection().IsHidden()); // Range still visible. |
| 891 } |
| 892 |
| 893 // crbug.com/707143 |
| 894 TEST_F(FrameSelectionTest, RangeOutsideFocus) { |
| 895 // Here the selection sits on a sub tree that hasn't the focused element. |
| 896 // This test case is the reason why we separate FrameSelection::HasFocus() and |
| 897 // FrameSelection::IsHidden(). Even when the selection's DOM nodes are |
| 898 // completely disconnected from the focused node, we still want the selection |
| 899 // to be visible (not hidden). |
| 900 SetBodyContent( |
| 901 "<a href='www' id='alink'>link</a>" |
| 902 "<div>" |
| 903 " <div>" |
| 904 " <span id='start'>start</span>" |
| 905 " </div>" |
| 906 " <div>line 1</div>" |
| 907 " <div>line 2</div>" |
| 908 " <div>line 3</div>" |
| 909 " <div>line 4</div>" |
| 910 " <span id='end'>end</span>" |
| 911 " <div></div>" |
| 912 "</div>"); |
| 913 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsNone()); |
| 914 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 915 EXPECT_TRUE(Selection().IsHidden()); |
| 916 |
| 917 Element* const start = GetDocument().getElementById("start"); |
| 918 Element* const end = GetDocument().getElementById("end"); |
| 919 Selection().SetSelection( |
| 920 SelectionInDOMTree::Builder() |
| 921 .SetBaseAndExtent(Position(start, 0), Position(end, 3)) |
| 922 .Build()); |
| 923 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 924 EXPECT_TRUE(Selection().SelectionHasFocus()); |
| 925 EXPECT_FALSE(Selection().IsHidden()); |
| 926 |
| 927 Element* const alink = GetDocument().getElementById("alink"); |
| 928 alink->focus(); |
| 929 EXPECT_TRUE(Selection().GetSelectionInDOMTree().IsRange()); |
| 930 EXPECT_FALSE(Selection().SelectionHasFocus()); |
| 931 EXPECT_FALSE(Selection().IsHidden()); // Range still visible. |
| 932 } |
| 933 |
353 } // namespace blink | 934 } // namespace blink |
OLD | NEW |