spelling_service_client.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spelling_service_client.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/string_escape.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 19a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/common/spellcheck_common.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_result.h" 21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/user_prefs/user_prefs.h" 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "content/public/browser/browser_context.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/google_api_keys.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h" 26d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "url/gurl.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The URL for requesting spell checking and sending user feedback. 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kSpellingServiceURL[] = "https://www.googleapis.com/rpc"; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// The location of spellcheck suggestions in JSON response from spelling 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// service. 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kMisspellingsPath[] = "result.spellingCheckResponse.misspellings"; 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// The location of error messages in JSON response from spelling service. 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kErrorPath[] = "error"; 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SpellingServiceClient::SpellingServiceClient() { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SpellingServiceClient::~SpellingServiceClient() { 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STLDeleteContainerPairPointers(spellcheck_fetchers_.begin(), 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_fetchers_.end()); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellingServiceClient::RequestTextCheck( 51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) content::BrowserContext* context, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ServiceType type, 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& text, 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TextCheckCompleteCallback& callback) { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type == SUGGEST || type == SPELLCHECK); 56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!context || !IsAvailable(context, type)) { 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback.Run(false, text, std::vector<SpellCheckResult>()); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const PrefService* pref = user_prefs::UserPrefs::Get(context); 62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(pref); 63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string language_code; 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string country_code; 66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) chrome::spellcheck_common::GetISOLanguageCountryCodeFromLocale( 67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) pref->GetString(prefs::kSpellCheckDictionary), 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &language_code, 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &country_code); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Format the JSON request to be sent to the Spelling service. 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string encoded_text = base::GetQuotedJSONString(text); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kSpellingRequest[] = 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "{" 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "\"method\":\"spelling.check\"," 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "\"apiVersion\":\"v%d\"," 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "\"params\":{" 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "\"text\":%s," 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "\"language\":\"%s\"," 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "\"originCountry\":\"%s\"," 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "\"key\":%s" 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "}" 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "}"; 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string api_key = base::GetQuotedJSONString(google_apis::GetAPIKey()); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string request = base::StringPrintf( 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kSpellingRequest, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) encoded_text.c_str(), 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) language_code.c_str(), 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) country_code.c_str(), 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) api_key.c_str()); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL url = GURL(kSpellingServiceURL); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLFetcher* fetcher = CreateURLFetcher(url); 96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) fetcher->SetRequestContext(context->GetRequestContext()); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fetcher->SetUploadData("application/json", request); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fetcher->SetLoadFlags( 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) spellcheck_fetchers_[fetcher] = new TextCheckCallbackData(callback, text); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fetcher->Start(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool SpellingServiceClient::IsAvailable( 106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) content::BrowserContext* context, 107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ServiceType type) { 108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const PrefService* pref = user_prefs::UserPrefs::Get(context); 109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(pref); 110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // If prefs don't allow spellchecking or if the context is off the record, 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the spelling service should be unavailable. 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!pref->GetBoolean(prefs::kEnableContinuousSpellcheck) || 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !pref->GetBoolean(prefs::kSpellCheckUseSpellingService) || 114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) context->IsOffTheRecord()) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the locale for spelling has not been set, the user has not decided to 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // use spellcheck so we don't do anything remote (suggest or spelling). 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string locale = pref->GetString(prefs::kSpellCheckDictionary); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (locale.empty()) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If we do not have the spelling service enabled, then we are only available 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // for SUGGEST. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CommandLine* command_line = CommandLine::ForCurrentProcess(); 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (command_line->HasSwitch(switches::kUseSpellingSuggestions)) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return type == SUGGEST; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Finally, if all options are available, we only enable only SUGGEST 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if SPELLCHECK is not available for our language because SPELLCHECK results 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are a superset of SUGGEST results. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(rlp): Only available for English right now. Fix this line to include 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // all languages SPELLCHECK covers. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool language_available = !locale.compare(0, 2, "en"); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (language_available) { 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return type == SPELLCHECK; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only SUGGEST is allowed. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return type == SUGGEST; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SpellingServiceClient::ParseResponse( 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& data, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<SpellCheckResult>* results) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When this JSON-RPC call finishes successfully, the Spelling service returns 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an JSON object listed below. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * result - an envelope object representing the result from the APIARY 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // server, which is the JSON-API front-end for the Spelling service. This 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // object consists of the following variable: 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - spellingCheckResponse (SpellingCheckResponse). 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * SpellingCheckResponse - an object representing the result from the 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spelling service. This object consists of the following variable: 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - misspellings (optional array of Misspelling) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Misspelling - an object representing a misspelling region and its 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // suggestions. This object consists of the following variables: 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - charStart (number) - the beginning of the misspelled region; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - charLength (number) - the length of the misspelled region; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - suggestions (array of string) - the suggestions for the misspelling 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // text, and; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - canAutoCorrect (optional boolean) - whether we can use the first 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // suggestion for auto-correction. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For example, the Spelling service returns the following JSON when we send a 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spelling request for "duck goes quisk" as of 16 August, 2011. 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "result": { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "spellingCheckResponse": { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "misspellings": [{ 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "charStart": 10, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "charLength": 5, 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "suggestions": [{ "suggestion": "quack" }], 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "canAutoCorrect": false 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // }] 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // } 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If the service is not available, the Spelling service returns JSON with an 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // error. 179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // { 180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // "error": { 181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // "code": 400, 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // "message": "Bad Request", 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // "data": [...] 184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // } 185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // } 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<base::DictionaryValue> value( 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static_cast<base::DictionaryValue*>( 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS))); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY)) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Check for errors from spelling service. 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::DictionaryValue* error = NULL; 194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (value->GetDictionary(kErrorPath, &error)) 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Retrieve the array of Misspelling objects. When the input text does not 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have misspelled words, it returns an empty JSON. (In this case, its HTTP 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // status is 200.) We just return true for this case. 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ListValue* misspellings = NULL; 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!value->GetList(kMisspellingsPath, &misspellings)) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < misspellings->GetSize(); ++i) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Retrieve the i-th misspelling region and put it to the given vector. When 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the Spelling service sends two or more suggestions, we read only the 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // first one because SpellCheckResult can store only one suggestion. 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::DictionaryValue* misspelling = NULL; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!misspellings->GetDictionary(i, &misspelling)) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start = 0; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int length = 0; 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ListValue* suggestions = NULL; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!misspelling->GetInteger("charStart", &start) || 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !misspelling->GetInteger("charLength", &length) || 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !misspelling->GetList("suggestions", &suggestions)) { 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::DictionaryValue* suggestion = NULL; 222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 replacement; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!suggestions->GetDictionary(0, &suggestion) || 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggestion->GetString("suggestion", &replacement)) { 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpellCheckResult result( 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpellCheckResult::SPELLING, start, length, replacement); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->push_back(result); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)SpellingServiceClient::TextCheckCallbackData::TextCheckCallbackData( 235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) TextCheckCompleteCallback callback, 236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 text) 237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : callback(callback), 238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) text(text) { 239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)SpellingServiceClient::TextCheckCallbackData::~TextCheckCallbackData() { 242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void SpellingServiceClient::OnURLFetchComplete( 245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const net::URLFetcher* source) { 246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(spellcheck_fetchers_[source]); 247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_ptr<const net::URLFetcher> fetcher(source); 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_ptr<TextCheckCallbackData> 249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) callback_data(spellcheck_fetchers_[fetcher.get()]); 250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool success = false; 251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<SpellCheckResult> results; 252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (fetcher->GetResponseCode() / 100 == 2) { 253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string data; 254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fetcher->GetResponseAsString(&data); 255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) success = ParseResponse(data, &results); 256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) callback_data->callback.Run(success, callback_data->text, results); 258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) spellcheck_fetchers_.erase(fetcher.get()); 259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)net::URLFetcher* SpellingServiceClient::CreateURLFetcher(const GURL& url) { 262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return net::URLFetcher::Create(url, net::URLFetcher::POST, this); 263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 264