Compare commits

..

175 Commits

Author SHA1 Message Date
Cheng Zhao
506237f5d6 Bump v0.20.5 2015-01-07 23:27:58 -08:00
Cheng Zhao
609e3ec3ff Don't allow duplicate object in a parsed array
This feature was introduced to fix #874 but caused the converter to go
through a deep nested object sometimes, which made program crash on
Windows. So we have to revert the fix even though it makes a regression.

Fixes atom/atom#4904.
2015-01-07 23:20:03 -08:00
Cheng Zhao
640c8f88ff Bump v0.20.4 2015-01-05 15:51:29 -08:00
Cheng Zhao
d0ed681643 Merge pull request #977 from atom/dialog-icon
Add "icon" option for dialog.showMessageBox
2015-01-05 15:50:33 -08:00
Cheng Zhao
5656714b27 docs: "icon" option of dialog.showMessageBox 2015-01-05 15:30:54 -08:00
Cheng Zhao
ecb9e93394 File dialogs don't need icon 2015-01-05 15:29:26 -08:00
Cheng Zhao
708e738521 views: Fix showing icon in message dialog 2015-01-05 15:26:35 -08:00
Cheng Zhao
8457090b18 Add "icon" option for message box 2015-01-05 15:08:42 -08:00
Cheng Zhao
513052de87 Enable initializing an empty image 2015-01-05 14:55:06 -08:00
Cheng Zhao
d65919d896 Add --disable-http-cache switch, fixes #891 2015-01-05 13:40:38 -08:00
Cheng Zhao
895ccf69a7 Avoid using app API in renderer process for #907 2015-01-04 22:51:00 -08:00
Cheng Zhao
3063b5189a Upgrade brightray for #941 2015-01-04 22:33:02 -08:00
Cheng Zhao
335cd79b37 Don't call Screen functions until app is ready
Fixes #907.
2015-01-04 22:27:02 -08:00
Cheng Zhao
e3bad233e9 Upgrade native_mate to fix throwing exception from constructor 2015-01-04 22:13:46 -08:00
Cheng Zhao
7abb08cc25 docs: Document dialog.showErrorBox, fixes #909 2015-01-04 21:56:45 -08:00
Cheng Zhao
31bdfc2281 Merge pull request #972 from atom/template-image
Add support for template image
2015-01-02 19:43:17 -08:00
Cheng Zhao
bf14f67cb8 win: Fix building 2015-01-02 19:31:19 -08:00
Cheng Zhao
ef7a60807b linux: Fix building 2015-01-02 19:26:17 -08:00
Cheng Zhao
f17673be9c docs: Template image 2015-01-02 19:15:09 -08:00
Cheng Zhao
079f81b304 mac: Add support for template image 2015-01-02 19:01:38 -08:00
Cheng Zhao
ab83b21fa6 Use gfx::Image instead of gfx::ImageSkia in API
The gfx::Image can use NSImage directly as underlying format, so we
don't have to decode images ourselves on Mac, and we will also be able
to make use of template images.
2015-01-02 18:43:56 -08:00
Cheng Zhao
3d7da455bc mac: Check for invalid image 2015-01-02 18:35:33 -08:00
Cheng Zhao
ac8a9afada mac: Initialize gfx::ImageSkia from gfx::Image 2015-01-02 18:34:13 -08:00
Cheng Zhao
8faab22f5e mac: Initialize gfx::Image from NSImage 2015-01-02 18:24:23 -08:00
Cheng Zhao
40679ae82c Simplify the image_converter.cc 2015-01-02 18:10:29 -08:00
Cheng Zhao
f972c38bc8 Add converters for gfx::Image 2015-01-02 17:13:26 -08:00
Cheng Zhao
e1f0f02da9 Upgrade brightray for #969 2015-01-02 15:18:55 -08:00
Cheng Zhao
b4d9c92705 Merge pull request #966 from ttilley/master
fix typo in atom.gyp
2015-01-02 12:10:32 -08:00
Travis Tilley
44b932f90b fix typo in atom.gyp
use product_name instead of project_name when creating framework symlinks; fixes build on MacOS
2015-01-01 10:51:59 -05:00
Cheng Zhao
c5411c3291 docs: Add troubleshooting for runnin on Git Bash, closed #711 2014-12-29 19:09:36 -08:00
Cheng Zhao
7dc8ede90f Bump v0.20.3 2014-12-29 12:21:35 -08:00
Cheng Zhao
b94375c794 Merge pull request #962 from atom/fix-rename-bundle
Fix renaming application bundle on Mac
2014-12-29 12:20:38 -08:00
Cheng Zhao
45c2cda6bb docs: Mention the GYP_DEFINES way of rebranding 2014-12-29 12:12:04 -08:00
Cheng Zhao
5c65f037b0 docs: Update Application Distribution 2014-12-29 10:46:15 -08:00
Cheng Zhao
de55d8c292 Make product_name and project_name configurable
Now users can make use of GYP_DEFINES to custom application name:

