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

Side by Side Diff: chrome/browser/extensions/api/omnibox/omnibox_api.cc

Issue 12314164: Modified Omnibox extension api to use JSON Schema Compiler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Replaced include with forward declaration Created 7 years, 8 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h" 5 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
6 6
7 #include "base/json/json_writer.h" 7 #include "base/json/json_writer.h"
8 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "base/string16.h" 10 #include "base/string16.h"
11 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
12 #include "base/values.h" 12 #include "base/values.h"
13 #include "chrome/browser/extensions/event_router.h" 13 #include "chrome/browser/extensions/event_router.h"
14 #include "chrome/browser/extensions/extension_prefs.h" 14 #include "chrome/browser/extensions/extension_prefs.h"
15 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_system.h" 16 #include "chrome/browser/extensions/extension_system.h"
17 #include "chrome/browser/extensions/tab_helper.h" 17 #include "chrome/browser/extensions/tab_helper.h"
18 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/search_engines/template_url.h" 19 #include "chrome/browser/search_engines/template_url.h"
20 #include "chrome/browser/search_engines/template_url_service.h" 20 #include "chrome/browser/search_engines/template_url_service.h"
21 #include "chrome/browser/search_engines/template_url_service_factory.h" 21 #include "chrome/browser/search_engines/template_url_service_factory.h"
22 #include "chrome/common/chrome_notification_types.h" 22 #include "chrome/common/chrome_notification_types.h"
23 #include "chrome/common/extensions/api/omnibox.h"
23 #include "chrome/common/extensions/api/omnibox/omnibox_handler.h" 24 #include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
24 #include "chrome/common/extensions/extension.h" 25 #include "chrome/common/extensions/extension.h"
25 #include "content/public/browser/notification_details.h" 26 #include "content/public/browser/notification_details.h"
26 #include "content/public/browser/notification_service.h" 27 #include "content/public/browser/notification_service.h"
27 #include "ui/gfx/image/image.h" 28 #include "ui/gfx/image/image.h"
28 29
29 namespace events { 30 namespace events {
30 const char kOnInputStarted[] = "omnibox.onInputStarted"; 31 const char kOnInputStarted[] = "omnibox.onInputStarted";
31 const char kOnInputChanged[] = "omnibox.onInputChanged"; 32 const char kOnInputChanged[] = "omnibox.onInputChanged";
32 const char kOnInputEntered[] = "omnibox.onInputEntered"; 33 const char kOnInputEntered[] = "omnibox.onInputEntered";
33 const char kOnInputCancelled[] = "omnibox.onInputCancelled"; 34 const char kOnInputCancelled[] = "omnibox.onInputCancelled";
34 } // namespace events 35 } // namespace events
35 36
36 namespace extensions { 37 namespace extensions {
37 38
39 namespace omnibox = api::omnibox;
40 namespace SendSuggestions = omnibox::SendSuggestions;
41 namespace SetDefaultSuggestion = omnibox::SetDefaultSuggestion;
42
38 namespace { 43 namespace {
39 44
40 const char kSuggestionContent[] = "content"; 45 const char kSuggestionContent[] = "content";
41 const char kSuggestionDescription[] = "description"; 46 const char kSuggestionDescription[] = "description";
42 const char kSuggestionDescriptionStyles[] = "descriptionStyles"; 47 const char kSuggestionDescriptionStyles[] = "descriptionStyles";
43 const char kSuggestionDescriptionStylesRaw[] = "descriptionStylesRaw"; 48 const char kSuggestionDescriptionStylesRaw[] = "descriptionStylesRaw";
44 const char kDescriptionStylesType[] = "type"; 49 const char kDescriptionStylesType[] = "type";
45 const char kDescriptionStylesOffset[] = "offset"; 50 const char kDescriptionStylesOffset[] = "offset";
46 const char kDescriptionStylesLength[] = "length"; 51 const char kDescriptionStylesLength[] = "length";
47 const char kCurrentTabDisposition[] = "currentTab"; 52 const char kCurrentTabDisposition[] = "currentTab";
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 omnibox_popup_icon_manager_.GetIcon(extension_id)); 234 omnibox_popup_icon_manager_.GetIcon(extension_id));
230 } 235 }
231 236
232 template <> 237 template <>
233 void ProfileKeyedAPIFactory<OmniboxAPI>::DeclareFactoryDependencies() { 238 void ProfileKeyedAPIFactory<OmniboxAPI>::DeclareFactoryDependencies() {
234 DependsOn(ExtensionSystemFactory::GetInstance()); 239 DependsOn(ExtensionSystemFactory::GetInstance());
235 DependsOn(TemplateURLServiceFactory::GetInstance()); 240 DependsOn(TemplateURLServiceFactory::GetInstance());
236 } 241 }
237 242
238 bool OmniboxSendSuggestionsFunction::RunImpl() { 243 bool OmniboxSendSuggestionsFunction::RunImpl() {
239 ExtensionOmniboxSuggestions suggestions; 244 scoped_ptr<SendSuggestions::Params> params(
240 ListValue* suggestions_value; 245 SendSuggestions::Params::Create(*args_));
241 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &suggestions.request_id)); 246 EXTENSION_FUNCTION_VALIDATE(params);
242 EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &suggestions_value));
243
244 suggestions.suggestions.resize(suggestions_value->GetSize());
245 for (size_t i = 0; i < suggestions_value->GetSize(); ++i) {
246 ExtensionOmniboxSuggestion& suggestion = suggestions.suggestions[i];
247 DictionaryValue* suggestion_value;
248 EXTENSION_FUNCTION_VALIDATE(suggestions_value->GetDictionary(
249 i, &suggestion_value));
250 EXTENSION_FUNCTION_VALIDATE(suggestion.Populate(*suggestion_value, true));
251 }
252 247
253 content::NotificationService::current()->Notify( 248 content::NotificationService::current()->Notify(
254 chrome::NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY, 249 chrome::NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY,
255 content::Source<Profile>(profile_->GetOriginalProfile()), 250 content::Source<Profile>(profile_->GetOriginalProfile()),
256 content::Details<ExtensionOmniboxSuggestions>(&suggestions)); 251 content::Details<SendSuggestions::Params>(params.get()));
257 252
258 return true; 253 return true;
259 } 254 }
260 255
261 bool OmniboxSetDefaultSuggestionFunction::RunImpl() { 256 bool OmniboxSetDefaultSuggestionFunction::RunImpl() {
262 ExtensionOmniboxSuggestion suggestion; 257 scoped_ptr<SetDefaultSuggestion::Params> params(
263 DictionaryValue* suggestion_value; 258 SetDefaultSuggestion::Params::Create(*args_));
264 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &suggestion_value)); 259 EXTENSION_FUNCTION_VALIDATE(params);
265 EXTENSION_FUNCTION_VALIDATE(suggestion.Populate(*suggestion_value, false));
266 260
267 ExtensionPrefs* prefs = 261 ExtensionPrefs* prefs =
268 ExtensionSystem::Get(profile())->extension_service()->extension_prefs(); 262 ExtensionSystem::Get(profile())->extension_service()->extension_prefs();
269 if (prefs) 263 if (prefs)
270 prefs->SetOmniboxDefaultSuggestion(extension_id(), suggestion); 264 prefs->SetOmniboxDefaultSuggestion(extension_id(), params->suggestion);
271 265
272 content::NotificationService::current()->Notify( 266 content::NotificationService::current()->Notify(
273 chrome::NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED, 267 chrome::NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED,
274 content::Source<Profile>(profile_->GetOriginalProfile()), 268 content::Source<Profile>(profile_->GetOriginalProfile()),
275 content::NotificationService::NoDetails()); 269 content::NotificationService::NoDetails());
276 270
277 return true; 271 return true;
278 } 272 }
279 273
280 ExtensionOmniboxSuggestion::ExtensionOmniboxSuggestion() {} 274 // This function converts style information populated by the JSON schema
275 // compiler into an ACMatchClassifications object.
276 ACMatchClassifications StyleTypesToACMatchClassifications(
277 const omnibox::SuggestResult &suggestion) {
278 ACMatchClassifications match_classifications;
279 if (suggestion.description_styles) {
280 string16 description = UTF8ToUTF16(suggestion.description);
281 std::vector<int> styles(description.length(), 0);
281 282
282 ExtensionOmniboxSuggestion::~ExtensionOmniboxSuggestion() {} 283 for (std::vector<linked_ptr<omnibox::SuggestResult::DescriptionStylesType> >
284 ::iterator i = suggestion.description_styles->begin();
285 i != suggestion.description_styles->end(); ++i) {
286 omnibox::SuggestResult::DescriptionStylesType* style = i->get();
283 287
284 bool ExtensionOmniboxSuggestion::Populate(const base::DictionaryValue& value, 288 int length = description.length();
285 bool require_content) { 289 if (style->length)
286 if (!value.GetString(kSuggestionContent, &content) && require_content) 290 length = *style->length;
287 return false;
288 291
289 if (!value.GetString(kSuggestionDescription, &description)) 292 size_t offset = style->offset >= 0 ? style->offset :
290 return false; 293 std::max(0, static_cast<int>(description.length()) + style->offset);
291 294
292 description_styles.clear(); 295 int type_class;
293 if (value.HasKey(kSuggestionDescriptionStyles)) { 296 switch (style->type) {
294 // This version comes from the extension. 297 case omnibox::SuggestResult::DescriptionStylesType::TYPE_URL:
295 const ListValue* styles = NULL; 298 type_class = AutocompleteMatch::ACMatchClassification::URL;
296 if (!value.GetList(kSuggestionDescriptionStyles, &styles) || 299 break;
297 !ReadStylesFromValue(*styles)) { 300 case omnibox::SuggestResult::DescriptionStylesType::TYPE_MATCH:
298 return false; 301 type_class = AutocompleteMatch::ACMatchClassification::MATCH;
302 break;
303 case omnibox::SuggestResult::DescriptionStylesType::TYPE_DIM:
304 type_class = AutocompleteMatch::ACMatchClassification::DIM;
305 break;
306 default:
307 type_class = AutocompleteMatch::ACMatchClassification::NONE;
308 return match_classifications;
309 }
310
311 for (size_t j = offset; j < offset + length && j < styles.size(); ++j)
312 styles[j] |= type_class;
299 } 313 }
300 } else if (value.HasKey(kSuggestionDescriptionStylesRaw)) { 314
301 // This version comes from ToValue(), which we use to persist to disk. 315 for (size_t i = 0; i < styles.size(); ++i) {
302 const ListValue* styles = NULL; 316 if (i == 0 || styles[i] != styles[i-1])
303 if (!value.GetList(kSuggestionDescriptionStylesRaw, &styles) || 317 match_classifications.push_back(
304 styles->empty()) { 318 ACMatchClassification(i, styles[i]));
305 return false;
306 }
307 for (size_t i = 0; i < styles->GetSize(); ++i) {
308 const base::DictionaryValue* style = NULL;
309 int offset, type;
310 if (!styles->GetDictionary(i, &style))
311 return false;
312 if (!style->GetInteger(kDescriptionStylesType, &type))
313 return false;
314 if (!style->GetInteger(kDescriptionStylesOffset, &offset))
315 return false;
316 description_styles.push_back(ACMatchClassification(offset, type));
317 } 319 }
318 } else { 320 } else {
319 description_styles.push_back( 321 match_classifications.push_back(
320 ACMatchClassification(0, ACMatchClassification::NONE)); 322 ACMatchClassification(0, ACMatchClassification::NONE));
321 } 323 }
322 324
323 return true; 325 return match_classifications;
324 } 326 }
325 327
326 bool ExtensionOmniboxSuggestion::ReadStylesFromValue(
327 const ListValue& styles_value) {
328 description_styles.clear();
329
330 // Step 1: Build a vector of styles, 1 per character of description text.
331 std::vector<int> styles;
332 styles.resize(description.length()); // sets all styles to 0
333
334 for (size_t i = 0; i < styles_value.GetSize(); ++i) {
335 const DictionaryValue* style;
336 std::string type;
337 int offset;
338 int length;
339 if (!styles_value.GetDictionary(i, &style))
340 return false;
341 if (!style->GetString(kDescriptionStylesType, &type))
342 return false;
343 if (!style->GetInteger(kDescriptionStylesOffset, &offset))
344 return false;
345 if (!style->GetInteger(kDescriptionStylesLength, &length) || length < 0)
346 length = description.length();
347
348 if (offset < 0)
349 offset = std::max(0, static_cast<int>(description.length()) + offset);
350
351 int type_class =
352 (type == "url") ? ACMatchClassification::URL :
353 (type == "match") ? ACMatchClassification::MATCH :
354 (type == "dim") ? ACMatchClassification::DIM : -1;
355 if (type_class == -1)
356 return false;
357
358 for (int j = offset;
359 j < offset + length && j < static_cast<int>(styles.size()); ++j)
360 styles[j] |= type_class;
361 }
362
363 // Step 2: Convert the vector into continuous runs of common styles.
364 for (size_t i = 0; i < styles.size(); ++i) {
365 if (i == 0 || styles[i] != styles[i-1])
366 description_styles.push_back(ACMatchClassification(i, styles[i]));
367 }
368
369 return true;
370 }
371
372 scoped_ptr<base::DictionaryValue> ExtensionOmniboxSuggestion::ToValue() const {
373 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
374
375 value->SetString(kSuggestionContent, content);
376 value->SetString(kSuggestionDescription, description);
377
378 if (description_styles.size() > 0) {
379 base::ListValue* styles_value = new base::ListValue();
380 for (size_t i = 0; i < description_styles.size(); ++i) {
381 base::DictionaryValue* style = new base::DictionaryValue();
382 style->SetInteger(kDescriptionStylesOffset, description_styles[i].offset);
383 style->SetInteger(kDescriptionStylesType, description_styles[i].style);
384 styles_value->Append(style);
385 }
386
387 value->Set(kSuggestionDescriptionStylesRaw, styles_value);
388 }
389
390 return value.Pass();
391 }
392
393 ExtensionOmniboxSuggestions::ExtensionOmniboxSuggestions() : request_id(0) {}
394
395 ExtensionOmniboxSuggestions::~ExtensionOmniboxSuggestions() {}
396
397 void ApplyDefaultSuggestionForExtensionKeyword( 328 void ApplyDefaultSuggestionForExtensionKeyword(
398 Profile* profile, 329 Profile* profile,
399 const TemplateURL* keyword, 330 const TemplateURL* keyword,
400 const string16& remaining_input, 331 const string16& remaining_input,
401 AutocompleteMatch* match) { 332 AutocompleteMatch* match) {
402 DCHECK(keyword->IsExtensionKeyword()); 333 DCHECK(keyword->IsExtensionKeyword());
403 334
404 ExtensionPrefs* prefs = 335 ExtensionPrefs* prefs =
405 ExtensionSystem::Get(profile)->extension_service()->extension_prefs(); 336 ExtensionSystem::Get(profile)->extension_service()->extension_prefs();
406 if (!prefs) 337 if (!prefs)
407 return; 338 return;
408 339
409 ExtensionOmniboxSuggestion suggestion = 340 scoped_ptr<omnibox::SuggestResult> suggestion(
410 prefs->GetOmniboxDefaultSuggestion(keyword->GetExtensionId()); 341 prefs->GetOmniboxDefaultSuggestion(keyword->GetExtensionId()));
411 if (suggestion.description.empty()) 342 if (!suggestion || suggestion->description.empty())
412 return; // fall back to the universal default 343 return; // fall back to the universal default
413 344
414 const string16 kPlaceholderText(ASCIIToUTF16("%s")); 345 const string16 kPlaceholderText(ASCIIToUTF16("%s"));
415 const string16 kReplacementText(ASCIIToUTF16("<input>")); 346 const string16 kReplacementText(ASCIIToUTF16("<input>"));
416 347
417 string16 description = suggestion.description; 348 string16 description = UTF8ToUTF16(suggestion->description);
418 ACMatchClassifications& description_styles = match->contents_class; 349 ACMatchClassifications& description_styles = match->contents_class;
419 description_styles = suggestion.description_styles; 350 description_styles = StyleTypesToACMatchClassifications(*suggestion);
420 351
421 // Replace "%s" with the user's input and adjust the style offsets to the 352 // Replace "%s" with the user's input and adjust the style offsets to the
422 // new length of the description. 353 // new length of the description.
423 size_t placeholder(suggestion.description.find(kPlaceholderText, 0)); 354 size_t placeholder(description.find(kPlaceholderText, 0));
424 if (placeholder != string16::npos) { 355 if (placeholder != string16::npos) {
425 string16 replacement = 356 string16 replacement =
426 remaining_input.empty() ? kReplacementText : remaining_input; 357 remaining_input.empty() ? kReplacementText : remaining_input;
427 description.replace(placeholder, kPlaceholderText.length(), replacement); 358 description.replace(placeholder, kPlaceholderText.length(), replacement);
428 359
429 for (size_t i = 0; i < description_styles.size(); ++i) { 360 for (size_t i = 0; i < description_styles.size(); ++i) {
430 if (description_styles[i].offset > placeholder) 361 if (description_styles[i].offset > placeholder)
431 description_styles[i].offset += replacement.length() - 2; 362 description_styles[i].offset += replacement.length() - 2;
432 } 363 }
433 } 364 }
434 365
435 match->contents.assign(description); 366 match->contents.assign(description);
436 } 367 }
437 368
438 } // namespace extensions 369 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/omnibox/omnibox_api.h ('k') | chrome/browser/extensions/api/omnibox/omnibox_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698