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 |