OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ash/common/wm/workspace/magnetism_matcher.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cmath> | |
9 | |
10 #include "base/memory/ptr_util.h" | |
11 | |
12 namespace ash { | |
13 namespace { | |
14 | |
15 // Returns true if |a| is close enough to |b| that the two edges snap. | |
16 bool IsCloseEnough(int a, int b) { | |
17 return abs(a - b) <= MagnetismMatcher::kMagneticDistance; | |
18 } | |
19 | |
20 // Returns true if the specified SecondaryMagnetismEdge can be matched with a | |
21 // primary edge of |primary|. |edges| is a bitmask of the allowed | |
22 // MagnetismEdges. | |
23 bool CanMatchSecondaryEdge(MagnetismEdge primary, | |
24 SecondaryMagnetismEdge secondary, | |
25 uint32_t edges) { | |
26 // Convert |secondary| to a MagnetismEdge so we can compare it to |edges|. | |
27 MagnetismEdge secondary_as_magnetism_edge = MAGNETISM_EDGE_TOP; | |
28 switch (primary) { | |
29 case MAGNETISM_EDGE_TOP: | |
30 case MAGNETISM_EDGE_BOTTOM: | |
31 if (secondary == SECONDARY_MAGNETISM_EDGE_LEADING) | |
32 secondary_as_magnetism_edge = MAGNETISM_EDGE_LEFT; | |
33 else if (secondary == SECONDARY_MAGNETISM_EDGE_TRAILING) | |
34 secondary_as_magnetism_edge = MAGNETISM_EDGE_RIGHT; | |
35 else | |
36 NOTREACHED(); | |
37 break; | |
38 case MAGNETISM_EDGE_LEFT: | |
39 case MAGNETISM_EDGE_RIGHT: | |
40 if (secondary == SECONDARY_MAGNETISM_EDGE_LEADING) | |
41 secondary_as_magnetism_edge = MAGNETISM_EDGE_TOP; | |
42 else if (secondary == SECONDARY_MAGNETISM_EDGE_TRAILING) | |
43 secondary_as_magnetism_edge = MAGNETISM_EDGE_BOTTOM; | |
44 else | |
45 NOTREACHED(); | |
46 break; | |
47 } | |
48 return (edges & secondary_as_magnetism_edge) != 0; | |
49 } | |
50 | |
51 } // namespace | |
52 | |
53 // MagnetismEdgeMatcher -------------------------------------------------------- | |
54 | |
55 MagnetismEdgeMatcher::MagnetismEdgeMatcher(const gfx::Rect& bounds, | |
56 MagnetismEdge edge) | |
57 : bounds_(bounds), edge_(edge) { | |
58 ranges_.push_back(GetSecondaryRange(bounds_)); | |
59 } | |
60 | |
61 MagnetismEdgeMatcher::~MagnetismEdgeMatcher() {} | |
62 | |
63 bool MagnetismEdgeMatcher::ShouldAttach(const gfx::Rect& bounds) { | |
64 if (is_edge_obscured()) | |
65 return false; | |
66 | |
67 if (IsCloseEnough(GetPrimaryCoordinate(bounds_, edge_), | |
68 GetPrimaryCoordinate(bounds, FlipEdge(edge_)))) { | |
69 const Range range(GetSecondaryRange(bounds)); | |
70 Ranges::const_iterator i = | |
71 std::lower_bound(ranges_.begin(), ranges_.end(), range); | |
72 // Close enough, but only attach if some portion of the edge is visible. | |
73 if ((i != ranges_.begin() && RangesIntersect(*(i - 1), range)) || | |
74 (i != ranges_.end() && RangesIntersect(*i, range))) { | |
75 return true; | |
76 } | |
77 } | |
78 // NOTE: this checks against the current bounds, we may want to allow some | |
79 // flexibility here. | |
80 const Range primary_range(GetPrimaryRange(bounds)); | |
81 if (primary_range.first <= GetPrimaryCoordinate(bounds_, edge_) && | |
82 primary_range.second >= GetPrimaryCoordinate(bounds_, edge_)) { | |
83 UpdateRanges(GetSecondaryRange(bounds)); | |
84 } | |
85 return false; | |
86 } | |
87 | |
88 void MagnetismEdgeMatcher::UpdateRanges(const Range& range) { | |
89 Ranges::const_iterator it = | |
90 std::lower_bound(ranges_.begin(), ranges_.end(), range); | |
91 if (it != ranges_.begin() && RangesIntersect(*(it - 1), range)) | |
92 --it; | |
93 if (it == ranges_.end()) | |
94 return; | |
95 | |
96 for (size_t i = it - ranges_.begin(); | |
97 i < ranges_.size() && RangesIntersect(ranges_[i], range);) { | |
98 if (range.first <= ranges_[i].first && range.second >= ranges_[i].second) { | |
99 ranges_.erase(ranges_.begin() + i); | |
100 } else if (range.first < ranges_[i].first) { | |
101 DCHECK_GT(range.second, ranges_[i].first); | |
102 ranges_[i] = Range(range.second, ranges_[i].second); | |
103 ++i; | |
104 } else { | |
105 Range existing(ranges_[i]); | |
106 ranges_[i].second = range.first; | |
107 ++i; | |
108 if (existing.second > range.second) { | |
109 ranges_.insert(ranges_.begin() + i, | |
110 Range(range.second, existing.second)); | |
111 ++i; | |
112 } | |
113 } | |
114 } | |
115 } | |
116 | |
117 // MagnetismMatcher ------------------------------------------------------------ | |
118 | |
119 // static | |
120 const int MagnetismMatcher::kMagneticDistance = 8; | |
121 | |
122 MagnetismMatcher::MagnetismMatcher(const gfx::Rect& bounds, uint32_t edges) | |
123 : edges_(edges) { | |
124 if (edges & MAGNETISM_EDGE_TOP) { | |
125 matchers_.push_back( | |
126 base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_TOP)); | |
127 } | |
128 if (edges & MAGNETISM_EDGE_LEFT) { | |
129 matchers_.push_back( | |
130 base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_LEFT)); | |
131 } | |
132 if (edges & MAGNETISM_EDGE_BOTTOM) { | |
133 matchers_.push_back( | |
134 base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_BOTTOM)); | |
135 } | |
136 if (edges & MAGNETISM_EDGE_RIGHT) { | |
137 matchers_.push_back( | |
138 base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_RIGHT)); | |
139 } | |
140 } | |
141 | |
142 MagnetismMatcher::~MagnetismMatcher() {} | |
143 | |
144 bool MagnetismMatcher::ShouldAttach(const gfx::Rect& bounds, | |
145 MatchedEdge* edge) { | |
146 for (const auto& matcher : matchers_) { | |
147 if (matcher->ShouldAttach(bounds)) { | |
148 edge->primary_edge = matcher->edge(); | |
149 AttachToSecondaryEdge(bounds, edge->primary_edge, | |
150 &(edge->secondary_edge)); | |
151 return true; | |
152 } | |
153 } | |
154 return false; | |
155 } | |
156 | |
157 bool MagnetismMatcher::AreEdgesObscured() const { | |
158 for (const auto& matcher : matchers_) { | |
159 if (!matcher->is_edge_obscured()) | |
160 return false; | |
161 } | |
162 return true; | |
163 } | |
164 | |
165 void MagnetismMatcher::AttachToSecondaryEdge( | |
166 const gfx::Rect& bounds, | |
167 MagnetismEdge edge, | |
168 SecondaryMagnetismEdge* secondary_edge) const { | |
169 const gfx::Rect& src_bounds(matchers_[0]->bounds()); | |
170 if (edge == MAGNETISM_EDGE_LEFT || edge == MAGNETISM_EDGE_RIGHT) { | |
171 if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_LEADING, edges_) && | |
172 IsCloseEnough(bounds.y(), src_bounds.y())) { | |
173 *secondary_edge = SECONDARY_MAGNETISM_EDGE_LEADING; | |
174 } else if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_TRAILING, | |
175 edges_) && | |
176 IsCloseEnough(bounds.bottom(), src_bounds.bottom())) { | |
177 *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING; | |
178 } else { | |
179 *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE; | |
180 } | |
181 } else { | |
182 if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_LEADING, edges_) && | |
183 IsCloseEnough(bounds.x(), src_bounds.x())) { | |
184 *secondary_edge = SECONDARY_MAGNETISM_EDGE_LEADING; | |
185 } else if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_TRAILING, | |
186 edges_) && | |
187 IsCloseEnough(bounds.right(), src_bounds.right())) { | |
188 *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING; | |
189 } else { | |
190 *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE; | |
191 } | |
192 } | |
193 } | |
194 | |
195 } // namespace ash | |
OLD | NEW |