OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h" | |
6 | |
7 #include "ash/system/tray/actionable_view.h" | |
8 #include "ash/system/tray/tray_background_view.h" | |
9 #include "ash/system/tray/tray_popup_header_button.h" | |
10 #include "ash/wm/window_util.h" | |
xiyuan
2014/09/11 03:33:10
nit: line 7-10 seems not used.
dmazzoni
2014/09/11 21:44:38
Done.
| |
11 #include "chrome/browser/chromeos/ui/focus_ring_layer.h" | |
12 #include "ui/aura/window.h" | |
13 #include "ui/views/controls/button/label_button.h" | |
14 #include "ui/views/view.h" | |
15 #include "ui/views/widget/widget.h" | |
xiyuan
2014/09/11 03:33:11
nit: line 12-15 seems not used
dmazzoni
2014/09/11 21:44:38
Done.
| |
16 | |
17 namespace chromeos { | |
18 | |
19 namespace { | |
xiyuan
2014/09/11 03:33:10
nit: insert an empty line after
dmazzoni
2014/09/11 21:44:38
Done.
| |
20 // The number of pixels the focus ring is outset from the object it outlines, | |
21 // which also determines the border radius of the rounded corners. | |
22 // TODO(dmazzoni): take display resolution into account. | |
23 const int kAccessibilityFocusRingMargin = 16; | |
24 } | |
xiyuan
2014/09/11 03:33:10
nit: insert an emtpy line before and add "// name
dmazzoni
2014/09/11 21:44:38
Done.
| |
25 | |
26 // static | |
27 AccessibilityFocusRingController* | |
28 AccessibilityFocusRingController::GetInstance() { | |
29 return Singleton<AccessibilityFocusRingController>::get(); | |
30 } | |
31 | |
32 AccessibilityFocusRingController::AccessibilityFocusRingController() { | |
33 } | |
34 | |
35 AccessibilityFocusRingController::~AccessibilityFocusRingController() { | |
36 } | |
37 | |
38 void AccessibilityFocusRingController::SetFocusRing( | |
39 const std::vector<gfx::Rect>& rects) { | |
40 rects_ = rects; | |
41 Update(); | |
42 } | |
43 | |
44 void AccessibilityFocusRingController::Update() { | |
45 rings_.clear(); | |
46 RectsToRings(rects_, &rings_); | |
47 | |
48 if (!main_focus_ring_layer_) | |
49 main_focus_ring_layer_.reset(new AccessibilityFocusRingLayer(this)); | |
50 | |
51 if (rings_.size()) | |
xiyuan
2014/09/11 03:33:10
nit: rings_.size() -> !rings_.empty()
dmazzoni
2014/09/11 21:44:38
Done.
| |
52 main_focus_ring_layer_->Set(rings_[0]); | |
53 } | |
54 | |
55 struct Region { | |
xiyuan
2014/09/11 03:33:10
nit: Move into anonymous namespace?
dmazzoni
2014/09/11 21:44:38
Done, and added a comment.
| |
56 explicit Region(gfx::Rect initial_rect) { | |
57 bounds = initial_rect; | |
58 rects.push_back(initial_rect); | |
59 } | |
60 gfx::Rect bounds; | |
61 std::vector<gfx::Rect> rects; | |
62 }; | |
63 | |
64 void AccessibilityFocusRingController::RectsToRings( | |
65 const std::vector<gfx::Rect>& rects, | |
66 std::vector<AccessibilityFocusRing>* rings) const { | |
67 if (rects.size() == 0) | |
xiyuan
2014/09/11 03:33:10
nit: rects.size() == 0 -> rects.empty()
dmazzoni
2014/09/11 21:44:38
Done.
| |
68 return; | |
69 | |
70 // Split the rects into contiguous regions. | |
71 std::vector<Region> regions; | |
72 regions.push_back(Region(rects[0])); | |
73 for (size_t i = 1; i < rects.size(); ++i) { | |
74 bool found = false; | |
75 for (size_t j = 0; j < regions.size(); ++j) { | |
76 if (Intersects(rects[i], regions[j].bounds)) { | |
xiyuan
2014/09/11 03:33:10
Should we set |found| to true here?
dmazzoni
2014/09/11 21:44:39
Yes, thanks
| |
77 regions[j].rects.push_back(rects[i]); | |
78 regions[j].bounds.Union(rects[i]); | |
79 } | |
80 } | |
81 if (!found) { | |
82 regions.push_back(Region(rects[i])); | |
83 } | |
84 } | |
85 | |
86 // Keep merging regions that intersect. | |
87 // TODO(dmazzoni): reduce the worst-case complexity! This appears like | |
88 // it could be O(n^3), make sure it's not in practice. | |
89 bool merged; | |
90 do { | |
91 merged = false; | |
92 for (size_t i = 0; i < regions.size() - 1 && !merged; ++i) { | |
93 for (size_t j = i + 1; j < regions.size() && !merged; ++j) { | |
94 if (Intersects(regions[i].bounds, regions[j].bounds)) { | |
95 regions[i].rects.insert(regions[i].rects.end(), | |
96 regions[j].rects.begin(), | |
97 regions[j].rects.end()); | |
98 regions[i].bounds.Union(regions[j].bounds); | |
99 regions.erase(regions.begin() + j); | |
100 merged = true; | |
101 } | |
102 } | |
103 } | |
104 } while (merged); | |
105 | |
106 for (size_t i = 0; i < regions.size(); ++i) { | |
107 std::sort(regions[i].rects.begin(), regions[i].rects.end()); | |
108 rings->push_back(RingFromSortedRects(regions[i].rects)); | |
109 } | |
110 } | |
111 | |
112 int AccessibilityFocusRingController::GetMargin() const { | |
113 return kAccessibilityFocusRingMargin; | |
114 } | |
115 | |
116 // Given a vector of rects that all overlap, already sorted from top to bottom | |
117 // and left to right, split them into three shapes covering the top, middle, | |
118 // and bottom of a "paragraph shape". | |
119 // | |
120 // Input: | |
121 // | |
122 // +---+---+ | |
123 // | 1 | 2 | | |
124 // +---------------------+---+---+ | |
125 // | 3 | | |
126 // +--------+---------------+----+ | |
127 // | 4 | 5 | | |
128 // +--------+---------------+--+ | |
129 // | 6 | | |
130 // +---------+-----------------+ | |
131 // | 7 | | |
132 // +---------+ | |
133 // | |
134 // Output: | |
135 // | |
136 // +-------+ | |
137 // | Top | | |
138 // +---------------------+-------+ | |
139 // | | | |
140 // | | | |
141 // | Middle | | |
142 // | | | |
143 // | | | |
144 // +---------+-------------------+ | |
145 // | Bottom | | |
146 // +---------+ | |
147 // | |
148 // When there's no clear "top" or "bottom" segment, split the overall rect | |
149 // evenly so that some of the area still fits into the "top" and "bottom" | |
150 // segments. | |
151 void AccessibilityFocusRingController::SplitIntoParagraphShape( | |
152 const std::vector<gfx::Rect>& rects, | |
153 gfx::Rect* top, | |
154 gfx::Rect* middle, | |
155 gfx::Rect* bottom) const { | |
156 size_t n = rects.size(); | |
157 | |
158 // Figure out how many rects belong in the top portion. | |
159 gfx::Rect top_rect = rects[0]; | |
160 int top_middle = (top_rect.y() + top_rect.bottom()) / 2; | |
161 size_t top_count = 1; | |
162 while (top_count < n && rects[top_count].y() < top_middle) { | |
163 top_rect.Union(rects[top_count]); | |
164 top_middle = (top_rect.y() + top_rect.bottom()) / 2; | |
165 top_count++; | |
166 } | |
167 | |
168 // Figure out how many rects belong in the bottom portion. | |
169 gfx::Rect bottom_rect = rects[n - 1]; | |
170 int bottom_middle = (bottom_rect.y() + bottom_rect.bottom()) / 2; | |
171 size_t bottom_count = std::min(static_cast<size_t>(1), n - top_count); | |
172 while (bottom_count + top_count < n && | |
173 rects[n - bottom_count - 1].bottom() > bottom_middle) { | |
174 bottom_rect.Union(rects[n - bottom_count - 1]); | |
175 bottom_middle = (bottom_rect.y() + bottom_rect.bottom()) / 2; | |
176 bottom_count++; | |
177 } | |
178 | |
179 // Whatever's left goes to the middle rect, but if there's no middle or | |
180 // bottom rect, split the existing rects evenly to make one. | |
181 gfx::Rect middle_rect; | |
182 if (top_count + bottom_count < n) { | |
183 middle_rect = rects[top_count]; | |
184 for (size_t i = top_count + 1; i < n - bottom_count; i++) | |
185 middle_rect.Union(rects[i]); | |
186 } else if (bottom_count > 0) { | |
187 gfx::Rect enclosing_rect = top_rect; | |
188 enclosing_rect.Union(bottom_rect); | |
189 int middle_top = (top_rect.y() + top_rect.bottom() * 2) / 3; | |
190 int middle_bottom = (bottom_rect.y() * 2 + bottom_rect.bottom()) / 3; | |
191 top_rect.set_height(middle_top - top_rect.y()); | |
192 bottom_rect.set_height(bottom_rect.bottom() - middle_bottom); | |
193 bottom_rect.set_y(middle_bottom); | |
194 middle_rect = gfx::Rect(enclosing_rect.x(), middle_top, | |
195 enclosing_rect.width(), middle_bottom - middle_top); | |
196 } else { | |
197 int middle_top = (top_rect.y() * 2 + top_rect.bottom()) / 3; | |
198 int middle_bottom = (top_rect.y() + top_rect.bottom() * 2) / 3; | |
199 middle_rect = gfx::Rect(top_rect.x(), middle_top, | |
200 top_rect.width(), middle_bottom - middle_top); | |
201 bottom_rect = gfx::Rect( | |
202 top_rect.x(), middle_bottom, | |
203 top_rect.width(), top_rect.bottom() - middle_bottom); | |
204 top_rect.set_height(middle_top - top_rect.y()); | |
205 } | |
206 | |
207 if (middle_rect.y() > top_rect.bottom()) { | |
208 middle_rect.set_height( | |
209 middle_rect.height() + middle_rect.y() - top_rect.bottom()); | |
210 middle_rect.set_y(top_rect.bottom()); | |
211 } | |
212 | |
213 if (middle_rect.bottom() < bottom_rect.y()) { | |
214 middle_rect.set_height(bottom_rect.y() - middle_rect.y()); | |
215 } | |
216 | |
217 *top = top_rect; | |
218 *middle = middle_rect; | |
219 *bottom = bottom_rect; | |
220 } | |
221 | |
222 AccessibilityFocusRing AccessibilityFocusRingController::RingFromSortedRects( | |
223 const std::vector<gfx::Rect>& rects) const { | |
224 if (rects.size() == 1) | |
225 return AccessibilityFocusRing::CreateWithRect(rects[0], GetMargin()); | |
226 | |
227 gfx::Rect top; | |
228 gfx::Rect middle; | |
229 gfx::Rect bottom; | |
230 SplitIntoParagraphShape(rects, &top, &middle, &bottom); | |
231 | |
232 return AccessibilityFocusRing::CreateWithParagraphShape( | |
233 top, middle, bottom, GetMargin()); | |
234 } | |
235 | |
236 bool AccessibilityFocusRingController::Intersects( | |
237 const gfx::Rect& r1, const gfx::Rect& r2) const { | |
238 int slop = GetMargin(); | |
239 return (r2.x() <= r1.right() + slop && | |
240 r2.right() >= r1.x() - slop && | |
241 r2.y() <= r1.bottom() + slop && | |
242 r2.bottom() >= r1.y() - slop); | |
243 } | |
244 | |
245 void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() { | |
246 Update(); | |
247 } | |
248 | |
249 } // namespace chromeos | |
OLD | NEW |