OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 // HACK: we need this #define in place before npapi.h is included for | |
6 // plugins to work. However, all sorts of headers include npapi.h, so | |
7 // the only way to be certain the define is in place is to put it | |
8 // here. You might ask, "Why not set it in npapi.h directly, or in | |
9 // this directory's SConscript, then?" but it turns out this define | |
10 // makes npapi.h include Xlib.h, which in turn defines a ton of symbols | |
11 // like None and Status, causing conflicts with the aforementioned | |
12 // many headers that include npapi.h. Ugh. | |
13 // See also plugin_host.cc. | |
14 #define MOZ_X11 1 | |
15 | |
16 #include "webkit/glue/plugins/webplugin_delegate_impl.h" | 5 #include "webkit/glue/plugins/webplugin_delegate_impl.h" |
17 | 6 |
18 #include <string> | 7 #include <string> |
19 #include <vector> | 8 #include <vector> |
20 | 9 |
21 #include <gtk/gtk.h> | 10 #include <gtk/gtk.h> |
22 #include <gdk/gdkx.h> | 11 #include <gdk/gdkx.h> |
23 | 12 |
24 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
25 #include "base/file_util.h" | 14 #include "base/file_util.h" |
26 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
27 #include "base/process_util.h" | 16 #include "base/process_util.h" |
28 #include "base/stats_counters.h" | 17 #include "base/stats_counters.h" |
29 #include "base/string_util.h" | 18 #include "base/string_util.h" |
| 19 #include "webkit/api/public/WebInputEvent.h" |
30 // #include "webkit/default_plugin/plugin_impl.h" | 20 // #include "webkit/default_plugin/plugin_impl.h" |
31 #include "webkit/glue/glue_util.h" | 21 #include "webkit/glue/glue_util.h" |
32 #include "webkit/glue/webplugin.h" | 22 #include "webkit/glue/webplugin.h" |
33 #include "webkit/glue/plugins/plugin_constants_win.h" | 23 #include "webkit/glue/plugins/plugin_constants_win.h" |
34 #include "webkit/glue/plugins/plugin_instance.h" | 24 #include "webkit/glue/plugins/plugin_instance.h" |
35 #include "webkit/glue/plugins/plugin_lib.h" | 25 #include "webkit/glue/plugins/plugin_lib.h" |
36 #include "webkit/glue/plugins/plugin_list.h" | 26 #include "webkit/glue/plugins/plugin_list.h" |
37 #include "webkit/glue/plugins/plugin_stream_url.h" | 27 #include "webkit/glue/plugins/plugin_stream_url.h" |
38 #include "webkit/glue/webkit_glue.h" | 28 #include "webkit/glue/webkit_glue.h" |
| 29 #if defined(OS_LINUX) |
| 30 #include "third_party/npapi/bindings/npapi_x11.h" |
| 31 #endif |
| 32 |
| 33 using WebKit::WebKeyboardEvent; |
| 34 using WebKit::WebInputEvent; |
| 35 using WebKit::WebMouseEvent; |
39 | 36 |
40 WebPluginDelegate* WebPluginDelegate::Create( | 37 WebPluginDelegate* WebPluginDelegate::Create( |
41 const FilePath& filename, | 38 const FilePath& filename, |
42 const std::string& mime_type, | 39 const std::string& mime_type, |
43 gfx::NativeView containing_view) { | 40 gfx::NativeView containing_view) { |
44 scoped_refptr<NPAPI::PluginLib> plugin = | 41 scoped_refptr<NPAPI::PluginLib> plugin = |
45 NPAPI::PluginLib::CreatePluginLib(filename); | 42 NPAPI::PluginLib::CreatePluginLib(filename); |
46 if (plugin.get() == NULL) | 43 if (plugin.get() == NULL) |
47 return NULL; | 44 return NULL; |
48 | 45 |
49 NPError err = plugin->NP_Initialize(); | 46 NPError err = plugin->NP_Initialize(); |
50 if (err != NPERR_NO_ERROR) | 47 if (err != NPERR_NO_ERROR) |
51 return NULL; | 48 return NULL; |
52 | 49 |
53 scoped_refptr<NPAPI::PluginInstance> instance = | 50 scoped_refptr<NPAPI::PluginInstance> instance = |
54 plugin->CreateInstance(mime_type); | 51 plugin->CreateInstance(mime_type); |
55 return new WebPluginDelegateImpl(containing_view, instance.get()); | 52 return new WebPluginDelegateImpl(containing_view, instance.get()); |
56 } | 53 } |
57 | 54 |
58 WebPluginDelegateImpl::WebPluginDelegateImpl( | 55 WebPluginDelegateImpl::WebPluginDelegateImpl( |
59 gfx::NativeView containing_view, | 56 gfx::NativeView containing_view, |
60 NPAPI::PluginInstance *instance) | 57 NPAPI::PluginInstance *instance) |
61 : | 58 : |
62 windowed_handle_(0), | 59 windowed_handle_(0), |
63 windowed_did_set_window_(false), | 60 windowed_did_set_window_(false), |
64 windowless_(false), | 61 windowless_(false), |
65 plugin_(NULL), | 62 plugin_(NULL), |
| 63 windowless_needs_set_window_(true), |
66 instance_(instance), | 64 instance_(instance), |
67 pixmap_(NULL), | 65 pixmap_(NULL), |
| 66 first_event_time_(-1.0), |
68 parent_(containing_view), | 67 parent_(containing_view), |
69 quirks_(0) | 68 quirks_(0) { |
70 { | |
71 memset(&window_, 0, sizeof(window_)); | 69 memset(&window_, 0, sizeof(window_)); |
72 | |
73 } | 70 } |
74 | 71 |
75 WebPluginDelegateImpl::~WebPluginDelegateImpl() { | 72 WebPluginDelegateImpl::~WebPluginDelegateImpl() { |
76 DestroyInstance(); | 73 DestroyInstance(); |
77 | 74 |
78 if (!windowless_) | 75 if (!windowless_) |
79 WindowedDestroyWindow(); | 76 WindowedDestroyWindow(); |
80 | 77 |
81 if (window_.ws_info) { | 78 if (window_.ws_info) { |
82 // We only ever use ws_info as an NPSetWindowCallbackStruct. | 79 // We only ever use ws_info as an NPSetWindowCallbackStruct. |
(...skipping 30 matching lines...) Expand all Loading... |
113 if (!start_result) | 110 if (!start_result) |
114 return false; | 111 return false; |
115 | 112 |
116 windowless_ = instance_->windowless(); | 113 windowless_ = instance_->windowless(); |
117 if (windowless_) { | 114 if (windowless_) { |
118 // For windowless plugins we should set the containing window handle | 115 // For windowless plugins we should set the containing window handle |
119 // as the instance window handle. This is what Safari does. Not having | 116 // as the instance window handle. This is what Safari does. Not having |
120 // a valid window handle causes subtle bugs with plugins which retreive | 117 // a valid window handle causes subtle bugs with plugins which retreive |
121 // the window handle and validate the same. The window handle can be | 118 // the window handle and validate the same. The window handle can be |
122 // retreived via NPN_GetValue of NPNVnetscapeWindow. | 119 // retreived via NPN_GetValue of NPNVnetscapeWindow. |
123 // instance_->set_window_handle(parent_); | 120 instance_->set_window_handle(parent_); |
124 // CreateDummyWindowForActivation(); | 121 // CreateDummyWindowForActivation(); |
125 // handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); | 122 // handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); |
126 } else { | 123 } else { |
127 if (!WindowedCreatePlugin()) | 124 if (!WindowedCreatePlugin()) |
128 return false; | 125 return false; |
129 } | 126 } |
130 | 127 |
131 plugin->SetWindow(windowed_handle_); | 128 plugin->SetWindow(windowed_handle_); |
132 plugin_url_ = url.spec(); | 129 plugin_url_ = url.spec(); |
133 | 130 |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 | 383 |
387 void WebPluginDelegateImpl::WindowedSetWindow() { | 384 void WebPluginDelegateImpl::WindowedSetWindow() { |
388 if (!instance_) | 385 if (!instance_) |
389 return; | 386 return; |
390 | 387 |
391 if (!windowed_handle_) { | 388 if (!windowed_handle_) { |
392 NOTREACHED(); | 389 NOTREACHED(); |
393 return; | 390 return; |
394 } | 391 } |
395 | 392 |
396 // XXX instance()->set_window_handle(windowed_handle_); | 393 instance()->set_window_handle(windowed_handle_); |
397 | 394 |
398 DCHECK(!instance()->windowless()); | 395 DCHECK(!instance()->windowless()); |
399 | 396 |
400 window_.clipRect.top = clip_rect_.y(); | 397 window_.clipRect.top = clip_rect_.y(); |
401 window_.clipRect.left = clip_rect_.x(); | 398 window_.clipRect.left = clip_rect_.x(); |
402 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); | 399 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); |
403 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); | 400 window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); |
404 window_.height = window_rect_.height(); | 401 window_.height = window_rect_.height(); |
405 window_.width = window_rect_.width(); | 402 window_.width = window_rect_.width(); |
406 window_.x = window_rect_.x(); | 403 window_.x = window_rect_.x(); |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 // this background. | 535 // this background. |
539 cairo_t* cairo = gdk_cairo_create(pixmap_); | 536 cairo_t* cairo = gdk_cairo_create(pixmap_); |
540 cairo_set_source_surface(cairo, context, 0, 0); | 537 cairo_set_source_surface(cairo, context, 0, 0); |
541 cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(), | 538 cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(), |
542 draw_rect.width(), draw_rect.height()); | 539 draw_rect.width(), draw_rect.height()); |
543 cairo_clip(cairo); | 540 cairo_clip(cairo); |
544 cairo_paint(cairo); | 541 cairo_paint(cairo); |
545 cairo_destroy(cairo); | 542 cairo_destroy(cairo); |
546 | 543 |
547 // Construct the paint message, targeting the pixmap. | 544 // Construct the paint message, targeting the pixmap. |
548 XGraphicsExposeEvent event = {0}; | 545 NPEvent np_event = {0}; |
| 546 XGraphicsExposeEvent &event = np_event.xgraphicsexpose; |
549 event.type = GraphicsExpose; | 547 event.type = GraphicsExpose; |
550 event.display = GDK_DISPLAY(); | 548 event.display = GDK_DISPLAY(); |
551 event.drawable = GDK_PIXMAP_XID(pixmap_); | 549 event.drawable = GDK_PIXMAP_XID(pixmap_); |
552 event.x = draw_rect.x(); | 550 event.x = draw_rect.x(); |
553 event.y = draw_rect.y(); | 551 event.y = draw_rect.y(); |
554 event.width = draw_rect.width(); | 552 event.width = draw_rect.width(); |
555 event.height = draw_rect.height(); | 553 event.height = draw_rect.height(); |
556 | 554 |
557 // Tell the plugin to paint into the pixmap. | 555 // Tell the plugin to paint into the pixmap. |
558 static StatsRate plugin_paint("Plugin.Paint"); | 556 static StatsRate plugin_paint("Plugin.Paint"); |
559 StatsScope<StatsRate> scope(plugin_paint); | 557 StatsScope<StatsRate> scope(plugin_paint); |
560 NPError err = instance()->NPP_HandleEvent(reinterpret_cast<XEvent*>(&event)); | 558 NPError err = instance()->NPP_HandleEvent(&np_event); |
561 DCHECK_EQ(err, NPERR_NO_ERROR); | 559 DCHECK_EQ(err, NPERR_NO_ERROR); |
562 | 560 |
563 // Now copy the rendered image pixmap back into the drawing buffer. | 561 // Now copy the rendered image pixmap back into the drawing buffer. |
564 cairo = cairo_create(context); | 562 cairo = cairo_create(context); |
565 gdk_cairo_set_source_pixmap(cairo, pixmap_, 0, 0); | 563 gdk_cairo_set_source_pixmap(cairo, pixmap_, 0, 0); |
566 cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(), | 564 cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(), |
567 draw_rect.width(), draw_rect.height()); | 565 draw_rect.width(), draw_rect.height()); |
568 cairo_clip(cairo); | 566 cairo_clip(cairo); |
569 cairo_paint(cairo); | 567 cairo_paint(cairo); |
570 cairo_destroy(cairo); | 568 cairo_destroy(cairo); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 if (!force_set_window) | 612 if (!force_set_window) |
615 windowless_needs_set_window_ = false; | 613 windowless_needs_set_window_ = false; |
616 | 614 |
617 NPError err = instance()->NPP_SetWindow(&window_); | 615 NPError err = instance()->NPP_SetWindow(&window_); |
618 DCHECK(err == NPERR_NO_ERROR); | 616 DCHECK(err == NPERR_NO_ERROR); |
619 } | 617 } |
620 | 618 |
621 void WebPluginDelegateImpl::SetFocus() { | 619 void WebPluginDelegateImpl::SetFocus() { |
622 DCHECK(instance()->windowless()); | 620 DCHECK(instance()->windowless()); |
623 | 621 |
624 NOTIMPLEMENTED(); | 622 NPEvent np_event = {0}; |
625 /* NPEvent focus_event; | 623 XFocusChangeEvent &event = np_event.xfocus; |
626 focus_event.event = WM_SETFOCUS; | 624 event.type = FocusIn; |
627 focus_event.wParam = 0; | 625 event.display = GDK_DISPLAY(); |
628 focus_event.lParam = 0; | 626 // Same values as Firefox. .serial and .window stay 0. |
629 | 627 event.mode = -1; |
630 instance()->NPP_HandleEvent(&focus_event);*/ | 628 event.detail = NotifyDetailNone; |
631 } | 629 instance()->NPP_HandleEvent(&np_event); |
632 | 630 } |
633 bool WebPluginDelegateImpl::HandleEvent(NPEvent* event, | 631 |
634 WebCursor* cursor) { | 632 // Converts a WebInputEvent::Modifiers bitfield into a |
635 bool ret = instance()->NPP_HandleEvent(event) != 0; | 633 // corresponding X modifier state. |
| 634 static int GetXModifierState(int modifiers) { |
| 635 int x_state = 0; |
| 636 if (modifiers & WebInputEvent::ControlKey) |
| 637 x_state |= ControlMask; |
| 638 if (modifiers & WebInputEvent::ShiftKey) |
| 639 x_state |= ShiftMask; |
| 640 if (modifiers & WebInputEvent::AltKey) |
| 641 x_state |= Mod1Mask; |
| 642 if (modifiers & WebInputEvent::MetaKey) |
| 643 x_state |= Mod2Mask; |
| 644 if (modifiers & WebInputEvent::LeftButtonDown) |
| 645 x_state |= Button1Mask; |
| 646 if (modifiers & WebInputEvent::MiddleButtonDown) |
| 647 x_state |= Button2Mask; |
| 648 if (modifiers & WebInputEvent::RightButtonDown) |
| 649 x_state |= Button3Mask; |
| 650 // TODO(piman@google.com): There are other modifiers, e.g. Num Lock, that |
| 651 // should be set (and Firefox does), but we didn't keep the information in |
| 652 // the WebKit event. |
| 653 return x_state; |
| 654 } |
| 655 |
| 656 static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, |
| 657 Time timestamp, |
| 658 NPEvent *np_event) { |
| 659 np_event->xany.display = GDK_DISPLAY(); |
| 660 // NOTE: Firefox keeps xany.serial and xany.window as 0. |
| 661 |
| 662 int modifier_state = GetXModifierState(event.modifiers); |
| 663 |
| 664 Window root = GDK_ROOT_WINDOW(); |
| 665 switch (event.type) { |
| 666 case WebInputEvent::MouseMove: { |
| 667 np_event->type = MotionNotify; |
| 668 XMotionEvent &motion_event = np_event->xmotion; |
| 669 motion_event.root = root; |
| 670 motion_event.time = timestamp; |
| 671 motion_event.x = event.x; |
| 672 motion_event.y = event.y; |
| 673 motion_event.x_root = event.globalX; |
| 674 motion_event.y_root = event.globalY; |
| 675 motion_event.state = modifier_state; |
| 676 motion_event.is_hint = NotifyNormal; |
| 677 motion_event.same_screen = True; |
| 678 break; |
| 679 } |
| 680 case WebInputEvent::MouseLeave: |
| 681 case WebInputEvent::MouseEnter: { |
| 682 if (event.type == WebInputEvent::MouseEnter) { |
| 683 np_event->type = EnterNotify; |
| 684 } else { |
| 685 np_event->type = LeaveNotify; |
| 686 } |
| 687 XCrossingEvent &crossing_event = np_event->xcrossing; |
| 688 crossing_event.root = root; |
| 689 crossing_event.time = timestamp; |
| 690 crossing_event.x = event.x; |
| 691 crossing_event.y = event.y; |
| 692 crossing_event.x_root = event.globalX; |
| 693 crossing_event.y_root = event.globalY; |
| 694 crossing_event.mode = -1; // This is what Firefox sets it to. |
| 695 crossing_event.detail = NotifyDetailNone; |
| 696 crossing_event.same_screen = True; |
| 697 // TODO(piman@google.com): set this to the correct value. Firefox does. I |
| 698 // don't know where to get the information though, we get focus |
| 699 // notifications, but no unfocus. |
| 700 crossing_event.focus = 0; |
| 701 crossing_event.state = modifier_state; |
| 702 break; |
| 703 } |
| 704 case WebInputEvent::MouseUp: |
| 705 case WebInputEvent::MouseDown: { |
| 706 if (event.type == WebInputEvent::MouseDown) { |
| 707 np_event->type = ButtonPress; |
| 708 } else { |
| 709 np_event->type = ButtonRelease; |
| 710 } |
| 711 XButtonEvent &button_event = np_event->xbutton; |
| 712 button_event.root = root; |
| 713 button_event.time = timestamp; |
| 714 button_event.x = event.x; |
| 715 button_event.y = event.y; |
| 716 button_event.x_root = event.globalX; |
| 717 button_event.y_root = event.globalY; |
| 718 button_event.state = modifier_state; |
| 719 switch (event.button) { |
| 720 case WebMouseEvent::ButtonLeft: |
| 721 button_event.button = Button1; |
| 722 break; |
| 723 case WebMouseEvent::ButtonMiddle: |
| 724 button_event.button = Button2; |
| 725 break; |
| 726 case WebMouseEvent::ButtonRight: |
| 727 button_event.button = Button3; |
| 728 break; |
| 729 } |
| 730 button_event.same_screen = True; |
| 731 break; |
| 732 } |
| 733 default: |
| 734 NOTREACHED(); |
| 735 return false; |
| 736 } |
| 737 return true; |
| 738 } |
| 739 |
| 740 static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event, |
| 741 Time timestamp, |
| 742 NPEvent *np_event) { |
| 743 np_event->xany.display = GDK_DISPLAY(); |
| 744 // NOTE: Firefox keeps xany.serial and xany.window as 0. |
| 745 |
| 746 switch (event.type) { |
| 747 case WebKeyboardEvent::KeyDown: |
| 748 np_event->type = KeyPress; |
| 749 break; |
| 750 case WebKeyboardEvent::KeyUp: |
| 751 np_event->type = KeyRelease; |
| 752 break; |
| 753 default: |
| 754 NOTREACHED(); |
| 755 return false; |
| 756 } |
| 757 XKeyEvent &key_event = np_event->xkey; |
| 758 key_event.send_event = False; |
| 759 key_event.display = GDK_DISPLAY(); |
| 760 // NOTE: Firefox keeps xany.serial and xany.window as 0. |
| 761 // TODO(piman@google.com): is this right for multiple screens ? |
| 762 key_event.root = DefaultRootWindow(key_event.display); |
| 763 key_event.time = timestamp; |
| 764 // NOTE: We don't have the correct information for x/y/x_root/y_root. Firefox |
| 765 // doesn't have it either, so we pass the same values. |
| 766 key_event.x = 0; |
| 767 key_event.y = 0; |
| 768 key_event.x_root = -1; |
| 769 key_event.y_root = -1; |
| 770 key_event.state = GetXModifierState(event.modifiers); |
| 771 key_event.keycode = event.nativeKeyCode; |
| 772 key_event.same_screen = True; |
| 773 return true; |
| 774 } |
| 775 |
| 776 static bool NPEventFromWebInputEvent(const WebInputEvent& event, |
| 777 Time timestamp, |
| 778 NPEvent* np_event) { |
| 779 switch (event.type) { |
| 780 case WebInputEvent::MouseMove: |
| 781 case WebInputEvent::MouseLeave: |
| 782 case WebInputEvent::MouseEnter: |
| 783 case WebInputEvent::MouseDown: |
| 784 case WebInputEvent::MouseUp: |
| 785 if (event.size < sizeof(WebMouseEvent)) { |
| 786 NOTREACHED(); |
| 787 return false; |
| 788 } |
| 789 return NPEventFromWebMouseEvent( |
| 790 *static_cast<const WebMouseEvent*>(&event), timestamp, np_event); |
| 791 case WebInputEvent::KeyDown: |
| 792 case WebInputEvent::KeyUp: |
| 793 if (event.size < sizeof(WebKeyboardEvent)) { |
| 794 NOTREACHED(); |
| 795 return false; |
| 796 } |
| 797 return NPEventFromWebKeyboardEvent( |
| 798 *static_cast<const WebKeyboardEvent*>(&event), timestamp, np_event); |
| 799 default: |
| 800 return false; |
| 801 } |
| 802 } |
| 803 |
| 804 bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, |
| 805 WebCursor* cursor) { |
| 806 DCHECK(windowless_) << "events should only be received in windowless mode"; |
| 807 |
| 808 if (first_event_time_ < 0.0) |
| 809 first_event_time_ = event.timeStampSeconds; |
| 810 Time timestamp = static_cast<Time>( |
| 811 (event.timeStampSeconds - first_event_time_) * 1.0e3); |
| 812 NPEvent np_event = {0}; |
| 813 if (!NPEventFromWebInputEvent(event, timestamp, &np_event)) { |
| 814 return false; |
| 815 } |
| 816 bool ret = instance()->NPP_HandleEvent(&np_event) != 0; |
636 | 817 |
637 #if 0 | 818 #if 0 |
638 if (event->event == WM_MOUSEMOVE) { | 819 if (event->event == WM_MOUSEMOVE) { |
639 // Snag a reference to the current cursor ASAP in case the plugin modified | 820 // Snag a reference to the current cursor ASAP in case the plugin modified |
640 // it. There is a nasty race condition here with the multiprocess browser | 821 // it. There is a nasty race condition here with the multiprocess browser |
641 // as someone might be setting the cursor in the main process as well. | 822 // as someone might be setting the cursor in the main process as well. |
642 *cursor = current_windowless_cursor_; | 823 *cursor = current_windowless_cursor_; |
643 } | 824 } |
644 #endif | 825 #endif |
645 | 826 |
(...skipping 24 matching lines...) Expand all Loading... |
670 return stream; | 851 return stream; |
671 } | 852 } |
672 | 853 |
673 void WebPluginDelegateImpl::URLRequestRouted(const std::string&url, | 854 void WebPluginDelegateImpl::URLRequestRouted(const std::string&url, |
674 bool notify_needed, | 855 bool notify_needed, |
675 intptr_t notify_data) { | 856 intptr_t notify_data) { |
676 if (notify_needed) { | 857 if (notify_needed) { |
677 instance()->SetURLLoadData(GURL(url.c_str()), notify_data); | 858 instance()->SetURLLoadData(GURL(url.c_str()), notify_data); |
678 } | 859 } |
679 } | 860 } |
OLD | NEW |