172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Use of this source code is governed by a BSD-style license that can be 3bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// found in the LICENSE file. 4bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen 5bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/chromeos/login/wizard_accessibility_handler.h" 6bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen 7731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <algorithm> 8731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/i18n/char_iterator.h" 10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/logging.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/string_number_conversions.h" 13bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/accessibility_events.h" 14bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/chromeos/cros/cros_library.h" 15bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/chromeos/cros/speech_synthesis_library.h" 16731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/extensions/extension_accessibility_api.h" 17731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/extensions/extension_accessibility_api_constants.h" 1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h" 19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_details.h" 20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_source.h" 21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "grit/generated_resources.h" 2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 24731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace keys = extension_accessibility_api_constants; 25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 26731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace { 27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstatic std::string SubstringUTF8(std::string str, int start, int len) { 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::i18n::UTF8CharIterator iter(&str); 30731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick for (int i = 0; i < start; i++) { 31731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!iter.Advance()) 32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return std::string(); 33731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int byte_start = iter.array_pos(); 36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick for (int i = 0; i < len; i++) { 37731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!iter.Advance()) 38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick break; 39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int byte_len = iter.array_pos() - byte_start; 41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return str.substr(byte_start, byte_len); 43731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// If the string consists of a single character and that character is 46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// punctuation that is not normally spoken by TTS, replace the string 47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// with a description of that character (like "period" for "."). 48731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string DescribePunctuation(const std::string& str) { 49731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (str == "!") { 50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_EXCLAMATION_POINT); 51731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == "(") { 52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LEFT_PAREN); 53731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == ")") { 54731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_RIGHT_PAREN); 55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == ";") { 56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_SEMICOLON); 57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == ":") { 58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_COLON); 59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == "\"") { 60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_QUOTE); 61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == ",") { 62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_COMMA); 63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == ".") { 64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_PERIOD); 65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (str == " ") { 66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_SPACE); 67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return str; 69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Append words and separate adding a space if needed. Call 73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// DescribePunctuation on to_append so that single punctuation 74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// characters are expanded ('.' -> 'period') but punctuation 75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// in the middle of a larger phrase are handled by the speech 76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// engine. 77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid AppendUtterance(std::string to_append, std::string* str) { 78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if ((*str).size()) 79731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *str += " "; 80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *str += DescribePunctuation(to_append); 82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Append a localized string from its message ID, adding a space if needed. 85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid AppendUtterance(int message_id, std::string* str) { 86731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(l10n_util::GetStringUTF8(message_id), str); 87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Append a phrase of the form "3 of 5", adding a space if needed. 90731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid AppendIndexOfCount(int index, int count, std::string* str) { 91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick string16 index_str = base::IntToString16(index); 92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick string16 count_str = base::IntToString16(count); 93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(l10n_util::GetStringFUTF8(IDS_CHROMEOS_ACC_INDEX_OF_COUNT, 94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick index_str, 95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick count_str), str); 96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} // anonymous namespace 99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 100731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace chromeos { 101bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen 102bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid WizardAccessibilityHandler::Observe( 103bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen NotificationType type, 104bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen const NotificationSource& source, 105bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen const NotificationDetails& details) { 106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityControlInfo *control_info = 107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick Details<const AccessibilityControlInfo>(details).ptr(); 108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string description; 109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EarconType earcon = NO_EARCON; 110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DescribeAccessibilityEvent(type, control_info, &description, &earcon); 111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick Speak(description.c_str(), false, true); 112bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen} 113bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen 114bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid WizardAccessibilityHandler::Speak(const char* speak_str, 115bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen bool queue, 116bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen bool interruptible) { 117bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { 118bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen if (queue || !interruptible) { 119bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen std::string props = ""; 120bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen props.append("enqueue="); 121bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen props.append(queue ? "1;" : "0;"); 122bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen props.append("interruptible="); 123bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen props.append(interruptible ? "1;" : "0;"); 124bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> 125bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen SetSpeakProperties(props.c_str()); 126bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen } 127bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> 128bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen Speak(speak_str); 129bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen } 130bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen} 131731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 132731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WizardAccessibilityHandler::DescribeAccessibilityEvent( 133731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick NotificationType event_type, 134731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityControlInfo* control_info, 135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string* out_spoken_description, 136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EarconType* out_earcon) { 137731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_spoken_description = std::string(); 138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = NO_EARCON; 139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick switch (event_type.value) { 141731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick case NotificationType::ACCESSIBILITY_CONTROL_FOCUSED: 142731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DescribeControl(control_info, false, out_spoken_description, out_earcon); 143731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick break; 144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick case NotificationType::ACCESSIBILITY_CONTROL_ACTION: 145731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DescribeControl(control_info, true, out_spoken_description, out_earcon); 146731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick break; 147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick case NotificationType::ACCESSIBILITY_TEXT_CHANGED: 148731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DescribeTextChanged(control_info, out_spoken_description, out_earcon); 149731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick break; 150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick case NotificationType::ACCESSIBILITY_MENU_OPENED: 151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_OBJECT_OPENED; 152731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick break; 153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick case NotificationType::ACCESSIBILITY_MENU_CLOSED: 154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_OBJECT_CLOSED; 155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick break; 156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick default: 157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick NOTREACHED(); 158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return; 159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (control_info->type() == keys::kTypeTextBox) { 162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityTextBoxInfo* text_box = 163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityTextBoxInfo*>(control_info); 164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick previous_text_value_ = GetTextBoxValue(text_box); 165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick previous_text_selection_start_ = text_box->selection_start(); 166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick previous_text_selection_end_ = text_box->selection_end(); 167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WizardAccessibilityHandler::DescribeControl( 171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityControlInfo* control_info, 172731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick bool is_action, 173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string* out_spoken_description, 174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EarconType* out_earcon) { 175731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (control_info->type() == keys::kTypeButton) { 176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_BUTTON; 177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(control_info->name(), out_spoken_description); 178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_BUTTON, out_spoken_description); 179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeCheckbox) { 180731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(control_info->name(), out_spoken_description); 181731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityCheckboxInfo* checkbox_info = 182731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityCheckboxInfo*>(control_info); 183731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (checkbox_info->checked()) { 184731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_CHECK_ON; 185731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_CHECKBOX_CHECKED, 186731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_CHECK_OFF; 189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_CHECKBOX_UNCHECKED, 190731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 192731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeComboBox) { 193731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_LISTBOX; 194731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityComboBoxInfo* combobox_info = 195731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityComboBoxInfo*>(control_info); 196731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(combobox_info->value(), out_spoken_description); 197731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(combobox_info->name(), out_spoken_description); 198731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_COMBOBOX, out_spoken_description); 199731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendIndexOfCount(combobox_info->item_index() + 1, 200731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick combobox_info->item_count(), 201731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 202731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeLink) { 203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_LINK; 204731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(control_info->name(), out_spoken_description); 205731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_LINK, out_spoken_description); 206731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeListBox) { 207731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_LISTBOX; 208731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityListBoxInfo* listbox_info = 209731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityListBoxInfo*>(control_info); 210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(listbox_info->value(), out_spoken_description); 211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(listbox_info->name(), out_spoken_description); 212731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_LISTBOX, out_spoken_description); 213731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendIndexOfCount(listbox_info->item_index() + 1, 214731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick listbox_info->item_count(), 215731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 216731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeMenu) { 217731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_MENU; 218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(control_info->name(), out_spoken_description); 219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_MENU, out_spoken_description); 220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeMenuItem) { 221731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityMenuItemInfo* menu_item_info = 222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityMenuItemInfo*>(control_info); 223731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(menu_item_info->name(), out_spoken_description); 224731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (menu_item_info->has_submenu()) 225731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_HAS_SUBMENU, out_spoken_description); 226731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendIndexOfCount(menu_item_info->item_index() + 1, 227731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick menu_item_info->item_count(), 228731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 229731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeRadioButton) { 230731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(control_info->name(), out_spoken_description); 231731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityRadioButtonInfo* radio_info = 232731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityRadioButtonInfo*>(control_info); 233731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (radio_info->checked()) { 234731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_CHECK_ON; 235731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_RADIO_SELECTED, out_spoken_description); 236731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 237731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_CHECK_OFF; 238731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_RADIO_UNSELECTED, 239731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 240731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 241731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendIndexOfCount(radio_info->item_index() + 1, 242731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick radio_info->item_count(), 243731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 244731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeTab) { 245731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_TAB; 246731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(control_info->name(), out_spoken_description); 247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityTabInfo* tab_info = 248731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityTabInfo*>(control_info); 249731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_TAB, out_spoken_description); 250731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendIndexOfCount(tab_info->tab_index() + 1, 251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick tab_info->tab_count(), 252731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 253731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeTextBox) { 254731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *out_earcon = EARCON_TEXTBOX; 255731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityTextBoxInfo* textbox_info = 256731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityTextBoxInfo*>(control_info); 257731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(GetTextBoxValue(textbox_info), out_spoken_description); 258731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(textbox_info->name(), out_spoken_description); 259731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (textbox_info->password()) { 260731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_PASSWORDBOX, out_spoken_description); 261731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_TEXTBOX, out_spoken_description); 263731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 264731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (control_info->type() == keys::kTypeWindow) { 265731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // No feedback when a window gets focus 266731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 267731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 268731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (is_action) 269731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_SELECTED, out_spoken_description); 270731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 271731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 272731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WizardAccessibilityHandler::DescribeTextChanged( 273731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityControlInfo* control_info, 274731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string* out_spoken_description, 275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick EarconType* out_earcon) { 276731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK_EQ(control_info->type(), keys::kTypeTextBox); 277731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityTextBoxInfo* text_box = 278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick static_cast<const AccessibilityTextBoxInfo*>(control_info); 279731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 280731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string old_value = previous_text_value_; 281731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int old_start = previous_text_selection_start_; 282731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int old_end = previous_text_selection_end_; 283731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string new_value = GetTextBoxValue(text_box); 284731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int new_start = text_box->selection_start(); 285731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int new_end = text_box->selection_end(); 286731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 287731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (new_value == old_value) { 288731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DescribeTextSelectionChanged(new_value, 289731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_start, old_end, 290731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_start, new_end, 291731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 292731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 293731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DescribeTextContentsChanged(old_value, new_value, 294731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 295731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 296731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 297731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 298731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string WizardAccessibilityHandler::GetTextBoxValue( 299731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const AccessibilityTextBoxInfo* textbox_info) { 300731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string value = textbox_info->value(); 301731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (textbox_info->password()) { 30272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::i18n::UTF8CharIterator iter(&value); 303731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string obscured; 304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick while (!iter.end()) { 305731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick obscured += "*"; 306731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick iter.Advance(); 307731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 308731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return obscured; 309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return value; 311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 312731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 313731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WizardAccessibilityHandler::DescribeTextSelectionChanged( 315731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const std::string& value, 316731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int old_start, 317731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int old_end, 318731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int new_start, 319731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int new_end, 320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string* out_spoken_description) { 321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (new_start == new_end) { 322731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // It's currently a cursor. 323731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (old_start != old_end) { 324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // It was previously a selection, so just announce 'unselected'. 325731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(IDS_CHROMEOS_ACC_TEXT_UNSELECTED, out_spoken_description); 326731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (old_start == new_start + 1 || old_start == new_start - 1) { 327731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Moved by one character; read it. 328731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, std::min(old_start, new_start), 1), 329731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 330731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 331731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Moved by more than one character. Read all characters crossed. 332731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, 333731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::min(old_start, new_start), 334731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick abs(old_start - new_start)), 335731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 336731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 337731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 338731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // It's currently a selection. 339731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (old_start == old_end) { 340731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // It was previously a cursor. 341731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, new_start, new_end - new_start), 342731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 343731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (old_start == new_start && old_end < new_end) { 344731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Added to end of selection. 345731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, old_end, new_end - old_end), 346731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 347731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (old_start == new_start && old_end > new_end) { 348731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Removed from end of selection. 349731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, new_end, old_end - new_end), 350731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 351731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (old_end == new_end && old_start > new_start) { 352731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Added to beginning of selection. 353731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, new_start, old_start - new_start), 354731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 355731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else if (old_end == new_end && old_start < new_start) { 356731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Removed from beginning of selection. 357731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, old_start, new_start - old_start), 358731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 359731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } else { 360731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // The selection changed but it wasn't an obvious extension of 361731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // a previous selection. Just read the new selection. 362731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(SubstringUTF8(value, new_start, new_end - new_start), 363731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick out_spoken_description); 364731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 365731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 366731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 367731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 368731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WizardAccessibilityHandler::DescribeTextContentsChanged( 369731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const std::string& old_value, 370731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const std::string& new_value, 371731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string* out_spoken_description) { 372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int old_array_len = old_value.size(); 373731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int new_array_len = new_value.size(); 374731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 375731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Get the unicode characters and indices of the start of each 376731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // character's UTF8-encoded representation. 377731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick scoped_array<int32> old_chars(new int32[old_array_len]); 378731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick scoped_array<int> old_indices(new int[old_array_len + 1]); 37972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::i18n::UTF8CharIterator old_iter(&old_value); 380731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick while (!old_iter.end()) { 381731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_chars[old_iter.char_pos()] = old_iter.get(); 382731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_indices[old_iter.char_pos()] = old_iter.array_pos(); 383731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_iter.Advance(); 384731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 385731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int old_char_len = old_iter.char_pos(); 386731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_indices[old_char_len] = old_iter.array_pos(); 387731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 388731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick scoped_array<int32> new_chars(new int32[new_array_len]); 389731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick scoped_array<int> new_indices(new int[new_array_len + 1]); 39072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::i18n::UTF8CharIterator new_iter(&new_value); 391731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick while (!new_iter.end()) { 392731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_chars[new_iter.char_pos()] = new_iter.get(); 393731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_indices[new_iter.char_pos()] = new_iter.array_pos(); 394731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_iter.Advance(); 395731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 396731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int new_char_len = new_iter.char_pos(); 397731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_indices[new_char_len] = new_iter.array_pos(); 398731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 399731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Find the common prefix of the two strings. 400731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int prefix_char_len = 0; 401731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick while (prefix_char_len < old_char_len && 402731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick prefix_char_len < new_char_len && 403731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_chars[prefix_char_len] == new_chars[prefix_char_len]) { 404731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick prefix_char_len++; 405731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 406731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 407731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Find the common suffix of the two stirngs. 408731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int suffix_char_len = 0; 409731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick while (suffix_char_len < old_char_len - prefix_char_len && 410731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick suffix_char_len < new_char_len - prefix_char_len && 411731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick (old_chars[old_char_len - suffix_char_len - 1] == 412731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_chars[new_char_len - suffix_char_len - 1])) { 413731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick suffix_char_len++; 414731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 415731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 416731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int old_suffix_char_start = old_char_len - suffix_char_len; 417731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick int new_suffix_char_start = new_char_len - suffix_char_len; 418731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 419731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Find the substring that was deleted (if any) to get the new string 420731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // from the old - it's the part in the middle of the old string if you 421731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // remove the common prefix and suffix. 422731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string deleted = old_value.substr( 423731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_indices[prefix_char_len], 424731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick old_indices[old_suffix_char_start] - old_indices[prefix_char_len]); 425731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 426731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Find the substring that was inserted (if any) to get the new string 427731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // from the old - it's the part in the middle of the new string if you 428731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // remove the common prefix and suffix. 429731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string inserted = new_value.substr( 430731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_indices[prefix_char_len], 431731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new_indices[new_suffix_char_start] - new_indices[prefix_char_len]); 432731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 433dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!inserted.empty() && !deleted.empty()) { 434731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Replace one substring with another, speak inserted text. 435731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(inserted, out_spoken_description); 436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else if (!inserted.empty()) { 437731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Speak inserted text. 438731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(inserted, out_spoken_description); 439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else if (!deleted.empty()) { 440731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Speak deleted text. 441731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick AppendUtterance(deleted, out_spoken_description); 442731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 443731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 444731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 445731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} // namespace chromeos 446