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.
5 #include "ash/wm/workspace/magnetism_matcher.h"
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
;
18 // Returns true if the specified SecondaryMagnetismEdge can be matched with a
19 // primary edge of |primary|. |edges| is a bitmask of the allowed
21 bool CanMatchSecondaryEdge(MagnetismEdge primary
,
22 SecondaryMagnetismEdge secondary
,
24 // Convert |secondary| to a MagnetismEdge so we can compare it to |edges|.
25 MagnetismEdge secondary_as_magnetism_edge
= MAGNETISM_EDGE_TOP
;
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
;
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
;
46 return (edges
& secondary_as_magnetism_edge
) != 0;
51 // MagnetismEdgeMatcher --------------------------------------------------------
53 MagnetismEdgeMatcher::MagnetismEdgeMatcher(const gfx::Rect
& bounds
,
57 ranges_
.push_back(GetSecondaryRange(bounds_
));
60 MagnetismEdgeMatcher::~MagnetismEdgeMatcher() {
63 bool MagnetismEdgeMatcher::ShouldAttach(const gfx::Rect
& bounds
) {
64 if (is_edge_obscured())
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
))) {
78 // NOTE: this checks against the current bounds, we may want to allow some
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
));
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
))
93 if (it
== ranges_
.end())
96 for (size_t i
= it
- ranges_
.begin();
97 i
< ranges_
.size() && RangesIntersect(ranges_
[i
], range
); ) {
98 if (range
.first
<= ranges_
[i
].first
&&
99 range
.second
>= ranges_
[i
].second
) {
100 ranges_
.erase(ranges_
.begin() + i
);
101 } else if (range
.first
< ranges_
[i
].first
) {
102 DCHECK_GT(range
.second
, ranges_
[i
].first
);
103 ranges_
[i
] = Range(range
.second
, ranges_
[i
].second
);
106 Range
existing(ranges_
[i
]);
107 ranges_
[i
].second
= range
.first
;
109 if (existing
.second
> range
.second
) {
110 ranges_
.insert(ranges_
.begin() + i
,
111 Range(range
.second
, existing
.second
));
118 // MagnetismMatcher ------------------------------------------------------------
121 const int MagnetismMatcher::kMagneticDistance
= 8;
123 MagnetismMatcher::MagnetismMatcher(const gfx::Rect
& bounds
, uint32 edges
)
125 if (edges
& MAGNETISM_EDGE_TOP
)
126 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
, MAGNETISM_EDGE_TOP
));
127 if (edges
& MAGNETISM_EDGE_LEFT
)
128 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
, MAGNETISM_EDGE_LEFT
));
129 if (edges
& MAGNETISM_EDGE_BOTTOM
) {
130 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
,
131 MAGNETISM_EDGE_BOTTOM
));
133 if (edges
& MAGNETISM_EDGE_RIGHT
)
134 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
, MAGNETISM_EDGE_RIGHT
));
137 MagnetismMatcher::~MagnetismMatcher() {
140 bool MagnetismMatcher::ShouldAttach(const gfx::Rect
& bounds
,
142 for (size_t i
= 0; i
< matchers_
.size(); ++i
) {
143 if (matchers_
[i
]->ShouldAttach(bounds
)) {
144 edge
->primary_edge
= matchers_
[i
]->edge();
145 AttachToSecondaryEdge(bounds
, edge
->primary_edge
,
146 &(edge
->secondary_edge
));
153 bool MagnetismMatcher::AreEdgesObscured() const {
154 for (size_t i
= 0; i
< matchers_
.size(); ++i
) {
155 if (!matchers_
[i
]->is_edge_obscured())
161 void MagnetismMatcher::AttachToSecondaryEdge(
162 const gfx::Rect
& bounds
,
164 SecondaryMagnetismEdge
* secondary_edge
) const {
165 const gfx::Rect
& src_bounds(matchers_
[0]->bounds());
166 if (edge
== MAGNETISM_EDGE_LEFT
|| edge
== MAGNETISM_EDGE_RIGHT
) {
167 if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_LEADING
, edges_
) &&
168 IsCloseEnough(bounds
.y(), src_bounds
.y())) {
169 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_LEADING
;
170 } else if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_TRAILING
,
172 IsCloseEnough(bounds
.bottom(), src_bounds
.bottom())) {
173 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_TRAILING
;
175 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_NONE
;
178 if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_LEADING
, edges_
) &&
179 IsCloseEnough(bounds
.x(), src_bounds
.x())) {
180 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_LEADING
;
181 } else if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_TRAILING
,
183 IsCloseEnough(bounds
.right(), src_bounds
.right())) {
184 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_TRAILING
;
186 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_NONE
;