Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc

Issue 557393003: Introduce AccessibilityFocusRing. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@accessibility_private_histograms
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698