• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
6 
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/timer/timer.h"
10 #include "content/browser/accessibility/accessibility_mode_helper.h"
11 #include "content/browser/renderer_host/render_widget_host_impl.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/render_widget_host_iterator.h"
15 #include "content/public/common/content_switches.h"
16 #include "ui/gfx/sys_color_change_listener.h"
17 
18 #if defined(OS_WIN)
19 #include "base/win/windows_version.h"
20 #endif
21 
22 namespace content {
23 
24 // Update the accessibility histogram 45 seconds after initialization.
25 static const int kAccessibilityHistogramDelaySecs = 45;
26 
27 // static
GetInstance()28 BrowserAccessibilityState* BrowserAccessibilityState::GetInstance() {
29   return BrowserAccessibilityStateImpl::GetInstance();
30 }
31 
32 // static
GetInstance()33 BrowserAccessibilityStateImpl* BrowserAccessibilityStateImpl::GetInstance() {
34   return Singleton<BrowserAccessibilityStateImpl,
35                    LeakySingletonTraits<BrowserAccessibilityStateImpl> >::get();
36 }
37 
BrowserAccessibilityStateImpl()38 BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl()
39     : BrowserAccessibilityState(),
40       accessibility_mode_(AccessibilityModeOff) {
41   ResetAccessibilityModeValue();
42 #if defined(OS_WIN)
43   // On Windows, UpdateHistograms calls some system functions with unknown
44   // runtime, so call it on the file thread to ensure there's no jank.
45   // Everything in that method must be safe to call on another thread.
46   BrowserThread::ID update_histogram_thread = BrowserThread::FILE;
47 #else
48   // On all other platforms, UpdateHistograms should be called on the main
49   // thread.
50   BrowserThread::ID update_histogram_thread = BrowserThread::UI;
51 #endif
52 
53   // We need to AddRef() the leaky singleton so that Bind doesn't
54   // delete it prematurely.
55   AddRef();
56   BrowserThread::PostDelayedTask(
57       update_histogram_thread, FROM_HERE,
58       base::Bind(&BrowserAccessibilityStateImpl::UpdateHistograms, this),
59       base::TimeDelta::FromSeconds(kAccessibilityHistogramDelaySecs));
60 }
61 
~BrowserAccessibilityStateImpl()62 BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() {
63 }
64 
OnScreenReaderDetected()65 void BrowserAccessibilityStateImpl::OnScreenReaderDetected() {
66   if (CommandLine::ForCurrentProcess()->HasSwitch(
67           switches::kDisableRendererAccessibility)) {
68     return;
69   }
70   EnableAccessibility();
71 }
72 
EnableAccessibility()73 void BrowserAccessibilityStateImpl::EnableAccessibility() {
74   AddAccessibilityMode(AccessibilityModeComplete);
75 }
76 
DisableAccessibility()77 void BrowserAccessibilityStateImpl::DisableAccessibility() {
78   ResetAccessibilityMode();
79 }
80 
ResetAccessibilityModeValue()81 void BrowserAccessibilityStateImpl::ResetAccessibilityModeValue() {
82   accessibility_mode_ = AccessibilityModeOff;
83 #if defined(OS_WIN)
84   // On Windows 8, always enable accessibility for editable text controls
85   // so we can show the virtual keyboard when one is enabled.
86   if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
87       !CommandLine::ForCurrentProcess()->HasSwitch(
88           switches::kDisableRendererAccessibility)) {
89     accessibility_mode_ = AccessibilityModeEditableTextOnly;
90   }
91 #endif  // defined(OS_WIN)
92 
93   if (CommandLine::ForCurrentProcess()->HasSwitch(
94           switches::kForceRendererAccessibility)) {
95     accessibility_mode_ = AccessibilityModeComplete;
96   }
97 }
98 
ResetAccessibilityMode()99 void BrowserAccessibilityStateImpl::ResetAccessibilityMode() {
100   ResetAccessibilityModeValue();
101 
102   // Iterate over all RenderWidgetHosts, even swapped out ones in case
103   // they become active again.
104   scoped_ptr<RenderWidgetHostIterator> widgets(
105       RenderWidgetHostImpl::GetAllRenderWidgetHosts());
106   while (RenderWidgetHost* widget = widgets->GetNextHost()) {
107     // Ignore processes that don't have a connection, such as crashed tabs.
108     if (!widget->GetProcess()->HasConnection())
109       continue;
110     if (!widget->IsRenderView())
111       continue;
112 
113     RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
114     rwhi->ResetAccessibilityMode();
115   }
116 }
117 
IsAccessibleBrowser()118 bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() {
119   return ((accessibility_mode_ & AccessibilityModeComplete) ==
120           AccessibilityModeComplete);
121 }
122 
AddHistogramCallback(base::Closure callback)123 void BrowserAccessibilityStateImpl::AddHistogramCallback(
124     base::Closure callback) {
125   histogram_callbacks_.push_back(callback);
126 }
127 
UpdateHistogramsForTesting()128 void BrowserAccessibilityStateImpl::UpdateHistogramsForTesting() {
129   UpdateHistograms();
130 }
131 
UpdateHistograms()132 void BrowserAccessibilityStateImpl::UpdateHistograms() {
133   UpdatePlatformSpecificHistograms();
134 
135   for (size_t i = 0; i < histogram_callbacks_.size(); ++i)
136     histogram_callbacks_[i].Run();
137 
138   UMA_HISTOGRAM_BOOLEAN("Accessibility.State", IsAccessibleBrowser());
139   UMA_HISTOGRAM_BOOLEAN("Accessibility.InvertedColors",
140                         gfx::IsInvertedColorScheme());
141   UMA_HISTOGRAM_BOOLEAN("Accessibility.ManuallyEnabled",
142                         CommandLine::ForCurrentProcess()->HasSwitch(
143                             switches::kForceRendererAccessibility));
144 }
145 
146 #if !defined(OS_WIN)
UpdatePlatformSpecificHistograms()147 void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
148 }
149 #endif
150 
AddAccessibilityMode(AccessibilityMode mode)151 void BrowserAccessibilityStateImpl::AddAccessibilityMode(
152     AccessibilityMode mode) {
153   if (CommandLine::ForCurrentProcess()->HasSwitch(
154           switches::kDisableRendererAccessibility)) {
155     return;
156   }
157 
158   accessibility_mode_ =
159       content::AddAccessibilityModeTo(accessibility_mode_, mode);
160 
161   AddOrRemoveFromRenderWidgets(mode, true);
162 }
163 
RemoveAccessibilityMode(AccessibilityMode mode)164 void BrowserAccessibilityStateImpl::RemoveAccessibilityMode(
165     AccessibilityMode mode) {
166   if (CommandLine::ForCurrentProcess()->HasSwitch(
167           switches::kForceRendererAccessibility) &&
168       mode == AccessibilityModeComplete) {
169     return;
170   }
171 
172   accessibility_mode_ =
173       content::RemoveAccessibilityModeFrom(accessibility_mode_, mode);
174 
175   AddOrRemoveFromRenderWidgets(mode, false);
176 }
177 
AddOrRemoveFromRenderWidgets(AccessibilityMode mode,bool add)178 void BrowserAccessibilityStateImpl::AddOrRemoveFromRenderWidgets(
179     AccessibilityMode mode,
180     bool add) {
181   // Iterate over all RenderWidgetHosts, even swapped out ones in case
182   // they become active again.
183   scoped_ptr<RenderWidgetHostIterator> widgets(
184       RenderWidgetHostImpl::GetAllRenderWidgetHosts());
185   while (RenderWidgetHost* widget = widgets->GetNextHost()) {
186     // Ignore processes that don't have a connection, such as crashed tabs.
187     if (!widget->GetProcess()->HasConnection())
188       continue;
189     if (!widget->IsRenderView())
190       continue;
191 
192     RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
193     if (add)
194       rwhi->AddAccessibilityMode(mode);
195     else
196       rwhi->RemoveAccessibilityMode(mode);
197   }
198 }
199 
200 }  // namespace content
201