export GYP_DEFINES="product_name=MyApp project_name=myapp"
./script/update.py
./script/build.py -C Release -t myapp
2014-12-29 09:51:47 -08:00
Cheng Zhao
a9d67e9715 Discard "framework_name"
We are using "'product_name' Framework" directly in C++, so we should
keep the name consistent in C++ and gyp
2014-12-29 09:49:10 -08:00
Cheng Zhao
9bd517e623 Use PRODUCT_NAME as application name 2014-12-29 09:46:27 -08:00
Cheng Zhao
22d5d40a66 Define PRODUCT_NAME 2014-12-29 09:42:54 -08:00
Cheng Zhao
3f307ea8a6 Revert #898 2014-12-29 09:35:08 -08:00
Cheng Zhao
ded58b8e65 mac: BrowserWindow.show() should also focus on window 2014-12-27 17:41:13 -08:00
Cheng Zhao
a23218c51d Bump v0.20.2 2014-12-22 13:11:28 -08:00
Cheng Zhao
70225009af Fix bootstrap.py on posix platform 2014-12-21 17:39:59 -08:00
Cheng Zhao
80bea0766e win: Update version file with unix line ending 2014-12-21 16:30:48 -08:00
Cheng Zhao
54933f992a Upgrade libchromiumcontent to fix icu symbols 2014-12-21 16:27:56 -08:00
Cheng Zhao
c0bf2facca Merge pull request #942 from atom/spell-check-client
Add support for spell checking
2014-12-20 14:25:32 -08:00
Cheng Zhao
d642fe6075 docs: webFrame.setSpellCheckProvider 2014-12-19 22:34:34 -08:00
Cheng Zhao
e7dfd48b1c Spell check pasted text 2014-12-19 22:13:07 -08:00
Cheng Zhao
90b2d12371 Add option to turn on/off auto correct word 2014-12-19 21:01:47 -08:00
Cheng Zhao
f6c66e7ece Use Chrome's policy for auto correct word 2014-12-19 20:56:16 -08:00
Cheng Zhao
c6a18b1b59 Split the words before sending it to spellCheck 2014-12-19 20:42:19 -08:00
Cheng Zhao
6cdc8e4b96 Small style fixes 2014-12-19 12:48:53 -08:00
Cheng Zhao
598060dfd8 Merge pull request #938 from omo/show-definition-for-selection
Add BrowserWindow.showDefinitionForSelection()
2014-12-19 12:43:48 -08:00
Cheng Zhao
b801a93dc5 Also expose requestCheckingOfText 2014-12-18 17:41:42 -08:00
Hajime Morrita
dc9329ff43 Add BrowserWindow.showDefinitionForSelection()
This API shows the system-provided pop-up dictionary.
Some Mac apps including Chrome have "Look Up in in Dictionary" context
menu item. This API can be used to implement it.
2014-12-18 16:45:45 -08:00
Cheng Zhao
a61331a083 Call JavaScript to get spell check results 2014-12-18 16:44:38 -08:00
Cheng Zhao
f1fbc5c701 Add webFrame.setSpellCheckClient API 2014-12-18 13:54:01 -08:00
Cheng Zhao
896077222d Add an empty SpellCheckClient 2014-12-18 13:43:51 -08:00
Cheng Zhao
47d7a355f2 Make file dialogs work in <webview>, fixes #930 2014-12-18 12:58:17 -08:00
Cheng Zhao
a1ae399d10 Make getUserMedia work in <webview>, fixes #845 2014-12-18 12:02:53 -08:00
Cheng Zhao
48b0d85f54 Merge pull request #934 from atom/webview-websecurity
Add "disablewebsecurity" attribute for <webview>
2014-12-18 11:21:04 -08:00
Cheng Zhao
423d269187 docs: "disablewebsecurity" attribute 2014-12-17 21:34:02 -08:00
Cheng Zhao
da54ac5f55 Don't leak listeners in embedder when guest is destroyed 2014-12-17 20:44:15 -08:00
Cheng Zhao
a26091e485 Suppress EventEmitter warnings 2014-12-17 20:33:47 -08:00
Cheng Zhao
40ab21d9df spec: "disablewebsecurity" attribute 2014-12-17 18:14:10 -08:00
Cheng Zhao
947e6aca9b Set web preferences for guest page 2014-12-17 18:13:39 -08:00
Cheng Zhao
c92d2531b5 Add "disablewebsecurity" attribute for <webview> 2014-12-17 18:13:20 -08:00
Cheng Zhao
6d168b89ef Use "http" for download url, fixes #929 2014-12-17 16:25:25 -08:00
Cheng Zhao
55c8206bda Bump v0.20.1 2014-12-17 15:27:42 -08:00
Cheng Zhao
c01e3cf9aa Merge pull request #931 from atom/will-navigate
Add "will-navigate" event
2014-12-17 15:27:15 -08:00
Cheng Zhao
040049f9e7 docs: "will-navigate" event 2014-12-17 15:15:37 -08:00
Cheng Zhao
2fc1e2a4e6 Merge pull request #924 from atom/webview-ipc-message
Add ipc-message event for <webview>
2014-12-17 15:06:25 -08:00
Cheng Zhao
eaacf0a6ef spec: "will-navigate" event 2014-12-17 15:03:34 -08:00
Cheng Zhao
c2975d2bcc Redirect BrowserWindow's "will-navigate" event to WebContents 2014-12-17 14:56:51 -08:00
Cheng Zhao
60df32aab5 Add "will-navigate" event for WebContents 2014-12-17 14:55:22 -08:00
Cheng Zhao
fd596d4a65 Add "will-navigate" event for BrowserWindow 2014-12-17 14:40:19 -08:00
Cheng Zhao
5142b7858b Upgrade brightray to fix crash in #393 2014-12-17 13:16:06 -08:00
Cheng Zhao
a8f5a4e2d4 Add sendToHost method 2014-12-17 11:09:11 -08:00
Cheng Zhao
d46300587a Remove uses of deprecated APIs in remote module 2014-12-17 11:00:41 -08:00
Cheng Zhao
64a41b65bb Merge pull request #923 from ffdd/patch-1
Add that Menu.setApplication only works after 'ready' event.
2014-12-17 10:29:46 -08:00
Cheng Zhao
275ac2c4b6 doc: ipc-message event 2014-12-16 21:19:04 -08:00
Cheng Zhao
c0285747a2 spec: ipc-message event 2014-12-16 21:11:30 -08:00
Cheng Zhao
95793e410d Redirect guest page's ipc message to embedder 2014-12-16 21:10:53 -08:00
ffdd
31d606220e Add that Menu.setApplication only works after 'ready' event.
I got caught on this while trying to add a menu in my application in OSX.
2014-12-16 21:50:40 -05:00
Cheng Zhao
4fc14959a8 Allow same object to appear in one list when parsing V8 array
Fixes #874.
2014-12-16 16:57:42 -08:00
Cheng Zhao
95dd73bd1d Add maximum depth when converting V8 object to base::Value 2014-12-16 16:46:23 -08:00
Cheng Zhao
5bed184014 Merge pull request #922 from atom/dialog-thread
Run asynchronous file dialog in new thread on Windows
2014-12-16 14:01:05 -08:00
Cheng Zhao
4fa7e8e914 Merge pull request #919 from paulcbetts/nullref-in-webview-manager
Fix nullref crash in WebViewManager::RemoveGuest
2014-12-16 13:40:11 -08:00
Cheng Zhao
63e83a7ef8 win: Don't hang when failed to create thread 2014-12-16 12:33:17 -08:00
Cheng Zhao
c20e1e9d82 win: Run async save dialog in new thread 2014-12-16 12:27:26 -08:00
Cheng Zhao
253bacdf1d win: Run async open dialog in new thread 2014-12-16 11:27:38 -08:00
Cheng Zhao
98127ba13c linux: Fix building 2014-12-15 17:28:51 -08:00
Cheng Zhao
cb911b19dd win: Fixes stopping FlashFrame, closes #906 2014-12-15 17:27:58 -08:00
Cheng Zhao
d50eeb04d5 Upgrade cpplint 2014-12-15 17:15:56 -08:00
Cheng Zhao
1641caf353 Fix cpplint warnings 2014-12-15 16:57:04 -08:00
Cheng Zhao
23951e6ef3 views: Implement CanMinimize, fixes #918 2014-12-15 16:46:37 -08:00
Cheng Zhao
c9a5c6515c views: Make it possible to show a window in maximized state
Fixes #834.
2014-12-15 16:38:20 -08:00
Cheng Zhao
0ab32bfe17 win: Reserve border space for maximized frameless window
Fixes #732.
2014-12-15 16:01:11 -08:00
Cheng Zhao
3d30e6ddc4 win: Don't allow maximzing a unresiazble frameless window
Fixes #857.
2014-12-15 12:55:16 -08:00
Paul Betts
ffdf2f7fcf Check key via ContainsKey instead of null check 2014-12-15 11:22:14 -08:00
Paul Betts
974415f8a1 You're not my real Dad, cpplint 2014-12-15 06:23:00 -08:00
Paul Betts
3105092130 Fix nullref crash in RemoveGuest 2014-12-15 06:10:39 -08:00
Cheng Zhao
85b0885af7 Bump v0.20.0 2014-12-12 18:21:14 -08:00
Cheng Zhao
11cd301127 Only listen to its own events in <webview>, fixes #885 2014-12-12 17:16:12 -08:00
Cheng Zhao
654d21100f Upgrade libchromiumcontent to remove dom storage quota
Closes #897.
2014-12-12 16:42:07 -08:00
Cheng Zhao
5bd924a52d mac: Use com.github.atom-shell as default CFBundleIdentifier 2014-12-12 15:37:13 -08:00
Cheng Zhao
186d34c33a Merge pull request #904 from atom/chrome39
Upgrade to Chrome 39
2014-12-12 15:23:55 -08:00
Cheng Zhao
b0a414ea83 Upgrade brightray 2014-12-12 14:50:39 -08:00
Cheng Zhao
099eb53d3c Upgrade libchromiumcontent to fix generating node.lib 2014-12-12 10:40:42 -08:00
Cheng Zhao
e3ccb18696 win: Fix calculating window bounds on high DPI display 2014-12-12 09:04:43 -08:00
Cheng Zhao
e38614ce31 win: No longer support building with VS Express
The Community edition can provide everything we need for Professional
edition.
2014-12-11 19:47:15 -08:00
Cheng Zhao
290dd4ccd8 win: Use d3dcompiler_46.dll 2014-12-11 19:46:42 -08:00
Cheng Zhao
1bebf1cc2c win: Fix generating location.pak. 2014-12-11 19:29:36 -08:00
Cheng Zhao
d8d9dea792 Upgrade node to fix failed call to LoadLibrary 2014-12-11 18:33:39 -08:00
Cheng Zhao
7457f81283 mac: Fix installing view on frameless window
Closes #601.
2014-12-11 14:25:51 -08:00
Cheng Zhao
158d8efb8e Merge pull request #910 from sonnyp/patch-1
Update tray.md
2014-12-11 13:08:23 -08:00
Cheng Zhao
0b668b8e17 Minor fixes on <webview> 2014-12-11 09:30:55 -08:00
Sonny Piers
5437470b4e Update tray.md
checked seems to be the correct property
2014-12-11 12:28:01 +01:00
Cheng Zhao
409f2b4d0f win: Fix compilation errors 2014-12-10 14:17:07 -08:00
Cheng Zhao
64edede20d Move handling of "preload" to web-view-attributes 2014-12-10 11:05:51 -08:00
Cheng Zhao
6624fd9a1b Fix relative links in "src" of <webview> 2014-12-10 10:51:34 -08:00
Cheng Zhao
1cdbb6f186 Upgrade brightray to fix running on Mac 2014-12-09 22:40:26 -08:00
Cheng Zhao
f57533fa0e Add os_bsd variable for breakpad 2014-12-09 17:25:45 -08:00
Cheng Zhao
2db7c84cbc spec: Remove "restore" event test
It is too slow and unstable.
2014-12-09 17:16:21 -08:00
Cheng Zhao
cefc846e9e linux: Upgrade breakpad to fix building 2014-12-09 17:05:18 -08:00
Cheng Zhao
1853bef39a views: SizeConstraintsChanged has become required 2014-12-09 16:55:01 -08:00
Cheng Zhao
22c4911b58 linux: GTK+ status icon has come back 2014-12-09 16:55:01 -08:00
Cheng Zhao
e58b3ddc86 Bump Chrome version 2014-12-09 16:37:40 -08:00
Cheng Zhao
e3ba17f2d3 linux: Disable warnings for g_settings_list_schemas 2014-12-09 16:37:05 -08:00
Cheng Zhao
7d1830d014 Upgrade node to bump node module version 2014-12-09 15:49:17 -08:00
Cheng Zhao
da3a988c8c Merge branch 'master' into chrome39
Conflicts:
	vendor/brightray
