OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/tab_contents/introducer_handler.h" |
| 6 |
| 7 #include "chrome/app/chrome_command_ids.h" |
| 8 #include "chrome/browser/prefs/pref_service.h" |
| 9 #include "chrome/browser/profiles/profile.h" |
| 10 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h" |
| 11 #include "chrome/browser/tabs/tab_strip_model.h" |
| 12 #include "chrome/browser/ui/browser.h" |
| 13 #include "chrome/browser/ui/browser_list.h" |
| 14 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 15 #include "chrome/common/pref_names.h" |
| 16 #include "content/browser/tab_contents/tab_contents.h" |
| 17 #include "content/browser/renderer_host/render_process_host.h" |
| 18 #include "content/browser/renderer_host/render_view_host.h" |
| 19 #include "content/browser/tab_contents/tab_contents_observer.h" |
| 20 #include "content/browser/worker_host/message_port_service.h" |
| 21 #include "content/common/introducer_messages.h" |
| 22 #include "grit/generated_resources.h" |
| 23 #include "net/base/data_url.h" |
| 24 #include "ui/base/l10n/l10n_util.h" |
| 25 #include "ui/base/models/simple_menu_model.h" |
| 26 #include "ui/gfx/favicon_size.h" |
| 27 #include "webkit/glue/context_menu.h" |
| 28 #include "webkit/glue/image_decoder.h" |
| 29 |
| 30 static SkBitmap ImageFromDataUrl(const GURL& icon) { |
| 31 std::string mime_type, charset, data; |
| 32 if (!net::DataURL::Parse(icon, &mime_type, &charset, &data)) { |
| 33 return SkBitmap(); |
| 34 } |
| 35 webkit_glue::ImageDecoder decoder(gfx::Size(kFaviconSize, kFaviconSize)); |
| 36 return decoder.Decode(reinterpret_cast<const unsigned char*>(data.data()), |
| 37 data.size()); |
| 38 } |
| 39 |
| 40 static void InstallReturn(TabContents* tab, int request_id, bool accepted) { |
| 41 RenderViewHost* host = tab->render_view_host(); |
| 42 if (host) { |
| 43 host->Send(new IntroducerMsg_InstallReturn(host->routing_id(), |
| 44 request_id, accepted)); |
| 45 } |
| 46 } |
| 47 |
| 48 static bool UpdateRegistration(TabContents* tab, |
| 49 const std::string& registrant, const GURL& icon, |
| 50 const string16& name, const GURL& home) { |
| 51 Profile* profile = tab->profile(); |
| 52 PrefService* prefs = profile->IsOffTheRecord() ? |
| 53 profile->GetOffTheRecordPrefs() : profile->GetPrefs(); |
| 54 DictionaryValue* registrations = |
| 55 prefs->GetMutableDictionary(prefs::kIntroducerRegistrations); |
| 56 if (!registrations) { return false; } |
| 57 DictionaryValue* registration = NULL; |
| 58 if (!registrations->GetDictionaryWithoutPathExpansion(registrant, |
| 59 ®istration)) { |
| 60 registration = new DictionaryValue(); |
| 61 registrations->SetWithoutPathExpansion(registrant, registration); |
| 62 } |
| 63 registration->SetString("icon", icon.spec()); |
| 64 registration->SetString("name", name); |
| 65 registration->SetString("home", home.spec()); |
| 66 if (!profile->IsOffTheRecord()) { |
| 67 prefs->ScheduleSavePersistentPrefs(); |
| 68 } |
| 69 return true; |
| 70 } |
| 71 |
| 72 class InstallInfoBar : public ConfirmInfoBarDelegate { |
| 73 public: |
| 74 InstallInfoBar( |
| 75 TabContents* tab, |
| 76 int request_id, |
| 77 const std::string& registrant, |
| 78 const GURL& icon, |
| 79 const string16& name, |
| 80 const GURL& home) : |
| 81 ConfirmInfoBarDelegate(tab), |
| 82 tab_(tab), |
| 83 request_id_(request_id), |
| 84 registrant_(registrant), |
| 85 icon_(icon), |
| 86 name_(name), |
| 87 home_(home), |
| 88 decoded_icon_(ImageFromDataUrl(icon)) {} |
| 89 |
| 90 virtual void InfoBarClosed() { delete this; } |
| 91 virtual SkBitmap* GetIcon() const { |
| 92 return const_cast<SkBitmap*>(&decoded_icon_); |
| 93 } |
| 94 virtual string16 GetMessageText() const { |
| 95 return l10n_util::GetStringFUTF16(IDS_INTRODUCER_INSTALL_QUESTION, name_); |
| 96 } |
| 97 virtual bool Accept() { |
| 98 if (!UpdateRegistration(tab_, registrant_, icon_, name_, home_)) { |
| 99 return false; |
| 100 } |
| 101 InstallReturn(tab_, request_id_, true); |
| 102 return true; |
| 103 } |
| 104 virtual bool Cancel() { |
| 105 InstallReturn(tab_, request_id_, false); |
| 106 return true; |
| 107 } |
| 108 |
| 109 private: |
| 110 TabContents* tab_; |
| 111 const int request_id_; |
| 112 const std::string registrant_; |
| 113 const GURL icon_; |
| 114 const string16 name_; |
| 115 const GURL home_; |
| 116 SkBitmap decoded_icon_; |
| 117 |
| 118 DISALLOW_COPY_AND_ASSIGN(InstallInfoBar); |
| 119 }; |
| 120 |
| 121 struct AcceptContext { |
| 122 webkit_glue::IntroductionContext introduction; |
| 123 std::string expected_registrant; |
| 124 int customer_render_process_id; |
| 125 int customer_render_view_id; |
| 126 scoped_ptr<IPC::Message> connect_return; |
| 127 |
| 128 AcceptContext() : customer_render_process_id(0), |
| 129 customer_render_view_id(0) {} |
| 130 }; |
| 131 |
| 132 class IntroducerHandler : public TabContentsObserver { |
| 133 public: |
| 134 explicit IntroducerHandler(TabContents* tab) : TabContentsObserver(tab) {} |
| 135 virtual ~IntroducerHandler() {} |
| 136 |
| 137 virtual bool OnMessageReceived(const IPC::Message& message) { |
| 138 bool handled = true; |
| 139 |
| 140 IPC_BEGIN_MESSAGE_MAP(IntroducerHandler, message) |
| 141 IPC_MESSAGE_HANDLER(IntroducerHostMsg_Install, OnInstall) |
| 142 IPC_MESSAGE_HANDLER(IntroducerHostMsg_Uninstall, OnUninstall) |
| 143 IPC_MESSAGE_HANDLER(IntroducerHostMsg_Offer, OnOffer) |
| 144 IPC_MESSAGE_HANDLER(IntroducerHostMsg_Rescind, OnRescind) |
| 145 IPC_MESSAGE_HANDLER(IntroducerHostMsg_Connect, OnConnect) |
| 146 IPC_MESSAGE_HANDLER(IntroducerHostMsg_Accept, OnAccept) |
| 147 IPC_MESSAGE_UNHANDLED(handled = false) |
| 148 IPC_END_MESSAGE_MAP() |
| 149 |
| 150 return handled; |
| 151 } |
| 152 |
| 153 private: |
| 154 |
| 155 void OnInstall(const IPC::Message& message, int request_id, |
| 156 const std::string& registrant, const GURL& icon, |
| 157 const string16& name, const GURL& home) { |
| 158 TabContents* tab = tab_contents(); |
| 159 Profile* profile = tab->profile(); |
| 160 PrefService* prefs = profile->IsOffTheRecord() ? |
| 161 profile->GetOffTheRecordPrefs() : profile->GetPrefs(); |
| 162 const DictionaryValue* registrations = |
| 163 prefs->GetDictionary(prefs::kIntroducerRegistrations); |
| 164 DictionaryValue* registration = NULL; |
| 165 std::string prior_icon; |
| 166 string16 prior_name; |
| 167 if (!registrations || |
| 168 !registrations->GetDictionaryWithoutPathExpansion(registrant, |
| 169 ®istration) || |
| 170 !registration->GetString("icon", &prior_icon) || |
| 171 prior_icon != icon.spec() || |
| 172 !registration->GetString("name", &prior_name) || |
| 173 prior_name != name) { |
| 174 tab->AddInfoBar(new InstallInfoBar(tab, request_id, |
| 175 registrant, icon, name, home)); |
| 176 } else { |
| 177 InstallReturn(tab, request_id, |
| 178 UpdateRegistration(tab, registrant, icon, name, home)); |
| 179 } |
| 180 } |
| 181 |
| 182 void OnUninstall(const IPC::Message& message, int request_id, |
| 183 const std::string& registrant) { |
| 184 TabContents* tab = tab_contents(); |
| 185 Profile* profile = tab->profile(); |
| 186 PrefService* prefs = profile->IsOffTheRecord() ? |
| 187 profile->GetOffTheRecordPrefs() : profile->GetPrefs(); |
| 188 DictionaryValue* registrations = |
| 189 prefs->GetMutableDictionary(prefs::kIntroducerRegistrations); |
| 190 if (registrations) { |
| 191 registrations->RemoveWithoutPathExpansion(registrant, NULL); |
| 192 } |
| 193 InstallReturn(tab, request_id, true); |
| 194 } |
| 195 |
| 196 void OnOffer(const IPC::Message& message, int request_id, |
| 197 const std::string& registrant, |
| 198 IntroducerHostMsg_Offer_Params args) { |
| 199 TabContents* tab = tab_contents(); |
| 200 Profile* profile = tab->profile(); |
| 201 PrefService* prefs = profile->IsOffTheRecord() ? |
| 202 profile->GetOffTheRecordPrefs() : profile->GetPrefs(); |
| 203 DictionaryValue* registrations = |
| 204 prefs->GetMutableDictionary(prefs::kIntroducerRegistrations); |
| 205 DictionaryValue* registration = NULL; |
| 206 const bool agreed = registrations && registrations-> |
| 207 GetDictionaryWithoutPathExpansion(registrant, ®istration); |
| 208 if (agreed) { |
| 209 DictionaryValue* services = NULL; |
| 210 if (!registration->GetDictionary("services", &services)) { |
| 211 services = new DictionaryValue(); |
| 212 registration->Set("services", services); |
| 213 } |
| 214 DictionaryValue* service = new DictionaryValue(); |
| 215 service->SetString("label", args.label); |
| 216 DictionaryValue* supports = new DictionaryValue(); |
| 217 for (std::vector<std::string>::iterator i = args.supports.begin(), |
| 218 end = args.supports.end(); |
| 219 i != end; ++i) { |
| 220 supports->SetWithoutPathExpansion(*i, Value::CreateNullValue()); |
| 221 } |
| 222 service->Set("supports", supports); |
| 223 if (!args.window.is_empty()) { |
| 224 service->SetString("window", args.window.spec()); |
| 225 } |
| 226 if (!args.frame.is_empty()) { |
| 227 service->SetString("frame", args.frame.spec()); |
| 228 } |
| 229 int hits = 0; |
| 230 DictionaryValue* prior = NULL; |
| 231 if (services->GetDictionaryWithoutPathExpansion(args.id, &prior)) { |
| 232 prior->GetInteger("hits", &hits); |
| 233 } |
| 234 service->SetInteger("hits", hits); |
| 235 services->SetWithoutPathExpansion(args.id, service); |
| 236 if (!profile->IsOffTheRecord()) { |
| 237 prefs->ScheduleSavePersistentPrefs(); |
| 238 } |
| 239 } |
| 240 InstallReturn(tab, request_id, agreed); |
| 241 } |
| 242 |
| 243 void OnRescind(const IPC::Message& message, int request_id, |
| 244 const std::string& registrant, const std::string& id) { |
| 245 TabContents* tab = tab_contents(); |
| 246 Profile* profile = tab->profile(); |
| 247 PrefService* prefs = profile->IsOffTheRecord() ? |
| 248 profile->GetOffTheRecordPrefs() : profile->GetPrefs(); |
| 249 DictionaryValue* registrations = |
| 250 prefs->GetMutableDictionary(prefs::kIntroducerRegistrations); |
| 251 DictionaryValue* registration = NULL; |
| 252 if (registrations && registrations-> |
| 253 GetDictionaryWithoutPathExpansion(registrant, ®istration)) { |
| 254 DictionaryValue* services = NULL; |
| 255 if (registration->GetDictionary("services", &services)) { |
| 256 if (services->RemoveWithoutPathExpansion(id, NULL)) { |
| 257 if (!profile->IsOffTheRecord()) { |
| 258 prefs->ScheduleSavePersistentPrefs(); |
| 259 } |
| 260 } |
| 261 } |
| 262 } |
| 263 InstallReturn(tab, request_id, true); |
| 264 } |
| 265 |
| 266 void OnConnect(const IPC::Message& message, int request_id, |
| 267 const std::string& customer, |
| 268 int64 frame_id, |
| 269 const std::vector<std::string>& wanted, |
| 270 int port_id) { |
| 271 ContextMenuParams params; |
| 272 params.introduction_context.request_id = request_id; |
| 273 params.introduction_context.customer = customer; |
| 274 params.introduction_context.frame_id = frame_id; |
| 275 params.introduction_context.wanted = wanted; |
| 276 params.introduction_context.port_id = port_id; |
| 277 RenderViewHostDelegate::View* view = |
| 278 tab_contents()->render_view_host()->delegate()->GetViewDelegate(); |
| 279 if (view) { |
| 280 view->ShowContextMenu(params); |
| 281 } else { |
| 282 IntroducerService::Dismiss(tab_contents(), request_id); |
| 283 } |
| 284 } |
| 285 |
| 286 void OnAccept(const IPC::Message& message, int request_id, int64 src, |
| 287 const std::string& registrant, int port_id) { |
| 288 scoped_ptr<AcceptContext> accept_context(pending_[src]); |
| 289 pending_.erase(src); |
| 290 RenderViewHost* service_host = tab_contents()->render_view_host(); |
| 291 if (accept_context.get()) { |
| 292 RenderViewHost* customer_host = RenderViewHost::FromID( |
| 293 accept_context->customer_render_process_id, |
| 294 accept_context->customer_render_view_id); |
| 295 if (accept_context->expected_registrant == registrant) { |
| 296 MessagePortService* ports = MessagePortService::GetInstance(); |
| 297 ports->Entangle(port_id, accept_context->introduction.port_id); |
| 298 ports->Entangle(accept_context->introduction.port_id, port_id); |
| 299 service_host->Send(new IntroducerMsg_AcceptReturn( |
| 300 service_host->routing_id(), request_id, |
| 301 accept_context->introduction.customer, |
| 302 accept_context->introduction.wanted)); |
| 303 if (customer_host) { |
| 304 customer_host->Send(accept_context->connect_return.release()); |
| 305 } |
| 306 } else { |
| 307 service_host->Send(new IntroducerMsg_AcceptReturn( |
| 308 service_host->routing_id(), request_id, |
| 309 "", std::vector<std::string>())); |
| 310 if (customer_host) { |
| 311 customer_host->Send(new IntroducerMsg_ConnectReturn( |
| 312 customer_host->routing_id(), |
| 313 accept_context->introduction.request_id, |
| 314 std::vector<std::string>())); |
| 315 } |
| 316 } |
| 317 } else { |
| 318 service_host->Send(new IntroducerMsg_AcceptReturn( |
| 319 service_host->routing_id(), request_id, |
| 320 "", std::vector<std::string>())); |
| 321 } |
| 322 } |
| 323 |
| 324 private: |
| 325 friend class IntroducerService; |
| 326 std::map<int64,AcceptContext*> pending_; |
| 327 |
| 328 DISALLOW_COPY_AND_ASSIGN(IntroducerHandler); |
| 329 }; |
| 330 |
| 331 // static |
| 332 TabContentsObserver* IntroducerService::Make(TabContents* tab) { |
| 333 return new IntroducerHandler(tab); |
| 334 } |
| 335 |
| 336 // static |
| 337 void IntroducerService::RegisterUserPrefs(PrefService* user_prefs) { |
| 338 if (!user_prefs->FindPreference(prefs::kIntroducerRegistrations)) { |
| 339 user_prefs->RegisterDictionaryPref(prefs::kIntroducerRegistrations); |
| 340 } |
| 341 } |
| 342 |
| 343 // static |
| 344 bool IntroducerService::InitMenu( |
| 345 TabContents* tab, Profile* profile, |
| 346 const ContextMenuParams& params, |
| 347 std::map< int, std::pair<std::string,std::string> >* commands, |
| 348 ui::SimpleMenuModel* menu) { |
| 349 const std::vector<std::string>& wanted = params.introduction_context.wanted; |
| 350 if (!wanted.empty()) { |
| 351 PrefService* prefs = profile->IsOffTheRecord() ? |
| 352 profile->GetOffTheRecordPrefs() : profile->GetPrefs(); |
| 353 const DictionaryValue* registrations = |
| 354 prefs->GetDictionary(prefs::kIntroducerRegistrations); |
| 355 if (registrations) { |
| 356 int command_id = IDC_INTRODUCER_CONTEXT_CUSTOM_FIRST; |
| 357 std::vector<int> priority; |
| 358 for (DictionaryValue::key_iterator i = registrations->begin_keys(), |
| 359 i_last = registrations->end_keys(); |
| 360 command_id < IDC_INTRODUCER_CONTEXT_CUSTOM_LAST && i != i_last; ++i) { |
| 361 DictionaryValue* registration = NULL; |
| 362 if (registrations->GetDictionaryWithoutPathExpansion(*i, |
| 363 ®istration)) { |
| 364 SkBitmap icon; |
| 365 DictionaryValue* services = NULL; |
| 366 if (registration->GetDictionary("services", &services)) { |
| 367 for (DictionaryValue::key_iterator j = services->begin_keys(), |
| 368 j_last = services->end_keys(); |
| 369 command_id < IDC_INTRODUCER_CONTEXT_CUSTOM_LAST && j != j_last; |
| 370 ++j) { |
| 371 DictionaryValue* service = NULL; |
| 372 if (services->GetDictionaryWithoutPathExpansion(*j, &service)) { |
| 373 if (service->HasKey("window") || |
| 374 (params.introduction_context.frame_id && |
| 375 service->HasKey("frame"))) { |
| 376 DictionaryValue* supports = NULL; |
| 377 if (service->GetDictionary("supports", &supports)) { |
| 378 for (std::vector<std::string>::const_iterator |
| 379 k = wanted.begin(), |
| 380 k_last = wanted.end(); k != k_last; ++k) { |
| 381 if (supports->HasKey(*k)) { |
| 382 int hits = 0; |
| 383 service->GetInteger("hits", &hits); |
| 384 int index = menu->GetItemCount(); |
| 385 std::vector<int>::iterator l_first = priority.begin(), |
| 386 l = priority.end(); |
| 387 for (; l != l_first; --l, --index) { |
| 388 if (*(l - 1) >= hits) { |
| 389 break; |
| 390 } |
| 391 } |
| 392 priority.insert(l, hits); |
| 393 string16 label; |
| 394 service->GetString("label", &label); |
| 395 menu->InsertItemAt(index, command_id, label); |
| 396 if (icon.isNull()) { |
| 397 std::string icon_url; |
| 398 if (registration->GetString("icon", &icon_url)) { |
| 399 icon = ImageFromDataUrl(GURL(icon_url)); |
| 400 } |
| 401 } |
| 402 menu->SetIcon(index, icon); |
| 403 (*commands)[command_id] = std::make_pair(*i, *j); |
| 404 command_id += 1; |
| 405 break; |
| 406 } |
| 407 } |
| 408 } |
| 409 } |
| 410 } |
| 411 } |
| 412 } |
| 413 } |
| 414 } |
| 415 } |
| 416 } |
| 417 return 0 != params.introduction_context.request_id; |
| 418 } |
| 419 |
| 420 // static |
| 421 bool IntroducerService::Introduce( |
| 422 TabContents* tab, Profile* profile, const ContextMenuParams& params, |
| 423 const std::pair<std::string,std::string>& selection) { |
| 424 PrefService* prefs = profile->IsOffTheRecord() ? |
| 425 profile->GetOffTheRecordPrefs() : profile->GetPrefs(); |
| 426 DictionaryValue* registrations = |
| 427 prefs->GetMutableDictionary(prefs::kIntroducerRegistrations); |
| 428 DictionaryValue* registration = NULL; |
| 429 DictionaryValue* services = NULL; |
| 430 DictionaryValue* service = NULL; |
| 431 if (!registrations || |
| 432 !registrations->GetDictionaryWithoutPathExpansion(selection.first, |
| 433 ®istration) || |
| 434 !registration->GetDictionary("services", &services) || |
| 435 !services->GetDictionaryWithoutPathExpansion(selection.second, |
| 436 &service)) { |
| 437 return false; |
| 438 } |
| 439 int hits = 0; |
| 440 service->GetInteger("hits", &hits); |
| 441 service->SetInteger("hits", hits + 1); |
| 442 std::vector<std::string> agreed; |
| 443 const std::vector<std::string>& wanted = params.introduction_context.wanted; |
| 444 DictionaryValue* supports = NULL; |
| 445 if (service->GetDictionary("supports", &supports)) { |
| 446 for (std::vector<std::string>::const_iterator i = wanted.begin(), |
| 447 i_last = wanted.end(); |
| 448 i != i_last; ++i) { |
| 449 if (supports->HasKey(*i)) { |
| 450 agreed.push_back(*i); |
| 451 } |
| 452 } |
| 453 } |
| 454 if (!profile->IsOffTheRecord()) { |
| 455 prefs->ScheduleSavePersistentPrefs(); |
| 456 } |
| 457 |
| 458 RenderViewHost* host = tab->render_view_host(); |
| 459 if (!host) { |
| 460 return false; |
| 461 } |
| 462 scoped_ptr<AcceptContext> accept_context(new AcceptContext()); |
| 463 accept_context->introduction = params.introduction_context; |
| 464 accept_context->expected_registrant = selection.first; |
| 465 accept_context->customer_render_process_id = host->process()->id(); |
| 466 accept_context->customer_render_view_id = host->routing_id(); |
| 467 accept_context->connect_return.reset(new IntroducerMsg_ConnectReturn( |
| 468 host->routing_id(), params.introduction_context.request_id, agreed)); |
| 469 |
| 470 std::string frame; |
| 471 if (params.introduction_context.frame_id && |
| 472 service->GetString("frame", &frame)) { |
| 473 IntroducerHandler* handler = |
| 474 static_cast<IntroducerHandler*>(tab->introducer_handler_.get()); |
| 475 handler->pending_[params.introduction_context.frame_id] = |
| 476 accept_context.release(); |
| 477 host->Send(new IntroducerMsg_ConnectNavigation( |
| 478 host->routing_id(), params.introduction_context.request_id, GURL(frame))); |
| 479 return true; |
| 480 } |
| 481 |
| 482 std::string window; |
| 483 if (service->GetString("window", &window)) { |
| 484 Browser* browser = BrowserList::GetLastActive(); |
| 485 if (browser) { |
| 486 TabContentsWrapper* service_tab = browser->CreateTabContentsForURL( |
| 487 GURL(window), GURL(), profile, PageTransition::LINK, false, NULL); |
| 488 browser->tabstrip_model()->AppendTabContents(service_tab, true); |
| 489 IntroducerHandler* handler = static_cast<IntroducerHandler*>( |
| 490 service_tab->tab_contents()->introducer_handler_.get()); |
| 491 handler->pending_[0] = accept_context.release(); |
| 492 return true; |
| 493 } |
| 494 } |
| 495 |
| 496 return false; |
| 497 } |
| 498 |
| 499 // static |
| 500 void IntroducerService::Dismiss(TabContents* tab, int request_id) { |
| 501 RenderViewHost* host = tab->render_view_host(); |
| 502 if (host) { |
| 503 host->Send(new IntroducerMsg_ConnectReturn(host->routing_id(), request_id, |
| 504 std::vector<std::string>())); |
| 505 } |
| 506 } |
OLD | NEW |