diff --git a/atom.gyp b/atom.gyp index 3b607589a1..b4cd71c439 100644 --- a/atom.gyp +++ b/atom.gyp @@ -44,11 +44,13 @@ 'atom/common/lib/init.coffee', 'atom/common/lib/asar.coffee', 'atom/renderer/lib/chrome-api.coffee', - 'atom/renderer/lib/guest-view-internal.coffee', 'atom/renderer/lib/init.coffee', 'atom/renderer/lib/inspector.coffee', 'atom/renderer/lib/override.coffee', - 'atom/renderer/lib/web-view.coffee', + 'atom/renderer/lib/web-view/guest-view-internal.coffee', + 'atom/renderer/lib/web-view/web-view.coffee', + 'atom/renderer/lib/web-view/web-view-attributes.coffee', + 'atom/renderer/lib/web-view/web-view-constants.coffee', 'atom/renderer/api/lib/ipc.coffee', 'atom/renderer/api/lib/remote.coffee', 'atom/renderer/api/lib/web-frame.coffee', @@ -282,6 +284,7 @@ 'chromium_src/chrome/browser/printing/print_job_manager.h', 'chromium_src/chrome/browser/printing/print_job_worker.cc', 'chromium_src/chrome/browser/printing/print_job_worker.h', + 'chromium_src/chrome/browser/printing/print_job_worker_owner.cc', 'chromium_src/chrome/browser/printing/print_job_worker_owner.h', 'chromium_src/chrome/browser/printing/print_view_manager_base.cc', 'chromium_src/chrome/browser/printing/print_view_manager_base.h', @@ -292,8 +295,6 @@ 'chromium_src/chrome/browser/printing/printer_query.h', 'chromium_src/chrome/browser/printing/printing_message_filter.cc', 'chromium_src/chrome/browser/printing/printing_message_filter.h', - 'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.cc', - 'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.h', 'chromium_src/chrome/browser/speech/tts_controller.h', 'chromium_src/chrome/browser/speech/tts_controller_impl.cc', 'chromium_src/chrome/browser/speech/tts_controller_impl.h', @@ -308,10 +309,6 @@ 'chromium_src/chrome/browser/ui/cocoa/color_chooser_mac.mm', 'chromium_src/chrome/browser/ui/views/color_chooser_aura.cc', 'chromium_src/chrome/browser/ui/views/color_chooser_aura.h', - 'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc', - 'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h', - 'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc', - 'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h', 'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc', 'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h', 'chromium_src/chrome/common/print_messages.cc', @@ -322,7 +319,7 @@ 'chromium_src/chrome/renderer/printing/print_web_view_helper.cc', 'chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc', 'chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm', - 'chromium_src/chrome/renderer/printing/print_web_view_helper_win.cc', + 'chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc', 'chromium_src/chrome/renderer/printing/print_web_view_helper.h', 'chromium_src/chrome/renderer/tts_dispatcher.cc', 'chromium_src/chrome/renderer/tts_dispatcher.h', @@ -479,10 +476,10 @@ '<(libchromiumcontent_library_dir)/libEGL.dll', '<(libchromiumcontent_library_dir)/libGLESv2.dll', '<(libchromiumcontent_resources_dir)/icudtl.dat', + '<(libchromiumcontent_resources_dir)/content_resources_200_percent.pak', '<(libchromiumcontent_resources_dir)/content_shell.pak', '<(libchromiumcontent_resources_dir)/ui_resources_200_percent.pak', - '<(libchromiumcontent_resources_dir)/webkit_resources_200_percent.pak', - 'external_binaries/d3dcompiler_43.dll', + 'external_binaries/d3dcompiler_46.dll', 'external_binaries/msvcp120.dll', 'external_binaries/msvcr120.dll', 'external_binaries/vccorlib120.dll', @@ -528,6 +525,8 @@ 'defines': [ # This is defined in skia/skia_common.gypi. 'SK_SUPPORT_LEGACY_GETTOPDEVICE', + # Disable warnings for g_settings_list_schemas. + 'GLIB_DISABLE_DEPRECATION_WARNINGS', ], 'sources': [ '<@(lib_sources)', @@ -884,13 +883,14 @@ { 'action_name': 'Make Empty Paks', 'inputs': [ - 'tools/posix/make_locale_paks.sh', + 'tools/make_locale_paks.py', ], 'outputs': [ '<(PRODUCT_DIR)/locales' ], 'action': [ - 'tools/posix/make_locale_paks.sh', + 'python', + 'tools/make_locale_paks.py', '<(PRODUCT_DIR)', '<@(locales)', ], @@ -932,31 +932,5 @@ }, # target generate_node_lib ], }], # OS==win - # Using Visual Studio Express. - ['msvs_express==1', { - 'target_defaults': { - 'defines!': [ - '_SECURE_ATL', - ], - 'msvs_settings': { - 'VCLibrarianTool': { - 'AdditionalLibraryDirectories': [ - '<(atom_source_root)/external_binaries/atl/lib', - ], - }, - 'VCLinkerTool': { - 'AdditionalLibraryDirectories': [ - '<(atom_source_root)/external_binaries/atl/lib', - ], - 'AdditionalDependencies': [ - 'atls.lib', - ], - }, - }, - 'msvs_system_include_dirs': [ - '<(atom_source_root)/external_binaries/atl/include', - ], - }, - }], # msvs_express==1 ], } diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index 1030bb85c4..f376df8668 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -111,7 +111,7 @@ void AtomMainDelegate::AddDataPackFromPath( pak_dir.Append(FILE_PATH_LITERAL("ui_resources_200_percent.pak")), ui::SCALE_FACTOR_200P); bundle->AddDataPackFromPath( - pak_dir.Append(FILE_PATH_LITERAL("webkit_resources_200_percent.pak")), + pak_dir.Append(FILE_PATH_LITERAL("content_resources_200_percent.pak")), ui::SCALE_FACTOR_200P); #endif } diff --git a/atom/browser/api/atom_api_content_tracing.cc b/atom/browser/api/atom_api_content_tracing.cc index 0eff591379..42295fd26c 100644 --- a/atom/browser/api/atom_api_content_tracing.cc +++ b/atom/browser/api/atom_api_content_tracing.cc @@ -69,14 +69,17 @@ void Initialize(v8::Handle exports, v8::Handle unused, dict.SetMethod("startRecording", base::Bind( &TracingController::EnableRecording, base::Unretained(controller))); dict.SetMethod("stopRecording", base::Bind( - &TracingController::DisableRecording, base::Unretained(controller))); + &TracingController::DisableRecording, + base::Unretained(controller), + nullptr)); dict.SetMethod("startMonitoring", base::Bind( &TracingController::EnableMonitoring, base::Unretained(controller))); dict.SetMethod("stopMonitoring", base::Bind( &TracingController::DisableMonitoring, base::Unretained(controller))); dict.SetMethod("captureMonitoringSnapshot", base::Bind( &TracingController::CaptureMonitoringSnapshot, - base::Unretained(controller))); + base::Unretained(controller), + nullptr)); dict.SetMethod("getTraceBufferPercentFull", base::Bind( &TracingController::GetTraceBufferPercentFull, base::Unretained(controller))); diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 9115cbc82a..7bd1095b8a 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -12,6 +12,7 @@ #include "atom/common/native_mate_converters/value_converter.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" +#include "content/public/browser/navigation_details.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -37,12 +38,14 @@ v8::Persistent template_; WebContents::WebContents(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), guest_instance_id_(-1), + element_instance_id_(-1), guest_opaque_(true), auto_size_enabled_(false) { } WebContents::WebContents(const mate::Dictionary& options) : guest_instance_id_(-1), + element_instance_id_(-1), guest_opaque_(true), auto_size_enabled_(false) { options.Get("guestInstanceId", &guest_instance_id_); @@ -188,6 +191,13 @@ void WebContents::DidGetRedirectForResourceRequest( Emit("did-get-redirect-request", args); } +void WebContents::DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + if (details.is_navigation_to_different_page()) + Emit("did-navigate-to-different-page"); +} + bool WebContents::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(WebContents, message) @@ -225,26 +235,8 @@ void WebContents::WebContentsDestroyed() { Emit("destroyed"); } -void WebContents::WillAttach(content::WebContents* embedder_web_contents, - const base::DictionaryValue& extra_params) { - embedder_web_contents_ = embedder_web_contents; - extra_params_.reset(extra_params.DeepCopy()); -} - -content::WebContents* WebContents::CreateNewGuestWindow( - const content::WebContents::CreateParams& create_params) { - NOTREACHED() << "Should not create new window from guest"; - return nullptr; -} - -void WebContents::DidAttach() { - base::ListValue args; - args.Append(extra_params_.release()); - Emit("did-attach", args); -} - -int WebContents::GetGuestInstanceID() const { - return guest_instance_id_; +void WebContents::DidAttach(int guest_proxy_routing_id) { + Emit("did-attach"); } void WebContents::ElementSizeChanged(const gfx::Size& old_size, @@ -260,18 +252,17 @@ void WebContents::GuestSizeChanged(const gfx::Size& old_size, GuestSizeChangedDueToAutoSize(old_size, new_size); } -void WebContents::RequestPointerLockPermission( - bool user_gesture, - bool last_unlocked_by_target, - const base::Callback& callback) { - callback.Run(true); -} - void WebContents::RegisterDestructionCallback( const DestructionCallback& callback) { destruction_callback_ = callback; } +void WebContents::WillAttach(content::WebContents* embedder_web_contents, + int browser_plugin_instance_id) { + embedder_web_contents_ = embedder_web_contents; + element_instance_id_ = browser_plugin_instance_id; +} + void WebContents::Destroy() { if (storage_) { if (!destruction_callback_.is_null()) @@ -294,7 +285,7 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) { params.referrer = content::Referrer(http_referrer.GetAsReferrer(), blink::WebReferrerPolicyDefault); - params.transition_type = content::PAGE_TRANSITION_TYPED; + params.transition_type = ui::PAGE_TRANSITION_TYPED; params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; web_contents()->GetController().LoadURLWithParams(params); } diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 7f6a697190..4bb798c90d 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -118,42 +118,35 @@ class WebContents : public mate::EventEmitter, const content::NativeWebKeyboardEvent& event) override; // content::WebContentsObserver: - virtual void RenderViewDeleted(content::RenderViewHost*) override; - virtual void RenderProcessGone(base::TerminationStatus status) override; - virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url) override; - virtual void DidFailLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url, - int error_code, - const base::string16& error_description) override; - virtual void DidStartLoading( - content::RenderViewHost* render_view_host) override; - virtual void DidStopLoading( - content::RenderViewHost* render_view_host) override; - virtual void DidGetRedirectForResourceRequest( + void RenderViewDeleted(content::RenderViewHost*) override; + void RenderProcessGone(base::TerminationStatus status) override; + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override; + void DidFailLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url, + int error_code, + const base::string16& error_description) override; + void DidStartLoading(content::RenderViewHost* render_view_host) override; + void DidStopLoading(content::RenderViewHost* render_view_host) override; + void DidGetRedirectForResourceRequest( content::RenderViewHost* render_view_host, const content::ResourceRedirectDetails& details) override; - virtual bool OnMessageReceived(const IPC::Message& message) override; - virtual void RenderViewReady() override; - virtual void WebContentsDestroyed() override; + void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; + bool OnMessageReceived(const IPC::Message& message) override; + void RenderViewReady() override; + void WebContentsDestroyed() override; // content::BrowserPluginGuestDelegate: - virtual void WillAttach(content::WebContents* embedder_web_contents, - const base::DictionaryValue& extra_params) override; - virtual content::WebContents* CreateNewGuestWindow( - const content::WebContents::CreateParams& create_params) override; - virtual void DidAttach() override; - virtual int GetGuestInstanceID() const override; - virtual void ElementSizeChanged(const gfx::Size& old_size, - const gfx::Size& new_size) override; - virtual void GuestSizeChanged(const gfx::Size& old_size, - const gfx::Size& new_size) override; - virtual void RequestPointerLockPermission( - bool user_gesture, - bool last_unlocked_by_target, - const base::Callback& callback) override; - virtual void RegisterDestructionCallback( - const DestructionCallback& callback) override; + void DidAttach(int guest_proxy_routing_id) final; + void ElementSizeChanged(const gfx::Size& old_size, + const gfx::Size& new_size) final; + void GuestSizeChanged(const gfx::Size& old_size, + const gfx::Size& new_size) final; + void RegisterDestructionCallback(const DestructionCallback& callback) final; + void WillAttach(content::WebContents* embedder_web_contents, + int browser_plugin_instance_id) final; private: // Called when received a message from renderer. @@ -171,17 +164,15 @@ class WebContents : public mate::EventEmitter, // Unique ID for a guest WebContents. int guest_instance_id_; + // |element_instance_id_| is an identifer that's unique to a particular + // element. + int element_instance_id_; + DestructionCallback destruction_callback_; // Stores whether the contents of the guest can be transparent. bool guest_opaque_; - // The extra parameters associated with this guest view passed - // in from JavaScript. This will typically be the view instance ID, - // the API to use, and view-specific parameters. These parameters - // are passed along to new guests that are created from this guest. - scoped_ptr extra_params_; - // Stores the WebContents that managed by this class. scoped_ptr storage_; diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 615adb512c..17255fd238 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -72,8 +72,6 @@ Window::Window(const mate::Dictionary& options) Window::~Window() { if (window_) Destroy(); - - Emit("destroyed"); } void Window::OnPageTitleUpdated(bool* prevent_default, diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index c39acc06ca..7b908676b1 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -56,7 +56,7 @@ AtomBrowserClient::~AtomBrowserClient() { void AtomBrowserClient::RenderProcessWillLaunch( content::RenderProcessHost* host) { int id = host->GetID(); - host->AddFilter(new PrintingMessageFilter(host->GetID())); + host->AddFilter(new printing::PrintingMessageFilter(host->GetID())); host->AddFilter(new TtsMessageFilter(id, host->GetBrowserContext())); } diff --git a/atom/browser/javascript_environment.cc b/atom/browser/javascript_environment.cc index e0dd7d54f7..f8dd71f471 100644 --- a/atom/browser/javascript_environment.cc +++ b/atom/browser/javascript_environment.cc @@ -7,8 +7,7 @@ namespace atom { JavascriptEnvironment::JavascriptEnvironment() - : isolate_holder_(gin::IsolateHolder::kNonStrictMode), - isolate_(isolate_holder_.isolate()), + : isolate_(isolate_holder_.isolate()), isolate_scope_(isolate_), locker_(isolate_), handle_scope_(isolate_), diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index db8ed44848..d5422c1b40 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -18,6 +18,8 @@ supportedWebViewEvents = [ nextInstanceId = 0 guestInstances = {} +embedderElementsMap = {} +reverseEmbedderElementsMap = {} # Generate guestInstanceId. getNextInstanceId = (webContents) -> @@ -33,15 +35,19 @@ createGuest = (embedder, params) -> guestInstanceId: id storagePartitionId: params.storagePartitionId guestInstances[id] = {guest, embedder} - preload = params.preload ? '' - webViewManager.addGuest id, embedder, guest, params.nodeIntegration, params.plugins, preload - # Destroy guest when the embedder is gone. - embedder.once 'render-view-deleted', -> + # Destroy guest when the embedder is gone or navigated. + destroyEvents = ['destroyed', 'crashed', 'did-navigate-to-different-page'] + destroy = -> destroyGuest id if guestInstances[id]? + embedder.removeListener event, destroy for event in destroyEvents + embedder.once event, destroy for event in destroyEvents # Init guest web view after attached. - guest.once 'did-attach', (event, params) -> + guest.once 'did-attach', -> + params = @attachParams + delete @attachParams + @viewInstanceId = params.instanceId min = width: params.minwidth, height: params.minheight max = width: params.maxwidth, height: params.maxheight @@ -66,15 +72,47 @@ createGuest = (embedder, params) -> id +# Attach the guest to an element of embedder. +attachGuest = (embedder, elementInstanceId, guestInstanceId, params) -> + guest = guestInstances[guestInstanceId].guest + + # Destroy the old guest when attaching. + key = "#{embedder.getId()}-#{elementInstanceId}" + oldGuestInstanceId = embedderElementsMap[key] + if oldGuestInstanceId? + # Reattachment to the same guest is not currently supported. + return unless oldGuestInstanceId != guestInstanceId + + return unless guestInstances[oldGuestInstanceId]? + destroyGuest oldGuestInstanceId + + webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest, + nodeIntegration: params.nodeintegration + plugins: params.plugins + preloadUrl: params.preload ? '' + + guest.attachParams = params + embedderElementsMap[key] = guestInstanceId + reverseEmbedderElementsMap[guestInstanceId] = key + # Destroy an existing guest instance. destroyGuest = (id) -> webViewManager.removeGuest id guestInstances[id].guest.destroy() delete guestInstances[id] + key = reverseEmbedderElementsMap[id] + if key? + delete reverseEmbedderElementsMap[id] + delete embedderElementsMap[key] + ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, type, params, requestId) -> event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}", createGuest(event.sender, params) +ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId, guestInstanceId, params, requestId) -> + attachGuest event.sender, elementInstanceId, guestInstanceId, params + event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}" + ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', (event, id) -> destroyGuest id diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 3170239ed8..2a34fe4151 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "atom/browser/native_window.h" +@class FullSizeContentView; class SkRegion; namespace atom { @@ -98,6 +99,9 @@ class NativeWindowMac : public NativeWindow { base::scoped_nsobject window_; + // The view that will fill the whole frameless window. + base::scoped_nsobject content_view_; + bool is_kiosk_; NSInteger attention_request_id_; // identifier from requestUserAttention diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 131e2096d4..17e361f789 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -25,6 +25,31 @@ static const CGFloat kAtomWindowCornerRadius = 4.0; - (CGFloat)roundedCornerRadius; @end +// This view always takes the size of its superview. It is intended to be used +// as a NSWindow's contentView. It is needed because NSWindow's implementation +// explicitly resizes the contentView at inopportune times. +@interface FullSizeContentView : NSView +@end + +@implementation FullSizeContentView + +// This method is directly called by NSWindow during a window resize on OSX +// 10.10.0, beta 2. We must override it to prevent the content view from +// shrinking. +- (void)setFrameSize:(NSSize)size { + if ([self superview]) + size = [[self superview] bounds].size; + [super setFrameSize:size]; +} + +// The contentView gets moved around during certain full-screen operations. +// This is less than ideal, and should eventually be removed. +- (void)viewDidMoveToSuperview { + [self setFrame:[[self superview] bounds]]; +} + +@end + @interface AtomNSWindowDelegate : NSObject { @private atom::NativeWindowMac* shell_; @@ -690,9 +715,24 @@ void NativeWindowMac::InstallView() { [view setFrame:[[window_ contentView] bounds]]; [[window_ contentView] addSubview:view]; } else { - NSView* frameView = [[window_ contentView] superview]; - [view setFrame:[frameView bounds]]; - [frameView addSubview:view]; + if (base::mac::IsOSYosemiteOrLater()) { + // In OSX 10.10, adding subviews to the root view for the NSView hierarchy + // produces warnings. To eliminate the warnings, we resize the contentView + // to fill the window, and add subviews to that. + // http://crbug.com/380412 + content_view_.reset([[FullSizeContentView alloc] init]); + [content_view_ + setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [content_view_ setFrame:[[[window_ contentView] superview] bounds]]; + [window_ setContentView:content_view_]; + + [view setFrame:[content_view_ bounds]]; + [content_view_ addSubview:view]; + } else { + NSView* frameView = [[window_ contentView] superview]; + [view setFrame:[frameView bounds]]; + [frameView addSubview:view]; + } ClipWebView(); diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 9ee492aaa6..8825371dc3 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -49,6 +49,7 @@ #include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" #include "ui/base/win/shell.h" +#include "ui/gfx/win/dpi.h" #include "ui/views/win/hwnd_util.h" #endif @@ -837,8 +838,15 @@ void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) { gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds( const gfx::Rect& bounds) { +#if defined(OS_WIN) + gfx::Rect dpi_bounds = gfx::win::DIPToScreenRect(bounds); + gfx::Rect window_bounds = gfx::win::ScreenToDIPRect( + window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds)); +#else gfx::Rect window_bounds = window_->non_client_view()->GetWindowBoundsForClientBounds(bounds); +#endif + if (menu_bar_ && menu_bar_visible_) window_bounds.set_height(window_bounds.height() + kMenuBarHeight); return window_bounds; diff --git a/atom/browser/net/adapter_request_job.cc b/atom/browser/net/adapter_request_job.cc index eabd65553e..6b5b905aba 100644 --- a/atom/browser/net/adapter_request_job.cc +++ b/atom/browser/net/adapter_request_job.cc @@ -22,7 +22,7 @@ AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler, } void AdapterRequestJob::Start() { - DCHECK(!real_job_); + DCHECK(!real_job_.get()); content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, @@ -31,35 +31,35 @@ void AdapterRequestJob::Start() { } void AdapterRequestJob::Kill() { - if (real_job_) // Kill could happen when real_job_ is created. + if (real_job_.get()) // Kill could happen when real_job_ is created. real_job_->Kill(); } bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read) { - DCHECK(real_job_); + DCHECK(!real_job_.get()); return real_job_->ReadRawData(buf, buf_size, bytes_read); } bool AdapterRequestJob::IsRedirectResponse(GURL* location, int* http_status_code) { - DCHECK(real_job_); + DCHECK(!real_job_.get()); return real_job_->IsRedirectResponse(location, http_status_code); } net::Filter* AdapterRequestJob::SetupFilter() const { - DCHECK(real_job_); + DCHECK(!real_job_.get()); return real_job_->SetupFilter(); } bool AdapterRequestJob::GetMimeType(std::string* mime_type) const { - DCHECK(real_job_); + DCHECK(!real_job_.get()); return real_job_->GetMimeType(mime_type); } bool AdapterRequestJob::GetCharset(std::string* charset) { - DCHECK(real_job_); + DCHECK(!real_job_.get()); return real_job_->GetCharset(charset); } diff --git a/atom/browser/ui/tray_icon.cc b/atom/browser/ui/tray_icon.cc index a59c0c7b8c..c8fb40902d 100644 --- a/atom/browser/ui/tray_icon.cc +++ b/atom/browser/ui/tray_icon.cc @@ -12,6 +12,9 @@ TrayIcon::TrayIcon() { TrayIcon::~TrayIcon() { } +void TrayIcon::SetPressedImage(const gfx::ImageSkia& image) { +} + void TrayIcon::SetTitle(const std::string& title) { } diff --git a/atom/browser/ui/tray_icon.h b/atom/browser/ui/tray_icon.h index 83ee98e757..a27ea82f22 100644 --- a/atom/browser/ui/tray_icon.h +++ b/atom/browser/ui/tray_icon.h @@ -23,7 +23,7 @@ class TrayIcon { virtual void SetImage(const gfx::ImageSkia& image) = 0; // Sets the image associated with this status icon when pressed. - virtual void SetPressedImage(const gfx::ImageSkia& image) = 0; + virtual void SetPressedImage(const gfx::ImageSkia& image); // Sets the hover text for this status icon. This is also used as the label // for the menu item which is created as a replacement for the status icon diff --git a/atom/browser/ui/tray_icon_gtk.cc b/atom/browser/ui/tray_icon_gtk.cc index b853453da4..c7a56ddb03 100644 --- a/atom/browser/ui/tray_icon_gtk.cc +++ b/atom/browser/ui/tray_icon_gtk.cc @@ -32,10 +32,6 @@ void TrayIconGtk::SetImage(const gfx::ImageSkia& image) { icon_->set_delegate(this); } -void TrayIconGtk::SetPressedImage(const gfx::ImageSkia& image) { - icon_->SetPressedImage(image); -} - void TrayIconGtk::SetToolTip(const std::string& tool_tip) { icon_->SetToolTip(base::UTF8ToUTF16(tool_tip)); } diff --git a/atom/browser/ui/tray_icon_gtk.h b/atom/browser/ui/tray_icon_gtk.h index e8eec3fda0..5027a2d448 100644 --- a/atom/browser/ui/tray_icon_gtk.h +++ b/atom/browser/ui/tray_icon_gtk.h @@ -24,7 +24,6 @@ class TrayIconGtk : public TrayIcon, // TrayIcon: virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE; - virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE; virtual void SetToolTip(const std::string& tool_tip) OVERRIDE; virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE; diff --git a/atom/browser/ui/views/frameless_view.cc b/atom/browser/ui/views/frameless_view.cc index 7e98085e0d..03a31e0828 100644 --- a/atom/browser/ui/views/frameless_view.cc +++ b/atom/browser/ui/views/frameless_view.cc @@ -95,6 +95,9 @@ void FramelessView::UpdateWindowIcon() { void FramelessView::UpdateWindowTitle() { } +void FramelessView::SizeConstraintsChanged() { +} + gfx::Size FramelessView::GetPreferredSize() const { return frame_->non_client_view()->GetWindowBoundsForClientBounds( gfx::Rect(frame_->client_view()->GetPreferredSize())).size(); diff --git a/atom/browser/ui/views/frameless_view.h b/atom/browser/ui/views/frameless_view.h index f07a8c6758..54dc3285fa 100644 --- a/atom/browser/ui/views/frameless_view.h +++ b/atom/browser/ui/views/frameless_view.h @@ -36,6 +36,7 @@ class FramelessView : public views::NonClientFrameView { void ResetWindowControls() override; void UpdateWindowIcon() override; void UpdateWindowTitle() override; + void SizeConstraintsChanged() override; // Overridden from View: gfx::Size GetPreferredSize() const override; diff --git a/atom/browser/ui/views/win_frame_view.cc b/atom/browser/ui/views/win_frame_view.cc index e1ef9a018e..db74661932 100644 --- a/atom/browser/ui/views/win_frame_view.cc +++ b/atom/browser/ui/views/win_frame_view.cc @@ -27,9 +27,9 @@ WinFrameView::~WinFrameView() { gfx::Rect WinFrameView::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { - gfx::Size size(client_bounds.size()); - ClientAreaSizeToWindowSize(&size); - return gfx::Rect(client_bounds.origin(), size); + return views::GetWindowBoundsForClientBounds( + static_cast(const_cast(this)), + client_bounds); } int WinFrameView::NonClientHitTest(const gfx::Point& point) { @@ -53,12 +53,4 @@ const char* WinFrameView::GetClassName() const { return kViewClassName; } -void WinFrameView::ClientAreaSizeToWindowSize(gfx::Size* size) const { - // AdjustWindowRect seems to return a wrong window size. - gfx::Size window = frame_->GetWindowBoundsInScreen().size(); - gfx::Size client = frame_->GetClientAreaBoundsInScreen().size(); - size->set_width(size->width() + window.width() - client.width()); - size->set_height(size->height() + window.height() - client.height()); -} - } // namespace atom diff --git a/atom/browser/ui/views/win_frame_view.h b/atom/browser/ui/views/win_frame_view.h index 43bab2c8f4..825677bff3 100644 --- a/atom/browser/ui/views/win_frame_view.h +++ b/atom/browser/ui/views/win_frame_view.h @@ -25,8 +25,6 @@ class WinFrameView : public FramelessView { const char* GetClassName() const override; private: - void ClientAreaSizeToWindowSize(gfx::Size* size) const; - DISALLOW_COPY_AND_ASSIGN(WinFrameView); }; diff --git a/atom/browser/web_view/web_view_manager.cc b/atom/browser/web_view/web_view_manager.cc index 5dd427c6a7..032be04e78 100644 --- a/atom/browser/web_view/web_view_manager.cc +++ b/atom/browser/web_view/web_view_manager.cc @@ -32,6 +32,19 @@ struct Converter { } }; +template<> +struct Converter { + static bool FromV8(v8::Isolate* isolate, v8::Handle val, + atom::WebViewManager::WebViewOptions* out) { + Dictionary options; + if (!ConvertFromV8(isolate, val, &options)) + return false; + return options.Get("nodeIntegration", &(out->node_integration)) && + options.Get("plugins", &(out->plugins)) && + options.Get("preloadUrl", &(out->preload_url)); + } +}; + } // namespace mate namespace atom { @@ -43,17 +56,16 @@ WebViewManager::~WebViewManager() { } void WebViewManager::AddGuest(int guest_instance_id, + int element_instance_id, content::WebContents* embedder, content::WebContents* web_contents, - bool node_integration, - bool plugins, - const GURL& preload_url) { + const WebViewOptions& options) { web_contents_map_[guest_instance_id] = { web_contents, embedder }; WebViewRendererState::WebViewInfo web_view_info = { - guest_instance_id, node_integration, plugins + guest_instance_id, options.node_integration, options.plugins }; - net::FileURLToFilePath(preload_url, &web_view_info.preload_script); + net::FileURLToFilePath(options.preload_url, &web_view_info.preload_script); content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, @@ -61,6 +73,10 @@ void WebViewManager::AddGuest(int guest_instance_id, base::Unretained(WebViewRendererState::GetInstance()), web_contents->GetRenderProcessHost()->GetID(), web_view_info)); + + // Map the element in embedder to guest. + ElementInstanceKey key(embedder, element_instance_id); + element_instance_id_to_guest_map_[key] = guest_instance_id; } void WebViewManager::RemoveGuest(int guest_instance_id) { @@ -71,18 +87,28 @@ void WebViewManager::RemoveGuest(int guest_instance_id) { &WebViewRendererState::RemoveGuest, base::Unretained(WebViewRendererState::GetInstance()), web_contents->GetRenderProcessHost()->GetID())); - web_contents_map_.erase(guest_instance_id); + + // Remove the record of element in embedder too. + for (const auto& element : element_instance_id_to_guest_map_) + if (element.second == guest_instance_id) { + element_instance_id_to_guest_map_.erase(element.first); + break; + } } -void WebViewManager::MaybeGetGuestByInstanceIDOrKill( - int guest_instance_id, - int embedder_render_process_id, - const GuestByInstanceIDCallback& callback) { +content::WebContents* WebViewManager::GetGuestByInstanceID( + content::WebContents* embedder, + int element_instance_id) { + ElementInstanceKey key(embedder, element_instance_id); + if (!ContainsKey(element_instance_id_to_guest_map_, key)) + return nullptr; + + int guest_instance_id = element_instance_id_to_guest_map_[key]; if (ContainsKey(web_contents_map_, guest_instance_id)) - callback.Run(web_contents_map_[guest_instance_id].web_contents); + return web_contents_map_[guest_instance_id].web_contents; else - callback.Run(nullptr); + return nullptr; } bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents, diff --git a/atom/browser/web_view/web_view_manager.h b/atom/browser/web_view/web_view_manager.h index e687440895..e14d31cec0 100644 --- a/atom/browser/web_view/web_view_manager.h +++ b/atom/browser/web_view/web_view_manager.h @@ -8,6 +8,7 @@ #include #include "content/public/browser/browser_plugin_guest_manager.h" +#include "url/gurl.h" namespace content { class BrowserContext; @@ -20,22 +21,26 @@ class WebViewManager : public content::BrowserPluginGuestManager { explicit WebViewManager(content::BrowserContext* context); virtual ~WebViewManager(); + struct WebViewOptions { + bool node_integration; + bool plugins; + GURL preload_url; + }; + void AddGuest(int guest_instance_id, + int element_instance_id, content::WebContents* embedder, content::WebContents* web_contents, - bool node_integration, - bool plugins, - const GURL& preload_url); + const WebViewOptions& options); void RemoveGuest(int guest_instance_id); protected: // content::BrowserPluginGuestManager: - virtual void MaybeGetGuestByInstanceIDOrKill( - int guest_instance_id, - int embedder_render_process_id, - const GuestByInstanceIDCallback& callback) override; - virtual bool ForEachGuest(content::WebContents* embedder_web_contents, - const GuestCallback& callback) override; + content::WebContents* GetGuestByInstanceID( + content::WebContents* embedder_web_contents, + int element_instance_id) override; + bool ForEachGuest(content::WebContents* embedder, + const GuestCallback& callback) override; private: struct WebContentsWithEmbedder { @@ -44,6 +49,32 @@ class WebViewManager : public content::BrowserPluginGuestManager { }; std::map web_contents_map_; + struct ElementInstanceKey { + content::WebContents* owner_web_contents; + int element_instance_id; + + ElementInstanceKey() + : owner_web_contents(nullptr), + element_instance_id(0) {} + + ElementInstanceKey(content::WebContents* owner_web_contents, + int element_instance_id) + : owner_web_contents(owner_web_contents), + element_instance_id(element_instance_id) {} + + bool operator<(const ElementInstanceKey& other) const { + if (owner_web_contents != other.owner_web_contents) + return owner_web_contents < other.owner_web_contents; + return element_instance_id < other.element_instance_id; + } + + bool operator==(const ElementInstanceKey& other) const { + return (owner_web_contents == other.owner_web_contents) && + (element_instance_id == other.element_instance_id); + } + }; + std::map element_instance_id_to_guest_map_; + DISALLOW_COPY_AND_ASSIGN(WebViewManager); }; diff --git a/atom/common/api/atom_api_clipboard.cc b/atom/common/api/atom_api_clipboard.cc index ee6cc0ccc4..36b8cecb7c 100644 --- a/atom/common/api/atom_api_clipboard.cc +++ b/atom/common/api/atom_api_clipboard.cc @@ -58,8 +58,7 @@ base::string16 ReadText(ui::ClipboardType type) { } void WriteText(const base::string16& text, ui::ClipboardType type) { - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - ui::ScopedClipboardWriter writer(clipboard, type); + ui::ScopedClipboardWriter writer(type); writer.WriteText(text); } diff --git a/atom/common/chrome_version.h b/atom/common/chrome_version.h index 4b8494e871..e684321e17 100644 --- a/atom/common/chrome_version.h +++ b/atom/common/chrome_version.h @@ -8,7 +8,7 @@ #ifndef ATOM_COMMON_CHROME_VERSION_H_ #define ATOM_COMMON_CHROME_VERSION_H_ -#define CHROME_VERSION_STRING "38.0.2125.101" +#define CHROME_VERSION_STRING "39.0.2171.65" #define CHROME_VERSION "v" CHROME_VERSION_STRING #endif // ATOM_COMMON_CHROME_VERSION_H_ diff --git a/atom/common/crash_reporter/crash_reporter_mac.mm b/atom/common/crash_reporter/crash_reporter_mac.mm index ff1e214dbb..5875bc78f0 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.mm +++ b/atom/common/crash_reporter/crash_reporter_mac.mm @@ -4,6 +4,7 @@ #include "atom/common/crash_reporter/crash_reporter_mac.h" +#include "base/mac/mac_util.h" #include "base/memory/singleton.h" #include "base/strings/sys_string_conversions.h" #import "vendor/breakpad/src/client/apple/Framework/BreakpadDefines.h" @@ -54,7 +55,19 @@ void CrashReporterMac::InitBreakpad(const std::string& product_name, [parameters setValue:base::SysUTF8ToNSString(dump_dir) forKey:@BREAKPAD_DUMP_DIRECTORY]; + // Temporarily run Breakpad in-process on 10.10 and later because APIs that + // it depends on got broken (http://crbug.com/386208). + // This can catch crashes in the browser process only. + if (base::mac::IsOSYosemiteOrLater()) { + [parameters setObject:[NSNumber numberWithBool:YES] + forKey:@BREAKPAD_IN_PROCESS]; + } + breakpad_ = BreakpadCreate(parameters); + if (!breakpad_) { + LOG(ERROR) << "Failed to initialize breakpad"; + return; + } for (StringMap::const_iterator iter = upload_parameters_.begin(); iter != upload_parameters_.end(); ++iter) { diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 9bfd0c4f3c..e43c4d9625 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -89,6 +89,19 @@ namespace { void UvNoOp(uv_async_t* handle) { } +// Moved from node.cc. +void HandleCloseCb(uv_handle_t* handle) { + node::Environment* env = reinterpret_cast(handle->data); + env->FinishHandleCleanup(handle); +} + +void HandleCleanup(node::Environment* env, + uv_handle_t* handle, + void* arg) { + handle->data = env; + uv_close(handle, HandleCloseCb); +} + // Convert the given vector to an array of C-strings. The strings in the // returned vector are only guaranteed valid so long as the vector of strings // is not modified. @@ -181,6 +194,7 @@ node::Environment* NodeBindings::CreateEnvironment( // Construct the parameters that passed to node::CreateEnvironment: v8::Isolate* isolate = context->GetIsolate(); + uv_loop_t* loop = uv_default_loop(); int argc = args.size(); const char** argv = c_argv.get(); int exec_argc = 0; @@ -191,13 +205,16 @@ node::Environment* NodeBindings::CreateEnvironment( // Following code are stripped from node::CreateEnvironment in node.cc: HandleScope handle_scope(isolate); - Context::Scope context_scope(context); - Environment* env = Environment::New(context); + Context::Scope context_scope(context); + Environment* env = Environment::New(context, loop); + + isolate->SetAutorunMicrotasks(false); uv_check_init(env->event_loop(), env->immediate_check_handle()); uv_unref( reinterpret_cast(env->immediate_check_handle())); + uv_idle_init(env->event_loop(), env->immediate_idle_handle()); uv_prepare_init(env->event_loop(), env->idle_prepare_handle()); @@ -205,6 +222,24 @@ node::Environment* NodeBindings::CreateEnvironment( uv_unref(reinterpret_cast(env->idle_prepare_handle())); uv_unref(reinterpret_cast(env->idle_check_handle())); + // Register handle cleanups + env->RegisterHandleCleanup( + reinterpret_cast(env->immediate_check_handle()), + HandleCleanup, + nullptr); + env->RegisterHandleCleanup( + reinterpret_cast(env->immediate_idle_handle()), + HandleCleanup, + nullptr); + env->RegisterHandleCleanup( + reinterpret_cast(env->idle_prepare_handle()), + HandleCleanup, + nullptr); + env->RegisterHandleCleanup( + reinterpret_cast(env->idle_check_handle()), + HandleCleanup, + nullptr); + Local process_template = FunctionTemplate::New(isolate); process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process")); @@ -212,7 +247,7 @@ node::Environment* NodeBindings::CreateEnvironment( env->set_process_object(process_object); SetupProcessObject(env, argc, argv, exec_argc, exec_argv); - Load(env); + LoadEnvironment(env); return env; } diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index 0b80de8e4c..9fc9008ea3 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -5,6 +5,7 @@ #include "atom/renderer/api/atom_api_web_frame.h" #include "atom/common/native_mate_converters/string16_converter.h" +#include "content/public/renderer/render_frame.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" #include "third_party/WebKit/public/web/WebDocument.h" @@ -51,6 +52,10 @@ v8::Handle WebFrame::RegisterEmbedderCustomElement( return web_frame_->document().registerEmbedderCustomElement(name, options, c); } +void WebFrame::AttachGuest(int id) { + content::RenderFrame::FromWebFrame(web_frame_)->AttachGuest(id); +} + mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) @@ -60,7 +65,8 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( .SetMethod("setZoomFactor", &WebFrame::SetZoomFactor) .SetMethod("getZoomFactor", &WebFrame::GetZoomFactor) .SetMethod("registerEmbedderCustomElement", - &WebFrame::RegisterEmbedderCustomElement); + &WebFrame::RegisterEmbedderCustomElement) + .SetMethod("attachGuest", &WebFrame::AttachGuest); } // static diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index 955794f229..132199e3fe 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -35,6 +35,7 @@ class WebFrame : public mate::Wrappable { v8::Handle RegisterEmbedderCustomElement( const base::string16& name, v8::Handle options); + void AttachGuest(int element_instance_id); // mate::Wrappable: virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 91d83bf1f4..c910014e19 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -92,7 +92,7 @@ void AtomRendererClient::WebKitInitialized() { v8::Isolate* isolate = blink::mainThreadIsolate(); v8::HandleScope handle_scope(isolate); v8::Local context = v8::Context::New(isolate); - global_env = node::Environment::New(context); + global_env = node::Environment::New(context, uv_default_loop()); } void AtomRendererClient::RenderThreadStarted() { @@ -161,7 +161,7 @@ void AtomRendererClient::DidCreateScriptContext(blink::WebFrame* frame, } void AtomRendererClient::WillReleaseScriptContext( - blink::WebFrame* frame, + blink::WebLocalFrame* frame, v8::Handle context, int world_id) { node::Environment* env = node::Environment::GetCurrent(context); diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index cb461b2bca..ed2c1e1ad7 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -27,7 +27,7 @@ class AtomRendererClient : public content::ContentRendererClient, virtual ~AtomRendererClient(); // Forwarded by RenderFrameObserver. - void WillReleaseScriptContext(blink::WebFrame* frame, + void WillReleaseScriptContext(blink::WebLocalFrame* frame, v8::Handle context, int world_id); diff --git a/atom/renderer/lib/init.coffee b/atom/renderer/lib/init.coffee index ebf69ac3a6..c2ca2feb32 100644 --- a/atom/renderer/lib/init.coffee +++ b/atom/renderer/lib/init.coffee @@ -36,17 +36,19 @@ for arg in process.argv if location.protocol is 'chrome-devtools:' # Override some inspector APIs. - require path.join(__dirname, 'inspector') + require './inspector' nodeIntegration = 'true' else if location.protocol is 'chrome-extension:' # Add implementations of chrome API. - require path.join(__dirname, 'chrome-api') + require './chrome-api' nodeIntegration = 'true' else # Override default web functions. - require path.join(__dirname, 'override') + require './override' # Load webview tag implementation. - require path.join(__dirname, 'web-view') unless process.guestInstanceId? + unless process.guestInstanceId? + require './web-view/web-view' + require './web-view/web-view-attributes' if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe'] # Export node bindings to global. diff --git a/atom/renderer/lib/web-view.coffee b/atom/renderer/lib/web-view.coffee deleted file mode 100644 index 2bae4a9021..0000000000 --- a/atom/renderer/lib/web-view.coffee +++ /dev/null @@ -1,590 +0,0 @@ -v8Util = process.atomBinding 'v8_util' -guestViewInternal = require './guest-view-internal' -webFrame = require 'web-frame' -remote = require 'remote' - -# ID generator. -nextId = 0 -getNextId = -> ++nextId - -# FIXME -# Discarded after Chrome 39 -PLUGIN_METHOD_ATTACH = '-internal-attach' - -# Attributes. -WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY = 'allowtransparency' -WEB_VIEW_ATTRIBUTE_AUTOSIZE = 'autosize' -WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight' -WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth' -WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight' -WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth' -WEB_VIEW_ATTRIBUTE_PARTITION = 'partition' -WEB_VIEW_ATTRIBUTE_NODEINTEGRATION = 'nodeintegration' -WEB_VIEW_ATTRIBUTE_PLUGINS = 'plugins' -WEB_VIEW_ATTRIBUTE_PRELOAD = 'preload' -AUTO_SIZE_ATTRIBUTES = [ - WEB_VIEW_ATTRIBUTE_AUTOSIZE, - WEB_VIEW_ATTRIBUTE_MAXHEIGHT, - WEB_VIEW_ATTRIBUTE_MAXWIDTH, - WEB_VIEW_ATTRIBUTE_MINHEIGHT, - WEB_VIEW_ATTRIBUTE_MINWIDTH, -] - -# Error messages. -ERROR_MSG_ALREADY_NAVIGATED = - 'The object has already navigated, so its partition cannot be changed.' -ERROR_MSG_CANNOT_INJECT_SCRIPT = ': ' + - 'Script cannot be injected into content until the page has loaded.' -ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE = ': ' + - 'contentWindow is not available at this time. It will become available ' + - 'when the page has finished loading.' -ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.' -ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE = - 'Only "file:" or "asar:" protocol is supported in "preload" attribute.' - -# Represents the state of the storage partition. -class Partition - constructor: -> - @validPartitionId = true - @persistStorage = false - @storagePartitionId = '' - - toAttribute: -> - return '' unless @validPartitionId - (if @persistStorage then 'persist:' else '') + @storagePartitionId - - fromAttribute: (value, hasNavigated) -> - result = {} - if hasNavigated - result.error = ERROR_MSG_ALREADY_NAVIGATED - return result - value ?= '' - - LEN = 'persist:'.length - if value.substr(0, LEN) == 'persist:' - value = value.substr LEN - unless value - @validPartitionId = false - result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE - return result - @persistStorage = true - else - @persistStorage = false - - @storagePartitionId = value - result - -# Represents the internal state of the WebView node. -class WebView - constructor: (@webviewNode) -> - v8Util.setHiddenValue @webviewNode, 'internal', this - @attached = false - @pendingGuestCreation = false - @elementAttached = false - - @beforeFirstNavigation = true - @contentWindow = null - @validPartitionId = true - # Used to save some state upon deferred attachment. - # If bindings is not available, we defer attachment. - # This state contains whether or not the attachment request was for - # newwindow. - @deferredAttachState = null - - # on* Event handlers. - @on = {} - - @browserPluginNode = @createBrowserPluginNode() - shadowRoot = @webviewNode.createShadowRoot() - @partition = new Partition() - - @setupWebViewSrcAttributeMutationObserver() - @setupFocusPropagation() - @setupWebviewNodeProperties() - - @viewInstanceId = getNextId() - guestViewInternal.registerEvents this, @viewInstanceId - - shadowRoot.appendChild @browserPluginNode - - createBrowserPluginNode: -> - # We create BrowserPlugin as a custom element in order to observe changes - # to attributes synchronously. - browserPluginNode = new WebView.BrowserPlugin() - v8Util.setHiddenValue browserPluginNode, 'internal', this - browserPluginNode - - getGuestInstanceId: -> - @guestInstanceId - - # Resets some state upon reattaching element to the DOM. - reset: -> - # If guestInstanceId is defined then the has navigated and has - # already picked up a partition ID. Thus, we need to reset the initialization - # state. However, it may be the case that beforeFirstNavigation is false BUT - # guestInstanceId has yet to be initialized. This means that we have not - # heard back from createGuest yet. We will not reset the flag in this case so - # that we don't end up allocating a second guest. - if @guestInstanceId - guestViewInternal.destroyGuest @guestInstanceId - @guestInstanceId = undefined - @beforeFirstNavigation = true - @validPartitionId = true - @partition.validPartitionId = true - @contentWindow = null - @internalInstanceId = 0 - - # Sets the .request property. - setRequestPropertyOnWebViewNode: (request) -> - Object.defineProperty @webviewNode, 'request', value: request, enumerable: true - - setupFocusPropagation: -> - unless @webviewNode.hasAttribute 'tabIndex' - # needs a tabIndex in order to be focusable. - # TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute - # to allow to be focusable. - # See http://crbug.com/231664. - @webviewNode.setAttribute 'tabIndex', -1 - @webviewNode.addEventListener 'focus', (e) => - # Focus the BrowserPlugin when the takes focus. - @browserPluginNode.focus() - @webviewNode.addEventListener 'blur', (e) => - # Blur the BrowserPlugin when the loses focus. - @browserPluginNode.blur() - - # Validation helper function for executeScript() and insertCSS(). - validateExecuteCodeCall: -> - throw new Error(ERROR_MSG_CANNOT_INJECT_SCRIPT) unless @guestInstanceId - - setupAutoSizeProperties: -> - for attributeName in AUTO_SIZE_ATTRIBUTES - this[attributeName] = @webviewNode.getAttribute attributeName - Object.defineProperty @webviewNode, attributeName, - get: => this[attributeName] - set: (value) => @webviewNode.setAttribute attributeName, value - enumerable: true - - setupWebviewNodeProperties: -> - @setupAutoSizeProperties() - - Object.defineProperty @webviewNode, WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY, - get: => @allowtransparency - set: (value) => - @webviewNode.setAttribute WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY, value - enumerable: true - - # We cannot use {writable: true} property descriptor because we want a - # dynamic getter value. - Object.defineProperty @webviewNode, 'contentWindow', - get: => - return @contentWindow if @contentWindow? - window.console.error ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE - # No setter. - enumerable: true - - Object.defineProperty @webviewNode, 'partition', - get: => @partition.toAttribute() - set: (value) => - result = @partition.fromAttribute value, @hasNavigated() - throw result.error if result.error? - @webviewNode.setAttribute 'partition', value - enumerable: true - - @src = @webviewNode.getAttribute 'src' - Object.defineProperty @webviewNode, 'src', - get: => @src - set: (value) => @webviewNode.setAttribute 'src', value - # No setter. - enumerable: true - - @httpreferrer = @webviewNode.getAttribute 'httpreferrer' - Object.defineProperty @webviewNode, 'httpreferrer', - get: => @httpreferrer - set: (value) => @webviewNode.setAttribute 'httpreferrer', value - enumerable: true - - # The purpose of this mutation observer is to catch assignment to the src - # attribute without any changes to its value. This is useful in the case - # where the webview guest has crashed and navigating to the same address - # spawns off a new process. - setupWebViewSrcAttributeMutationObserver: -> - @srcAndPartitionObserver = new MutationObserver (mutations) => - for mutation in mutations - oldValue = mutation.oldValue - newValue = @webviewNode.getAttribute mutation.attributeName - return if oldValue isnt newValue - @handleWebviewAttributeMutation mutation.attributeName, oldValue, newValue - params = - attributes: true, - attributeOldValue: true, - attributeFilter: ['src', 'partition', 'httpreferrer'] - @srcAndPartitionObserver.observe @webviewNode, params - - # This observer monitors mutations to attributes of the and - # updates the BrowserPlugin properties accordingly. In turn, updating - # a BrowserPlugin property will update the corresponding BrowserPlugin - # attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more - # details. - handleWebviewAttributeMutation: (name, oldValue, newValue) -> - if name in AUTO_SIZE_ATTRIBUTES - this[name] = newValue - return unless @guestInstanceId - # Convert autosize attribute to boolean. - autosize = @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_AUTOSIZE - guestViewInternal.setAutoSize @guestInstanceId, - enableAutoSize: autosize, - min: - width: parseInt @minwidth || 0 - height: parseInt @minheight || 0 - max: - width: parseInt @maxwidth || 0 - height: parseInt @maxheight || 0 - else if name is WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY - # We treat null attribute (attribute removed) and the empty string as - # one case. - oldValue ?= '' - newValue ?= '' - - return if oldValue is newValue - @allowtransparency = newValue != '' - - return unless @guestInstanceId - - guestViewInternal.setAllowTransparency @guestInstanceId, @allowtransparency - else if name is 'httpreferrer' - oldValue ?= '' - newValue ?= '' - - if newValue == '' and oldValue != '' - @webviewNode.setAttribute 'httpreferrer', oldValue - - @httpreferrer = newValue - - result = {} - # If the httpreferrer changes treat it as though the src changes and reload - # the page with the new httpreferrer. - @parseSrcAttribute result - - throw result.error if result.error? - else if name is 'src' - # We treat null attribute (attribute removed) and the empty string as - # one case. - oldValue ?= '' - newValue ?= '' - # Once we have navigated, we don't allow clearing the src attribute. - # Once enters a navigated state, it cannot be return back to a - # placeholder state. - if newValue == '' and oldValue != '' - # src attribute changes normally initiate a navigation. We suppress - # the next src attribute handler call to avoid reloading the page - # on every guest-initiated navigation. - @ignoreNextSrcAttributeChange = true - @webviewNode.setAttribute 'src', oldValue - @src = newValue - if @ignoreNextSrcAttributeChange - # Don't allow the src mutation observer to see this change. - @srcAndPartitionObserver.takeRecords() - @ignoreNextSrcAttributeChange = false - return - result = {} - @parseSrcAttribute result - - throw result.error if result.error? - else if name is 'partition' - # Note that throwing error here won't synchronously propagate. - @partition.fromAttribute newValue, @hasNavigated() - - handleBrowserPluginAttributeMutation: (name, oldValue, newValue) -> - # FIXME - # internalbindings => internalInstanceid after Chrome 39 - if name is 'internalbindings' and !oldValue and !!newValue - @browserPluginNode.removeAttribute 'internalbindings' - # FIXME - # @internalInstanceId = parseInt newValue - - if !!@guestInstanceId and @guestInstanceId != 0 - isNewWindow = if @deferredAttachState then @deferredAttachState.isNewWindow else false - params = @buildAttachParams isNewWindow - # FIXME - # guestViewInternalNatives.AttachGuest - # @internalInstanceId, - # @guestInstanceId, - # params, - # (w) => @contentWindow = w - @browserPluginNode[PLUGIN_METHOD_ATTACH] @guestInstanceId, params - - onSizeChanged: (webViewEvent) -> - newWidth = webViewEvent.newWidth - newHeight = webViewEvent.newHeight - - node = @webviewNode - - width = node.offsetWidth - height = node.offsetHeight - - # Check the current bounds to make sure we do not resize - # outside of current constraints. - if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXWIDTH) and - node[WEB_VIEW_ATTRIBUTE_MAXWIDTH] - maxWidth = node[WEB_VIEW_ATTRIBUTE_MAXWIDTH] - else - maxWidth = width - - if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINWIDTH) and - node[WEB_VIEW_ATTRIBUTE_MINWIDTH] - minWidth = node[WEB_VIEW_ATTRIBUTE_MINWIDTH] - else - minWidth = width - minWidth = maxWidth if minWidth > maxWidth - - if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXHEIGHT) and - node[WEB_VIEW_ATTRIBUTE_MAXHEIGHT] - maxHeight = node[WEB_VIEW_ATTRIBUTE_MAXHEIGHT] - else - maxHeight = height - - if node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINHEIGHT) and - node[WEB_VIEW_ATTRIBUTE_MINHEIGHT] - minHeight = node[WEB_VIEW_ATTRIBUTE_MINHEIGHT] - else - minHeight = height - minHeight = maxHeight if minHeight > maxHeight - - if not @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_AUTOSIZE or - (newWidth >= minWidth and - newWidth <= maxWidth and - newHeight >= minHeight and - newHeight <= maxHeight) - node.style.width = newWidth + 'px' - node.style.height = newHeight + 'px' - # Only fire the DOM event if the size of the has actually - # changed. - @dispatchEvent webViewEvent - - # Returns if is in the render tree. - isPluginInRenderTree: -> - # FIXME - # !!@internalInstanceId && @internalInstanceId != 0 - 'function' == typeof this.browserPluginNode[PLUGIN_METHOD_ATTACH] - - hasNavigated: -> - not @beforeFirstNavigation - - parseSrcAttribute: (result) -> - unless @partition.validPartitionId - result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE - return - @src = @webviewNode.getAttribute 'src' - - return unless @src - - unless @guestInstanceId? - if @beforeFirstNavigation - @beforeFirstNavigation = false - @createGuest() - return - - # Navigate to |this.src|. - urlOptions = if @httpreferrer then {@httpreferrer} else {} - remote.getGuestWebContents(@guestInstanceId).loadUrl @src, urlOptions - - parseAttributes: -> - return unless @elementAttached - hasNavigated = @hasNavigated() - attributeValue = @webviewNode.getAttribute 'partition' - result = @partition.fromAttribute attributeValue, hasNavigated - @parseSrcAttribute result - - createGuest: -> - return if @pendingGuestCreation - storagePartitionId = - @webviewNode.getAttribute(WEB_VIEW_ATTRIBUTE_PARTITION) or - @webviewNode[WEB_VIEW_ATTRIBUTE_PARTITION] - params = - storagePartitionId: storagePartitionId - nodeIntegration: @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_NODEINTEGRATION - plugins: @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_PLUGINS - if @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_PRELOAD - preload = @webviewNode.getAttribute WEB_VIEW_ATTRIBUTE_PRELOAD - # Get the full path. - a = document.createElement 'a' - a.href = preload - params.preload = a.href - # Only support file: or asar: protocol. - protocol = params.preload.substr 0, 5 - unless protocol in ['file:', 'asar:'] - delete params.preload - console.error ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE - guestViewInternal.createGuest 'webview', params, (guestInstanceId) => - @pendingGuestCreation = false - unless @elementAttached - guestViewInternal.destroyGuest guestInstanceId - return - @attachWindow guestInstanceId, false - @pendingGuestCreation = true - - dispatchEvent: (webViewEvent) -> - @webviewNode.dispatchEvent webViewEvent - - # Adds an 'on' property on the webview, which can be used to set/unset - # an event handler. - setupEventProperty: (eventName) -> - propertyName = 'on' + eventName.toLowerCase() - Object.defineProperty @webviewNode, propertyName, - get: => @on[propertyName] - set: (value) => - if @on[propertyName] - @webviewNode.removeEventListener eventName, @on[propertyName] - @on[propertyName] = value - if value - @webviewNode.addEventListener eventName, value - enumerable: true - - # Updates state upon loadcommit. - onLoadCommit: (@baseUrlForDataUrl, @currentEntryIndex, @entryCount, @processId, url, isTopLevel) -> - oldValue = @webviewNode.getAttribute 'src' - newValue = url - if isTopLevel and (oldValue != newValue) - # Touching the src attribute triggers a navigation. To avoid - # triggering a page reload on every guest-initiated navigation, - # we use the flag ignoreNextSrcAttributeChange here. - this.ignoreNextSrcAttributeChange = true - this.webviewNode.setAttribute 'src', newValue - - onAttach: (storagePartitionId) -> - @webviewNode.setAttribute 'partition', storagePartitionId - @partition.fromAttribute storagePartitionId, this.hasNavigated() - - buildAttachParams: (isNewWindow) -> - allowtransparency: @allowtransparency || false - autosize: @webviewNode.hasAttribute WEB_VIEW_ATTRIBUTE_AUTOSIZE - instanceId: @viewInstanceId - maxheight: parseInt @maxheight || 0 - maxwidth: parseInt @maxwidth || 0 - minheight: parseInt @minheight || 0 - minwidth: parseInt @minwidth || 0 - # We don't need to navigate new window from here. - src: if isNewWindow then undefined else @src - # If we have a partition from the opener, that will also be already - # set via this.onAttach(). - storagePartitionId: @partition.toAttribute() - userAgentOverride: @userAgentOverride - httpreferrer: @httpreferrer - - attachWindow: (guestInstanceId, isNewWindow) -> - @guestInstanceId = guestInstanceId - params = @buildAttachParams isNewWindow - - unless @isPluginInRenderTree() - @deferredAttachState = isNewWindow: isNewWindow - return true - - @deferredAttachState = null - # FIXME - # guestViewInternalNatives.AttachGuest @internalInstanceId, @guestInstanceId, params, (w) => @contentWindow = w - @browserPluginNode[PLUGIN_METHOD_ATTACH] @guestInstanceId, params - -# Registers browser plugin custom element. -registerBrowserPluginElement = -> - proto = Object.create HTMLObjectElement.prototype - - proto.createdCallback = -> - @setAttribute 'type', 'application/browser-plugin' - @setAttribute 'id', 'browser-plugin-' + getNextId() - # The node fills in the container. - @style.width = '100%' - @style.height = '100%' - - proto.attributeChangedCallback = (name, oldValue, newValue) -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - internal.handleBrowserPluginAttributeMutation name, oldValue, newValue - - proto.attachedCallback = -> - # Load the plugin immediately. - unused = this.nonExistentAttribute - - WebView.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin', - extends: 'object', prototype: proto - - delete proto.createdCallback - delete proto.attachedCallback - delete proto.detachedCallback - delete proto.attributeChangedCallback - -# Registers custom element. -registerWebViewElement = -> - proto = Object.create HTMLObjectElement.prototype - - proto.createdCallback = -> - new WebView(this) - - proto.attributeChangedCallback = (name, oldValue, newValue) -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - internal.handleWebviewAttributeMutation name, oldValue, newValue - - proto.detachedCallback = -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - internal.elementAttached = false - internal.reset() - - proto.attachedCallback = -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - unless internal.elementAttached - internal.elementAttached = true - internal.parseAttributes() - - # Public-facing API methods. - methods = [ - "getUrl" - "getTitle" - "isLoading" - "isWaitingForResponse" - "stop" - "reload" - "reloadIgnoringCache" - "canGoBack" - "canGoForward" - "canGoToOffset" - "goBack" - "goForward" - "goToIndex" - "goToOffset" - "isCrashed" - "setUserAgent" - "executeJavaScript" - "insertCSS" - "openDevTools" - "closeDevTools" - "isDevToolsOpened" - "send" - "getId" - ] - - # Forward proto.foo* method calls to WebView.foo*. - createHandler = (m) -> - (args...) -> - internal = v8Util.getHiddenValue this, 'internal' - remote.getGuestWebContents(internal.guestInstanceId)[m] args... - proto[m] = createHandler m for m in methods - - window.WebView = webFrame.registerEmbedderCustomElement 'webview', - prototype: proto - - # Delete the callbacks so developers cannot call them and produce unexpected - # behavior. - delete proto.createdCallback - delete proto.attachedCallback - delete proto.detachedCallback - delete proto.attributeChangedCallback - -useCapture = true -listener = (event) -> - return if document.readyState == 'loading' - registerBrowserPluginElement() - registerWebViewElement() - window.removeEventListener event.type, listener, useCapture -window.addEventListener 'readystatechange', listener, true diff --git a/atom/renderer/lib/guest-view-internal.coffee b/atom/renderer/lib/web-view/guest-view-internal.coffee similarity index 81% rename from atom/renderer/lib/guest-view-internal.coffee rename to atom/renderer/lib/web-view/guest-view-internal.coffee index 76474d27ec..5757536ac4 100644 --- a/atom/renderer/lib/guest-view-internal.coffee +++ b/atom/renderer/lib/web-view/guest-view-internal.coffee @@ -1,4 +1,5 @@ ipc = require 'ipc' +webFrame = require 'web-frame' requestId = 0 @@ -36,7 +37,13 @@ module.exports = createGuest: (type, params, callback) -> requestId++ ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', type, params, requestId - ipc.on "ATOM_SHELL_RESPONSE_#{requestId}", callback + ipc.once "ATOM_SHELL_RESPONSE_#{requestId}", callback + + attachGuest: (elementInstanceId, guestInstanceId, params, callback) -> + requestId++ + ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params, requestId + ipc.once "ATOM_SHELL_RESPONSE_#{requestId}", callback + webFrame.attachGuest elementInstanceId destroyGuest: (guestInstanceId) -> ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId diff --git a/atom/renderer/lib/web-view/web-view-attributes.coffee b/atom/renderer/lib/web-view/web-view-attributes.coffee new file mode 100644 index 0000000000..a3e97b5be4 --- /dev/null +++ b/atom/renderer/lib/web-view/web-view-attributes.coffee @@ -0,0 +1,207 @@ +WebViewImpl = require './web-view' +guestViewInternal = require './guest-view-internal' +webViewConstants = require './web-view-constants' +remote = require 'remote' + +# Helper function to resolve url set in attribute. +a = document.createElement 'a' +resolveUrl = (url) -> + a.href = url + a.href + +# Attribute objects. +# Default implementation of a WebView attribute. +class WebViewAttribute + constructor: (name, webViewImpl) -> + @name = name + @webViewImpl = webViewImpl + @ignoreMutation = false + + @defineProperty() + + # Retrieves and returns the attribute's value. + getValue: -> @webViewImpl.webviewNode.getAttribute(@name) || '' + + # Sets the attribute's value. + setValue: (value) -> @webViewImpl.webviewNode.setAttribute(@name, value || '') + + # Changes the attribute's value without triggering its mutation handler. + setValueIgnoreMutation: (value) -> + @ignoreMutation = true + @webViewImpl.webviewNode.setAttribute(@name, value || '') + @ignoreMutation = false + + # Defines this attribute as a property on the webview node. + defineProperty: -> + Object.defineProperty @webViewImpl.webviewNode, @name, + get: => @getValue() + set: (value) => @setValue value + enumerable: true + + # Called when the attribute's value changes. + handleMutation: -> + +# An attribute that is treated as a Boolean. +class BooleanAttribute extends WebViewAttribute + constructor: (name, webViewImpl) -> + super name, webViewImpl + + getValue: -> @webViewImpl.webviewNode.hasAttribute @name + + setValue: (value) -> + unless value + @webViewImpl.webviewNode.removeAttribute @name + else + @webViewImpl.webviewNode.setAttribute @name, '' + +# Attribute that specifies whether transparency is allowed in the webview. +class AllowTransparencyAttribute extends BooleanAttribute + constructor: (webViewImpl) -> + super webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl + + handleMutation: (oldValue, newValue) -> + return unless @webViewImpl.guestInstanceId + guestViewInternal.setAllowTransparency @webViewImpl.guestInstanceId, @getValue() + +# Attribute used to define the demension limits of autosizing. +class AutosizeDimensionAttribute extends WebViewAttribute + constructor: (name, webViewImpl) -> + super name, webViewImpl + + getValue: -> parseInt(@webViewImpl.webviewNode.getAttribute(@name)) || 0 + + handleMutation: (oldValue, newValue) -> + return unless @webViewImpl.guestInstanceId + guestViewInternal.setAutoSize @webViewImpl.guestInstanceId, + enableAutoSize: @webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() + min: + width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0 + height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0 + max: + width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0 + height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0 + +# Attribute that specifies whether the webview should be autosized. +class AutosizeAttribute extends BooleanAttribute + constructor: (webViewImpl) -> + super webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl + + handleMutation: AutosizeDimensionAttribute::handleMutation + +# Attribute representing the state of the storage partition. +class PartitionAttribute extends WebViewAttribute + constructor: (webViewImpl) -> + super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl + @validPartitionId = true + + handleMutation: (oldValue, newValue) -> + newValue = newValue || '' + + # The partition cannot change if the webview has already navigated. + unless @webViewImpl.beforeFirstNavigation + window.console.error webViewConstants.ERROR_MSG_ALREADY_NAVIGATED + @setValueIgnoreMutation oldValue + return + + if newValue is 'persist:' + @validPartitionId = false + window.console.error webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE + +# Attribute that handles the location and navigation of the webview. +class SrcAttribute extends WebViewAttribute + constructor: (webViewImpl) -> + super webViewConstants.ATTRIBUTE_SRC, webViewImpl + @setupMutationObserver() + + getValue: -> + if @webViewImpl.webviewNode.hasAttribute @name + resolveUrl @webViewImpl.webviewNode.getAttribute(@name) + else + '' + + handleMutation: (oldValue, newValue) -> + # Once we have navigated, we don't allow clearing the src attribute. + # Once enters a navigated state, it cannot return to a + # placeholder state. + if not newValue and oldValue + # src attribute changes normally initiate a navigation. We suppress + # the next src attribute handler call to avoid reloading the page + # on every guest-initiated navigation. + @setValueIgnoreMutation oldValue + return + @parse() + + # The purpose of this mutation observer is to catch assignment to the src + # attribute without any changes to its value. This is useful in the case + # where the webview guest has crashed and navigating to the same address + # spawns off a new process. + setupMutationObserver: -> + @observer = new MutationObserver (mutations) => + for mutation in mutations + oldValue = mutation.oldValue + newValue = @getValue() + return if oldValue isnt newValue + @handleMutation oldValue, newValue + params = + attributes: true, + attributeOldValue: true, + attributeFilter: [@name] + @observer.observe @webViewImpl.webviewNode, params + + parse: -> + if not @webViewImpl.elementAttached or + not @webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId or + not @.getValue() + return + + unless @webViewImpl.guestInstanceId? + if @webViewImpl.beforeFirstNavigation + @webViewImpl.beforeFirstNavigation = false + @webViewImpl.createGuest() + return + + # Navigate to |this.src|. + httpreferrer = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() + urlOptions = if httpreferrer then {httpreferrer} else {} + remote.getGuestWebContents(@webViewImpl.guestInstanceId).loadUrl @getValue(), urlOptions + +# Attribute specifies HTTP referrer. +class HttpReferrerAttribute extends WebViewAttribute + constructor: (webViewImpl) -> + super webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl + +# Attribute that set preload script. +class PreloadAttribute extends WebViewAttribute + constructor: (webViewImpl) -> + super webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl + + getValue: -> + return '' unless @webViewImpl.webviewNode.hasAttribute @name + preload = resolveUrl @webViewImpl.webviewNode.getAttribute(@name) + protocol = preload.substr 0, 5 + unless protocol in ['file:', 'asar:'] + console.error webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE + preload = '' + preload + +# Sets up all of the webview attributes. +WebViewImpl::setupWebViewAttributes = -> + @attributes = {} + + @attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY] = new AllowTransparencyAttribute(this) + @attributes[webViewConstants.ATTRIBUTE_AUTOSIZE] = new AutosizeAttribute(this) + @attributes[webViewConstants.ATTRIBUTE_PARTITION] = new PartitionAttribute(this) + @attributes[webViewConstants.ATTRIBUTE_SRC] = new SrcAttribute(this) + @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER] = new HttpReferrerAttribute(this) + @attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this) + @attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this) + @attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this) + + autosizeAttributes = [ + webViewConstants.ATTRIBUTE_MAXHEIGHT + webViewConstants.ATTRIBUTE_MAXWIDTH + webViewConstants.ATTRIBUTE_MINHEIGHT + webViewConstants.ATTRIBUTE_MINWIDTH + ] + for attribute in autosizeAttributes + @attributes[attribute] = new AutosizeDimensionAttribute(attribute, this) diff --git a/atom/renderer/lib/web-view/web-view-constants.coffee b/atom/renderer/lib/web-view/web-view-constants.coffee new file mode 100644 index 0000000000..f40f14c4d7 --- /dev/null +++ b/atom/renderer/lib/web-view/web-view-constants.coffee @@ -0,0 +1,28 @@ +module.exports = + # Attributes. + ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency' + ATTRIBUTE_AUTOSIZE: 'autosize' + ATTRIBUTE_MAXHEIGHT: 'maxheight' + ATTRIBUTE_MAXWIDTH: 'maxwidth' + ATTRIBUTE_MINHEIGHT: 'minheight' + ATTRIBUTE_MINWIDTH: 'minwidth' + ATTRIBUTE_NAME: 'name' + ATTRIBUTE_PARTITION: 'partition' + ATTRIBUTE_SRC: 'src' + ATTRIBUTE_HTTPREFERRER: 'httpreferrer' + ATTRIBUTE_NODEINTEGRATION: 'nodeintegration' + ATTRIBUTE_PLUGINS: 'plugins' + ATTRIBUTE_PRELOAD: 'preload' + + # Internal attribute. + ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid' + + # Error messages. + ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.' + ERROR_MSG_CANNOT_INJECT_SCRIPT: ': ' + + 'Script cannot be injected into content until the page has loaded.' + ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE: ': ' + + 'contentWindow is not available at this time. It will become available ' + + 'when the page has finished loading.' + ERROR_MSG_INVALID_PARTITION_ATTRIBUTE: 'Invalid partition attribute.' + ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE: 'Only "file:" or "asar:" protocol is supported in "preload" attribute.' diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee new file mode 100644 index 0000000000..e095c0b74d --- /dev/null +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -0,0 +1,300 @@ +v8Util = process.atomBinding 'v8_util' +guestViewInternal = require './guest-view-internal' +webViewConstants = require './web-view-constants' +webFrame = require 'web-frame' +remote = require 'remote' + +# ID generator. +nextId = 0 +getNextId = -> ++nextId + +# Represents the internal state of the WebView node. +class WebViewImpl + constructor: (@webviewNode) -> + v8Util.setHiddenValue @webviewNode, 'internal', this + @attached = false + @pendingGuestCreation = false + @elementAttached = false + + @beforeFirstNavigation = true + @contentWindow = null + + # on* Event handlers. + @on = {} + + @browserPluginNode = @createBrowserPluginNode() + shadowRoot = @webviewNode.createShadowRoot() + @setupWebViewAttributes() + @setupFocusPropagation() + @setupWebviewNodeProperties() + + @viewInstanceId = getNextId() + + guestViewInternal.registerEvents this, @viewInstanceId + + shadowRoot.appendChild @browserPluginNode + + createBrowserPluginNode: -> + # We create BrowserPlugin as a custom element in order to observe changes + # to attributes synchronously. + browserPluginNode = new WebViewImpl.BrowserPlugin() + v8Util.setHiddenValue browserPluginNode, 'internal', this + browserPluginNode + + # Resets some state upon reattaching element to the DOM. + reset: -> + # If guestInstanceId is defined then the has navigated and has + # already picked up a partition ID. Thus, we need to reset the initialization + # state. However, it may be the case that beforeFirstNavigation is false BUT + # guestInstanceId has yet to be initialized. This means that we have not + # heard back from createGuest yet. We will not reset the flag in this case so + # that we don't end up allocating a second guest. + if @guestInstanceId + # FIXME + guestViewInternal.destroyGuest @guestInstanceId + @guestInstanceId = undefined + @beforeFirstNavigation = true + @attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true + @contentWindow = null + @internalInstanceId = 0 + + # Sets the .request property. + setRequestPropertyOnWebViewNode: (request) -> + Object.defineProperty @webviewNode, 'request', value: request, enumerable: true + + setupFocusPropagation: -> + unless @webviewNode.hasAttribute 'tabIndex' + # needs a tabIndex in order to be focusable. + # TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute + # to allow to be focusable. + # See http://crbug.com/231664. + @webviewNode.setAttribute 'tabIndex', -1 + @webviewNode.addEventListener 'focus', (e) => + # Focus the BrowserPlugin when the takes focus. + @browserPluginNode.focus() + @webviewNode.addEventListener 'blur', (e) => + # Blur the BrowserPlugin when the loses focus. + @browserPluginNode.blur() + + setupWebviewNodeProperties: -> + # We cannot use {writable: true} property descriptor because we want a + # dynamic getter value. + Object.defineProperty @webviewNode, 'contentWindow', + get: => + return @contentWindow if @contentWindow? + window.console.error webViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE + # No setter. + enumerable: true + + # This observer monitors mutations to attributes of the and + # updates the BrowserPlugin properties accordingly. In turn, updating + # a BrowserPlugin property will update the corresponding BrowserPlugin + # attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more + # details. + handleWebviewAttributeMutation: (attributeName, oldValue, newValue) -> + if not @attributes[attributeName] or @attributes[attributeName].ignoreMutation + return + + # Let the changed attribute handle its own mutation; + @attributes[attributeName].handleMutation oldValue, newValue + + handleBrowserPluginAttributeMutation: (attributeName, oldValue, newValue) -> + if attributeName is webViewConstants.ATTRIBUTE_INTERNALINSTANCEID and !oldValue and !!newValue + @browserPluginNode.removeAttribute webViewConstants.ATTRIBUTE_INTERNALINSTANCEID + @internalInstanceId = parseInt newValue + + return unless @guestInstanceId + + guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildAttachParams(), (w) => @contentWindow = w + + onSizeChanged: (webViewEvent) -> + newWidth = webViewEvent.newWidth + newHeight = webViewEvent.newHeight + + node = @webviewNode + + width = node.offsetWidth + height = node.offsetHeight + + # Check the current bounds to make sure we do not resize + # outside of current constraints. + maxWidth = @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width + maxHeight = @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width + minWidth = @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width + minHeight = @attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() | width + + if not @attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() or + (newWidth >= minWidth and + newWidth <= maxWidth and + newHeight >= minHeight and + newHeight <= maxHeight) + node.style.width = newWidth + 'px' + node.style.height = newHeight + 'px' + # Only fire the DOM event if the size of the has actually + # changed. + @dispatchEvent webViewEvent + + createGuest: -> + return if @pendingGuestCreation + params = + storagePartitionId: @attributes[webViewConstants.ATTRIBUTE_PARTITION].getValue() + guestViewInternal.createGuest 'webview', params, (guestInstanceId) => + @pendingGuestCreation = false + unless @elementAttached + guestViewInternal.destroyGuest guestInstanceId + return + @attachWindow guestInstanceId + @pendingGuestCreation = true + + dispatchEvent: (webViewEvent) -> + @webviewNode.dispatchEvent webViewEvent + + # Adds an 'on' property on the webview, which can be used to set/unset + # an event handler. + setupEventProperty: (eventName) -> + propertyName = 'on' + eventName.toLowerCase() + Object.defineProperty @webviewNode, propertyName, + get: => @on[propertyName] + set: (value) => + if @on[propertyName] + @webviewNode.removeEventListener eventName, @on[propertyName] + @on[propertyName] = value + if value + @webviewNode.addEventListener eventName, value + enumerable: true + + # Updates state upon loadcommit. + onLoadCommit: (@baseUrlForDataUrl, @currentEntryIndex, @entryCount, @processId, url, isTopLevel) -> + oldValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_SRC + newValue = url + if isTopLevel and (oldValue != newValue) + # Touching the src attribute triggers a navigation. To avoid + # triggering a page reload on every guest-initiated navigation, + # we do not handle this mutation + @attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation newValue + + onAttach: (storagePartitionId) -> + @attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue storagePartitionId + + buildAttachParams: -> + params = + instanceId: @viewInstanceId + userAgentOverride: @userAgentOverride + for attributeName, attribute of @attributes + params[attributeName] = attribute.getValue() + params + + attachWindow: (guestInstanceId) -> + @guestInstanceId = guestInstanceId + params = @buildAttachParams() + + return true unless @internalInstanceId + + guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, params, (w) => @contentWindow = w + +# Registers browser plugin custom element. +registerBrowserPluginElement = -> + proto = Object.create HTMLObjectElement.prototype + + proto.createdCallback = -> + @setAttribute 'type', 'application/browser-plugin' + @setAttribute 'id', 'browser-plugin-' + getNextId() + # The node fills in the container. + @style.width = '100%' + @style.height = '100%' + + proto.attributeChangedCallback = (name, oldValue, newValue) -> + internal = v8Util.getHiddenValue this, 'internal' + return unless internal + internal.handleBrowserPluginAttributeMutation name, oldValue, newValue + + proto.attachedCallback = -> + # Load the plugin immediately. + unused = this.nonExistentAttribute + + WebViewImpl.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin', + extends: 'object', prototype: proto + + delete proto.createdCallback + delete proto.attachedCallback + delete proto.detachedCallback + delete proto.attributeChangedCallback + +# Registers custom element. +registerWebViewElement = -> + proto = Object.create HTMLObjectElement.prototype + + proto.createdCallback = -> + new WebViewImpl(this) + + proto.attributeChangedCallback = (name, oldValue, newValue) -> + internal = v8Util.getHiddenValue this, 'internal' + return unless internal + internal.handleWebviewAttributeMutation name, oldValue, newValue + + proto.detachedCallback = -> + internal = v8Util.getHiddenValue this, 'internal' + return unless internal + internal.elementAttached = false + internal.reset() + + proto.attachedCallback = -> + internal = v8Util.getHiddenValue this, 'internal' + return unless internal + unless internal.elementAttached + internal.elementAttached = true + internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse() + + # Public-facing API methods. + methods = [ + "getUrl" + "getTitle" + "isLoading" + "isWaitingForResponse" + "stop" + "reload" + "reloadIgnoringCache" + "canGoBack" + "canGoForward" + "canGoToOffset" + "goBack" + "goForward" + "goToIndex" + "goToOffset" + "isCrashed" + "setUserAgent" + "executeJavaScript" + "insertCSS" + "openDevTools" + "closeDevTools" + "isDevToolsOpened" + "send" + "getId" + ] + + # Forward proto.foo* method calls to WebViewImpl.foo*. + createHandler = (m) -> + (args...) -> + internal = v8Util.getHiddenValue this, 'internal' + remote.getGuestWebContents(internal.guestInstanceId)[m] args... + proto[m] = createHandler m for m in methods + + window.WebView = webFrame.registerEmbedderCustomElement 'webview', + prototype: proto + + # Delete the callbacks so developers cannot call them and produce unexpected + # behavior. + delete proto.createdCallback + delete proto.attachedCallback + delete proto.detachedCallback + delete proto.attributeChangedCallback + +useCapture = true +listener = (event) -> + return if document.readyState == 'loading' + registerBrowserPluginElement() + registerWebViewElement() + window.removeEventListener event.type, listener, useCapture +window.addEventListener 'readystatechange', listener, true + +module.exports = WebViewImpl diff --git a/chromium_src/chrome/browser/printing/print_job.cc b/chromium_src/chrome/browser/printing/print_job.cc index 4a58440685..25cf0ad790 100644 --- a/chromium_src/chrome/browser/printing/print_job.cc +++ b/chromium_src/chrome/browser/printing/print_job.cc @@ -32,29 +32,25 @@ void HoldRefCallback(const scoped_refptr& owner, namespace printing { PrintJob::PrintJob() - : ui_message_loop_(base::MessageLoop::current()), - source_(NULL), + : source_(NULL), worker_(), settings_(), is_job_pending_(false), is_canceling_(false), quit_factory_(this) { - DCHECK(ui_message_loop_); // This is normally a UI message loop, but in unit tests, the message loop is // of the 'default' type. DCHECK(base::MessageLoopForUI::IsCurrent() || - ui_message_loop_->type() == base::MessageLoop::TYPE_DEFAULT); - ui_message_loop_->AddDestructionObserver(this); + base::MessageLoop::current()->type() == + base::MessageLoop::TYPE_DEFAULT); } PrintJob::~PrintJob() { - ui_message_loop_->RemoveDestructionObserver(this); // The job should be finished (or at least canceled) when it is destroyed. DCHECK(!is_job_pending_); DCHECK(!is_canceling_); - if (worker_.get()) - DCHECK(worker_->message_loop() == NULL); - DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); + DCHECK(!worker_ || !worker_->IsRunning()); + DCHECK(RunsTasksOnCurrentThread()); } void PrintJob::Initialize(PrintJobWorkerOwner* job, @@ -85,7 +81,7 @@ void PrintJob::Initialize(PrintJobWorkerOwner* job, void PrintJob::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { - DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); + DCHECK(RunsTasksOnCurrentThread()); switch (type) { case chrome::NOTIFICATION_PRINT_JOB_EVENT: { OnNotifyPrintJobEvent(*content::Details(details).ptr()); @@ -107,10 +103,6 @@ PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) { return NULL; } -base::MessageLoop* PrintJob::message_loop() { - return ui_message_loop_; -} - const PrintSettings& PrintJob::settings() const { return settings_; } @@ -122,23 +114,20 @@ int PrintJob::cookie() const { return document_->cookie(); } -void PrintJob::WillDestroyCurrentMessageLoop() { - NOTREACHED(); -} - void PrintJob::StartPrinting() { - DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); - DCHECK(worker_->message_loop()); + DCHECK(RunsTasksOnCurrentThread()); + DCHECK(worker_->IsRunning()); DCHECK(!is_job_pending_); - if (!worker_->message_loop() || is_job_pending_) + if (!worker_->IsRunning() || is_job_pending_) return; // Real work is done in PrintJobWorker::StartPrinting(). - worker_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&HoldRefCallback, make_scoped_refptr(this), - base::Bind(&PrintJobWorker::StartPrinting, - base::Unretained(worker_.get()), document_))); + worker_->PostTask(FROM_HERE, + base::Bind(&HoldRefCallback, + make_scoped_refptr(this), + base::Bind(&PrintJobWorker::StartPrinting, + base::Unretained(worker_.get()), + document_))); // Set the flag right now. is_job_pending_ = true; @@ -152,7 +141,7 @@ void PrintJob::StartPrinting() { } void PrintJob::Stop() { - DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); + DCHECK(RunsTasksOnCurrentThread()); if (quit_factory_.HasWeakPtrs()) { // In case we're running a nested message loop to wait for a job to finish, @@ -164,7 +153,7 @@ void PrintJob::Stop() { // Be sure to live long enough. scoped_refptr handle(this); - if (worker_->message_loop()) { + if (worker_->IsRunning()) { ControlledWorkerShutdown(); } else { // Flush the cached document. @@ -180,10 +169,8 @@ void PrintJob::Cancel() { // Be sure to live long enough. scoped_refptr handle(this); - DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); - base::MessageLoop* worker_loop = - worker_.get() ? worker_->message_loop() : NULL; - if (worker_loop) { + DCHECK(RunsTasksOnCurrentThread()); + if (worker_ && worker_->IsRunning()) { // Call this right now so it renders the context invalid. Do not use // InvokeLater since it would take too much time. worker_->Cancel(); @@ -237,14 +224,15 @@ void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) { settings_ = document_->settings(); } - if (worker_.get() && worker_->message_loop()) { + if (worker_) { DCHECK(!is_job_pending_); // Sync the document with the worker. - worker_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&HoldRefCallback, make_scoped_refptr(this), - base::Bind(&PrintJobWorker::OnDocumentChanged, - base::Unretained(worker_.get()), document_))); + worker_->PostTask(FROM_HERE, + base::Bind(&HoldRefCallback, + make_scoped_refptr(this), + base::Bind(&PrintJobWorker::OnDocumentChanged, + base::Unretained(worker_.get()), + document_))); } } @@ -264,7 +252,6 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) { } case JobEventDetails::NEW_DOC: case JobEventDetails::NEW_PAGE: - case JobEventDetails::PAGE_DONE: case JobEventDetails::JOB_DONE: case JobEventDetails::ALL_PAGES_REQUESTED: { // Don't care. @@ -276,6 +263,8 @@ void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) { FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this)); break; } + case JobEventDetails::PAGE_DONE: + break; default: { NOTREACHED(); break; @@ -300,7 +289,7 @@ void PrintJob::OnDocumentDone() { } void PrintJob::ControlledWorkerShutdown() { - DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); + DCHECK(RunsTasksOnCurrentThread()); // The deadlock this code works around is specific to window messaging on // Windows, so we aren't likely to need it on any other platforms. diff --git a/chromium_src/chrome/browser/printing/print_job.h b/chromium_src/chrome/browser/printing/print_job.h index 2ff827a8ed..1b816085c6 100644 --- a/chromium_src/chrome/browser/printing/print_job.h +++ b/chromium_src/chrome/browser/printing/print_job.h @@ -15,15 +15,19 @@ class Thread; +namespace base { +class RefCountedMemory; +} + namespace printing { -// See definition below. class JobEventDetails; - +class MetafilePlayer; +class PdfToEmfConverter; +class PrintJobWorker; class PrintedDocument; class PrintedPage; class PrintedPagesSource; -class PrintJobWorker; class PrinterQuery; // Manages the print work for a specific document. Talks to the printer through @@ -33,8 +37,7 @@ class PrinterQuery; // reference to the job to be sure it is kept alive. All the code in this class // runs in the UI thread. class PrintJob : public PrintJobWorkerOwner, - public content::NotificationObserver, - public base::MessageLoop::DestructionObserver { + public content::NotificationObserver { public: // Create a empty PrintJob. When initializing with this constructor, // post-constructor initialization must be done with Initialize(). @@ -54,13 +57,9 @@ class PrintJob : public PrintJobWorkerOwner, virtual void GetSettingsDone(const PrintSettings& new_settings, PrintingContext::Result result) OVERRIDE; virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE; - virtual base::MessageLoop* message_loop() OVERRIDE; virtual const PrintSettings& settings() const OVERRIDE; virtual int cookie() const OVERRIDE; - // DestructionObserver implementation. - virtual void WillDestroyCurrentMessageLoop() OVERRIDE; - // Starts the actual printing. Signals the worker that it should begin to // spool as soon as data is available. void StartPrinting(); @@ -116,10 +115,6 @@ class PrintJob : public PrintJobWorkerOwner, content::NotificationRegistrar registrar_; - // Main message loop reference. Used to send notifications in the right - // thread. - base::MessageLoop* const ui_message_loop_; - // Source that generates the PrintedPage's (i.e. a WebContents). It will be // set back to NULL if the source is deleted before this object. PrintedPagesSource* source_; diff --git a/chromium_src/chrome/browser/printing/print_job_manager.cc b/chromium_src/chrome/browser/printing/print_job_manager.cc index 9dc0c85404..ec08a98923 100644 --- a/chromium_src/chrome/browser/printing/print_job_manager.cc +++ b/chromium_src/chrome/browser/printing/print_job_manager.cc @@ -22,11 +22,6 @@ PrintQueriesQueue::~PrintQueriesQueue() { queued_queries_.clear(); } -void PrintQueriesQueue::SetDestination(PrintDestinationInterface* destination) { - base::AutoLock lock(lock_); - destination_ = destination; -} - void PrintQueriesQueue::QueuePrinterQuery(PrinterQuery* job) { base::AutoLock lock(lock_); DCHECK(job); @@ -49,17 +44,27 @@ scoped_refptr PrintQueriesQueue::PopPrinterQuery( return NULL; } -scoped_refptr PrintQueriesQueue::CreatePrinterQuery() { - scoped_refptr job = new printing::PrinterQuery; - base::AutoLock lock(lock_); - job->SetWorkerDestination(destination_); +scoped_refptr PrintQueriesQueue::CreatePrinterQuery( + int render_process_id, + int render_view_id) { + scoped_refptr job = + new printing::PrinterQuery(render_process_id, render_view_id); return job; } void PrintQueriesQueue::Shutdown() { - base::AutoLock lock(lock_); - queued_queries_.clear(); - destination_ = NULL; + PrinterQueries queries_to_stop; + { + base::AutoLock lock(lock_); + queued_queries_.swap(queries_to_stop); + } + // Stop all pending queries, requests to generate print preview do not have + // corresponding PrintJob, so any pending preview requests are not covered + // by PrintJobManager::StopJobs and should be stopped explicitly. + for (PrinterQueries::iterator itr = queries_to_stop.begin(); + itr != queries_to_stop.end(); ++itr) { + (*itr)->PostTask(FROM_HERE, base::Bind(&PrinterQuery::StopWorker, *itr)); + } } PrintJobManager::PrintJobManager() : is_shutdown_(false) { @@ -72,7 +77,7 @@ PrintJobManager::~PrintJobManager() { scoped_refptr PrintJobManager::queue() { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - if (!queue_) + if (!queue_.get()) queue_ = new PrintQueriesQueue(); return queue_; } @@ -83,7 +88,7 @@ void PrintJobManager::Shutdown() { is_shutdown_ = true; registrar_.RemoveAll(); StopJobs(true); - if (queue_) + if (queue_.get()) queue_->Shutdown(); queue_ = NULL; } diff --git a/chromium_src/chrome/browser/printing/print_job_manager.h b/chromium_src/chrome/browser/printing/print_job_manager.h index 9d03d9a340..ef61541a2e 100644 --- a/chromium_src/chrome/browser/printing/print_job_manager.h +++ b/chromium_src/chrome/browser/printing/print_job_manager.h @@ -10,11 +10,11 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" #include "base/threading/non_thread_safe.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -#include "printing/print_destination_interface.h" namespace printing { @@ -26,9 +26,6 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe { public: PrintQueriesQueue(); - // Sets the print destination to be set on the next print job. - void SetDestination(PrintDestinationInterface* destination); - // Queues a semi-initialized worker thread. Can be called from any thread. // Current use case is queuing from the I/O thread. // TODO(maruel): Have them vanish after a timeout (~5 minutes?) @@ -39,7 +36,8 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe { scoped_refptr PopPrinterQuery(int document_cookie); // Creates new query. - scoped_refptr CreatePrinterQuery(); + scoped_refptr CreatePrinterQuery(int render_process_id, + int render_view_id); void Shutdown(); @@ -54,8 +52,6 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe { PrinterQueries queued_queries_; - scoped_refptr destination_; - DISALLOW_COPY_AND_ASSIGN(PrintQueriesQueue); }; diff --git a/chromium_src/chrome/browser/printing/print_job_worker.cc b/chromium_src/chrome/browser/printing/print_job_worker.cc index a14c87c794..c4794f8154 100644 --- a/chromium_src/chrome/browser/printing/print_job_worker.cc +++ b/chromium_src/chrome/browser/printing/print_job_worker.cc @@ -13,10 +13,10 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/printing/print_job.h" -#include "chrome/browser/printing/printing_ui_web_contents_observer.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" -#include "grit/generated_resources.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" #include "printing/print_job_constants.h" #include "printing/printed_document.h" #include "printing/printed_page.h" @@ -25,6 +25,8 @@ using content::BrowserThread; +namespace printing { + namespace { // Helper function to ensure |owner| is valid until at least |callback| returns. @@ -33,9 +35,41 @@ void HoldRefCallback(const scoped_refptr& owner, callback.Run(); } -} // namespace +class PrintingContextDelegate : public PrintingContext::Delegate { + public: + PrintingContextDelegate(int render_process_id, int render_view_id); + virtual ~PrintingContextDelegate(); -namespace printing { + virtual gfx::NativeView GetParentView() OVERRIDE; + virtual std::string GetAppLocale() OVERRIDE; + + private: + int render_process_id_; + int render_view_id_; +}; + +PrintingContextDelegate::PrintingContextDelegate(int render_process_id, + int render_view_id) + : render_process_id_(render_process_id), + render_view_id_(render_view_id) { +} + +PrintingContextDelegate::~PrintingContextDelegate() { +} + +gfx::NativeView PrintingContextDelegate::GetParentView() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::RenderViewHost* view = + content::RenderViewHost::FromID(render_process_id_, render_view_id_); + if (!view) + return NULL; + content::WebContents* wc = content::WebContents::FromRenderViewHost(view); + return wc ? wc->GetNativeView() : NULL; +} + +std::string PrintingContextDelegate::GetAppLocale() { + return g_browser_process->GetApplicationLocale(); +} void NotificationCallback(PrintJobWorkerOwner* print_job, JobEventDetails::Type detail_type, @@ -49,22 +83,25 @@ void NotificationCallback(PrintJobWorkerOwner* print_job, content::Details(details)); } -PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner) - : Thread("Printing_Worker"), - owner_(owner), - weak_factory_(this) { - // The object is created in the IO thread. - DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current()); +} // namespace - printing_context_.reset(PrintingContext::Create( - g_browser_process->GetApplicationLocale())); +PrintJobWorker::PrintJobWorker(int render_process_id, + int render_view_id, + PrintJobWorkerOwner* owner) + : owner_(owner), thread_("Printing_Worker"), weak_factory_(this) { + // The object is created in the IO thread. + DCHECK(owner_->RunsTasksOnCurrentThread()); + + printing_context_delegate_.reset( + new PrintingContextDelegate(render_process_id, render_view_id)); + printing_context_ = PrintingContext::Create(printing_context_delegate_.get()); } PrintJobWorker::~PrintJobWorker() { // The object is normally deleted in the UI thread, but when the user // cancels printing or in the case of print preview, the worker is destroyed // on the I/O thread. - DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current()); + DCHECK(owner_->RunsTasksOnCurrentThread()); Stop(); } @@ -73,18 +110,12 @@ void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) { owner_ = new_owner; } -void PrintJobWorker::SetPrintDestination( - PrintDestinationInterface* destination) { - destination_ = destination; -} - void PrintJobWorker::GetSettings( bool ask_user_for_settings, - scoped_ptr web_contents_observer, int document_page_count, bool has_selection, MarginType margin_type) { - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK_EQ(page_number_, PageNumber::npos()); // Recursive task processing is needed for the dialog in case it needs to be @@ -97,13 +128,12 @@ void PrintJobWorker::GetSettings( // When we delegate to a destination, we don't ask the user for settings. // TODO(mad): Ask the destination for settings. - if (ask_user_for_settings && destination_.get() == NULL) { + if (ask_user_for_settings) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), base::Bind(&PrintJobWorker::GetSettingsWithUI, base::Unretained(this), - base::Passed(&web_contents_observer), document_page_count, has_selection))); } else { @@ -116,8 +146,8 @@ void PrintJobWorker::GetSettings( } void PrintJobWorker::SetSettings( - const base::DictionaryValue* const new_settings) { - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + scoped_ptr new_settings) { + DCHECK(task_runner_->RunsTasksOnCurrentThread()); BrowserThread::PostTask( BrowserThread::UI, @@ -126,11 +156,12 @@ void PrintJobWorker::SetSettings( make_scoped_refptr(owner_), base::Bind(&PrintJobWorker::UpdatePrintSettings, base::Unretained(this), - base::Owned(new_settings)))); + base::Passed(&new_settings)))); } void PrintJobWorker::UpdatePrintSettings( - const base::DictionaryValue* const new_settings) { + scoped_ptr new_settings) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); PrintingContext::Result result = printing_context_->UpdatePrintSettings(*new_settings); GetSettingsDone(result); @@ -147,36 +178,31 @@ void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) { // We can't use OnFailure() here since owner_ may not support notifications. // PrintJob will create the new PrintedDocument. - owner_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PrintJobWorkerOwner::GetSettingsDone, - make_scoped_refptr(owner_), printing_context_->settings(), - result)); + owner_->PostTask(FROM_HERE, + base::Bind(&PrintJobWorkerOwner::GetSettingsDone, + make_scoped_refptr(owner_), + printing_context_->settings(), + result)); } void PrintJobWorker::GetSettingsWithUI( - scoped_ptr web_contents_observer, int document_page_count, bool has_selection) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - gfx::NativeView parent_view = web_contents_observer->GetParentView(); - if (!parent_view) { - GetSettingsWithUIDone(printing::PrintingContext::FAILED); - return; - } printing_context_->AskUserForSettings( - parent_view, document_page_count, has_selection, + document_page_count, + has_selection, base::Bind(&PrintJobWorker::GetSettingsWithUIDone, base::Unretained(this))); } void PrintJobWorker::GetSettingsWithUIDone(PrintingContext::Result result) { - message_loop()->PostTask( - FROM_HERE, - base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), - base::Bind(&PrintJobWorker::GetSettingsDone, - base::Unretained(this), result))); + PostTask(FROM_HERE, + base::Bind(&HoldRefCallback, + make_scoped_refptr(owner_), + base::Bind(&PrintJobWorker::GetSettingsDone, + base::Unretained(this), + result))); } void PrintJobWorker::UseDefaultSettings() { @@ -185,9 +211,9 @@ void PrintJobWorker::UseDefaultSettings() { } void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK_EQ(page_number_, PageNumber::npos()); - DCHECK_EQ(document_, new_document); + DCHECK_EQ(document_.get(), new_document); DCHECK(document_.get()); if (!document_.get() || page_number_ != PageNumber::npos() || @@ -216,7 +242,7 @@ void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { } void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) { - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK_EQ(page_number_, PageNumber::npos()); if (page_number_ != PageNumber::npos()) @@ -230,7 +256,7 @@ void PrintJobWorker::OnNewPage() { return; // message_loop() could return NULL when the print job is cancelled. - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + DCHECK(task_runner_->RunsTasksOnCurrentThread()); if (page_number_ == PageNumber::npos()) { // Find first page to print. @@ -243,15 +269,13 @@ void PrintJobWorker::OnNewPage() { } // We have enough information to initialize page_number_. page_number_.Init(document_->settings(), page_count); - if (destination_.get() != NULL) - destination_->SetPageCount(page_count); } DCHECK_NE(page_number_, PageNumber::npos()); while (true) { // Is the page available? scoped_refptr page = document_->GetPage(page_number_.ToInt()); - if (!page) { + if (!page.get()) { // We need to wait for the page to be available. base::MessageLoop::current()->PostDelayedTask( FROM_HERE, @@ -277,8 +301,33 @@ void PrintJobWorker::Cancel() { // context we run. } +bool PrintJobWorker::IsRunning() const { + return thread_.IsRunning(); +} + +bool PrintJobWorker::PostTask(const tracked_objects::Location& from_here, + const base::Closure& task) { + if (task_runner_.get()) + return task_runner_->PostTask(from_here, task); + return false; +} + +void PrintJobWorker::StopSoon() { + thread_.StopSoon(); +} + +void PrintJobWorker::Stop() { + thread_.Stop(); +} + +bool PrintJobWorker::Start() { + bool result = thread_.Start(); + task_runner_ = thread_.task_runner(); + return result; +} + void PrintJobWorker::OnDocumentDone() { - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK_EQ(page_number_, PageNumber::npos()); DCHECK(document_.get()); @@ -287,24 +336,28 @@ void PrintJobWorker::OnDocumentDone() { return; } - owner_->message_loop()->PostTask( - FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), - JobEventDetails::DOC_DONE, document_, - scoped_refptr())); + owner_->PostTask(FROM_HERE, + base::Bind(&NotificationCallback, + make_scoped_refptr(owner_), + JobEventDetails::DOC_DONE, + document_, + scoped_refptr())); // Makes sure the variables are reinitialized. document_ = NULL; } void PrintJobWorker::SpoolPage(PrintedPage* page) { - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK_NE(page_number_, PageNumber::npos()); // Signal everyone that the page is about to be printed. - owner_->message_loop()->PostTask( - FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), - JobEventDetails::NEW_PAGE, document_, - make_scoped_refptr(page))); + owner_->PostTask(FROM_HERE, + base::Bind(&NotificationCallback, + make_scoped_refptr(owner_), + JobEventDetails::NEW_PAGE, + document_, + make_scoped_refptr(page))); // Preprocess. if (printing_context_->NewPage() != PrintingContext::OK) { @@ -312,18 +365,6 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) { return; } - if (destination_.get() != NULL) { - std::vector metabytes(page->metafile()->GetDataSize()); - bool success = page->metafile()->GetData( - reinterpret_cast(&metabytes[0]), metabytes.size()); - DCHECK(success) << "Failed to get metafile data."; - destination_->SetPageContent( - page->page_number(), - reinterpret_cast(&metabytes[0]), - metabytes.size()); - return; - } - // Actual printing. #if defined(OS_WIN) || defined(OS_MACOSX) document_->RenderPrintedPage(*page, printing_context_->context()); @@ -338,23 +379,26 @@ void PrintJobWorker::SpoolPage(PrintedPage* page) { } // Signal everyone that the page is printed. - owner_->message_loop()->PostTask( - FROM_HERE, - base::Bind(NotificationCallback, make_scoped_refptr(owner_), - JobEventDetails::PAGE_DONE, document_, - make_scoped_refptr(page))); + owner_->PostTask(FROM_HERE, + base::Bind(&NotificationCallback, + make_scoped_refptr(owner_), + JobEventDetails::PAGE_DONE, + document_, + make_scoped_refptr(page))); } void PrintJobWorker::OnFailure() { - DCHECK_EQ(message_loop(), base::MessageLoop::current()); + DCHECK(task_runner_->RunsTasksOnCurrentThread()); // We may loose our last reference by broadcasting the FAILED event. scoped_refptr handle(owner_); - owner_->message_loop()->PostTask( - FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), - JobEventDetails::FAILED, document_, - scoped_refptr())); + owner_->PostTask(FROM_HERE, + base::Bind(&NotificationCallback, + make_scoped_refptr(owner_), + JobEventDetails::FAILED, + document_, + scoped_refptr())); Cancel(); // Makes sure the variables are reinitialized. diff --git a/chromium_src/chrome/browser/printing/print_job_worker.h b/chromium_src/chrome/browser/printing/print_job_worker.h index 2ce01f081a..a8378bb235 100644 --- a/chromium_src/chrome/browser/printing/print_job_worker.h +++ b/chromium_src/chrome/browser/printing/print_job_worker.h @@ -9,12 +9,10 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread.h" +#include "content/public/browser/browser_thread.h" #include "printing/page_number.h" -#include "printing/print_destination_interface.h" -#include "printing/printing_context.h" #include "printing/print_job_constants.h" - -class PrintingUIWebContentsObserver; +#include "printing/printing_context.h" namespace base { class DictionaryValue; @@ -22,39 +20,35 @@ class DictionaryValue; namespace printing { -class PrintedDocument; -class PrintedPage; class PrintJob; class PrintJobWorkerOwner; +class PrintedDocument; +class PrintedPage; // Worker thread code. It manages the PrintingContext, which can be blocking // and/or run a message loop. This is the object that generates most // NOTIFY_PRINT_JOB_EVENT notifications, but they are generated through a // NotificationTask task to be executed from the right thread, the UI thread. // PrintJob always outlives its worker instance. -class PrintJobWorker : public base::Thread { +class PrintJobWorker { public: - explicit PrintJobWorker(PrintJobWorkerOwner* owner); + PrintJobWorker(int render_process_id, + int render_view_id, + PrintJobWorkerOwner* owner); virtual ~PrintJobWorker(); void SetNewOwner(PrintJobWorkerOwner* new_owner); - // Set a destination for print. - // This supercedes the document's rendering destination. - void SetPrintDestination(PrintDestinationInterface* destination); - // Initializes the print settings. If |ask_user_for_settings| is true, a // Print... dialog box will be shown to ask the user his preference. void GetSettings( bool ask_user_for_settings, - scoped_ptr web_contents_observer, int document_page_count, bool has_selection, MarginType margin_type); - // Set the new print settings. This function takes ownership of - // |new_settings|. - void SetSettings(const base::DictionaryValue* const new_settings); + // Set the new print settings. + void SetSettings(scoped_ptr new_settings); // Starts the printing loop. Every pages are printed as soon as the data is // available. Makes sure the new_document is the right one. @@ -71,6 +65,22 @@ class PrintJobWorker : public base::Thread { // This is the only function that can be called in a thread. void Cancel(); + // Returns true if the thread has been started, and not yet stopped. + bool IsRunning() const; + + // Posts the given task to be run. + bool PostTask(const tracked_objects::Location& from_here, + const base::Closure& task); + + // Signals the thread to exit in the near future. + void StopSoon(); + + // Signals the thread to exit and returns once the thread has exited. + void Stop(); + + // Starts the thread. + bool Start(); + protected: // Retrieves the context for testing only. PrintingContext* printing_context() { return printing_context_.get(); } @@ -97,7 +107,6 @@ class PrintJobWorker : public base::Thread { // Required on Mac and Linux. Windows can display UI from non-main threads, // but sticks with this for consistency. void GetSettingsWithUI( - scoped_ptr web_contents_observer, int document_page_count, bool has_selection); @@ -106,9 +115,8 @@ class PrintJobWorker : public base::Thread { // back into the IO thread for GetSettingsDone(). void GetSettingsWithUIDone(PrintingContext::Result result); - // Called on the UI thread to update the print settings. This function takes - // the ownership of |new_settings|. - void UpdatePrintSettings(const base::DictionaryValue* const new_settings); + // Called on the UI thread to update the print settings. + void UpdatePrintSettings(scoped_ptr new_settings); // Reports settings back to owner_. void GetSettingsDone(PrintingContext::Result result); @@ -118,15 +126,15 @@ class PrintJobWorker : public base::Thread { // systems. void UseDefaultSettings(); + // Printing context delegate. + scoped_ptr printing_context_delegate_; + // Information about the printer setting. scoped_ptr printing_context_; // The printed document. Only has read-only access. scoped_refptr document_; - // The print destination, may be NULL. - scoped_refptr destination_; - // The print job owning this worker thread. It is guaranteed to outlive this // object. PrintJobWorkerOwner* owner_; @@ -134,6 +142,12 @@ class PrintJobWorker : public base::Thread { // Current page number to print. PageNumber page_number_; + // Thread to run worker tasks. + base::Thread thread_; + + // Tread-safe pointer to task runner of the |thread_|. + scoped_refptr task_runner_; + // Used to generate a WeakPtr for callbacks. base::WeakPtrFactory weak_factory_; diff --git a/chromium_src/chrome/browser/printing/print_job_worker_owner.cc b/chromium_src/chrome/browser/printing/print_job_worker_owner.cc new file mode 100644 index 0000000000..843ab4616d --- /dev/null +++ b/chromium_src/chrome/browser/printing/print_job_worker_owner.cc @@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/printing/print_job_worker_owner.h" + +#include "base/message_loop/message_loop.h" + +namespace printing { + +PrintJobWorkerOwner::PrintJobWorkerOwner() + : task_runner_(base::MessageLoop::current()->task_runner()) { +} + +PrintJobWorkerOwner::~PrintJobWorkerOwner() { +} + +bool PrintJobWorkerOwner::RunsTasksOnCurrentThread() const { + return task_runner_->RunsTasksOnCurrentThread(); +} + +bool PrintJobWorkerOwner::PostTask(const tracked_objects::Location& from_here, + const base::Closure& task) { + return task_runner_->PostTask(from_here, task); +} + +} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_job_worker_owner.h b/chromium_src/chrome/browser/printing/print_job_worker_owner.h index 8f9f58509f..00a561a39b 100644 --- a/chromium_src/chrome/browser/printing/print_job_worker_owner.h +++ b/chromium_src/chrome/browser/printing/print_job_worker_owner.h @@ -10,8 +10,12 @@ namespace base { class MessageLoop; +class SequencedTaskRunner; } +namespace tracked_objects { +class Location; +} namespace printing { @@ -21,6 +25,8 @@ class PrintSettings; class PrintJobWorkerOwner : public base::RefCountedThreadSafe { public: + PrintJobWorkerOwner(); + // Finishes the initialization began by PrintJobWorker::GetSettings(). // Creates a new PrintedDocument if necessary. Solely meant to be called by // PrintJobWorker. @@ -30,19 +36,29 @@ class PrintJobWorkerOwner // Detach the PrintJobWorker associated to this object. virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) = 0; - // Retrieves the message loop that is expected to process GetSettingsDone. - virtual base::MessageLoop* message_loop() = 0; - // Access the current settings. virtual const PrintSettings& settings() const = 0; // Cookie uniquely identifying the PrintedDocument and/or loaded settings. virtual int cookie() const = 0; + // Returns true if the current thread is a thread on which a task + // may be run, and false if no task will be run on the current + // thread. + bool RunsTasksOnCurrentThread() const; + + // Posts the given task to be run. + bool PostTask(const tracked_objects::Location& from_here, + const base::Closure& task); + protected: friend class base::RefCountedThreadSafe; - virtual ~PrintJobWorkerOwner() {} + virtual ~PrintJobWorkerOwner(); + + // Task runner reference. Used to send notifications in the right + // thread. + scoped_refptr task_runner_; }; } // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.cc b/chromium_src/chrome/browser/printing/print_view_manager_base.cc index db77791ba7..e2cfedd4a2 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.cc +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.cc @@ -24,11 +24,14 @@ #include "content/public/browser/notification_source.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" -#include "grit/generated_resources.h" -#include "printing/metafile_impl.h" +#include "printing/pdf_metafile_skia.h" #include "printing/printed_document.h" #include "ui/base/l10n/l10n_util.h" +#if defined(ENABLE_FULL_PRINTING) +#include "chrome/browser/printing/print_error_dialog.h" +#endif + using base::TimeDelta; using content::BrowserThread; @@ -36,11 +39,6 @@ namespace printing { namespace { -#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING) -// Limits memory usage by raster to 64 MiB. -const int kMaxRasterSizeInPixels = 16*1024*1024; -#endif - } // namespace PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) @@ -50,11 +48,10 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) inside_inner_message_loop_(false), cookie_(0), queue_(g_browser_process->print_job_manager()->queue()) { - DCHECK(queue_); -#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \ - defined(WIN_PDF_METAFILE_FOR_PRINTING) + DCHECK(queue_.get()); +#if !defined(OS_MACOSX) expecting_first_page_ = true; -#endif +#endif // OS_MACOSX printing_enabled_ = true; } @@ -63,10 +60,12 @@ PrintViewManagerBase::~PrintViewManagerBase() { DisconnectFromCurrentPrintJob(); } +#if !defined(DISABLE_BASIC_PRINTING) bool PrintViewManagerBase::PrintNow(bool silent, bool print_background) { return PrintNowInternal(new PrintMsg_PrintPages( routing_id(), silent, print_background)); } +#endif // !DISABLE_BASIC_PRINTING void PrintViewManagerBase::NavigationStopped() { // Cancel the current job, wait for the worker to finish. @@ -117,13 +116,12 @@ void PrintViewManagerBase::OnDidPrintPage( return; } -#if (defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)) || \ - defined(OS_MACOSX) +#if defined(OS_MACOSX) const bool metafile_must_be_valid = true; -#elif defined(OS_POSIX) || defined(WIN_PDF_METAFILE_FOR_PRINTING) +#else const bool metafile_must_be_valid = expecting_first_page_; expecting_first_page_ = false; -#endif +#endif // OS_MACOSX base::SharedMemory shared_buf(params.metafile_data_handle, true); if (metafile_must_be_valid) { @@ -134,7 +132,7 @@ void PrintViewManagerBase::OnDidPrintPage( } } - scoped_ptr metafile(new NativeMetafile); + scoped_ptr metafile(new PdfMetafileSkia); if (metafile_must_be_valid) { if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) { NOTREACHED() << "Invalid metafile header"; @@ -143,32 +141,10 @@ void PrintViewManagerBase::OnDidPrintPage( } } -#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING) - bool big_emf = (params.data_size && params.data_size >= kMetafileMaxSize); - int raster_size = - std::min(params.page_size.GetArea(), kMaxRasterSizeInPixels); - if (big_emf) { - scoped_ptr raster_metafile( - metafile->RasterizeMetafile(raster_size)); - if (raster_metafile.get()) { - metafile.swap(raster_metafile); - } else if (big_emf) { - // Don't fall back to emf here. - NOTREACHED() << "size:" << params.data_size; - TerminatePrintJob(true); - web_contents()->Stop(); - return; - } - } -#endif // OS_WIN && !WIN_PDF_METAFILE_FOR_PRINTING - -#if !defined(WIN_PDF_METAFILE_FOR_PRINTING) +#if !defined(OS_WIN) // Update the rendered document. It will send notifications to the listener. document->SetPage(params.page_number, - metafile.release(), -#if defined(OS_WIN) - params.actual_shrink, -#endif // OS_WIN + metafile.PassAs(), params.page_size, params.content_area); @@ -180,19 +156,8 @@ void PrintViewManagerBase::OnDidPrintPage( params.data_size); document->DebugDumpData(bytes, FILE_PATH_LITERAL(".pdf")); - - if (!pdf_to_emf_converter_) - pdf_to_emf_converter_ = PdfToEmfConverter::CreateDefault(); - - const int kPrinterDpi = print_job_->settings().dpi(); - pdf_to_emf_converter_->Start( - bytes, - printing::PdfRenderSettings(params.content_area, kPrinterDpi, true), - base::Bind(&PrintViewManagerBase::OnPdfToEmfConverted, - base::Unretained(this), - params)); } -#endif // !WIN_PDF_METAFILE_FOR_PRINTING +#endif // !OS_WIN } void PrintViewManagerBase::OnPrintingFailed(int cookie) { @@ -386,10 +351,9 @@ void PrintViewManagerBase::DisconnectFromCurrentPrintJob() { // DO NOT wait for the job to finish. ReleasePrintJob(); } -#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \ - defined(WIN_PDF_METAFILE_FOR_PRINTING) +#if !defined(OS_MACOSX) expecting_first_page_ = true; -#endif +#endif // OS_MACOSX } void PrintViewManagerBase::PrintingDone(bool success) { @@ -481,12 +445,12 @@ bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) { // The job was initiated by a script. Time to get the corresponding worker // thread. scoped_refptr queued_query = queue_->PopPrinterQuery(cookie); - if (!queued_query) { + if (!queued_query.get()) { NOTREACHED(); return false; } - if (!CreateNewPrintJob(queued_query)) { + if (!CreateNewPrintJob(queued_query.get())) { // Don't kill anything. return false; } @@ -512,8 +476,6 @@ void PrintViewManagerBase::ReleasePrinterQuery() { int cookie = cookie_; cookie_ = 0; - queue_->SetDestination(NULL); - printing::PrintJobManager* print_job_manager = g_browser_process->print_job_manager(); @@ -523,7 +485,7 @@ void PrintViewManagerBase::ReleasePrinterQuery() { scoped_refptr printer_query; printer_query = queue_->PopPrinterQuery(cookie); - if (!printer_query) + if (!printer_query.get()) return; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.h b/chromium_src/chrome/browser/printing/print_view_manager_base.h index 61b0fd4400..f9232fdfe8 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.h +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.h @@ -23,7 +23,7 @@ class RenderViewHost; namespace printing { class JobEventDetails; -class PdfToEmfConverter; +class MetafilePlayer; class PrintJob; class PrintJobWorkerOwner; class PrintQueriesQueue; @@ -35,10 +35,12 @@ class PrintViewManagerBase : public content::NotificationObserver, public: virtual ~PrintViewManagerBase(); +#if !defined(DISABLE_BASIC_PRINTING) // Prints the current document immediately. Since the rendering is // asynchronous, the actual printing will not be completed on the return of // this function. Returns false if printing is impossible at the moment. virtual bool PrintNow(bool silent, bool print_background); +#endif // !DISABLE_BASIC_PRINTING // PrintedPagesSource implementation. virtual base::string16 RenderSourceName() OVERRIDE; @@ -140,11 +142,10 @@ class PrintViewManagerBase : public content::NotificationObserver, // print settings are being loaded. bool inside_inner_message_loop_; -#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \ - defined(WIN_PDF_METAFILE_FOR_PRINTING) +#if !defined(OS_MACOSX) // Set to true when OnDidPrintPage() should be expecting the first page. bool expecting_first_page_; -#endif +#endif // OS_MACOSX // The document cookie of the current PrinterQuery. int cookie_; diff --git a/chromium_src/chrome/browser/printing/printer_query.cc b/chromium_src/chrome/browser/printing/printer_query.cc index 6770e575c6..6cd11ff067 100644 --- a/chromium_src/chrome/browser/printing/printer_query.cc +++ b/chromium_src/chrome/browser/printing/printer_query.cc @@ -10,13 +10,11 @@ #include "base/threading/thread_restrictions.h" #include "base/values.h" #include "chrome/browser/printing/print_job_worker.h" -#include "chrome/browser/printing/printing_ui_web_contents_observer.h" namespace printing { -PrinterQuery::PrinterQuery() - : io_message_loop_(base::MessageLoop::current()), - worker_(new PrintJobWorker(this)), +PrinterQuery::PrinterQuery(int render_process_id, int render_view_id) + : worker_(new PrintJobWorker(render_process_id, render_view_id, this)), is_print_dialog_box_shown_(false), cookie_(PrintSettings::NewCookie()), last_status_(PrintingContext::FAILED) { @@ -57,10 +55,6 @@ PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) { return worker_.release(); } -base::MessageLoop* PrinterQuery::message_loop() { - return io_message_loop_; -} - const PrintSettings& PrinterQuery::settings() const { return settings_; } @@ -71,43 +65,34 @@ int PrinterQuery::cookie() const { void PrinterQuery::GetSettings( GetSettingsAskParam ask_user_for_settings, - scoped_ptr web_contents_observer, int expected_page_count, bool has_selection, MarginType margin_type, const base::Closure& callback) { - DCHECK_EQ(io_message_loop_, base::MessageLoop::current()); + DCHECK(RunsTasksOnCurrentThread()); DCHECK(!is_print_dialog_box_shown_); StartWorker(callback); // Real work is done in PrintJobWorker::GetSettings(). is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER; - worker_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PrintJobWorker::GetSettings, - base::Unretained(worker_.get()), - is_print_dialog_box_shown_, - base::Passed(&web_contents_observer), - expected_page_count, - has_selection, - margin_type)); + worker_->PostTask(FROM_HERE, + base::Bind(&PrintJobWorker::GetSettings, + base::Unretained(worker_.get()), + is_print_dialog_box_shown_, + expected_page_count, + has_selection, + margin_type)); } -void PrinterQuery::SetSettings(const base::DictionaryValue& new_settings, +void PrinterQuery::SetSettings(scoped_ptr new_settings, const base::Closure& callback) { StartWorker(callback); - worker_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PrintJobWorker::SetSettings, - base::Unretained(worker_.get()), - new_settings.DeepCopy())); -} - -void PrinterQuery::SetWorkerDestination( - PrintDestinationInterface* destination) { - worker_->SetPrintDestination(destination); + worker_->PostTask(FROM_HERE, + base::Bind(&PrintJobWorker::SetSettings, + base::Unretained(worker_.get()), + base::Passed(&new_settings))); } void PrinterQuery::StartWorker(const base::Closure& callback) { @@ -115,7 +100,7 @@ void PrinterQuery::StartWorker(const base::Closure& callback) { DCHECK(worker_.get()); // Lazily create the worker thread. There is one worker thread per print job. - if (!worker_->message_loop()) + if (!worker_->IsRunning()) worker_->Start(); callback_ = callback; diff --git a/chromium_src/chrome/browser/printing/printer_query.h b/chromium_src/chrome/browser/printing/printer_query.h index aab4914324..22af08d7af 100644 --- a/chromium_src/chrome/browser/printing/printer_query.h +++ b/chromium_src/chrome/browser/printing/printer_query.h @@ -11,11 +11,8 @@ #include "chrome/browser/printing/print_job_worker_owner.h" #include "printing/print_job_constants.h" -class PrintingUIWebContentsObserver; - namespace base { class DictionaryValue; -class MessageLoop; } namespace printing { @@ -32,13 +29,12 @@ class PrinterQuery : public PrintJobWorkerOwner { ASK_USER, }; - PrinterQuery(); + PrinterQuery(int render_process_id, int render_view_id); // PrintJobWorkerOwner implementation. virtual void GetSettingsDone(const PrintSettings& new_settings, PrintingContext::Result result) OVERRIDE; virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE; - virtual base::MessageLoop* message_loop() OVERRIDE; virtual const PrintSettings& settings() const OVERRIDE; virtual int cookie() const OVERRIDE; @@ -48,19 +44,15 @@ class PrinterQuery : public PrintJobWorkerOwner { // |ask_for_user_settings| is DEFAULTS. void GetSettings( GetSettingsAskParam ask_user_for_settings, - scoped_ptr web_contents_observer, int expected_page_count, bool has_selection, MarginType margin_type, const base::Closure& callback); // Updates the current settings with |new_settings| dictionary values. - void SetSettings(const base::DictionaryValue& new_settings, + void SetSettings(scoped_ptr new_settings, const base::Closure& callback); - // Set a destination for the worker. - void SetWorkerDestination(PrintDestinationInterface* destination); - // Stops the worker thread since the client is done with this object. void StopWorker(); @@ -78,10 +70,6 @@ class PrinterQuery : public PrintJobWorkerOwner { // Lazy create the worker thread. There is one worker thread per print job. void StartWorker(const base::Closure& callback); - // Main message loop reference. Used to send notifications in the right - // thread. - base::MessageLoop* const io_message_loop_; - // All the UI is done in a worker thread because many Win32 print functions // are blocking and enters a message loop without your consent. There is one // worker thread per print job. diff --git a/chromium_src/chrome/browser/printing/printing_message_filter.cc b/chromium_src/chrome/browser/printing/printing_message_filter.cc index d10843fe3c..15ca50fba5 100644 --- a/chromium_src/chrome/browser/printing/printing_message_filter.cc +++ b/chromium_src/chrome/browser/printing/printing_message_filter.cc @@ -8,21 +8,56 @@ #include "base/bind.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/printing/printer_query.h" #include "chrome/browser/printing/print_job_manager.h" -#include "chrome/browser/printing/printing_ui_web_contents_observer.h" +#include "chrome/browser/printing/printer_query.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_io_data.h" #include "chrome/common/print_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/child_process_host.h" + +#if defined(ENABLE_FULL_PRINTING) +#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" +#endif + +#if defined(OS_CHROMEOS) +#include + +#include + +#include "base/files/file_util.h" +#include "base/lazy_instance.h" +#include "chrome/browser/printing/print_dialog_cloud.h" +#endif + +#if defined(OS_ANDROID) +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/printing/print_view_manager_basic.h" +#include "printing/printing_context_android.h" +#endif using content::BrowserThread; +namespace printing { + namespace { -void RenderParamsFromPrintSettings(const printing::PrintSettings& settings, +#if defined(OS_CHROMEOS) +typedef std::map SequenceToPathMap; + +struct PrintingSequencePathMap { + SequenceToPathMap map; + int sequence; +}; + +// No locking, only access on the FILE thread. +static base::LazyInstance + g_printing_file_descriptor_map = LAZY_INSTANCE_INITIALIZER; +#endif + +void RenderParamsFromPrintSettings(const PrintSettings& settings, PrintMsg_Print_Params* params) { params->page_size = settings.page_setup_device_units().physical_size(); params->content_size.SetSize( @@ -57,21 +92,45 @@ PrintingMessageFilter::PrintingMessageFilter(int render_process_id) : BrowserMessageFilter(PrintMsgStart), render_process_id_(render_process_id), queue_(g_browser_process->print_job_manager()->queue()) { - DCHECK(queue_); + DCHECK(queue_.get()); } PrintingMessageFilter::~PrintingMessageFilter() { } +void PrintingMessageFilter::OverrideThreadForMessage( + const IPC::Message& message, BrowserThread::ID* thread) { +#if defined(OS_CHROMEOS) + if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID || + message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { + *thread = BrowserThread::FILE; + } +#elif defined(OS_ANDROID) + if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID || + message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { + *thread = BrowserThread::UI; + } +#endif +} + bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilter, message) #if defined(OS_WIN) IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection) +#endif +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) + IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting, + OnAllocateTempFileForPrinting) + IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten, + OnTempFileForPrintingWritten) #endif IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, OnGetDefaultPrintSettings) IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) +#if defined(ENABLE_FULL_PRINTING) + IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel) +#endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -88,6 +147,102 @@ void PrintingMessageFilter::OnDuplicateSection( } #endif +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) +void PrintingMessageFilter::OnAllocateTempFileForPrinting( + int render_view_id, + base::FileDescriptor* temp_file_fd, + int* sequence_number) { +#if defined(OS_CHROMEOS) + // TODO(thestig): Use |render_view_id| for Chrome OS. + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + temp_file_fd->fd = *sequence_number = -1; + temp_file_fd->auto_close = false; + + SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map; + *sequence_number = g_printing_file_descriptor_map.Get().sequence++; + + base::FilePath path; + if (base::CreateTemporaryFile(&path)) { + int fd = open(path.value().c_str(), O_WRONLY); + if (fd >= 0) { + SequenceToPathMap::iterator it = map->find(*sequence_number); + if (it != map->end()) { + NOTREACHED() << "Sequence number already in use. seq=" << + *sequence_number; + } else { + (*map)[*sequence_number] = path; + temp_file_fd->fd = fd; + temp_file_fd->auto_close = true; + } + } + } +#elif defined(OS_ANDROID) + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; + PrintViewManagerBasic* print_view_manager = + PrintViewManagerBasic::FromWebContents(wc); + // The file descriptor is originally created in & passed from the Android + // side, and it will handle the closing. + const base::FileDescriptor& file_descriptor = + print_view_manager->file_descriptor(); + temp_file_fd->fd = file_descriptor.fd; + temp_file_fd->auto_close = false; +#endif +} + +void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id, + int sequence_number) { +#if defined(OS_CHROMEOS) + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map; + SequenceToPathMap::iterator it = map->find(sequence_number); + if (it == map->end()) { + NOTREACHED() << "Got a sequence that we didn't pass to the " + "renderer: " << sequence_number; + return; + } + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&PrintingMessageFilter::CreatePrintDialogForFile, + this, render_view_id, it->second)); + + // Erase the entry in the map. + map->erase(it); +#elif defined(OS_ANDROID) + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; + PrintViewManagerBasic* print_view_manager = + PrintViewManagerBasic::FromWebContents(wc); + const base::FileDescriptor& file_descriptor = + print_view_manager->file_descriptor(); + PrintingContextAndroid::PdfWritingDone(file_descriptor.fd, true); + // Invalidate the file descriptor so it doesn't accidentally get reused. + print_view_manager->set_file_descriptor(base::FileDescriptor(-1, false)); +#endif +} +#endif // defined(OS_CHROMEOS) || defined(OS_ANDROID) + +#if defined(OS_CHROMEOS) +void PrintingMessageFilter::CreatePrintDialogForFile( + int render_view_id, + const base::FilePath& path) { + content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; + print_dialog_cloud::CreatePrintDialogForFile( + wc->GetBrowserContext(), + wc->GetTopLevelNativeWindow(), + path, + wc->GetTitle(), + base::string16(), + std::string("application/pdf")); +} +#endif // defined(OS_CHROMEOS) + content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView( int render_view_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -96,80 +251,41 @@ content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView( return view ? content::WebContents::FromRenderViewHost(view) : NULL; } -struct PrintingMessageFilter::GetPrintSettingsForRenderViewParams { - printing::PrinterQuery::GetSettingsAskParam ask_user_for_settings; - int expected_page_count; - bool has_selection; - printing::MarginType margin_type; -}; - -void PrintingMessageFilter::GetPrintSettingsForRenderView( - int render_view_id, - GetPrintSettingsForRenderViewParams params, - const base::Closure& callback, - scoped_refptr printer_query) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::WebContents* wc = GetWebContentsForRenderView(render_view_id); - if (wc) { - scoped_ptr wc_observer( - new PrintingUIWebContentsObserver(wc)); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&printing::PrinterQuery::GetSettings, printer_query, - params.ask_user_for_settings, base::Passed(&wc_observer), - params.expected_page_count, params.has_selection, - params.margin_type, callback)); - } else { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&PrintingMessageFilter::OnGetPrintSettingsFailed, this, - callback, printer_query)); - } -} - -void PrintingMessageFilter::OnGetPrintSettingsFailed( - const base::Closure& callback, - scoped_refptr printer_query) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - printer_query->GetSettingsDone(printing::PrintSettings(), - printing::PrintingContext::FAILED); - callback.Run(); -} - void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - scoped_refptr printer_query; - if (false) { + scoped_refptr printer_query; +#if 0 + if (!profile_io_data_->printing_enabled()->GetValue()) { // Reply with NULL query. OnGetDefaultPrintSettingsReply(printer_query, reply_msg); return; } +#endif printer_query = queue_->PopPrinterQuery(0); - if (!printer_query) - printer_query = queue_->CreatePrinterQuery(); + if (!printer_query.get()) { + printer_query = + queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); + } // Loads default settings. This is asynchronous, only the IPC message sender // will hang until the settings are retrieved. - GetPrintSettingsForRenderViewParams params; - params.ask_user_for_settings = printing::PrinterQuery::DEFAULTS; - params.expected_page_count = 0; - params.has_selection = false; - params.margin_type = printing::DEFAULT_MARGINS; - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this, - reply_msg->routing_id(), params, - base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply, - this, printer_query, reply_msg), - printer_query)); + printer_query->GetSettings( + PrinterQuery::DEFAULTS, + 0, + false, + DEFAULT_MARGINS, + base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply, + this, + printer_query, + reply_msg)); } void PrintingMessageFilter::OnGetDefaultPrintSettingsReply( - scoped_refptr printer_query, + scoped_refptr printer_query, IPC::Message* reply_msg) { PrintMsg_Print_Params params; if (!printer_query.get() || - printer_query->last_status() != printing::PrintingContext::OK) { + printer_query->last_status() != PrintingContext::OK) { params.Reset(); } else { RenderParamsFromPrintSettings(printer_query->settings(), ¶ms); @@ -191,43 +307,69 @@ void PrintingMessageFilter::OnGetDefaultPrintSettingsReply( void PrintingMessageFilter::OnScriptedPrint( const PrintHostMsg_ScriptedPrint_Params& params, IPC::Message* reply_msg) { - scoped_refptr printer_query = + scoped_refptr printer_query = queue_->PopPrinterQuery(params.cookie); - if (!printer_query) - printer_query = queue_->CreatePrinterQuery(); - GetPrintSettingsForRenderViewParams settings_params; - settings_params.ask_user_for_settings = printing::PrinterQuery::ASK_USER; - settings_params.expected_page_count = params.expected_pages_count; - settings_params.has_selection = params.has_selection; - settings_params.margin_type = params.margin_type; - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this, - reply_msg->routing_id(), settings_params, - base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this, - printer_query, reply_msg), - printer_query)); + if (!printer_query.get()) { + printer_query = + queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); + } + printer_query->GetSettings( + PrinterQuery::ASK_USER, + params.expected_pages_count, + params.has_selection, + params.margin_type, + base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, + this, + printer_query, + reply_msg)); } void PrintingMessageFilter::OnScriptedPrintReply( - scoped_refptr printer_query, + scoped_refptr printer_query, IPC::Message* reply_msg) { PrintMsg_PrintPages_Params params; - if (printer_query->last_status() != printing::PrintingContext::OK || +#if defined(OS_ANDROID) + // We need to save the routing ID here because Send method below deletes the + // |reply_msg| before we can get the routing ID for the Android code. + int routing_id = reply_msg->routing_id(); +#endif + if (printer_query->last_status() != PrintingContext::OK || !printer_query->settings().dpi()) { params.Reset(); } else { RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params); params.params.document_cookie = printer_query->cookie(); - params.pages = - printing::PageRange::GetPages(printer_query->settings().ranges()); + params.pages = PageRange::GetPages(printer_query->settings().ranges()); } PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params); Send(reply_msg); if (params.params.dpi && params.params.document_cookie) { +#if defined(OS_ANDROID) + int file_descriptor; + const base::string16& device_name = printer_query->settings().device_name(); + if (base::StringToInt(device_name, &file_descriptor)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this, + routing_id, file_descriptor)); + } +#endif queue_->QueuePrinterQuery(printer_query.get()); } else { printer_query->StopWorker(); } } + +#if defined(OS_ANDROID) +void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; + PrintViewManagerBasic* print_view_manager = + PrintViewManagerBasic::FromWebContents(wc); + print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false)); +} +#endif + +} // namespace printing diff --git a/chromium_src/chrome/browser/printing/printing_message_filter.h b/chromium_src/chrome/browser/printing/printing_message_filter.h index 8a9d9c2d1e..5f437864c1 100644 --- a/chromium_src/chrome/browser/printing/printing_message_filter.h +++ b/chromium_src/chrome/browser/printing/printing_message_filter.h @@ -15,6 +15,8 @@ #endif struct PrintHostMsg_ScriptedPrint_Params; +class Profile; +class ProfileIOData; namespace base { class DictionaryValue; @@ -26,18 +28,21 @@ class WebContents; } namespace printing { -class PrinterQuery; + class PrintJobManager; class PrintQueriesQueue; -} +class PrinterQuery; // This class filters out incoming printing related IPC messages for the // renderer process on the IPC thread. class PrintingMessageFilter : public content::BrowserMessageFilter { public: - explicit PrintingMessageFilter(int render_process_id); + PrintingMessageFilter(int render_process_id); // content::BrowserMessageFilter methods. + virtual void OverrideThreadForMessage( + const IPC::Message& message, + content::BrowserThread::ID* thread) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; private: @@ -49,6 +54,25 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { base::SharedMemoryHandle* browser_handle); #endif +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) + // Used to ask the browser allocate a temporary file for the renderer + // to fill in resulting PDF in renderer. + void OnAllocateTempFileForPrinting(int render_view_id, + base::FileDescriptor* temp_file_fd, + int* sequence_number); + void OnTempFileForPrintingWritten(int render_view_id, int sequence_number); +#endif + +#if defined(OS_CHROMEOS) + void CreatePrintDialogForFile(int render_view_id, const base::FilePath& path); +#endif + +#if defined(OS_ANDROID) + // Updates the file descriptor for the PrintViewManagerBasic of a given + // render_view_id. + void UpdateFileDescriptor(int render_view_id, int fd); +#endif + // Given a render_view_id get the corresponding WebContents. // Must be called on the UI thread. content::WebContents* GetWebContentsForRenderView(int render_view_id); @@ -59,38 +83,33 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { // to base::Bind. struct GetPrintSettingsForRenderViewParams; - // Retrieve print settings. Uses |render_view_id| to get a parent - // for any UI created if needed. - void GetPrintSettingsForRenderView( - int render_view_id, - GetPrintSettingsForRenderViewParams params, - const base::Closure& callback, - scoped_refptr printer_query); - - void OnGetPrintSettingsFailed( - const base::Closure& callback, - scoped_refptr printer_query); - // Get the default print setting. void OnGetDefaultPrintSettings(IPC::Message* reply_msg); - void OnGetDefaultPrintSettingsReply( - scoped_refptr printer_query, - IPC::Message* reply_msg); + void OnGetDefaultPrintSettingsReply(scoped_refptr printer_query, + IPC::Message* reply_msg); // The renderer host have to show to the user the print dialog and returns // the selected print settings. The task is handled by the print worker // thread and the UI thread. The reply occurs on the IO thread. void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& params, IPC::Message* reply_msg); - void OnScriptedPrintReply( - scoped_refptr printer_query, - IPC::Message* reply_msg); + void OnScriptedPrintReply(scoped_refptr printer_query, + IPC::Message* reply_msg); + +#if defined(ENABLE_FULL_PRINTING) + // Check to see if print preview has been cancelled. + void OnCheckForCancel(int32 preview_ui_id, + int preview_request_id, + bool* cancel); +#endif const int render_process_id_; - scoped_refptr queue_; + scoped_refptr queue_; DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter); }; +} // namespace printing + #endif // CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc b/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc deleted file mode 100644 index 151117314c..0000000000 --- a/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h" - -#include - -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "chrome/browser/ui/libgtk2ui/menu_util.h" -#include "ui/base/models/menu_model.h" - -namespace libgtk2ui { - -AppIndicatorIconMenu::AppIndicatorIconMenu(ui::MenuModel* model) - : menu_model_(model), - click_action_replacement_menu_item_added_(false), - gtk_menu_(NULL), - block_activation_(false) { - { - ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/378770 - gtk_menu_ = gtk_menu_new(); - } - g_object_ref_sink(gtk_menu_); - if (menu_model_) { - BuildSubmenuFromModel(menu_model_, - gtk_menu_, - G_CALLBACK(OnMenuItemActivatedThunk), - &block_activation_, - this); - Refresh(); - } -} - -AppIndicatorIconMenu::~AppIndicatorIconMenu() { - gtk_widget_destroy(gtk_menu_); - g_object_unref(gtk_menu_); -} - -void AppIndicatorIconMenu::UpdateClickActionReplacementMenuItem( - const char* label, - const base::Closure& callback) { - click_action_replacement_callback_ = callback; - - if (click_action_replacement_menu_item_added_) { - GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_)); - for (GList* child = children; child; child = g_list_next(child)) { - if (g_object_get_data(G_OBJECT(child->data), "click-action-item") != - NULL) { - gtk_menu_item_set_label(GTK_MENU_ITEM(child->data), label); - break; - } - } - g_list_free(children); - } else { - click_action_replacement_menu_item_added_ = true; - - // If |menu_model_| is non empty, add a separator to separate the - // "click action replacement menu item" from the other menu items. - if (menu_model_ && menu_model_->GetItemCount() > 0) { - GtkWidget* menu_item = gtk_separator_menu_item_new(); - gtk_widget_show(menu_item); - gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item); - } - - GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(label); - g_object_set_data( - G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1)); - g_signal_connect(menu_item, - "activate", - G_CALLBACK(OnClickActionReplacementMenuItemActivatedThunk), - this); - gtk_widget_show(menu_item); - gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item); - } -} - -void AppIndicatorIconMenu::Refresh() { - gtk_container_foreach( - GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_); -} - -GtkMenu* AppIndicatorIconMenu::GetGtkMenu() { - return GTK_MENU(gtk_menu_); -} - - -void AppIndicatorIconMenu::OnClickActionReplacementMenuItemActivated( - GtkWidget* menu_item) { - click_action_replacement_callback_.Run(); -} - -void AppIndicatorIconMenu::OnMenuItemActivated(GtkWidget* menu_item) { - if (block_activation_) - return; - - ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item)); - if (!model) { - // There won't be a model for "native" submenus like the "Input Methods" - // context menu. We don't need to handle activation messages for submenus - // anyway, so we can just return here. - DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item))); - return; - } - - // The activate signal is sent to radio items as they get deselected; - // ignore it in this case. - if (GTK_IS_RADIO_MENU_ITEM(menu_item) && - !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) { - return; - } - - int id; - if (!GetMenuItemID(menu_item, &id)) - return; - - // The menu item can still be activated by hotkeys even if it is disabled. - if (menu_model_->IsEnabledAt(id)) - ExecuteCommand(model, id); -} - -} // namespace libgtk2ui diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h b/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h deleted file mode 100644 index a204710f9c..0000000000 --- a/chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_ -#define CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_ - -#include "base/callback.h" -#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" - -typedef struct _GtkMenu GtkMenu; -typedef struct _GtkWidget GtkWidget; - -namespace ui { -class MenuModel; -} - -namespace libgtk2ui { - -// The app indicator icon's menu. -class AppIndicatorIconMenu { - public: - explicit AppIndicatorIconMenu(ui::MenuModel* model); - virtual ~AppIndicatorIconMenu(); - - // Sets a menu item at the top of |gtk_menu_| as a replacement for the app - // indicator icon's click action. |callback| is called when the menu item - // is activated. - void UpdateClickActionReplacementMenuItem(const char* label, - const base::Closure& callback); - - // Refreshes all the menu item labels and menu item checked/enabled states. - void Refresh(); - - GtkMenu* GetGtkMenu(); - - private: - // Callback for when the "click action replacement" menu item is activated. - CHROMEGTK_CALLBACK_0(AppIndicatorIconMenu, - void, - OnClickActionReplacementMenuItemActivated); - - // Callback for when a menu item is activated. - CHROMEGTK_CALLBACK_0(AppIndicatorIconMenu, void, OnMenuItemActivated); - - // Not owned. - ui::MenuModel* menu_model_; - - // Whether a "click action replacement" menu item has been added to the menu. - bool click_action_replacement_menu_item_added_; - - // Called when the click action replacement menu item is activated. When a - // menu item from |menu_model_| is activated, MenuModel::ActivatedAt() is - // invoked and is assumed to do any necessary processing. - base::Closure click_action_replacement_callback_; - - GtkWidget* gtk_menu_; - - bool block_activation_; - - DISALLOW_COPY_AND_ASSIGN(AppIndicatorIconMenu); -}; - -} // namespace libgtk2ui - -#endif // CHROME_BROWSER_UI_LIBGTK2UI_APP_INDICATOR_ICON_MENU_H_ diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc b/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc deleted file mode 100644 index 2838bff2ea..0000000000 --- a/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/libgtk2ui/gtk2_status_icon.h" - -#include - -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h" -#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" -#include "ui/base/models/menu_model.h" -#include "ui/gfx/image/image_skia.h" - -namespace libgtk2ui { - -Gtk2StatusIcon::Gtk2StatusIcon(const gfx::ImageSkia& image, - const base::string16& tool_tip) { - GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*image.bitmap()); - gtk_status_icon_ = gtk_status_icon_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - - g_signal_connect(gtk_status_icon_, "activate", G_CALLBACK(OnClickThunk), - this); - g_signal_connect(gtk_status_icon_, "popup_menu", - G_CALLBACK(OnContextMenuRequestedThunk), this); - SetToolTip(tool_tip); -} - -Gtk2StatusIcon::~Gtk2StatusIcon() { - g_object_unref(gtk_status_icon_); -} - -void Gtk2StatusIcon::SetImage(const gfx::ImageSkia& image) { - GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*image.bitmap()); - gtk_status_icon_set_from_pixbuf(gtk_status_icon_, pixbuf); - g_object_unref(pixbuf); -} - -void Gtk2StatusIcon::SetPressedImage(const gfx::ImageSkia& image) { - // Ignore pressed images, since the standard on Linux is to not highlight - // pressed status icons. -} - -void Gtk2StatusIcon::SetToolTip(const base::string16& tool_tip) { - gtk_status_icon_set_tooltip_text(gtk_status_icon_, - base::UTF16ToUTF8(tool_tip).c_str()); -} - -void Gtk2StatusIcon::UpdatePlatformContextMenu(ui::MenuModel* model) { - menu_.reset(); - if (model) - menu_.reset(new AppIndicatorIconMenu(model)); -} - -void Gtk2StatusIcon::RefreshPlatformContextMenu() { - if (menu_.get()) - menu_->Refresh(); -} - -void Gtk2StatusIcon::OnClick(GtkStatusIcon* status_icon) { - if (delegate()) - delegate()->OnClick(); -} - -void Gtk2StatusIcon::OnContextMenuRequested(GtkStatusIcon* status_icon, - guint button, - guint32 activate_time) { - if (menu_.get()) { - gtk_menu_popup(menu_->GetGtkMenu(), - NULL, - NULL, - gtk_status_icon_position_menu, - gtk_status_icon_, - button, - activate_time); - } -} - -} // namespace libgtk2ui diff --git a/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h b/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h deleted file mode 100644 index d25b487b62..0000000000 --- a/chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_ -#define CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_ - -#include "base/memory/scoped_ptr.h" -#include "base/strings/string16.h" -#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" -#include "ui/base/glib/glib_integers.h" -#include "ui/base/glib/glib_signal.h" -#include "ui/views/linux_ui/status_icon_linux.h" - -typedef struct _GtkStatusIcon GtkStatusIcon; - -namespace gfx { -class ImageSkia; -} - -namespace ui { -class MenuModel; -} - -namespace libgtk2ui { -class AppIndicatorIconMenu; - -// Status icon implementation which uses the system tray X11 spec (via -// GtkStatusIcon). -class Gtk2StatusIcon : public views::StatusIconLinux { - public: - Gtk2StatusIcon(const gfx::ImageSkia& image, const base::string16& tool_tip); - virtual ~Gtk2StatusIcon(); - - // Overridden from views::StatusIconLinux: - virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE; - virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE; - virtual void SetToolTip(const base::string16& tool_tip) OVERRIDE; - virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE; - virtual void RefreshPlatformContextMenu() OVERRIDE; - - private: - CHROMEG_CALLBACK_0(Gtk2StatusIcon, void, OnClick, GtkStatusIcon*); - - CHROMEG_CALLBACK_2(Gtk2StatusIcon, - void, - OnContextMenuRequested, - GtkStatusIcon*, - guint, - guint); - - GtkStatusIcon* gtk_status_icon_; - - scoped_ptr menu_; - - DISALLOW_COPY_AND_ASSIGN(Gtk2StatusIcon); -}; - -} // namespace libgtk2ui - -#endif // CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_ diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index df9e287cdc..4e25da8629 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -22,8 +22,7 @@ #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" #include "net/base/escape.h" -#include "printing/metafile.h" -#include "printing/metafile_impl.h" +#include "printing/pdf_metafile_skia.h" #include "printing/units.h" #include "skia/ext/vector_platform_device_skia.h" #include "third_party/WebKit/public/platform/WebSize.h" @@ -65,7 +64,8 @@ bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) { return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() && !params.printable_area.IsEmpty() && params.document_cookie && params.desired_dpi && params.max_shrink && params.min_shrink && - params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0); + params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0) && + params.dpi > kMinDpi && params.document_cookie != 0; } PrintMsg_Print_Params GetCssPrintParams( @@ -409,8 +409,6 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, return expected_pages_count_; } - gfx::Size GetPrintCanvasSize() const; - void FinishPrinting(); bool IsLoadingSelection() { @@ -590,12 +588,6 @@ void PrepareFrameAndViewForPrint::CallOnReady() { return on_ready_.Run(); // Can delete |this|. } -gfx::Size PrepareFrameAndViewForPrint::GetPrintCanvasSize() const { - DCHECK(is_printing_started_); - return gfx::Size(web_print_params_.printContentArea.width, - web_print_params_.printContentArea.height); -} - void PrepareFrameAndViewForPrint::RestoreSize() { if (frame()) { blink::WebView* web_view = frame_.GetFrame()->view(); @@ -606,7 +598,7 @@ void PrepareFrameAndViewForPrint::RestoreSize() { } void PrepareFrameAndViewForPrint::FinishPrinting() { - blink::WebFrame* frame = frame_.GetFrame(); + blink::WebLocalFrame* frame = frame_.GetFrame(); if (frame) { blink::WebView* web_view = frame->view(); if (is_printing_started_) { @@ -630,10 +622,15 @@ void PrepareFrameAndViewForPrint::FinishPrinting() { PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view) : content::RenderViewObserver(render_view), content::RenderViewObserverTracker(render_view), + reset_prep_frame_view_(false), is_print_ready_metafile_sent_(false), ignore_css_margins_(false), + is_scripted_printing_blocked_(false), notify_browser_of_print_failure_(true), + print_for_preview_(false), print_node_in_progress_(false), + is_loading_(false), + is_scripted_preview_delayed_(false), weak_ptr_factory_(this) { } @@ -673,11 +670,13 @@ bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame** frame) { return true; } +#if !defined(DISABLE_BASIC_PRINTING) void PrintWebViewHelper::OnPrintPages(bool silent, bool print_background) { blink::WebLocalFrame* frame; if (GetPrintFrame(&frame)) Print(frame, blink::WebNode(), silent, print_background); } +#endif // !DISABLE_BASIC_PRINTING void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout( const PageSizeMargins& page_layout_in_points, @@ -726,9 +725,6 @@ void PrintWebViewHelper::PrintNode(const blink::WebNode& node) { } print_node_in_progress_ = true; - - // Make a copy of the node, in case RenderView::OnContextMenuClosed resets - // its |context_menu_node_|. blink::WebNode duplicate_node(node); Print(duplicate_node.document().frame(), duplicate_node); @@ -783,7 +779,7 @@ void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) { break; case FAIL_PRINT: - if (notify_browser_of_print_failure_ && print_pages_params_.get()) { + if (notify_browser_of_print_failure_ && print_pages_params_) { int cookie = print_pages_params_->params.document_cookie; Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie)); } @@ -821,8 +817,7 @@ void PrintWebViewHelper::PrintPages() { page_count)); #endif // !defined(OS_CHROMEOS) - if (!PrintPagesNative(prep_frame_view_->frame(), page_count, - prep_frame_view_->GetPrintCanvasSize())) { + if (!PrintPagesNative(prep_frame_view_->frame(), page_count)) { LOG(ERROR) << "Printing failed."; return DidFinishPrinting(FAIL_PRINT); } @@ -832,10 +827,9 @@ void PrintWebViewHelper::FinishFramePrinting() { prep_frame_view_.reset(); } -#if defined(OS_MACOSX) || defined(OS_WIN) +#if defined(OS_MACOSX) bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, - int page_count, - const gfx::Size& canvas_size) { + int page_count) { const PrintMsg_PrintPages_Params& params = *print_pages_params_; const PrintMsg_Print_Params& print_params = params.params; @@ -844,20 +838,20 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, if (params.pages.empty()) { for (int i = 0; i < page_count; ++i) { page_params.page_number = i; - PrintPageInternal(page_params, canvas_size, frame); + PrintPageInternal(page_params, frame); } } else { for (size_t i = 0; i < params.pages.size(); ++i) { if (params.pages[i] >= page_count) break; page_params.page_number = params.pages[i]; - PrintPageInternal(page_params, canvas_size, frame); + PrintPageInternal(page_params, frame); } } return true; } -#endif // OS_MACOSX || OS_WIN +#endif // OS_MACOSX // static - Not anonymous so that platform implementations can use it. void PrintWebViewHelper::ComputePageLayoutInPointsForCss( @@ -886,13 +880,6 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) { if (!PrintMsg_Print_Params_IsValid(settings.params)) result = false; - if (result && - (settings.params.dpi < kMinDpi || settings.params.document_cookie == 0)) { - // Invalid print page settings. - NOTREACHED(); - result = false; - } - // Reset to default values. ignore_css_margins_ = false; settings.pages.clear(); @@ -904,7 +891,7 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) { blink::WebPrintScalingOptionFitToPrintableArea; } - print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings)); + SetPrintPagesParams(settings); return result; } @@ -923,8 +910,6 @@ bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame, PrepareFrameAndViewForPrint prepare(params, frame, node, ignore_css_margins_); prepare.StartPrinting(); - Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(), - params.document_cookie)); *number_of_pages = prepare.GetExpectedPageCount(); return true; } @@ -953,9 +938,8 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame, new PrintHostMsg_ScriptedPrint(routing_id(), params, &print_settings); msg->EnableMessagePumping(); Send(msg); - print_pages_params_.reset(new PrintMsg_PrintPages_Params(print_settings)); - - print_pages_params_->params.print_scaling_option = scaling_option; + print_settings.params.print_scaling_option = scaling_option; + SetPrintPagesParams(print_settings); return (print_settings.params.dpi && print_settings.params.document_cookie); } @@ -965,9 +949,8 @@ bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame, return false; const PrintMsg_PrintPages_Params& params = *print_pages_params_; const PrintMsg_Print_Params& print_params = params.params; - prep_frame_view_.reset( - new PrepareFrameAndViewForPrint(print_params, frame, node, - ignore_css_margins_)); + prep_frame_view_.reset(new PrepareFrameAndViewForPrint( + print_params, frame, node, ignore_css_margins_)); DCHECK(!print_pages_params_->params.selection_only || print_pages_params_->pages.empty()); prep_frame_view_->CopySelectionIfNeeded( @@ -979,24 +962,27 @@ bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame, #if defined(OS_POSIX) bool PrintWebViewHelper::CopyMetafileDataToSharedMem( - Metafile* metafile, + PdfMetafileSkia* metafile, base::SharedMemoryHandle* shared_mem_handle) { uint32 buf_size = metafile->GetDataSize(); scoped_ptr shared_buf( content::RenderThread::Get()->HostAllocateSharedMemoryBuffer( buf_size).release()); - if (shared_buf.get()) { + if (shared_buf) { if (shared_buf->Map(buf_size)) { metafile->GetData(shared_buf->memory(), buf_size); - shared_buf->GiveToProcess(base::GetCurrentProcessHandle(), - shared_mem_handle); - return true; + return shared_buf->GiveToProcess(base::GetCurrentProcessHandle(), + shared_mem_handle); } } - NOTREACHED(); return false; } #endif // defined(OS_POSIX) +void PrintWebViewHelper::SetPrintPagesParams( + const PrintMsg_PrintPages_Params& settings) { + print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings)); +} + } // namespace printing diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.h b/chromium_src/chrome/renderer/printing/print_web_view_helper.h index 9ae64be20b..17b8cb05b6 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.h +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.h @@ -7,13 +7,15 @@ #include +#include "base/callback.h" +#include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/memory/shared_memory.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "content/public/renderer/render_view_observer.h" #include "content/public/renderer/render_view_observer_tracker.h" -#include "printing/metafile_impl.h" +#include "printing/pdf_metafile_skia.h" #include "third_party/WebKit/public/platform/WebCanvas.h" #include "third_party/WebKit/public/web/WebNode.h" #include "third_party/WebKit/public/web/WebPrintParams.h" @@ -22,6 +24,7 @@ struct PrintMsg_Print_Params; struct PrintMsg_PrintPage_Params; struct PrintMsg_PrintPages_Params; +struct PrintHostMsg_SetOptionsFromDocument_Params; namespace base { class DictionaryValue; @@ -81,8 +84,10 @@ class PrintWebViewHelper bool user_initiated) OVERRIDE; // Message handlers --------------------------------------------------------- +#if !defined(DISABLE_BASIC_PRINTING) void OnPrintPages(bool silent, bool print_background); void OnPrintingDone(bool success); +#endif // !DISABLE_BASIC_PRINTING // Get |page_size| and |content_area| information from // |page_layout_in_points|. @@ -125,20 +130,22 @@ class PrintWebViewHelper void OnFramePreparedForPrintPages(); void PrintPages(); - bool PrintPagesNative(blink::WebFrame* frame, - int page_count, - const gfx::Size& canvas_size); + bool PrintPagesNative(blink::WebFrame* frame, int page_count); void FinishFramePrinting(); // Prints the page listed in |params|. #if defined(OS_LINUX) || defined(OS_ANDROID) void PrintPageInternal(const PrintMsg_PrintPage_Params& params, - const gfx::Size& canvas_size, blink::WebFrame* frame, - Metafile* metafile); + PdfMetafileSkia* metafile); +#elif defined(OS_WIN) + void PrintPageInternal(const PrintMsg_PrintPage_Params& params, + blink::WebFrame* frame, + PdfMetafileSkia* metafile, + gfx::Size* page_size_in_dpi, + gfx::Rect* content_area_in_dpi); #else void PrintPageInternal(const PrintMsg_PrintPage_Params& params, - const gfx::Size& canvas_size, blink::WebFrame* frame); #endif @@ -147,24 +154,15 @@ class PrintWebViewHelper const blink::WebNode& node); // Platform specific helper function for rendering page(s) to |metafile|. -#if defined(OS_WIN) +#if defined(OS_MACOSX) void RenderPage(const PrintMsg_Print_Params& params, int page_number, blink::WebFrame* frame, bool is_preview, - Metafile* metafile, - double* scale_factor, - gfx::Size* page_size_in_dpi, - gfx::Rect* content_area_in_dpi); -#elif defined(OS_MACOSX) - void RenderPage(const PrintMsg_Print_Params& params, - int page_number, - blink::WebFrame* frame, - bool is_preview, - Metafile* metafile, + PdfMetafileSkia* metafile, gfx::Size* page_size, gfx::Rect* content_rect); -#endif // defined(OS_WIN) +#endif // defined(OS_MACOSX) // Renders page contents from |frame| to |content_area| of |canvas|. // |page_number| is zero-based. @@ -179,7 +177,7 @@ class PrintWebViewHelper // Helper methods ----------------------------------------------------------- - bool CopyMetafileDataToSharedMem(Metafile* metafile, + bool CopyMetafileDataToSharedMem(PdfMetafileSkia* metafile, base::SharedMemoryHandle* shared_mem_handle); // Helper method to get page layout in points and fit to page if needed. @@ -195,18 +193,35 @@ class PrintWebViewHelper // Script Initiated Printing ------------------------------------------------ + void SetPrintPagesParams(const PrintMsg_PrintPages_Params& settings); + // WebView used only to print the selection. scoped_ptr prep_frame_view_; + bool reset_prep_frame_view_; scoped_ptr print_pages_params_; bool is_print_ready_metafile_sent_; bool ignore_css_margins_; + // Used for scripted initiated printing blocking. + bool is_scripted_printing_blocked_; + // Let the browser process know of a printing failure. Only set to false when // the failure came from the browser in the first place. bool notify_browser_of_print_failure_; + // True, when printing from print preview. + bool print_for_preview_; + bool print_node_in_progress_; + bool is_loading_; + bool is_scripted_preview_delayed_; + + // Used to fix a race condition where the source is a PDF and print preview + // hangs because RequestPrintPreview is called before DidStopLoading() is + // called. This is a store for the RequestPrintPreview() call and its + // parameters so that it can be invoked after DidStopLoading. + base::Closure on_stop_loading_closure_; base::WeakPtrFactory weak_ptr_factory_; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc index bf5dfd7039..c42467d45c 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc @@ -8,10 +8,9 @@ #include "base/memory/scoped_ptr.h" #include "chrome/common/print_messages.h" #include "content/public/renderer/render_thread.h" -#include "printing/metafile.h" -#include "printing/metafile_impl.h" #include "printing/metafile_skia_wrapper.h" #include "printing/page_size_margins.h" +#include "printing/pdf_metafile_skia.h" #include "skia/ext/platform_device.h" #include "skia/ext/vector_canvas.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -27,9 +26,8 @@ namespace printing { using blink::WebFrame; bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, - int page_count, - const gfx::Size& canvas_size) { - NativeMetafile metafile; + int page_count) { + PdfMetafileSkia metafile; if (!metafile.Init()) return false; @@ -56,7 +54,7 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, page_params.params = params.params; for (size_t i = 0; i < printed_pages.size(); ++i) { page_params.page_number = printed_pages[i]; - PrintPageInternal(page_params, canvas_size, frame, &metafile); + PrintPageInternal(page_params, frame, &metafile); } // blink::printEnd() for PDF should be called before metafile is closed. @@ -119,9 +117,8 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, void PrintWebViewHelper::PrintPageInternal( const PrintMsg_PrintPage_Params& params, - const gfx::Size& canvas_size, WebFrame* frame, - Metafile* metafile) { + PdfMetafileSkia* metafile) { PageSizeMargins page_layout_in_points; double scale_factor = 1.0f; ComputePageLayoutInPointsForCss(frame, params.page_number, params.params, diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm index ddd91c88c5..9565269a0b 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm @@ -10,8 +10,6 @@ #include "base/mac/scoped_nsautorelease_pool.h" #include "base/metrics/histogram.h" #include "chrome/common/print_messages.h" -#include "printing/metafile.h" -#include "printing/metafile_impl.h" #include "printing/metafile_skia_wrapper.h" #include "printing/page_size_margins.h" #include "skia/ext/platform_device.h" @@ -25,9 +23,8 @@ using blink::WebFrame; void PrintWebViewHelper::PrintPageInternal( const PrintMsg_PrintPage_Params& params, - const gfx::Size& canvas_size, WebFrame* frame) { - NativeMetafile metafile; + PdfMetafileSkia metafile; if (!metafile.Init()) return; @@ -54,10 +51,13 @@ void PrintWebViewHelper::PrintPageInternal( Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params)); } -void PrintWebViewHelper::RenderPage( - const PrintMsg_Print_Params& params, int page_number, WebFrame* frame, - bool is_preview, Metafile* metafile, gfx::Size* page_size, - gfx::Rect* content_rect) { +void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params, + int page_number, + WebFrame* frame, + bool is_preview, + PdfMetafileSkia* metafile, + gfx::Size* page_size, + gfx::Rect* content_rect) { double scale_factor = 1.0f; double webkit_shrink_factor = frame->getPrintPageShrink(page_number); PageSizeMargins page_layout_in_points; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc new file mode 100644 index 0000000000..21e0c26e28 --- /dev/null +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc @@ -0,0 +1,250 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/printing/print_web_view_helper.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/process/process_handle.h" +#include "chrome/common/print_messages.h" +#include "content/public/renderer/render_thread.h" +#include "printing/metafile_skia_wrapper.h" +#include "printing/page_size_margins.h" +#include "printing/pdf_metafile_skia.h" +#include "printing/units.h" +#include "skia/ext/platform_device.h" +#include "skia/ext/vector_canvas.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" + + +namespace printing { + +using blink::WebFrame; + +#if 0 +bool PrintWebViewHelper::RenderPreviewPage( + int page_number, + const PrintMsg_Print_Params& print_params) { + PrintMsg_PrintPage_Params page_params; + page_params.params = print_params; + page_params.page_number = page_number; + scoped_ptr draft_metafile; + PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); + if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { + draft_metafile.reset(new PdfMetafileSkia); + initial_render_metafile = draft_metafile.get(); + } + + base::TimeTicks begin_time = base::TimeTicks::Now(); + PrintPageInternal(page_params, + print_preview_context_.prepared_frame(), + initial_render_metafile, + NULL, + NULL); + print_preview_context_.RenderedPreviewPage( + base::TimeTicks::Now() - begin_time); + if (draft_metafile.get()) { + draft_metafile->FinishDocument(); + } else if (print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages()) { + DCHECK(!draft_metafile.get()); + draft_metafile = + print_preview_context_.metafile()->GetMetafileForCurrentPage(); + } + return PreviewPageRendered(page_number, draft_metafile.get()); +} +#endif + +bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, + int page_count) { + PdfMetafileSkia metafile; + if (!metafile.Init()) + return false; + + const PrintMsg_PrintPages_Params& params = *print_pages_params_; + std::vector printed_pages; + if (params.pages.empty()) { + for (int i = 0; i < page_count; ++i) { + printed_pages.push_back(i); + } + } else { + // TODO(vitalybuka): redesign to make more code cross platform. + for (size_t i = 0; i < params.pages.size(); ++i) { + if (params.pages[i] >= 0 && params.pages[i] < page_count) { + printed_pages.push_back(params.pages[i]); + } + } + } + if (printed_pages.empty()) + return false; + + std::vector page_size_in_dpi(printed_pages.size()); + std::vector content_area_in_dpi(printed_pages.size()); + + PrintMsg_PrintPage_Params page_params; + page_params.params = params.params; + for (size_t i = 0; i < printed_pages.size(); ++i) { + page_params.page_number = printed_pages[i]; + PrintPageInternal(page_params, + frame, + &metafile, + &page_size_in_dpi[i], + &content_area_in_dpi[i]); + } + + // blink::printEnd() for PDF should be called before metafile is closed. + FinishFramePrinting(); + + metafile.FinishDocument(); + + // Get the size of the resulting metafile. + uint32 buf_size = metafile.GetDataSize(); + DCHECK_GT(buf_size, 0u); + + PrintHostMsg_DidPrintPage_Params printed_page_params; + printed_page_params.data_size = 0; + printed_page_params.document_cookie = params.params.document_cookie; + printed_page_params.page_size = params.params.page_size; + printed_page_params.content_area = params.params.printable_area; + + { + base::SharedMemory shared_buf; + // Allocate a shared memory buffer to hold the generated metafile data. + if (!shared_buf.CreateAndMapAnonymous(buf_size)) { + NOTREACHED() << "Buffer allocation failed"; + return false; + } + + // Copy the bits into shared memory. + if (!metafile.GetData(shared_buf.memory(), buf_size)) { + NOTREACHED() << "GetData() failed"; + shared_buf.Unmap(); + return false; + } + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), + &printed_page_params.metafile_data_handle); + shared_buf.Unmap(); + + printed_page_params.data_size = buf_size; + Send(new PrintHostMsg_DuplicateSection( + routing_id(), + printed_page_params.metafile_data_handle, + &printed_page_params.metafile_data_handle)); + } + + for (size_t i = 0; i < printed_pages.size(); ++i) { + printed_page_params.page_number = printed_pages[i]; + printed_page_params.page_size = page_size_in_dpi[i]; + printed_page_params.content_area = content_area_in_dpi[i]; + Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params)); + printed_page_params.metafile_data_handle = INVALID_HANDLE_VALUE; + } + return true; +} + +void PrintWebViewHelper::PrintPageInternal( + const PrintMsg_PrintPage_Params& params, + WebFrame* frame, + PdfMetafileSkia* metafile, + gfx::Size* page_size_in_dpi, + gfx::Rect* content_area_in_dpi) { + PageSizeMargins page_layout_in_points; + double css_scale_factor = 1.0f; + ComputePageLayoutInPointsForCss(frame, params.page_number, params.params, + ignore_css_margins_, &css_scale_factor, + &page_layout_in_points); + gfx::Size page_size; + gfx::Rect content_area; + GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size, + &content_area); + int dpi = static_cast(params.params.dpi); + // Calculate the actual page size and content area in dpi. + if (page_size_in_dpi) { + *page_size_in_dpi = + gfx::Size(static_cast(ConvertUnitDouble( + page_size.width(), kPointsPerInch, dpi)), + static_cast(ConvertUnitDouble( + page_size.height(), kPointsPerInch, dpi))); + } + + if (content_area_in_dpi) { + // Output PDF matches paper size and should be printer edge to edge. + *content_area_in_dpi = + gfx::Rect(0, 0, page_size_in_dpi->width(), page_size_in_dpi->height()); + } + + gfx::Rect canvas_area = + content_area; +#if 0 + params.params.display_header_footer ? gfx::Rect(page_size) : content_area; +#endif + + float webkit_page_shrink_factor = + frame->getPrintPageShrink(params.page_number); + float scale_factor = css_scale_factor * webkit_page_shrink_factor; + + SkBaseDevice* device = metafile->StartPageForVectorCanvas(page_size, + canvas_area, + scale_factor); + if (!device) + return; + + // The printPage method take a reference to the canvas we pass down, so it + // can't be a stack object. + skia::RefPtr canvas = + skia::AdoptRef(new skia::VectorCanvas(device)); + MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); + skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_); + +#if 0 + if (params.params.display_header_footer) { + // |page_number| is 0-based, so 1 is added. + PrintHeaderAndFooter(canvas.get(), + params.page_number + 1, + print_preview_context_.total_page_count(), + *frame, + scale_factor, + page_layout_in_points, + params.params); + } +#endif + + float webkit_scale_factor = RenderPageContent(frame, + params.page_number, + canvas_area, + content_area, + scale_factor, + canvas.get()); + DCHECK_GT(webkit_scale_factor, 0.0f); + // Done printing. Close the device context to retrieve the compiled metafile. + if (!metafile->FinishPage()) + NOTREACHED() << "metafile failed"; +} + +bool PrintWebViewHelper::CopyMetafileDataToSharedMem( + PdfMetafileSkia* metafile, + base::SharedMemoryHandle* shared_mem_handle) { + uint32 buf_size = metafile->GetDataSize(); + base::SharedMemory shared_buf; + // Allocate a shared memory buffer to hold the generated metafile data. + if (!shared_buf.CreateAndMapAnonymous(buf_size)) { + NOTREACHED() << "Buffer allocation failed"; + return false; + } + + // Copy the bits into shared memory. + if (!metafile->GetData(shared_buf.memory(), buf_size)) { + NOTREACHED() << "GetData() failed"; + shared_buf.Unmap(); + return false; + } + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle); + shared_buf.Unmap(); + + Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle, + shared_mem_handle)); + return true; +} + +} // namespace printing diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_win.cc deleted file mode 100644 index 4c1a78332c..0000000000 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_win.cc +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/renderer/printing/print_web_view_helper.h" - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram.h" -#include "base/process/process_handle.h" -#include "base/win/scoped_gdi_object.h" -#include "base/win/scoped_hdc.h" -#include "base/win/scoped_select_object.h" -#include "chrome/common/print_messages.h" -#include "printing/metafile.h" -#include "printing/metafile_impl.h" -#include "printing/metafile_skia_wrapper.h" -#include "printing/page_size_margins.h" -#include "printing/units.h" -#include "skia/ext/platform_device.h" -#include "skia/ext/refptr.h" -#include "skia/ext/vector_canvas.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "ui/gfx/gdi_util.h" -#include "ui/gfx/point.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/size.h" - -namespace printing { - -using blink::WebFrame; - -void PrintWebViewHelper::PrintPageInternal( - const PrintMsg_PrintPage_Params& params, - const gfx::Size& canvas_size, - WebFrame* frame) { - // Generate a memory-based metafile. It will use the current screen's DPI. - // Each metafile contains a single page. - scoped_ptr metafile(new NativeMetafile); - metafile->Init(); - DCHECK(metafile->context()); - skia::InitializeDC(metafile->context()); - - int page_number = params.page_number; - - // Calculate the dpi adjustment. - // Browser will render context using desired_dpi, so we need to calculate - // adjustment factor to play content on the printer DC later during the - // actual printing. - double actual_shrink = static_cast(params.params.desired_dpi / - params.params.dpi); - gfx::Size page_size_in_dpi; - gfx::Rect content_area_in_dpi; - - // Render page for printing. - RenderPage(params.params, page_number, frame, false, metafile.get(), - &actual_shrink, &page_size_in_dpi, &content_area_in_dpi); - - // Close the device context to retrieve the compiled metafile. - if (!metafile->FinishDocument()) - NOTREACHED(); - - if (!params.params.supports_alpha_blend && metafile->IsAlphaBlendUsed()) { - scoped_ptr raster_metafile( - metafile->RasterizeAlphaBlend()); - if (raster_metafile.get()) - metafile.swap(raster_metafile); - } - - // Get the size of the compiled metafile. - uint32 buf_size = metafile->GetDataSize(); - DCHECK_GT(buf_size, 128u); - - PrintHostMsg_DidPrintPage_Params page_params; - page_params.data_size = buf_size; - page_params.metafile_data_handle = NULL; - page_params.page_number = page_number; - page_params.document_cookie = params.params.document_cookie; - page_params.actual_shrink = actual_shrink; - page_params.page_size = page_size_in_dpi; - page_params.content_area = content_area_in_dpi; - - if (!CopyMetafileDataToSharedMem(metafile.get(), - &(page_params.metafile_data_handle))) { - page_params.data_size = 0; - } - - Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params)); -} - -void PrintWebViewHelper::RenderPage( - const PrintMsg_Print_Params& params, int page_number, WebFrame* frame, - bool is_preview, Metafile* metafile, double* actual_shrink, - gfx::Size* page_size_in_dpi, gfx::Rect* content_area_in_dpi) { - PageSizeMargins page_layout_in_points; - double css_scale_factor = 1.0f; - ComputePageLayoutInPointsForCss(frame, page_number, params, - ignore_css_margins_, &css_scale_factor, - &page_layout_in_points); - gfx::Size page_size; - gfx::Rect content_area; - GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size, - &content_area); - int dpi = static_cast(params.dpi); - // Calculate the actual page size and content area in dpi. - if (page_size_in_dpi) { - *page_size_in_dpi = gfx::Size( - static_cast(ConvertUnitDouble(page_size.width(), kPointsPerInch, - dpi)), - static_cast(ConvertUnitDouble(page_size.height(), kPointsPerInch, - dpi))); - } - - if (content_area_in_dpi) { - *content_area_in_dpi = gfx::Rect( - static_cast(ConvertUnitDouble(content_area.x(), kPointsPerInch, - dpi)), - static_cast(ConvertUnitDouble(content_area.y(), kPointsPerInch, - dpi)), - static_cast(ConvertUnitDouble(content_area.width(), kPointsPerInch, - dpi)), - static_cast(ConvertUnitDouble(content_area.height(), - kPointsPerInch, dpi))); - } - - float webkit_page_shrink_factor = frame->getPrintPageShrink(page_number); - float scale_factor = css_scale_factor * webkit_page_shrink_factor; - - gfx::Rect canvas_area = content_area; - - SkBaseDevice* device = metafile->StartPageForVectorCanvas( - page_size, canvas_area, scale_factor); - DCHECK(device); - // The printPage method may take a reference to the canvas we pass down, so it - // can't be a stack object. - skia::RefPtr canvas = - skia::AdoptRef(new skia::VectorCanvas(device)); - - float webkit_scale_factor = RenderPageContent(frame, page_number, canvas_area, - content_area, scale_factor, - canvas.get()); - - if (*actual_shrink <= 0 || webkit_scale_factor <= 0) { - NOTREACHED() << "Printing page " << page_number << " failed."; - } else { - // While rendering certain plugins (PDF) to metafile, we might need to - // set custom scale factor. Update |actual_shrink| with custom scale - // if it is set on canvas. - // TODO(gene): We should revisit this solution for the next versions. - // Consider creating metafile of the right size (or resizable) - // https://code.google.com/p/chromium/issues/detail?id=126037 - if (!MetafileSkiaWrapper::GetCustomScaleOnCanvas( - *canvas, actual_shrink)) { - // Update the dpi adjustment with the "page |actual_shrink|" calculated in - // webkit. - *actual_shrink /= (webkit_scale_factor * css_scale_factor); - } - } - - bool result = metafile->FinishPage(); - DCHECK(result); -} - -bool PrintWebViewHelper::CopyMetafileDataToSharedMem( - Metafile* metafile, base::SharedMemoryHandle* shared_mem_handle) { - uint32 buf_size = metafile->GetDataSize(); - base::SharedMemory shared_buf; - if (buf_size >= kMetafileMaxSize) { - NOTREACHED() << "Buffer too large: " << buf_size; - return false; - } - - // Allocate a shared memory buffer to hold the generated metafile data. - if (!shared_buf.CreateAndMapAnonymous(buf_size)) { - NOTREACHED() << "Buffer allocation failed"; - return false; - } - - // Copy the bits into shared memory. - if (!metafile->GetData(shared_buf.memory(), buf_size)) { - NOTREACHED() << "GetData() failed"; - shared_buf.Unmap(); - return false; - } - shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle); - shared_buf.Unmap(); - - Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle, - shared_mem_handle)); - return true; -} - -} // namespace printing diff --git a/common.gypi b/common.gypi index 2bf92e790e..7ee6d494a4 100644 --- a/common.gypi +++ b/common.gypi @@ -6,12 +6,9 @@ ['OS=="mac" or OS=="linux"', { 'clang': 1, }], - ['OS=="win" and (MSVS_VERSION=="2013e" or MSVS_VERSION=="2012e" or MSVS_VERSION=="2010e")', { - 'msvs_express': 1, - },{ - 'msvs_express': 0, - }], ], + # Required by breakpad. + 'os_bsd': 0, # Reflects node's config.gypi. 'component%': 'static_library', 'python': 'python', @@ -33,6 +30,7 @@ 'uv_parent_path': 'vendor/node/deps/uv', 'uv_use_dtrace': 'false', 'v8_postmortem_support': 'false', + 'v8_enable_i18n_support': 'false', # Required by Linux (empty for now, should support it in future). 'sysroot': '', }, diff --git a/package.json b/package.json index 88d258e125..a0b42404df 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "devDependencies": { - "atom-package-manager": "0.111.0", + "atom-package-manager": "0.112.0", "coffee-script": "~1.7.1", "coffeelint": "~1.3.0" }, diff --git a/script/bootstrap.py b/script/bootstrap.py index 5f288dce1c..c2554e213a 100755 --- a/script/bootstrap.py +++ b/script/bootstrap.py @@ -21,18 +21,18 @@ def main(): args = parse_args() if args.verbose: enable_verbose_mode() - update_submodules() - update_node_modules('.') - update_atom_modules('spec') - bootstrap_brightray(args.url) if sys.platform == 'cygwin': update_win32_python() + update_submodules() + update_node_modules('.') + bootstrap_brightray(args.url) if sys.platform in ['win32', 'cygwin']: install_runas() create_chrome_version_h() touch_config_gypi() update_atom_shell() + update_atom_modules('spec') def parse_args(): diff --git a/script/create-dist.py b/script/create-dist.py index e623b088c6..8a83c954e7 100755 --- a/script/create-dist.py +++ b/script/create-dist.py @@ -36,16 +36,16 @@ TARGET_BINARIES = { 'atom.exe', 'chromiumcontent.dll', 'content_shell.pak', - 'd3dcompiler_43.dll', + 'd3dcompiler_46.dll', 'ffmpegsumo.dll', 'icudtl.dat', 'libEGL.dll', 'libGLESv2.dll', 'msvcp120.dll', 'msvcr120.dll', + 'content_resources_200_percent.pak', 'ui_resources_200_percent.pak', 'vccorlib120.dll', - 'webkit_resources_200_percent.pak', 'xinput1_3.dll', ], 'linux': [ diff --git a/script/lib/config.py b/script/lib/config.py index 395fcd36ea..c90fc6be4e 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -4,7 +4,7 @@ import platform import sys BASE_URL = 'https://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = 'bb95d5c7958c649bb346d59a13ee0d8f15464304' +LIBCHROMIUMCONTENT_COMMIT = 'aa87035cc012ce0d533bb56b947bca81a6e71b82' ARCH = { 'cygwin': '32bit', diff --git a/script/update-external-binaries.py b/script/update-external-binaries.py index 5bb980118d..80f0df5717 100755 --- a/script/update-external-binaries.py +++ b/script/update-external-binaries.py @@ -7,7 +7,7 @@ import os from lib.util import safe_mkdir, rm_rf, extract_zip, tempdir, download -VERSION = 'v0.2.0' +VERSION = 'v0.3.0' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) FRAMEWORKS_URL = 'https://github.com/atom/atom-shell-frameworks/releases' \ '/download/' + VERSION @@ -28,7 +28,6 @@ def main(): download_and_unzip('ReactiveCocoa') download_and_unzip('Squirrel') elif sys.platform in ['cygwin', 'win32']: - download_and_unzip('atl') download_and_unzip('directxsdk') download_and_unzip('vs2012_crt') diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee index 09e0542c90..5bf3adcbe1 100644 --- a/spec/api-browser-window-spec.coffee +++ b/spec/api-browser-window-spec.coffee @@ -208,12 +208,3 @@ describe 'browser-window module', -> w.once 'minimize', -> done() w.show() w.minimize() - - describe 'restore event', -> - return if isCI and process.platform is 'linux' - it 'emits when window is restored', (done) -> - @timeout 10000 - w.once 'restore', -> done() - w.show() - w.minimize() - w.restore() diff --git a/spec/api-crash-reporter-spec.coffee b/spec/api-crash-reporter-spec.coffee index 43f7b2f035..c9aa025ca3 100644 --- a/spec/api-crash-reporter-spec.coffee +++ b/spec/api-crash-reporter-spec.coffee @@ -8,6 +8,9 @@ formidable = require 'formidable' BrowserWindow = remote.require 'browser-window' describe 'crash-reporter module', -> + # We have trouble makeing crash reporter work on Yosemite. + return if process.platform is 'darwin' + fixtures = path.resolve __dirname, 'fixtures' w = null diff --git a/tools/make_locale_paks.py b/tools/make_locale_paks.py new file mode 100755 index 0000000000..70597f54ab --- /dev/null +++ b/tools/make_locale_paks.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +# usage: make_locale_paks build_dir [...] +# +# This script creates the .pak files under locales directory, it is used to fool +# the ResourcesBundle that the locale is available. + +import errno +import sys +import os + + +def main(): + target_dir = sys.argv[1] + locale_dir = os.path.join(target_dir, 'locales') + safe_mkdir(locale_dir) + for pak in sys.argv[2:]: + touch(os.path.join(locale_dir, pak + '.pak')) + + +def touch(filename): + with open(filename, 'w+'): + pass + + +def safe_mkdir(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/posix/make_locale_paks.sh b/tools/posix/make_locale_paks.sh deleted file mode 100755 index 6f66a04e86..0000000000 --- a/tools/posix/make_locale_paks.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# usage: make_locale_paks locale_dir [...] -# -# This script creates the .pak files under locales directory, it is used to fool -# the ResourcesBundle that the locale is available. - -set -eu - -if [[ ${#} -eq 0 ]]; then - echo "usage: ${0} build_dir [locale_pak...]" >& 2 - exit 1 -fi - -PRODUCT_DIR="$1" -shift - -LOCALES_DIR="${PRODUCT_DIR}/locales" -if [[ ! -d "${LOCALES_DIR}" ]]; then - mkdir "${LOCALES_DIR}" -fi - -cd "${LOCALES_DIR}" - -for pak in "${@}"; do - if [[ ! -f "${pak}.pak" ]]; then - touch "${pak}.pak" - fi -done diff --git a/vendor/breakpad b/vendor/breakpad index 2483f32da1..1e937567e9 160000 --- a/vendor/breakpad +++ b/vendor/breakpad @@ -1 +1 @@ -Subproject commit 2483f32da1f729ac362fbbcaa9173843379697e9 +Subproject commit 1e937567e92d2c3beed4556f3c68a4b0362b1e6d diff --git a/vendor/brightray b/vendor/brightray index f7bde92364..d54838e3f5 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit f7bde923647448b1ae25fa4c1e3596d93febb7cf +Subproject commit d54838e3f5211e986424f4e82e24f1960b60594a diff --git a/vendor/node b/vendor/node index 6403ce1c2f..296b2c198b 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 6403ce1c2ff752e81c1145112fa73f9273b8e73a +Subproject commit 296b2c198be867ed89144acb20bd3570ce375cf5