2014-12-09 15:49:06 -08:00
Cheng Zhao
9d23cce2b6 Move "nodeintegration" and "plugins" to web-view-attributes 2014-12-09 14:51:35 -08:00
Cheng Zhao
68381e1b76 Use element instant id for GetGuestByInstanceID 2014-12-09 14:38:43 -08:00
Cheng Zhao
3493d2c701 Merge pull request #901 from IgorKlopov/patch-1
Full verbosity, helps troubleshooting
2014-12-08 21:45:55 -08:00
Cheng Zhao
9e1d3f9e27 Merge pull request #902 from IgorKlopov/patch-2
Why not verbose?
2014-12-08 21:44:00 -08:00
Cheng Zhao
7fdd94520e Merge pull request #898 from paulcbetts/dont-hardcode-atom-helper
Dont hardcode paths to Atom [Helper / Framework]
2014-12-08 21:39:14 -08:00
Cheng Zhao
9fcb6b2cd1 Moved parseSrcAttribute() into the SrcAttribute object as parse()
Imported from:
3bc15760f9%5E%21/
2014-12-08 21:35:10 -08:00
Cheng Zhao
cbafac774e Various webview cleanup
Imported from:
848f1ed048%5E%21/
2014-12-08 21:15:18 -08:00
Cheng Zhao
7f5fb4e6f9 Renamed "WebView" -> "WebViewImpl" in web_view.js and other files that import it
Imported from:
a615ea0839%5E%21/
2014-12-08 21:10:59 -08:00
Cheng Zhao
ac51207860 Optimized the handling of webview attribute mutation
Imported from:
86dff6fc51%5E%21/
2014-12-08 21:06:23 -08:00
Paul Betts
aa3be09ab0 Bump submodule to merged version 2014-12-08 20:26:09 -08:00
Cheng Zhao
4348143fd9 Simplify web-view.coffee
Imported from:
3ef1fc1b72%5E%21/
2014-12-08 17:15:50 -08:00
Cheng Zhao
b6b8b936f2 Automated the definitions of webview attributes as properties on the webview node
Imported from:
aef58f49f6%5E%21/
2014-12-08 17:05:57 -08:00
Cheng Zhao
2c27b953b5 Got rid of the internal copies of webview attributes
Imported from:
abb035a09b%5E%21/
2014-12-08 16:56:14 -08:00
Cheng Zhao
d7eae69587 Webview attributes overhaul
Imported from:
884a5b43cb
2014-12-08 16:14:12 -08:00
Cheng Zhao
e0f1433c12 Moved constants out of web-view.coffee and into a new file
Imported from:
ccbfe27c8d
2014-12-08 13:37:18 -08:00
IgorKlopov
27710cd4f7 bootstrap.py -v in mac 2014-12-08 20:07:29 +03:00
IgorKlopov
4d5bbbc2d7 bootstrap.py -v 2014-12-08 20:07:00 +03:00
IgorKlopov
da900b3094 bootstrap.py also imports it 2014-12-08 20:03:48 +03:00
IgorKlopov
0f29d9f30f verbose_mode from config.py
Also, no return value supposed for execute_stdout
2014-12-08 20:02:08 +03:00
IgorKlopov
b88824a70c verbose_mode getter/setter 2014-12-08 20:00:35 +03:00
Cheng Zhao
882a08f61a Fix browser plugin API changes 2014-12-08 09:00:00 -08:00
Cheng Zhao
a9072049ea Move webview code to atom/renderer/lib/web-view 2014-12-08 06:08:21 -08:00
Paul Betts
e87876671f Add some documentation about renaming Atom Shell 2014-12-07 21:38:29 -08:00
Paul Betts
d0f6c89e77 Bump brightray to pick up brightray/brightray#85 2014-12-07 21:26:19 -08:00
Paul Betts
8eab230fe1 Delete OverrideChildProcessPath and OverrideFrameworkBundlePath altogether 2014-12-07 21:06:47 -08:00
IgorKlopov
7ff95ec255 Travis CI says: execute unused
Removed `execute` import
2014-12-08 03:04:41 +03:00
IgorKlopov
20afd51a9d Travis CI says long line detected
Foldede the line
2014-12-08 02:58:04 +03:00
IgorKlopov
19bba5c18c One more verbose_mode
`bootstrap.py` new variable `verbose_mode` to run `npm install` with --verbose option
2014-12-08 02:52:13 +03:00
IgorKlopov
bf4c219766 Make use of execute_stdout
execute_stdout makes stdout real-time
2014-12-08 02:47:05 +03:00
IgorKlopov
a5e1d8c97f introduce execute_stdout
`execute_stdout` does not return the output of the process. Instead it outputs directly to current stdout (in real-time - to see what is `npm` doing now)
2014-12-08 02:42:55 +03:00
Cheng Zhao
7bc364a374 Upgrade node for new V8 API 2014-12-07 13:09:50 -08:00
Cheng Zhao
5dd73e74cb Disable crash reporter spec on Yosemite 2014-12-07 08:57:55 -08:00
Cheng Zhao
ba347f6460 mac: Fix crash reporting on Yosemite 2014-12-07 08:56:59 -08:00
Cheng Zhao
85cf8f9174 apm@0.112.0 2014-12-07 08:13:42 -08:00
IgorKlopov
2153e018a3 Bootstrap indeed 2014-12-07 18:47:23 +03:00
IgorKlopov
3f4fec0864 Why not verbose?
The silence are scary
2014-12-07 18:46:12 +03:00
Cheng Zhao
10823eeeaa Fix compilation errors caused by Chrome 39 2014-12-07 07:43:26 -08:00
Cheng Zhao
25ea169c72 Upgrade libchromiumcontent to 39.0.2171.65 2014-12-07 07:43:07 -08:00
IgorKlopov
743e8331b5 Helps troubleshooting 2014-12-07 18:42:59 +03:00
Cheng Zhao
d309fd5a27 Update printing code 2014-12-07 06:55:40 -08:00
Paul Betts
091357ad8e Find the MainMenu nib correctly 2014-12-05 23:19:19 -08:00
Paul Betts
3d4491a468 Determine the Helper name from the App name 2014-12-05 23:19:19 -08:00
Cheng Zhao
6d32db32ef Upgrade node, fixes #843 2014-12-04 12:17:36 -08:00
Cheng Zhao
357f5f9781 Upgrade brightray 2014-12-04 11:45:02 -08:00
Cheng Zhao
a0f5544a07 Fix compilation warning on Yosemite 2014-12-03 15:21:50 -08:00
139 changed files with 3884 additions and 2149 deletions

