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