Only fsync leveldb's directory when the manifest is being updated.
[chromium-blink-merge.git] / ash / wm / workspace / magnetism_matcher.cc
blobe7d674b850c4c51c45ac742b63a03fce4088ef62
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"
7 #include <algorithm>
8 #include <cmath>
10 namespace ash {
11 namespace internal {
13 namespace {
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
22 // MagnetismEdges.
23 bool CanMatchSecondaryEdge(MagnetismEdge primary,
24 SecondaryMagnetismEdge secondary,
25 uint32 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;
48 return (edges & secondary_as_magnetism_edge) != 0;
51 } // namespace
53 // MagnetismEdgeMatcher --------------------------------------------------------
55 MagnetismEdgeMatcher::MagnetismEdgeMatcher(const gfx::Rect& bounds,
56 MagnetismEdge edge)
57 : bounds_(bounds),
58 edge_(edge) {
59 ranges_.push_back(GetSecondaryRange(bounds_));
62 MagnetismEdgeMatcher::~MagnetismEdgeMatcher() {
65 bool MagnetismEdgeMatcher::ShouldAttach(const gfx::Rect& bounds) {
66 if (is_edge_obscured())
67 return false;
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))) {
77 return true;
80 // NOTE: this checks against the current bounds, we may want to allow some
81 // flexibility here.
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));
87 return false;
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))
94 --it;
95 if (it == ranges_.end())
96 return;
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);
106 ++i;
107 } else {
108 Range existing(ranges_[i]);
109 ranges_[i].second = range.first;
110 ++i;
111 if (existing.second > range.second) {
112 ranges_.insert(ranges_.begin() + i,
113 Range(range.second, existing.second));
114 ++i;
120 // MagnetismMatcher ------------------------------------------------------------
122 // static
123 const int MagnetismMatcher::kMagneticDistance = 8;
125 MagnetismMatcher::MagnetismMatcher(const gfx::Rect& bounds, uint32 edges)
126 : edges_(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,
143 MatchedEdge* edge) {
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));
149 return true;
152 return false;
155 bool MagnetismMatcher::AreEdgesObscured() const {
156 for (size_t i = 0; i < matchers_.size(); ++i) {
157 if (!matchers_[i]->is_edge_obscured())
158 return false;
160 return true;
163 void MagnetismMatcher::AttachToSecondaryEdge(
164 const gfx::Rect& bounds,
165 MagnetismEdge edge,
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,
173 edges_) &&
174 IsCloseEnough(bounds.bottom(), src_bounds.bottom())) {
175 *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING;
176 } else {
177 *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE;
179 } else {
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,
184 edges_) &&
185 IsCloseEnough(bounds.right(), src_bounds.right())) {
186 *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING;
187 } else {
188 *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE;
193 } // namespace internal
194 } // namespace ash