View File

@@ -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
],
}

View File

@@ -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
}

View File

@@ -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);
}

View File

@@ -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)));

View File

@@ -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);
}
}

View File

@@ -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) ||

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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_;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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', =>

View File

@@ -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

View File

@@ -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());

View File

@@ -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));

View File

@@ -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_; }

View File

@@ -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"

View File

@@ -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);

View File

@@ -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_),

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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();

View File

@@ -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) {}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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) {
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
};

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);
};

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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()

View File

@@ -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

View File

@@ -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_

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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)

View File

@@ -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_

View 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

View File

@@ -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

View File

@@ -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);
};

View File

@@ -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;
}

View File

@@ -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

View File

@@ -47,6 +47,8 @@ extern const char kOverlayScrollbars[];
extern const char kOverlayFullscreenVideo[];
extern const char kSharedWorker[];
extern const char kDisableHttpCache[];
} // namespace switches
} // namespace atom

View 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

View 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_

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View 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)

View 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.'

View 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

View File

@@ -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>

View File

@@ -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.

View File

@@ -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_;

View File

@@ -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;
}

View File

@@ -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);
};

View File

@@ -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.

View File

@@ -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_;

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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_;

View File

@@ -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;

View File

@@ -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.

View File

@@ -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(), &params);
@@ -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(), &params.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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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