| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. | 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. |
| 4 * All rights reserved. | 4 * All rights reserved. |
| 5 * | 5 * |
| 6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
| 7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
| 8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
| 9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
| 10 * | 10 * |
| 11 * This library is distributed in the hope that it will be useful, | 11 * This library is distributed in the hope that it will be useful, |
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 * Library General Public License for more details. | 14 * Library General Public License for more details. |
| 15 * | 15 * |
| 16 * You should have received a copy of the GNU Library General Public License | 16 * You should have received a copy of the GNU Library General Public License |
| 17 * along with this library; see the file COPYING.LIB. If not, write to | 17 * along with this library; see the file COPYING.LIB. If not, write to |
| 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 19 * Boston, MA 02110-1301, USA. | 19 * Boston, MA 02110-1301, USA. |
| 20 */ | 20 */ |
| 21 | 21 |
| 22 #include "core/layout/LayoutView.h" | 22 #include "core/layout/LayoutView.h" |
| 23 | 23 |
| 24 #include <inttypes.h> | 24 #include <inttypes.h> |
| 25 #include "core/dom/Document.h" | 25 #include "core/dom/Document.h" |
| 26 #include "core/dom/Element.h" | 26 #include "core/dom/Element.h" |
| 27 #include "core/editing/FrameSelection.h" | 27 #include "core/editing/FrameSelection.h" |
| 28 #include "core/editing/LayoutSelection.h" | |
| 29 #include "core/frame/FrameView.h" | 28 #include "core/frame/FrameView.h" |
| 30 #include "core/frame/LocalFrame.h" | 29 #include "core/frame/LocalFrame.h" |
| 31 #include "core/frame/Settings.h" | 30 #include "core/frame/Settings.h" |
| 32 #include "core/html/HTMLIFrameElement.h" | 31 #include "core/html/HTMLIFrameElement.h" |
| 33 #include "core/layout/HitTestResult.h" | 32 #include "core/layout/HitTestResult.h" |
| 34 #include "core/layout/LayoutGeometryMap.h" | 33 #include "core/layout/LayoutGeometryMap.h" |
| 35 #include "core/layout/LayoutPart.h" | 34 #include "core/layout/LayoutPart.h" |
| 36 #include "core/layout/ViewFragmentationContext.h" | 35 #include "core/layout/ViewFragmentationContext.h" |
| 37 #include "core/layout/api/LayoutAPIShim.h" | 36 #include "core/layout/api/LayoutAPIShim.h" |
| 38 #include "core/layout/api/LayoutPartItem.h" | 37 #include "core/layout/api/LayoutPartItem.h" |
| (...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 rects.push_back( | 602 rects.push_back( |
| 604 PixelSnappedIntRect(accumulated_offset, LayoutSize(Layer()->size()))); | 603 PixelSnappedIntRect(accumulated_offset, LayoutSize(Layer()->size()))); |
| 605 } | 604 } |
| 606 | 605 |
| 607 void LayoutView::AbsoluteQuads(Vector<FloatQuad>& quads, | 606 void LayoutView::AbsoluteQuads(Vector<FloatQuad>& quads, |
| 608 MapCoordinatesFlags mode) const { | 607 MapCoordinatesFlags mode) const { |
| 609 quads.push_back(LocalToAbsoluteQuad( | 608 quads.push_back(LocalToAbsoluteQuad( |
| 610 FloatRect(FloatPoint(), FloatSize(Layer()->size())), mode)); | 609 FloatRect(FloatPoint(), FloatSize(Layer()->size())), mode)); |
| 611 } | 610 } |
| 612 | 611 |
| 613 static LayoutObject* LayoutObjectAfterPosition(LayoutObject* object, | |
| 614 unsigned offset) { | |
| 615 if (!object) | |
| 616 return nullptr; | |
| 617 | |
| 618 LayoutObject* child = object->ChildAt(offset); | |
| 619 return child ? child : object->NextInPreOrderAfterChildren(); | |
| 620 } | |
| 621 | |
| 622 static LayoutRect SelectionRectForLayoutObject(const LayoutObject* object) { | |
| 623 if (!object->IsRooted()) | |
| 624 return LayoutRect(); | |
| 625 | |
| 626 if (!object->CanUpdateSelectionOnRootLineBoxes()) | |
| 627 return LayoutRect(); | |
| 628 | |
| 629 return object->SelectionRectInViewCoordinates(); | |
| 630 } | |
| 631 | |
| 632 // TODO(yoichio): Move this to LayoutSelection. | |
| 633 IntRect LayoutSelection::SelectionBounds() { | |
| 634 // Now create a single bounding box rect that encloses the whole selection. | |
| 635 LayoutRect sel_rect; | |
| 636 | |
| 637 typedef HashSet<const LayoutBlock*> VisitedContainingBlockSet; | |
| 638 VisitedContainingBlockSet visited_containing_blocks; | |
| 639 | |
| 640 Commit(*frame_selection_->GetDocument().GetLayoutView()); | |
| 641 LayoutObject* os = selection_start_; | |
| 642 LayoutObject* stop = | |
| 643 LayoutObjectAfterPosition(selection_end_, selection_end_pos_); | |
| 644 while (os && os != stop) { | |
| 645 if ((os->CanBeSelectionLeaf() || os == selection_start_ || | |
| 646 os == selection_end_) && | |
| 647 os->GetSelectionState() != SelectionNone) { | |
| 648 // Blocks are responsible for painting line gaps and margin gaps. They | |
| 649 // must be examined as well. | |
| 650 sel_rect.Unite(SelectionRectForLayoutObject(os)); | |
| 651 const LayoutBlock* cb = os->ContainingBlock(); | |
| 652 while (cb && !cb->IsLayoutView()) { | |
| 653 sel_rect.Unite(SelectionRectForLayoutObject(cb)); | |
| 654 VisitedContainingBlockSet::AddResult add_result = | |
| 655 visited_containing_blocks.insert(cb); | |
| 656 if (!add_result.is_new_entry) | |
| 657 break; | |
| 658 cb = cb->ContainingBlock(); | |
| 659 } | |
| 660 } | |
| 661 | |
| 662 os = os->NextInPreOrder(); | |
| 663 } | |
| 664 | |
| 665 return PixelSnappedIntRect(sel_rect); | |
| 666 } | |
| 667 | |
| 668 // TODO(yoichio): Move this to LayoutSelection. | |
| 669 void LayoutSelection::InvalidatePaintForSelection() { | |
| 670 LayoutObject* end = | |
| 671 LayoutObjectAfterPosition(selection_end_, selection_end_pos_); | |
| 672 for (LayoutObject* o = selection_start_; o && o != end; | |
| 673 o = o->NextInPreOrder()) { | |
| 674 if (!o->CanBeSelectionLeaf() && o != selection_start_ && | |
| 675 o != selection_end_) | |
| 676 continue; | |
| 677 if (o->GetSelectionState() == SelectionNone) | |
| 678 continue; | |
| 679 | |
| 680 o->SetShouldInvalidateSelection(); | |
| 681 } | |
| 682 } | |
| 683 | |
| 684 // When exploring the LayoutTree looking for the nodes involved in the | |
| 685 // Selection, sometimes it's required to change the traversing direction because | |
| 686 // the "start" position is below the "end" one. | |
| 687 static inline LayoutObject* GetNextOrPrevLayoutObjectBasedOnDirection( | |
| 688 const LayoutObject* o, | |
| 689 const LayoutObject* stop, | |
| 690 bool& continue_exploring, | |
| 691 bool& exploring_backwards) { | |
| 692 LayoutObject* next; | |
| 693 if (exploring_backwards) { | |
| 694 next = o->PreviousInPreOrder(); | |
| 695 continue_exploring = next && !(next)->IsLayoutView(); | |
| 696 } else { | |
| 697 next = o->NextInPreOrder(); | |
| 698 continue_exploring = next && next != stop; | |
| 699 exploring_backwards = !next && (next != stop); | |
| 700 if (exploring_backwards) { | |
| 701 next = stop->PreviousInPreOrder(); | |
| 702 continue_exploring = next && !next->IsLayoutView(); | |
| 703 } | |
| 704 } | |
| 705 | |
| 706 return next; | |
| 707 } | |
| 708 | |
| 709 // TODO(yoichio): Move this to LayoutSelection. | |
| 710 void LayoutSelection::SetSelection( | |
| 711 LayoutObject* start, | |
| 712 int start_pos, | |
| 713 LayoutObject* end, | |
| 714 int end_pos, | |
| 715 SelectionPaintInvalidationMode block_paint_invalidation_mode) { | |
| 716 // This code makes no assumptions as to if the layout tree is up to date or | |
| 717 // not and will not try to update it. Currently clearSelection calls this | |
| 718 // (intentionally) without updating the layout tree as it doesn't care. | |
| 719 // Other callers may want to force recalc style before calling this. | |
| 720 | |
| 721 // Make sure both our start and end objects are defined. | |
| 722 // Check www.msnbc.com and try clicking around to find the case where this | |
| 723 // happened. | |
| 724 if ((start && !end) || (end && !start)) | |
| 725 return; | |
| 726 | |
| 727 // Just return if the selection hasn't changed. | |
| 728 if (selection_start_ == start && selection_start_pos_ == start_pos && | |
| 729 selection_end_ == end && selection_end_pos_ == end_pos) | |
| 730 return; | |
| 731 | |
| 732 // Record the old selected objects. These will be used later when we compare | |
| 733 // against the new selected objects. | |
| 734 int old_start_pos = selection_start_pos_; | |
| 735 int old_end_pos = selection_end_pos_; | |
| 736 | |
| 737 // Objects each have a single selection rect to examine. | |
| 738 typedef HashMap<LayoutObject*, SelectionState> SelectedObjectMap; | |
| 739 SelectedObjectMap old_selected_objects; | |
| 740 // FIXME: |newSelectedObjects| doesn't really need to store the | |
| 741 // SelectionState, it's just more convenient to have it use the same data | |
| 742 // structure as |oldSelectedObjects|. | |
| 743 SelectedObjectMap new_selected_objects; | |
| 744 | |
| 745 // Blocks contain selected objects and fill gaps between them, either on the | |
| 746 // left, right, or in between lines and blocks. | |
| 747 // In order to get the visual rect right, we have to examine left, middle, and | |
| 748 // right rects individually, since otherwise the union of those rects might | |
| 749 // remain the same even when changes have occurred. | |
| 750 typedef HashMap<LayoutBlock*, SelectionState> SelectedBlockMap; | |
| 751 SelectedBlockMap old_selected_blocks; | |
| 752 // FIXME: |newSelectedBlocks| doesn't really need to store the SelectionState, | |
| 753 // it's just more convenient to have it use the same data structure as | |
| 754 // |oldSelectedBlocks|. | |
| 755 SelectedBlockMap new_selected_blocks; | |
| 756 | |
| 757 LayoutObject* os = selection_start_; | |
| 758 LayoutObject* stop = | |
| 759 LayoutObjectAfterPosition(selection_end_, selection_end_pos_); | |
| 760 bool exploring_backwards = false; | |
| 761 bool continue_exploring = os && (os != stop); | |
| 762 while (continue_exploring) { | |
| 763 if ((os->CanBeSelectionLeaf() || os == selection_start_ || | |
| 764 os == selection_end_) && | |
| 765 os->GetSelectionState() != SelectionNone) { | |
| 766 // Blocks are responsible for painting line gaps and margin gaps. They | |
| 767 // must be examined as well. | |
| 768 old_selected_objects.Set(os, os->GetSelectionState()); | |
| 769 if (block_paint_invalidation_mode == kPaintInvalidationNewXOROld) { | |
| 770 LayoutBlock* cb = os->ContainingBlock(); | |
| 771 while (cb && !cb->IsLayoutView()) { | |
| 772 SelectedBlockMap::AddResult result = | |
| 773 old_selected_blocks.insert(cb, cb->GetSelectionState()); | |
| 774 if (!result.is_new_entry) | |
| 775 break; | |
| 776 cb = cb->ContainingBlock(); | |
| 777 } | |
| 778 } | |
| 779 } | |
| 780 | |
| 781 os = GetNextOrPrevLayoutObjectBasedOnDirection(os, stop, continue_exploring, | |
| 782 exploring_backwards); | |
| 783 } | |
| 784 | |
| 785 // Now clear the selection. | |
| 786 SelectedObjectMap::iterator old_objects_end = old_selected_objects.end(); | |
| 787 for (SelectedObjectMap::iterator i = old_selected_objects.begin(); | |
| 788 i != old_objects_end; ++i) | |
| 789 i->key->SetSelectionStateIfNeeded(SelectionNone); | |
| 790 | |
| 791 // set selection start and end | |
| 792 selection_start_ = start; | |
| 793 selection_start_pos_ = start_pos; | |
| 794 selection_end_ = end; | |
| 795 selection_end_pos_ = end_pos; | |
| 796 | |
| 797 // Update the selection status of all objects between m_selectionStart and | |
| 798 // m_selectionEnd | |
| 799 if (start && start == end) { | |
| 800 start->SetSelectionStateIfNeeded(SelectionBoth); | |
| 801 } else { | |
| 802 if (start) | |
| 803 start->SetSelectionStateIfNeeded(SelectionStart); | |
| 804 if (end) | |
| 805 end->SetSelectionStateIfNeeded(SelectionEnd); | |
| 806 } | |
| 807 | |
| 808 LayoutObject* o = start; | |
| 809 stop = LayoutObjectAfterPosition(end, end_pos); | |
| 810 | |
| 811 while (o && o != stop) { | |
| 812 if (o != start && o != end && o->CanBeSelectionLeaf()) | |
| 813 o->SetSelectionStateIfNeeded(SelectionInside); | |
| 814 o = o->NextInPreOrder(); | |
| 815 } | |
| 816 | |
| 817 // Now that the selection state has been updated for the new objects, walk | |
| 818 // them again and put them in the new objects list. | |
| 819 o = start; | |
| 820 exploring_backwards = false; | |
| 821 continue_exploring = o && (o != stop); | |
| 822 while (continue_exploring) { | |
| 823 if ((o->CanBeSelectionLeaf() || o == start || o == end) && | |
| 824 o->GetSelectionState() != SelectionNone) { | |
| 825 new_selected_objects.Set(o, o->GetSelectionState()); | |
| 826 LayoutBlock* cb = o->ContainingBlock(); | |
| 827 while (cb && !cb->IsLayoutView()) { | |
| 828 SelectedBlockMap::AddResult result = | |
| 829 new_selected_blocks.insert(cb, cb->GetSelectionState()); | |
| 830 if (!result.is_new_entry) | |
| 831 break; | |
| 832 cb = cb->ContainingBlock(); | |
| 833 } | |
| 834 } | |
| 835 | |
| 836 o = GetNextOrPrevLayoutObjectBasedOnDirection(o, stop, continue_exploring, | |
| 837 exploring_backwards); | |
| 838 } | |
| 839 | |
| 840 // TODO(yoichio): DCHECK(frame_selection_->,,,->GetFrameView()); | |
| 841 if (!frame_selection_->GetDocument().GetLayoutView()->GetFrameView()) | |
| 842 return; | |
| 843 | |
| 844 // Have any of the old selected objects changed compared to the new selection? | |
| 845 for (SelectedObjectMap::iterator i = old_selected_objects.begin(); | |
| 846 i != old_objects_end; ++i) { | |
| 847 LayoutObject* obj = i->key; | |
| 848 SelectionState new_selection_state = obj->GetSelectionState(); | |
| 849 SelectionState old_selection_state = i->value; | |
| 850 if (new_selection_state != old_selection_state || | |
| 851 (selection_start_ == obj && old_start_pos != selection_start_pos_) || | |
| 852 (selection_end_ == obj && old_end_pos != selection_end_pos_)) { | |
| 853 obj->SetShouldInvalidateSelection(); | |
| 854 new_selected_objects.erase(obj); | |
| 855 } | |
| 856 } | |
| 857 | |
| 858 // Any new objects that remain were not found in the old objects dict, and so | |
| 859 // they need to be updated. | |
| 860 SelectedObjectMap::iterator new_objects_end = new_selected_objects.end(); | |
| 861 for (SelectedObjectMap::iterator i = new_selected_objects.begin(); | |
| 862 i != new_objects_end; ++i) | |
| 863 i->key->SetShouldInvalidateSelection(); | |
| 864 | |
| 865 // Have any of the old blocks changed? | |
| 866 SelectedBlockMap::iterator old_blocks_end = old_selected_blocks.end(); | |
| 867 for (SelectedBlockMap::iterator i = old_selected_blocks.begin(); | |
| 868 i != old_blocks_end; ++i) { | |
| 869 LayoutBlock* block = i->key; | |
| 870 SelectionState new_selection_state = block->GetSelectionState(); | |
| 871 SelectionState old_selection_state = i->value; | |
| 872 if (new_selection_state != old_selection_state) { | |
| 873 block->SetShouldInvalidateSelection(); | |
| 874 new_selected_blocks.erase(block); | |
| 875 } | |
| 876 } | |
| 877 | |
| 878 // Any new blocks that remain were not found in the old blocks dict, and so | |
| 879 // they need to be updated. | |
| 880 SelectedBlockMap::iterator new_blocks_end = new_selected_blocks.end(); | |
| 881 for (SelectedBlockMap::iterator i = new_selected_blocks.begin(); | |
| 882 i != new_blocks_end; ++i) | |
| 883 i->key->SetShouldInvalidateSelection(); | |
| 884 } | |
| 885 | |
| 886 // TODO(yoichio): Move this to LayoutSelection. | |
| 887 void LayoutSelection::ClearSelection() { | |
| 888 // For querying Layer::compositingState() | |
| 889 // This is correct, since destroying layout objects needs to cause eager paint | |
| 890 // invalidations. | |
| 891 DisableCompositingQueryAsserts disabler; | |
| 892 | |
| 893 SetSelection(0, -1, 0, -1, kPaintInvalidationNewMinusOld); | |
| 894 } | |
| 895 | |
| 896 void LayoutView::ClearSelection() { | 612 void LayoutView::ClearSelection() { |
| 897 frame_view_->GetFrame().Selection().ClearLayoutSelection(); | 613 frame_view_->GetFrame().Selection().ClearLayoutSelection(); |
| 898 } | 614 } |
| 899 | 615 |
| 900 bool LayoutView::HasPendingSelection() const { | 616 bool LayoutView::HasPendingSelection() const { |
| 901 return frame_view_->GetFrame().Selection().IsAppearanceDirty(); | 617 return frame_view_->GetFrame().Selection().IsAppearanceDirty(); |
| 902 } | 618 } |
| 903 | 619 |
| 904 void LayoutView::CommitPendingSelection() { | 620 void LayoutView::CommitPendingSelection() { |
| 905 TRACE_EVENT0("blink", "LayoutView::commitPendingSelection"); | 621 TRACE_EVENT0("blink", "LayoutView::commitPendingSelection"); |
| 906 frame_view_->GetFrame().Selection().CommitAppearanceIfNeeded(*this); | 622 frame_view_->GetFrame().Selection().CommitAppearanceIfNeeded(*this); |
| 907 } | 623 } |
| 908 | 624 |
| 909 void LayoutView::SelectionStartEnd(int& start_pos, int& end_pos) { | 625 void LayoutView::SelectionStartEnd(int& start_pos, int& end_pos) { |
| 910 frame_view_->GetFrame().Selection().LayoutSelectionStartEnd(start_pos, | 626 frame_view_->GetFrame().Selection().LayoutSelectionStartEnd(start_pos, |
| 911 end_pos); | 627 end_pos); |
| 912 } | 628 } |
| 913 | 629 |
| 914 // TODO(yoichio): Move this to LayoutSelection. | |
| 915 void LayoutSelection::SelectionStartEnd(int& start_pos, int& end_pos) { | |
| 916 Commit(*frame_selection_->GetDocument().GetLayoutView()); | |
| 917 start_pos = selection_start_pos_; | |
| 918 end_pos = selection_end_pos_; | |
| 919 } | |
| 920 | |
| 921 bool LayoutView::ShouldUsePrintingLayout() const { | 630 bool LayoutView::ShouldUsePrintingLayout() const { |
| 922 if (!GetDocument().Printing() || !frame_view_) | 631 if (!GetDocument().Printing() || !frame_view_) |
| 923 return false; | 632 return false; |
| 924 return frame_view_->GetFrame().ShouldUsePrintingLayout(); | 633 return frame_view_->GetFrame().ShouldUsePrintingLayout(); |
| 925 } | 634 } |
| 926 | 635 |
| 927 LayoutRect LayoutView::ViewRect() const { | 636 LayoutRect LayoutView::ViewRect() const { |
| 928 if (ShouldUsePrintingLayout()) | 637 if (ShouldUsePrintingLayout()) |
| 929 return LayoutRect(LayoutPoint(), Size()); | 638 return LayoutRect(LayoutPoint(), Size()); |
| 930 if (frame_view_) | 639 if (frame_view_) |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1113 // Frame scroll corner is painted using LayoutView as the display item client. | 822 // Frame scroll corner is painted using LayoutView as the display item client. |
| 1114 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled() && | 823 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled() && |
| 1115 (GetFrameView()->HorizontalScrollbar() || | 824 (GetFrameView()->HorizontalScrollbar() || |
| 1116 GetFrameView()->VerticalScrollbar())) | 825 GetFrameView()->VerticalScrollbar())) |
| 1117 return false; | 826 return false; |
| 1118 | 827 |
| 1119 return LayoutBlockFlow::PaintedOutputOfObjectHasNoEffectRegardlessOfSize(); | 828 return LayoutBlockFlow::PaintedOutputOfObjectHasNoEffectRegardlessOfSize(); |
| 1120 } | 829 } |
| 1121 | 830 |
| 1122 } // namespace blink | 831 } // namespace blink |
| OLD | NEW |