mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
433 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9dc6cfc1e9 | ||
|
|
749a1a3e9a | ||
|
|
93bbc0bca9 | ||
|
|
9d51da505e | ||
|
|
e5496d9ac0 | ||
|
|
c2b2a2072f | ||
|
|
446235c8cd | ||
|
|
530b040ade | ||
|
|
375ac3e6ec | ||
|
|
a200718944 | ||
|
|
ba02e19fae | ||
|
|
8e1979a6a5 | ||
|
|
e5386cf8ea | ||
|
|
e597229750 | ||
|
|
8b3ed9067e | ||
|
|
40d4c65866 | ||
|
|
1ca6534dcd | ||
|
|
830bb54d6a | ||
|
|
785eb9657b | ||
|
|
21bd578935 | ||
|
|
1e0facc103 | ||
|
|
db3e27ceaa | ||
|
|
b521e45ef8 | ||
|
|
ad6e67fdfa | ||
|
|
564b74b19c | ||
|
|
62b1034c6b | ||
|
|
4412a89270 | ||
|
|
d4aa2308cd | ||
|
|
8912b404a9 | ||
|
|
d7ec0b99fd | ||
|
|
87e02f2858 | ||
|
|
66f7f2e6f2 | ||
|
|
13722e26cd | ||
|
|
e365cb6b1c | ||
|
|
46b2b91a27 | ||
|
|
24bbe5dabf | ||
|
|
3717f5b7f2 | ||
|
|
10bc0c20b1 | ||
|
|
0a4fb2ec4f | ||
|
|
8cc1046992 | ||
|
|
3669113ad2 | ||
|
|
aad1f5082f | ||
|
|
f56d715104 | ||
|
|
cd12dbd47e | ||
|
|
5830532a45 | ||
|
|
4537d88a58 | ||
|
|
342e0c6cf7 | ||
|
|
512f89910d | ||
|
|
e2bd1abce6 | ||
|
|
5eb0bedbbc | ||
|
|
2454dccde0 | ||
|
|
0b1a3f3ef3 | ||
|
|
fafb28e41a | ||
|
|
ba25bed45b | ||
|
|
3773f81fd5 | ||
|
|
f2bdca31b3 | ||
|
|
9c235509a6 | ||
|
|
b1afe538ee | ||
|
|
0b97d58a6f | ||
|
|
880dce950d | ||
|
|
39975378bb | ||
|
|
96771c7098 | ||
|
|
0e92a3e333 | ||
|
|
dd871812b7 | ||
|
|
81d423c547 | ||
|
|
943fe2c22d | ||
|
|
38e948f55b | ||
|
|
3e4ad4c696 | ||
|
|
41e1555cf4 | ||
|
|
dcbd8316df | ||
|
|
1a1b45e088 | ||
|
|
0577e911b3 | ||
|
|
619c77f409 | ||
|
|
6c5c202a99 | ||
|
|
090c817ac9 | ||
|
|
f91a7e6d04 | ||
|
|
5d6ac2296b | ||
|
|
26dea993df | ||
|
|
eb8ac2b5d8 | ||
|
|
44528ce60e | ||
|
|
e72e09719a | ||
|
|
6f9d822472 | ||
|
|
67026cccc8 | ||
|
|
30c714a27f | ||
|
|
05031a38e5 | ||
|
|
ae8ffae59e | ||
|
|
587a9f1c5b | ||
|
|
bd264aa1ba | ||
|
|
9557ce523a | ||
|
|
f1e5a99881 | ||
|
|
03ba9533fb | ||
|
|
8f59c0b642 | ||
|
|
da5bac42f3 | ||
|
|
150b540e72 | ||
|
|
5189147021 | ||
|
|
d180d3b168 | ||
|
|
3f546e6bab | ||
|
|
c65ccb6857 | ||
|
|
e3504b2b24 | ||
|
|
53b9d61831 | ||
|
|
2c3751e287 | ||
|
|
4a81300100 | ||
|
|
73af4c017d | ||
|
|
2734d67a38 | ||
|
|
c81de98d22 | ||
|
|
599e9b90bb | ||
|
|
c1d7ad9631 | ||
|
|
ee0dc0d926 | ||
|
|
4254eb279f | ||
|
|
262b66b93a | ||
|
|
45491ca7ab | ||
|
|
1db843244d | ||
|
|
992aada90f | ||
|
|
c01d2fbbcd | ||
|
|
f75458f78d | ||
|
|
d6daea12af | ||
|
|
28e5258a96 | ||
|
|
f6d6a2a4c3 | ||
|
|
c56b78f0fa | ||
|
|
27b77a06ed | ||
|
|
357dea506a | ||
|
|
c2dcccf7c7 | ||
|
|
28764b0f77 | ||
|
|
66a1405d2b | ||
|
|
b3eb6dc32b | ||
|
|
3af2540fad | ||
|
|
2f41641139 | ||
|
|
131cd9cff6 | ||
|
|
bd20104e5a | ||
|
|
2e5a539f57 | ||
|
|
159b6ca611 | ||
|
|
3914ff2ac5 | ||
|
|
f12ccac17e | ||
|
|
f8d40a88fb | ||
|
|
e78db6ae07 | ||
|
|
e71d2bd8e7 | ||
|
|
ba7ddd66a1 | ||
|
|
f5f3278ffa | ||
|
|
bfa33de792 | ||
|
|
ae3ff4e1e3 | ||
|
|
0fa0aedd86 | ||
|
|
e6265ec405 | ||
|
|
6bce5b560b | ||
|
|
009b27f5f1 | ||
|
|
7d07f10c25 | ||
|
|
d830badc57 | ||
|
|
47d103af72 | ||
|
|
91c75d73dd | ||
|
|
2ead38b03f | ||
|
|
dd2ed559cf | ||
|
|
ab726ec1f5 | ||
|
|
2c47532702 | ||
|
|
95133af0ee | ||
|
|
17cc43152d | ||
|
|
0cb20c48f6 | ||
|
|
4e7f56846f | ||
|
|
4062ca5f68 | ||
|
|
e043ea9c20 | ||
|
|
10b53f7f73 | ||
|
|
7acd3c1973 | ||
|
|
889c982918 | ||
|
|
c70513f7ce | ||
|
|
691d8dd9ab | ||
|
|
316210d6c4 | ||
|
|
dddb598818 | ||
|
|
50bfe9e335 | ||
|
|
a03df3ac5a | ||
|
|
05d0f17447 | ||
|
|
f31848563f | ||
|
|
d9c3830df7 | ||
|
|
cb4558e75b | ||
|
|
be73388918 | ||
|
|
6a2bd80a9a | ||
|
|
52916f70ed | ||
|
|
a5234224a6 | ||
|
|
c6269bf77a | ||
|
|
0e4ae6f864 | ||
|
|
96bb9b2757 | ||
|
|
e0a57a0a47 | ||
|
|
8cf1bc8457 | ||
|
|
eb3769f98e | ||
|
|
afff32dc8d | ||
|
|
ddee9f3e75 | ||
|
|
625ee387f3 | ||
|
|
ebedb60684 | ||
|
|
9ecc4bcb7d | ||
|
|
b205bd381e | ||
|
|
af52eda0eb | ||
|
|
aed487ef40 | ||
|
|
50c7985ee2 | ||
|
|
00136a221f | ||
|
|
a6b86e924a | ||
|
|
ed01698444 | ||
|
|
6459531bef | ||
|
|
49b15bd4f3 | ||
|
|
c67268a74f | ||
|
|
2c79e9fd41 | ||
|
|
29c865f0e1 | ||
|
|
e0542945ce | ||
|
|
842ba6aea6 | ||
|
|
009e228218 | ||
|
|
d93b6c1cae | ||
|
|
2206279846 | ||
|
|
1e5b7af490 | ||
|
|
cb62afca23 | ||
|
|
254cdc0e6c | ||
|
|
2c6210cf9c | ||
|
|
3d4f0dfc44 | ||
|
|
874367e2c5 | ||
|
|
22652860a2 | ||
|
|
87db1e8802 | ||
|
|
8b6f3dc0aa | ||
|
|
9c46be9d47 | ||
|
|
9ee063ca14 | ||
|
|
eab88ea09c | ||
|
|
cfc5ecb05d | ||
|
|
8757da6c47 | ||
|
|
39e3506add | ||
|
|
0f2ef3feb2 | ||
|
|
82d801ab9e | ||
|
|
955ae78e33 | ||
|
|
8d40714f78 | ||
|
|
2c3ed90ff3 | ||
|
|
b1fc18f405 | ||
|
|
e8a04981bb | ||
|
|
a2cc936a3b | ||
|
|
e6e09a8a7c | ||
|
|
50736296a7 | ||
|
|
b759999272 | ||
|
|
a5969fd076 | ||
|
|
91150839be | ||
|
|
83aa9df1ee | ||
|
|
a38d34d368 | ||
|
|
e8461b6f90 | ||
|
|
33a19f9071 | ||
|
|
8ee91bce44 | ||
|
|
dbc1855b42 | ||
|
|
dd28a2ef14 | ||
|
|
609961a1de | ||
|
|
852d982057 | ||
|
|
6277a65bb7 | ||
|
|
26f7f2ab21 | ||
|
|
aa03fddb62 | ||
|
|
bbf2cbb6f6 | ||
|
|
221eff7fec | ||
|
|
c2073a3c45 | ||
|
|
71d257b190 | ||
|
|
0684d9da6d | ||
|
|
5337d8c23f | ||
|
|
b7d80e792d | ||
|
|
d02ced87b8 | ||
|
|
4bc9bf7654 | ||
|
|
f74d7d71e6 | ||
|
|
195be931a4 | ||
|
|
4a7d5fa769 | ||
|
|
16a0185ab5 | ||
|
|
8a09cf5369 | ||
|
|
c91ab5ec7c | ||
|
|
37244c3b08 | ||
|
|
7889e2750f | ||
|
|
63eb4b72e2 | ||
|
|
64e8ce0c07 | ||
|
|
bd64f5ced2 | ||
|
|
f7c75d36ba | ||
|
|
e99b8c3a2b | ||
|
|
0ddf90815b | ||
|
|
e432638b7d | ||
|
|
134ccb550c | ||
|
|
573c959a75 | ||
|
|
e7791a5486 | ||
|
|
a1a6ea6fe1 | ||
|
|
04d8f3218f | ||
|
|
ab859067aa | ||
|
|
9cdefb6069 | ||
|
|
a6c21666f4 | ||
|
|
3dad645619 | ||
|
|
292ffffa14 | ||
|
|
a1f17069ec | ||
|
|
71f46c0287 | ||
|
|
a34a16653e | ||
|
|
f96c76584f | ||
|
|
ade5b142f8 | ||
|
|
ed8f143427 | ||
|
|
586b407103 | ||
|
|
715a88026e | ||
|
|
3001ef7980 | ||
|
|
0a4144e67a | ||
|
|
71fa87e4ed | ||
|
|
4e781eb042 | ||
|
|
5f1897713c | ||
|
|
38b519ceb5 | ||
|
|
71f74f4042 | ||
|
|
c282d4c0ff | ||
|
|
00de81771c | ||
|
|
bc909ddf5e | ||
|
|
840095b444 | ||
|
|
be18a114e2 | ||
|
|
3e5449561f | ||
|
|
7f67cfb6a0 | ||
|
|
2b051e3884 | ||
|
|
290b221d79 | ||
|
|
c441dd1436 | ||
|
|
fcecd091da | ||
|
|
ac84f56e36 | ||
|
|
5a8f60fe32 | ||
|
|
aeb37941bb | ||
|
|
28a4069520 | ||
|
|
1aab23ece7 | ||
|
|
eea04e513d | ||
|
|
73c9241a17 | ||
|
|
fcf2be78cb | ||
|
|
ecb1625756 | ||
|
|
2592d2cfcd | ||
|
|
50cbb5744b | ||
|
|
aef4acb2e6 | ||
|
|
f4783772c5 | ||
|
|
ba9c47eb7e | ||
|
|
76416d5e47 | ||
|
|
1065374db4 | ||
|
|
65046b05af | ||
|
|
638bb9b0b1 | ||
|
|
864c8df639 | ||
|
|
81ed608b9c | ||
|
|
474f92e41b | ||
|
|
6a7113e3ce | ||
|
|
d2288815f8 | ||
|
|
2c7ccffe1a | ||
|
|
a67767dbea | ||
|
|
703ced32db | ||
|
|
c9965f0ffd | ||
|
|
291a60444a | ||
|
|
a1ef09a243 | ||
|
|
da10df3a9a | ||
|
|
5dc5f52f32 | ||
|
|
ce0509a665 | ||
|
|
1c9088ce7d | ||
|
|
a14739bde9 | ||
|
|
b479aa3d45 | ||
|
|
102d3966af | ||
|
|
1518ff6d22 | ||
|
|
5a37f96434 | ||
|
|
dddfe902a3 | ||
|
|
3740161caa | ||
|
|
7a158773f3 | ||
|
|
7f72207e66 | ||
|
|
f74ce9cc1c | ||
|
|
5018fe1e17 | ||
|
|
90392e9231 | ||
|
|
7a23add23b | ||
|
|
d87c8a8291 | ||
|
|
9b84dc4e1a | ||
|
|
37044f6fd4 | ||
|
|
33737498ec | ||
|
|
a0fea28632 | ||
|
|
23d1a80c04 | ||
|
|
29c39a3245 | ||
|
|
d7fda9c8cc | ||
|
|
f05ee4205d | ||
|
|
1964bb2acc | ||
|
|
04967de2ed | ||
|
|
6c984fac7c | ||
|
|
3f52a91312 | ||
|
|
acc0c616c4 | ||
|
|
c686fc4d6b | ||
|
|
9232620023 | ||
|
|
b1406fbad9 | ||
|
|
79c602c3cc | ||
|
|
db2f0a68e8 | ||
|
|
d7cf460918 | ||
|
|
68a98d5dc2 | ||
|
|
7c32378a73 | ||
|
|
9212a1db8e | ||
|
|
a839f70a99 | ||
|
|
d931a49e89 | ||
|
|
61b7a3afe3 | ||
|
|
cf6a904f95 | ||
|
|
00e5290dc8 | ||
|
|
627fe75a6a | ||
|
|
bc5ebb9911 | ||
|
|
1bd8a9869a | ||
|
|
0ee6e5334a | ||
|
|
c18ec7f5bc | ||
|
|
5f663dbf0a | ||
|
|
c566ba575f | ||
|
|
454413f69a | ||
|
|
714745cdd7 | ||
|
|
624b6b9762 | ||
|
|
7d97bb6fe0 | ||
|
|
86eb0a5eaa | ||
|
|
62d5c89f62 | ||
|
|
a88f951b2f | ||
|
|
467ba6b7a9 | ||
|
|
02714d466c | ||
|
|
741c8f3d98 | ||
|
|
773e932e98 | ||
|
|
374d83ed9c | ||
|
|
05fd81ebdc | ||
|
|
777f99193f | ||
|
|
d0ef43bd12 | ||
|
|
78171e2072 | ||
|
|
94c1fb32a7 | ||
|
|
d9b845fcdf | ||
|
|
225321b580 | ||
|
|
f493eb34ae | ||
|
|
1f2d7d1cd8 | ||
|
|
ebb1ddc0df | ||
|
|
d2681d2ba1 | ||
|
|
337460cdc2 | ||
|
|
ee51e37db7 | ||
|
|
96d53d279e | ||
|
|
1e9eaba423 | ||
|
|
a8681b0072 | ||
|
|
e6a2b0a479 | ||
|
|
0f990d40cc | ||
|
|
2dc533c4b9 | ||
|
|
bc06195409 | ||
|
|
e43c63ae08 | ||
|
|
cc34bc844d | ||
|
|
7423c89968 | ||
|
|
4337c07425 | ||
|
|
5c57f92ba5 | ||
|
|
c5e540823b | ||
|
|
28093a4d2d | ||
|
|
4e3187fbbd | ||
|
|
f9fee9174a | ||
|
|
0e8a585157 | ||
|
|
11ffb9dfb6 | ||
|
|
46c7ba734b | ||
|
|
fc4031ec26 | ||
|
|
d003b1bb57 | ||
|
|
8fda175264 | ||
|
|
d08392a0c4 | ||
|
|
48ccb0f2ab |
36
README-ko.md
36
README-ko.md
@@ -1,4 +1,4 @@
|
||||
[](http://electron.atom.io/)
|
||||
[](http://electron.atom.io/)
|
||||
|
||||
[](https://travis-ci.org/atom/electron)
|
||||
[](https://david-dm.org/atom/electron#info=devDependencies)
|
||||
@@ -6,25 +6,26 @@
|
||||
|
||||
### [Electron](https://github.com/atom/electron/) 한국어 참조문서
|
||||
|
||||
:zap: *이전까지 Atom Shell로 알려져 있었습니다* :zap:
|
||||
:zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap:
|
||||
|
||||
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와
|
||||
[Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다.
|
||||
|
||||
Electron은 JavaScript, HTML 그리고 CSS를 이용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와
|
||||
[Chromium](http://www.chromium.org) 을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom) 에 사용되고 있습니다.
|
||||
Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
|
||||
|
||||
Electron에 대한 중요한 알림을 받으려면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 Follow하세요.
|
||||
이 프로젝트는 기여자 규약 1.2를 준수합니다. 이 프로젝트에 참여할 때 코드를 유지해야 합니다. 받아들일 수 없는 행동은 atom@github.com로 보고 하십시오.
|
||||
|
||||
## 다운로드
|
||||
|
||||
Linux, Windows, Mac용으로 미리 빌드된 Electron 바이너리와 디버그 심볼이 준비되어 있습니다. [releases](https://github.com/atom/electron/releases) 페이지에서 받아 볼 수 있습니다.
|
||||
|
||||
또한 [`npm`](https://docs.npmjs.com/)을 이용하여 미리 빌드된 Electron 바이너리를 받을 수 있습니다:
|
||||
또한 [`npm`](https://docs.npmjs.com/)을 통해 미리 빌드된 Electron 바이너리를 받을 수도 있습니다:
|
||||
|
||||
```sh
|
||||
# $PATH에 `electron`을 등록하고 전역에 설치합니다.
|
||||
# $PATH에 `electron` 커맨드를 등록하고 전역에 설치합니다.
|
||||
npm install electron-prebuilt -g
|
||||
|
||||
# 개발용 dependency로 설치합니다.
|
||||
# 개발 의존성 모듈 형태로 설치합니다.
|
||||
npm install electron-prebuilt --save-dev
|
||||
```
|
||||
|
||||
@@ -32,13 +33,22 @@ npm install electron-prebuilt --save-dev
|
||||
|
||||
- [China](https://npm.taobao.org/mirrors/electron)
|
||||
|
||||
## 참조문서
|
||||
## 참조 문서
|
||||
|
||||
[docs](https://github.com/atom/electron/tree/master/docs/README-ko.md) 에 프레임워크 사용 가이드와 API 레퍼런스가 있습니다.
|
||||
추가적으로 Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법이 문서에 포함되어 있으니 참고하시기 바랍니다.
|
||||
[Docs](https://github.com/atom/electron/tree/master/docs/README.md)에 개발 가이드와 API 레퍼런스가 있습니다.
|
||||
Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문서에 포함되어 있으니 참고하시기 바랍니다.
|
||||
|
||||
## 참조 문서 (번역)
|
||||
|
||||
- [브라질 포르투칼어](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
|
||||
- [한국어](https://github.com/atom/electron/tree/master/docs-translations/ko)
|
||||
- [일본어](https://github.com/atom/electron/tree/master/docs-translations/jp)
|
||||
- [스페인어](https://github.com/atom/electron/tree/master/docs-translations/es)
|
||||
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
|
||||
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
|
||||
|
||||
## 커뮤니티
|
||||
|
||||
[Atom 포럼내의 `electron` 카테고리](http://discuss.atom.io/category/electron) 와 Freenode `#atom-shell` 채팅채널이 있습니다.
|
||||
[Atom 포럼내의 `electron` 카테고리](http://discuss.atom.io/category/electron)와 Freenode `#atom-shell` 채팅 채널에서 활발하게 토론이 이어지고 있습니다.
|
||||
|
||||
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 에 커뮤니티가 운영중인 유용한 예제 앱과 툴, 리소스가 있으니 한번 탐색해 보시기 바랍니다.
|
||||
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트엔 커뮤니티가 운영중인 유용한 예제 어플리케이션과 도구, 리소스가 있으니 한번 참고해 보시기 바랍니다.
|
||||
|
||||
@@ -43,6 +43,15 @@ Guides and the API reference are located in the
|
||||
[docs](https://github.com/atom/electron/tree/master/docs) directory. It also
|
||||
contains documents describing how to build and contribute to Electron.
|
||||
|
||||
## Documentation Translations
|
||||
|
||||
- [Brazilian Portuguese](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
|
||||
- [Korean](https://github.com/atom/electron/tree/master/docs-translations/ko)
|
||||
- [Japanese](https://github.com/atom/electron/tree/master/docs-translations/jp)
|
||||
- [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es)
|
||||
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
|
||||
- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
|
||||
|
||||
## Community
|
||||
|
||||
There is an [`electron` category on the Atom forums](http://discuss.atom.io/category/electron)
|
||||
|
||||
17
atom.gyp
17
atom.gyp
@@ -4,7 +4,7 @@
|
||||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.30.6',
|
||||
'version%': '0.32.1',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
@@ -144,7 +144,6 @@
|
||||
'destination': '<(PRODUCT_DIR)',
|
||||
'files': [
|
||||
'<@(copied_libraries)',
|
||||
'<(libchromiumcontent_dir)/ffmpegsumo.dll',
|
||||
'<(libchromiumcontent_dir)/libEGL.dll',
|
||||
'<(libchromiumcontent_dir)/libGLESv2.dll',
|
||||
'<(libchromiumcontent_dir)/icudtl.dat',
|
||||
@@ -193,7 +192,6 @@
|
||||
'destination': '<(PRODUCT_DIR)',
|
||||
'files': [
|
||||
'<@(copied_libraries)',
|
||||
'<(libchromiumcontent_dir)/libffmpegsumo.so',
|
||||
'<(libchromiumcontent_dir)/icudtl.dat',
|
||||
'<(libchromiumcontent_dir)/content_shell.pak',
|
||||
'<(libchromiumcontent_dir)/natives_blob.bin',
|
||||
@@ -226,8 +224,6 @@
|
||||
# Defined in Chromium but not exposed in its gyp file.
|
||||
'V8_USE_EXTERNAL_STARTUP_DATA',
|
||||
'ENABLE_PLUGINS',
|
||||
# Needed by Node.
|
||||
'NODE_WANT_INTERNALS=1',
|
||||
],
|
||||
'sources': [
|
||||
'<@(lib_sources)',
|
||||
@@ -441,7 +437,6 @@
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Libraries',
|
||||
'files': [
|
||||
'<@(copied_libraries)',
|
||||
'<(libchromiumcontent_dir)/ffmpegsumo.so',
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -462,6 +457,16 @@
|
||||
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
|
||||
],
|
||||
},
|
||||
{
|
||||
'postbuild_name': 'Fix path of ffmpeg',
|
||||
'action': [
|
||||
'install_name_tool',
|
||||
'-change',
|
||||
'@loader_path/libffmpeg.dylib',
|
||||
'@rpath/libffmpeg.dylib',
|
||||
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
|
||||
],
|
||||
},
|
||||
{
|
||||
'postbuild_name': 'Add symlinks for framework subdirectories',
|
||||
'action': [
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "atom/app/node_main.h"
|
||||
#include "atom/common/atom_command_line.h"
|
||||
#include "base/at_exit.h"
|
||||
#include "base/i18n/icu_util.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
@@ -134,6 +135,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
|
||||
node_indicator == "1") {
|
||||
// Now that argv conversion is done, we can finally start.
|
||||
base::AtExitManager atexit_manager;
|
||||
base::i18n::InitializeICU();
|
||||
return atom::NodeMain(argc, argv);
|
||||
} else if (env->GetVar("ATOM_SHELL_INTERNAL_CRASH_SERVICE",
|
||||
@@ -165,6 +167,7 @@ int main(int argc, const char* argv[]) {
|
||||
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
|
||||
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
|
||||
base::i18n::InitializeICU();
|
||||
base::AtExitManager atexit_manager;
|
||||
return atom::NodeMain(argc, const_cast<char**>(argv));
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
#else
|
||||
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
|
||||
#endif // defined(DEBUG)
|
||||
#endif // defined(OS_WIN)
|
||||
#else // defined(OS_WIN)
|
||||
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
|
||||
#endif // !defined(OS_WIN)
|
||||
logging::InitLogging(settings);
|
||||
|
||||
// Logging with pid and timestamp.
|
||||
|
||||
@@ -4,14 +4,21 @@
|
||||
|
||||
#include "atom/app/node_main.h"
|
||||
|
||||
#include "atom/app/uv_task_runner.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/browser/node_debugger.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/thread_task_runner_handle.h"
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/public/isolate_holder.h"
|
||||
#include "gin/v8_initializer.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
int NodeMain(int argc, char *argv[]) {
|
||||
base::CommandLine::Init(argc, argv);
|
||||
|
||||
argv = uv_setup_args(argc, argv);
|
||||
int exec_argc;
|
||||
const char** exec_argv;
|
||||
@@ -19,27 +26,29 @@ int NodeMain(int argc, char *argv[]) {
|
||||
|
||||
int exit_code = 1;
|
||||
{
|
||||
gin::IsolateHolder::LoadV8Snapshot();
|
||||
// Feed gin::PerIsolateData with a task runner.
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
|
||||
base::ThreadTaskRunnerHandle handle(uv_task_runner);
|
||||
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
gin::V8Initializer::LoadV8Natives();
|
||||
gin::IsolateHolder::Initialize(
|
||||
gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
|
||||
JavascriptEnvironment gin_env;
|
||||
node::Environment* env = node::CreateEnvironment(
|
||||
gin_env.isolate(), uv_default_loop(), gin_env.context(), argc, argv,
|
||||
gin_env.isolate(), loop, gin_env.context(), argc, argv,
|
||||
exec_argc, exec_argv);
|
||||
|
||||
// Start debugger.
|
||||
node::node_isolate = gin_env.isolate();
|
||||
if (node::use_debug_agent)
|
||||
node::StartDebug(env, node::debug_wait_connect);
|
||||
// Start our custom debugger implementation.
|
||||
NodeDebugger node_debugger(gin_env.isolate());
|
||||
if (node_debugger.IsRunning())
|
||||
env->AssignToContext(v8::Debug::GetDebugContext());
|
||||
|
||||
node::LoadEnvironment(env);
|
||||
|
||||
// Enable debugger.
|
||||
if (node::use_debug_agent)
|
||||
node::EnableDebug(env);
|
||||
|
||||
bool more;
|
||||
do {
|
||||
more = uv_run(env->event_loop(), UV_RUN_ONCE);
|
||||
|
||||
55
atom/app/uv_task_runner.cc
Normal file
55
atom/app/uv_task_runner.cc
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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/app/uv_task_runner.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
UvTaskRunner::UvTaskRunner(uv_loop_t* loop) : loop_(loop) {
|
||||
}
|
||||
|
||||
UvTaskRunner::~UvTaskRunner() {
|
||||
for (auto& iter : tasks_) {
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(iter.first));
|
||||
delete iter.first;
|
||||
}
|
||||
}
|
||||
|
||||
bool UvTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
uv_timer_t* timer = new uv_timer_t;
|
||||
timer->data = this;
|
||||
uv_timer_init(loop_, timer);
|
||||
uv_timer_start(timer, UvTaskRunner::OnTimeout, delay.InMilliseconds(), 0);
|
||||
tasks_[timer] = task;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UvTaskRunner::RunsTasksOnCurrentThread() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UvTaskRunner::PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
return PostDelayedTask(from_here, task, delay);;
|
||||
}
|
||||
|
||||
// static
|
||||
void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
|
||||
UvTaskRunner* self = static_cast<UvTaskRunner*>(timer->data);
|
||||
if (!ContainsKey(self->tasks_, timer))
|
||||
return;
|
||||
|
||||
self->tasks_[timer].Run();
|
||||
self->tasks_.erase(timer);
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(timer));
|
||||
delete timer;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
44
atom/app/uv_task_runner.h
Normal file
44
atom/app/uv_task_runner.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_APP_UV_TASK_RUNNER_H_
|
||||
#define ATOM_APP_UV_TASK_RUNNER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "vendor/node/deps/uv/include/uv.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// TaskRunner implementation that posts tasks into libuv's default loop.
|
||||
class UvTaskRunner : public base::SingleThreadTaskRunner {
|
||||
public:
|
||||
explicit UvTaskRunner(uv_loop_t* loop);
|
||||
~UvTaskRunner() override;
|
||||
|
||||
// base::SingleThreadTaskRunner:
|
||||
bool PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) override;
|
||||
bool RunsTasksOnCurrentThread() const override;
|
||||
bool PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) override;
|
||||
|
||||
private:
|
||||
static void OnTimeout(uv_timer_t* timer);
|
||||
|
||||
uv_loop_t* loop_;
|
||||
|
||||
std::map<uv_timer_t*, base::Closure> tasks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(UvTaskRunner);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_APP_UV_TASK_RUNNER_H_
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_path.h"
|
||||
@@ -34,8 +35,6 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#endif
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using atom::Browser;
|
||||
|
||||
namespace mate {
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
#include "base/time/time.h"
|
||||
#include "atom/browser/auto_updater.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
@@ -7,39 +7,30 @@
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "content/public/browser/tracing_controller.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using content::TracingController;
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<base::trace_event::CategoryFilter> {
|
||||
struct Converter<base::trace_event::TraceConfig> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::trace_event::CategoryFilter* out) {
|
||||
std::string filter;
|
||||
if (!ConvertFromV8(isolate, val, &filter))
|
||||
return false;
|
||||
*out = base::trace_event::CategoryFilter(filter);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<base::trace_event::TraceOptions> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
base::trace_event::TraceOptions* out) {
|
||||
std::string options;
|
||||
base::trace_event::TraceConfig* out) {
|
||||
Dictionary options;
|
||||
if (!ConvertFromV8(isolate, val, &options))
|
||||
return false;
|
||||
return out->SetFromString(options);
|
||||
std::string category_filter, trace_options;
|
||||
if (!options.Get("categoryFilter", &category_filter) ||
|
||||
!options.Get("traceOptions", &trace_options))
|
||||
return false;
|
||||
*out = base::trace_event::TraceConfig(category_filter, trace_options);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using atom::api::Cookies;
|
||||
using content::BrowserThread;
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ class Cookies : public mate::Wrappable {
|
||||
// Must be called on IO thread.
|
||||
net::CookieStore* GetCookieStore();
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
net::URLRequestContextGetter* request_context_getter_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Cookies);
|
||||
};
|
||||
|
||||
@@ -107,6 +107,10 @@ void Menu::SetSublabel(int index, const base::string16& sublabel) {
|
||||
model_->SetSublabel(index, sublabel);
|
||||
}
|
||||
|
||||
void Menu::SetRole(int index, const base::string16& role) {
|
||||
model_->SetRole(index, role);
|
||||
}
|
||||
|
||||
void Menu::Clear() {
|
||||
model_->Clear();
|
||||
}
|
||||
@@ -154,6 +158,7 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("insertSubMenu", &Menu::InsertSubMenuAt)
|
||||
.SetMethod("setIcon", &Menu::SetIcon)
|
||||
.SetMethod("setSublabel", &Menu::SetSublabel)
|
||||
.SetMethod("setRole", &Menu::SetRole)
|
||||
.SetMethod("clear", &Menu::Clear)
|
||||
.SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId)
|
||||
.SetMethod("getItemCount", &Menu::GetItemCount)
|
||||
|
||||
@@ -73,6 +73,7 @@ class Menu : public mate::Wrappable,
|
||||
Menu* menu);
|
||||
void SetIcon(int index, const gfx::Image& image);
|
||||
void SetSublabel(int index, const base::string16& sublabel);
|
||||
void SetRole(int index, const base::string16& role);
|
||||
void Clear();
|
||||
int GetIndexOfCommandId(int command_id);
|
||||
int GetItemCount() const;
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
#include "atom/browser/api/atom_api_power_monitor.h"
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/power_monitor/power_monitor.h"
|
||||
#include "base/power_monitor/power_monitor_device_source.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -41,9 +40,9 @@ void PowerMonitor::OnResume() {
|
||||
// static
|
||||
v8::Local<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError(
|
||||
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||
isolate,
|
||||
"Cannot initialize \"power-monitor\" module before app is ready");
|
||||
"Cannot initialize \"power-monitor\" module before app is ready")));
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "content/public/browser/power_save_blocker.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
|
||||
@@ -7,17 +7,13 @@
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/api/atom_api_session.h"
|
||||
#include "atom/browser/net/adapter_request_job.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/browser/net/url_request_async_asar_job.h"
|
||||
#include "atom/browser/net/url_request_buffer_job.h"
|
||||
#include "atom/browser/net/url_request_fetch_job.h"
|
||||
#include "atom/browser/net/url_request_string_job.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
@@ -41,230 +37,35 @@ namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||
|
||||
scoped_refptr<base::RefCountedBytes> BufferToRefCountedBytes(
|
||||
v8::Local<v8::Value> buf) {
|
||||
scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes);
|
||||
auto start = reinterpret_cast<const unsigned char*>(node::Buffer::Data(buf));
|
||||
data->data().assign(start, start + node::Buffer::Length(buf));
|
||||
return data;
|
||||
}
|
||||
|
||||
class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
public:
|
||||
CustomProtocolRequestJob(Protocol* registry,
|
||||
ProtocolHandler* protocol_handler,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: AdapterRequestJob(protocol_handler, request, network_delegate),
|
||||
registry_(registry) {
|
||||
}
|
||||
|
||||
void GetJobTypeInUI(const Protocol::JsProtocolHandler& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
v8::Locker locker(registry_->isolate());
|
||||
v8::HandleScope handle_scope(registry_->isolate());
|
||||
|
||||
// Call the JS handler.
|
||||
v8::Local<v8::Value> result = callback.Run(request());
|
||||
|
||||
// Determine the type of the job we are going to create.
|
||||
if (result->IsString()) {
|
||||
std::string data = mate::V8ToString(result);
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||
GetWeakPtr(), "text/plain", "UTF-8", data));
|
||||
return;
|
||||
} else if (result->IsObject()) {
|
||||
v8::Local<v8::Object> obj = result->ToObject();
|
||||
mate::Dictionary dict(registry_->isolate(), obj);
|
||||
std::string name = mate::V8ToString(obj->GetConstructorName());
|
||||
if (name == "RequestStringJob") {
|
||||
std::string mime_type, charset, data;
|
||||
dict.Get("mimeType", &mime_type);
|
||||
dict.Get("charset", &charset);
|
||||
dict.Get("data", &data);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||
GetWeakPtr(), mime_type, charset, data));
|
||||
return;
|
||||
} else if (name == "RequestBufferJob") {
|
||||
std::string mime_type, encoding;
|
||||
v8::Local<v8::Value> buffer;
|
||||
dict.Get("mimeType", &mime_type);
|
||||
dict.Get("encoding", &encoding);
|
||||
dict.Get("data", &buffer);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateBufferJobAndStart,
|
||||
GetWeakPtr(), mime_type, encoding,
|
||||
BufferToRefCountedBytes(buffer)));
|
||||
return;
|
||||
} else if (name == "RequestFileJob") {
|
||||
base::FilePath path;
|
||||
dict.Get("path", &path);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
|
||||
GetWeakPtr(), path));
|
||||
return;
|
||||
} else if (name == "RequestErrorJob") {
|
||||
int error = net::ERR_NOT_IMPLEMENTED;
|
||||
dict.Get("error", &error);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||
GetWeakPtr(), error));
|
||||
return;
|
||||
} else if (name == "RequestHttpJob") {
|
||||
GURL url;
|
||||
std::string method, referrer;
|
||||
dict.Get("url", &url);
|
||||
dict.Get("method", &method);
|
||||
dict.Get("referrer", &referrer);
|
||||
|
||||
v8::Local<v8::Value> value;
|
||||
mate::Handle<Session> session;
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter;
|
||||
// "session" null -> pass nullptr;
|
||||
// "session" a Session object -> use passed session.
|
||||
// "session" undefined -> use current session;
|
||||
if (dict.Get("session", &session))
|
||||
request_context_getter =
|
||||
session->browser_context()->GetRequestContext();
|
||||
else if (dict.Get("session", &value) && value->IsNull())
|
||||
request_context_getter = nullptr;
|
||||
else
|
||||
request_context_getter = registry_->request_context_getter();
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
|
||||
request_context_getter, url, method, referrer));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try the default protocol handler if we have.
|
||||
if (default_protocol_handler()) {
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
|
||||
GetWeakPtr()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to the not implemented error.
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||
GetWeakPtr(), net::ERR_NOT_IMPLEMENTED));
|
||||
}
|
||||
|
||||
// AdapterRequestJob:
|
||||
void GetJobType() override {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&CustomProtocolRequestJob::GetJobTypeInUI,
|
||||
base::Unretained(this),
|
||||
registry_->GetProtocolHandler(request()->url().scheme())));
|
||||
}
|
||||
|
||||
private:
|
||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||
};
|
||||
|
||||
// Always return the same CustomProtocolRequestJob for all requests, because
|
||||
// the content API needs the ProtocolHandler to return a job immediately, and
|
||||
// getting the real job from the JS requires asynchronous calls, so we have
|
||||
// to create an adapter job first.
|
||||
// Users can also pass an extra ProtocolHandler as the fallback one when
|
||||
// registered handler doesn't want to deal with the request.
|
||||
class CustomProtocolHandler : public ProtocolHandler {
|
||||
public:
|
||||
CustomProtocolHandler(api::Protocol* registry,
|
||||
ProtocolHandler* protocol_handler = NULL)
|
||||
: registry_(registry), protocol_handler_(protocol_handler) {
|
||||
}
|
||||
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override {
|
||||
return new CustomProtocolRequestJob(registry_, protocol_handler_.get(),
|
||||
request, network_delegate);
|
||||
}
|
||||
|
||||
ProtocolHandler* ReleaseDefaultProtocolHandler() {
|
||||
return protocol_handler_.release();
|
||||
}
|
||||
|
||||
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
|
||||
|
||||
private:
|
||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||
scoped_ptr<ProtocolHandler> protocol_handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||
};
|
||||
|
||||
std::string ConvertErrorCode(int error_code) {
|
||||
switch (error_code) {
|
||||
case Protocol::ERR_SCHEME_REGISTERED:
|
||||
return "The Scheme is already registered";
|
||||
case Protocol::ERR_SCHEME_UNREGISTERED:
|
||||
return "The Scheme has not been registered";
|
||||
case Protocol::ERR_SCHEME_INTERCEPTED:
|
||||
return "There is no protocol handler to intercept";
|
||||
case Protocol::ERR_SCHEME_UNINTERCEPTED:
|
||||
return "The protocol is not intercepted";
|
||||
case Protocol::ERR_NO_SCHEME:
|
||||
return "The Scheme does not exist.";
|
||||
case Protocol::ERR_SCHEME:
|
||||
return "Cannot intercept custom protocols";
|
||||
default:
|
||||
NOTREACHED();
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Protocol::Protocol(AtomBrowserContext* browser_context)
|
||||
: request_context_getter_(browser_context->GetRequestContext()),
|
||||
job_factory_(browser_context->job_factory()) {
|
||||
CHECK(job_factory_);
|
||||
}
|
||||
|
||||
Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
|
||||
const std::string& scheme) {
|
||||
return protocol_handlers_[scheme];
|
||||
}
|
||||
|
||||
void Protocol::OnIOActionCompleted(const JsCompletionCallback& callback,
|
||||
int error) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
if (error) {
|
||||
callback.Run(v8::Exception::Error(
|
||||
mate::StringToV8(isolate(), ConvertErrorCode(error))));
|
||||
return;
|
||||
}
|
||||
|
||||
callback.Run(v8::Null(isolate()));
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
|
||||
.SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol)
|
||||
.SetMethod("_registerProtocol", &Protocol::RegisterProtocol)
|
||||
.SetMethod("_unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||
.SetMethod("_interceptProtocol", &Protocol::InterceptProtocol)
|
||||
.SetMethod("_uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||
.SetMethod("registerStringProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestStringJob>)
|
||||
.SetMethod("registerBufferProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestBufferJob>)
|
||||
.SetMethod("registerFileProtocol",
|
||||
&Protocol::RegisterProtocol<UrlRequestAsyncAsarJob>)
|
||||
.SetMethod("registerHttpProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||
.SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled)
|
||||
.SetMethod("interceptStringProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestStringJob>)
|
||||
.SetMethod("interceptBufferProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestBufferJob>)
|
||||
.SetMethod("interceptFileProtocol",
|
||||
&Protocol::InterceptProtocol<UrlRequestAsyncAsarJob>)
|
||||
.SetMethod("interceptHttpProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||
}
|
||||
|
||||
void Protocol::RegisterStandardSchemes(
|
||||
@@ -272,131 +73,86 @@ void Protocol::RegisterStandardSchemes(
|
||||
atom::AtomBrowserClient::SetCustomSchemes(schemes);
|
||||
}
|
||||
|
||||
void Protocol::IsHandledProtocol(const std::string& scheme,
|
||||
const net::CompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AtomURLRequestJobFactory::IsHandledProtocol,
|
||||
base::Unretained(job_factory_), scheme),
|
||||
void Protocol::UnregisterProtocol(
|
||||
const std::string& scheme, mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
Protocol::ProtocolError Protocol::UnregisterProtocolInIO(
|
||||
const std::string& scheme) {
|
||||
if (!job_factory_->HasProtocolHandler(scheme))
|
||||
return PROTOCOL_NOT_REGISTERED;
|
||||
job_factory_->SetProtocolHandler(scheme, nullptr);
|
||||
return PROTOCOL_OK;
|
||||
}
|
||||
|
||||
void Protocol::IsProtocolHandled(const std::string& scheme,
|
||||
const BooleanCallback& callback) {
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::IsProtocolHandledInIO,
|
||||
base::Unretained(this), scheme),
|
||||
callback);
|
||||
}
|
||||
|
||||
void Protocol::RegisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::RegisterProtocolInIO,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
bool Protocol::IsProtocolHandledInIO(const std::string& scheme) {
|
||||
return job_factory_->IsHandledProtocol(scheme);
|
||||
}
|
||||
|
||||
void Protocol::UnregisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Protocol::InterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::InterceptProtocolInIO,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Protocol::UninterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
void Protocol::UninterceptProtocol(
|
||||
const std::string& scheme, mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UninterceptProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
int Protocol::RegisterProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
if (ContainsKey(protocol_handlers_, scheme) ||
|
||||
job_factory_->IsHandledProtocol(scheme)) {
|
||||
return ERR_SCHEME_REGISTERED;
|
||||
}
|
||||
|
||||
protocol_handlers_[scheme] = handler;
|
||||
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
|
||||
|
||||
return OK;
|
||||
Protocol::ProtocolError Protocol::UninterceptProtocolInIO(
|
||||
const std::string& scheme) {
|
||||
if (!original_protocols_.contains(scheme))
|
||||
return PROTOCOL_NOT_INTERCEPTED;
|
||||
job_factory_->ReplaceProtocol(scheme,
|
||||
original_protocols_.take_and_erase(scheme));
|
||||
return PROTOCOL_OK;
|
||||
}
|
||||
|
||||
int Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
void Protocol::OnIOCompleted(
|
||||
const CompletionCallback& callback, ProtocolError error) {
|
||||
// The completion callback is optional.
|
||||
if (callback.is_null())
|
||||
return;
|
||||
|
||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||
if (it == protocol_handlers_.end()) {
|
||||
return ERR_SCHEME_UNREGISTERED;
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
if (error == PROTOCOL_OK) {
|
||||
callback.Run(v8::Null(isolate()));
|
||||
} else {
|
||||
std::string str = ErrorCodeToString(error);
|
||||
callback.Run(v8::Exception::Error(mate::StringToV8(isolate(), str)));
|
||||
}
|
||||
|
||||
protocol_handlers_.erase(it);
|
||||
job_factory_->SetProtocolHandler(scheme, NULL);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int Protocol::InterceptProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
// Force the request context to initialize, otherwise we might have nothing
|
||||
// to intercept.
|
||||
request_context_getter_->GetURLRequestContext();
|
||||
|
||||
if (!job_factory_->HasProtocolHandler(scheme))
|
||||
return ERR_NO_SCHEME;
|
||||
|
||||
if (ContainsKey(protocol_handlers_, scheme))
|
||||
return ERR_SCHEME;
|
||||
|
||||
protocol_handlers_[scheme] = handler;
|
||||
ProtocolHandler* original_handler = job_factory_->GetProtocolHandler(scheme);
|
||||
if (original_handler == nullptr) {
|
||||
return ERR_SCHEME_INTERCEPTED;
|
||||
std::string Protocol::ErrorCodeToString(ProtocolError error) {
|
||||
switch (error) {
|
||||
case PROTOCOL_FAIL: return "Failed to manipulate protocol factory";
|
||||
case PROTOCOL_REGISTERED: return "The scheme has been registred";
|
||||
case PROTOCOL_NOT_REGISTERED: return "The scheme has not been registred";
|
||||
case PROTOCOL_INTERCEPTED: return "The scheme has been intercepted";
|
||||
case PROTOCOL_NOT_INTERCEPTED: return "The scheme has not been intercepted";
|
||||
default: return "Unexpected error";
|
||||
}
|
||||
|
||||
job_factory_->ReplaceProtocol(
|
||||
scheme, new CustomProtocolHandler(this, original_handler));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||
if (it == protocol_handlers_.end())
|
||||
return ERR_SCHEME_UNREGISTERED;
|
||||
|
||||
protocol_handlers_.erase(it);
|
||||
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
||||
job_factory_->GetProtocolHandler(scheme));
|
||||
if (handler->original_handler() == nullptr) {
|
||||
return ERR_SCHEME_UNINTERCEPTED;
|
||||
}
|
||||
|
||||
// Reset the protocol handler to the orignal one and delete current protocol
|
||||
// handler.
|
||||
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
|
||||
delete job_factory_->ReplaceProtocol(scheme, original_handler);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -9,10 +9,14 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/containers/scoped_ptr_hash_map.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/arguments.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/base/completion_callback.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace net {
|
||||
class URLRequest;
|
||||
@@ -26,31 +30,16 @@ class AtomURLRequestJobFactory;
|
||||
|
||||
namespace api {
|
||||
|
||||
class Protocol : public mate::EventEmitter {
|
||||
class Protocol : public mate::Wrappable {
|
||||
public:
|
||||
using JsProtocolHandler =
|
||||
base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>;
|
||||
using JsCompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
|
||||
enum {
|
||||
OK = 0,
|
||||
ERR_SCHEME_REGISTERED,
|
||||
ERR_SCHEME_UNREGISTERED,
|
||||
ERR_SCHEME_INTERCEPTED,
|
||||
ERR_SCHEME_UNINTERCEPTED,
|
||||
ERR_NO_SCHEME,
|
||||
ERR_SCHEME
|
||||
};
|
||||
using Handler =
|
||||
base::Callback<void(const net::URLRequest*, v8::Local<v8::Value>)>;
|
||||
using CompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
using BooleanCallback = base::Callback<void(bool)>;
|
||||
|
||||
static mate::Handle<Protocol> Create(
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
|
||||
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
|
||||
|
||||
net::URLRequestContextGetter* request_context_getter() {
|
||||
return request_context_getter_.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit Protocol(AtomBrowserContext* browser_context);
|
||||
|
||||
@@ -59,48 +48,139 @@ class Protocol : public mate::EventEmitter {
|
||||
v8::Isolate* isolate);
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, JsProtocolHandler> ProtocolHandlersMap;
|
||||
// Possible errors.
|
||||
enum ProtocolError {
|
||||
PROTOCOL_OK, // no error
|
||||
PROTOCOL_FAIL, // operation failed, should never occur
|
||||
PROTOCOL_REGISTERED,
|
||||
PROTOCOL_NOT_REGISTERED,
|
||||
PROTOCOL_INTERCEPTED,
|
||||
PROTOCOL_NOT_INTERCEPTED,
|
||||
};
|
||||
|
||||
// Callback called after performing action on IO thread.
|
||||
void OnIOActionCompleted(const JsCompletionCallback& callback,
|
||||
int error);
|
||||
// The protocol handler that will create a protocol handler for certain
|
||||
// request job.
|
||||
template<typename RequestJob>
|
||||
class CustomProtocolHandler
|
||||
: public net::URLRequestJobFactory::ProtocolHandler {
|
||||
public:
|
||||
CustomProtocolHandler(
|
||||
v8::Isolate* isolate,
|
||||
net::URLRequestContextGetter* request_context,
|
||||
const Handler& handler)
|
||||
: isolate_(isolate),
|
||||
request_context_(request_context),
|
||||
handler_(handler) {}
|
||||
~CustomProtocolHandler() override {}
|
||||
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override {
|
||||
RequestJob* request_job = new RequestJob(request, network_delegate);
|
||||
request_job->SetHandlerInfo(isolate_, request_context_, handler_);
|
||||
return request_job;
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
net::URLRequestContextGetter* request_context_;
|
||||
Protocol::Handler handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||
};
|
||||
|
||||
// Register schemes to standard scheme list.
|
||||
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
|
||||
|
||||
// Returns whether a scheme has been registered.
|
||||
void IsHandledProtocol(const std::string& scheme,
|
||||
const net::CompletionCallback& callback);
|
||||
// Register the protocol with certain request job.
|
||||
template<typename RequestJob>
|
||||
void RegisterProtocol(const std::string& scheme,
|
||||
const Handler& handler,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::RegisterProtocolInIO<RequestJob>,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
template<typename RequestJob>
|
||||
ProtocolError RegisterProtocolInIO(const std::string& scheme,
|
||||
const Handler& handler) {
|
||||
if (job_factory_->IsHandledProtocol(scheme))
|
||||
return PROTOCOL_REGISTERED;
|
||||
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
|
||||
new CustomProtocolHandler<RequestJob>(
|
||||
isolate(), request_context_getter_, handler));
|
||||
if (job_factory_->SetProtocolHandler(scheme, protocol_handler.Pass()))
|
||||
return PROTOCOL_OK;
|
||||
else
|
||||
return PROTOCOL_FAIL;
|
||||
}
|
||||
|
||||
// Register/unregister an networking |scheme| which would be handled by
|
||||
// |callback|.
|
||||
void RegisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback);
|
||||
void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme,
|
||||
const JsCompletionCallback& callback);
|
||||
// Unregister the protocol handler that handles |scheme|.
|
||||
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
|
||||
ProtocolError UnregisterProtocolInIO(const std::string& scheme);
|
||||
|
||||
// Intercept/unintercept an existing protocol handler.
|
||||
void InterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback);
|
||||
void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme,
|
||||
const JsCompletionCallback& callback);
|
||||
// Whether the protocol has handler registered.
|
||||
void IsProtocolHandled(const std::string& scheme,
|
||||
const BooleanCallback& callback);
|
||||
bool IsProtocolHandledInIO(const std::string& scheme);
|
||||
|
||||
// The networking related operations have to be done in IO thread.
|
||||
int RegisterProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler);
|
||||
int UnregisterProtocolInIO(const std::string& scheme);
|
||||
int InterceptProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler);
|
||||
int UninterceptProtocolInIO(const std::string& scheme);
|
||||
// Replace the protocol handler with a new one.
|
||||
template<typename RequestJob>
|
||||
void InterceptProtocol(const std::string& scheme,
|
||||
const Handler& handler,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::InterceptProtocolInIO<RequestJob>,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
template<typename RequestJob>
|
||||
ProtocolError InterceptProtocolInIO(const std::string& scheme,
|
||||
const Handler& handler) {
|
||||
if (!job_factory_->IsHandledProtocol(scheme))
|
||||
return PROTOCOL_NOT_REGISTERED;
|
||||
// It is possible a protocol is handled but can not be intercepted.
|
||||
if (!job_factory_->HasProtocolHandler(scheme))
|
||||
return PROTOCOL_FAIL;
|
||||
if (ContainsKey(original_protocols_, scheme))
|
||||
return PROTOCOL_INTERCEPTED;
|
||||
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
|
||||
new CustomProtocolHandler<RequestJob>(
|
||||
isolate(), request_context_getter_, handler));
|
||||
original_protocols_.set(
|
||||
scheme,
|
||||
job_factory_->ReplaceProtocol(scheme, protocol_handler.Pass()));
|
||||
return PROTOCOL_OK;
|
||||
}
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
// Restore the |scheme| to its original protocol handler.
|
||||
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
|
||||
ProtocolError UninterceptProtocolInIO(const std::string& scheme);
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
ProtocolHandlersMap protocol_handlers_;
|
||||
// Convert error code to JS exception and call the callback.
|
||||
void OnIOCompleted(const CompletionCallback& callback, ProtocolError error);
|
||||
|
||||
// Convert error code to string.
|
||||
std::string ErrorCodeToString(ProtocolError error);
|
||||
|
||||
net::URLRequestContextGetter* request_context_getter_;
|
||||
|
||||
// Map that stores the original protocols of schemes.
|
||||
using OriginalProtocolsMap = base::ScopedPtrHashMap<
|
||||
std::string,
|
||||
scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>>;
|
||||
OriginalProtocolsMap original_protocols_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_; // weak ref
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Protocol);
|
||||
};
|
||||
|
||||
@@ -113,14 +113,16 @@ mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
|
||||
// static
|
||||
v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError(isolate,
|
||||
"Cannot initialize \"screen\" module before app is ready");
|
||||
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||
isolate,
|
||||
"Cannot initialize \"screen\" module before app is ready")));
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
|
||||
if (!screen) {
|
||||
node::ThrowError(isolate, "Failed to get screen information");
|
||||
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||
isolate, "Failed to get screen information")));
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
|
||||
#include "atom/browser/api/atom_api_cookies.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/prefs/pref_service.h"
|
||||
#include "base/strings/string_util.h"
|
||||
@@ -28,8 +30,6 @@
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
using content::StoragePartition;
|
||||
|
||||
@@ -101,6 +101,19 @@ struct Converter<ClearStorageDataOptions> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<content::DownloadItem*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
content::DownloadItem* val) {
|
||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
dict.Set("url", val->GetURL());
|
||||
dict.Set("filename", val->GetSuggestedFilename());
|
||||
dict.Set("mimeType", val->GetMimeType());
|
||||
dict.Set("hasUserGesture", val->HasUserGesture());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
@@ -109,6 +122,10 @@ namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
// The wrapSession funtion which is implemented in JavaScript
|
||||
using WrapSessionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
WrapSessionCallback g_wrap_session;
|
||||
|
||||
class ResolveProxyHelper {
|
||||
public:
|
||||
ResolveProxyHelper(AtomBrowserContext* browser_context,
|
||||
@@ -215,13 +232,40 @@ void SetProxyInIO(net::URLRequestContextGetter* getter,
|
||||
Session::Session(AtomBrowserContext* browser_context)
|
||||
: browser_context_(browser_context) {
|
||||
AttachAsUserData(browser_context);
|
||||
|
||||
// Observe DownloadManger to get download notifications.
|
||||
content::BrowserContext::GetDownloadManager(browser_context)->
|
||||
AddObserver(this);
|
||||
}
|
||||
|
||||
Session::~Session() {
|
||||
content::BrowserContext::GetDownloadManager(browser_context())->
|
||||
RemoveObserver(this);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
auto web_contents = item->GetWebContents();
|
||||
bool prevent_default = Emit("will-download", item,
|
||||
api::WebContents::CreateFrom(isolate(),
|
||||
web_contents));
|
||||
if (prevent_default) {
|
||||
item->Cancel(true);
|
||||
item->Remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool Session::IsDestroyed() const {
|
||||
return !browser_context_;
|
||||
}
|
||||
|
||||
void Session::Destroy() {
|
||||
browser_context_ = nullptr;
|
||||
}
|
||||
|
||||
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
|
||||
new ResolveProxyHelper(browser_context_, url, callback);
|
||||
new ResolveProxyHelper(browser_context(), url, callback);
|
||||
}
|
||||
|
||||
void Session::ClearCache(const net::CompletionCallback& callback) {
|
||||
@@ -242,7 +286,7 @@ void Session::ClearStorageData(mate::Arguments* args) {
|
||||
}
|
||||
|
||||
auto storage_partition =
|
||||
content::BrowserContext::GetStoragePartition(browser_context_, nullptr);
|
||||
content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
|
||||
storage_partition->ClearData(
|
||||
options.storage_types, options.quota_types, options.origin,
|
||||
content::StoragePartition::OriginMatcherFunction(),
|
||||
@@ -263,7 +307,7 @@ void Session::SetDownloadPath(const base::FilePath& path) {
|
||||
|
||||
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
||||
if (cookies_.IsEmpty()) {
|
||||
auto handle = atom::api::Cookies::Create(isolate, browser_context_);
|
||||
auto handle = atom::api::Cookies::Create(isolate, browser_context());
|
||||
cookies_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
return v8::Local<v8::Value>::New(isolate, cookies_);
|
||||
@@ -282,15 +326,47 @@ mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
|
||||
|
||||
// static
|
||||
mate::Handle<Session> Session::CreateFrom(
|
||||
v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context) {
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
|
||||
auto existing = TrackableObject::FromWrappedClass(isolate, browser_context);
|
||||
if (existing)
|
||||
return mate::CreateHandle(isolate, static_cast<Session*>(existing));
|
||||
|
||||
return mate::CreateHandle(isolate, new Session(browser_context));
|
||||
auto handle = mate::CreateHandle(isolate, new Session(browser_context));
|
||||
g_wrap_session.Run(handle.ToV8());
|
||||
return handle;
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<Session> Session::FromPartition(
|
||||
v8::Isolate* isolate, const std::string& partition, bool in_memory) {
|
||||
auto browser_context = brightray::BrowserContext::From(partition, in_memory);
|
||||
return CreateFrom(isolate,
|
||||
static_cast<AtomBrowserContext*>(browser_context.get()));
|
||||
}
|
||||
|
||||
void SetWrapSession(const WrapSessionCallback& callback) {
|
||||
g_wrap_session = callback;
|
||||
}
|
||||
|
||||
void ClearWrapSession() {
|
||||
g_wrap_session.Reset();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("fromPartition", &atom::api::Session::FromPartition);
|
||||
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
|
||||
dict.SetMethod("_clearWrapSession", &atom::api::ClearWrapSession);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_session, Initialize)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/base/completion_callback.h"
|
||||
|
||||
@@ -27,7 +28,8 @@ class AtomBrowserContext;
|
||||
|
||||
namespace api {
|
||||
|
||||
class Session: public mate::TrackableObject<Session> {
|
||||
class Session: public mate::TrackableObject<Session>,
|
||||
public content::DownloadManager::Observer {
|
||||
public:
|
||||
using ResolveProxyCallback = base::Callback<void(std::string)>;
|
||||
|
||||
@@ -35,17 +37,29 @@ class Session: public mate::TrackableObject<Session> {
|
||||
static mate::Handle<Session> CreateFrom(
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
|
||||
AtomBrowserContext* browser_context() const { return browser_context_; }
|
||||
// Gets the Session of |partition| and |in_memory|.
|
||||
static mate::Handle<Session> FromPartition(
|
||||
v8::Isolate* isolate, const std::string& partition, bool in_memory);
|
||||
|
||||
AtomBrowserContext* browser_context() const { return browser_context_.get(); }
|
||||
|
||||
protected:
|
||||
explicit Session(AtomBrowserContext* browser_context);
|
||||
~Session();
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
// content::DownloadManager::Observer:
|
||||
void OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) override;
|
||||
|
||||
// mate::Wrappable:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
private:
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void ClearCache(const net::CompletionCallback& callback);
|
||||
void ClearStorageData(mate::Arguments* args);
|
||||
@@ -53,9 +67,10 @@ class Session: public mate::TrackableObject<Session> {
|
||||
void SetDownloadPath(const base::FilePath& path);
|
||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||
|
||||
// Cached object for cookies API.
|
||||
v8::Global<v8::Value> cookies_;
|
||||
|
||||
AtomBrowserContext* browser_context_; // weak ref
|
||||
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Session);
|
||||
};
|
||||
|
||||
@@ -12,13 +12,12 @@
|
||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -35,7 +34,8 @@ Tray::~Tray() {
|
||||
// static
|
||||
mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError(isolate, "Cannot create Tray before app is ready");
|
||||
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||
isolate, "Cannot create Tray before app is ready")));
|
||||
return nullptr;
|
||||
}
|
||||
return new Tray(image);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/web_contents_preferences.h"
|
||||
#include "atom/browser/web_view_guest_delegate.h"
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
@@ -153,23 +154,41 @@ WebContents::WebContents(content::WebContents* web_contents)
|
||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||
}
|
||||
|
||||
WebContents::WebContents(const mate::Dictionary& options) {
|
||||
WebContents::WebContents(v8::Isolate* isolate,
|
||||
const mate::Dictionary& options) {
|
||||
// Whether it is a guest WebContents.
|
||||
bool is_guest = false;
|
||||
options.Get("isGuest", &is_guest);
|
||||
|
||||
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
|
||||
|
||||
auto browser_context = AtomBrowserMainParts::Get()->browser_context();
|
||||
// Obtain the session.
|
||||
std::string partition;
|
||||
mate::Handle<api::Session> session;
|
||||
if (options.Get("session", &session)) {
|
||||
} else if (options.Get("partition", &partition) && !partition.empty()) {
|
||||
bool in_memory = true;
|
||||
if (base::StartsWith(partition, "persist:", base::CompareCase::SENSITIVE)) {
|
||||
in_memory = false;
|
||||
partition = partition.substr(8);
|
||||
}
|
||||
session = Session::FromPartition(isolate, partition, in_memory);
|
||||
} else {
|
||||
// Use the default session if not specified.
|
||||
session = Session::FromPartition(isolate, "", false);
|
||||
}
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
|
||||
content::WebContents* web_contents;
|
||||
if (is_guest) {
|
||||
content::SiteInstance* site_instance = content::SiteInstance::CreateForURL(
|
||||
browser_context, GURL("chrome-guest://fake-host"));
|
||||
content::WebContents::CreateParams params(browser_context, site_instance);
|
||||
session->browser_context(), GURL("chrome-guest://fake-host"));
|
||||
content::WebContents::CreateParams params(
|
||||
session->browser_context(), site_instance);
|
||||
guest_delegate_.reset(new WebViewGuestDelegate);
|
||||
params.guest_delegate = guest_delegate_.get();
|
||||
web_contents = content::WebContents::Create(params);
|
||||
} else {
|
||||
content::WebContents::CreateParams params(browser_context);
|
||||
content::WebContents::CreateParams params(session->browser_context());
|
||||
web_contents = content::WebContents::Create(params);
|
||||
}
|
||||
|
||||
@@ -177,6 +196,11 @@ WebContents::WebContents(const mate::Dictionary& options) {
|
||||
AttachAsUserData(web_contents);
|
||||
InitWithWebContents(web_contents);
|
||||
|
||||
// Save the preferences.
|
||||
base::DictionaryValue web_preferences;
|
||||
mate::ConvertFromV8(isolate, options.GetHandle(), &web_preferences);
|
||||
new WebContentsPreferences(web_contents, &web_preferences);
|
||||
|
||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||
|
||||
if (is_guest) {
|
||||
@@ -217,7 +241,7 @@ bool WebContents::ShouldCreateWebContents(
|
||||
int route_id,
|
||||
int main_frame_route_id,
|
||||
WindowContainerType window_container_type,
|
||||
const base::string16& frame_name,
|
||||
const std::string& frame_name,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
content::SessionStorageNamespace* session_storage_namespace) {
|
||||
@@ -277,7 +301,10 @@ bool WebContents::IsPopupOrPanel(const content::WebContents* source) const {
|
||||
void WebContents::HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (type_ == BROWSER_WINDOW) {
|
||||
if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen()) {
|
||||
// Escape exits tabbed fullscreen mode.
|
||||
ExitFullscreenModeForTab(source);
|
||||
} else if (type_ == BROWSER_WINDOW) {
|
||||
owner_window()->HandleKeyboardEvent(source, event);
|
||||
} else if (type_ == WEB_VIEW && guest_delegate_) {
|
||||
// Send the unhandled keyboard events back to the embedder.
|
||||
@@ -359,14 +386,16 @@ void WebContents::DidFailProvisionalLoad(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const GURL& validated_url,
|
||||
int error_code,
|
||||
const base::string16& error_description) {
|
||||
const base::string16& error_description,
|
||||
bool was_ignored_by_handler) {
|
||||
Emit("did-fail-load", error_code, error_description);
|
||||
}
|
||||
|
||||
void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
|
||||
const GURL& validated_url,
|
||||
int error_code,
|
||||
const base::string16& error_description) {
|
||||
const base::string16& error_description,
|
||||
bool was_ignored_by_handler) {
|
||||
Emit("did-fail-load", error_code, error_description);
|
||||
}
|
||||
|
||||
@@ -476,6 +505,7 @@ void WebContents::NavigationEntryCommitted(
|
||||
}
|
||||
|
||||
void WebContents::Destroy() {
|
||||
session_.Reset();
|
||||
if (type_ == WEB_VIEW && managed_web_contents()) {
|
||||
// When force destroying the "destroyed" event is not emitted.
|
||||
WebContentsDestroyed();
|
||||
@@ -638,10 +668,6 @@ void WebContents::InspectServiceWorker() {
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
|
||||
if (session_.IsEmpty()) {
|
||||
auto handle = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
session_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
return v8::Local<v8::Value>::New(isolate, session_);
|
||||
}
|
||||
|
||||
@@ -691,17 +717,19 @@ void WebContents::PrintToPDF(const base::DictionaryValue& setting,
|
||||
PrintToPDF(setting, callback);
|
||||
}
|
||||
|
||||
void WebContents::AddWorkSpace(const base::FilePath& path) {
|
||||
void WebContents::AddWorkSpace(mate::Arguments* args,
|
||||
const base::FilePath& path) {
|
||||
if (path.empty()) {
|
||||
node::ThrowError(isolate(), "path cannot be empty");
|
||||
args->ThrowError("path cannot be empty");
|
||||
return;
|
||||
}
|
||||
DevToolsAddFileSystem(path);
|
||||
}
|
||||
|
||||
void WebContents::RemoveWorkSpace(const base::FilePath& path) {
|
||||
void WebContents::RemoveWorkSpace(mate::Arguments* args,
|
||||
const base::FilePath& path) {
|
||||
if (path.empty()) {
|
||||
node::ThrowError(isolate(), "path cannot be empty");
|
||||
args->ThrowError("path cannot be empty");
|
||||
return;
|
||||
}
|
||||
DevToolsRemoveFileSystem(path);
|
||||
@@ -877,7 +905,7 @@ mate::Handle<WebContents> WebContents::CreateFrom(
|
||||
// static
|
||||
mate::Handle<WebContents> WebContents::Create(
|
||||
v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||
auto handle = mate::CreateHandle(isolate, new WebContents(options));
|
||||
auto handle = mate::CreateHandle(isolate, new WebContents(isolate, options));
|
||||
g_wrap_web_contents.Run(handle.ToV8());
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
#include "content/public/common/favicon_url.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/common/favicon_url.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
@@ -48,7 +48,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
static mate::Handle<WebContents> Create(
|
||||
v8::Isolate* isolate, const mate::Dictionary& options);
|
||||
|
||||
void Destroy();
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
bool IsAlive() const;
|
||||
int GetID() const;
|
||||
bool Equal(const WebContents* web_contents) const;
|
||||
@@ -85,8 +87,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
const PrintToPDFCallback& callback);
|
||||
|
||||
// DevTools workspace api.
|
||||
void AddWorkSpace(const base::FilePath& path);
|
||||
void RemoveWorkSpace(const base::FilePath& path);
|
||||
void AddWorkSpace(mate::Arguments* args, const base::FilePath& path);
|
||||
void RemoveWorkSpace(mate::Arguments* args, const base::FilePath& path);
|
||||
|
||||
// Editing commands.
|
||||
void Undo();
|
||||
@@ -116,7 +118,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
|
||||
protected:
|
||||
explicit WebContents(content::WebContents* web_contents);
|
||||
explicit WebContents(const mate::Dictionary& options);
|
||||
WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
|
||||
~WebContents();
|
||||
|
||||
// mate::Wrappable:
|
||||
@@ -135,7 +137,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
int route_id,
|
||||
int main_frame_route_id,
|
||||
WindowContainerType window_container_type,
|
||||
const base::string16& frame_name,
|
||||
const std::string& frame_name,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
content::SessionStorageNamespace* session_storage_namespace) override;
|
||||
@@ -170,11 +172,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
void DidFailLoad(content::RenderFrameHost* render_frame_host,
|
||||
const GURL& validated_url,
|
||||
int error_code,
|
||||
const base::string16& error_description) override;
|
||||
const base::string16& error_description,
|
||||
bool was_ignored_by_handler) override;
|
||||
void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host,
|
||||
const GURL& validated_url,
|
||||
int error_code,
|
||||
const base::string16& error_description) override;
|
||||
const base::string16& error_description,
|
||||
bool was_ignored_by_handler) override;
|
||||
void DidStartLoading() override;
|
||||
void DidStopLoading() override;
|
||||
void DidGetResourceResponseStart(
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/web_contents_preferences.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/base/filename_util.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
using atom::WebContentsPreferences;
|
||||
|
||||
namespace mate {
|
||||
|
||||
@@ -25,28 +26,6 @@ struct Converter<content::WebContents*> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<atom::WebViewManager::WebViewInfo> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
atom::WebViewManager::WebViewInfo* out) {
|
||||
Dictionary options;
|
||||
if (!ConvertFromV8(isolate, val, &options))
|
||||
return false;
|
||||
|
||||
GURL preload_url;
|
||||
if (!options.Get("preloadUrl", &preload_url))
|
||||
return false;
|
||||
|
||||
if (!preload_url.is_empty() &&
|
||||
!net::FileURLToFilePath(preload_url, &(out->preload_script)))
|
||||
return false;
|
||||
|
||||
return options.Get("nodeIntegration", &(out->node_integration)) &&
|
||||
options.Get("plugins", &(out->plugins)) &&
|
||||
options.Get("disableWebSecurity", &(out->disable_web_security));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace {
|
||||
@@ -65,14 +44,13 @@ void AddGuest(int guest_instance_id,
|
||||
int element_instance_id,
|
||||
content::WebContents* embedder,
|
||||
content::WebContents* guest_web_contents,
|
||||
atom::WebViewManager::WebViewInfo info) {
|
||||
const base::DictionaryValue& options) {
|
||||
auto manager = GetWebViewManager(embedder);
|
||||
if (manager) {
|
||||
info.guest_instance_id = guest_instance_id;
|
||||
info.embedder = embedder;
|
||||
if (manager)
|
||||
manager->AddGuest(guest_instance_id, element_instance_id, embedder,
|
||||
guest_web_contents, info);
|
||||
}
|
||||
guest_web_contents);
|
||||
|
||||
WebContentsPreferences::FromWebContents(guest_web_contents)->Merge(options);
|
||||
}
|
||||
|
||||
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
@@ -64,9 +65,21 @@ void OnCapturePageDone(
|
||||
|
||||
|
||||
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||
// Use options['web-preferences'] to create WebContents.
|
||||
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
|
||||
options.Get(switches::kWebPreferences, &web_preferences);
|
||||
|
||||
// Be compatible with old options which are now in web_preferences.
|
||||
v8::Local<v8::Value> value;
|
||||
if (options.Get(switches::kNodeIntegration, &value))
|
||||
web_preferences.Set(switches::kNodeIntegration, value);
|
||||
if (options.Get(switches::kPreloadScript, &value))
|
||||
web_preferences.Set(switches::kPreloadScript, value);
|
||||
if (options.Get(switches::kZoomFactor, &value))
|
||||
web_preferences.Set(switches::kZoomFactor, value);
|
||||
|
||||
// Creates the WebContents used by BrowserWindow.
|
||||
mate::Dictionary web_contents_options(isolate, v8::Object::New(isolate));
|
||||
auto web_contents = WebContents::Create(isolate, web_contents_options);
|
||||
auto web_contents = WebContents::Create(isolate, web_preferences);
|
||||
web_contents_.Reset(isolate, web_contents.ToV8());
|
||||
api_web_contents_ = web_contents.get();
|
||||
|
||||
@@ -195,8 +208,8 @@ void Window::OnExecuteWindowsCommand(const std::string& command_name) {
|
||||
mate::Wrappable* Window::New(v8::Isolate* isolate,
|
||||
const mate::Dictionary& options) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError(isolate,
|
||||
"Cannot create BrowserWindow before app is ready");
|
||||
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||
isolate, "Cannot create BrowserWindow before app is ready")));
|
||||
return nullptr;
|
||||
}
|
||||
return new Window(isolate, options);
|
||||
@@ -207,7 +220,10 @@ bool Window::IsDestroyed() const {
|
||||
}
|
||||
|
||||
void Window::Destroy() {
|
||||
window_->CloseContents(nullptr);
|
||||
if (window_) {
|
||||
window_->CloseContents(nullptr);
|
||||
window_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::Close() {
|
||||
|
||||
@@ -78,8 +78,10 @@ class Window : public mate::TrackableObject<Window>,
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
private:
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
// APIs for NativeWindow.
|
||||
void Destroy();
|
||||
void Close();
|
||||
bool IsClosed();
|
||||
void Focus();
|
||||
|
||||
@@ -56,7 +56,7 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(
|
||||
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
|
||||
v8::Local<v8::Object> event = CreateEventObject(isolate);
|
||||
event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||
(void)event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
||||
return event;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ class EventEmitter : public Wrappable {
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message,
|
||||
const Args&... args) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
||||
return EmitWithEvent(name, event, args...);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
bindings = process.atomBinding 'app'
|
||||
sessionBindings = process.atomBinding 'session'
|
||||
|
||||
app = bindings.app
|
||||
app.__proto__ = EventEmitter.prototype
|
||||
|
||||
wrapSession = (session) ->
|
||||
# session is an Event Emitter.
|
||||
session.__proto__ = EventEmitter.prototype
|
||||
|
||||
app.setApplicationMenu = (menu) ->
|
||||
require('menu').setApplicationMenu menu
|
||||
|
||||
@@ -41,5 +46,9 @@ app.getDataPath = -> @getPath 'userData'
|
||||
app.setDataPath = (path) -> @setPath 'userData', path
|
||||
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
|
||||
|
||||
# Session wrapper.
|
||||
sessionBindings._setWrapSession wrapSession
|
||||
process.once 'exit', sessionBindings._clearWrapSession
|
||||
|
||||
# Only one App object pemitted.
|
||||
module.exports = app
|
||||
|
||||
@@ -62,6 +62,12 @@ BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
|
||||
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
|
||||
|
||||
# Be compatible with old API.
|
||||
BrowserWindow::undo = -> @webContents.undo()
|
||||
BrowserWindow::redo = -> @webContents.redo()
|
||||
BrowserWindow::cut = -> @webContents.cut()
|
||||
BrowserWindow::copy = -> @webContents.copy()
|
||||
BrowserWindow::paste = -> @webContents.paste()
|
||||
BrowserWindow::selectAll = -> @webContents.selectAll()
|
||||
BrowserWindow::restart = -> @webContents.reload()
|
||||
BrowserWindow::getUrl = -> @webContents.getUrl()
|
||||
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
|
||||
|
||||
@@ -3,18 +3,30 @@ v8Util = process.atomBinding 'v8_util'
|
||||
|
||||
nextCommandId = 0
|
||||
|
||||
# Maps role to methods of webContents
|
||||
rolesMap =
|
||||
undo: 'undo'
|
||||
redo: 'redo'
|
||||
cut: 'cut'
|
||||
copy: 'copy'
|
||||
paste: 'paste'
|
||||
selectall: 'selectAll'
|
||||
minimize: 'minimize'
|
||||
close: 'close'
|
||||
|
||||
class MenuItem
|
||||
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
|
||||
|
||||
constructor: (options) ->
|
||||
Menu = require 'menu'
|
||||
|
||||
{click, @selector, @type, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
|
||||
{click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
|
||||
|
||||
@type = 'submenu' if not @type? and @submenu?
|
||||
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
|
||||
|
||||
@overrideReadOnlyProperty 'type', 'normal'
|
||||
@overrideReadOnlyProperty 'role'
|
||||
@overrideReadOnlyProperty 'accelerator'
|
||||
@overrideReadOnlyProperty 'icon'
|
||||
@overrideReadOnlyProperty 'submenu'
|
||||
@@ -27,12 +39,14 @@ class MenuItem
|
||||
throw new Error("Unknown menu type #{@type}") if MenuItem.types.indexOf(@type) is -1
|
||||
|
||||
@commandId = ++nextCommandId
|
||||
@click = =>
|
||||
@click = (focusedWindow) =>
|
||||
# Manually flip the checked flags when clicked.
|
||||
@checked = !@checked if @type in ['checkbox', 'radio']
|
||||
|
||||
if typeof click is 'function'
|
||||
click this, BrowserWindow.getFocusedWindow()
|
||||
if @role and rolesMap[@role] and process.platform isnt 'darwin'
|
||||
focusedWindow?[rolesMap[@role]]()
|
||||
else if typeof click is 'function'
|
||||
click this, focusedWindow
|
||||
else if typeof @selector is 'string'
|
||||
Menu.sendActionToFirstResponder @selector
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@ Menu::_init = ->
|
||||
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
||||
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
||||
getIconForCommandId: (commandId) => @commandsMap[commandId]?.icon
|
||||
executeCommand: (commandId) => @commandsMap[commandId]?.click()
|
||||
executeCommand: (commandId) =>
|
||||
@commandsMap[commandId]?.click BrowserWindow.getFocusedWindow()
|
||||
menuWillShow: =>
|
||||
# Make sure radio groups have at least one menu item seleted.
|
||||
for id, group of @groupsMap
|
||||
@@ -115,6 +116,7 @@ Menu::insert = (pos, item) ->
|
||||
|
||||
@setSublabel pos, item.sublabel if item.sublabel?
|
||||
@setIcon pos, item.icon if item.icon?
|
||||
@setRole pos, item.role if item.role?
|
||||
|
||||
# Make menu accessable to items.
|
||||
item.overrideReadOnlyProperty 'menu', this
|
||||
|
||||
@@ -2,63 +2,23 @@ app = require 'app'
|
||||
throw new Error('Can not initialize protocol module before app is ready') unless app.isReady()
|
||||
|
||||
protocol = process.atomBinding('protocol').protocol
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
protocol.__proto__ = EventEmitter.prototype
|
||||
|
||||
GetWrappedCallback = (scheme, callback, notification) ->
|
||||
wrappedCallback = (error) ->
|
||||
if not callback?
|
||||
if error
|
||||
throw error
|
||||
else
|
||||
protocol.emit notification, scheme
|
||||
else
|
||||
callback error, scheme
|
||||
|
||||
# Compatibility with old api.
|
||||
# Warn about removed APIs.
|
||||
logAndThrow = (callback, message) ->
|
||||
console.error message
|
||||
if callback then callback(new Error(message)) else throw new Error(message)
|
||||
protocol.registerProtocol = (scheme, handler, callback) ->
|
||||
protocol._registerProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'registered')
|
||||
|
||||
protocol.unregisterProtocol = (scheme, callback) ->
|
||||
protocol._unregisterProtocol scheme, GetWrappedCallback(scheme, callback, 'unregistered')
|
||||
|
||||
logAndThrow callback,
|
||||
'registerProtocol API has been replaced by the
|
||||
register[File/Http/Buffer/String]Protocol API family, please
|
||||
switch to the new APIs.'
|
||||
protocol.isHandledProtocol = (scheme, callback) ->
|
||||
logAndThrow callback,
|
||||
'isHandledProtocol API has been replaced by isProtocolHandled.'
|
||||
protocol.interceptProtocol = (scheme, handler, callback) ->
|
||||
protocol._interceptProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'intercepted')
|
||||
|
||||
protocol.uninterceptProtocol = (scheme, callback) ->
|
||||
protocol._uninterceptProtocol scheme, GetWrappedCallback(scheme, callback, 'unintercepted')
|
||||
|
||||
protocol.RequestStringJob =
|
||||
class RequestStringJob
|
||||
constructor: ({mimeType, charset, data}) ->
|
||||
if typeof data isnt 'string' and not data instanceof Buffer
|
||||
throw new TypeError('Data should be string or Buffer')
|
||||
|
||||
@mimeType = mimeType ? 'text/plain'
|
||||
@charset = charset ? 'UTF-8'
|
||||
@data = String data
|
||||
|
||||
protocol.RequestBufferJob =
|
||||
class RequestBufferJob
|
||||
constructor: ({mimeType, encoding, data}) ->
|
||||
if not data instanceof Buffer
|
||||
throw new TypeError('Data should be Buffer')
|
||||
|
||||
@mimeType = mimeType ? 'application/octet-stream'
|
||||
@encoding = encoding ? 'utf8'
|
||||
@data = new Buffer(data)
|
||||
|
||||
protocol.RequestFileJob =
|
||||
class RequestFileJob
|
||||
constructor: (@path) ->
|
||||
|
||||
protocol.RequestErrorJob =
|
||||
class RequestErrorJob
|
||||
constructor: (@error) ->
|
||||
|
||||
protocol.RequestHttpJob =
|
||||
class RequestHttpJob
|
||||
constructor: ({@session, @url, @method, @referrer}) ->
|
||||
logAndThrow callback,
|
||||
'interceptProtocol API has been replaced by the
|
||||
intercept[File/Http/Buffer/String]Protocol API family, please
|
||||
switch to the new APIs.'
|
||||
|
||||
module.exports = protocol
|
||||
|
||||
@@ -29,7 +29,9 @@ class IDUserData : public base::SupportsUserData::Data {
|
||||
} // namespace
|
||||
|
||||
TrackableObjectBase::TrackableObjectBase()
|
||||
: weak_map_id_(0), wrapped_(nullptr) {
|
||||
: weak_map_id_(0), wrapped_(nullptr), weak_factory_(this) {
|
||||
RegisterDestructionCallback(
|
||||
base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
TrackableObjectBase::~TrackableObjectBase() {
|
||||
@@ -61,8 +63,9 @@ int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
|
||||
}
|
||||
|
||||
// static
|
||||
void TrackableObjectBase::RegisterDestructionCallback(void (*c)()) {
|
||||
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(base::Bind(c));
|
||||
void TrackableObjectBase::RegisterDestructionCallback(
|
||||
const base::Closure& closure) {
|
||||
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(closure);
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/common/id_weak_map.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
|
||||
namespace base {
|
||||
class SupportsUserData;
|
||||
@@ -28,6 +30,9 @@ class TrackableObjectBase : public mate::EventEmitter {
|
||||
// Wrap TrackableObject into a class that SupportsUserData.
|
||||
void AttachAsUserData(base::SupportsUserData* wrapped);
|
||||
|
||||
// Subclasses should implement this to destroy their native types.
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
protected:
|
||||
~TrackableObjectBase() override;
|
||||
|
||||
@@ -39,12 +44,14 @@ class TrackableObjectBase : public mate::EventEmitter {
|
||||
|
||||
// Register a callback that should be destroyed before JavaScript environment
|
||||
// gets destroyed.
|
||||
static void RegisterDestructionCallback(void (*callback)());
|
||||
static void RegisterDestructionCallback(const base::Closure& closure);
|
||||
|
||||
int32_t weak_map_id_;
|
||||
base::SupportsUserData* wrapped_;
|
||||
|
||||
private:
|
||||
base::WeakPtrFactory<TrackableObjectBase> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase);
|
||||
};
|
||||
|
||||
@@ -85,7 +92,8 @@ class TrackableObject : public TrackableObjectBase {
|
||||
}
|
||||
|
||||
TrackableObject() {
|
||||
RegisterDestructionCallback(&TrackableObject<T>::ReleaseAllWeakReferences);
|
||||
RegisterDestructionCallback(
|
||||
base::Bind(&TrackableObject<T>::ReleaseAllWeakReferences));
|
||||
}
|
||||
|
||||
// Removes this instance from the weak map.
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/common/google_api_key.h"
|
||||
#include "content/public/browser/geolocation_provider.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -24,6 +25,7 @@ const char* kGeolocationProviderUrl =
|
||||
} // namespace
|
||||
|
||||
AtomAccessTokenStore::AtomAccessTokenStore() {
|
||||
content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices();
|
||||
}
|
||||
|
||||
AtomAccessTokenStore::~AtomAccessTokenStore() {
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
#include "atom/browser/atom_speech_recognition_manager_delegate.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/browser/web_contents_preferences.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "chrome/browser/printing/printing_message_filter.h"
|
||||
@@ -36,6 +37,7 @@
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
#include "ppapi/host/ppapi_host.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -52,34 +54,6 @@ bool g_suppress_renderer_process_restart = false;
|
||||
// Custom schemes to be registered to standard.
|
||||
std::string g_custom_schemes = "";
|
||||
|
||||
// Find out the owner of the child process according to |process_id|.
|
||||
enum ProcessOwner {
|
||||
OWNER_NATIVE_WINDOW,
|
||||
OWNER_GUEST_WEB_CONTENTS,
|
||||
OWNER_NONE, // it might be devtools though.
|
||||
};
|
||||
ProcessOwner GetProcessOwner(int process_id,
|
||||
NativeWindow** window,
|
||||
WebViewManager::WebViewInfo* info) {
|
||||
auto web_contents = content::WebContents::FromRenderViewHost(
|
||||
content::RenderViewHost::FromID(process_id, kDefaultRoutingID));
|
||||
if (!web_contents)
|
||||
return OWNER_NONE;
|
||||
|
||||
// First search for NativeWindow.
|
||||
for (auto native_window : *WindowList::GetInstance())
|
||||
if (web_contents == native_window->web_contents()) {
|
||||
*window = native_window;
|
||||
return OWNER_NATIVE_WINDOW;
|
||||
}
|
||||
|
||||
// Then search for guest WebContents.
|
||||
if (WebViewManager::GetInfoForWebContents(web_contents, info))
|
||||
return OWNER_GUEST_WEB_CONTENTS;
|
||||
|
||||
return OWNER_NONE;
|
||||
}
|
||||
|
||||
scoped_refptr<net::X509Certificate> ImportCertFromFile(
|
||||
const base::FilePath& path) {
|
||||
if (path.empty())
|
||||
@@ -155,15 +129,7 @@ void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
|
||||
// Custom preferences of guest page.
|
||||
auto web_contents = content::WebContents::FromRenderViewHost(host);
|
||||
WebViewManager::WebViewInfo info;
|
||||
if (WebViewManager::GetInfoForWebContents(web_contents, &info)) {
|
||||
prefs->web_security_enabled = !info.disable_web_security;
|
||||
return;
|
||||
}
|
||||
|
||||
NativeWindow* window = NativeWindow::FromWebContents(web_contents);
|
||||
if (window)
|
||||
window->OverrideWebkitPrefs(prefs);
|
||||
WebContentsPreferences::OverrideWebkitPrefs(web_contents, prefs);
|
||||
}
|
||||
|
||||
std::string AtomBrowserClient::GetApplicationLocale() {
|
||||
@@ -185,6 +151,13 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
||||
return;
|
||||
|
||||
*new_instance = content::SiteInstance::CreateForURL(browser_context, url);
|
||||
|
||||
// Remember the original renderer process of the pending renderer process.
|
||||
auto current_process = current_instance->GetProcess();
|
||||
auto pending_process = (*new_instance)->GetProcess();
|
||||
pending_processes_[pending_process->GetID()] = current_process->GetID();
|
||||
// Clear the entry in map when process ends.
|
||||
current_process->AddObserver(this);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
@@ -208,23 +181,18 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
}
|
||||
#endif
|
||||
|
||||
NativeWindow* window;
|
||||
WebViewManager::WebViewInfo info;
|
||||
ProcessOwner owner = GetProcessOwner(process_id, &window, &info);
|
||||
// If the process is a pending process, we should use the old one.
|
||||
if (ContainsKey(pending_processes_, process_id))
|
||||
process_id = pending_processes_[process_id];
|
||||
|
||||
if (owner == OWNER_NATIVE_WINDOW) {
|
||||
window->AppendExtraCommandLineSwitches(command_line);
|
||||
} else if (owner == OWNER_GUEST_WEB_CONTENTS) {
|
||||
command_line->AppendSwitchASCII(
|
||||
switches::kGuestInstanceID, base::IntToString(info.guest_instance_id));
|
||||
command_line->AppendSwitchASCII(
|
||||
switches::kNodeIntegration, info.node_integration ? "true" : "false");
|
||||
if (info.plugins)
|
||||
command_line->AppendSwitch(switches::kEnablePlugins);
|
||||
if (!info.preload_script.empty())
|
||||
command_line->AppendSwitchPath(
|
||||
switches::kPreloadScript, info.preload_script);
|
||||
}
|
||||
// Get the WebContents of the render process.
|
||||
content::WebContents* web_contents = content::WebContents::FromRenderViewHost(
|
||||
content::RenderViewHost::FromID(process_id, kDefaultRoutingID));
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
WebContentsPreferences::AppendExtraCommandLineSwitches(
|
||||
web_contents, command_line);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::DidCreatePpapiPlugin(
|
||||
@@ -264,4 +232,15 @@ brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
|
||||
return new AtomBrowserMainParts;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::RenderProcessHostDestroyed(
|
||||
content::RenderProcessHost* host) {
|
||||
int process_id = host->GetID();
|
||||
for (const auto& entry : pending_processes_) {
|
||||
if (entry.first == process_id || entry.second == process_id) {
|
||||
pending_processes_.erase(entry.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
#ifndef ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "brightray/browser/browser_client.h"
|
||||
#include "content/public/browser/render_process_host_observer.h"
|
||||
|
||||
namespace content {
|
||||
class QuotaPermissionContext;
|
||||
@@ -21,7 +23,8 @@ class SSLCertRequestInfo;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserClient : public brightray::BrowserClient {
|
||||
class AtomBrowserClient : public brightray::BrowserClient,
|
||||
public content::RenderProcessHostObserver {
|
||||
public:
|
||||
AtomBrowserClient();
|
||||
virtual ~AtomBrowserClient();
|
||||
@@ -54,10 +57,17 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
|
||||
|
||||
private:
|
||||
// brightray::BrowserClient:
|
||||
brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) override;
|
||||
|
||||
// content::RenderProcessHostObserver:
|
||||
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
|
||||
|
||||
private:
|
||||
// pending_render_process => current_render_process.
|
||||
std::map<int, int> pending_processes_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
||||
};
|
||||
|
||||
|
||||
@@ -56,8 +56,10 @@ std::string RemoveWhitespace(const std::string& str) {
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomBrowserContext::AtomBrowserContext()
|
||||
: job_factory_(new AtomURLRequestJobFactory) {
|
||||
AtomBrowserContext::AtomBrowserContext(const std::string& partition,
|
||||
bool in_memory)
|
||||
: brightray::BrowserContext(partition, in_memory),
|
||||
job_factory_(new AtomURLRequestJobFactory) {
|
||||
}
|
||||
|
||||
AtomBrowserContext::~AtomBrowserContext() {
|
||||
@@ -85,32 +87,37 @@ net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
|
||||
content::URLRequestInterceptorScopedVector* interceptors) {
|
||||
scoped_ptr<AtomURLRequestJobFactory> job_factory(job_factory_);
|
||||
|
||||
for (content::ProtocolHandlerMap::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
job_factory->SetProtocolHandler(it->first, it->second.release());
|
||||
for (auto& it : *handlers) {
|
||||
job_factory->SetProtocolHandler(it.first,
|
||||
make_scoped_ptr(it.second.release()));
|
||||
}
|
||||
handlers->clear();
|
||||
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kDataScheme, new net::DataProtocolHandler);
|
||||
url::kDataScheme, make_scoped_ptr(new net::DataProtocolHandler));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kFileScheme, new asar::AsarProtocolHandler(
|
||||
url::kFileScheme, make_scoped_ptr(new asar::AsarProtocolHandler(
|
||||
BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kHttpScheme, new HttpProtocolHandler(url::kHttpScheme));
|
||||
url::kHttpScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kHttpScheme)));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kHttpsScheme, new HttpProtocolHandler(url::kHttpsScheme));
|
||||
url::kHttpsScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kHttpsScheme)));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kWsScheme, new HttpProtocolHandler(url::kWsScheme));
|
||||
url::kWsScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kWsScheme)));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kWssScheme, new HttpProtocolHandler(url::kWssScheme));
|
||||
url::kWssScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kWssScheme)));
|
||||
|
||||
auto host_resolver = url_request_context_getter()
|
||||
->GetURLRequestContext()
|
||||
->host_resolver();
|
||||
auto host_resolver =
|
||||
url_request_context_getter()->GetURLRequestContext()->host_resolver();
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kFtpScheme, new net::FtpProtocolHandler(
|
||||
new net::FtpNetworkLayer(host_resolver)));
|
||||
url::kFtpScheme,
|
||||
make_scoped_ptr(new net::FtpProtocolHandler(
|
||||
new net::FtpNetworkLayer(host_resolver))));
|
||||
|
||||
// Set up interceptors in the reverse order.
|
||||
scoped_ptr<net::URLRequestJobFactory> top_job_factory = job_factory.Pass();
|
||||
@@ -145,7 +152,7 @@ AtomBrowserContext::GetDownloadManagerDelegate() {
|
||||
|
||||
content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
|
||||
if (!guest_manager_)
|
||||
guest_manager_.reset(new WebViewManager(this));
|
||||
guest_manager_.reset(new WebViewManager);
|
||||
return guest_manager_.get();
|
||||
}
|
||||
|
||||
@@ -157,3 +164,13 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace brightray {
|
||||
|
||||
// static
|
||||
scoped_refptr<BrowserContext> BrowserContext::Create(
|
||||
const std::string& partition, bool in_memory) {
|
||||
return make_scoped_refptr(new atom::AtomBrowserContext(partition, in_memory));
|
||||
}
|
||||
|
||||
} // namespace brightray
|
||||
|
||||
@@ -17,8 +17,8 @@ class WebViewManager;
|
||||
|
||||
class AtomBrowserContext : public brightray::BrowserContext {
|
||||
public:
|
||||
AtomBrowserContext();
|
||||
virtual ~AtomBrowserContext();
|
||||
AtomBrowserContext(const std::string& partition, bool in_memory);
|
||||
~AtomBrowserContext() override;
|
||||
|
||||
// brightray::URLRequestContextGetter::Delegate:
|
||||
std::string GetUserAgent() override;
|
||||
@@ -41,7 +41,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
scoped_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
|
||||
scoped_ptr<WebViewManager> guest_manager_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_; // Weak reference.
|
||||
// Managed by brightray::BrowserContext.
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
|
||||
};
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/bridge_task_runner.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/browser/node_debugger.h"
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/thread_task_runner_handle.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "v8/include/v8-debug.h"
|
||||
|
||||
@@ -19,8 +23,6 @@
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
|
||||
#endif
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// static
|
||||
@@ -37,8 +39,6 @@ AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
}
|
||||
|
||||
AtomBrowserMainParts::~AtomBrowserMainParts() {
|
||||
for (const auto& callback : destruction_callbacks_)
|
||||
callback.Run();
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -52,10 +52,6 @@ void AtomBrowserMainParts::RegisterDestructionCallback(
|
||||
destruction_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
|
||||
return new AtomBrowserContext();
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
brightray::BrowserMainParts::PostEarlyInitialization();
|
||||
|
||||
@@ -63,15 +59,30 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
SetDPIFromGSettings();
|
||||
#endif
|
||||
|
||||
// The ProxyResolverV8 has setup a complete V8 environment, in order to avoid
|
||||
// conflicts we only initialize our V8 environment after that.
|
||||
js_env_.reset(new JavascriptEnvironment);
|
||||
{
|
||||
// Temporary set the bridge_task_runner_ as current thread's task runner,
|
||||
// so we can fool gin::PerIsolateData to use it as its task runner, instead
|
||||
// of getting current message loop's task runner, which is null for now.
|
||||
bridge_task_runner_ = new BridgeTaskRunner;
|
||||
base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
|
||||
|
||||
// The ProxyResolverV8 has setup a complete V8 environment, in order to
|
||||
// avoid conflicts we only initialize our V8 environment after that.
|
||||
js_env_.reset(new JavascriptEnvironment);
|
||||
}
|
||||
|
||||
node_bindings_->Initialize();
|
||||
|
||||
// Support the "--debug" switch.
|
||||
node_debugger_.reset(new NodeDebugger(js_env_->isolate()));
|
||||
|
||||
// Create the global environment.
|
||||
global_env = node_bindings_->CreateEnvironment(js_env_->context());
|
||||
|
||||
// Make sure node can get correct environment when debugging.
|
||||
if (node_debugger_->IsRunning())
|
||||
global_env->AssignToContext(v8::Debug::GetDebugContext());
|
||||
|
||||
// Add atom-shell extended APIs.
|
||||
atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object());
|
||||
|
||||
@@ -105,4 +116,14 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostMainMessageLoopRun() {
|
||||
brightray::BrowserMainParts::PostMainMessageLoopRun();
|
||||
|
||||
// Make sure destruction callbacks are called before message loop is
|
||||
// destroyed, otherwise some objects that need to be deleted on IO thread
|
||||
// won't be freed.
|
||||
for (const auto& callback : destruction_callbacks_)
|
||||
callback.Run();
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "brightray/browser/browser_main_parts.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
|
||||
class BrowserProcess;
|
||||
|
||||
@@ -19,6 +21,8 @@ class AtomBindings;
|
||||
class Browser;
|
||||
class JavascriptEnvironment;
|
||||
class NodeBindings;
|
||||
class NodeDebugger;
|
||||
class BridgeTaskRunner;
|
||||
|
||||
class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
public:
|
||||
@@ -34,12 +38,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
Browser* browser() { return browser_.get(); }
|
||||
|
||||
protected:
|
||||
// Implementations of brightray::BrowserMainParts.
|
||||
brightray::BrowserContext* CreateBrowserContext() override;
|
||||
|
||||
// Implementations of content::BrowserMainParts.
|
||||
// content::BrowserMainParts:
|
||||
void PostEarlyInitialization() override;
|
||||
void PreMainMessageLoopRun() override;
|
||||
void PostMainMessageLoopRun() override;
|
||||
#if defined(OS_MACOSX)
|
||||
void PreMainMessageLoopStart() override;
|
||||
void PostDestroyThreads() override;
|
||||
@@ -53,10 +55,15 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
// A fake BrowserProcess object that used to feed the source code from chrome.
|
||||
scoped_ptr<BrowserProcess> fake_browser_process_;
|
||||
|
||||
// The gin::PerIsolateData requires a task runner to create, so we feed it
|
||||
// with a task runner that will post all work to main loop.
|
||||
scoped_refptr<BridgeTaskRunner> bridge_task_runner_;
|
||||
|
||||
scoped_ptr<Browser> browser_;
|
||||
scoped_ptr<JavascriptEnvironment> js_env_;
|
||||
scoped_ptr<NodeBindings> node_bindings_;
|
||||
scoped_ptr<AtomBindings> atom_bindings_;
|
||||
scoped_ptr<NodeDebugger> node_debugger_;
|
||||
|
||||
base::Timer gc_timer_;
|
||||
|
||||
|
||||
42
atom/browser/bridge_task_runner.cc
Normal file
42
atom/browser/bridge_task_runner.cc
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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/browser/bridge_task_runner.h"
|
||||
|
||||
#include "base/message_loop/message_loop.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
bool BridgeTaskRunner::PostDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
|
||||
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
|
||||
}
|
||||
|
||||
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
|
||||
return message_loop->task_runner()->RunsTasksOnCurrentThread();
|
||||
}
|
||||
|
||||
bool BridgeTaskRunner::PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
|
||||
return message_loop->task_runner()->PostNonNestableDelayedTask(
|
||||
from_here, task, delay);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
35
atom/browser/bridge_task_runner.h
Normal file
35
atom/browser/bridge_task_runner.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
|
||||
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
|
||||
|
||||
#include "base/single_thread_task_runner.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Post all tasks to the current message loop's task runner if available,
|
||||
// otherwise fail silently.
|
||||
class BridgeTaskRunner : public base::SingleThreadTaskRunner {
|
||||
public:
|
||||
BridgeTaskRunner() {}
|
||||
~BridgeTaskRunner() override {}
|
||||
|
||||
// base::SingleThreadTaskRunner:
|
||||
bool PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) override;
|
||||
bool RunsTasksOnCurrentThread() const override;
|
||||
bool PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
|
||||
@@ -45,7 +45,8 @@ void Browser::Shutdown() {
|
||||
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
|
||||
|
||||
is_quiting_ = true;
|
||||
base::MessageLoop::current()->Quit();
|
||||
base::MessageLoop::current()->PostTask(
|
||||
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
|
||||
}
|
||||
|
||||
std::string Browser::GetVersion() const {
|
||||
|
||||
@@ -153,7 +153,7 @@ class Browser : public WindowListObserver {
|
||||
void OnWindowAllClosed() override;
|
||||
|
||||
// Observers of the browser.
|
||||
ObserverList<BrowserObserver> observers_;
|
||||
base::ObserverList<BrowserObserver> observers_;
|
||||
|
||||
// Whether "ready" event has been emitted.
|
||||
bool is_ready_;
|
||||
|
||||
@@ -48,6 +48,8 @@ class CommonWebContentsDelegate
|
||||
|
||||
NativeWindow* owner_window() const { return owner_window_.get(); }
|
||||
|
||||
bool is_html_fullscreen() const { return html_fullscreen_; }
|
||||
|
||||
protected:
|
||||
// content::WebContentsDelegate:
|
||||
content::WebContents* OpenURLFromTab(
|
||||
|
||||
@@ -36,238 +36,176 @@ app.once('ready', function() {
|
||||
if (Menu.getApplicationMenu())
|
||||
return;
|
||||
|
||||
var template;
|
||||
var template = [
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'CmdOrCtrl+Z',
|
||||
role: 'undo'
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+CmdOrCtrl+Z',
|
||||
role: 'redo'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'CmdOrCtrl+X',
|
||||
role: 'cut'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'CmdOrCtrl+C',
|
||||
role: 'copy'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'CmdOrCtrl+V',
|
||||
role: 'paste'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'CmdOrCtrl+A',
|
||||
role: 'selectall'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'CmdOrCtrl+R',
|
||||
click: function(item, focusedWindow) {
|
||||
if (focusedWindow)
|
||||
focusedWindow.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Full Screen',
|
||||
accelerator: (function() {
|
||||
if (process.platform == 'darwin')
|
||||
return 'Ctrl+Command+F';
|
||||
else
|
||||
return 'F11';
|
||||
})(),
|
||||
click: function(item, focusedWindow) {
|
||||
if (focusedWindow)
|
||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: (function() {
|
||||
if (process.platform == 'darwin')
|
||||
return 'Alt+Command+I';
|
||||
else
|
||||
return 'Ctrl+Shift+I';
|
||||
})(),
|
||||
click: function(item, focusedWindow) {
|
||||
if (focusedWindow)
|
||||
focusedWindow.toggleDevTools();
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Minimize',
|
||||
accelerator: 'CmdOrCtrl+M',
|
||||
role: 'minimize'
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'CmdOrCtrl+W',
|
||||
role: 'close'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
if (process.platform == 'darwin') {
|
||||
template = [
|
||||
template.unshift({
|
||||
label: 'Electron',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Electron',
|
||||
role: 'about'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Services',
|
||||
role: 'services',
|
||||
submenu: []
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Electron',
|
||||
accelerator: 'Command+H',
|
||||
role: 'hide'
|
||||
},
|
||||
{
|
||||
label: 'Hide Others',
|
||||
accelerator: 'Command+Shift+H',
|
||||
role: 'hideothers:'
|
||||
},
|
||||
{
|
||||
label: 'Show All',
|
||||
role: 'unhide:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() { app.quit(); }
|
||||
},
|
||||
]
|
||||
});
|
||||
template[3].submenu.push(
|
||||
{
|
||||
label: 'Electron',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Electron',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Services',
|
||||
submenu: []
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Electron',
|
||||
accelerator: 'Command+H',
|
||||
selector: 'hide:'
|
||||
},
|
||||
{
|
||||
label: 'Hide Others',
|
||||
accelerator: 'Command+Shift+H',
|
||||
selector: 'hideOtherApplications:'
|
||||
},
|
||||
{
|
||||
label: 'Show All',
|
||||
selector: 'unhideAllApplications:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() { app.quit(); }
|
||||
},
|
||||
]
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'Command+Z',
|
||||
selector: 'undo:'
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+Command+Z',
|
||||
selector: 'redo:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'Command+X',
|
||||
selector: 'cut:'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'Command+C',
|
||||
selector: 'copy:'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'Command+V',
|
||||
selector: 'paste:'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'Command+A',
|
||||
selector: 'selectAll:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'Command+R',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Full Screen',
|
||||
accelerator: 'Ctrl+Command+F',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.toggleDevTools();
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Minimize',
|
||||
accelerator: 'Command+M',
|
||||
selector: 'performMiniaturize:'
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
selector: 'performClose:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Bring All to Front',
|
||||
selector: 'arrangeInFront:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
label: 'Bring All to Front',
|
||||
role: 'front'
|
||||
}
|
||||
];
|
||||
} else {
|
||||
template = [
|
||||
{
|
||||
label: '&File',
|
||||
submenu: [
|
||||
{
|
||||
label: '&Open',
|
||||
accelerator: 'Ctrl+O',
|
||||
},
|
||||
{
|
||||
label: '&Close',
|
||||
accelerator: 'Ctrl+W',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.close();
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '&View',
|
||||
submenu: [
|
||||
{
|
||||
label: '&Reload',
|
||||
accelerator: 'Ctrl+R',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle &Full Screen',
|
||||
accelerator: 'F11',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle &Developer Tools',
|
||||
accelerator: 'Shift+Ctrl+I',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.toggleDevTools();
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
var menu = Menu.buildFromTemplate(template);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/v8_initializer.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -19,7 +20,7 @@ JavascriptEnvironment::JavascriptEnvironment()
|
||||
}
|
||||
|
||||
bool JavascriptEnvironment::Initialize() {
|
||||
gin::IsolateHolder::LoadV8Snapshot();
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
return true;
|
||||
|
||||
@@ -64,14 +64,16 @@ app.once 'ready', ->
|
||||
catch e
|
||||
|
||||
# The chrome-extension: can map a extension URL request to real file path.
|
||||
protocol.registerProtocol 'chrome-extension', (request) ->
|
||||
chromeExtensionHandler = (request, callback) ->
|
||||
parsed = url.parse request.url
|
||||
return unless parsed.hostname and parsed.path?
|
||||
return unless /extension-\d+/.test parsed.hostname
|
||||
return callback() unless parsed.hostname and parsed.path?
|
||||
return callback() unless /extension-\d+/.test parsed.hostname
|
||||
|
||||
directory = getPathForHost parsed.hostname
|
||||
return unless directory?
|
||||
return new protocol.RequestFileJob(path.join(directory, parsed.path))
|
||||
return callback() unless directory?
|
||||
callback path.join(directory, parsed.path)
|
||||
protocol.registerFileProtocol 'chrome-extension', chromeExtensionHandler, (error) ->
|
||||
console.error 'Unable to register chrome-extension protocol' if error
|
||||
|
||||
BrowserWindow::_loadDevToolsExtensions = (extensionInfoArray) ->
|
||||
@devToolsWebContents?.executeJavaScript "DevToolsAPI.addExtensions(#{JSON.stringify(extensionInfoArray)});"
|
||||
|
||||
@@ -30,6 +30,10 @@ guestInstances = {}
|
||||
embedderElementsMap = {}
|
||||
reverseEmbedderElementsMap = {}
|
||||
|
||||
# Moves the last element of array to the first one.
|
||||
moveLastToFirst = (list) ->
|
||||
list.unshift list.pop()
|
||||
|
||||
# Generate guestInstanceId.
|
||||
getNextInstanceId = (webContents) ->
|
||||
++nextInstanceId
|
||||
@@ -39,14 +43,20 @@ createGuest = (embedder, params) ->
|
||||
webViewManager ?= process.atomBinding 'web_view_manager'
|
||||
|
||||
id = getNextInstanceId embedder
|
||||
guest = webContents.create {isGuest: true, embedder}
|
||||
guest = webContents.create {isGuest: true, partition: params.partition, embedder}
|
||||
guestInstances[id] = {guest, embedder}
|
||||
|
||||
# Destroy guest when the embedder is gone or navigated.
|
||||
destroyEvents = ['destroyed', 'crashed', 'did-navigate-to-different-page']
|
||||
destroy = ->
|
||||
destroyGuest embedder, id if guestInstances[id]?
|
||||
embedder.once event, destroy for event in destroyEvents
|
||||
for event in destroyEvents
|
||||
embedder.once event, destroy
|
||||
# Users might also listen to the crashed event, so We must ensure the guest
|
||||
# is destroyed before users' listener gets called. It is done by moving our
|
||||
# listener to the first one in queue.
|
||||
listeners = embedder._events[event]
|
||||
moveLastToFirst listeners if Array.isArray listeners
|
||||
guest.once 'destroyed', ->
|
||||
embedder.removeListener event, destroy for event in destroyEvents
|
||||
|
||||
@@ -105,11 +115,13 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
|
||||
return unless guestInstances[oldGuestInstanceId]?
|
||||
destroyGuest embedder, oldGuestInstanceId
|
||||
|
||||
webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest,
|
||||
nodeIntegration: params.nodeintegration
|
||||
plugins: params.plugins
|
||||
disableWebSecurity: params.disablewebsecurity
|
||||
preloadUrl: params.preload ? ''
|
||||
webPreferences =
|
||||
'guest-instance-id': guestInstanceId
|
||||
'node-integration': params.nodeintegration ? false
|
||||
'plugins': params.plugins
|
||||
'web-security': !params.disablewebsecurity
|
||||
webPreferences['preload-url'] = params.preload if params.preload
|
||||
webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest, webPreferences
|
||||
|
||||
guest.attachParams = params
|
||||
embedderElementsMap[key] = guestInstanceId
|
||||
|
||||
@@ -57,13 +57,19 @@ ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, me
|
||||
if guestContents?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
||||
guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, message, targetOrigin) ->
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) ->
|
||||
embedder = v8Util.getHiddenValue event.sender, 'embedder'
|
||||
if embedder?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
||||
embedder.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin
|
||||
embedder.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, sourceOrigin
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
|
||||
BrowserWindow.fromId(guestId)?.webContents?[method] args...
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_IS_GUEST_WINDOW', (event) ->
|
||||
event.returnValue = v8Util.getHiddenValue(event.sender, 'embedder') isnt undefined
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_GET_GUEST_ID', (event) ->
|
||||
embedder = v8Util.getHiddenValue event.sender, 'embedder'
|
||||
if embedder?
|
||||
guest = BrowserWindow.fromWebContents event.sender
|
||||
if guest?
|
||||
event.returnValue = guest.id
|
||||
return
|
||||
event.returnValue = null
|
||||
|
||||
@@ -92,5 +92,8 @@ app.setAppPath packagePath
|
||||
# Load the chrome extension support.
|
||||
require './chrome-extension'
|
||||
|
||||
# Set main startup script of the app.
|
||||
mainStartupScript = packageJson.main or 'index.js'
|
||||
|
||||
# Finally load app's main.js and transfer control to C++.
|
||||
Module._load path.join(packagePath, packageJson.main), Module, true
|
||||
Module._load path.join(packagePath, mainStartupScript), Module, true
|
||||
|
||||
@@ -1,82 +1,65 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
|
||||
# Class to reference all objects.
|
||||
class ObjectsStore
|
||||
@stores = {}
|
||||
|
||||
constructor: ->
|
||||
@nextId = 0
|
||||
@objects = []
|
||||
|
||||
getNextId: ->
|
||||
++@nextId
|
||||
|
||||
add: (obj) ->
|
||||
id = @getNextId()
|
||||
@objects[id] = obj
|
||||
id
|
||||
|
||||
has: (id) ->
|
||||
@objects[id]?
|
||||
|
||||
remove: (id) ->
|
||||
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
|
||||
delete @objects[id]
|
||||
|
||||
get: (id) ->
|
||||
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
|
||||
@objects[id]
|
||||
|
||||
@forRenderView: (key) ->
|
||||
@stores[key] = new ObjectsStore unless @stores[key]?
|
||||
@stores[key]
|
||||
|
||||
@releaseForRenderView: (key) ->
|
||||
delete @stores[key]
|
||||
|
||||
class ObjectsRegistry extends EventEmitter
|
||||
constructor: ->
|
||||
@setMaxListeners Number.MAX_VALUE
|
||||
@nextId = 0
|
||||
|
||||
# Objects in weak map will be not referenced (so we won't leak memory), and
|
||||
# every object created in browser will have a unique id in weak map.
|
||||
@objectsWeakMap = new IDWeakMap
|
||||
@objectsWeakMap.add = (obj) ->
|
||||
id = IDWeakMap::add.call this, obj
|
||||
v8Util.setHiddenValue obj, 'atomId', id
|
||||
id
|
||||
# Stores all objects by ref-counting.
|
||||
# (id) => {object, count}
|
||||
@storage = {}
|
||||
|
||||
# Stores the IDs of objects referenced by WebContents.
|
||||
# (webContentsId) => {(id) => (count)}
|
||||
@owners = {}
|
||||
|
||||
# Register a new object, the object would be kept referenced until you release
|
||||
# it explicitly.
|
||||
add: (key, obj) ->
|
||||
# Some native objects may already been added to objectsWeakMap, be care not
|
||||
# to add it twice.
|
||||
@objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
|
||||
id = v8Util.getHiddenValue obj, 'atomId'
|
||||
add: (webContentsId, obj) ->
|
||||
id = @saveToStorage obj
|
||||
# Remember the owner.
|
||||
@owners[webContentsId] ?= {}
|
||||
@owners[webContentsId][id] ?= 0
|
||||
@owners[webContentsId][id]++
|
||||
# Returns object's id
|
||||
id
|
||||
|
||||
# Store and reference the object, then return the storeId which points to
|
||||
# where the object is stored. The caller can later dereference the object
|
||||
# with the storeId.
|
||||
# We use a difference key because the same object can be referenced for
|
||||
# multiple times by the same renderer view.
|
||||
store = ObjectsStore.forRenderView key
|
||||
storeId = store.add obj
|
||||
|
||||
[id, storeId]
|
||||
|
||||
# Get an object according to its id.
|
||||
# Get an object according to its ID.
|
||||
get: (id) ->
|
||||
@objectsWeakMap.get id
|
||||
@storage[id]?.object
|
||||
|
||||
# Remove an object according to its storeId.
|
||||
remove: (key, storeId) ->
|
||||
ObjectsStore.forRenderView(key).remove storeId
|
||||
# Dereference an object according to its ID.
|
||||
remove: (webContentsId, id) ->
|
||||
@dereference id, 1
|
||||
# Also reduce the count in owner.
|
||||
pointer = @owners[webContentsId]
|
||||
--pointer[id]
|
||||
delete pointer[id] if pointer[id] is 0
|
||||
|
||||
# Clear all references to objects from renderer view.
|
||||
clear: (key) ->
|
||||
@emit "clear-#{key}"
|
||||
ObjectsStore.releaseForRenderView key
|
||||
# Clear all references to objects refrenced by the WebContents.
|
||||
clear: (webContentsId) ->
|
||||
@emit "clear-#{webContentsId}"
|
||||
return unless @owners[webContentsId]?
|
||||
@dereference id, count for id, count of @owners[webContentsId]
|
||||
delete @owners[webContentsId]
|
||||
|
||||
# Private: Saves the object into storage and assigns an ID for it.
|
||||
saveToStorage: (object) ->
|
||||
id = v8Util.getHiddenValue object, 'atomId'
|
||||
unless id
|
||||
id = ++@nextId
|
||||
@storage[id] = {count: 0, object}
|
||||
v8Util.setHiddenValue object, 'atomId', id
|
||||
++@storage[id].count
|
||||
id
|
||||
|
||||
# Private: Dereference the object from store.
|
||||
dereference: (id, count) ->
|
||||
pointer = @storage[id]
|
||||
pointer.count -= count
|
||||
if pointer.count is 0
|
||||
v8Util.deleteHiddenValue pointer.object, 'atomId'
|
||||
delete @storage[id]
|
||||
|
||||
module.exports = new ObjectsRegistry
|
||||
|
||||
@@ -4,7 +4,7 @@ objectsRegistry = require './objects-registry.js'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
|
||||
# Convert a real value into meta data.
|
||||
valueToMeta = (sender, value) ->
|
||||
valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||
meta = type: typeof value
|
||||
|
||||
meta.type = 'buffer' if Buffer.isBuffer value
|
||||
@@ -12,6 +12,10 @@ valueToMeta = (sender, value) ->
|
||||
meta.type = 'array' if Array.isArray value
|
||||
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
|
||||
|
||||
# Treat simple objects as value.
|
||||
if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple'
|
||||
meta.type = 'value'
|
||||
|
||||
# Treat the arguments object as array.
|
||||
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
|
||||
|
||||
@@ -24,7 +28,7 @@ valueToMeta = (sender, value) ->
|
||||
# Reference the original value if it's an object, because when it's
|
||||
# passed to renderer we would assume the renderer keeps a reference of
|
||||
# it.
|
||||
[meta.id, meta.storeId] = objectsRegistry.add sender.getId(), value
|
||||
meta.id = objectsRegistry.add sender.getId(), value
|
||||
|
||||
meta.members = []
|
||||
meta.members.push {name: prop, type: typeof field} for prop, field of value
|
||||
@@ -80,11 +84,11 @@ unwrapArgs = (sender, args) ->
|
||||
callFunction = (event, func, caller, args) ->
|
||||
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
|
||||
args.push (ret) ->
|
||||
event.returnValue = valueToMeta event.sender, ret
|
||||
event.returnValue = valueToMeta event.sender, ret, true
|
||||
func.apply caller, args
|
||||
else
|
||||
ret = func.apply caller, args
|
||||
event.returnValue = valueToMeta event.sender, ret
|
||||
event.returnValue = valueToMeta event.sender, ret, true
|
||||
|
||||
# Send by BrowserWindow when its render view is deleted.
|
||||
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) ->
|
||||
@@ -170,8 +174,8 @@ ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, storeId) ->
|
||||
objectsRegistry.remove event.sender.getId(), storeId
|
||||
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) ->
|
||||
objectsRegistry.remove event.sender.getId(), id
|
||||
|
||||
ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) ->
|
||||
try
|
||||
|
||||
@@ -15,12 +15,10 @@
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/json/json_writer.h"
|
||||
#include "base/prefs/pref_service.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
@@ -31,8 +29,6 @@
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/common/renderer_preferences.h"
|
||||
#include "content/public/common/web_preferences.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
@@ -43,10 +39,6 @@
|
||||
#include "ui/gfx/screen.h"
|
||||
#include "ui/gl/gpu_switching_manager.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/switches.h"
|
||||
#endif
|
||||
|
||||
using content::NavigationEntry;
|
||||
using content::RenderWidgetHostView;
|
||||
using content::RenderWidgetHost;
|
||||
@@ -57,17 +49,6 @@ namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Array of available web runtime features.
|
||||
const char* kWebRuntimeFeatures[] = {
|
||||
switches::kExperimentalFeatures,
|
||||
switches::kExperimentalCanvasFeatures,
|
||||
switches::kSubpixelFontScaling,
|
||||
switches::kOverlayScrollbars,
|
||||
switches::kOverlayFullscreenVideo,
|
||||
switches::kSharedWorker,
|
||||
switches::kPageVisibility,
|
||||
};
|
||||
|
||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||
// responsible for deleting the returned SkRegion instance.
|
||||
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
|
||||
@@ -94,9 +75,7 @@ NativeWindow::NativeWindow(
|
||||
transparent_(false),
|
||||
enable_larger_than_screen_(false),
|
||||
is_closed_(false),
|
||||
node_integration_(true),
|
||||
has_dialog_attached_(false),
|
||||
zoom_factor_(1.0),
|
||||
aspect_ratio_(0.0),
|
||||
inspectable_web_contents_(inspectable_web_contents),
|
||||
weak_factory_(this) {
|
||||
@@ -105,7 +84,6 @@ NativeWindow::NativeWindow(
|
||||
options.Get(switches::kFrame, &has_frame_);
|
||||
options.Get(switches::kTransparent, &transparent_);
|
||||
options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_);
|
||||
options.Get(switches::kNodeIntegration, &node_integration_);
|
||||
|
||||
// Tell the content module to initialize renderer widget with transparent
|
||||
// mode.
|
||||
@@ -114,25 +92,6 @@ NativeWindow::NativeWindow(
|
||||
// Read icon before window is created.
|
||||
options.Get(switches::kIcon, &icon_);
|
||||
|
||||
// The "preload" option must be absolute path.
|
||||
if (options.Get(switches::kPreloadScript, &preload_script_) &&
|
||||
!preload_script_.IsAbsolute()) {
|
||||
LOG(ERROR) << "Path of \"preload\" script must be absolute.";
|
||||
preload_script_.clear();
|
||||
}
|
||||
|
||||
// Be compatible with old API of "node-integration" option.
|
||||
std::string old_string_token;
|
||||
if (options.Get(switches::kNodeIntegration, &old_string_token) &&
|
||||
old_string_token != "disable")
|
||||
node_integration_ = true;
|
||||
|
||||
// Read the web preferences.
|
||||
options.Get(switches::kWebPreferences, &web_preferences_);
|
||||
|
||||
// Read the zoom factor before any navigation.
|
||||
options.Get(switches::kZoomFactor, &zoom_factor_);
|
||||
|
||||
WindowList::AddWindow(this);
|
||||
}
|
||||
|
||||
@@ -381,81 +340,6 @@ void NativeWindow::RendererResponsive(content::WebContents* source) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
|
||||
}
|
||||
|
||||
void NativeWindow::AppendExtraCommandLineSwitches(
|
||||
base::CommandLine* command_line) {
|
||||
// Append --node-integration to renderer process.
|
||||
command_line->AppendSwitchASCII(switches::kNodeIntegration,
|
||||
node_integration_ ? "true" : "false");
|
||||
|
||||
// Append --preload.
|
||||
if (!preload_script_.empty())
|
||||
command_line->AppendSwitchPath(switches::kPreloadScript, preload_script_);
|
||||
|
||||
// Append --zoom-factor.
|
||||
if (zoom_factor_ != 1.0)
|
||||
command_line->AppendSwitchASCII(switches::kZoomFactor,
|
||||
base::DoubleToString(zoom_factor_));
|
||||
|
||||
if (web_preferences_.IsEmpty())
|
||||
return;
|
||||
|
||||
bool b;
|
||||
#if defined(OS_WIN)
|
||||
// Check if DirectWrite is disabled.
|
||||
if (web_preferences_.Get(switches::kDirectWrite, &b) && !b)
|
||||
command_line->AppendSwitch(::switches::kDisableDirectWrite);
|
||||
#endif
|
||||
|
||||
// Check if plugins are enabled.
|
||||
if (web_preferences_.Get("plugins", &b) && b)
|
||||
command_line->AppendSwitch(switches::kEnablePlugins);
|
||||
|
||||
// This set of options are not availabe in WebPreferences, so we have to pass
|
||||
// them via command line and enable them in renderer procss.
|
||||
for (size_t i = 0; i < arraysize(kWebRuntimeFeatures); ++i) {
|
||||
const char* feature = kWebRuntimeFeatures[i];
|
||||
if (web_preferences_.Get(feature, &b))
|
||||
command_line->AppendSwitchASCII(feature, b ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
|
||||
if (web_preferences_.IsEmpty())
|
||||
return;
|
||||
|
||||
bool b;
|
||||
std::vector<base::FilePath> list;
|
||||
if (web_preferences_.Get("javascript", &b))
|
||||
prefs->javascript_enabled = b;
|
||||
if (web_preferences_.Get("images", &b))
|
||||
prefs->images_enabled = b;
|
||||
if (web_preferences_.Get("java", &b))
|
||||
prefs->java_enabled = b;
|
||||
if (web_preferences_.Get("text-areas-are-resizable", &b))
|
||||
prefs->text_areas_are_resizable = b;
|
||||
if (web_preferences_.Get("webgl", &b))
|
||||
prefs->experimental_webgl_enabled = b;
|
||||
if (web_preferences_.Get("webaudio", &b))
|
||||
prefs->webaudio_enabled = b;
|
||||
if (web_preferences_.Get("web-security", &b)) {
|
||||
prefs->web_security_enabled = b;
|
||||
prefs->allow_displaying_insecure_content = !b;
|
||||
prefs->allow_running_insecure_content = !b;
|
||||
}
|
||||
if (web_preferences_.Get("allow-displaying-insecure-content", &b))
|
||||
prefs->allow_displaying_insecure_content = b;
|
||||
if (web_preferences_.Get("allow-running-insecure-content", &b))
|
||||
prefs->allow_running_insecure_content = b;
|
||||
if (web_preferences_.Get("extra-plugin-dirs", &list)) {
|
||||
if (content::PluginService::GetInstance()->NPAPIPluginsSupported()) {
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
content::PluginService::GetInstance()->AddExtraPluginDir(list[i]);
|
||||
} else {
|
||||
LOG(WARNING) << "NPAPI plugins not supported on this platform";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowClosed() {
|
||||
if (is_closed_)
|
||||
return;
|
||||
|
||||
@@ -19,23 +19,17 @@
|
||||
#include "content/public/browser/readback_types.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "native_mate/persistent_dictionary.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
class SkRegion;
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
namespace brightray {
|
||||
class InspectableWebContents;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
struct NativeWebKeyboardEvent;
|
||||
struct WebPreferences;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
@@ -189,10 +183,6 @@ class NativeWindow : public content::WebContentsObserver,
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {}
|
||||
|
||||
// Called when renderer process is going to be started.
|
||||
void AppendExtraCommandLineSwitches(base::CommandLine* command_line);
|
||||
void OverrideWebkitPrefs(content::WebPreferences* prefs);
|
||||
|
||||
// Public API used by platform-dependent delegates and observers to send UI
|
||||
// related notifications.
|
||||
void NotifyWindowClosed();
|
||||
@@ -282,9 +272,6 @@ class NativeWindow : public content::WebContentsObserver,
|
||||
// The windows has been closed.
|
||||
bool is_closed_;
|
||||
|
||||
// Whether node integration is enabled.
|
||||
bool node_integration_;
|
||||
|
||||
// There is a dialog that has been attached to window.
|
||||
bool has_dialog_attached_;
|
||||
|
||||
@@ -292,15 +279,6 @@ class NativeWindow : public content::WebContentsObserver,
|
||||
// it should be cancelled when we can prove that the window is responsive.
|
||||
base::CancelableClosure window_unresposive_closure_;
|
||||
|
||||
// Web preferences.
|
||||
mate::PersistentDictionary web_preferences_;
|
||||
|
||||
// The script to load before page's JavaScript starts to run.
|
||||
base::FilePath preload_script_;
|
||||
|
||||
// Page's default zoom factor.
|
||||
double zoom_factor_;
|
||||
|
||||
// Used to maintain the aspect ratio of a view which is inside of the
|
||||
// content view.
|
||||
double aspect_ratio_;
|
||||
@@ -310,7 +288,7 @@ class NativeWindow : public content::WebContentsObserver,
|
||||
brightray::InspectableWebContents* inspectable_web_contents_;
|
||||
|
||||
// Observers of this window.
|
||||
ObserverList<NativeWindowObserver> observers_;
|
||||
base::ObserverList<NativeWindowObserver> observers_;
|
||||
|
||||
base::WeakPtrFactory<NativeWindow> weak_factory_;
|
||||
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/net/adapter_request_job.h"
|
||||
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "atom/browser/net/url_request_buffer_job.h"
|
||||
#include "atom/browser/net/url_request_fetch_job.h"
|
||||
#include "atom/browser/net/url_request_string_job.h"
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
#include "atom/common/asar/asar_util.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/url_request/url_request_error_job.h"
|
||||
#include "net/url_request/url_request_file_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: URLRequestJob(request, network_delegate),
|
||||
protocol_handler_(protocol_handler),
|
||||
weak_factory_(this) {
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Start() {
|
||||
DCHECK(!real_job_.get());
|
||||
GetJobType();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Kill() {
|
||||
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_.get());
|
||||
// Read post-filtered data if available.
|
||||
if (real_job_->HasFilter())
|
||||
return real_job_->Read(buf, buf_size, bytes_read);
|
||||
else
|
||||
return real_job_->ReadRawData(buf, buf_size, bytes_read);
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->IsRedirectResponse(location, http_status_code);
|
||||
}
|
||||
|
||||
net::Filter* AdapterRequestJob::SetupFilter() const {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->SetupFilter();
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::GetMimeType(std::string* mime_type) const {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->GetMimeType(mime_type);
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::GetCharset(std::string* charset) {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->GetCharset(charset);
|
||||
}
|
||||
|
||||
void AdapterRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
real_job_->GetResponseInfo(info);
|
||||
}
|
||||
|
||||
int AdapterRequestJob::GetResponseCode() const {
|
||||
return real_job_->GetResponseCode();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const {
|
||||
real_job_->GetLoadTimingInfo(load_timing_info);
|
||||
}
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateErrorJobAndStart(int error_code) {
|
||||
real_job_ = new net::URLRequestErrorJob(
|
||||
request(), network_delegate(), error_code);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateStringJobAndStart(const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data) {
|
||||
real_job_ = new URLRequestStringJob(
|
||||
request(), network_delegate(), mime_type, charset, data);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateBufferJobAndStart(
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data) {
|
||||
real_job_ = new URLRequestBufferJob(
|
||||
request(), network_delegate(), mime_type, charset, data);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
|
||||
real_job_ = asar::CreateJobFromPath(
|
||||
path,
|
||||
request(),
|
||||
network_delegate(),
|
||||
content::BrowserThread::GetBlockingPool()->
|
||||
GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateHttpJobAndStart(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer) {
|
||||
if (!url.is_valid()) {
|
||||
CreateErrorJobAndStart(net::ERR_INVALID_URL);
|
||||
return;
|
||||
}
|
||||
|
||||
real_job_ = new URLRequestFetchJob(request_context_getter, request(),
|
||||
network_delegate(), url, method, referrer);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
|
||||
real_job_ = protocol_handler_->MaybeCreateJob(request(),
|
||||
network_delegate());
|
||||
if (!real_job_.get()) {
|
||||
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
|
||||
} else {
|
||||
// Copy headers from original request.
|
||||
real_job_->SetExtraRequestHeaders(request()->extra_request_headers());
|
||||
real_job_->Start();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||
#define ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
// Ask JS which type of job it wants, and then delegate corresponding methods.
|
||||
class AdapterRequestJob : public net::URLRequestJob {
|
||||
public:
|
||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||
|
||||
AdapterRequestJob(ProtocolHandler* protocol_handler,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate);
|
||||
|
||||
public:
|
||||
// net::URLRequestJob:
|
||||
void Start() override;
|
||||
void Kill() override;
|
||||
bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int *bytes_read) override;
|
||||
bool IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) override;
|
||||
net::Filter* SetupFilter() const override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
bool GetCharset(std::string* charset) override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
int GetResponseCode() const override;
|
||||
void GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const override;
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
|
||||
|
||||
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
|
||||
|
||||
// Override this function to determine which job should be started.
|
||||
virtual void GetJobType() = 0;
|
||||
|
||||
void CreateErrorJobAndStart(int error_code);
|
||||
void CreateStringJobAndStart(const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data);
|
||||
void CreateBufferJobAndStart(const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data);
|
||||
void CreateFileJobAndStart(const base::FilePath& path);
|
||||
void CreateHttpJobAndStart(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
void CreateJobFromProtocolHandlerAndStart();
|
||||
|
||||
private:
|
||||
// The delegated request job.
|
||||
scoped_refptr<net::URLRequestJob> real_job_;
|
||||
|
||||
// Default protocol handler.
|
||||
ProtocolHandler* protocol_handler_;
|
||||
|
||||
base::WeakPtrFactory<AdapterRequestJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AdapterRequestJob);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||
@@ -5,45 +5,11 @@
|
||||
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
||||
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
#include "atom/common/asar/archive.h"
|
||||
#include "atom/common/asar/asar_util.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/url_request/url_request_error_job.h"
|
||||
#include "net/url_request/url_request_file_job.h"
|
||||
|
||||
namespace asar {
|
||||
|
||||
// static
|
||||
net::URLRequestJob* CreateJobFromPath(
|
||||
const base::FilePath& full_path,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner) {
|
||||
// Create asar:// job when the path contains "xxx.asar/", otherwise treat the
|
||||
// URL request as file://.
|
||||
base::FilePath asar_path, relative_path;
|
||||
if (!GetAsarArchivePath(full_path, &asar_path, &relative_path))
|
||||
return new net::URLRequestFileJob(request, network_delegate, full_path,
|
||||
file_task_runner);
|
||||
|
||||
std::shared_ptr<Archive> archive = GetOrCreateAsarArchive(asar_path);
|
||||
Archive::FileInfo file_info;
|
||||
if (!archive || !archive->GetFileInfo(relative_path, &file_info))
|
||||
return new net::URLRequestErrorJob(request, network_delegate,
|
||||
net::ERR_FILE_NOT_FOUND);
|
||||
|
||||
if (file_info.unpacked) {
|
||||
base::FilePath real_path;
|
||||
archive->CopyFileOut(relative_path, &real_path);
|
||||
return new net::URLRequestFileJob(request, network_delegate, real_path,
|
||||
file_task_runner);
|
||||
}
|
||||
|
||||
return new URLRequestAsarJob(request, network_delegate, archive,
|
||||
relative_path, file_info, file_task_runner);
|
||||
}
|
||||
|
||||
AsarProtocolHandler::AsarProtocolHandler(
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner)
|
||||
: file_task_runner_(file_task_runner) {}
|
||||
@@ -56,8 +22,9 @@ net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob(
|
||||
net::NetworkDelegate* network_delegate) const {
|
||||
base::FilePath full_path;
|
||||
net::FileURLToFilePath(request->url(), &full_path);
|
||||
return CreateJobFromPath(full_path, request, network_delegate,
|
||||
file_task_runner_);
|
||||
URLRequestAsarJob* job = new URLRequestAsarJob(request, network_delegate);
|
||||
job->Initialize(file_task_runner_, full_path);
|
||||
return job;
|
||||
}
|
||||
|
||||
bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {
|
||||
|
||||
@@ -5,48 +5,128 @@
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/task_runner.h"
|
||||
#include "atom/common/asar/archive.h"
|
||||
#include "atom/common/asar/asar_util.h"
|
||||
#include "net/base/file_stream.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/filter/filter.h"
|
||||
#include "net/http/http_util.h"
|
||||
#include "net/url_request/url_request_status.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/shortcut.h"
|
||||
#endif
|
||||
|
||||
namespace asar {
|
||||
|
||||
URLRequestAsarJob::FileMetaInfo::FileMetaInfo()
|
||||
: file_size(0),
|
||||
mime_type_result(false),
|
||||
file_exists(false),
|
||||
is_directory(false) {
|
||||
}
|
||||
|
||||
URLRequestAsarJob::URLRequestAsarJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info,
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner)
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: net::URLRequestJob(request, network_delegate),
|
||||
archive_(archive),
|
||||
file_path_(file_path),
|
||||
file_info_(file_info),
|
||||
stream_(new net::FileStream(file_task_runner)),
|
||||
type_(TYPE_ERROR),
|
||||
remaining_bytes_(0),
|
||||
file_task_runner_(file_task_runner),
|
||||
weak_ptr_factory_(this) {}
|
||||
|
||||
URLRequestAsarJob::~URLRequestAsarJob() {}
|
||||
|
||||
void URLRequestAsarJob::Start() {
|
||||
remaining_bytes_ = static_cast<int64>(file_info_.size);
|
||||
void URLRequestAsarJob::Initialize(
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path) {
|
||||
// Determine whether it is an asar file.
|
||||
base::FilePath asar_path, relative_path;
|
||||
if (!GetAsarArchivePath(file_path, &asar_path, &relative_path)) {
|
||||
InitializeFileJob(file_task_runner, file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = base::File::FLAG_OPEN |
|
||||
base::File::FLAG_READ |
|
||||
base::File::FLAG_ASYNC;
|
||||
int rv = stream_->Open(archive_->path(), flags,
|
||||
base::Bind(&URLRequestAsarJob::DidOpen,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING)
|
||||
DidOpen(rv);
|
||||
std::shared_ptr<Archive> archive = GetOrCreateAsarArchive(asar_path);
|
||||
Archive::FileInfo file_info;
|
||||
if (!archive || !archive->GetFileInfo(relative_path, &file_info)) {
|
||||
type_ = TYPE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_info.unpacked) {
|
||||
base::FilePath real_path;
|
||||
archive->CopyFileOut(relative_path, &real_path);
|
||||
InitializeFileJob(file_task_runner, real_path);
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeAsarJob(file_task_runner, archive, relative_path, file_info);
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::InitializeAsarJob(
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info) {
|
||||
type_ = TYPE_ASAR;
|
||||
file_task_runner_ = file_task_runner;
|
||||
stream_.reset(new net::FileStream(file_task_runner_));
|
||||
archive_ = archive;
|
||||
file_path_ = file_path;
|
||||
file_info_ = file_info;
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::InitializeFileJob(
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path) {
|
||||
type_ = TYPE_FILE;
|
||||
file_task_runner_ = file_task_runner;
|
||||
stream_.reset(new net::FileStream(file_task_runner_));
|
||||
file_path_ = file_path;
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::Start() {
|
||||
if (type_ == TYPE_ASAR) {
|
||||
remaining_bytes_ = static_cast<int64>(file_info_.size);
|
||||
|
||||
int flags = base::File::FLAG_OPEN |
|
||||
base::File::FLAG_READ |
|
||||
base::File::FLAG_ASYNC;
|
||||
int rv = stream_->Open(archive_->path(), flags,
|
||||
base::Bind(&URLRequestAsarJob::DidOpen,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING)
|
||||
DidOpen(rv);
|
||||
} else if (type_ == TYPE_FILE) {
|
||||
FileMetaInfo* meta_info = new FileMetaInfo();
|
||||
file_task_runner_->PostTaskAndReply(
|
||||
FROM_HERE,
|
||||
base::Bind(&URLRequestAsarJob::FetchMetaInfo, file_path_,
|
||||
base::Unretained(meta_info)),
|
||||
base::Bind(&URLRequestAsarJob::DidFetchMetaInfo,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
base::Owned(meta_info)));
|
||||
} else {
|
||||
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_FILE_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::Kill() {
|
||||
stream_.reset();
|
||||
weak_ptr_factory_.InvalidateWeakPtrs();
|
||||
|
||||
URLRequestJob::Kill();
|
||||
}
|
||||
|
||||
@@ -85,8 +165,97 @@ bool URLRequestAsarJob::ReadRawData(net::IOBuffer* dest,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool URLRequestAsarJob::IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) {
|
||||
if (type_ != TYPE_FILE)
|
||||
return false;
|
||||
#if defined(OS_WIN)
|
||||
// Follow a Windows shortcut.
|
||||
// We just resolve .lnk file, ignore others.
|
||||
if (!base::LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
|
||||
return false;
|
||||
|
||||
base::FilePath new_path = file_path_;
|
||||
bool resolved;
|
||||
resolved = base::win::ResolveShortcut(new_path, &new_path, NULL);
|
||||
|
||||
// If shortcut is not resolved succesfully, do not redirect.
|
||||
if (!resolved)
|
||||
return false;
|
||||
|
||||
*location = net::FilePathToFileURL(new_path);
|
||||
*http_status_code = 301;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
net::Filter* URLRequestAsarJob::SetupFilter() const {
|
||||
// Bug 9936 - .svgz files needs to be decompressed.
|
||||
return base::LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
|
||||
? net::Filter::GZipFactory() : NULL;
|
||||
}
|
||||
|
||||
bool URLRequestAsarJob::GetMimeType(std::string* mime_type) const {
|
||||
return net::GetMimeTypeFromFile(file_path_, mime_type);
|
||||
if (type_ == TYPE_ASAR) {
|
||||
return net::GetMimeTypeFromFile(file_path_, mime_type);
|
||||
} else {
|
||||
if (meta_info_.mime_type_result) {
|
||||
*mime_type = meta_info_.mime_type;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::SetExtraRequestHeaders(
|
||||
const net::HttpRequestHeaders& headers) {
|
||||
std::string range_header;
|
||||
if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
|
||||
// We only care about "Range" header here.
|
||||
std::vector<net::HttpByteRange> ranges;
|
||||
if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
|
||||
if (ranges.size() == 1) {
|
||||
byte_range_ = ranges[0];
|
||||
} else {
|
||||
NotifyDone(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::FetchMetaInfo(const base::FilePath& file_path,
|
||||
FileMetaInfo* meta_info) {
|
||||
base::File::Info file_info;
|
||||
meta_info->file_exists = base::GetFileInfo(file_path, &file_info);
|
||||
if (meta_info->file_exists) {
|
||||
meta_info->file_size = file_info.size;
|
||||
meta_info->is_directory = file_info.is_directory;
|
||||
}
|
||||
// On Windows GetMimeTypeFromFile() goes to the registry. Thus it should be
|
||||
// done in WorkerPool.
|
||||
meta_info->mime_type_result =
|
||||
net::GetMimeTypeFromFile(file_path, &meta_info->mime_type);
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::DidFetchMetaInfo(const FileMetaInfo* meta_info) {
|
||||
meta_info_ = *meta_info;
|
||||
if (!meta_info_.file_exists || meta_info_.is_directory) {
|
||||
DidOpen(net::ERR_FILE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = base::File::FLAG_OPEN |
|
||||
base::File::FLAG_READ |
|
||||
base::File::FLAG_ASYNC;
|
||||
int rv = stream_->Open(file_path_, flags,
|
||||
base::Bind(&URLRequestAsarJob::DidOpen,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING)
|
||||
DidOpen(rv);
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::DidOpen(int result) {
|
||||
@@ -95,24 +264,57 @@ void URLRequestAsarJob::DidOpen(int result) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rv = stream_->Seek(base::File::FROM_BEGIN,
|
||||
file_info_.offset,
|
||||
base::Bind(&URLRequestAsarJob::DidSeek,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING) {
|
||||
// stream_->Seek() failed, so pass an intentionally erroneous value
|
||||
// into DidSeek().
|
||||
DidSeek(-1);
|
||||
if (type_ == TYPE_ASAR) {
|
||||
int rv = stream_->Seek(file_info_.offset,
|
||||
base::Bind(&URLRequestAsarJob::DidSeek,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING) {
|
||||
// stream_->Seek() failed, so pass an intentionally erroneous value
|
||||
// into DidSeek().
|
||||
DidSeek(-1);
|
||||
}
|
||||
} else {
|
||||
if (!byte_range_.ComputeBounds(meta_info_.file_size)) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
}
|
||||
|
||||
remaining_bytes_ = byte_range_.last_byte_position() -
|
||||
byte_range_.first_byte_position() + 1;
|
||||
|
||||
if (remaining_bytes_ > 0 && byte_range_.first_byte_position() != 0) {
|
||||
int rv = stream_->Seek(byte_range_.first_byte_position(),
|
||||
base::Bind(&URLRequestAsarJob::DidSeek,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING) {
|
||||
// stream_->Seek() failed, so pass an intentionally erroneous value
|
||||
// into DidSeek().
|
||||
DidSeek(-1);
|
||||
}
|
||||
} else {
|
||||
// We didn't need to call stream_->Seek() at all, so we pass to DidSeek()
|
||||
// the value that would mean seek success. This way we skip the code
|
||||
// handling seek failure.
|
||||
DidSeek(byte_range_.first_byte_position());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::DidSeek(int64 result) {
|
||||
if (result != static_cast<int64>(file_info_.offset)) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
if (type_ == TYPE_ASAR) {
|
||||
if (result != static_cast<int64>(file_info_.offset)) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (result != byte_range_.first_byte_position()) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
set_expected_content_size(remaining_bytes_);
|
||||
NotifyHeadersComplete();
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "atom/common/asar/archive.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/http/http_byte_range.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
|
||||
namespace base {
|
||||
@@ -34,11 +36,20 @@ net::URLRequestJob* CreateJobFromPath(
|
||||
class URLRequestAsarJob : public net::URLRequestJob {
|
||||
public:
|
||||
URLRequestAsarJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info,
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner);
|
||||
net::NetworkDelegate* network_delegate);
|
||||
|
||||
void Initialize(const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path);
|
||||
|
||||
protected:
|
||||
virtual ~URLRequestAsarJob();
|
||||
|
||||
void InitializeAsarJob(const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info);
|
||||
void InitializeFileJob(const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path);
|
||||
|
||||
// net::URLRequestJob:
|
||||
void Start() override;
|
||||
@@ -46,12 +57,39 @@ class URLRequestAsarJob : public net::URLRequestJob {
|
||||
bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int* bytes_read) override;
|
||||
bool IsRedirectResponse(GURL* location, int* http_status_code) override;
|
||||
net::Filter* SetupFilter() const override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
|
||||
protected:
|
||||
virtual ~URLRequestAsarJob();
|
||||
void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
|
||||
|
||||
private:
|
||||
// Meta information about the file. It's used as a member in the
|
||||
// URLRequestFileJob and also passed between threads because disk access is
|
||||
// necessary to obtain it.
|
||||
struct FileMetaInfo {
|
||||
FileMetaInfo();
|
||||
|
||||
// Size of the file.
|
||||
int64 file_size;
|
||||
// Mime type associated with the file.
|
||||
std::string mime_type;
|
||||
// Result returned from GetMimeTypeFromFile(), i.e. flag showing whether
|
||||
// obtaining of the mime type was successful.
|
||||
bool mime_type_result;
|
||||
// Flag showing whether the file exists.
|
||||
bool file_exists;
|
||||
// Flag showing whether the file name actually refers to a directory.
|
||||
bool is_directory;
|
||||
};
|
||||
|
||||
// Fetches file info on a background thread.
|
||||
static void FetchMetaInfo(const base::FilePath& file_path,
|
||||
FileMetaInfo* meta_info);
|
||||
|
||||
// Callback after fetching file info on a background thread.
|
||||
void DidFetchMetaInfo(const FileMetaInfo* meta_info);
|
||||
|
||||
|
||||
// Callback after opening file on a background thread.
|
||||
void DidOpen(int result);
|
||||
|
||||
@@ -62,14 +100,24 @@ class URLRequestAsarJob : public net::URLRequestJob {
|
||||
// Callback after data is asynchronously read from the file into |buf|.
|
||||
void DidRead(scoped_refptr<net::IOBuffer> buf, int result);
|
||||
|
||||
// The type of this job.
|
||||
enum JobType {
|
||||
TYPE_ERROR,
|
||||
TYPE_ASAR,
|
||||
TYPE_FILE,
|
||||
};
|
||||
JobType type_;
|
||||
|
||||
std::shared_ptr<Archive> archive_;
|
||||
base::FilePath file_path_;
|
||||
Archive::FileInfo file_info_;
|
||||
|
||||
scoped_ptr<net::FileStream> stream_;
|
||||
int64 remaining_bytes_;
|
||||
FileMetaInfo meta_info_;
|
||||
scoped_refptr<base::TaskRunner> file_task_runner_;
|
||||
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner_;
|
||||
net::HttpByteRange byte_range_;
|
||||
int64 remaining_bytes_;
|
||||
|
||||
base::WeakPtrFactory<URLRequestAsarJob> weak_ptr_factory_;
|
||||
|
||||
|
||||
@@ -23,10 +23,7 @@ AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
|
||||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::SetProtocolHandler(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
const std::string& scheme, scoped_ptr<ProtocolHandler> protocol_handler) {
|
||||
if (!protocol_handler) {
|
||||
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
|
||||
if (it == protocol_handler_map_.end())
|
||||
@@ -39,21 +36,17 @@ bool AtomURLRequestJobFactory::SetProtocolHandler(
|
||||
|
||||
if (ContainsKey(protocol_handler_map_, scheme))
|
||||
return false;
|
||||
protocol_handler_map_[scheme] = protocol_handler;
|
||||
protocol_handler_map_[scheme] = protocol_handler.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
DCHECK(protocol_handler);
|
||||
|
||||
scoped_ptr<ProtocolHandler> AtomURLRequestJobFactory::ReplaceProtocol(
|
||||
const std::string& scheme, scoped_ptr<ProtocolHandler> protocol_handler) {
|
||||
if (!ContainsKey(protocol_handler_map_, scheme))
|
||||
return nullptr;
|
||||
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
|
||||
protocol_handler_map_[scheme] = protocol_handler;
|
||||
return original_protocol_handler;
|
||||
protocol_handler_map_[scheme] = protocol_handler.release();
|
||||
return make_scoped_ptr(original_protocol_handler);
|
||||
}
|
||||
|
||||
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
|
||||
@@ -25,13 +24,13 @@ class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
|
||||
// Sets the ProtocolHandler for a scheme. Returns true on success, false on
|
||||
// failure (a ProtocolHandler already exists for |scheme|). On success,
|
||||
// URLRequestJobFactory takes ownership of |protocol_handler|.
|
||||
bool SetProtocolHandler(const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler);
|
||||
bool SetProtocolHandler(
|
||||
const std::string& scheme, scoped_ptr<ProtocolHandler> protocol_handler);
|
||||
|
||||
// Intercepts the ProtocolHandler for a scheme. Returns the original protocol
|
||||
// handler on success, otherwise returns NULL.
|
||||
ProtocolHandler* ReplaceProtocol(const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler);
|
||||
scoped_ptr<ProtocolHandler> ReplaceProtocol(
|
||||
const std::string& scheme, scoped_ptr<ProtocolHandler> protocol_handler);
|
||||
|
||||
// Returns the protocol handler registered with scheme.
|
||||
ProtocolHandler* GetProtocolHandler(const std::string& scheme) const;
|
||||
|
||||
131
atom/browser/net/js_asker.cc
Normal file
131
atom/browser/net/js_asker.cc
Normal file
@@ -0,0 +1,131 @@
|
||||
// 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/browser/net/js_asker.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/v8_value_converter.h"
|
||||
#include "native_mate/function_template.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
struct CallbackHolder {
|
||||
ResponseCallback callback;
|
||||
};
|
||||
|
||||
// Cached JavaScript version of |HandlerCallback|.
|
||||
v8::Persistent<v8::FunctionTemplate> g_handler_callback_;
|
||||
|
||||
// The callback which is passed to |handler|.
|
||||
void HandlerCallback(v8::Isolate* isolate,
|
||||
v8::Local<v8::External> external,
|
||||
v8::Local<v8::Object> state,
|
||||
mate::Arguments* args) {
|
||||
// Check if the callback has already been called.
|
||||
v8::Local<v8::String> called_symbol = mate::StringToSymbol(isolate, "called");
|
||||
if (state->Has(called_symbol))
|
||||
return; // no nothing
|
||||
else
|
||||
state->Set(called_symbol, v8::Boolean::New(isolate, true));
|
||||
|
||||
// If there is no argument passed then we failed.
|
||||
scoped_ptr<CallbackHolder> holder(
|
||||
static_cast<CallbackHolder*>(external->Value()));
|
||||
CHECK(holder);
|
||||
v8::Local<v8::Value> value;
|
||||
if (!args->GetNext(&value)) {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(holder->callback, false, nullptr));
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass whatever user passed to the actaul request job.
|
||||
V8ValueConverter converter;
|
||||
v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
|
||||
scoped_ptr<base::Value> options(converter.FromV8Value(value, context));
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(holder->callback, true, base::Passed(&options)));
|
||||
}
|
||||
|
||||
// func.bind(func, arg1, arg2).
|
||||
// NB(zcbenz): Using C++11 version crashes VS.
|
||||
v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Function> func,
|
||||
v8::Local<v8::Value> arg1,
|
||||
v8::Local<v8::Value> arg2) {
|
||||
v8::MaybeLocal<v8::Value> bind = func->Get(mate::StringToV8(isolate, "bind"));
|
||||
CHECK(!bind.IsEmpty());
|
||||
v8::Local<v8::Function> bind_func =
|
||||
v8::Local<v8::Function>::Cast(bind.ToLocalChecked());
|
||||
v8::Local<v8::Value> converted[] = { func, arg1, arg2 };
|
||||
return bind_func->Call(
|
||||
context, func, arraysize(converted), converted).ToLocalChecked();
|
||||
}
|
||||
|
||||
// Generate the callback that will be passed to |handler|.
|
||||
v8::MaybeLocal<v8::Value> GenerateCallback(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context> context,
|
||||
const ResponseCallback& callback) {
|
||||
// The FunctionTemplate is cached.
|
||||
if (g_handler_callback_.IsEmpty())
|
||||
g_handler_callback_.Reset(
|
||||
isolate,
|
||||
mate::CreateFunctionTemplate(isolate, base::Bind(&HandlerCallback)));
|
||||
|
||||
v8::Local<v8::FunctionTemplate> handler_callback =
|
||||
v8::Local<v8::FunctionTemplate>::New(isolate, g_handler_callback_);
|
||||
CallbackHolder* holder = new CallbackHolder;
|
||||
holder->callback = callback;
|
||||
return BindFunctionWith(isolate, context, handler_callback->GetFunction(),
|
||||
v8::External::New(isolate, holder),
|
||||
v8::Object::New(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AskForOptions(v8::Isolate* isolate,
|
||||
const JavaScriptHandler& handler,
|
||||
net::URLRequest* request,
|
||||
const ResponseCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
// We don't convert the callback to C++ directly because creating
|
||||
// FunctionTemplate will cause memory leak since V8 never releases it. So we
|
||||
// have to create the function object in JavaScript to work around it.
|
||||
v8::MaybeLocal<v8::Value> wrapped_callback = GenerateCallback(
|
||||
isolate, context, callback);
|
||||
if (wrapped_callback.IsEmpty()) {
|
||||
callback.Run(false, nullptr);
|
||||
return;
|
||||
}
|
||||
handler.Run(request, wrapped_callback.ToLocalChecked());
|
||||
}
|
||||
|
||||
bool IsErrorOptions(base::Value* value, int* error) {
|
||||
if (value->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(value);
|
||||
if (dict->GetInteger("error", error))
|
||||
return true;
|
||||
} else if (value->IsType(base::Value::TYPE_INTEGER)) {
|
||||
if (value->GetAsInteger(error))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace atom
|
||||
102
atom/browser/net/js_asker.h
Normal file
102
atom/browser/net/js_asker.h
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_JS_ASKER_H_
|
||||
#define ATOM_BROWSER_NET_JS_ASKER_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
using JavaScriptHandler =
|
||||
base::Callback<void(const net::URLRequest*, v8::Local<v8::Value>)>;
|
||||
|
||||
namespace internal {
|
||||
|
||||
using ResponseCallback =
|
||||
base::Callback<void(bool, scoped_ptr<base::Value> options)>;
|
||||
|
||||
// Ask handler for options in UI thread.
|
||||
void AskForOptions(v8::Isolate* isolate,
|
||||
const JavaScriptHandler& handler,
|
||||
net::URLRequest* request,
|
||||
const ResponseCallback& callback);
|
||||
|
||||
// Test whether the |options| means an error.
|
||||
bool IsErrorOptions(base::Value* value, int* error);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template<typename RequestJob>
|
||||
class JsAsker : public RequestJob {
|
||||
public:
|
||||
JsAsker(net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: RequestJob(request, network_delegate), weak_factory_(this) {}
|
||||
|
||||
// Called by |CustomProtocolHandler| to store handler related information.
|
||||
void SetHandlerInfo(
|
||||
v8::Isolate* isolate,
|
||||
net::URLRequestContextGetter* request_context_getter,
|
||||
const JavaScriptHandler& handler) {
|
||||
isolate_ = isolate;
|
||||
request_context_getter_ = request_context_getter;
|
||||
handler_ = handler;
|
||||
}
|
||||
|
||||
// Subclass should do initailze work here.
|
||||
virtual void StartAsync(scoped_ptr<base::Value> options) = 0;
|
||||
|
||||
net::URLRequestContextGetter* request_context_getter() const {
|
||||
return request_context_getter_;
|
||||
}
|
||||
|
||||
private:
|
||||
// RequestJob:
|
||||
void Start() override {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&internal::AskForOptions,
|
||||
isolate_,
|
||||
handler_,
|
||||
RequestJob::request(),
|
||||
base::Bind(&JsAsker::OnResponse,
|
||||
weak_factory_.GetWeakPtr())));
|
||||
}
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override {
|
||||
info->headers = new net::HttpResponseHeaders("");
|
||||
}
|
||||
|
||||
// Called when the JS handler has sent the response, we need to decide whether
|
||||
// to start, or fail the job.
|
||||
void OnResponse(bool success, scoped_ptr<base::Value> value) {
|
||||
int error = net::ERR_NOT_IMPLEMENTED;
|
||||
if (success && value && !internal::IsErrorOptions(value.get(), &error)) {
|
||||
StartAsync(value.Pass());
|
||||
} else {
|
||||
RequestJob::NotifyStartError(
|
||||
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
}
|
||||
}
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
net::URLRequestContextGetter* request_context_getter_;
|
||||
JavaScriptHandler handler_;
|
||||
|
||||
base::WeakPtrFactory<JsAsker> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(JsAsker);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_JS_ASKER_H_
|
||||
37
atom/browser/net/url_request_async_asar_job.cc
Normal file
37
atom/browser/net/url_request_async_asar_job.cc
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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/browser/net/url_request_async_asar_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
UrlRequestAsyncAsarJob::UrlRequestAsyncAsarJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<asar::URLRequestAsarJob>(request, network_delegate) {
|
||||
}
|
||||
|
||||
void UrlRequestAsyncAsarJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
base::FilePath::StringType file_path;
|
||||
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
static_cast<base::DictionaryValue*>(options.get())->GetString(
|
||||
"path", &file_path);
|
||||
} else if (options->IsType(base::Value::TYPE_STRING)) {
|
||||
options->GetAsString(&file_path);
|
||||
}
|
||||
|
||||
if (file_path.empty()) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED));
|
||||
} else {
|
||||
asar::URLRequestAsarJob::Initialize(
|
||||
content::BrowserThread::GetBlockingPool()->
|
||||
GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
|
||||
base::FilePath(file_path));
|
||||
asar::URLRequestAsarJob::Start();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
27
atom/browser/net/url_request_async_asar_job.h
Normal file
27
atom/browser/net/url_request_async_asar_job.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
||||
#define ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
||||
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Like URLRequestAsarJob, but asks the JavaScript handler for file path.
|
||||
class UrlRequestAsyncAsarJob : public JsAsker<asar::URLRequestAsarJob> {
|
||||
public:
|
||||
UrlRequestAsyncAsarJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(UrlRequestAsyncAsarJob);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
||||
@@ -11,15 +11,32 @@
|
||||
namespace atom {
|
||||
|
||||
URLRequestBufferJob::URLRequestBufferJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data)
|
||||
: net::URLRequestSimpleJob(request, network_delegate),
|
||||
mime_type_(mime_type),
|
||||
charset_(charset),
|
||||
buffer_data_(data) {
|
||||
net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<net::URLRequestSimpleJob>(request, network_delegate) {
|
||||
}
|
||||
|
||||
void URLRequestBufferJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
const base::BinaryValue* binary = nullptr;
|
||||
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("mimeType", &mime_type_);
|
||||
dict->GetString("charset", &charset_);
|
||||
dict->GetBinary("data", &binary);
|
||||
} else if (options->IsType(base::Value::TYPE_BINARY)) {
|
||||
options->GetAsBinary(&binary);
|
||||
}
|
||||
|
||||
if (!binary) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED));
|
||||
return;
|
||||
}
|
||||
|
||||
data_ = new base::RefCountedBytes(
|
||||
reinterpret_cast<const unsigned char*>(binary->GetBuffer()),
|
||||
binary->GetSize());
|
||||
net::URLRequestSimpleJob::Start();
|
||||
}
|
||||
|
||||
int URLRequestBufferJob::GetRefCountedData(
|
||||
@@ -29,7 +46,7 @@ int URLRequestBufferJob::GetRefCountedData(
|
||||
const net::CompletionCallback& callback) const {
|
||||
*mime_type = mime_type_;
|
||||
*charset = charset_;
|
||||
*data = buffer_data_;
|
||||
*data = data_;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,19 +7,18 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class URLRequestBufferJob : public net::URLRequestSimpleJob {
|
||||
class URLRequestBufferJob : public JsAsker<net::URLRequestSimpleJob> {
|
||||
public:
|
||||
URLRequestBufferJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data);
|
||||
URLRequestBufferJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
// URLRequestSimpleJob:
|
||||
int GetRefCountedData(std::string* mime_type,
|
||||
@@ -30,7 +29,7 @@ class URLRequestBufferJob : public net::URLRequestSimpleJob {
|
||||
private:
|
||||
std::string mime_type_;
|
||||
std::string charset_;
|
||||
scoped_refptr<base::RefCountedBytes> buffer_data_;
|
||||
scoped_refptr<base::RefCountedBytes> data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestBufferJob);
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace {
|
||||
|
||||
// Convert string to RequestType.
|
||||
net::URLFetcher::RequestType GetRequestType(const std::string& raw) {
|
||||
std::string method = StringToUpperASCII(raw);
|
||||
std::string method = base::StringToUpperASCII(raw);
|
||||
if (method.empty() || method == "GET")
|
||||
return net::URLFetcher::GET;
|
||||
else if (method == "POST")
|
||||
@@ -75,42 +75,65 @@ class ResponsePiper : public net::URLFetcherResponseWriter {
|
||||
} // namespace
|
||||
|
||||
URLRequestFetchJob::URLRequestFetchJob(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer)
|
||||
: net::URLRequestJob(request, network_delegate),
|
||||
net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<net::URLRequestJob>(request, network_delegate),
|
||||
pending_buffer_size_(0) {
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
if (!options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url, method, referrer;
|
||||
base::Value* session = nullptr;
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("url", &url);
|
||||
dict->GetString("method", &method);
|
||||
dict->GetString("referrer", &referrer);
|
||||
dict->Get("session", &session);
|
||||
|
||||
// Check if URL is valid.
|
||||
GURL formated_url(url);
|
||||
if (!formated_url.is_valid()) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_INVALID_URL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use |request|'s method if |method| is not specified.
|
||||
net::URLFetcher::RequestType request_type;
|
||||
if (method.empty())
|
||||
request_type = GetRequestType(request->method());
|
||||
request_type = GetRequestType(request()->method());
|
||||
else
|
||||
request_type = GetRequestType(method);
|
||||
|
||||
fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
|
||||
// Use request context if provided else create one.
|
||||
if (request_context_getter)
|
||||
fetcher_->SetRequestContext(request_context_getter.get());
|
||||
else
|
||||
fetcher_->SetRequestContext(GetRequestContext());
|
||||
|
||||
fetcher_ = net::URLFetcher::Create(formated_url, request_type, this);
|
||||
fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
|
||||
|
||||
// When |session| is set to |null| we use a new request context for fetch job.
|
||||
if (session && session->IsType(base::Value::TYPE_NULL))
|
||||
fetcher_->SetRequestContext(CreateRequestContext());
|
||||
else
|
||||
fetcher_->SetRequestContext(request_context_getter());
|
||||
|
||||
// Use |request|'s referrer if |referrer| is not specified.
|
||||
if (referrer.empty()) {
|
||||
fetcher_->SetReferrer(request->referrer());
|
||||
} else {
|
||||
if (referrer.empty())
|
||||
fetcher_->SetReferrer(request()->referrer());
|
||||
else
|
||||
fetcher_->SetReferrer(referrer);
|
||||
}
|
||||
|
||||
// Use |request|'s headers.
|
||||
fetcher_->SetExtraRequestHeaders(request->extra_request_headers().ToString());
|
||||
fetcher_->SetExtraRequestHeaders(
|
||||
request()->extra_request_headers().ToString());
|
||||
|
||||
fetcher_->Start();
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* URLRequestFetchJob::GetRequestContext() {
|
||||
net::URLRequestContextGetter* URLRequestFetchJob::CreateRequestContext() {
|
||||
if (!url_request_context_getter_.get()) {
|
||||
auto task_runner = base::ThreadTaskRunnerHandle::Get();
|
||||
net::URLRequestContextBuilder builder;
|
||||
@@ -150,12 +173,8 @@ int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer, int num_bytes) {
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::Start() {
|
||||
fetcher_->Start();
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::Kill() {
|
||||
URLRequestJob::Kill();
|
||||
JsAsker<URLRequestJob>::Kill();
|
||||
fetcher_.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_fetcher_delegate.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
@@ -15,22 +16,20 @@ namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
class URLRequestFetchJob : public net::URLRequestJob,
|
||||
class URLRequestFetchJob : public JsAsker<net::URLRequestJob>,
|
||||
public net::URLFetcherDelegate {
|
||||
public:
|
||||
URLRequestFetchJob(scoped_refptr<net::URLRequestContextGetter> context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
URLRequestFetchJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
net::URLRequestContextGetter* GetRequestContext();
|
||||
// Called by response writer.
|
||||
void HeadersCompleted();
|
||||
int DataAvailable(net::IOBuffer* buffer, int num_bytes);
|
||||
|
||||
protected:
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
// net::URLRequestJob:
|
||||
void Start() override;
|
||||
void Kill() override;
|
||||
bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
@@ -43,6 +42,9 @@ class URLRequestFetchJob : public net::URLRequestJob,
|
||||
void OnURLFetchComplete(const net::URLFetcher* source) override;
|
||||
|
||||
private:
|
||||
// Create a independent request context.
|
||||
net::URLRequestContextGetter* CreateRequestContext();
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
|
||||
scoped_ptr<net::URLFetcher> fetcher_;
|
||||
scoped_refptr<net::IOBuffer> pending_buffer_;
|
||||
|
||||
@@ -10,15 +10,22 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
URLRequestStringJob::URLRequestStringJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data)
|
||||
: net::URLRequestSimpleJob(request, network_delegate),
|
||||
mime_type_(mime_type),
|
||||
charset_(charset),
|
||||
data_(data) {
|
||||
URLRequestStringJob::URLRequestStringJob(
|
||||
net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<net::URLRequestSimpleJob>(request, network_delegate) {
|
||||
}
|
||||
|
||||
void URLRequestStringJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("mimeType", &mime_type_);
|
||||
dict->GetString("charset", &charset_);
|
||||
dict->GetString("data", &data_);
|
||||
} else if (options->IsType(base::Value::TYPE_STRING)) {
|
||||
options->GetAsString(&data_);
|
||||
}
|
||||
net::URLRequestSimpleJob::Start();
|
||||
}
|
||||
|
||||
int URLRequestStringJob::GetData(
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
#ifndef ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
||||
#define ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
||||
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class URLRequestStringJob : public net::URLRequestSimpleJob {
|
||||
class URLRequestStringJob : public JsAsker<net::URLRequestSimpleJob> {
|
||||
public:
|
||||
URLRequestStringJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data);
|
||||
URLRequestStringJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
// URLRequestSimpleJob:
|
||||
int GetData(std::string* mime_type,
|
||||
|
||||
209
atom/browser/node_debugger.cc
Normal file
209
atom/browser/node_debugger.cc
Normal file
@@ -0,0 +1,209 @@
|
||||
// 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/browser/node_debugger.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/test/embedded_test_server/tcp_listen_socket.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been
|
||||
// taken by gin, blink and node, using 2 is a safe option for now.
|
||||
const int kIsolateSlot = 2;
|
||||
|
||||
const char* kContentLength = "Content-Length";
|
||||
|
||||
} // namespace
|
||||
|
||||
NodeDebugger::NodeDebugger(v8::Isolate* isolate)
|
||||
: isolate_(isolate),
|
||||
thread_("NodeDebugger"),
|
||||
content_length_(-1),
|
||||
weak_factory_(this) {
|
||||
bool use_debug_agent = false;
|
||||
int port = 5858;
|
||||
bool wait_for_connection = false;
|
||||
|
||||
std::string port_str;
|
||||
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd->HasSwitch("debug")) {
|
||||
use_debug_agent = true;
|
||||
port_str = cmd->GetSwitchValueASCII("debug");
|
||||
}
|
||||
if (cmd->HasSwitch("debug-brk")) {
|
||||
use_debug_agent = true;
|
||||
wait_for_connection = true;
|
||||
port_str = cmd->GetSwitchValueASCII("debug-brk");
|
||||
}
|
||||
|
||||
if (use_debug_agent) {
|
||||
if (!port_str.empty())
|
||||
base::StringToInt(port_str, &port);
|
||||
|
||||
isolate_->SetData(kIsolateSlot, this);
|
||||
v8::Debug::SetMessageHandler(DebugMessageHandler);
|
||||
|
||||
if (wait_for_connection)
|
||||
v8::Debug::DebugBreak(isolate_);
|
||||
|
||||
uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI);
|
||||
|
||||
// Start a new IO thread.
|
||||
base::Thread::Options options;
|
||||
options.message_loop_type = base::MessageLoop::TYPE_IO;
|
||||
if (!thread_.StartWithOptions(options)) {
|
||||
LOG(ERROR) << "Unable to start debugger thread";
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the server in new IO thread.
|
||||
thread_.message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(),
|
||||
port));
|
||||
}
|
||||
}
|
||||
|
||||
NodeDebugger::~NodeDebugger() {
|
||||
thread_.Stop();
|
||||
}
|
||||
|
||||
bool NodeDebugger::IsRunning() const {
|
||||
return thread_.IsRunning();
|
||||
}
|
||||
|
||||
void NodeDebugger::StartServer(int port) {
|
||||
server_ = net::test_server::TCPListenSocket::CreateAndListen(
|
||||
"127.0.0.1", port, this);
|
||||
if (!server_) {
|
||||
LOG(ERROR) << "Cannot start debugger server";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeDebugger::CloseSession() {
|
||||
accepted_socket_.reset();
|
||||
}
|
||||
|
||||
void NodeDebugger::OnMessage(const std::string& message) {
|
||||
if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") !=
|
||||
std::string::npos)
|
||||
CloseSession();
|
||||
|
||||
base::string16 message16 = base::UTF8ToUTF16(message);
|
||||
v8::Debug::SendCommand(
|
||||
isolate_,
|
||||
reinterpret_cast<const uint16_t*>(message16.data()), message16.size());
|
||||
|
||||
uv_async_send(&weak_up_ui_handle_);
|
||||
}
|
||||
|
||||
void NodeDebugger::SendMessage(const std::string& message) {
|
||||
if (accepted_socket_) {
|
||||
std::string header = base::StringPrintf(
|
||||
"%s: %d\r\n\r\n", kContentLength, static_cast<int>(message.size()));
|
||||
accepted_socket_->Send(header);
|
||||
accepted_socket_->Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeDebugger::SendConnectMessage() {
|
||||
accepted_socket_->Send(base::StringPrintf(
|
||||
"Type: connect\r\n"
|
||||
"V8-Version: %s\r\n"
|
||||
"Protocol-Version: 1\r\n"
|
||||
"Embedding-Host: %s\r\n"
|
||||
"%s: 0\r\n",
|
||||
v8::V8::GetVersion(), ATOM_PRODUCT_NAME, kContentLength), true);
|
||||
}
|
||||
|
||||
// static
|
||||
void NodeDebugger::ProcessMessageInUI(uv_async_t* handle) {
|
||||
v8::Debug::ProcessDebugMessages();
|
||||
}
|
||||
|
||||
// static
|
||||
void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) {
|
||||
NodeDebugger* self = static_cast<NodeDebugger*>(
|
||||
message.GetIsolate()->GetData(kIsolateSlot));
|
||||
|
||||
if (self) {
|
||||
std::string message8(*v8::String::Utf8Value(message.GetJSON()));
|
||||
self->thread_.message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(),
|
||||
message8));
|
||||
}
|
||||
}
|
||||
|
||||
void NodeDebugger::DidAccept(
|
||||
net::test_server::StreamListenSocket* server,
|
||||
scoped_ptr<net::test_server::StreamListenSocket> socket) {
|
||||
// Only accept one session.
|
||||
if (accepted_socket_) {
|
||||
socket->Send(std::string("Remote debugging session already active"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
accepted_socket_ = socket.Pass();
|
||||
SendConnectMessage();
|
||||
}
|
||||
|
||||
void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket,
|
||||
const char* data,
|
||||
int len) {
|
||||
buffer_.append(data, len);
|
||||
|
||||
do {
|
||||
if (buffer_.size() == 0)
|
||||
return;
|
||||
|
||||
// Read the "Content-Length" header.
|
||||
if (content_length_ < 0) {
|
||||
size_t pos = buffer_.find("\r\n\r\n");
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
|
||||
// We can be sure that the header is "Content-Length: xxx\r\n".
|
||||
std::string content_length = buffer_.substr(16, pos - 16);
|
||||
if (!base::StringToInt(content_length, &content_length_)) {
|
||||
DidClose(accepted_socket_.get());
|
||||
return;
|
||||
}
|
||||
|
||||
// Strip header from buffer.
|
||||
buffer_ = buffer_.substr(pos + 4);
|
||||
}
|
||||
|
||||
// Read the message.
|
||||
if (buffer_.size() >= static_cast<size_t>(content_length_)) {
|
||||
std::string message = buffer_.substr(0, content_length_);
|
||||
buffer_ = buffer_.substr(content_length_);
|
||||
|
||||
OnMessage(message);
|
||||
|
||||
// Get ready for next message.
|
||||
content_length_ = -1;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void NodeDebugger::DidClose(net::test_server::StreamListenSocket* socket) {
|
||||
// If we lost the connection, then simulate a disconnect msg:
|
||||
OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}");
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
65
atom/browser/node_debugger.h
Normal file
65
atom/browser/node_debugger.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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_BROWSER_NODE_DEBUGGER_H_
|
||||
#define ATOM_BROWSER_NODE_DEBUGGER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "net/test/embedded_test_server/stream_listen_socket.h"
|
||||
#include "v8/include/v8-debug.h"
|
||||
#include "vendor/node/deps/uv/include/uv.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Add support for node's "--debug" switch.
|
||||
class NodeDebugger : public net::test_server::StreamListenSocket::Delegate {
|
||||
public:
|
||||
explicit NodeDebugger(v8::Isolate* isolate);
|
||||
virtual ~NodeDebugger();
|
||||
|
||||
bool IsRunning() const;
|
||||
|
||||
private:
|
||||
void StartServer(int port);
|
||||
void CloseSession();
|
||||
void OnMessage(const std::string& message);
|
||||
void SendMessage(const std::string& message);
|
||||
void SendConnectMessage();
|
||||
|
||||
static void ProcessMessageInUI(uv_async_t* handle);
|
||||
|
||||
static void DebugMessageHandler(const v8::Debug::Message& message);
|
||||
|
||||
// net::test_server::StreamListenSocket::Delegate:
|
||||
void DidAccept(
|
||||
net::test_server::StreamListenSocket* server,
|
||||
scoped_ptr<net::test_server::StreamListenSocket> socket) override;
|
||||
void DidRead(net::test_server::StreamListenSocket* socket,
|
||||
const char* data,
|
||||
int len) override;
|
||||
void DidClose(net::test_server::StreamListenSocket* socket) override;
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
|
||||
uv_async_t weak_up_ui_handle_;
|
||||
|
||||
base::Thread thread_;
|
||||
scoped_ptr<net::test_server::StreamListenSocket> server_;
|
||||
scoped_ptr<net::test_server::StreamListenSocket> accepted_socket_;
|
||||
|
||||
std::string buffer_;
|
||||
int content_length_;
|
||||
|
||||
base::WeakPtrFactory<NodeDebugger> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NodeDebugger);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NODE_DEBUGGER_H_
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.30.6</string>
|
||||
<string>0.32.1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!-- Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
|
||||
|
||||
@@ -56,8 +56,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,30,6,0
|
||||
PRODUCTVERSION 0,30,6,0
|
||||
FILEVERSION 0,32,1,0
|
||||
PRODUCTVERSION 0,32,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -74,12 +74,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.30.6"
|
||||
VALUE "FileVersion", "0.32.1"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.30.6"
|
||||
VALUE "ProductVersion", "0.32.1"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AtomMenuModel::AtomMenuModel(Delegate* delegate)
|
||||
@@ -14,6 +16,17 @@ AtomMenuModel::AtomMenuModel(Delegate* delegate)
|
||||
AtomMenuModel::~AtomMenuModel() {
|
||||
}
|
||||
|
||||
void AtomMenuModel::SetRole(int index, const base::string16& role) {
|
||||
roles_[index] = role;
|
||||
}
|
||||
|
||||
base::string16 AtomMenuModel::GetRoleAt(int index) {
|
||||
if (ContainsKey(roles_, index))
|
||||
return roles_[index];
|
||||
else
|
||||
return base::string16();
|
||||
}
|
||||
|
||||
void AtomMenuModel::MenuClosed() {
|
||||
ui::SimpleMenuModel::MenuClosed();
|
||||
FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
||||
#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/observer_list.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
|
||||
@@ -31,13 +33,17 @@ class AtomMenuModel : public ui::SimpleMenuModel {
|
||||
void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
|
||||
void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
|
||||
|
||||
void SetRole(int index, const base::string16& role);
|
||||
base::string16 GetRoleAt(int index);
|
||||
|
||||
// ui::SimpleMenuModel:
|
||||
void MenuClosed() override;
|
||||
|
||||
private:
|
||||
Delegate* delegate_; // weak ref.
|
||||
|
||||
ObserverList<Observer> observers_;
|
||||
std::map<int, base::string16> roles_;
|
||||
base::ObserverList<Observer> observers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);
|
||||
};
|
||||
|
||||
@@ -59,17 +59,4 @@ class MenuModel;
|
||||
|
||||
@end
|
||||
|
||||
// Exposed only for unit testing, do not call directly.
|
||||
@interface AtomMenuController (PrivateExposedForTesting)
|
||||
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item;
|
||||
@end
|
||||
|
||||
// Protected methods that subclassers can override.
|
||||
@interface AtomMenuController (Protected)
|
||||
- (void)addItemToMenu:(NSMenu*)menu
|
||||
atIndex:(NSInteger)index
|
||||
fromModel:(ui::MenuModel*)model;
|
||||
- (NSMenu*)menuFromModel:(ui::MenuModel*)model;
|
||||
@end
|
||||
|
||||
#endif // ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_
|
||||
|
||||
@@ -8,16 +8,36 @@
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
|
||||
#include "ui/base/l10n/l10n_util_mac.h"
|
||||
#include "ui/events/cocoa/cocoa_event_utils.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
@interface AtomMenuController (Private)
|
||||
- (void)addSeparatorToMenu:(NSMenu*)menu
|
||||
atIndex:(int)index;
|
||||
@end
|
||||
namespace {
|
||||
|
||||
struct Role {
|
||||
SEL selector;
|
||||
const char* role;
|
||||
};
|
||||
Role kRolesMap[] = {
|
||||
{ @selector(orderFrontStandardAboutPanel:), "about" },
|
||||
{ @selector(hide:), "hide" },
|
||||
{ @selector(hideOtherApplications:), "hideothers" },
|
||||
{ @selector(unhideAllApplications:), "unhide" },
|
||||
{ @selector(arrangeInFront:), "front" },
|
||||
{ @selector(undo:), "undo" },
|
||||
{ @selector(redo:), "redo" },
|
||||
{ @selector(cut:), "cut" },
|
||||
{ @selector(copy:), "copy" },
|
||||
{ @selector(paste:), "paste" },
|
||||
{ @selector(selectAll:), "selectall" },
|
||||
{ @selector(performMiniaturize:), "minimize" },
|
||||
{ @selector(performClose:), "close" },
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@implementation AtomMenuController
|
||||
|
||||
@@ -101,7 +121,9 @@
|
||||
// associated with the entry in the model identified by |modelIndex|.
|
||||
- (void)addItemToMenu:(NSMenu*)menu
|
||||
atIndex:(NSInteger)index
|
||||
fromModel:(ui::MenuModel*)model {
|
||||
fromModel:(ui::MenuModel*)ui_model {
|
||||
atom::AtomMenuModel* model = static_cast<atom::AtomMenuModel*>(ui_model);
|
||||
|
||||
base::string16 label16 = model->GetLabelAt(index);
|
||||
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
|
||||
base::scoped_nsobject<NSMenuItem> item(
|
||||
@@ -124,13 +146,13 @@
|
||||
[submenu setTitle:[item title]];
|
||||
[item setSubmenu:submenu];
|
||||
|
||||
// Hack to set window and help menu.
|
||||
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
|
||||
// Set submenu's role.
|
||||
base::string16 role = model->GetRoleAt(index);
|
||||
if (role == base::ASCIIToUTF16("window"))
|
||||
[NSApp setWindowsMenu:submenu];
|
||||
else if ([[item title] isEqualToString:@"Help"])
|
||||
else if (role == base::ASCIIToUTF16("help"))
|
||||
[NSApp setHelpMenu:submenu];
|
||||
if ([[item title] isEqualToString:@"Services"] &&
|
||||
[submenu numberOfItems] == 0)
|
||||
if (role == base::ASCIIToUTF16("services"))
|
||||
[NSApp setServicesMenu:submenu];
|
||||
} else {
|
||||
// The MenuModel works on indexes so we can't just set the command id as the
|
||||
@@ -139,7 +161,6 @@
|
||||
// model. Setting the target to |self| allows this class to participate
|
||||
// in validation of the menu items.
|
||||
[item setTag:index];
|
||||
[item setTarget:self];
|
||||
NSValue* modelObject = [NSValue valueWithPointer:model];
|
||||
[item setRepresentedObject:modelObject]; // Retains |modelObject|.
|
||||
ui::Accelerator accelerator;
|
||||
@@ -153,6 +174,19 @@
|
||||
platformAccelerator->modifier_mask()];
|
||||
}
|
||||
}
|
||||
|
||||
// Set menu item's role.
|
||||
base::string16 role = model->GetRoleAt(index);
|
||||
if (role.empty()) {
|
||||
[item setTarget:self];
|
||||
} else {
|
||||
for (const Role& pair : kRolesMap) {
|
||||
if (role == base::ASCIIToUTF16(pair.role)) {
|
||||
[item setAction:pair.selector];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[menu insertItem:item atIndex:index];
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ namespace {
|
||||
// Makes sure that .jpg also shows .JPG.
|
||||
gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info,
|
||||
std::string* file_extension) {
|
||||
return EndsWith(file_info->filename, *file_extension, false);
|
||||
// Makes .* file extension matches all file types.
|
||||
if (*file_extension == ".*")
|
||||
return true;
|
||||
return base::EndsWith(file_info->filename, *file_extension, false);
|
||||
}
|
||||
|
||||
// Deletes |data| when gtk_file_filter_add_custom() is done with it.
|
||||
|
||||
@@ -23,6 +23,12 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
|
||||
for (size_t i = 0; i < filters.size(); ++i) {
|
||||
const Filter& filter = filters[i];
|
||||
for (size_t j = 0; j < filter.second.size(); ++j) {
|
||||
// If we meet a '*' file extension, we allow all the file types and no
|
||||
// need to set the specified file types.
|
||||
if (filter.second[j] == "*") {
|
||||
[dialog setAllowsOtherFileTypes:YES];
|
||||
return;
|
||||
}
|
||||
base::ScopedCFTypeRef<CFStringRef> ext_cf(
|
||||
base::SysUTF8ToCFStringRef(filter.second[j]));
|
||||
[file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];
|
||||
|
||||
@@ -252,7 +252,7 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
|
||||
bool matched = false;
|
||||
for (size_t i = 0; i < filter.second.size(); ++i) {
|
||||
if (EndsWith(file_name, filter.second[i], false)) {
|
||||
if (base::EndsWith(file_name, filter.second[i], false)) {
|
||||
matched = true;
|
||||
break;;
|
||||
}
|
||||
|
||||
@@ -78,9 +78,9 @@ int ShowMessageBoxUTF16(HWND parent,
|
||||
const base::string16& message,
|
||||
const base::string16& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
TASKDIALOG_FLAGS flags = TDF_SIZE_TO_CONTENT; // show all content.
|
||||
if (cancel_id != 0)
|
||||
flags |= TDF_ALLOW_DIALOG_CANCELLATION; // allow dialog to be cancelled.
|
||||
TASKDIALOG_FLAGS flags =
|
||||
TDF_SIZE_TO_CONTENT | // Show all content.
|
||||
TDF_ALLOW_DIALOG_CANCELLATION; // Allow canceling the dialog.
|
||||
|
||||
TASKDIALOGCONFIG config = { 0 };
|
||||
config.cbSize = sizeof(config);
|
||||
|
||||
@@ -67,7 +67,7 @@ class TrayIcon {
|
||||
TrayIcon();
|
||||
|
||||
private:
|
||||
ObserverList<TrayIconObserver> observers_;
|
||||
base::ObserverList<TrayIconObserver> observers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TrayIcon);
|
||||
};
|
||||
|
||||
@@ -207,8 +207,14 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
}
|
||||
inMouseEventSequence_ = NO;
|
||||
|
||||
// Show menu when single clicked on the icon.
|
||||
if (event.clickCount == 1 && menuController_)
|
||||
// Show menu when there is a context menu.
|
||||
// NB(hokein): Make tray's behavior more like official one's.
|
||||
// When the tray icon gets clicked quickly multiple times, the
|
||||
// event.clickCount doesn't always return 1. Instead, it returns a value that
|
||||
// counts the clicked times.
|
||||
// So we don't check the clickCount here, just pop up the menu for each click
|
||||
// event.
|
||||
if (menuController_)
|
||||
[statusItem_ popUpStatusItemMenu:[menuController_ menu]];
|
||||
|
||||
// Don't emit click events when menu is showing.
|
||||
|
||||
@@ -41,7 +41,7 @@ void SetWindowType(::Window xwindow, const std::string& type) {
|
||||
XDisplay* xdisplay = gfx::GetXDisplay();
|
||||
std::string type_prefix = "_NET_WM_WINDOW_TYPE_";
|
||||
::Atom window_type = XInternAtom(
|
||||
xdisplay, (type_prefix + StringToUpperASCII(type)).c_str(), False);
|
||||
xdisplay, (type_prefix + base::StringToUpperASCII(type)).c_str(), False);
|
||||
XChangeProperty(xdisplay, xwindow,
|
||||
XInternAtom(xdisplay, "_NET_WM_WINDOW_TYPE", False),
|
||||
XA_ATOM,
|
||||
|
||||
154
atom/browser/web_contents_preferences.cc
Normal file
154
atom/browser/web_contents_preferences.cc
Normal file
@@ -0,0 +1,154 @@
|
||||
// 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/browser/web_contents_preferences.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "content/public/common/web_preferences.h"
|
||||
#include "net/base/filename_util.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/switches.h"
|
||||
#endif
|
||||
|
||||
DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::WebContentsPreferences);
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Array of available web runtime features.
|
||||
const char* kWebRuntimeFeatures[] = {
|
||||
switches::kExperimentalFeatures,
|
||||
switches::kExperimentalCanvasFeatures,
|
||||
switches::kSubpixelFontScaling,
|
||||
switches::kOverlayScrollbars,
|
||||
switches::kOverlayFullscreenVideo,
|
||||
switches::kSharedWorker,
|
||||
switches::kPageVisibility,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
WebContentsPreferences::WebContentsPreferences(
|
||||
content::WebContents* web_contents,
|
||||
base::DictionaryValue* web_preferences) {
|
||||
web_preferences_.Swap(web_preferences);
|
||||
web_contents->SetUserData(UserDataKey(), this);
|
||||
}
|
||||
|
||||
WebContentsPreferences::~WebContentsPreferences() {
|
||||
}
|
||||
|
||||
void WebContentsPreferences::Merge(const base::DictionaryValue& extend) {
|
||||
web_preferences_.MergeDictionary(&extend);
|
||||
}
|
||||
|
||||
// static
|
||||
void WebContentsPreferences::AppendExtraCommandLineSwitches(
|
||||
content::WebContents* web_contents, base::CommandLine* command_line) {
|
||||
WebContentsPreferences* self = FromWebContents(web_contents);
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
base::DictionaryValue& web_preferences = self->web_preferences_;
|
||||
|
||||
bool b;
|
||||
#if defined(OS_WIN)
|
||||
// Check if DirectWrite is disabled.
|
||||
if (web_preferences.GetBoolean(switches::kDirectWrite, &b) && !b)
|
||||
command_line->AppendSwitch(::switches::kDisableDirectWrite);
|
||||
#endif
|
||||
|
||||
// Check if plugins are enabled.
|
||||
if (web_preferences.GetBoolean("plugins", &b) && b)
|
||||
command_line->AppendSwitch(switches::kEnablePlugins);
|
||||
|
||||
// This set of options are not availabe in WebPreferences, so we have to pass
|
||||
// them via command line and enable them in renderer procss.
|
||||
for (size_t i = 0; i < arraysize(kWebRuntimeFeatures); ++i) {
|
||||
const char* feature = kWebRuntimeFeatures[i];
|
||||
if (web_preferences.GetBoolean(feature, &b))
|
||||
command_line->AppendSwitchASCII(feature, b ? "true" : "false");
|
||||
}
|
||||
|
||||
// Check if we have node integration specified.
|
||||
bool node_integration = true;
|
||||
web_preferences.GetBoolean(switches::kNodeIntegration, &node_integration);
|
||||
// Be compatible with old API of "node-integration" option.
|
||||
std::string old_token;
|
||||
if (web_preferences.GetString(switches::kNodeIntegration, &old_token) &&
|
||||
old_token != "disable")
|
||||
node_integration = true;
|
||||
command_line->AppendSwitchASCII(switches::kNodeIntegration,
|
||||
node_integration ? "true" : "false");
|
||||
|
||||
// The preload script.
|
||||
base::FilePath::StringType preload;
|
||||
if (web_preferences.GetString(switches::kPreloadScript, &preload)) {
|
||||
if (base::FilePath(preload).IsAbsolute())
|
||||
command_line->AppendSwitchNative(switches::kPreloadScript, preload);
|
||||
else
|
||||
LOG(ERROR) << "preload script must have abosulute path.";
|
||||
} else if (web_preferences.GetString(switches::kPreloadUrl, &preload)) {
|
||||
// Translate to file path if there is "preload-url" option.
|
||||
base::FilePath preload_path;
|
||||
if (net::FileURLToFilePath(GURL(preload), &preload_path))
|
||||
command_line->AppendSwitchPath(switches::kPreloadScript, preload_path);
|
||||
else
|
||||
LOG(ERROR) << "preload url must be file:// protocol.";
|
||||
}
|
||||
|
||||
// The zoom factor.
|
||||
double zoom_factor = 1.0;
|
||||
if (web_preferences.GetDouble(switches::kZoomFactor, &zoom_factor) &&
|
||||
zoom_factor != 1.0)
|
||||
command_line->AppendSwitchASCII(switches::kZoomFactor,
|
||||
base::DoubleToString(zoom_factor));
|
||||
|
||||
// --guest-instance-id, which is used to identify guest WebContents.
|
||||
int guest_instance_id;
|
||||
if (web_preferences.GetInteger(switches::kGuestInstanceID,
|
||||
&guest_instance_id))
|
||||
command_line->AppendSwitchASCII(switches::kGuestInstanceID,
|
||||
base::IntToString(guest_instance_id));
|
||||
}
|
||||
|
||||
// static
|
||||
void WebContentsPreferences::OverrideWebkitPrefs(
|
||||
content::WebContents* web_contents, content::WebPreferences* prefs) {
|
||||
WebContentsPreferences* self = FromWebContents(web_contents);
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
bool b;
|
||||
if (self->web_preferences_.GetBoolean("javascript", &b))
|
||||
prefs->javascript_enabled = b;
|
||||
if (self->web_preferences_.GetBoolean("images", &b))
|
||||
prefs->images_enabled = b;
|
||||
if (self->web_preferences_.GetBoolean("java", &b))
|
||||
prefs->java_enabled = b;
|
||||
if (self->web_preferences_.GetBoolean("text-areas-are-resizable", &b))
|
||||
prefs->text_areas_are_resizable = b;
|
||||
if (self->web_preferences_.GetBoolean("webgl", &b))
|
||||
prefs->experimental_webgl_enabled = b;
|
||||
if (self->web_preferences_.GetBoolean("webaudio", &b))
|
||||
prefs->webaudio_enabled = b;
|
||||
if (self->web_preferences_.GetBoolean("web-security", &b)) {
|
||||
prefs->web_security_enabled = b;
|
||||
prefs->allow_displaying_insecure_content = !b;
|
||||
prefs->allow_running_insecure_content = !b;
|
||||
}
|
||||
if (self->web_preferences_.GetBoolean("allow-displaying-insecure-content",
|
||||
&b))
|
||||
prefs->allow_displaying_insecure_content = b;
|
||||
if (self->web_preferences_.GetBoolean("allow-running-insecure-content", &b))
|
||||
prefs->allow_running_insecure_content = b;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
50
atom/browser/web_contents_preferences.h
Normal file
50
atom/browser/web_contents_preferences.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_
|
||||
#define ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_
|
||||
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
struct WebPreferences;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Stores and applies the preferences of WebContents.
|
||||
class WebContentsPreferences
|
||||
: public content::WebContentsUserData<WebContentsPreferences> {
|
||||
public:
|
||||
// Append command paramters according to |web_contents|'s preferences.
|
||||
static void AppendExtraCommandLineSwitches(
|
||||
content::WebContents* web_contents, base::CommandLine* command_line);
|
||||
|
||||
// Modify the WebPreferences according to |web_contents|'s preferences.
|
||||
static void OverrideWebkitPrefs(
|
||||
content::WebContents* web_contents, content::WebPreferences* prefs);
|
||||
|
||||
WebContentsPreferences(content::WebContents* web_contents,
|
||||
base::DictionaryValue* web_preferences);
|
||||
~WebContentsPreferences() override;
|
||||
|
||||
// $.extend(|web_preferences_|, |new_web_preferences|).
|
||||
void Merge(const base::DictionaryValue& new_web_preferences);
|
||||
|
||||
private:
|
||||
friend class content::WebContentsUserData<WebContentsPreferences>;
|
||||
|
||||
base::DictionaryValue web_preferences_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebContentsPreferences);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_
|
||||
@@ -158,9 +158,11 @@ void WebViewGuestDelegate::SetGuestHost(content::GuestHost* guest_host) {
|
||||
void WebViewGuestDelegate::WillAttach(
|
||||
content::WebContents* embedder_web_contents,
|
||||
int element_instance_id,
|
||||
bool is_full_page_plugin) {
|
||||
bool is_full_page_plugin,
|
||||
const base::Closure& completion_callback) {
|
||||
embedder_web_contents_ = embedder_web_contents;
|
||||
is_full_page_plugin_ = is_full_page_plugin;
|
||||
completion_callback.Run();
|
||||
}
|
||||
|
||||
void WebViewGuestDelegate::GuestSizeChangedDueToAutoSize(
|
||||
|
||||
@@ -70,7 +70,8 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate,
|
||||
void SetGuestHost(content::GuestHost* guest_host) final;
|
||||
void WillAttach(content::WebContents* embedder_web_contents,
|
||||
int element_instance_id,
|
||||
bool is_full_page_plugin) final;
|
||||
bool is_full_page_plugin,
|
||||
const base::Closure& completion_callback) final;
|
||||
|
||||
private:
|
||||
// This method is invoked when the contents auto-resized to give the container
|
||||
|
||||
@@ -10,33 +10,7 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
WebViewManager* GetManagerFromWebContents(
|
||||
const content::WebContents* web_contents) {
|
||||
auto context = web_contents->GetBrowserContext();
|
||||
if (!context)
|
||||
return nullptr;
|
||||
return static_cast<WebViewManager*>(context->GetGuestManager());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
bool WebViewManager::GetInfoForWebContents(
|
||||
const content::WebContents* web_contents, WebViewInfo* info) {
|
||||
auto manager = GetManagerFromWebContents(web_contents);
|
||||
if (!manager)
|
||||
return false;
|
||||
base::AutoLock auto_lock(manager->lock_);
|
||||
auto iter = manager->webview_info_map_.find(web_contents);
|
||||
if (iter == manager->webview_info_map_.end())
|
||||
return false;
|
||||
*info = iter->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
WebViewManager::WebViewManager(content::BrowserContext* context) {
|
||||
WebViewManager::WebViewManager() {
|
||||
}
|
||||
|
||||
WebViewManager::~WebViewManager() {
|
||||
@@ -45,11 +19,8 @@ WebViewManager::~WebViewManager() {
|
||||
void WebViewManager::AddGuest(int guest_instance_id,
|
||||
int element_instance_id,
|
||||
content::WebContents* embedder,
|
||||
content::WebContents* web_contents,
|
||||
const WebViewInfo& info) {
|
||||
base::AutoLock auto_lock(lock_);
|
||||
web_contents_embdder_map_[guest_instance_id] = { web_contents, embedder };
|
||||
webview_info_map_[web_contents] = info;
|
||||
content::WebContents* web_contents) {
|
||||
web_contents_embedder_map_[guest_instance_id] = { web_contents, embedder };
|
||||
|
||||
// Map the element in embedder to guest.
|
||||
int owner_process_id = embedder->GetRenderProcessHost()->GetID();
|
||||
@@ -58,13 +29,10 @@ void WebViewManager::AddGuest(int guest_instance_id,
|
||||
}
|
||||
|
||||
void WebViewManager::RemoveGuest(int guest_instance_id) {
|
||||
base::AutoLock auto_lock(lock_);
|
||||
if (!ContainsKey(web_contents_embdder_map_, guest_instance_id))
|
||||
if (!ContainsKey(web_contents_embedder_map_, guest_instance_id))
|
||||
return;
|
||||
|
||||
auto web_contents = web_contents_embdder_map_[guest_instance_id].web_contents;
|
||||
web_contents_embdder_map_.erase(guest_instance_id);
|
||||
webview_info_map_.erase(web_contents);
|
||||
web_contents_embedder_map_.erase(guest_instance_id);
|
||||
|
||||
// Remove the record of element in embedder too.
|
||||
for (const auto& element : element_instance_id_to_guest_map_)
|
||||
@@ -82,15 +50,15 @@ content::WebContents* WebViewManager::GetGuestByInstanceID(
|
||||
return nullptr;
|
||||
|
||||
int guest_instance_id = element_instance_id_to_guest_map_[key];
|
||||
if (ContainsKey(web_contents_embdder_map_, guest_instance_id))
|
||||
return web_contents_embdder_map_[guest_instance_id].web_contents;
|
||||
if (ContainsKey(web_contents_embedder_map_, guest_instance_id))
|
||||
return web_contents_embedder_map_[guest_instance_id].web_contents;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents,
|
||||
const GuestCallback& callback) {
|
||||
for (auto& item : web_contents_embdder_map_)
|
||||
for (auto& item : web_contents_embedder_map_)
|
||||
if (item.second.embedder == embedder_web_contents &&
|
||||
callback.Run(item.second.web_contents))
|
||||
return true;
|
||||
|
||||
@@ -7,41 +7,19 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "content/public/browser/browser_plugin_guest_manager.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class RenderProcessHost;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class WebViewManager : public content::BrowserPluginGuestManager {
|
||||
public:
|
||||
struct WebViewInfo {
|
||||
int guest_instance_id;
|
||||
content::WebContents* embedder;
|
||||
bool node_integration;
|
||||
bool plugins;
|
||||
bool disable_web_security;
|
||||
base::FilePath preload_script;
|
||||
};
|
||||
|
||||
// Finds the WebViewManager attached with |web_contents| and returns the
|
||||
// WebViewInfo of it.
|
||||
static bool GetInfoForWebContents(const content::WebContents* web_contents,
|
||||
WebViewInfo* info);
|
||||
|
||||
explicit WebViewManager(content::BrowserContext* context);
|
||||
virtual ~WebViewManager();
|
||||
WebViewManager();
|
||||
~WebViewManager() override;
|
||||
|
||||
void AddGuest(int guest_instance_id,
|
||||
int element_instance_id,
|
||||
content::WebContents* embedder,
|
||||
content::WebContents* web_contents,
|
||||
const WebViewInfo& info);
|
||||
content::WebContents* web_contents);
|
||||
void RemoveGuest(int guest_instance_id);
|
||||
|
||||
protected:
|
||||
@@ -57,7 +35,7 @@ class WebViewManager : public content::BrowserPluginGuestManager {
|
||||
content::WebContents* embedder;
|
||||
};
|
||||
// guest_instance_id => (web_contents, embedder)
|
||||
std::map<int, WebContentsWithEmbedder> web_contents_embdder_map_;
|
||||
std::map<int, WebContentsWithEmbedder> web_contents_embedder_map_;
|
||||
|
||||
struct ElementInstanceKey {
|
||||
int embedder_process_id;
|
||||
@@ -81,12 +59,6 @@ class WebViewManager : public content::BrowserPluginGuestManager {
|
||||
// (embedder_process_id, element_instance_id) => guest_instance_id
|
||||
std::map<ElementInstanceKey, int> element_instance_id_to_guest_map_;
|
||||
|
||||
typedef std::map<const content::WebContents*, WebViewInfo> WebViewInfoMap;
|
||||
// web_contents => (guest_instance_id, embedder, ...)
|
||||
WebViewInfoMap webview_info_map_;
|
||||
|
||||
base::Lock lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebViewManager);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace atom {
|
||||
|
||||
// static
|
||||
base::LazyInstance<ObserverList<WindowListObserver>>::Leaky
|
||||
base::LazyInstance<base::ObserverList<WindowListObserver>>::Leaky
|
||||
WindowList::observers_ = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
// static
|
||||
|
||||
@@ -60,7 +60,8 @@ class WindowList {
|
||||
|
||||
// A list of observers which will be notified of every window addition and
|
||||
// removal across all WindowLists.
|
||||
static base::LazyInstance<ObserverList<WindowListObserver>>::Leaky observers_;
|
||||
static base::LazyInstance<base::ObserverList<WindowListObserver>>::Leaky
|
||||
observers_;
|
||||
|
||||
static WindowList* instance_;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user