Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(315)

Side by Side Diff: ui/gfx/win/rect_util.cc

Issue 1679393002: Multiple DPI Tracking for ScreenWin (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to b4da629 and a few equivalent comparison tweaks in rect_util Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gfx/win/rect_util.h"
6
7 #include <algorithm>
8
9 #include "ui/gfx/geometry/rect.h"
10 #include "ui/gfx/geometry/safe_integer_conversions.h"
11 #include "ui/gfx/geometry/size.h"
12 #include "ui/gfx/geometry/vector2d.h"
13 #include "ui/gfx/range/range.h"
14
15 namespace {
16
17 enum class RelativePosition {
18 BOTTOM = 0,
19 LEFT = 1,
20 TOP = 2,
21 RIGHT = 3,
22 };
23
24 gfx::Rect CoordinateRotateRectangle90(const gfx::Rect& rect) {
25 return gfx::Rect(rect.y(), -rect.x() - rect.width(),
26 rect.height(), rect.width());
27 }
28
29 gfx::Rect CoordinateRotateRectangle180(const gfx::Rect& rect) {
30 return gfx::Rect(-rect.x() - rect.width(), -rect.y() -rect.height(),
31 rect.width(), rect.height());
32 }
33
34 gfx::Rect CoordinateRotateRectangle270(const gfx::Rect& rect) {
35 return gfx::Rect(-rect.y() - rect.height(), rect.x(),
36 rect.height(), rect.width());
37 }
38
39 gfx::Rect CoordinateReflectRectangleYAxis(const gfx::Rect& rect) {
40 return gfx::Rect(-rect.x() - rect.width(), rect.y(),
41 rect.width(), rect.height());
42 }
43
44 gfx::Rect CanonicalizeRelativePosition(const gfx::Rect& rect,
45 RelativePosition relative_position) {
46 switch (relative_position) {
47 case RelativePosition::LEFT:
48 return CoordinateRotateRectangle90(rect);
49 case RelativePosition::TOP:
50 return CoordinateRotateRectangle180(rect);
51 case RelativePosition::RIGHT:
52 return CoordinateRotateRectangle270(rect);
53 }
54 return rect;
55 }
56
57 gfx::Rect CanonicalizeTouchingEdge(const gfx::Rect& rect,
58 gfx::win::RectEdge edge) {
59 switch (edge) {
60 case gfx::win::RectEdge::LEFT:
61 return CoordinateRotateRectangle90(rect);
sky 2016/02/17 17:28:48 Can you elaborate on why we need the rotation?
robliao 2016/02/18 00:34:38 The rotation allows us to take advantage of the ro
62 case gfx::win::RectEdge::TOP:
63 // Helps prefer left and top alignment.
64 return CoordinateReflectRectangleYAxis(
65 CoordinateRotateRectangle180(rect));
66 case gfx::win::RectEdge::RIGHT:
67 // Helps prefer left and top alignment.
68 return CoordinateReflectRectangleYAxis(
69 CoordinateRotateRectangle270(rect));
70 }
71 return rect;
72 }
73
74 // Inverse of CanonicalizeTouchingEdge.
75 gfx::Rect RevertToOriginalEdge(const gfx::Rect& rect, gfx::win::RectEdge edge) {
76 switch (edge) {
77 case gfx::win::RectEdge::LEFT:
78 return CoordinateRotateRectangle270(rect);
79 case gfx::win::RectEdge::TOP:
80 return CoordinateRotateRectangle180(
81 CoordinateReflectRectangleYAxis(rect));
82 case gfx::win::RectEdge::RIGHT:
83 return CoordinateRotateRectangle90(
84 CoordinateReflectRectangleYAxis(rect));
85 }
86 return rect;
87 }
88
89 bool InRange(int target, int lower_bound, int upper_bound) {
90 return lower_bound <= target && target <= upper_bound;
91 }
92
93 // Scales |val| within |old_min| and |old_max| to |new_min| and |new_max|.
94 int ScaleValue(int new_min, int new_max, int old_min, int old_max, int val) {
95 int old_delta = old_max - old_min;
96 if (old_delta == 0) {
97 DCHECK_EQ(new_min, new_max);
98 return new_min;
99 }
100 float percent =
101 static_cast<float>(val - old_min) / static_cast<float>(old_delta);
102 return new_min + gfx::ToFlooredInt(percent * (float)(new_max - new_min));
103 }
104
105 RelativePosition RectRelativePosition(const gfx::Rect& ref,
106 const gfx::Rect& test) {
107 if (ref.bottom() <= test.y())
108 return RelativePosition::BOTTOM;
109 else if (test.right() <= ref.x())
110 return RelativePosition::LEFT;
111 else if (test.bottom() <= ref.y())
112 return RelativePosition::TOP;
113
114 return RelativePosition::RIGHT;
115 }
116
117 } // namespace
118
119 namespace gfx {
120 namespace win {
121
122 RectEdge FindTouchingRectEdge(const gfx::Rect& ref, const gfx::Rect& test) {
sky 2016/02/17 04:40:28 Add description, in particular who the return valu
robliao 2016/02/18 00:34:39 Done for RectRelativePosition. The header contains
123 int max_x = std::max(ref.x(), test.x());
sky 2016/02/17 17:28:48 This functions seems more complex than it needs to
robliao 2016/02/18 00:34:39 We need to do the intersection test because a rect
124 int max_y = std::max(ref.y(), test.y());
125 int min_right = std::min(ref.right(), test.right());
126 int min_bottom = std::min(ref.bottom(), test.bottom());
127 if (max_x == min_right && max_y == min_bottom) {
128 // Corner touching.
129 if (ref.bottom() == max_y)
130 return RectEdge::BOTTOM;
131 else if (ref.x() == max_x)
132 return RectEdge::LEFT;
133
134 return RectEdge::TOP;
135 } else if (max_x == min_right) {
sky 2016/02/17 04:40:28 nit: no else after return.
robliao 2016/02/18 00:34:39 Done.
136 // Vertical edge touching.
137 return ref.x() == max_x ? RectEdge::LEFT : RectEdge::RIGHT;
138 } else if (max_y == min_bottom) {
139 // Horizontal edge touching.
140 return ref.y() == max_y ? RectEdge::TOP : RectEdge::BOTTOM;
141 }
142 return RectEdge::NONE;
143 }
144
145 // Writing code that specifically deals with scaling each rect is tedious and
146 // error prone. Instead, this function transforms the positions of the
147 // two rects so that |ref_scaled_rect| is always on top of |ref_original_rect|,
148 // calculates the scaled and positioned target rect, and then reverses the
149 // transforms. As a result, the position logic can be written in terms of the
150 // bottom of the |ref_original_rect| instead of the bottom, left, top, and
151 // right.
152 gfx::Rect ScaleAndPositionRect(gfx::Rect ref_scaled_rect,
153 gfx::Rect ref_original_rect,
154 gfx::Rect target_rect,
155 float target_scale_factor) {
156 RectEdge orig_edge = FindTouchingRectEdge(ref_original_rect, target_rect);
157
158 // Scale size only since the scaled origin location will be determined below.
159 gfx::Rect scaled_rect = gfx::ScaleToEnclosingRect(target_rect,
160 1.0f / target_scale_factor);
161 scaled_rect.set_origin(gfx::Point(0, 0));
162
163 if (orig_edge == RectEdge::NONE) {
164 // Currently, we expect all rectangles to touch each other.
165 NOTREACHED();
sky 2016/02/17 17:28:48 If that's the case, then 164 should be a DCHECK.
robliao 2016/02/18 00:34:39 Done.
166 scaled_rect.set_origin(target_rect.origin());
167 }
168
169 // Transform rectangles so we can simply deal with bottom edge sharing.
170 ref_scaled_rect = CanonicalizeTouchingEdge(ref_scaled_rect, orig_edge);
171 ref_original_rect = CanonicalizeTouchingEdge(ref_original_rect, orig_edge);
172 target_rect = CanonicalizeTouchingEdge(target_rect, orig_edge);
173 scaled_rect = CanonicalizeTouchingEdge(scaled_rect, orig_edge);
174
175 // Position the rect.
176 scaled_rect.set_y(ref_scaled_rect.bottom());
177 int x;
178 if (target_rect.right() == ref_original_rect.right()) {
179 // Maintain right alignment. If the rectangle was left-aligned, the next
180 // case will catch that.
181 x = ref_scaled_rect.right() - scaled_rect.width();
182 } else if (InRange(target_rect.x(),
183 ref_original_rect.x(),
184 ref_original_rect.right())) {
185 // Position using the left point relative to the reference rect.
186 x = ScaleValue(ref_scaled_rect.x(), ref_scaled_rect.right(),
187 ref_original_rect.x(), ref_original_rect.right(),
188 target_rect.x());
189 } else if (InRange(target_rect.right(),
190 ref_original_rect.x(),
191 ref_original_rect.right())) {
192 // Position using the right point relative to the reference rect.
193 x = ScaleValue(ref_scaled_rect.x(), ref_scaled_rect.right(),
194 ref_original_rect.x(), ref_original_rect.right(),
195 target_rect.right()) - scaled_rect.width();
196 } else if (InRange(ref_scaled_rect.x(),
197 target_rect.x(),
198 target_rect.right())) {
199 // Position relative to the left point of the reference rect.
200 int offset = ScaleValue(0, scaled_rect.width(),
201 0, target_rect.width(),
202 ref_original_rect.x() - target_rect.x());
203 x = ref_scaled_rect.x() - offset;
204 } else {
205 // Position relative to the right point of the reference rect.
206 int offset = ScaleValue(0, scaled_rect.width(),
207 0, target_rect.width(),
208 ref_original_rect.right() - target_rect.x());
209 x = ref_scaled_rect.x() - offset - scaled_rect.width();
210 }
211 scaled_rect.set_x(x);
212 DCHECK(
213 FindTouchingRectEdge(ref_scaled_rect, scaled_rect) == RectEdge::BOTTOM);
214
215 // Reverse the transformation.
216 return RevertToOriginalEdge(scaled_rect, orig_edge);
217 }
218
219 // This function takes the same approach as ScaleAndPositionRect, transforming
220 // the two input rects so that the relative positions are always the same.
221 int64_t SquaredDistanceBetweenRects(gfx::Rect ref, gfx::Rect rect) {
222 if (ref.Intersects(rect))
223 return 0;
224
225 RelativePosition relative_position = RectRelativePosition(ref, rect);
226 ref = CanonicalizeRelativePosition(ref, relative_position);
227 rect = CanonicalizeRelativePosition(rect, relative_position);
228 // Now that the ref is on top, we can concentrate ref bottom
229 // and rect top calculations.
230 if (rect.right() < ref.x())
231 return (rect.top_right() - ref.bottom_left()).LengthSquared();
232 else if (ref.right() < rect.x())
233 return (rect.origin() - ref.bottom_right()).LengthSquared();
234
235 int distance = rect.y() - ref.bottom();
236 return distance * distance;
237 }
238
239 } // namespace win
240 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698