mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
506237f5d6 | ||
|
|
609e3ec3ff | ||
|
|
640c8f88ff | ||
|
|
d0ed681643 | ||
|
|
5656714b27 | ||
|
|
ecb9e93394 | ||
|
|
708e738521 | ||
|
|
8457090b18 | ||
|
|
513052de87 | ||
|
|
d65919d896 | ||
|
|
895ccf69a7 | ||
|
|
3063b5189a | ||
|
|
335cd79b37 | ||
|
|
e3bad233e9 | ||
|
|
7abb08cc25 | ||
|
|
31bdfc2281 | ||
|
|
bf14f67cb8 | ||
|
|
ef7a60807b | ||
|
|
f17673be9c | ||
|
|
079f81b304 | ||
|
|
ab83b21fa6 | ||
|
|
3d7da455bc | ||
|
|
ac8a9afada | ||
|
|
8faab22f5e | ||
|
|
40679ae82c | ||
|
|
f972c38bc8 | ||
|
|
e1f0f02da9 | ||
|
|
b4d9c92705 | ||
|
|
44b932f90b | ||
|
|
c5411c3291 | ||
|
|
7dc8ede90f | ||
|
|
b94375c794 | ||
|
|
45c2cda6bb | ||
|
|
5c65f037b0 | ||
|
|
de55d8c292 | ||
|
|
a9d67e9715 | ||
|
|
9bd517e623 | ||
|
|
22d5d40a66 | ||
|
|
3f307ea8a6 | ||
|
|
ded58b8e65 | ||
|
|
a23218c51d | ||
|
|
70225009af | ||
|
|
80bea0766e | ||
|
|
54933f992a | ||
|
|
c0bf2facca | ||
|
|
d642fe6075 | ||
|
|
e7dfd48b1c | ||
|
|
90b2d12371 | ||
|
|
f6c66e7ece | ||
|
|
c6a18b1b59 | ||
|
|
6cdc8e4b96 | ||
|
|
598060dfd8 | ||
|
|
b801a93dc5 | ||
|
|
dc9329ff43 | ||
|
|
a61331a083 | ||
|
|
f1fbc5c701 | ||
|
|
896077222d | ||
|
|
47d7a355f2 | ||
|
|
a1ae399d10 | ||
|
|
48b0d85f54 | ||
|
|
423d269187 | ||
|
|
da54ac5f55 | ||
|
|
a26091e485 | ||
|
|
40ab21d9df | ||
|
|
947e6aca9b | ||
|
|
c92d2531b5 | ||
|
|
6d168b89ef | ||
|
|
55c8206bda | ||
|
|
c01e3cf9aa | ||
|
|
040049f9e7 | ||
|
|
2fc1e2a4e6 | ||
|
|
eaacf0a6ef | ||
|
|
c2975d2bcc | ||
|
|
60df32aab5 | ||
|
|
fd596d4a65 | ||
|
|
5142b7858b | ||
|
|
a8f5a4e2d4 | ||
|
|
d46300587a | ||
|
|
64a41b65bb | ||
|
|
275ac2c4b6 | ||
|
|
c0285747a2 | ||
|
|
95793e410d | ||
|
|
31d606220e | ||
|
|
4fc14959a8 | ||
|
|
95dd73bd1d | ||
|
|
5bed184014 | ||
|
|
4fa7e8e914 | ||
|
|
63e83a7ef8 | ||
|
|
c20e1e9d82 | ||
|
|
253bacdf1d | ||
|
|
98127ba13c | ||
|
|
cb911b19dd | ||
|
|
d50eeb04d5 | ||
|
|
1641caf353 | ||
|
|
23951e6ef3 | ||
|
|
c9a5c6515c | ||
|
|
0ab32bfe17 | ||
|
|
3d30e6ddc4 | ||
|
|
ffdf2f7fcf | ||
|
|
974415f8a1 | ||
|
|
3105092130 | ||
|
|
85b0885af7 | ||
|
|
11cd301127 | ||
|
|
654d21100f | ||
|
|
5bd924a52d | ||
|
|
186d34c33a | ||
|
|
b0a414ea83 | ||
|
|
099eb53d3c | ||
|
|
e3ccb18696 | ||
|
|
e38614ce31 | ||
|
|
290dd4ccd8 | ||
|
|
1bebf1cc2c | ||
|
|
d8d9dea792 | ||
|
|
7457f81283 | ||
|
|
158d8efb8e | ||
|
|
0b668b8e17 | ||
|
|
5437470b4e | ||
|
|
409f2b4d0f | ||
|
|
64edede20d | ||
|
|
6624fd9a1b | ||
|
|
1cdbb6f186 | ||
|
|
f57533fa0e | ||
|
|
2db7c84cbc | ||
|
|
cefc846e9e | ||
|
|
1853bef39a | ||
|
|
22c4911b58 | ||
|
|
e58b3ddc86 | ||
|
|
e3ba17f2d3 | ||
|
|
7d1830d014 | ||
|
|
da3a988c8c | ||
|
|
9d23cce2b6 | ||
|
|
68381e1b76 | ||
|
|
3493d2c701 | ||
|
|
9e1d3f9e27 | ||
|
|
7fdd94520e | ||
|
|
9fcb6b2cd1 | ||
|
|
cbafac774e | ||
|
|
7f5fb4e6f9 | ||
|
|
ac51207860 | ||
|
|
aa3be09ab0 | ||
|
|
4348143fd9 | ||
|
|
b6b8b936f2 | ||
|
|
2c27b953b5 | ||
|
|
d7eae69587 | ||
|
|
e0f1433c12 | ||
|
|
27710cd4f7 | ||
|
|
4d5bbbc2d7 | ||
|
|
da900b3094 | ||
|
|
0f29d9f30f | ||
|
|
b88824a70c | ||
|
|
882a08f61a | ||
|
|
a9072049ea | ||
|
|
e87876671f | ||
|
|
d0f6c89e77 | ||
|
|
8eab230fe1 | ||
|
|
7ff95ec255 | ||
|
|
20afd51a9d | ||
|
|
19bba5c18c | ||
|
|
bf4c219766 | ||
|
|
a5e1d8c97f | ||
|
|
7bc364a374 | ||
|
|
5dd73e74cb | ||
|
|
ba347f6460 | ||
|
|
85cf8f9174 | ||
|
|
2153e018a3 | ||
|
|
3f4fec0864 | ||
|
|
10823eeeaa | ||
|
|
25ea169c72 | ||
|
|
743e8331b5 | ||
|
|
d309fd5a27 | ||
|
|
091357ad8e | ||
|
|
3d4491a468 | ||
|
|
6d32db32ef | ||
|
|
357f5f9781 | ||
|
|
a0f5544a07 |
79
atom.gyp
79
atom.gyp
@@ -3,9 +3,8 @@
|
||||
'includes': [
|
||||
'vendor/native_mate/native_mate_files.gypi',
|
||||
],
|
||||
'project_name': 'atom',
|
||||
'product_name': 'Atom',
|
||||
'framework_name': 'Atom Framework',
|
||||
'project_name%': 'atom',
|
||||
'product_name%': 'Atom',
|
||||
'app_sources': [
|
||||
'atom/app/atom_main.cc',
|
||||
'atom/app/atom_main.h',
|
||||
@@ -44,11 +43,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',
|
||||
@@ -237,6 +238,7 @@
|
||||
'atom/common/native_mate_converters/gurl_converter.h',
|
||||
'atom/common/native_mate_converters/image_converter.cc',
|
||||
'atom/common/native_mate_converters/image_converter.h',
|
||||
'atom/common/native_mate_converters/image_converter_mac.mm',
|
||||
'atom/common/native_mate_converters/string16_converter.h',
|
||||
'atom/common/native_mate_converters/v8_value_converter.cc',
|
||||
'atom/common/native_mate_converters/v8_value_converter.h',
|
||||
@@ -258,10 +260,12 @@
|
||||
'atom/common/platform_util_mac.mm',
|
||||
'atom/common/platform_util_win.cc',
|
||||
'atom/renderer/api/atom_api_renderer_ipc.cc',
|
||||
'atom/renderer/api/atom_renderer_bindings.cc',
|
||||
'atom/renderer/api/atom_renderer_bindings.h',
|
||||
'atom/renderer/api/atom_api_spell_check_client.cc',
|
||||
'atom/renderer/api/atom_api_spell_check_client.h',
|
||||
'atom/renderer/api/atom_api_web_frame.cc',
|
||||
'atom/renderer/api/atom_api_web_frame.h',
|
||||
'atom/renderer/api/atom_renderer_bindings.cc',
|
||||
'atom/renderer/api/atom_renderer_bindings.h',
|
||||
'atom/renderer/atom_render_view_observer.cc',
|
||||
'atom/renderer/atom_render_view_observer.h',
|
||||
'atom/renderer/atom_renderer_client.cc',
|
||||
@@ -283,6 +287,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',
|
||||
@@ -293,8 +298,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',
|
||||
@@ -309,10 +312,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',
|
||||
@@ -323,8 +322,10 @@
|
||||
'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/spellchecker/spellcheck_worditerator.cc',
|
||||
'chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h',
|
||||
'chromium_src/chrome/renderer/tts_dispatcher.cc',
|
||||
'chromium_src/chrome/renderer/tts_dispatcher.h',
|
||||
'chromium_src/library_loaders/libgio_loader.cc',
|
||||
@@ -419,7 +420,7 @@
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Frameworks',
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/<(product_name) Helper.app',
|
||||
'<(PRODUCT_DIR)/<(framework_name).framework',
|
||||
'<(PRODUCT_DIR)/<(product_name) Framework.framework',
|
||||
'external_binaries/Squirrel.framework',
|
||||
'external_binaries/ReactiveCocoa.framework',
|
||||
'external_binaries/Mantle.framework',
|
||||
@@ -480,10 +481,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',
|
||||
@@ -527,8 +528,11 @@
|
||||
'vendor/node/node.gyp:node_lib',
|
||||
],
|
||||
'defines': [
|
||||
'PRODUCT_NAME="<(product_name)"',
|
||||
# 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)',
|
||||
@@ -782,7 +786,7 @@
|
||||
'targets': [
|
||||
{
|
||||
'target_name': '<(project_name)_framework',
|
||||
'product_name': '<(framework_name)',
|
||||
'product_name': '<(product_name) Framework',
|
||||
'type': 'shared_library',
|
||||
'dependencies': [
|
||||
'<(project_name)_lib',
|
||||
@@ -818,7 +822,7 @@
|
||||
'LIBRARY_SEARCH_PATHS': [
|
||||
'<(libchromiumcontent_library_dir)',
|
||||
],
|
||||
'LD_DYLIB_INSTALL_NAME': '@rpath/<(framework_name).framework/<(framework_name)',
|
||||
'LD_DYLIB_INSTALL_NAME': '@rpath/<(product_name) Framework.framework/<(product_name) Framework',
|
||||
'LD_RUNPATH_SEARCH_PATHS': [
|
||||
'@loader_path/Libraries',
|
||||
],
|
||||
@@ -828,14 +832,14 @@
|
||||
},
|
||||
'copies': [
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(framework_name).framework/Versions/A/Libraries',
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Libraries',
|
||||
'files': [
|
||||
'<(libchromiumcontent_library_dir)/ffmpegsumo.so',
|
||||
'<(libchromiumcontent_library_dir)/libchromiumcontent.dylib',
|
||||
],
|
||||
},
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(framework_name).framework/Versions/A/Resources',
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/Inspector',
|
||||
'<(PRODUCT_DIR)/crash_report_sender.app',
|
||||
@@ -847,7 +851,7 @@
|
||||
'postbuild_name': 'Add symlinks for framework subdirectories',
|
||||
'action': [
|
||||
'tools/mac/create-framework-subdir-symlinks.sh',
|
||||
'<(framework_name)',
|
||||
'<(product_name) Framework',
|
||||
'Libraries',
|
||||
'Frameworks',
|
||||
],
|
||||
@@ -885,13 +889,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)',
|
||||
],
|
||||
@@ -933,31 +938,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
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@@ -23,14 +23,15 @@ base::FilePath GetFrameworksPath() {
|
||||
|
||||
void AtomMainDelegate::OverrideFrameworkBundlePath() {
|
||||
base::mac::SetOverrideFrameworkBundlePath(
|
||||
GetFrameworksPath().Append("Atom Framework.framework"));
|
||||
GetFrameworksPath().Append(PRODUCT_NAME " Framework.framework"));
|
||||
}
|
||||
|
||||
void AtomMainDelegate::OverrideChildProcessPath() {
|
||||
base::FilePath helper_path = GetFrameworksPath().Append("Atom Helper.app")
|
||||
.Append("Contents")
|
||||
.Append("MacOS")
|
||||
.Append("Atom Helper");
|
||||
base::FilePath helper_path =
|
||||
GetFrameworksPath().Append(PRODUCT_NAME " Helper.app")
|
||||
.Append("Contents")
|
||||
.Append("MacOS")
|
||||
.Append(PRODUCT_NAME " Helper");
|
||||
PathService::Override(content::CHILD_PROCESS_EXE, helper_path);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,14 +69,17 @@ void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> 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)));
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
@@ -40,21 +41,27 @@ namespace {
|
||||
|
||||
void ShowMessageBox(int type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const std::vector<std::string>& texts,
|
||||
const gfx::ImageSkia& icon,
|
||||
atom::NativeWindow* window,
|
||||
mate::Arguments* args) {
|
||||
// FIXME We are exceeding the parameters limit of base::Bind here, so we have
|
||||
// to pass some parameters in an array. We should remove this once we have
|
||||
// variadic template support in base::Bind.
|
||||
const std::string& title = texts[0];
|
||||
const std::string& message = texts[1];
|
||||
const std::string& detail = texts[2];
|
||||
|
||||
v8::Handle<v8::Value> peek = args->PeekNext();
|
||||
atom::MessageBoxCallback callback;
|
||||
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, title,
|
||||
message, detail, callback);
|
||||
message, detail, icon, callback);
|
||||
} else {
|
||||
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
|
||||
buttons, title, message, detail);
|
||||
buttons, title, message, detail, icon);
|
||||
args->Return(chosen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -19,7 +20,7 @@ namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
Tray::Tray(const gfx::ImageSkia& image)
|
||||
Tray::Tray(const gfx::Image& image)
|
||||
: tray_icon_(TrayIcon::Create()) {
|
||||
tray_icon_->SetImage(image);
|
||||
tray_icon_->AddObserver(this);
|
||||
@@ -29,7 +30,7 @@ Tray::~Tray() {
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Wrappable* Tray::New(const gfx::ImageSkia& image) {
|
||||
mate::Wrappable* Tray::New(const gfx::Image& image) {
|
||||
return new Tray(image);
|
||||
}
|
||||
|
||||
@@ -57,13 +58,13 @@ void Tray::Destroy() {
|
||||
tray_icon_.reset();
|
||||
}
|
||||
|
||||
void Tray::SetImage(mate::Arguments* args, const gfx::ImageSkia& image) {
|
||||
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetImage(image);
|
||||
}
|
||||
|
||||
void Tray::SetPressedImage(mate::Arguments* args, const gfx::ImageSkia& image) {
|
||||
void Tray::SetPressedImage(mate::Arguments* args, const gfx::Image& image) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetPressedImage(image);
|
||||
@@ -92,7 +93,7 @@ void Tray::DisplayBalloon(mate::Arguments* args,
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
|
||||
gfx::ImageSkia icon;
|
||||
gfx::Image icon;
|
||||
options.Get("icon", &icon);
|
||||
base::string16 title, content;
|
||||
if (!options.Get("title", &title) ||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
namespace gfx {
|
||||
class ImageSkia;
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
@@ -31,13 +31,13 @@ class Menu;
|
||||
class Tray : public mate::EventEmitter,
|
||||
public TrayIconObserver {
|
||||
public:
|
||||
static mate::Wrappable* New(const gfx::ImageSkia& image);
|
||||
static mate::Wrappable* New(const gfx::Image& image);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Handle<v8::ObjectTemplate> prototype);
|
||||
|
||||
protected:
|
||||
explicit Tray(const gfx::ImageSkia& image);
|
||||
explicit Tray(const gfx::Image& image);
|
||||
virtual ~Tray();
|
||||
|
||||
// TrayIconObserver:
|
||||
@@ -48,8 +48,8 @@ class Tray : public mate::EventEmitter,
|
||||
void OnBalloonClosed() override;
|
||||
|
||||
void Destroy();
|
||||
void SetImage(mate::Arguments* args, const gfx::ImageSkia& image);
|
||||
void SetPressedImage(mate::Arguments* args, const gfx::ImageSkia& image);
|
||||
void SetImage(mate::Arguments* args, const gfx::Image& image);
|
||||
void SetPressedImage(mate::Arguments* args, const gfx::Image& image);
|
||||
void SetToolTip(mate::Arguments* args, const std::string& tool_tip);
|
||||
void SetTitle(mate::Arguments* args, const std::string& title);
|
||||
void SetHighlightMode(mate::Arguments* args, bool highlight);
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/web_dialog_helper.h"
|
||||
#include "atom/browser/web_view/web_view_renderer_state.h"
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
@@ -12,6 +15,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"
|
||||
@@ -21,6 +25,7 @@
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "vendor/brightray/browser/media/media_stream_devices_controller.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -32,17 +37,30 @@ namespace {
|
||||
|
||||
v8::Persistent<v8::ObjectTemplate> template_;
|
||||
|
||||
// Get the window that has the |guest| embedded.
|
||||
NativeWindow* GetWindowFromGuest(const content::WebContents* guest) {
|
||||
int guest_process_id = guest->GetRenderProcessHost()->GetID();
|
||||
WebViewRendererState::WebViewInfo info;
|
||||
if (!WebViewRendererState::GetInstance()->GetInfo(guest_process_id, &info))
|
||||
return nullptr;
|
||||
return NativeWindow::FromRenderView(
|
||||
info.embedder->GetRenderProcessHost()->GetID(),
|
||||
info.embedder->GetRoutingID());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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_);
|
||||
@@ -108,9 +126,15 @@ content::WebContents* WebContents::OpenURLFromTab(
|
||||
args.AppendString("");
|
||||
args.AppendInteger(params.disposition);
|
||||
Emit("-new-window", args);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Give user a chance to cancel navigation.
|
||||
base::ListValue args;
|
||||
args.AppendString(params.url.spec());
|
||||
if (Emit("will-navigate", args))
|
||||
return nullptr;
|
||||
|
||||
content::NavigationController::LoadURLParams load_url_params(params.url);
|
||||
load_url_params.referrer = params.referrer;
|
||||
load_url_params.transition_type = params.transition;
|
||||
@@ -125,6 +149,29 @@ content::WebContents* WebContents::OpenURLFromTab(
|
||||
return web_contents();
|
||||
}
|
||||
|
||||
void WebContents::RunFileChooser(content::WebContents* guest,
|
||||
const content::FileChooserParams& params) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(GetWindowFromGuest(guest)));
|
||||
web_dialog_helper_->RunFileChooser(guest, params);
|
||||
}
|
||||
|
||||
void WebContents::EnumerateDirectory(content::WebContents* guest,
|
||||
int request_id,
|
||||
const base::FilePath& path) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(GetWindowFromGuest(guest)));
|
||||
web_dialog_helper_->EnumerateDirectory(guest, request_id, path);
|
||||
}
|
||||
|
||||
void WebContents::RequestMediaAccessPermission(
|
||||
content::WebContents*,
|
||||
const content::MediaStreamRequest& request,
|
||||
const content::MediaResponseCallback& callback) {
|
||||
brightray::MediaStreamDevicesController controller(request, callback);
|
||||
controller.TakeAction();
|
||||
}
|
||||
|
||||
void WebContents::HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
@@ -188,6 +235,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 +279,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,23 +296,25 @@ 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<void(bool enabled)>& 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())
|
||||
destruction_callback_.Run();
|
||||
|
||||
// When force destroying the "destroyed" event is not emitted.
|
||||
WebContentsDestroyed();
|
||||
|
||||
Observe(nullptr);
|
||||
storage_.reset();
|
||||
}
|
||||
@@ -294,7 +332,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);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ class Dictionary;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class WebDialogHelper;
|
||||
|
||||
namespace api {
|
||||
|
||||
class WebContents : public mate::EventEmitter,
|
||||
@@ -92,7 +94,7 @@ class WebContents : public mate::EventEmitter,
|
||||
~WebContents();
|
||||
|
||||
// mate::Wrappable:
|
||||
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
|
||||
// content::WebContentsDelegate:
|
||||
@@ -113,47 +115,49 @@ class WebContents : public mate::EventEmitter,
|
||||
content::WebContents* OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) override;
|
||||
void RunFileChooser(content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) override;
|
||||
void EnumerateDirectory(content::WebContents* web_contents,
|
||||
int request_id,
|
||||
const base::FilePath& path) override;
|
||||
void RequestMediaAccessPermission(
|
||||
content::WebContents*,
|
||||
const content::MediaStreamRequest&,
|
||||
const content::MediaResponseCallback&) override;
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
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<void(bool enabled)>& 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.
|
||||
@@ -168,20 +172,20 @@ class WebContents : public mate::EventEmitter,
|
||||
void GuestSizeChangedDueToAutoSize(const gfx::Size& old_size,
|
||||
const gfx::Size& new_size);
|
||||
|
||||
scoped_ptr<WebDialogHelper> web_dialog_helper_;
|
||||
|
||||
// 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<base::DictionaryValue> extra_params_;
|
||||
|
||||
// Stores the WebContents that managed by this class.
|
||||
scoped_ptr<brightray::InspectableWebContents> storage_;
|
||||
|
||||
|
||||
@@ -72,8 +72,6 @@ Window::Window(const mate::Dictionary& options)
|
||||
Window::~Window() {
|
||||
if (window_)
|
||||
Destroy();
|
||||
|
||||
Emit("destroyed");
|
||||
}
|
||||
|
||||
void Window::OnPageTitleUpdated(bool* prevent_default,
|
||||
@@ -94,6 +92,12 @@ void Window::WillCreatePopupWindow(const base::string16& frame_name,
|
||||
Emit("-new-window", args);
|
||||
}
|
||||
|
||||
void Window::WillNavigate(bool* prevent_default, const GURL& url) {
|
||||
base::ListValue args;
|
||||
args.AppendString(url.spec());
|
||||
*prevent_default = Emit("-will-navigate", args);
|
||||
}
|
||||
|
||||
void Window::WillCloseWindow(bool* prevent_default) {
|
||||
*prevent_default = Emit("close");
|
||||
}
|
||||
@@ -418,6 +422,12 @@ bool Window::IsMenuBarVisible() {
|
||||
return window_->IsMenuBarVisible();
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void Window::ShowDefinitionForSelection() {
|
||||
window_->ShowDefinitionForSelection();
|
||||
}
|
||||
#endif
|
||||
|
||||
mate::Handle<WebContents> Window::GetWebContents(v8::Isolate* isolate) const {
|
||||
return WebContents::CreateFrom(isolate, window_->GetWebContents());
|
||||
}
|
||||
@@ -487,6 +497,10 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide)
|
||||
.SetMethod("setMenuBarVisibility", &Window::SetMenuBarVisibility)
|
||||
.SetMethod("isMenuBarVisible", &Window::IsMenuBarVisible)
|
||||
#if defined(OS_MACOSX)
|
||||
.SetMethod("showDefinitionForSelection",
|
||||
&Window::ShowDefinitionForSelection)
|
||||
#endif
|
||||
.SetMethod("_getWebContents", &Window::GetWebContents)
|
||||
.SetMethod("_getDevToolsWebContents", &Window::GetDevToolsWebContents);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ class Window : public mate::EventEmitter,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
WindowOpenDisposition disposition) override;
|
||||
void WillNavigate(bool* prevent_default, const GURL& url) override;
|
||||
void WillCloseWindow(bool* prevent_default) override;
|
||||
void OnWindowClosed() override;
|
||||
void OnWindowBlur() override;
|
||||
@@ -122,6 +123,10 @@ class Window : public mate::EventEmitter,
|
||||
void SetMenuBarVisibility(bool visible);
|
||||
bool IsMenuBarVisible();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void ShowDefinitionForSelection();
|
||||
#endif
|
||||
|
||||
// APIs for WebContents.
|
||||
mate::Handle<WebContents> GetWebContents(v8::Isolate* isolate) const;
|
||||
mate::Handle<WebContents> GetDevToolsWebContents(v8::Isolate* isolate) const;
|
||||
|
||||
@@ -30,6 +30,10 @@ BrowserWindow::_init = ->
|
||||
options = show: true, width: 800, height: 600
|
||||
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
|
||||
|
||||
# Redirect "will-navigate" to webContents.
|
||||
@on '-will-navigate', (event, url) =>
|
||||
@webContents.emit 'will-navigate', event, url
|
||||
|
||||
# Remove the window from weak map immediately when it's destroyed, since we
|
||||
# could be iterating windows before GC happened.
|
||||
@once 'closed', =>
|
||||
|
||||
@@ -91,12 +91,12 @@ module.exports =
|
||||
options.title ?= ''
|
||||
options.message ?= ''
|
||||
options.detail ?= ''
|
||||
options.icon ?= null
|
||||
|
||||
binding.showMessageBox options.type,
|
||||
options.buttons,
|
||||
String(options.title),
|
||||
String(options.message),
|
||||
String(options.detail),
|
||||
[options.title, options.message, options.detail],
|
||||
options.icon,
|
||||
window,
|
||||
callback
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -96,6 +96,14 @@ void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
return;
|
||||
}
|
||||
|
||||
// Custom preferences of guest page.
|
||||
int guest_process_id = render_view_host->GetProcess()->GetID();
|
||||
WebViewRendererState::WebViewInfo info;
|
||||
if (WebViewRendererState::GetInstance()->GetInfo(guest_process_id, &info)) {
|
||||
prefs->web_security_enabled = !info.disable_web_security;
|
||||
return;
|
||||
}
|
||||
|
||||
NativeWindow* window = NativeWindow::FromRenderView(
|
||||
render_view_host->GetProcess()->GetID(),
|
||||
render_view_host->GetRoutingID());
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
||||
#include "atom/browser/web_view/web_view_manager.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
@@ -26,6 +28,14 @@ namespace {
|
||||
|
||||
const char* kAsarScheme = "asar";
|
||||
|
||||
class NoCacheBackend : public net::HttpCache::BackendFactory {
|
||||
int CreateBackend(net::NetLog* net_log,
|
||||
scoped_ptr<disk_cache::Backend>* backend,
|
||||
const net::CompletionCallback& callback) override {
|
||||
return net::ERR_FAILED;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomBrowserContext::AtomBrowserContext()
|
||||
@@ -69,6 +79,16 @@ net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
|
||||
return top_job_factory.release();
|
||||
}
|
||||
|
||||
net::HttpCache::BackendFactory*
|
||||
AtomBrowserContext::CreateHttpCacheBackendFactory(
|
||||
const base::FilePath& base_path) {
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (command_line->HasSwitch(switches::kDisableHttpCache))
|
||||
return new NoCacheBackend;
|
||||
else
|
||||
return brightray::BrowserContext::CreateHttpCacheBackendFactory(base_path);
|
||||
}
|
||||
|
||||
content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
|
||||
if (!guest_manager_)
|
||||
guest_manager_.reset(new WebViewManager(this));
|
||||
|
||||
@@ -23,12 +23,14 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
static AtomBrowserContext* Get();
|
||||
|
||||
// brightray::URLRequestContextGetter::Delegate:
|
||||
virtual net::URLRequestJobFactory* CreateURLRequestJobFactory(
|
||||
net::URLRequestJobFactory* CreateURLRequestJobFactory(
|
||||
content::ProtocolHandlerMap* handlers,
|
||||
content::URLRequestInterceptorScopedVector* interceptors) override;
|
||||
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
|
||||
const base::FilePath& base_path) override;
|
||||
|
||||
// content::BrowserContext:
|
||||
virtual content::BrowserPluginGuestManager* GetGuestManager() override;
|
||||
content::BrowserPluginGuestManager* GetGuestManager() override;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() {
|
||||
base::FilePath frameworkPath = brightray::MainApplicationBundlePath()
|
||||
.Append("Contents")
|
||||
.Append("Frameworks")
|
||||
.Append("Atom Framework.framework");
|
||||
.Append(PRODUCT_NAME " Framework.framework");
|
||||
NSBundle* frameworkBundle = [NSBundle
|
||||
bundleWithPath:base::mac::FilePathToNSString(frameworkPath)];
|
||||
NSNib* mainNib = [[NSNib alloc] initWithNibNamed:@"MainMenu"
|
||||
|
||||
@@ -20,28 +20,28 @@ class AtomSpeechRecognitionManagerDelegate
|
||||
virtual ~AtomSpeechRecognitionManagerDelegate();
|
||||
|
||||
// content::SpeechRecognitionEventListener:
|
||||
virtual void OnRecognitionStart(int session_id) override;
|
||||
virtual void OnAudioStart(int session_id) override;
|
||||
virtual void OnEnvironmentEstimationComplete(int session_id) override;
|
||||
virtual void OnSoundStart(int session_id) override;
|
||||
virtual void OnSoundEnd(int session_id) override;
|
||||
virtual void OnAudioEnd(int session_id) override;
|
||||
virtual void OnRecognitionEnd(int session_id) override;
|
||||
virtual void OnRecognitionResults(
|
||||
void OnRecognitionStart(int session_id) override;
|
||||
void OnAudioStart(int session_id) override;
|
||||
void OnEnvironmentEstimationComplete(int session_id) override;
|
||||
void OnSoundStart(int session_id) override;
|
||||
void OnSoundEnd(int session_id) override;
|
||||
void OnAudioEnd(int session_id) override;
|
||||
void OnRecognitionEnd(int session_id) override;
|
||||
void OnRecognitionResults(
|
||||
int session_id, const content::SpeechRecognitionResults& result) override;
|
||||
virtual void OnRecognitionError(
|
||||
void OnRecognitionError(
|
||||
int session_id, const content::SpeechRecognitionError& error) override;
|
||||
virtual void OnAudioLevelsChange(int session_id, float volume,
|
||||
float noise_volume) override;
|
||||
void OnAudioLevelsChange(int session_id, float volume,
|
||||
float noise_volume) override;
|
||||
|
||||
// content::SpeechRecognitionManagerDelegate:
|
||||
virtual void GetDiagnosticInformation(bool* can_report_metrics,
|
||||
std::string* hardware_info) override;
|
||||
virtual void CheckRecognitionIsAllowed(
|
||||
void GetDiagnosticInformation(bool* can_report_metrics,
|
||||
std::string* hardware_info) override;
|
||||
void CheckRecognitionIsAllowed(
|
||||
int session_id,
|
||||
base::Callback<void(bool ask_user, bool is_allowed)> callback) override;
|
||||
virtual content::SpeechRecognitionEventListener* GetEventListener() override;
|
||||
virtual bool FilterProfanities(int render_process_id) override;
|
||||
content::SpeechRecognitionEventListener* GetEventListener() override;
|
||||
bool FilterProfanities(int render_process_id) override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomSpeechRecognitionManagerDelegate);
|
||||
|
||||
@@ -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_),
|
||||
|
||||
@@ -18,6 +18,8 @@ supportedWebViewEvents = [
|
||||
|
||||
nextInstanceId = 0
|
||||
guestInstances = {}
|
||||
embedderElementsMap = {}
|
||||
reverseEmbedderElementsMap = {}
|
||||
|
||||
# Generate guestInstanceId.
|
||||
getNextInstanceId = (webContents) ->
|
||||
@@ -33,15 +35,20 @@ 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.once event, destroy for event in destroyEvents
|
||||
guest.once 'destroyed', ->
|
||||
embedder.removeListener 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
|
||||
@@ -60,21 +67,58 @@ createGuest = (embedder, params) ->
|
||||
guest.on event, (_, args...) ->
|
||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{guest.viewInstanceId}", event, args...
|
||||
|
||||
# Dispatch guest's IPC messages to embedder.
|
||||
guest.on 'ipc-message-host', (_, channel, args...) ->
|
||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{guest.viewInstanceId}", channel, args...
|
||||
|
||||
# Autosize.
|
||||
guest.on 'size-changed', (_, args...) ->
|
||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED", args...
|
||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{guest.viewInstanceId}", args...
|
||||
|
||||
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
|
||||
disableWebSecurity: params.disablewebsecurity
|
||||
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
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ NativeWindow* NativeWindow::FromRenderView(int process_id, int routing_id) {
|
||||
return window;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||
@@ -247,6 +247,10 @@ void NativeWindow::Print(bool silent, bool print_background) {
|
||||
PrintNow(silent, print_background);
|
||||
}
|
||||
|
||||
void NativeWindow::ShowDefinitionForSelection() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void NativeWindow::SetAutoHideMenuBar(bool auto_hide) {
|
||||
}
|
||||
|
||||
@@ -370,13 +374,13 @@ void NativeWindow::CloseWebContents() {
|
||||
|
||||
content::WebContents* NativeWindow::GetWebContents() const {
|
||||
if (!inspectable_web_contents_)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
return inspectable_web_contents()->GetWebContents();
|
||||
}
|
||||
|
||||
content::WebContents* NativeWindow::GetDevToolsWebContents() const {
|
||||
if (!inspectable_web_contents_)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
return inspectable_web_contents()->devtools_web_contents();
|
||||
}
|
||||
|
||||
@@ -439,9 +443,10 @@ void NativeWindow::OverrideWebkitPrefs(const GURL& url,
|
||||
prefs->experimental_webgl_enabled = b;
|
||||
if (web_preferences_.Get("webaudio", &b))
|
||||
prefs->webaudio_enabled = b;
|
||||
if (web_preferences_.Get("extra-plugin-dirs", &list))
|
||||
if (web_preferences_.Get("extra-plugin-dirs", &list)) {
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
content::PluginService::GetInstance()->AddExtraPluginDir(list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowClosed() {
|
||||
@@ -523,9 +528,17 @@ content::WebContents* NativeWindow::OpenURLFromTab(
|
||||
params.url,
|
||||
"",
|
||||
params.disposition));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Give user a chance to prevent navigation.
|
||||
bool prevent_default = false;
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
WillNavigate(&prevent_default, params.url));
|
||||
if (prevent_default)
|
||||
return nullptr;
|
||||
|
||||
content::NavigationController::LoadURLParams load_url_params(params.url);
|
||||
load_url_params.referrer = params.referrer;
|
||||
load_url_params.transition_type = params.transition;
|
||||
|
||||
@@ -161,6 +161,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
// Print current page.
|
||||
virtual void Print(bool silent, bool print_background);
|
||||
|
||||
// Show popup dictionary.
|
||||
virtual void ShowDefinitionForSelection();
|
||||
|
||||
// Toggle the menu bar.
|
||||
virtual void SetAutoHideMenuBar(bool auto_hide);
|
||||
virtual bool IsMenuBarAutoHide();
|
||||
|
||||
@@ -7,10 +7,14 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
|
||||
@class FullSizeContentView;
|
||||
class SkRegion;
|
||||
|
||||
namespace atom {
|
||||
@@ -67,6 +71,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
virtual bool HasModalDialog() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
virtual void SetProgressBar(double progress) OVERRIDE;
|
||||
virtual void ShowDefinitionForSelection() OVERRIDE;
|
||||
|
||||
// Returns true if |point| in local Cocoa coordinate system falls within
|
||||
// the draggable region.
|
||||
@@ -98,6 +103,9 @@ class NativeWindowMac : public NativeWindow {
|
||||
|
||||
base::scoped_nsobject<NSWindow> window_;
|
||||
|
||||
// The view that will fill the whole frameless window.
|
||||
base::scoped_nsobject<FullSizeContentView> content_view_;
|
||||
|
||||
bool is_kiosk_;
|
||||
|
||||
NSInteger attention_request_id_; // identifier from requestUserAttention
|
||||
|
||||
@@ -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<NSWindowDelegate> {
|
||||
@private
|
||||
atom::NativeWindowMac* shell_;
|
||||
@@ -361,6 +386,10 @@ bool NativeWindowMac::IsFocused() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::Show() {
|
||||
// This method is supposed to put focus on window, however if the app does not
|
||||
// have focus then "makeKeyAndOrderFront" will only show the window.
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
[window_ makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
@@ -617,6 +646,16 @@ void NativeWindowMac::SetProgressBar(double progress) {
|
||||
[dock_tile display];
|
||||
}
|
||||
|
||||
void NativeWindowMac::ShowDefinitionForSelection() {
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
|
||||
if (!rwhv)
|
||||
return;
|
||||
rwhv->ShowDefinitionForSelection();
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region_)
|
||||
return false;
|
||||
@@ -690,9 +729,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();
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ class NativeWindowObserver {
|
||||
const std::string& partition_id,
|
||||
WindowOpenDisposition disposition) {}
|
||||
|
||||
// Called when user is starting an navigation in web page.
|
||||
virtual void WillNavigate(bool* prevent_default, const GURL& url) {}
|
||||
|
||||
// Called when the window is gonna closed.
|
||||
virtual void WillCloseWindow(bool* prevent_default) {}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
|
||||
#include "ui/views/controls/webview/webview.h"
|
||||
#include "ui/views/window/client_view.h"
|
||||
#include "ui/views/widget/native_widget_private.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
@@ -49,6 +50,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
|
||||
|
||||
@@ -220,7 +222,7 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
#endif
|
||||
|
||||
// Add web view.
|
||||
SetLayoutManager(new MenuLayout(kMenuBarHeight));
|
||||
SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
|
||||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
AddChildView(web_view_);
|
||||
|
||||
@@ -295,7 +297,11 @@ bool NativeWindowViews::IsVisible() {
|
||||
}
|
||||
|
||||
void NativeWindowViews::Maximize() {
|
||||
window_->Maximize();
|
||||
if (IsVisible())
|
||||
window_->Maximize();
|
||||
else
|
||||
window_->native_widget_private()->ShowWithWindowState(
|
||||
ui::SHOW_STATE_MAXIMIZED);
|
||||
}
|
||||
|
||||
void NativeWindowViews::Unmaximize() {
|
||||
@@ -307,7 +313,11 @@ bool NativeWindowViews::IsMaximized() {
|
||||
}
|
||||
|
||||
void NativeWindowViews::Minimize() {
|
||||
window_->Minimize();
|
||||
if (IsVisible())
|
||||
window_->Minimize();
|
||||
else
|
||||
window_->native_widget_private()->ShowWithWindowState(
|
||||
ui::SHOW_STATE_MINIMIZED);
|
||||
}
|
||||
|
||||
void NativeWindowViews::Restore() {
|
||||
@@ -319,7 +329,11 @@ bool NativeWindowViews::IsMinimized() {
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetFullScreen(bool fullscreen) {
|
||||
window_->SetFullscreen(fullscreen);
|
||||
if (IsVisible())
|
||||
window_->SetFullscreen(fullscreen);
|
||||
else
|
||||
window_->native_widget_private()->ShowWithWindowState(
|
||||
ui::SHOW_STATE_FULLSCREEN);
|
||||
#if defined(OS_WIN)
|
||||
// There is no native fullscreen state on Windows.
|
||||
if (fullscreen)
|
||||
@@ -410,17 +424,15 @@ gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
|
||||
void NativeWindowViews::SetResizable(bool resizable) {
|
||||
#if defined(OS_WIN)
|
||||
if (has_frame_) {
|
||||
// WS_MAXIMIZEBOX => Maximize button
|
||||
// WS_MINIMIZEBOX => Minimize button
|
||||
// WS_THICKFRAME => Resize handle
|
||||
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
|
||||
if (resizable)
|
||||
style |= WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
|
||||
else
|
||||
style = (style & ~(WS_MAXIMIZEBOX | WS_THICKFRAME)) | WS_MINIMIZEBOX;
|
||||
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
|
||||
}
|
||||
// WS_MAXIMIZEBOX => Maximize button
|
||||
// WS_MINIMIZEBOX => Minimize button
|
||||
// WS_THICKFRAME => Resize handle
|
||||
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
|
||||
if (resizable)
|
||||
style |= WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
|
||||
else
|
||||
style = (style & ~(WS_MAXIMIZEBOX | WS_THICKFRAME)) | WS_MINIMIZEBOX;
|
||||
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
|
||||
#elif defined(USE_X11)
|
||||
if (resizable != resizable_) {
|
||||
// On Linux there is no "resizable" property of a window, we have to set
|
||||
@@ -477,6 +489,18 @@ std::string NativeWindowViews::GetTitle() {
|
||||
}
|
||||
|
||||
void NativeWindowViews::FlashFrame(bool flash) {
|
||||
#if defined(OS_WIN)
|
||||
// The Chromium's implementation has a bug stopping flash.
|
||||
if (!flash) {
|
||||
FLASHWINFO fwi;
|
||||
fwi.cbSize = sizeof(fwi);
|
||||
fwi.hwnd = GetAcceleratedWidget();
|
||||
fwi.dwFlags = FLASHW_STOP;
|
||||
fwi.uCount = 0;
|
||||
FlashWindowEx(&fwi);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
window_->FlashFrame(flash);
|
||||
}
|
||||
|
||||
@@ -663,6 +687,10 @@ bool NativeWindowViews::CanMaximize() const {
|
||||
return resizable_;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::CanMinimize() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
base::string16 NativeWindowViews::GetWindowTitle() const {
|
||||
return base::UTF8ToUTF16(title_);
|
||||
}
|
||||
@@ -837,8 +865,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;
|
||||
|
||||
@@ -98,6 +98,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
views::View* GetInitiallyFocusedView() override;
|
||||
bool CanResize() const override;
|
||||
bool CanMaximize() const override;
|
||||
bool CanMinimize() const override;
|
||||
base::string16 GetWindowTitle() const override;
|
||||
bool ShouldHandleSystemCommands() const override;
|
||||
gfx::ImageSkia GetWindowAppIcon() override;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.github.atom</string>
|
||||
<string>com.github.atom-shell</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.19.5</string>
|
||||
<string>0.20.5</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,19,5,0
|
||||
PRODUCTVERSION 0,19,5,0
|
||||
FILEVERSION 0,20,5,0
|
||||
PRODUCTVERSION 0,20,5,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Atom-Shell"
|
||||
VALUE "FileVersion", "0.19.5"
|
||||
VALUE "FileVersion", "0.20.5"
|
||||
VALUE "InternalName", "atom.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "atom.exe"
|
||||
VALUE "ProductName", "Atom-Shell"
|
||||
VALUE "ProductVersion", "0.19.5"
|
||||
VALUE "ProductVersion", "0.20.5"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "third_party/wtl/include/atlapp.h"
|
||||
#include "third_party/wtl/include/atldlgs.h"
|
||||
@@ -113,6 +114,50 @@ class FileDialog {
|
||||
DISALLOW_COPY_AND_ASSIGN(FileDialog);
|
||||
};
|
||||
|
||||
struct RunState {
|
||||
base::Thread* dialog_thread;
|
||||
base::MessageLoop* ui_message_loop;
|
||||
};
|
||||
|
||||
bool CreateDialogThread(RunState* run_state) {
|
||||
base::Thread* thread = new base::Thread("AtomShell_FileDialogThread");
|
||||
thread->init_com_with_mta(false);
|
||||
if (!thread->Start())
|
||||
return false;
|
||||
|
||||
run_state->dialog_thread = thread;
|
||||
run_state->ui_message_loop = base::MessageLoop::current();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RunOpenDialogInNewThread(const RunState& run_state,
|
||||
atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
const OpenDialogCallback& callback) {
|
||||
std::vector<base::FilePath> paths;
|
||||
bool result = ShowOpenDialog(parent, title, default_path, filters, properties,
|
||||
&paths);
|
||||
run_state.ui_message_loop->PostTask(FROM_HERE,
|
||||
base::Bind(callback, result, paths));
|
||||
run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread);
|
||||
}
|
||||
|
||||
void RunSaveDialogInNewThread(const RunState& run_state,
|
||||
atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
const SaveDialogCallback& callback) {
|
||||
base::FilePath path;
|
||||
bool result = ShowSaveDialog(parent, title, default_path, filters, &path);
|
||||
run_state.ui_message_loop->PostTask(FROM_HERE,
|
||||
base::Bind(callback, result, path));
|
||||
run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
@@ -162,20 +207,22 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
void ShowOpenDialog(atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
const OpenDialogCallback& callback) {
|
||||
std::vector<base::FilePath> paths;
|
||||
bool result = ShowOpenDialog(parent_window,
|
||||
title,
|
||||
default_path,
|
||||
filters,
|
||||
properties,
|
||||
&paths);
|
||||
callback.Run(result, paths);
|
||||
RunState run_state;
|
||||
if (!CreateDialogThread(&run_state)) {
|
||||
callback.Run(false, std::vector<base::FilePath>());
|
||||
return;
|
||||
}
|
||||
|
||||
run_state.dialog_thread->message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&RunOpenDialogInNewThread, run_state, parent, title,
|
||||
default_path, filters, properties, callback));
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
@@ -218,15 +265,21 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
void ShowSaveDialog(atom::NativeWindow* parent,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
const SaveDialogCallback& callback) {
|
||||
base::FilePath path;
|
||||
bool result = ShowSaveDialog(parent_window, title, default_path, filters,
|
||||
&path);
|
||||
callback.Run(result, path);
|
||||
RunState run_state;
|
||||
if (!CreateDialogThread(&run_state)) {
|
||||
callback.Run(false, base::FilePath());
|
||||
return;
|
||||
}
|
||||
|
||||
run_state.dialog_thread->message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&RunSaveDialogInNewThread, run_state, parent, title,
|
||||
default_path, filters, callback));
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace gfx {
|
||||
class ImageSkia;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindow;
|
||||
@@ -28,7 +32,8 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail);
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon);
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
@@ -36,6 +41,7 @@ void ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback);
|
||||
|
||||
// Like ShowMessageBox with simplest settings, but safe to call at very early
|
||||
|
||||
@@ -96,7 +96,8 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
NSAlert* alert = CreateNSAlert(
|
||||
parent_window, type, buttons, title, message, detail);
|
||||
|
||||
@@ -127,6 +128,7 @@ void ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
NSAlert* alert = CreateNSAlert(
|
||||
parent_window, type, buttons, title, message, detail);
|
||||
|
||||
@@ -60,7 +60,8 @@ class MessageDialog : public views::WidgetDelegate,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail);
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon);
|
||||
virtual ~MessageDialog();
|
||||
|
||||
void Show(base::RunLoop* run_loop = NULL);
|
||||
@@ -75,24 +76,28 @@ class MessageDialog : public views::WidgetDelegate,
|
||||
|
||||
private:
|
||||
// Overridden from views::WidgetDelegate:
|
||||
virtual base::string16 GetWindowTitle() const;
|
||||
virtual views::Widget* GetWidget() OVERRIDE;
|
||||
virtual const views::Widget* GetWidget() const OVERRIDE;
|
||||
virtual views::View* GetContentsView() OVERRIDE;
|
||||
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
|
||||
virtual ui::ModalType GetModalType() const OVERRIDE;
|
||||
virtual views::NonClientFrameView* CreateNonClientFrameView(
|
||||
views::Widget* widget) OVERRIDE;
|
||||
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
|
||||
base::string16 GetWindowTitle() const override;
|
||||
gfx::ImageSkia GetWindowAppIcon() override;
|
||||
gfx::ImageSkia GetWindowIcon() override;
|
||||
bool ShouldShowWindowIcon() const override;
|
||||
views::Widget* GetWidget() override;
|
||||
const views::Widget* GetWidget() const override;
|
||||
views::View* GetContentsView() override;
|
||||
views::View* GetInitiallyFocusedView() override;
|
||||
ui::ModalType GetModalType() const override;
|
||||
views::NonClientFrameView* CreateNonClientFrameView(
|
||||
views::Widget* widget) override;
|
||||
views::ClientView* CreateClientView(views::Widget* widget) override;
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual gfx::Size GetPreferredSize() const OVERRIDE;
|
||||
virtual void Layout() OVERRIDE;
|
||||
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
|
||||
gfx::Size GetPreferredSize() const override;
|
||||
void Layout() override;
|
||||
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
|
||||
|
||||
// Overridden from views::ButtonListener:
|
||||
virtual void ButtonPressed(views::Button* sender,
|
||||
const ui::Event& event) OVERRIDE;
|
||||
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
|
||||
|
||||
gfx::ImageSkia icon_;
|
||||
|
||||
bool delete_on_close_;
|
||||
int result_;
|
||||
@@ -118,7 +123,7 @@ class MessageDialogClientView : public views::ClientView {
|
||||
}
|
||||
|
||||
// views::ClientView:
|
||||
virtual bool CanClose() OVERRIDE {
|
||||
bool CanClose() override {
|
||||
dialog_->Close();
|
||||
return false;
|
||||
}
|
||||
@@ -137,8 +142,10 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail)
|
||||
: delete_on_close_(false),
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon)
|
||||
: icon_(icon),
|
||||
delete_on_close_(false),
|
||||
result_(-1),
|
||||
title_(base::UTF8ToUTF16(title)),
|
||||
parent_(parent_window),
|
||||
@@ -174,6 +181,7 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
|
||||
|
||||
views::Widget::InitParams params;
|
||||
params.delegate = this;
|
||||
params.type = views::Widget::InitParams::TYPE_WINDOW;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
if (parent_) {
|
||||
params.parent = parent_->GetNativeWindow();
|
||||
@@ -184,6 +192,7 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
|
||||
|
||||
widget_.reset(new views::Widget);
|
||||
widget_->Init(params);
|
||||
widget_->UpdateWindowIcon();
|
||||
|
||||
// Bind to ESC.
|
||||
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
|
||||
@@ -230,6 +239,18 @@ base::string16 MessageDialog::GetWindowTitle() const {
|
||||
return title_;
|
||||
}
|
||||
|
||||
gfx::ImageSkia MessageDialog::GetWindowAppIcon() {
|
||||
return icon_;
|
||||
}
|
||||
|
||||
gfx::ImageSkia MessageDialog::GetWindowIcon() {
|
||||
return icon_;
|
||||
}
|
||||
|
||||
bool MessageDialog::ShouldShowWindowIcon() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
views::Widget* MessageDialog::GetWidget() {
|
||||
return widget_.get();
|
||||
}
|
||||
@@ -338,8 +359,10 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
MessageDialog dialog(parent_window, type, buttons, title, message, detail);
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
MessageDialog dialog(
|
||||
parent_window, type, buttons, title, message, detail, icon);
|
||||
{
|
||||
base::MessageLoop::ScopedNestableTaskAllower allow(
|
||||
base::MessageLoopForUI::current());
|
||||
@@ -357,10 +380,11 @@ void ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
// The dialog would be deleted when the dialog is closed.
|
||||
MessageDialog* dialog = new MessageDialog(
|
||||
parent_window, type, buttons, title, message, detail);
|
||||
parent_window, type, buttons, title, message, detail, icon);
|
||||
dialog->set_callback(callback);
|
||||
dialog->Show();
|
||||
}
|
||||
|
||||
@@ -12,13 +12,16 @@ TrayIcon::TrayIcon() {
|
||||
TrayIcon::~TrayIcon() {
|
||||
}
|
||||
|
||||
void TrayIcon::SetPressedImage(const gfx::Image& image) {
|
||||
}
|
||||
|
||||
void TrayIcon::SetTitle(const std::string& title) {
|
||||
}
|
||||
|
||||
void TrayIcon::SetHighlightMode(bool highlight) {
|
||||
}
|
||||
|
||||
void TrayIcon::DisplayBalloon(const gfx::ImageSkia& icon,
|
||||
void TrayIcon::DisplayBalloon(const gfx::Image& icon,
|
||||
const base::string16& title,
|
||||
const base::string16& contents) {
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ class TrayIcon {
|
||||
virtual ~TrayIcon();
|
||||
|
||||
// Sets the image associated with this status icon.
|
||||
virtual void SetImage(const gfx::ImageSkia& image) = 0;
|
||||
virtual void SetImage(const gfx::Image& 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::Image& 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
|
||||
@@ -41,7 +41,7 @@ class TrayIcon {
|
||||
|
||||
// Displays a notification balloon with the specified contents.
|
||||
// Depending on the platform it might not appear by the icon tray.
|
||||
virtual void DisplayBalloon(const gfx::ImageSkia& icon,
|
||||
virtual void DisplayBalloon(const gfx::Image& icon,
|
||||
const base::string16& title,
|
||||
const base::string16& contents);
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ class TrayIconCocoa : public TrayIcon {
|
||||
TrayIconCocoa();
|
||||
virtual ~TrayIconCocoa();
|
||||
|
||||
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetImage(const gfx::Image& image) OVERRIDE;
|
||||
virtual void SetPressedImage(const gfx::Image& image) OVERRIDE;
|
||||
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
|
||||
virtual void SetTitle(const std::string& title) OVERRIDE;
|
||||
virtual void SetHighlightMode(bool highlight) OVERRIDE;
|
||||
|
||||
@@ -53,20 +53,14 @@ TrayIconCocoa::~TrayIconCocoa() {
|
||||
[[NSStatusBar systemStatusBar] removeStatusItem:item_];
|
||||
}
|
||||
|
||||
void TrayIconCocoa::SetImage(const gfx::ImageSkia& image) {
|
||||
if (!image.isNull()) {
|
||||
gfx::Image neutral(image);
|
||||
if (!neutral.IsEmpty())
|
||||
[item_ setImage:neutral.ToNSImage()];
|
||||
}
|
||||
void TrayIconCocoa::SetImage(const gfx::Image& image) {
|
||||
if (!image.IsEmpty())
|
||||
[item_ setImage:image.ToNSImage()];
|
||||
}
|
||||
|
||||
void TrayIconCocoa::SetPressedImage(const gfx::ImageSkia& image) {
|
||||
if (!image.isNull()) {
|
||||
gfx::Image neutral(image);
|
||||
if (!neutral.IsEmpty())
|
||||
[item_ setAlternateImage:neutral.ToNSImage()];
|
||||
}
|
||||
void TrayIconCocoa::SetPressedImage(const gfx::Image& image) {
|
||||
if (!image.IsEmpty())
|
||||
[item_ setAlternateImage:image.ToNSImage()];
|
||||
}
|
||||
|
||||
void TrayIconCocoa::SetToolTip(const std::string& tool_tip) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/app_indicator_icon.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_status_icon.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -17,25 +18,21 @@ TrayIconGtk::TrayIconGtk() {
|
||||
TrayIconGtk::~TrayIconGtk() {
|
||||
}
|
||||
|
||||
void TrayIconGtk::SetImage(const gfx::ImageSkia& image) {
|
||||
void TrayIconGtk::SetImage(const gfx::Image& image) {
|
||||
if (icon_) {
|
||||
icon_->SetImage(image);
|
||||
icon_->SetImage(image.AsImageSkia());
|
||||
return;
|
||||
}
|
||||
|
||||
base::string16 empty;
|
||||
if (libgtk2ui::AppIndicatorIcon::CouldOpen())
|
||||
icon_.reset(
|
||||
new libgtk2ui::AppIndicatorIcon(base::GenerateGUID(), image, empty));
|
||||
icon_.reset(new libgtk2ui::AppIndicatorIcon(
|
||||
base::GenerateGUID(), image.AsImageSkia(), empty));
|
||||
else
|
||||
icon_.reset(new libgtk2ui::Gtk2StatusIcon(image, empty));
|
||||
icon_.reset(new libgtk2ui::Gtk2StatusIcon(image.AsImageSkia(), empty));
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ class TrayIconGtk : public TrayIcon,
|
||||
virtual ~TrayIconGtk();
|
||||
|
||||
// TrayIcon:
|
||||
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
|
||||
virtual void SetImage(const gfx::Image& image) OVERRIDE;
|
||||
virtual void SetToolTip(const std::string& tool_tip) OVERRIDE;
|
||||
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,16 +4,47 @@
|
||||
|
||||
#include "atom/browser/ui/views/menu_layout.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
MenuLayout::MenuLayout(int menu_height)
|
||||
: menu_height_(menu_height) {
|
||||
namespace {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
gfx::Rect SubstractBorderSize(gfx::Rect bounds) {
|
||||
int border_width = GetSystemMetrics(SM_CXSIZEFRAME) - 1;
|
||||
int border_height = GetSystemMetrics(SM_CYSIZEFRAME) - 1;
|
||||
bounds.set_x(bounds.x() + border_width);
|
||||
bounds.set_y(bounds.y() + border_height);
|
||||
bounds.set_width(bounds.width() - 2 * border_width);
|
||||
bounds.set_height(bounds.height() - 2 * border_height);
|
||||
return bounds;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
MenuLayout::MenuLayout(NativeWindowViews* window, int menu_height)
|
||||
: window_(window),
|
||||
menu_height_(menu_height) {
|
||||
}
|
||||
|
||||
MenuLayout::~MenuLayout() {
|
||||
}
|
||||
|
||||
void MenuLayout::Layout(views::View* host) {
|
||||
#if defined(OS_WIN)
|
||||
// Reserve border space for maximized frameless window so we won't have the
|
||||
// content go outside of screen.
|
||||
if (!window_->has_frame() && window_->IsMaximized()) {
|
||||
gfx::Rect bounds = SubstractBorderSize(host->GetContentsBounds());
|
||||
host->child_at(0)->SetBoundsRect(bounds);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!HasMenu(host)) {
|
||||
views::FillLayout::Layout(host);
|
||||
return;
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowViews;
|
||||
|
||||
class MenuLayout : public views::FillLayout {
|
||||
public:
|
||||
explicit MenuLayout(int menu_height);
|
||||
MenuLayout(NativeWindowViews* window, int menu_height);
|
||||
virtual ~MenuLayout();
|
||||
|
||||
// views::LayoutManager:
|
||||
@@ -23,6 +25,7 @@ class MenuLayout : public views::FillLayout {
|
||||
private:
|
||||
bool HasMenu(const views::View* host) const;
|
||||
|
||||
NativeWindowViews* window_;
|
||||
int menu_height_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuLayout);
|
||||
|
||||
@@ -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<views::View*>(const_cast<WinFrameView*>(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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "base/win/windows_version.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "ui/gfx/icon_util.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/views/controls/menu/menu_runner.h"
|
||||
@@ -90,19 +91,19 @@ void NotifyIcon::ResetIcon() {
|
||||
LOG(WARNING) << "Unable to re-create status tray icon.";
|
||||
}
|
||||
|
||||
void NotifyIcon::SetImage(const gfx::ImageSkia& image) {
|
||||
void NotifyIcon::SetImage(const gfx::Image& image) {
|
||||
// Create the icon.
|
||||
NOTIFYICONDATA icon_data;
|
||||
InitIconData(&icon_data);
|
||||
icon_data.uFlags = NIF_ICON;
|
||||
icon_.Set(IconUtil::CreateHICONFromSkBitmap(*image.bitmap()));
|
||||
icon_.Set(IconUtil::CreateHICONFromSkBitmap(image.AsBitmap()));
|
||||
icon_data.hIcon = icon_.Get();
|
||||
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
|
||||
if (!result)
|
||||
LOG(WARNING) << "Error setting status tray icon image";
|
||||
}
|
||||
|
||||
void NotifyIcon::SetPressedImage(const gfx::ImageSkia& image) {
|
||||
void NotifyIcon::SetPressedImage(const gfx::Image& image) {
|
||||
// Ignore pressed images, since the standard on Windows is to not highlight
|
||||
// pressed status icons.
|
||||
}
|
||||
@@ -118,7 +119,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
|
||||
LOG(WARNING) << "Unable to set tooltip for status tray icon";
|
||||
}
|
||||
|
||||
void NotifyIcon::DisplayBalloon(const gfx::ImageSkia& icon,
|
||||
void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
|
||||
const base::string16& title,
|
||||
const base::string16& contents) {
|
||||
NOTIFYICONDATA icon_data;
|
||||
@@ -130,8 +131,8 @@ void NotifyIcon::DisplayBalloon(const gfx::ImageSkia& icon,
|
||||
icon_data.uTimeout = 0;
|
||||
|
||||
base::win::Version win_version = base::win::GetVersion();
|
||||
if (!icon.isNull() && win_version != base::win::VERSION_PRE_XP) {
|
||||
balloon_icon_.Set(IconUtil::CreateHICONFromSkBitmap(*icon.bitmap()));
|
||||
if (!icon.IsEmpty() && win_version != base::win::VERSION_PRE_XP) {
|
||||
balloon_icon_.Set(IconUtil::CreateHICONFromSkBitmap(icon.AsBitmap()));
|
||||
icon_data.hBalloonIcon = balloon_icon_.Get();
|
||||
icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ class NotifyIcon : public TrayIcon {
|
||||
UINT message_id() const { return message_id_; }
|
||||
|
||||
// Overridden from TrayIcon:
|
||||
void SetImage(const gfx::ImageSkia& image) override;
|
||||
void SetPressedImage(const gfx::ImageSkia& image) override;
|
||||
void SetImage(const gfx::Image& image) override;
|
||||
void SetPressedImage(const gfx::Image& image) override;
|
||||
void SetToolTip(const std::string& tool_tip) override;
|
||||
void DisplayBalloon(const gfx::ImageSkia& icon,
|
||||
void DisplayBalloon(const gfx::Image& icon,
|
||||
const base::string16& title,
|
||||
const base::string16& contents) override;
|
||||
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
|
||||
|
||||
@@ -32,6 +32,20 @@ struct Converter<content::WebContents*> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<atom::WebViewManager::WebViewOptions> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> 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)) &&
|
||||
options.Get("disableWebSecurity", &(out->disable_web_security));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
@@ -43,17 +57,20 @@ 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,
|
||||
embedder,
|
||||
options.node_integration,
|
||||
options.plugins,
|
||||
options.disable_web_security,
|
||||
};
|
||||
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,10 +78,19 @@ 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) {
|
||||
if (!ContainsKey(web_contents_map_, guest_instance_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto web_contents = web_contents_map_[guest_instance_id].web_contents;
|
||||
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(
|
||||
@@ -73,16 +99,27 @@ void WebViewManager::RemoveGuest(int guest_instance_id) {
|
||||
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,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "content/public/browser/browser_plugin_guest_manager.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
@@ -20,22 +21,27 @@ class WebViewManager : public content::BrowserPluginGuestManager {
|
||||
explicit WebViewManager(content::BrowserContext* context);
|
||||
virtual ~WebViewManager();
|
||||
|
||||
struct WebViewOptions {
|
||||
bool node_integration;
|
||||
bool plugins;
|
||||
bool disable_web_security;
|
||||
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 +50,32 @@ class WebViewManager : public content::BrowserPluginGuestManager {
|
||||
};
|
||||
std::map<int, WebContentsWithEmbedder> 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<ElementInstanceKey, int> element_instance_id_to_guest_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebViewManager);
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/memory/singleton.h"
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class WebViewManager;
|
||||
@@ -22,8 +26,10 @@ class WebViewRendererState {
|
||||
public:
|
||||
struct WebViewInfo {
|
||||
int guest_instance_id;
|
||||
content::WebContents* embedder;
|
||||
bool node_integration;
|
||||
bool plugins;
|
||||
bool disable_web_security;
|
||||
base::FilePath preload_script;
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
binding = process.atomBinding 'screen'
|
||||
|
||||
checkAppIsReady = ->
|
||||
unless process.type is 'renderer' or require('app').isReady()
|
||||
throw new Error('Can not use screen module before the "ready" event of app module gets emitted')
|
||||
|
||||
module.exports =
|
||||
if process.platform in ['linux', 'win32'] and process.type is 'renderer'
|
||||
# On Linux we could not access screen in renderer process.
|
||||
require('remote').require 'screen'
|
||||
else
|
||||
process.atomBinding 'screen'
|
||||
getCursorScreenPoint: ->
|
||||
checkAppIsReady()
|
||||
binding.getCursorScreenPoint()
|
||||
getPrimaryDisplay: ->
|
||||
checkAppIsReady()
|
||||
binding.getPrimaryDisplay()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define ATOM_VERSION_H
|
||||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 19
|
||||
#define ATOM_MINOR_VERSION 20
|
||||
#define ATOM_PATCH_VERSION 5
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -456,7 +456,7 @@ DWORD CrashService::AsyncSendDump(void* context) {
|
||||
default:
|
||||
report_id = L"<unknown>";
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
VLOG(1) << "dump for pid =" << info->pid << " crash2 id =" << report_id;
|
||||
|
||||
@@ -12,9 +12,12 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "ui/gfx/codec/jpeg_codec.h"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/base/layout.h"
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace {
|
||||
@@ -29,6 +32,8 @@ ScaleFactorPair kScaleFactorPairs[] = {
|
||||
{ "@2x" , 2.0f },
|
||||
{ "@3x" , 3.0f },
|
||||
{ "@1x" , 1.0f },
|
||||
{ "@4x" , 4.0f },
|
||||
{ "@5x" , 5.0f },
|
||||
{ "@1.25x" , 1.25f },
|
||||
{ "@1.33x" , 1.33f },
|
||||
{ "@1.4x" , 1.4f },
|
||||
@@ -40,10 +45,6 @@ ScaleFactorPair kScaleFactorPairs[] = {
|
||||
float GetScaleFactorFromPath(const base::FilePath& path) {
|
||||
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
|
||||
|
||||
// There is no scale info in the file path.
|
||||
if (!EndsWith(filename, "x", true))
|
||||
return 1.0f;
|
||||
|
||||
// We don't try to convert string to float here because it is very very
|
||||
// expensive.
|
||||
for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) {
|
||||
@@ -54,27 +55,9 @@ float GetScaleFactorFromPath(const base::FilePath& path) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void AppendIfExists(std::vector<base::FilePath>* paths,
|
||||
const base::FilePath& path) {
|
||||
if (base::PathExists(path))
|
||||
paths->push_back(path);
|
||||
}
|
||||
|
||||
void PopulatePossibleFilePaths(std::vector<base::FilePath>* paths,
|
||||
const base::FilePath& path) {
|
||||
AppendIfExists(paths, path);
|
||||
|
||||
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
|
||||
if (MatchPattern(filename, "*@*x"))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i)
|
||||
AppendIfExists(paths,
|
||||
path.InsertBeforeExtensionASCII(kScaleFactorPairs[i].name));
|
||||
}
|
||||
|
||||
bool AddImageSkiaRepFromPath(gfx::ImageSkia* image,
|
||||
const base::FilePath& path) {
|
||||
bool AddImageSkiaRep(gfx::ImageSkia* image,
|
||||
const base::FilePath& path,
|
||||
double scale_factor) {
|
||||
std::string file_contents;
|
||||
if (!base::ReadFileToString(path, &file_contents))
|
||||
return false;
|
||||
@@ -89,13 +72,28 @@ bool AddImageSkiaRepFromPath(gfx::ImageSkia* image,
|
||||
// Try JPEG.
|
||||
decoded.reset(gfx::JPEGCodec::Decode(data, size));
|
||||
|
||||
if (decoded) {
|
||||
image->AddRepresentation(gfx::ImageSkiaRep(
|
||||
*decoded.release(), GetScaleFactorFromPath(path)));
|
||||
return true;
|
||||
}
|
||||
if (!decoded)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
image->AddRepresentation(gfx::ImageSkiaRep(*decoded.release(), scale_factor));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
|
||||
const base::FilePath& path) {
|
||||
bool succeed = false;
|
||||
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
|
||||
if (MatchPattern(filename, "*@*x"))
|
||||
// Don't search for other representations if the DPI has been specified.
|
||||
return AddImageSkiaRep(image, path, GetScaleFactorFromPath(path));
|
||||
else
|
||||
succeed |= AddImageSkiaRep(image, path, 1.0f);
|
||||
|
||||
for (const ScaleFactorPair& pair : kScaleFactorPairs)
|
||||
succeed |= AddImageSkiaRep(image,
|
||||
path.InsertBeforeExtensionASCII(pair.name),
|
||||
pair.scale);
|
||||
return succeed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -103,21 +101,27 @@ bool AddImageSkiaRepFromPath(gfx::ImageSkia* image,
|
||||
bool Converter<gfx::ImageSkia>::FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
gfx::ImageSkia* out) {
|
||||
base::FilePath path;
|
||||
if (Converter<base::FilePath>::FromV8(isolate, val, &path)) {
|
||||
std::vector<base::FilePath> paths;
|
||||
PopulatePossibleFilePaths(&paths, path);
|
||||
if (paths.empty())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < paths.size(); ++i) {
|
||||
if (!AddImageSkiaRepFromPath(out, paths[i]))
|
||||
return false;
|
||||
}
|
||||
if (val->IsNull())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
base::FilePath path;
|
||||
if (!Converter<base::FilePath>::FromV8(isolate, val, &path))
|
||||
return false;
|
||||
|
||||
return PopulateImageSkiaRepsFromPath(out, path);
|
||||
}
|
||||
|
||||
bool Converter<gfx::Image>::FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
gfx::Image* out) {
|
||||
gfx::ImageSkia image;
|
||||
if (!ConvertFromV8(isolate, val, &image))
|
||||
return false;
|
||||
|
||||
*out = gfx::Image(image);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace gfx {
|
||||
class Image;
|
||||
class ImageSkia;
|
||||
}
|
||||
|
||||
@@ -20,6 +21,13 @@ struct Converter<gfx::ImageSkia> {
|
||||
gfx::ImageSkia* out);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<gfx::Image> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
gfx::Image* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_
|
||||
|
||||
60
atom/common/native_mate_converters/image_converter_mac.mm
Normal file
60
atom/common/native_mate_converters/image_converter_mac.mm
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/mac/foundation_util.h"
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsTemplateImage(const std::string& path) {
|
||||
return (MatchPattern(path, "*Template.*") ||
|
||||
MatchPattern(path, "*Template@*x.*"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
bool Converter<gfx::ImageSkia>::FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
gfx::ImageSkia* out) {
|
||||
gfx::Image image;
|
||||
if (!ConvertFromV8(isolate, val, &image))
|
||||
return false;
|
||||
|
||||
*out = image.AsImageSkia();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Converter<gfx::Image>::FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
gfx::Image* out) {
|
||||
if (val->IsNull())
|
||||
return true;
|
||||
|
||||
std::string path;
|
||||
if (!ConvertFromV8(isolate, val, &path))
|
||||
return false;
|
||||
|
||||
base::scoped_nsobject<NSImage> image([[NSImage alloc]
|
||||
initByReferencingFile:base::SysUTF8ToNSString(path)]);
|
||||
if (![image isValid])
|
||||
return false;
|
||||
|
||||
if (IsTemplateImage(path))
|
||||
[image setTemplate:YES];
|
||||
|
||||
*out = gfx::Image(image.release());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "atom/common/native_mate_converters/v8_value_converter.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -13,12 +14,70 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxRecursionDepth = 20;
|
||||
|
||||
} // namespace
|
||||
|
||||
// The state of a call to FromV8Value.
|
||||
class V8ValueConverter::FromV8ValueState {
|
||||
public:
|
||||
// Level scope which updates the current depth of some FromV8ValueState.
|
||||
class Level {
|
||||
public:
|
||||
explicit Level(FromV8ValueState* state) : state_(state) {
|
||||
state_->max_recursion_depth_--;
|
||||
}
|
||||
~Level() {
|
||||
state_->max_recursion_depth_++;
|
||||
}
|
||||
|
||||
private:
|
||||
FromV8ValueState* state_;
|
||||
};
|
||||
|
||||
FromV8ValueState() : max_recursion_depth_(kMaxRecursionDepth) {}
|
||||
|
||||
// If |handle| is not in |unique_map_|, then add it to |unique_map_| and
|
||||
// return true.
|
||||
//
|
||||
// Otherwise do nothing and return false. Here "A is unique" means that no
|
||||
// other handle B in the map points to the same object as A. Note that A can
|
||||
// be unique even if there already is another handle with the same identity
|
||||
// hash (key) in the map, because two objects can have the same hash.
|
||||
bool UpdateAndCheckUniqueness(v8::Handle<v8::Object> handle) {
|
||||
typedef HashToHandleMap::const_iterator Iterator;
|
||||
int hash = handle->GetIdentityHash();
|
||||
// We only compare using == with handles to objects with the same identity
|
||||
// hash. Different hash obviously means different objects, but two objects
|
||||
// in a couple of thousands could have the same identity hash.
|
||||
std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash);
|
||||
for (Iterator it = range.first; it != range.second; ++it) {
|
||||
// Operator == for handles actually compares the underlying objects.
|
||||
if (it->second == handle)
|
||||
return false;
|
||||
}
|
||||
unique_map_.insert(std::make_pair(hash, handle));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasReachedMaxRecursionDepth() {
|
||||
return max_recursion_depth_ < 0;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::multimap<int, v8::Handle<v8::Object> > HashToHandleMap;
|
||||
HashToHandleMap unique_map_;
|
||||
|
||||
int max_recursion_depth_;
|
||||
};
|
||||
|
||||
V8ValueConverter::V8ValueConverter()
|
||||
: date_allowed_(false),
|
||||
reg_exp_allowed_(false),
|
||||
function_allowed_(false),
|
||||
strip_null_from_objects_(false),
|
||||
avoid_identity_hash_for_testing_(false) {}
|
||||
strip_null_from_objects_(false) {}
|
||||
|
||||
void V8ValueConverter::SetDateAllowed(bool val) {
|
||||
date_allowed_ = val;
|
||||
@@ -48,8 +107,8 @@ base::Value* V8ValueConverter::FromV8Value(
|
||||
v8::Local<v8::Context> context) const {
|
||||
v8::Context::Scope context_scope(context);
|
||||
v8::HandleScope handle_scope(context->GetIsolate());
|
||||
HashToHandleMap unique_map;
|
||||
return FromV8ValueImpl(val, &unique_map);
|
||||
FromV8ValueState state;
|
||||
return FromV8ValueImpl(&state, val, context->GetIsolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8ValueConverter::ToV8ValueImpl(
|
||||
@@ -141,10 +200,16 @@ v8::Local<v8::Value> V8ValueConverter::ToV8Object(
|
||||
return result;
|
||||
}
|
||||
|
||||
base::Value* V8ValueConverter::FromV8ValueImpl(v8::Local<v8::Value> val,
|
||||
HashToHandleMap* unique_map) const {
|
||||
base::Value* V8ValueConverter::FromV8ValueImpl(
|
||||
FromV8ValueState* state,
|
||||
v8::Handle<v8::Value> val,
|
||||
v8::Isolate* isolate) const {
|
||||
CHECK(!val.IsEmpty());
|
||||
|
||||
FromV8ValueState::Level state_level(state);
|
||||
if (state->HasReachedMaxRecursionDepth())
|
||||
return NULL;
|
||||
|
||||
if (val->IsNull())
|
||||
return base::Value::CreateNullValue();
|
||||
|
||||
@@ -170,7 +235,7 @@ base::Value* V8ValueConverter::FromV8ValueImpl(v8::Local<v8::Value> val,
|
||||
if (!date_allowed_)
|
||||
// JSON.stringify would convert this to a string, but an object is more
|
||||
// consistent within this class.
|
||||
return FromV8Object(val->ToObject(), unique_map);
|
||||
return FromV8Object(val->ToObject(), state, isolate);
|
||||
v8::Date* date = v8::Date::Cast(*val);
|
||||
return new base::FundamentalValue(date->NumberValue() / 1000.0);
|
||||
}
|
||||
@@ -178,35 +243,36 @@ base::Value* V8ValueConverter::FromV8ValueImpl(v8::Local<v8::Value> val,
|
||||
if (val->IsRegExp()) {
|
||||
if (!reg_exp_allowed_)
|
||||
// JSON.stringify converts to an object.
|
||||
return FromV8Object(val->ToObject(), unique_map);
|
||||
return FromV8Object(val->ToObject(), state, isolate);
|
||||
return new base::StringValue(*v8::String::Utf8Value(val->ToString()));
|
||||
}
|
||||
|
||||
// v8::Value doesn't have a ToArray() method for some reason.
|
||||
if (val->IsArray())
|
||||
return FromV8Array(val.As<v8::Array>(), unique_map);
|
||||
return FromV8Array(val.As<v8::Array>(), state, isolate);
|
||||
|
||||
if (val->IsFunction()) {
|
||||
if (!function_allowed_)
|
||||
// JSON.stringify refuses to convert function(){}.
|
||||
return NULL;
|
||||
return FromV8Object(val->ToObject(), unique_map);
|
||||
return FromV8Object(val->ToObject(), state, isolate);
|
||||
}
|
||||
|
||||
if (val->IsObject()) {
|
||||
return FromV8Object(val->ToObject(), unique_map);
|
||||
return FromV8Object(val->ToObject(), state, isolate);
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Unexpected v8 value type encountered.";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base::Value* V8ValueConverter::FromV8Array(v8::Local<v8::Array> val,
|
||||
HashToHandleMap* unique_map) const {
|
||||
if (!UpdateAndCheckUniqueness(unique_map, val))
|
||||
base::Value* V8ValueConverter::FromV8Array(
|
||||
v8::Handle<v8::Array> val,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
if (!state->UpdateAndCheckUniqueness(val))
|
||||
return base::Value::CreateNullValue();
|
||||
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
scoped_ptr<v8::Context::Scope> scope;
|
||||
// If val was created in a different context than our current one, change to
|
||||
// that context, but change back after val is converted.
|
||||
@@ -228,7 +294,7 @@ base::Value* V8ValueConverter::FromV8Array(v8::Local<v8::Array> val,
|
||||
if (!val->HasRealIndexedProperty(i))
|
||||
continue;
|
||||
|
||||
base::Value* child = FromV8ValueImpl(child_v8, unique_map);
|
||||
base::Value* child = FromV8ValueImpl(state, child_v8, isolate);
|
||||
if (child)
|
||||
result->Append(child);
|
||||
else
|
||||
@@ -241,10 +307,11 @@ base::Value* V8ValueConverter::FromV8Array(v8::Local<v8::Array> val,
|
||||
|
||||
base::Value* V8ValueConverter::FromV8Object(
|
||||
v8::Local<v8::Object> val,
|
||||
HashToHandleMap* unique_map) const {
|
||||
if (!UpdateAndCheckUniqueness(unique_map, val))
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
if (!state->UpdateAndCheckUniqueness(val))
|
||||
return base::Value::CreateNullValue();
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
|
||||
scoped_ptr<v8::Context::Scope> scope;
|
||||
// If val was created in a different context than our current one, change to
|
||||
// that context, but change back after val is converted.
|
||||
@@ -281,7 +348,7 @@ base::Value* V8ValueConverter::FromV8Object(
|
||||
child_v8 = v8::Null(isolate);
|
||||
}
|
||||
|
||||
scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_map));
|
||||
scoped_ptr<base::Value> child(FromV8ValueImpl(state, child_v8, isolate));
|
||||
if (!child.get())
|
||||
// JSON.stringify skips properties whose values don't serialize, for
|
||||
// example undefined and functions. Emulate that behavior.
|
||||
@@ -317,24 +384,4 @@ base::Value* V8ValueConverter::FromV8Object(
|
||||
return result.release();
|
||||
}
|
||||
|
||||
bool V8ValueConverter::UpdateAndCheckUniqueness(
|
||||
HashToHandleMap* map,
|
||||
v8::Local<v8::Object> handle) const {
|
||||
typedef HashToHandleMap::const_iterator Iterator;
|
||||
|
||||
int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash();
|
||||
// We only compare using == with handles to objects with the same identity
|
||||
// hash. Different hash obviously means different objects, but two objects in
|
||||
// a couple of thousands could have the same identity hash.
|
||||
std::pair<Iterator, Iterator> range = map->equal_range(hash);
|
||||
for (Iterator it = range.first; it != range.second; ++it) {
|
||||
// Operator == for handles actually compares the underlying objects.
|
||||
if (it->second == handle)
|
||||
return false;
|
||||
}
|
||||
|
||||
map->insert(std::pair<int, v8::Local<v8::Object> >(hash, handle));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_V8_VALUE_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_V8_VALUE_CONVERTER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "v8/include/v8.h"
|
||||
@@ -34,7 +32,7 @@ class V8ValueConverter {
|
||||
v8::Local<v8::Context> context) const;
|
||||
|
||||
private:
|
||||
typedef std::multimap<int, v8::Local<v8::Object> > HashToHandleMap;
|
||||
class FromV8ValueState;
|
||||
|
||||
v8::Local<v8::Value> ToV8ValueImpl(v8::Isolate* isolate,
|
||||
const base::Value* value) const;
|
||||
@@ -44,21 +42,16 @@ class V8ValueConverter {
|
||||
v8::Isolate* isolate,
|
||||
const base::DictionaryValue* dictionary) const;
|
||||
|
||||
base::Value* FromV8ValueImpl(v8::Local<v8::Value> value,
|
||||
HashToHandleMap* unique_map) const;
|
||||
base::Value* FromV8Array(v8::Local<v8::Array> array,
|
||||
HashToHandleMap* unique_map) const;
|
||||
base::Value* FromV8ValueImpl(FromV8ValueState* state,
|
||||
v8::Handle<v8::Value> value,
|
||||
v8::Isolate* isolate) const;
|
||||
base::Value* FromV8Array(v8::Handle<v8::Array> array,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const;
|
||||
|
||||
base::Value* FromV8Object(v8::Local<v8::Object> object,
|
||||
HashToHandleMap* unique_map) const;
|
||||
|
||||
// If |handle| is not in |map|, then add it to |map| and return true.
|
||||
// Otherwise do nothing and return false. Here "A is unique" means that no
|
||||
// other handle B in the map points to the same object as A. Note that A can
|
||||
// be unique even if there already is another handle with the same identity
|
||||
// hash (key) in the map, because two objects can have the same hash.
|
||||
bool UpdateAndCheckUniqueness(HashToHandleMap* map,
|
||||
v8::Local<v8::Object> handle) const;
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const;
|
||||
|
||||
// If true, we will convert Date JavaScript objects to doubles.
|
||||
bool date_allowed_;
|
||||
@@ -73,8 +66,6 @@ class V8ValueConverter {
|
||||
// into Values.
|
||||
bool strip_null_from_objects_;
|
||||
|
||||
bool avoid_identity_hash_for_testing_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(V8ValueConverter);
|
||||
};
|
||||
|
||||
|
||||
@@ -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<node::Environment*>(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<uv_handle_t*>(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<uv_handle_t*>(env->idle_prepare_handle()));
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle()));
|
||||
|
||||
// Register handle cleanups
|
||||
env->RegisterHandleCleanup(
|
||||
reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()),
|
||||
HandleCleanup,
|
||||
nullptr);
|
||||
env->RegisterHandleCleanup(
|
||||
reinterpret_cast<uv_handle_t*>(env->immediate_idle_handle()),
|
||||
HandleCleanup,
|
||||
nullptr);
|
||||
env->RegisterHandleCleanup(
|
||||
reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()),
|
||||
HandleCleanup,
|
||||
nullptr);
|
||||
env->RegisterHandleCleanup(
|
||||
reinterpret_cast<uv_handle_t*>(env->idle_check_handle()),
|
||||
HandleCleanup,
|
||||
nullptr);
|
||||
|
||||
Local<FunctionTemplate> 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;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@ const char kOverlayScrollbars[] = "overlay-scrollbars";
|
||||
const char kOverlayFullscreenVideo[] = "overlay-fullscreen-video";
|
||||
const char kSharedWorker[] = "shared-worker";
|
||||
|
||||
// Disable HTTP cache.
|
||||
const char kDisableHttpCache[] = "disable-http-cache";
|
||||
|
||||
} // namespace switches
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -47,6 +47,8 @@ extern const char kOverlayScrollbars[];
|
||||
extern const char kOverlayFullscreenVideo[];
|
||||
extern const char kSharedWorker[];
|
||||
|
||||
extern const char kDisableHttpCache[];
|
||||
|
||||
} // namespace switches
|
||||
|
||||
} // namespace atom
|
||||
|
||||
247
atom/renderer/api/atom_api_spell_check_client.cc
Normal file
247
atom/renderer/api/atom_api_spell_check_client.cc
Normal file
@@ -0,0 +1,247 @@
|
||||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/renderer/api/atom_api_spell_check_client.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "base/logging.h"
|
||||
#include "native_mate/converter.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "third_party/icu/source/common/unicode/uscript.h"
|
||||
#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
|
||||
#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxAutoCorrectWordSize = 8;
|
||||
|
||||
bool HasWordCharacters(const base::string16& text, int index) {
|
||||
const base::char16* data = text.data();
|
||||
int length = text.length();
|
||||
while (index < length) {
|
||||
uint32 code = 0;
|
||||
U16_NEXT(data, index, length, code);
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
if (uscript_getScript(code, &error) != USCRIPT_COMMON)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SpellCheckClient::SpellCheckClient(const std::string& language,
|
||||
bool auto_spell_correct_turned_on,
|
||||
v8::Isolate* isolate,
|
||||
v8::Handle<v8::Object> provider)
|
||||
: auto_spell_correct_turned_on_(auto_spell_correct_turned_on),
|
||||
isolate_(isolate),
|
||||
provider_(isolate, provider) {
|
||||
character_attributes_.SetDefaultLanguage(language);
|
||||
|
||||
// Persistent the method.
|
||||
mate::Dictionary dict(isolate, provider);
|
||||
dict.Get("spellCheck", &spell_check_);
|
||||
}
|
||||
|
||||
SpellCheckClient::~SpellCheckClient() {}
|
||||
|
||||
void SpellCheckClient::spellCheck(
|
||||
const blink::WebString& text,
|
||||
int& misspelling_start,
|
||||
int& misspelling_len,
|
||||
blink::WebVector<blink::WebString>* optional_suggestions) {
|
||||
std::vector<blink::WebTextCheckingResult> results;
|
||||
SpellCheckText(base::string16(text), true, &results);
|
||||
if (results.size() == 1) {
|
||||
misspelling_start = results[0].location;
|
||||
misspelling_len = results[0].length;
|
||||
}
|
||||
}
|
||||
|
||||
void SpellCheckClient::checkTextOfParagraph(
|
||||
const blink::WebString& text,
|
||||
blink::WebTextCheckingTypeMask mask,
|
||||
blink::WebVector<blink::WebTextCheckingResult>* results) {
|
||||
if (!results)
|
||||
return;
|
||||
|
||||
if (!(mask & blink::WebTextCheckingTypeSpelling))
|
||||
return;
|
||||
|
||||
NOTREACHED() << "checkTextOfParagraph should never be called";
|
||||
}
|
||||
|
||||
void SpellCheckClient::requestCheckingOfText(
|
||||
const blink::WebString& textToCheck,
|
||||
const blink::WebVector<uint32_t>& markersInText,
|
||||
const blink::WebVector<unsigned>& markerOffsets,
|
||||
blink::WebTextCheckingCompletion* completionCallback) {
|
||||
base::string16 text(textToCheck);
|
||||
if (text.empty() || !HasWordCharacters(text, 0)) {
|
||||
completionCallback->didCancelCheckingText();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<blink::WebTextCheckingResult> results;
|
||||
SpellCheckText(text, false, &results);
|
||||
completionCallback->didFinishCheckingText(results);
|
||||
}
|
||||
|
||||
blink::WebString SpellCheckClient::autoCorrectWord(
|
||||
const blink::WebString& misspelledWord) {
|
||||
if (auto_spell_correct_turned_on_)
|
||||
return GetAutoCorrectionWord(base::string16(misspelledWord));
|
||||
else
|
||||
return blink::WebString();
|
||||
}
|
||||
|
||||
void SpellCheckClient::showSpellingUI(bool show) {
|
||||
}
|
||||
|
||||
bool SpellCheckClient::isShowingSpellingUI() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SpellCheckClient::updateSpellingUIWithMisspelledWord(
|
||||
const blink::WebString& word) {
|
||||
}
|
||||
|
||||
void SpellCheckClient::SpellCheckText(
|
||||
const base::string16& text,
|
||||
bool stop_at_first_result,
|
||||
std::vector<blink::WebTextCheckingResult>* results) {
|
||||
if (text.length() == 0 || spell_check_.IsEmpty())
|
||||
return;
|
||||
|
||||
base::string16 word;
|
||||
int word_start;
|
||||
int word_length;
|
||||
if (!text_iterator_.IsInitialized() &&
|
||||
!text_iterator_.Initialize(&character_attributes_, true)) {
|
||||
// We failed to initialize text_iterator_, return as spelled correctly.
|
||||
VLOG(1) << "Failed to initialize SpellcheckWordIterator";
|
||||
return;
|
||||
}
|
||||
|
||||
base::string16 in_word(text);
|
||||
text_iterator_.SetText(in_word.c_str(), in_word.size());
|
||||
while (text_iterator_.GetNextWord(&word, &word_start, &word_length)) {
|
||||
// Found a word (or a contraction) that the spellchecker can check the
|
||||
// spelling of.
|
||||
if (SpellCheckWord(word))
|
||||
continue;
|
||||
|
||||
// If the given word is a concatenated word of two or more valid words
|
||||
// (e.g. "hello:hello"), we should treat it as a valid word.
|
||||
if (IsValidContraction(word))
|
||||
continue;
|
||||
|
||||
blink::WebTextCheckingResult result;
|
||||
result.location = word_start;
|
||||
result.length = word_length;
|
||||
results->push_back(result);
|
||||
|
||||
if (stop_at_first_result)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellCheckClient::SpellCheckWord(const base::string16& word_to_check) {
|
||||
if (spell_check_.IsEmpty())
|
||||
return true;
|
||||
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
v8::Handle<v8::Value> word = mate::ConvertToV8(isolate_, word_to_check);
|
||||
v8::Handle<v8::Value> result = spell_check_.NewHandle()->Call(
|
||||
provider_.NewHandle(), 1, &word);
|
||||
|
||||
if (result->IsBoolean())
|
||||
return result->BooleanValue();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
base::string16 SpellCheckClient::GetAutoCorrectionWord(
|
||||
const base::string16& word) {
|
||||
base::string16 autocorrect_word;
|
||||
|
||||
int word_length = static_cast<int>(word.size());
|
||||
if (word_length < 2 || word_length > kMaxAutoCorrectWordSize)
|
||||
return autocorrect_word;
|
||||
|
||||
base::char16 misspelled_word[kMaxAutoCorrectWordSize + 1];
|
||||
const base::char16* word_char = word.c_str();
|
||||
for (int i = 0; i <= kMaxAutoCorrectWordSize; ++i) {
|
||||
if (i >= word_length)
|
||||
misspelled_word[i] = 0;
|
||||
else
|
||||
misspelled_word[i] = word_char[i];
|
||||
}
|
||||
|
||||
// Swap adjacent characters and spellcheck.
|
||||
int misspelling_start, misspelling_len;
|
||||
for (int i = 0; i < word_length - 1; i++) {
|
||||
// Swap.
|
||||
std::swap(misspelled_word[i], misspelled_word[i + 1]);
|
||||
|
||||
// Check spelling.
|
||||
misspelling_start = misspelling_len = 0;
|
||||
spellCheck(blink::WebString(misspelled_word, word_length),
|
||||
misspelling_start,
|
||||
misspelling_len,
|
||||
NULL);
|
||||
|
||||
// Make decision: if only one swap produced a valid word, then we want to
|
||||
// return it. If we found two or more, we don't do autocorrection.
|
||||
if (misspelling_len == 0) {
|
||||
if (autocorrect_word.empty()) {
|
||||
autocorrect_word.assign(misspelled_word);
|
||||
} else {
|
||||
autocorrect_word.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the swapped characters.
|
||||
std::swap(misspelled_word[i], misspelled_word[i + 1]);
|
||||
}
|
||||
return autocorrect_word;
|
||||
}
|
||||
|
||||
// Returns whether or not the given string is a valid contraction.
|
||||
// This function is a fall-back when the SpellcheckWordIterator class
|
||||
// returns a concatenated word which is not in the selected dictionary
|
||||
// (e.g. "in'n'out") but each word is valid.
|
||||
bool SpellCheckClient::IsValidContraction(const base::string16& contraction) {
|
||||
if (!contraction_iterator_.IsInitialized() &&
|
||||
!contraction_iterator_.Initialize(&character_attributes_, false)) {
|
||||
// We failed to initialize the word iterator, return as spelled correctly.
|
||||
VLOG(1) << "Failed to initialize contraction_iterator_";
|
||||
return true;
|
||||
}
|
||||
|
||||
contraction_iterator_.SetText(contraction.c_str(), contraction.length());
|
||||
|
||||
base::string16 word;
|
||||
int word_start;
|
||||
int word_length;
|
||||
|
||||
while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) {
|
||||
if (!SpellCheckWord(word))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
93
atom/renderer/api/atom_api_spell_check_client.h
Normal file
93
atom/renderer/api/atom_api_spell_check_client.h
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_RENDERER_API_ATOM_API_SPELL_CHECK_CLIENT_H_
|
||||
#define ATOM_RENDERER_API_ATOM_API_SPELL_CHECK_CLIENT_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "chrome/renderer/spellchecker/spellcheck_worditerator.h"
|
||||
#include "native_mate/scoped_persistent.h"
|
||||
#include "third_party/WebKit/public/web/WebSpellCheckClient.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class SpellCheckClient : public blink::WebSpellCheckClient {
|
||||
public:
|
||||
SpellCheckClient(const std::string& language,
|
||||
bool auto_spell_correct_turned_on,
|
||||
v8::Isolate* isolate,
|
||||
v8::Handle<v8::Object> provider);
|
||||
virtual ~SpellCheckClient();
|
||||
|
||||
private:
|
||||
// blink::WebSpellCheckClient:
|
||||
void spellCheck(
|
||||
const blink::WebString& text,
|
||||
int& misspelledOffset,
|
||||
int& misspelledLength,
|
||||
blink::WebVector<blink::WebString>* optionalSuggestions) override;
|
||||
void checkTextOfParagraph(
|
||||
const blink::WebString&,
|
||||
blink::WebTextCheckingTypeMask mask,
|
||||
blink::WebVector<blink::WebTextCheckingResult>* results) override;
|
||||
void requestCheckingOfText(
|
||||
const blink::WebString& textToCheck,
|
||||
const blink::WebVector<uint32_t>& markersInText,
|
||||
const blink::WebVector<unsigned>& markerOffsets,
|
||||
blink::WebTextCheckingCompletion* completionCallback) override;
|
||||
blink::WebString autoCorrectWord(
|
||||
const blink::WebString& misspelledWord) override;
|
||||
void showSpellingUI(bool show) override;
|
||||
bool isShowingSpellingUI() override;
|
||||
void updateSpellingUIWithMisspelledWord(
|
||||
const blink::WebString& word) override;
|
||||
|
||||
// Check the spelling of text.
|
||||
void SpellCheckText(const base::string16& text,
|
||||
bool stop_at_first_result,
|
||||
std::vector<blink::WebTextCheckingResult>* results);
|
||||
|
||||
// Call JavaScript to check spelling a word.
|
||||
bool SpellCheckWord(const base::string16& word_to_check);
|
||||
|
||||
// Find a possible correctly spelled word for a misspelled word. Computes an
|
||||
// empty string if input misspelled word is too long, there is ambiguity, or
|
||||
// the correct spelling cannot be determined.
|
||||
base::string16 GetAutoCorrectionWord(const base::string16& word);
|
||||
|
||||
// Returns whether or not the given word is a contraction of valid words
|
||||
// (e.g. "word:word").
|
||||
bool IsValidContraction(const base::string16& word);
|
||||
|
||||
// Represents character attributes used for filtering out characters which
|
||||
// are not supported by this SpellCheck object.
|
||||
SpellcheckCharAttribute character_attributes_;
|
||||
|
||||
// Represents word iterators used in this spellchecker. The |text_iterator_|
|
||||
// splits text provided by WebKit into words, contractions, or concatenated
|
||||
// words. The |contraction_iterator_| splits a concatenated word extracted by
|
||||
// |text_iterator_| into word components so we can treat a concatenated word
|
||||
// consisting only of correct words as a correct word.
|
||||
SpellcheckWordIterator text_iterator_;
|
||||
SpellcheckWordIterator contraction_iterator_;
|
||||
|
||||
bool auto_spell_correct_turned_on_;
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
mate::ScopedPersistent<v8::Object> provider_;
|
||||
mate::ScopedPersistent<v8::Function> spell_check_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SpellCheckClient);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_RENDERER_API_ATOM_API_SPELL_CHECK_CLIENT_H_
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "atom/renderer/api/atom_api_web_frame.h"
|
||||
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/renderer/api/atom_api_spell_check_client.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 +53,24 @@ v8::Handle<v8::Value> WebFrame::RegisterEmbedderCustomElement(
|
||||
return web_frame_->document().registerEmbedderCustomElement(name, options, c);
|
||||
}
|
||||
|
||||
void WebFrame::AttachGuest(int id) {
|
||||
content::RenderFrame::FromWebFrame(web_frame_)->AttachGuest(id);
|
||||
}
|
||||
|
||||
void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
|
||||
const std::string& language,
|
||||
bool auto_spell_correct_turned_on,
|
||||
v8::Handle<v8::Object> provider) {
|
||||
if (!provider->Has(mate::StringToV8(args->isolate(), "spellCheck"))) {
|
||||
args->ThrowError("\"spellCheck\" has to be defined");
|
||||
return;
|
||||
}
|
||||
|
||||
spell_check_client_.reset(new SpellCheckClient(
|
||||
language, auto_spell_correct_turned_on, args->isolate(), provider));
|
||||
web_frame_->view()->setSpellCheckClient(spell_check_client_.get());
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
@@ -60,7 +80,9 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
|
||||
.SetMethod("setZoomFactor", &WebFrame::SetZoomFactor)
|
||||
.SetMethod("getZoomFactor", &WebFrame::GetZoomFactor)
|
||||
.SetMethod("registerEmbedderCustomElement",
|
||||
&WebFrame::RegisterEmbedderCustomElement);
|
||||
&WebFrame::RegisterEmbedderCustomElement)
|
||||
.SetMethod("attachGuest", &WebFrame::AttachGuest)
|
||||
.SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
@@ -14,10 +15,16 @@ namespace blink {
|
||||
class WebLocalFrame;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Arguments;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class SpellCheckClient;
|
||||
|
||||
class WebFrame : public mate::Wrappable {
|
||||
public:
|
||||
static mate::Handle<WebFrame> Create(v8::Isolate* isolate);
|
||||
@@ -35,11 +42,20 @@ class WebFrame : public mate::Wrappable {
|
||||
|
||||
v8::Handle<v8::Value> RegisterEmbedderCustomElement(
|
||||
const base::string16& name, v8::Handle<v8::Object> options);
|
||||
void AttachGuest(int element_instance_id);
|
||||
|
||||
// Set the provider that will be used by SpellCheckClient for spell check.
|
||||
void SetSpellCheckProvider(mate::Arguments* args,
|
||||
const std::string& language,
|
||||
bool auto_spell_correct_turned_on,
|
||||
v8::Handle<v8::Object> provider);
|
||||
|
||||
// mate::Wrappable:
|
||||
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate);
|
||||
|
||||
scoped_ptr<SpellCheckClient> spell_check_client_;
|
||||
|
||||
blink::WebLocalFrame* web_frame_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebFrame);
|
||||
|
||||
@@ -16,6 +16,9 @@ class Ipc extends EventEmitter
|
||||
sendSync: (args...) ->
|
||||
JSON.parse ipc.sendSync('ipc-message-sync', [args...])
|
||||
|
||||
sendToHost: (args...) ->
|
||||
ipc.send 'ipc-message-host', [args...]
|
||||
|
||||
# Discarded
|
||||
sendChannel: -> @send.apply this, arguments
|
||||
sendChannelSync: -> @sendSync.apply this, arguments
|
||||
|
||||
@@ -40,7 +40,7 @@ metaToValue = (meta) ->
|
||||
constructor: ->
|
||||
if @constructor == RemoteFunction
|
||||
# Constructor call.
|
||||
obj = ipc.sendChannelSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)
|
||||
obj = ipc.sendSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)
|
||||
|
||||
# Returning object in constructor will replace constructed object
|
||||
# with the returned object.
|
||||
@@ -48,7 +48,7 @@ metaToValue = (meta) ->
|
||||
return metaToValue obj
|
||||
else
|
||||
# Function call.
|
||||
ret = ipc.sendChannelSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)
|
||||
ret = ipc.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)
|
||||
return metaToValue ret
|
||||
else
|
||||
ret = v8Util.createObjectWithName meta.name
|
||||
@@ -62,27 +62,27 @@ metaToValue = (meta) ->
|
||||
constructor: ->
|
||||
if @constructor is RemoteMemberFunction
|
||||
# Constructor call.
|
||||
obj = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', meta.id, member.name, wrapArgs(arguments)
|
||||
obj = ipc.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', meta.id, member.name, wrapArgs(arguments)
|
||||
return metaToValue obj
|
||||
else
|
||||
# Call member function.
|
||||
ret = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments)
|
||||
ret = ipc.sendSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments)
|
||||
return metaToValue ret
|
||||
else
|
||||
ret.__defineSetter__ member.name, (value) ->
|
||||
# Set member data.
|
||||
ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
|
||||
ipc.sendSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
|
||||
value
|
||||
|
||||
ret.__defineGetter__ member.name, ->
|
||||
# Get member data.
|
||||
ret = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name
|
||||
ret = ipc.sendSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name
|
||||
metaToValue ret
|
||||
|
||||
# Track delegate object's life time, and tell the browser to clean up
|
||||
# when the object is GCed.
|
||||
v8Util.setDestructor ret, ->
|
||||
ipc.sendChannel 'ATOM_BROWSER_DEREFERENCE', meta.storeId
|
||||
ipc.send 'ATOM_BROWSER_DEREFERENCE', meta.storeId
|
||||
|
||||
# Remember object's id.
|
||||
v8Util.setHiddenValue ret, 'atomId', meta.id
|
||||
@@ -104,19 +104,19 @@ moduleCache = {}
|
||||
exports.require = (module) ->
|
||||
return moduleCache[module] if moduleCache[module]?
|
||||
|
||||
meta = ipc.sendChannelSync 'ATOM_BROWSER_REQUIRE', module
|
||||
meta = ipc.sendSync 'ATOM_BROWSER_REQUIRE', module
|
||||
moduleCache[module] = metaToValue meta
|
||||
|
||||
# Get current window object.
|
||||
windowCache = null
|
||||
exports.getCurrentWindow = ->
|
||||
return windowCache if windowCache?
|
||||
meta = ipc.sendChannelSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId
|
||||
meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId
|
||||
windowCache = metaToValue meta
|
||||
|
||||
# Get a global object in browser.
|
||||
exports.getGlobal = (name) ->
|
||||
meta = ipc.sendChannelSync 'ATOM_BROWSER_GLOBAL', name
|
||||
meta = ipc.sendSync 'ATOM_BROWSER_GLOBAL', name
|
||||
metaToValue meta
|
||||
|
||||
# Get the process object in browser.
|
||||
@@ -133,5 +133,5 @@ exports.createFunctionWithReturnValue = (returnValue) ->
|
||||
|
||||
# Get the guest WebContents from guestInstanceId.
|
||||
exports.getGuestWebContents = (guestInstanceId) ->
|
||||
meta = ipc.sendChannelSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId
|
||||
meta = ipc.sendSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId
|
||||
metaToValue meta
|
||||
|
||||
@@ -92,7 +92,7 @@ void AtomRendererClient::WebKitInitialized() {
|
||||
v8::Isolate* isolate = blink::mainThreadIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> 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<v8::Context> context,
|
||||
int world_id) {
|
||||
node::Environment* env = node::Environment::GetCurrent(context);
|
||||
|
||||
@@ -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<v8::Context> context,
|
||||
int world_id);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 = '<webview>: ' +
|
||||
'Script cannot be injected into content until the page has loaded.'
|
||||
ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE = '<webview>: ' +
|
||||
'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 <object> 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 <webview> element to the DOM.
|
||||
reset: ->
|
||||
# If guestInstanceId is defined then the <webview> 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 <webview>.request property.
|
||||
setRequestPropertyOnWebViewNode: (request) ->
|
||||
Object.defineProperty @webviewNode, 'request', value: request, enumerable: true
|
||||
|
||||
setupFocusPropagation: ->
|
||||
unless @webviewNode.hasAttribute 'tabIndex'
|
||||
# <webview> needs a tabIndex in order to be focusable.
|
||||
# TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
|
||||
# to allow <webview> to be focusable.
|
||||
# See http://crbug.com/231664.
|
||||
@webviewNode.setAttribute 'tabIndex', -1
|
||||
@webviewNode.addEventListener 'focus', (e) =>
|
||||
# Focus the BrowserPlugin when the <webview> takes focus.
|
||||
@browserPluginNode.focus()
|
||||
@webviewNode.addEventListener 'blur', (e) =>
|
||||
# Blur the BrowserPlugin when the <webview> 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 <webview> 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 <webview> 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 <webview>
|
||||
# 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 <webview> has actually
|
||||
# changed.
|
||||
@dispatchEvent webViewEvent
|
||||
|
||||
# Returns if <object> 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<event>' 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 <object> custom element.
|
||||
registerBrowserPluginElement = ->
|
||||
proto = Object.create HTMLObjectElement.prototype
|
||||
|
||||
proto.createdCallback = ->
|
||||
@setAttribute 'type', 'application/browser-plugin'
|
||||
@setAttribute 'id', 'browser-plugin-' + getNextId()
|
||||
# The <object> node fills in the <webview> 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 <webview> 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
|
||||
@@ -1,4 +1,5 @@
|
||||
ipc = require 'ipc'
|
||||
webFrame = require 'web-frame'
|
||||
|
||||
requestId = 0
|
||||
|
||||
@@ -27,7 +28,13 @@ module.exports =
|
||||
ipc.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{viewInstanceId}", (event, args...) ->
|
||||
dispatchEvent webView, event, args...
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED', (args...) ->
|
||||
ipc.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{viewInstanceId}", (channel, args...) ->
|
||||
domEvent = new Event('ipc-message')
|
||||
domEvent.channel = channel
|
||||
domEvent.args = [args...]
|
||||
webView.dispatchEvent domEvent
|
||||
|
||||
ipc.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{viewInstanceId}", (args...) ->
|
||||
domEvent = new Event('size-changed')
|
||||
for f, i in ['oldWidth', 'oldHeight', 'newWidth', 'newHeight']
|
||||
domEvent[f] = args[i]
|
||||
@@ -36,7 +43,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
|
||||
208
atom/renderer/lib/web-view/web-view-attributes.coffee
Normal file
208
atom/renderer/lib/web-view/web-view-attributes.coffee
Normal file
@@ -0,0 +1,208 @@
|
||||
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 <webview> 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_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, 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)
|
||||
29
atom/renderer/lib/web-view/web-view-constants.coffee
Normal file
29
atom/renderer/lib/web-view/web-view-constants.coffee
Normal file
@@ -0,0 +1,29 @@
|
||||
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_DISABLEWEBSECURITY: 'disablewebsecurity'
|
||||
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: '<webview>: ' +
|
||||
'Script cannot be injected into content until the page has loaded.'
|
||||
ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE: '<webview>: ' +
|
||||
'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.'
|
||||
299
atom/renderer/lib/web-view/web-view.coffee
Normal file
299
atom/renderer/lib/web-view/web-view.coffee
Normal file
@@ -0,0 +1,299 @@
|
||||
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 <webview> element to the DOM.
|
||||
reset: ->
|
||||
# If guestInstanceId is defined then the <webview> 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
|
||||
@attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true
|
||||
@contentWindow = null
|
||||
@internalInstanceId = 0
|
||||
|
||||
# Sets the <webview>.request property.
|
||||
setRequestPropertyOnWebViewNode: (request) ->
|
||||
Object.defineProperty @webviewNode, 'request', value: request, enumerable: true
|
||||
|
||||
setupFocusPropagation: ->
|
||||
unless @webviewNode.hasAttribute 'tabIndex'
|
||||
# <webview> needs a tabIndex in order to be focusable.
|
||||
# TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
|
||||
# to allow <webview> to be focusable.
|
||||
# See http://crbug.com/231664.
|
||||
@webviewNode.setAttribute 'tabIndex', -1
|
||||
@webviewNode.addEventListener 'focus', (e) =>
|
||||
# Focus the BrowserPlugin when the <webview> takes focus.
|
||||
@browserPluginNode.focus()
|
||||
@webviewNode.addEventListener 'blur', (e) =>
|
||||
# Blur the BrowserPlugin when the <webview> 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 <webview> 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 <webview>
|
||||
# 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 <webview> 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<event>' 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 <object> custom element.
|
||||
registerBrowserPluginElement = ->
|
||||
proto = Object.create HTMLObjectElement.prototype
|
||||
|
||||
proto.createdCallback = ->
|
||||
@setAttribute 'type', 'application/browser-plugin'
|
||||
@setAttribute 'id', 'browser-plugin-' + getNextId()
|
||||
# The <object> node fills in the <webview> 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 <webview> 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
|
||||
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.github.atom.helper</string>
|
||||
<string>com.github.atom-shell.helper</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -32,29 +32,25 @@ void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& 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<JobEventDetails>(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<PrintJob> 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<PrintJob> 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.
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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<PrinterQuery> PrintQueriesQueue::PopPrinterQuery(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery() {
|
||||
scoped_refptr<PrinterQuery> job = new printing::PrinterQuery;
|
||||
base::AutoLock lock(lock_);
|
||||
job->SetWorkerDestination(destination_);
|
||||
scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery(
|
||||
int render_process_id,
|
||||
int render_view_id) {
|
||||
scoped_refptr<PrinterQuery> 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<PrintQueriesQueue> 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;
|
||||
}
|
||||
|
||||
@@ -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<PrintQueriesQueue> {
|
||||
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<PrintQueriesQueue> {
|
||||
scoped_refptr<PrinterQuery> PopPrinterQuery(int document_cookie);
|
||||
|
||||
// Creates new query.
|
||||
scoped_refptr<PrinterQuery> CreatePrinterQuery();
|
||||
scoped_refptr<PrinterQuery> CreatePrinterQuery(int render_process_id,
|
||||
int render_view_id);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
@@ -54,8 +52,6 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe<PrintQueriesQueue> {
|
||||
|
||||
PrinterQueries queued_queries_;
|
||||
|
||||
scoped_refptr<PrintDestinationInterface> destination_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PrintQueriesQueue);
|
||||
};
|
||||
|
||||
|
||||
@@ -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<printing::PrintJobWorkerOwner>& 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<JobEventDetails>(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<PrintingUIWebContentsObserver> 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<base::DictionaryValue> 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<base::DictionaryValue> 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<PrintingUIWebContentsObserver> 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<PrintedPage> 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<PrintedPage>()));
|
||||
owner_->PostTask(FROM_HERE,
|
||||
base::Bind(&NotificationCallback,
|
||||
make_scoped_refptr(owner_),
|
||||
JobEventDetails::DOC_DONE,
|
||||
document_,
|
||||
scoped_refptr<PrintedPage>()));
|
||||
|
||||
// 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<uint8> metabytes(page->metafile()->GetDataSize());
|
||||
bool success = page->metafile()->GetData(
|
||||
reinterpret_cast<void*>(&metabytes[0]), metabytes.size());
|
||||
DCHECK(success) << "Failed to get metafile data.";
|
||||
destination_->SetPageContent(
|
||||
page->page_number(),
|
||||
reinterpret_cast<void*>(&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<PrintJobWorkerOwner> handle(owner_);
|
||||
|
||||
owner_->message_loop()->PostTask(
|
||||
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
|
||||
JobEventDetails::FAILED, document_,
|
||||
scoped_refptr<PrintedPage>()));
|
||||
owner_->PostTask(FROM_HERE,
|
||||
base::Bind(&NotificationCallback,
|
||||
make_scoped_refptr(owner_),
|
||||
JobEventDetails::FAILED,
|
||||
document_,
|
||||
scoped_refptr<PrintedPage>()));
|
||||
Cancel();
|
||||
|
||||
// Makes sure the variables are reinitialized.
|
||||
|
||||
@@ -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<PrintingUIWebContentsObserver> 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<base::DictionaryValue> 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<PrintingUIWebContentsObserver> 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<base::DictionaryValue> 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<PrintingContext::Delegate> printing_context_delegate_;
|
||||
|
||||
// Information about the printer setting.
|
||||
scoped_ptr<PrintingContext> printing_context_;
|
||||
|
||||
// The printed document. Only has read-only access.
|
||||
scoped_refptr<PrintedDocument> document_;
|
||||
|
||||
// The print destination, may be NULL.
|
||||
scoped_refptr<PrintDestinationInterface> 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<base::SequencedTaskRunner> task_runner_;
|
||||
|
||||
// Used to generate a WeakPtr for callbacks.
|
||||
base::WeakPtrFactory<PrintJobWorker> weak_factory_;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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<PrintJobWorkerOwner> {
|
||||
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<PrintJobWorkerOwner>;
|
||||
|
||||
virtual ~PrintJobWorkerOwner() {}
|
||||
virtual ~PrintJobWorkerOwner();
|
||||
|
||||
// Task runner reference. Used to send notifications in the right
|
||||
// thread.
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner_;
|
||||
};
|
||||
|
||||
} // namespace printing
|
||||
|
||||
@@ -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<NativeMetafile> metafile(new NativeMetafile);
|
||||
scoped_ptr<PdfMetafileSkia> 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<NativeMetafile> 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<MetafilePlayer>(),
|
||||
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<PrinterQuery> 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<printing::PrinterQuery> printer_query;
|
||||
printer_query = queue_->PopPrinterQuery(cookie);
|
||||
if (!printer_query)
|
||||
if (!printer_query.get())
|
||||
return;
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::IO, FROM_HERE,
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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<PrintingUIWebContentsObserver> 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<base::DictionaryValue> 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;
|
||||
|
||||
@@ -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<PrintingUIWebContentsObserver> 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<base::DictionaryValue> 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.
|
||||
|
||||
@@ -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 <fcntl.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#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<int, base::FilePath> SequenceToPathMap;
|
||||
|
||||
struct PrintingSequencePathMap {
|
||||
SequenceToPathMap map;
|
||||
int sequence;
|
||||
};
|
||||
|
||||
// No locking, only access on the FILE thread.
|
||||
static base::LazyInstance<PrintingSequencePathMap>
|
||||
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<printing::PrinterQuery> printer_query) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
|
||||
if (wc) {
|
||||
scoped_ptr<PrintingUIWebContentsObserver> 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<printing::PrinterQuery> 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<printing::PrinterQuery> printer_query;
|
||||
if (false) {
|
||||
scoped_refptr<PrinterQuery> 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<printing::PrinterQuery> printer_query,
|
||||
scoped_refptr<PrinterQuery> 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<printing::PrinterQuery> printer_query =
|
||||
scoped_refptr<PrinterQuery> 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<printing::PrinterQuery> printer_query,
|
||||
scoped_refptr<PrinterQuery> 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
|
||||
|
||||
@@ -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<printing::PrinterQuery> printer_query);
|
||||
|
||||
void OnGetPrintSettingsFailed(
|
||||
const base::Closure& callback,
|
||||
scoped_refptr<printing::PrinterQuery> printer_query);
|
||||
|
||||
// Get the default print setting.
|
||||
void OnGetDefaultPrintSettings(IPC::Message* reply_msg);
|
||||
void OnGetDefaultPrintSettingsReply(
|
||||
scoped_refptr<printing::PrinterQuery> printer_query,
|
||||
IPC::Message* reply_msg);
|
||||
void OnGetDefaultPrintSettingsReply(scoped_refptr<PrinterQuery> 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<printing::PrinterQuery> printer_query,
|
||||
IPC::Message* reply_msg);
|
||||
void OnScriptedPrintReply(scoped_refptr<PrinterQuery> 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<printing::PrintQueriesQueue> queue_;
|
||||
scoped_refptr<PrintQueriesQueue> queue_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter);
|
||||
};
|
||||
|
||||
} // namespace printing
|
||||
|
||||
#endif // CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_
|
||||
|
||||
@@ -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 <gtk/gtk.h>
|
||||
|
||||
#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
|
||||
@@ -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_
|
||||
@@ -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 <gtk/gtk.h>
|
||||
|
||||
#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
|
||||
@@ -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<AppIndicatorIconMenu> menu_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Gtk2StatusIcon);
|
||||
};
|
||||
|
||||
} // namespace libgtk2ui
|
||||
|
||||
#endif // CHROME_BROWSER_UI_LIBGTK2UI_GTK2_STATUS_ICON_H_
|
||||
@@ -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<PrintWebViewHelper>(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<base::SharedMemory> 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
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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<PrepareFrameAndViewForPrint> prep_frame_view_;
|
||||
bool reset_prep_frame_view_;
|
||||
|
||||
scoped_ptr<PrintMsg_PrintPages_Params> 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<PrintWebViewHelper> weak_ptr_factory_;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user