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"
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
;
20 // Returns true if the specified SecondaryMagnetismEdge can be matched with a
21 // primary edge of |primary|. |edges| is a bitmask of the allowed
23 bool CanMatchSecondaryEdge(MagnetismEdge primary
,
24 SecondaryMagnetismEdge secondary
,
26 // Convert |secondary| to a MagnetismEdge so we can compare it to |edges|.
27 MagnetismEdge secondary_as_magnetism_edge
= MAGNETISM_EDGE_TOP
;
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
;
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
;
48 return (edges
& secondary_as_magnetism_edge
) != 0;
53 // MagnetismEdgeMatcher --------------------------------------------------------
55 MagnetismEdgeMatcher::MagnetismEdgeMatcher(const gfx::Rect
& bounds
,
59 ranges_
.push_back(GetSecondaryRange(bounds_
));
62 MagnetismEdgeMatcher::~MagnetismEdgeMatcher() {
65 bool MagnetismEdgeMatcher::ShouldAttach(const gfx::Rect
& bounds
) {
66 if (is_edge_obscured())
69 if (IsCloseEnough(GetPrimaryCoordinate(bounds_
, edge_
),
70 GetPrimaryCoordinate(bounds
, FlipEdge(edge_
)))) {
71 const Range
range(GetSecondaryRange(bounds
));
72 Ranges::const_iterator i
=
73 std::lower_bound(ranges_
.begin(), ranges_
.end(), range
);
74 // Close enough, but only attach if some portion of the edge is visible.
75 if ((i
!= ranges_
.begin() && RangesIntersect(*(i
- 1), range
)) ||
76 (i
!= ranges_
.end() && RangesIntersect(*i
, range
))) {
80 // NOTE: this checks against the current bounds, we may want to allow some
82 const Range
primary_range(GetPrimaryRange(bounds
));
83 if (primary_range
.first
<= GetPrimaryCoordinate(bounds_
, edge_
) &&
84 primary_range
.second
>= GetPrimaryCoordinate(bounds_
, edge_
)) {
85 UpdateRanges(GetSecondaryRange(bounds
));
90 void MagnetismEdgeMatcher::UpdateRanges(const Range
& range
) {
91 Ranges::const_iterator it
=
92 std::lower_bound(ranges_
.begin(), ranges_
.end(), range
);
93 if (it
!= ranges_
.begin() && RangesIntersect(*(it
- 1), range
))
95 if (it
== ranges_
.end())
98 for (size_t i
= it
- ranges_
.begin();
99 i
< ranges_
.size() && RangesIntersect(ranges_
[i
], range
); ) {
100 if (range
.first
<= ranges_
[i
].first
&&
101 range
.second
>= ranges_
[i
].second
) {
102 ranges_
.erase(ranges_
.begin() + i
);
103 } else if (range
.first
< ranges_
[i
].first
) {
104 DCHECK_GT(range
.second
, ranges_
[i
].first
);
105 ranges_
[i
] = Range(range
.second
, ranges_
[i
].second
);
108 Range
existing(ranges_
[i
]);
109 ranges_
[i
].second
= range
.first
;
111 if (existing
.second
> range
.second
) {
112 ranges_
.insert(ranges_
.begin() + i
,
113 Range(range
.second
, existing
.second
));
120 // MagnetismMatcher ------------------------------------------------------------
123 const int MagnetismMatcher::kMagneticDistance
= 8;
125 MagnetismMatcher::MagnetismMatcher(const gfx::Rect
& bounds
, uint32 edges
)
127 if (edges
& MAGNETISM_EDGE_TOP
)
128 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
, MAGNETISM_EDGE_TOP
));
129 if (edges
& MAGNETISM_EDGE_LEFT
)
130 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
, MAGNETISM_EDGE_LEFT
));
131 if (edges
& MAGNETISM_EDGE_BOTTOM
) {
132 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
,
133 MAGNETISM_EDGE_BOTTOM
));
135 if (edges
& MAGNETISM_EDGE_RIGHT
)
136 matchers_
.push_back(new MagnetismEdgeMatcher(bounds
, MAGNETISM_EDGE_RIGHT
));
139 MagnetismMatcher::~MagnetismMatcher() {
142 bool MagnetismMatcher::ShouldAttach(const gfx::Rect
& bounds
,
144 for (size_t i
= 0; i
< matchers_
.size(); ++i
) {
145 if (matchers_
[i
]->ShouldAttach(bounds
)) {
146 edge
->primary_edge
= matchers_
[i
]->edge();
147 AttachToSecondaryEdge(bounds
, edge
->primary_edge
,
148 &(edge
->secondary_edge
));
155 bool MagnetismMatcher::AreEdgesObscured() const {
156 for (size_t i
= 0; i
< matchers_
.size(); ++i
) {
157 if (!matchers_
[i
]->is_edge_obscured())
163 void MagnetismMatcher::AttachToSecondaryEdge(
164 const gfx::Rect
& bounds
,
166 SecondaryMagnetismEdge
* secondary_edge
) const {
167 const gfx::Rect
& src_bounds(matchers_
[0]->bounds());
168 if (edge
== MAGNETISM_EDGE_LEFT
|| edge
== MAGNETISM_EDGE_RIGHT
) {
169 if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_LEADING
, edges_
) &&
170 IsCloseEnough(bounds
.y(), src_bounds
.y())) {
171 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_LEADING
;
172 } else if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_TRAILING
,
174 IsCloseEnough(bounds
.bottom(), src_bounds
.bottom())) {
175 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_TRAILING
;
177 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_NONE
;
180 if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_LEADING
, edges_
) &&
181 IsCloseEnough(bounds
.x(), src_bounds
.x())) {
182 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_LEADING
;
183 } else if (CanMatchSecondaryEdge(edge
, SECONDARY_MAGNETISM_EDGE_TRAILING
,
185 IsCloseEnough(bounds
.right(), src_bounds
.right())) {
186 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_TRAILING
;
188 *secondary_edge
= SECONDARY_MAGNETISM_EDGE_NONE
;
193 } // namespace internal