| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first. | 5 #define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first. |
| 6 | 6 |
| 7 #include "ui/views/view.h" | 7 #include "ui/views/view.h" |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <cmath> | 10 #include <cmath> |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 const int kDefaultVerticalDragThreshold = 8; | 87 const int kDefaultVerticalDragThreshold = 8; |
| 88 | 88 |
| 89 // Returns the top view in |view|'s hierarchy. | 89 // Returns the top view in |view|'s hierarchy. |
| 90 const View* GetHierarchyRoot(const View* view) { | 90 const View* GetHierarchyRoot(const View* view) { |
| 91 const View* root = view; | 91 const View* root = view; |
| 92 while (root && root->parent()) | 92 while (root && root->parent()) |
| 93 root = root->parent(); | 93 root = root->parent(); |
| 94 return root; | 94 return root; |
| 95 } | 95 } |
| 96 | 96 |
| 97 /* |
| 98 gfx::Rect GetPixelBounds(const ui::PaintContext& parent_context, |
| 99 const gfx::Vector2d& child_origin, |
| 100 const gfx::Size& child_size, |
| 101 const gfx::Size& parent_pixel_size, |
| 102 const gfx::Rect& parent_bounds) { |
| 103 float dsf = parent_context.device_scale_factor(); |
| 104 |
| 105 int right = child_origin.x() + child_size.width(); |
| 106 int bottom = child_origin.y() + child_size.height(); |
| 107 |
| 108 int new_x = std::round(child_origin.x() * dsf); |
| 109 int new_y = std::round(child_origin.y() * dsf); |
| 110 |
| 111 int new_right; |
| 112 int new_bottom; |
| 113 |
| 114 if (right == parent_bounds.width()) { |
| 115 new_right = parent_pixel_size.width(); |
| 116 } else { |
| 117 new_right = std::round(right * dsf); |
| 118 } |
| 119 if (bottom == parent_bounds.height()) { |
| 120 new_bottom = parent_pixel_size.height(); |
| 121 } else { |
| 122 new_bottom = std::round(bottom * dsf); |
| 123 } |
| 124 return gfx::Rect(new_x, new_y, new_right - new_x, new_bottom - new_y); |
| 125 } |
| 126 */ |
| 127 |
| 97 } // namespace | 128 } // namespace |
| 98 | 129 |
| 99 namespace internal { | 130 namespace internal { |
| 100 | 131 |
| 101 #if DCHECK_IS_ON() | 132 #if DCHECK_IS_ON() |
| 102 class ScopedChildrenLock { | 133 class ScopedChildrenLock { |
| 103 public: | 134 public: |
| 104 explicit ScopedChildrenLock(const View* view) | 135 explicit ScopedChildrenLock(const View* view) |
| 105 : reset_(&view->iterating_, true) {} | 136 : reset_(&view->iterating_, true) {} |
| 106 ~ScopedChildrenLock() {} | 137 ~ScopedChildrenLock() {} |
| (...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 } else if (parent_) { | 852 } else if (parent_) { |
| 822 // Translate the requested paint rect to the parent's coordinate system | 853 // Translate the requested paint rect to the parent's coordinate system |
| 823 // then pass this notification up to the parent. | 854 // then pass this notification up to the parent. |
| 824 parent_->SchedulePaintInRect(ConvertRectToParent(rect)); | 855 parent_->SchedulePaintInRect(ConvertRectToParent(rect)); |
| 825 } | 856 } |
| 826 } | 857 } |
| 827 | 858 |
| 828 void View::Paint(const ui::PaintContext& parent_context) { | 859 void View::Paint(const ui::PaintContext& parent_context) { |
| 829 if (!ShouldPaint()) | 860 if (!ShouldPaint()) |
| 830 return; | 861 return; |
| 862 gfx::Vector2dF scale = parent_context.CanvasScale(); |
| 831 | 863 |
| 832 ui::PaintContext context(parent_context, GetPaintContextOffset()); | 864 gfx::Point offset_to_parent; |
| 865 if (!layer()) { |
| 866 // If the View has a layer() then it is a paint root. Otherwise, we need to |
| 867 // add the offset from the parent into the total offset from the paint root. |
| 868 DCHECK(parent() || origin() == gfx::Point()); |
| 869 offset_to_parent = GetMirroredPosition(); |
| 870 } |
| 871 |
| 872 gfx::Rect pixel_bounds = |
| 873 parent_context.GetPixelBounds(gfx::Rect(offset_to_parent, size())); |
| 874 /* |
| 875 LOG(ERROR) << "ParentPixelSize:" |
| 876 << "parent bounds=" << parent_bounds.ToString() |
| 877 << ", parent pixel=" << parent_pixel_size.ToString() |
| 878 << ", my size=" << size().ToString() |
| 879 << ", m pixel=" << pixel_bounds.ToString(); |
| 880 */ |
| 881 |
| 882 ui::PaintContext context(parent_context, GetPaintContextOffset(pixel_bounds)); |
| 883 context.UpdateSizeAndDSF(pixel_bounds.size(), size()); |
| 833 | 884 |
| 834 bool is_invalidated = true; | 885 bool is_invalidated = true; |
| 835 if (context.CanCheckInvalid()) { | 886 if (context.CanCheckInvalid()) { |
| 836 #if DCHECK_IS_ON() | 887 #if DCHECK_IS_ON() && 0 |
| 837 gfx::Vector2d offset; | 888 gfx::Vector2d offset; |
| 838 context.Visited(this); | 889 context.Visited(this); |
| 839 View* view = this; | 890 View* view = this; |
| 840 while (view->parent() && !view->layer()) { | 891 while (view->parent() && !view->layer()) { |
| 841 DCHECK(view->GetTransform().IsIdentity()); | 892 DCHECK(view->GetTransform().IsIdentity()); |
| 842 offset += view->GetMirroredPosition().OffsetFromOrigin(); | 893 offset += view->GetMirroredPosition().OffsetFromOrigin(); |
| 843 view = view->parent(); | 894 view = view->parent(); |
| 844 } | 895 } |
| 845 // The offset in the PaintContext should be the offset up to the paint root, | 896 // The offset in the PaintContext should be the offset up to the paint root, |
| 846 // which we compute and verify here. | 897 // which we compute and verify here. |
| 847 DCHECK_EQ(context.PaintOffset().x(), offset.x()); | 898 DCHECK_EQ(context.PaintOffset().x(), offset.x()); |
| 848 DCHECK_EQ(context.PaintOffset().y(), offset.y()); | 899 DCHECK_EQ(context.PaintOffset().y(), offset.y()); |
| 849 // The above loop will stop when |view| is the paint root, which should be | 900 // The above loop will stop when |view| is the paint root, which should be |
| 850 // the root of the current paint walk, as verified by storing the root in | 901 // the root of the current paint walk, as verified by storing the root in |
| 851 // the PaintContext. | 902 // the PaintContext. |
| 852 DCHECK_EQ(context.RootVisited(), view); | 903 DCHECK_EQ(context.RootVisited(), view); |
| 853 #endif | 904 #endif |
| 854 | 905 |
| 855 // If the View wasn't invalidated, don't waste time painting it, the output | 906 // If the View wasn't invalidated, don't waste time painting it, the output |
| 856 // would be culled. | 907 // would be culled. |
| 857 is_invalidated = context.IsRectInvalid(GetLocalBounds()); | 908 is_invalidated = context.IsRectInvalid(gfx::Rect(pixel_bounds.size())); |
| 858 } | 909 } |
| 859 | 910 |
| 860 TRACE_EVENT1("views", "View::Paint", "class", GetClassName()); | 911 TRACE_EVENT1("views", "View::Paint", "class", GetClassName()); |
| 861 | 912 |
| 862 // If the view is backed by a layer, it should paint with itself as the origin | 913 // If the view is backed by a layer, it should paint with itself as the origin |
| 863 // rather than relative to its parent. | 914 // rather than relative to its parent. |
| 864 // TODO(danakj): Rework clip and transform recorder usage here to use | 915 // TODO(danakj): Rework clip and transform recorder usage here to use |
| 865 // std::optional once we can do so. | 916 // std::optional once we can do so. |
| 866 ui::ClipRecorder clip_recorder(parent_context); | 917 ui::ClipRecorder clip_recorder(parent_context); |
| 867 if (!layer()) { | 918 if (!layer()) { |
| 868 // Set the clip rect to the bounds of this View, or |clip_path_| if it's | 919 // Set the clip rect to the bounds of this View, or |clip_path_| if it's |
| 869 // been set. Note that the X (or left) position we pass to ClipRect takes | 920 // been set. Note that the X (or left) position we pass to ClipRect takes |
| 870 // into consideration whether or not the View uses a right-to-left layout so | 921 // into consideration whether or not the View uses a right-to-left layout so |
| 871 // that we paint the View in its mirrored position if need be. | 922 // that we paint the View in its mirrored position if need be. |
| 872 if (clip_path_.isEmpty()) { | 923 if (clip_path_.isEmpty()) { |
| 873 clip_recorder.ClipRect(GetMirroredBounds()); | 924 clip_recorder.ClipRect(pixel_bounds); |
| 874 } else { | 925 } else { |
| 875 gfx::Path clip_path_in_parent = clip_path_; | 926 gfx::Path clip_path_in_parent = clip_path_; |
| 876 clip_path_in_parent.offset(GetMirroredX(), y()); | 927 clip_path_in_parent.offset(GetMirroredX(), y()); |
| 928 |
| 929 clip_path_in_parent.transform(SkMatrix::MakeScale( |
| 930 SkFloatToScalar(scale.x()), |
| 931 SkFloatToScalar(scale.y()))); |
| 877 clip_recorder.ClipPathWithAntiAliasing(clip_path_in_parent); | 932 clip_recorder.ClipPathWithAntiAliasing(clip_path_in_parent); |
| 878 } | 933 } |
| 879 } | 934 } |
| 880 | 935 |
| 881 ui::TransformRecorder transform_recorder(context); | 936 ui::TransformRecorder transform_recorder(context); |
| 882 SetupTransformRecorderForPainting(&transform_recorder); | 937 SetupTransformRecorderForPainting(&transform_recorder, |
| 938 GetPaintContextOffset(pixel_bounds)); |
| 883 | 939 |
| 884 // Note that the cache is not aware of the offset of the view | 940 // Note that the cache is not aware of the offset of the view |
| 885 // relative to the parent since painting is always done relative to | 941 // relative to the parent since painting is always done relative to |
| 886 // the top left of the individual view. | 942 // the top left of the individual view. |
| 887 if (is_invalidated || !paint_cache_.UseCache(context, size())) { | 943 if (is_invalidated || !paint_cache_.UseCache(context, pixel_bounds.size())) { |
| 888 ui::PaintRecorder recorder(context, size(), &paint_cache_); | 944 ui::PaintRecorder recorder(context, pixel_bounds.size(), &paint_cache_, |
| 945 true); |
| 889 gfx::Canvas* canvas = recorder.canvas(); | 946 gfx::Canvas* canvas = recorder.canvas(); |
| 890 gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, width(), | 947 gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, pixel_bounds.width(), |
| 891 flip_canvas_on_paint_for_rtl_ui_); | 948 flip_canvas_on_paint_for_rtl_ui_); |
| 892 | 949 |
| 893 // Delegate painting the contents of the View to the virtual OnPaint method. | 950 // Delegate painting the contents of the View to the virtual OnPaint method. |
| 894 OnPaint(canvas); | 951 OnPaint(canvas); |
| 895 } | 952 } |
| 896 | 953 |
| 897 // View::Paint() recursion over the subtree. | 954 // View::Paint() recursion over the subtree. |
| 898 PaintChildren(context); | 955 PaintChildren(context); |
| 899 } | 956 } |
| 900 | 957 |
| (...skipping 1036 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1937 // Translate the requested paint rect to the parent's coordinate system | 1994 // Translate the requested paint rect to the parent's coordinate system |
| 1938 // then pass this notification up to the parent. | 1995 // then pass this notification up to the parent. |
| 1939 parent_->SchedulePaintInRect(ConvertRectToParent(GetLocalBounds())); | 1996 parent_->SchedulePaintInRect(ConvertRectToParent(GetLocalBounds())); |
| 1940 } | 1997 } |
| 1941 } | 1998 } |
| 1942 | 1999 |
| 1943 bool View::ShouldPaint() const { | 2000 bool View::ShouldPaint() const { |
| 1944 return visible_ && !size().IsEmpty(); | 2001 return visible_ && !size().IsEmpty(); |
| 1945 } | 2002 } |
| 1946 | 2003 |
| 1947 gfx::Vector2d View::GetPaintContextOffset() const { | 2004 gfx::Vector2d View::GetPaintContextOffset(const gfx::Rect& pixel_bounds) const { |
| 1948 // If the View has a layer() then it is a paint root. Otherwise, we need to | 2005 // If the View has a layer() then it is a paint root. Otherwise, we need to |
| 1949 // add the offset from the parent into the total offset from the paint root. | 2006 // add the offset from the parent into the total offset from the paint root. |
| 1950 DCHECK(layer() || parent() || origin() == gfx::Point()); | 2007 DCHECK(layer() || parent() || origin() == gfx::Point()); |
| 1951 return layer() ? gfx::Vector2d() : GetMirroredPosition().OffsetFromOrigin(); | 2008 if (layer()) |
| 2009 return gfx::Vector2d(); |
| 2010 int mirrored_x = GetMirroredXForRect(pixel_bounds); |
| 2011 return gfx::Vector2d(mirrored_x, pixel_bounds.y()); |
| 1952 } | 2012 } |
| 1953 | 2013 |
| 1954 void View::SetupTransformRecorderForPainting( | 2014 void View::SetupTransformRecorderForPainting( |
| 1955 ui::TransformRecorder* recorder) const { | 2015 ui::TransformRecorder* recorder, |
| 2016 gfx::Vector2d offset_from_parent) const { |
| 1956 // If the view is backed by a layer, it should paint with itself as the origin | 2017 // If the view is backed by a layer, it should paint with itself as the origin |
| 1957 // rather than relative to its parent. | 2018 // rather than relative to its parent.2 |
| 1958 if (layer()) | 2019 if (layer()) |
| 1959 return; | 2020 return; |
| 1960 | 2021 |
| 1961 // Translate the graphics such that 0,0 corresponds to where this View is | 2022 // Translate the graphics such that 0,0 corresponds to where this View is |
| 1962 // located relative to its parent. | 2023 // located relative to its parent. |
| 1963 gfx::Transform transform_from_parent; | 2024 gfx::Transform transform_from_parent; |
| 1964 gfx::Vector2d offset_from_parent = GetMirroredPosition().OffsetFromOrigin(); | |
| 1965 transform_from_parent.Translate(offset_from_parent.x(), | 2025 transform_from_parent.Translate(offset_from_parent.x(), |
| 1966 offset_from_parent.y()); | 2026 offset_from_parent.y()); |
| 1967 transform_from_parent.PreconcatTransform(GetTransform()); | |
| 1968 recorder->Transform(transform_from_parent); | 2027 recorder->Transform(transform_from_parent); |
| 1969 } | 2028 } |
| 1970 | 2029 |
| 1971 void View::RecursivePaintHelper(void (View::*func)(const ui::PaintContext&), | 2030 void View::RecursivePaintHelper(void (View::*func)(const ui::PaintContext&), |
| 1972 const ui::PaintContext& context) { | 2031 const ui::PaintContext& context) { |
| 1973 View::Views children = GetChildrenInZOrder(); | 2032 View::Views children = GetChildrenInZOrder(); |
| 1974 DCHECK_EQ(child_count(), static_cast<int>(children.size())); | 2033 DCHECK_EQ(child_count(), static_cast<int>(children.size())); |
| 1975 for (auto* child : children) { | 2034 for (auto* child : children) { |
| 1976 if (!child->layer()) | 2035 if (!child->layer()) |
| 1977 (child->*func)(context); | 2036 (child->*func)(context); |
| 1978 } | 2037 } |
| 1979 } | 2038 } |
| 1980 | 2039 |
| 1981 void View::PaintFromPaintRoot(const ui::PaintContext& parent_context) { | 2040 void View::PaintFromPaintRoot(const ui::PaintContext& parent_context) { |
| 1982 Paint(parent_context); | 2041 Paint(parent_context); |
| 1983 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 2042 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 1984 switches::kDrawViewBoundsRects)) | 2043 switches::kDrawViewBoundsRects)) |
| 1985 PaintDebugRects(parent_context); | 2044 PaintDebugRects(parent_context); |
| 1986 } | 2045 } |
| 1987 | 2046 |
| 1988 void View::PaintDebugRects(const ui::PaintContext& parent_context) { | 2047 void View::PaintDebugRects(const ui::PaintContext& parent_context) { |
| 1989 if (!ShouldPaint()) | 2048 if (!ShouldPaint()) |
| 1990 return; | 2049 return; |
| 1991 | 2050 |
| 1992 ui::PaintContext context(parent_context, GetPaintContextOffset()); | 2051 //const gfx::Size& parent_pixel_size = parent_context.pixel_size(); |
| 2052 //const gfx::Rect parent_bounds = parent() ? parent()->bounds() : bounds(); |
| 2053 gfx::Point offset_to_parent; |
| 2054 if (!layer()) { |
| 2055 // If the View has a layer() then it is a paint root. Otherwise, we need to |
| 2056 // add the offset from the parent into the total offset from the paint root. |
| 2057 DCHECK(parent() || origin() == gfx::Point()); |
| 2058 offset_to_parent = GetMirroredPosition(); |
| 2059 } |
| 2060 gfx::Rect pixel_bounds = parent_context.GetPixelBounds(gfx::Rect(offset_to_par
ent, size())); |
| 2061 ui::PaintContext context(parent_context, GetPaintContextOffset(pixel_bounds)); |
| 2062 context.UpdateSizeAndDSF(pixel_bounds.size(), size()); |
| 2063 |
| 1993 ui::TransformRecorder transform_recorder(context); | 2064 ui::TransformRecorder transform_recorder(context); |
| 1994 SetupTransformRecorderForPainting(&transform_recorder); | 2065 SetupTransformRecorderForPainting(&transform_recorder, |
| 2066 pixel_bounds.OffsetFromOrigin()); |
| 1995 | 2067 |
| 1996 RecursivePaintHelper(&View::PaintDebugRects, context); | 2068 RecursivePaintHelper(&View::PaintDebugRects, context); |
| 1997 | 2069 |
| 1998 // Draw outline rects for debugging. | 2070 // Draw outline rects for debugging. |
| 1999 ui::PaintRecorder recorder(context, size()); | 2071 ui::PaintRecorder recorder(context, pixel_bounds.size(), &paint_cache_, true); |
| 2000 gfx::Canvas* canvas = recorder.canvas(); | 2072 gfx::Canvas* canvas = recorder.canvas(); |
| 2001 const float scale = canvas->UndoDeviceScaleFactor(); | 2073 const float scale = canvas->UndoDeviceScaleFactor(); |
| 2002 gfx::RectF outline_rect(ScaleToEnclosedRect(GetLocalBounds(), scale)); | 2074 gfx::RectF outline_rect(ScaleToEnclosedRect(GetLocalBounds(), scale)); |
| 2003 outline_rect.Inset(0.5f, 0.5f); | 2075 outline_rect.Inset(0.5f, 0.5f); |
| 2004 const SkColor color = SkColorSetARGB(0x30, 0xff, 0, 0); | 2076 const SkColor color = SkColorSetARGB(0x30, 0xff, 0, 0); |
| 2005 canvas->DrawRect(outline_rect, color); | 2077 canvas->DrawRect(outline_rect, color); |
| 2006 } | 2078 } |
| 2007 | 2079 |
| 2008 // Tree operations ------------------------------------------------------------- | 2080 // Tree operations ------------------------------------------------------------- |
| 2009 | 2081 |
| (...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2664 // Message the RootView to do the drag and drop. That way if we're removed | 2736 // Message the RootView to do the drag and drop. That way if we're removed |
| 2665 // the RootView can detect it and avoid calling us back. | 2737 // the RootView can detect it and avoid calling us back. |
| 2666 gfx::Point widget_location(event.location()); | 2738 gfx::Point widget_location(event.location()); |
| 2667 ConvertPointToWidget(this, &widget_location); | 2739 ConvertPointToWidget(this, &widget_location); |
| 2668 widget->RunShellDrag(this, data, widget_location, drag_operations, source); | 2740 widget->RunShellDrag(this, data, widget_location, drag_operations, source); |
| 2669 // WARNING: we may have been deleted. | 2741 // WARNING: we may have been deleted. |
| 2670 return true; | 2742 return true; |
| 2671 } | 2743 } |
| 2672 | 2744 |
| 2673 } // namespace views | 2745 } // namespace views |
| OLD | NEW |