atom_api_web_frame.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. // Copyright (c) 2014 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/renderer/api/atom_api_web_frame.h"
  5. #include "atom/common/api/api_messages.h"
  6. #include "atom/common/api/event_emitter_caller.h"
  7. #include "atom/common/native_mate_converters/blink_converter.h"
  8. #include "atom/common/native_mate_converters/callback.h"
  9. #include "atom/common/native_mate_converters/gfx_converter.h"
  10. #include "atom/common/native_mate_converters/string16_converter.h"
  11. #include "atom/renderer/api/atom_api_spell_check_client.h"
  12. #include "base/memory/memory_pressure_listener.h"
  13. #include "content/public/renderer/render_frame.h"
  14. #include "content/public/renderer/render_frame_visitor.h"
  15. #include "content/public/renderer/render_view.h"
  16. #include "native_mate/dictionary.h"
  17. #include "native_mate/object_template_builder.h"
  18. #include "third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h"
  19. #include "third_party/WebKit/public/platform/WebCache.h"
  20. #include "third_party/WebKit/public/web/WebDocument.h"
  21. #include "third_party/WebKit/public/web/WebElement.h"
  22. #include "third_party/WebKit/public/web/WebFrameWidget.h"
  23. #include "third_party/WebKit/public/web/WebImeTextSpan.h"
  24. #include "third_party/WebKit/public/web/WebInputMethodController.h"
  25. #include "third_party/WebKit/public/web/WebLocalFrame.h"
  26. #include "third_party/WebKit/public/web/WebScriptExecutionCallback.h"
  27. #include "third_party/WebKit/public/web/WebScriptSource.h"
  28. #include "third_party/WebKit/public/web/WebView.h"
  29. #include "atom/common/node_includes.h"
  30. namespace mate {
  31. template <>
  32. struct Converter<blink::WebLocalFrame::ScriptExecutionType> {
  33. static bool FromV8(v8::Isolate* isolate,
  34. v8::Local<v8::Value> val,
  35. blink::WebLocalFrame::ScriptExecutionType* out) {
  36. std::string execution_type;
  37. if (!ConvertFromV8(isolate, val, &execution_type))
  38. return false;
  39. if (execution_type == "asynchronous") {
  40. *out = blink::WebLocalFrame::kAsynchronous;
  41. } else if (execution_type == "asynchronousBlockingOnload") {
  42. *out = blink::WebLocalFrame::kAsynchronousBlockingOnload;
  43. } else if (execution_type == "synchronous") {
  44. *out = blink::WebLocalFrame::kSynchronous;
  45. } else {
  46. return false;
  47. }
  48. return true;
  49. }
  50. };
  51. } // namespace mate
  52. namespace atom {
  53. namespace api {
  54. namespace {
  55. class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
  56. public:
  57. using CompletionCallback =
  58. base::Callback<void(const v8::Local<v8::Value>& result)>;
  59. explicit ScriptExecutionCallback(const CompletionCallback& callback)
  60. : callback_(callback) {}
  61. ~ScriptExecutionCallback() override {}
  62. void Completed(
  63. const blink::WebVector<v8::Local<v8::Value>>& result) override {
  64. if (!callback_.is_null() && !result.IsEmpty() && !result[0].IsEmpty())
  65. // Right now only single results per frame is supported.
  66. callback_.Run(result[0]);
  67. delete this;
  68. }
  69. private:
  70. CompletionCallback callback_;
  71. DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback);
  72. };
  73. class FrameSpellChecker : public content::RenderFrameVisitor {
  74. public:
  75. explicit FrameSpellChecker(SpellCheckClient* spell_check_client,
  76. content::RenderFrame* main_frame)
  77. : spell_check_client_(spell_check_client), main_frame_(main_frame) {}
  78. ~FrameSpellChecker() override {
  79. spell_check_client_ = nullptr;
  80. main_frame_ = nullptr;
  81. }
  82. bool Visit(content::RenderFrame* render_frame) override {
  83. auto* view = render_frame->GetRenderView();
  84. if (view->GetMainRenderFrame() == main_frame_ ||
  85. (render_frame->IsMainFrame() && render_frame == main_frame_)) {
  86. render_frame->GetWebFrame()->SetTextCheckClient(spell_check_client_);
  87. }
  88. return true;
  89. }
  90. private:
  91. SpellCheckClient* spell_check_client_;
  92. content::RenderFrame* main_frame_;
  93. DISALLOW_COPY_AND_ASSIGN(FrameSpellChecker);
  94. };
  95. } // namespace
  96. WebFrame::WebFrame(v8::Isolate* isolate)
  97. : web_frame_(blink::WebLocalFrame::FrameForCurrentContext()) {
  98. Init(isolate);
  99. }
  100. WebFrame::WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame)
  101. : web_frame_(blink_frame) {
  102. Init(isolate);
  103. }
  104. WebFrame::~WebFrame() {}
  105. void WebFrame::SetName(const std::string& name) {
  106. web_frame_->SetName(blink::WebString::FromUTF8(name));
  107. }
  108. double WebFrame::SetZoomLevel(double level) {
  109. double result = 0.0;
  110. content::RenderFrame* render_frame =
  111. content::RenderFrame::FromWebFrame(web_frame_);
  112. render_frame->Send(new AtomFrameHostMsg_SetTemporaryZoomLevel(
  113. render_frame->GetRoutingID(), level, &result));
  114. return result;
  115. }
  116. double WebFrame::GetZoomLevel() const {
  117. double result = 0.0;
  118. content::RenderFrame* render_frame =
  119. content::RenderFrame::FromWebFrame(web_frame_);
  120. render_frame->Send(
  121. new AtomFrameHostMsg_GetZoomLevel(render_frame->GetRoutingID(), &result));
  122. return result;
  123. }
  124. double WebFrame::SetZoomFactor(double factor) {
  125. return blink::WebView::ZoomLevelToZoomFactor(
  126. SetZoomLevel(blink::WebView::ZoomFactorToZoomLevel(factor)));
  127. }
  128. double WebFrame::GetZoomFactor() const {
  129. return blink::WebView::ZoomLevelToZoomFactor(GetZoomLevel());
  130. }
  131. void WebFrame::SetVisualZoomLevelLimits(double min_level, double max_level) {
  132. web_frame_->View()->SetDefaultPageScaleLimits(min_level, max_level);
  133. web_frame_->View()->SetIgnoreViewportTagScaleLimits(true);
  134. }
  135. void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) {
  136. web_frame_->View()->ZoomLimitsChanged(min_level, max_level);
  137. }
  138. v8::Local<v8::Value> WebFrame::RegisterEmbedderCustomElement(
  139. const base::string16& name,
  140. v8::Local<v8::Object> options) {
  141. return web_frame_->GetDocument().RegisterEmbedderCustomElement(
  142. blink::WebString::FromUTF16(name), options);
  143. }
  144. void WebFrame::RegisterElementResizeCallback(
  145. int element_instance_id,
  146. const GuestViewContainer::ResizeCallback& callback) {
  147. auto* guest_view_container = GuestViewContainer::FromID(element_instance_id);
  148. if (guest_view_container)
  149. guest_view_container->RegisterElementResizeCallback(callback);
  150. }
  151. void WebFrame::AttachGuest(int id) {
  152. content::RenderFrame::FromWebFrame(web_frame_)->AttachGuest(id);
  153. }
  154. void WebFrame::DetachGuest(int id) {
  155. content::RenderFrame::FromWebFrame(web_frame_)->DetachGuest(id);
  156. }
  157. void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
  158. const std::string& language,
  159. bool auto_spell_correct_turned_on,
  160. v8::Local<v8::Object> provider) {
  161. if (!provider->Has(mate::StringToV8(args->isolate(), "spellCheck"))) {
  162. args->ThrowError("\"spellCheck\" has to be defined");
  163. return;
  164. }
  165. std::unique_ptr<SpellCheckClient> client(new SpellCheckClient(
  166. language, auto_spell_correct_turned_on, args->isolate(), provider));
  167. // Set spellchecker for all live frames in the same process or
  168. // in the sandbox mode for all live sub frames to this WebFrame.
  169. FrameSpellChecker spell_checker(
  170. client.get(), content::RenderFrame::FromWebFrame(web_frame_));
  171. content::RenderFrame::ForEach(&spell_checker);
  172. spell_check_client_.swap(client);
  173. web_frame_->SetSpellCheckPanelHostClient(spell_check_client_.get());
  174. }
  175. void WebFrame::RegisterURLSchemeAsBypassingCSP(const std::string& scheme) {
  176. // Register scheme to bypass pages's Content Security Policy.
  177. blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
  178. WTF::String::FromUTF8(scheme.data(), scheme.length()));
  179. }
  180. void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme,
  181. mate::Arguments* args) {
  182. // TODO(deepak1556): blink::SchemeRegistry methods should be called
  183. // before any renderer threads are created. Fixing this would break
  184. // current api. Change it with 2.0.
  185. // Read optional flags
  186. bool secure = true;
  187. bool bypassCSP = true;
  188. bool allowServiceWorkers = true;
  189. bool supportFetchAPI = true;
  190. bool corsEnabled = true;
  191. if (args->Length() == 2) {
  192. mate::Dictionary options;
  193. if (args->GetNext(&options)) {
  194. options.Get("secure", &secure);
  195. options.Get("bypassCSP", &bypassCSP);
  196. options.Get("allowServiceWorkers", &allowServiceWorkers);
  197. options.Get("supportFetchAPI", &supportFetchAPI);
  198. options.Get("corsEnabled", &corsEnabled);
  199. }
  200. }
  201. // Register scheme to privileged list (https, wss, data, chrome-extension)
  202. WTF::String privileged_scheme(
  203. WTF::String::FromUTF8(scheme.data(), scheme.length()));
  204. if (bypassCSP) {
  205. blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
  206. privileged_scheme);
  207. }
  208. if (allowServiceWorkers) {
  209. blink::SchemeRegistry::RegisterURLSchemeAsAllowingServiceWorkers(
  210. privileged_scheme);
  211. }
  212. if (supportFetchAPI) {
  213. blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(
  214. privileged_scheme);
  215. }
  216. if (corsEnabled) {
  217. blink::SchemeRegistry::RegisterURLSchemeAsCORSEnabled(privileged_scheme);
  218. }
  219. }
  220. void WebFrame::InsertText(const std::string& text) {
  221. web_frame_->FrameWidget()->GetActiveWebInputMethodController()->CommitText(
  222. blink::WebString::FromUTF8(text),
  223. blink::WebVector<blink::WebImeTextSpan>(), blink::WebRange(), 0);
  224. }
  225. void WebFrame::InsertCSS(const std::string& css) {
  226. web_frame_->GetDocument().InsertStyleSheet(blink::WebString::FromUTF8(css));
  227. }
  228. void WebFrame::ExecuteJavaScript(const base::string16& code,
  229. mate::Arguments* args) {
  230. bool has_user_gesture = false;
  231. args->GetNext(&has_user_gesture);
  232. ScriptExecutionCallback::CompletionCallback completion_callback;
  233. args->GetNext(&completion_callback);
  234. std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  235. new ScriptExecutionCallback(completion_callback));
  236. web_frame_->RequestExecuteScriptAndReturnValue(
  237. blink::WebScriptSource(blink::WebString::FromUTF16(code)),
  238. has_user_gesture, callback.release());
  239. }
  240. void WebFrame::ExecuteJavaScriptInIsolatedWorld(
  241. int world_id,
  242. const std::vector<mate::Dictionary>& scripts,
  243. mate::Arguments* args) {
  244. std::vector<blink::WebScriptSource> sources;
  245. for (const auto& script : scripts) {
  246. base::string16 code;
  247. base::string16 url;
  248. int start_line = 1;
  249. script.Get("url", &url);
  250. script.Get("startLine", &start_line);
  251. if (!script.Get("code", &code)) {
  252. args->ThrowError("Invalid 'code'");
  253. return;
  254. }
  255. sources.emplace_back(
  256. blink::WebScriptSource(blink::WebString::FromUTF16(code),
  257. blink::WebURL(GURL(url)), start_line));
  258. }
  259. bool has_user_gesture = false;
  260. args->GetNext(&has_user_gesture);
  261. blink::WebLocalFrame::ScriptExecutionType scriptExecutionType =
  262. blink::WebLocalFrame::kSynchronous;
  263. args->GetNext(&scriptExecutionType);
  264. ScriptExecutionCallback::CompletionCallback completion_callback;
  265. args->GetNext(&completion_callback);
  266. std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  267. new ScriptExecutionCallback(completion_callback));
  268. web_frame_->RequestExecuteScriptInIsolatedWorld(
  269. world_id, &sources.front(), sources.size(), has_user_gesture,
  270. scriptExecutionType, callback.release());
  271. }
  272. void WebFrame::SetIsolatedWorldSecurityOrigin(int world_id,
  273. const std::string& origin_url) {
  274. web_frame_->SetIsolatedWorldSecurityOrigin(
  275. world_id, blink::WebSecurityOrigin::CreateFromString(
  276. blink::WebString::FromUTF8(origin_url)));
  277. }
  278. void WebFrame::SetIsolatedWorldContentSecurityPolicy(
  279. int world_id,
  280. const std::string& security_policy) {
  281. web_frame_->SetIsolatedWorldContentSecurityPolicy(
  282. world_id, blink::WebString::FromUTF8(security_policy));
  283. }
  284. void WebFrame::SetIsolatedWorldHumanReadableName(int world_id,
  285. const std::string& name) {
  286. web_frame_->SetIsolatedWorldHumanReadableName(
  287. world_id, blink::WebString::FromUTF8(name));
  288. }
  289. // static
  290. mate::Handle<WebFrame> WebFrame::Create(v8::Isolate* isolate) {
  291. return mate::CreateHandle(isolate, new WebFrame(isolate));
  292. }
  293. blink::WebCache::ResourceTypeStats WebFrame::GetResourceUsage(
  294. v8::Isolate* isolate) {
  295. blink::WebCache::ResourceTypeStats stats;
  296. blink::WebCache::GetResourceTypeStats(&stats);
  297. return stats;
  298. }
  299. void WebFrame::ClearCache(v8::Isolate* isolate) {
  300. isolate->IdleNotificationDeadline(0.5);
  301. blink::WebCache::Clear();
  302. base::MemoryPressureListener::NotifyMemoryPressure(
  303. base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
  304. }
  305. v8::Local<v8::Value> WebFrame::Opener() const {
  306. blink::WebFrame* frame = web_frame_->Opener();
  307. if (frame && frame->IsWebLocalFrame())
  308. return mate::CreateHandle(isolate(),
  309. new WebFrame(isolate(), frame->ToWebLocalFrame()))
  310. .ToV8();
  311. else
  312. return v8::Null(isolate());
  313. }
  314. v8::Local<v8::Value> WebFrame::Parent() const {
  315. blink::WebFrame* frame = web_frame_->Parent();
  316. if (frame && frame->IsWebLocalFrame())
  317. return mate::CreateHandle(isolate(),
  318. new WebFrame(isolate(), frame->ToWebLocalFrame()))
  319. .ToV8();
  320. else
  321. return v8::Null(isolate());
  322. }
  323. v8::Local<v8::Value> WebFrame::Top() const {
  324. blink::WebFrame* frame = web_frame_->Top();
  325. if (frame && frame->IsWebLocalFrame())
  326. return mate::CreateHandle(isolate(),
  327. new WebFrame(isolate(), frame->ToWebLocalFrame()))
  328. .ToV8();
  329. else
  330. return v8::Null(isolate());
  331. }
  332. v8::Local<v8::Value> WebFrame::FirstChild() const {
  333. blink::WebFrame* frame = web_frame_->FirstChild();
  334. if (frame && frame->IsWebLocalFrame())
  335. return mate::CreateHandle(isolate(),
  336. new WebFrame(isolate(), frame->ToWebLocalFrame()))
  337. .ToV8();
  338. else
  339. return v8::Null(isolate());
  340. }
  341. v8::Local<v8::Value> WebFrame::NextSibling() const {
  342. blink::WebFrame* frame = web_frame_->NextSibling();
  343. if (frame && frame->IsWebLocalFrame())
  344. return mate::CreateHandle(isolate(),
  345. new WebFrame(isolate(), frame->ToWebLocalFrame()))
  346. .ToV8();
  347. else
  348. return v8::Null(isolate());
  349. }
  350. v8::Local<v8::Value> WebFrame::GetFrameForSelector(
  351. const std::string& selector) const {
  352. blink::WebElement element = web_frame_->GetDocument().QuerySelector(
  353. blink::WebString::FromUTF8(selector));
  354. blink::WebLocalFrame* element_frame =
  355. blink::WebLocalFrame::FromFrameOwnerElement(element);
  356. if (element_frame)
  357. return mate::CreateHandle(isolate(), new WebFrame(isolate(), element_frame))
  358. .ToV8();
  359. else
  360. return v8::Null(isolate());
  361. }
  362. v8::Local<v8::Value> WebFrame::FindFrameByName(const std::string& name) const {
  363. blink::WebLocalFrame* local_frame =
  364. web_frame_->FindFrameByName(blink::WebString::FromUTF8(name))
  365. ->ToWebLocalFrame();
  366. if (local_frame)
  367. return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame))
  368. .ToV8();
  369. else
  370. return v8::Null(isolate());
  371. }
  372. v8::Local<v8::Value> WebFrame::FindFrameByRoutingId(int routing_id) const {
  373. content::RenderFrame* render_frame =
  374. content::RenderFrame::FromRoutingID(routing_id);
  375. blink::WebLocalFrame* local_frame = nullptr;
  376. if (render_frame)
  377. local_frame = render_frame->GetWebFrame();
  378. if (local_frame)
  379. return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame))
  380. .ToV8();
  381. else
  382. return v8::Null(isolate());
  383. }
  384. v8::Local<v8::Value> WebFrame::RoutingId() const {
  385. int routing_id = content::RenderFrame::GetRoutingIdForWebFrame(web_frame_);
  386. return v8::Number::New(isolate(), routing_id);
  387. }
  388. // static
  389. void WebFrame::BuildPrototype(v8::Isolate* isolate,
  390. v8::Local<v8::FunctionTemplate> prototype) {
  391. prototype->SetClassName(mate::StringToV8(isolate, "WebFrame"));
  392. mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
  393. .SetMethod("setName", &WebFrame::SetName)
  394. .SetMethod("setZoomLevel", &WebFrame::SetZoomLevel)
  395. .SetMethod("getZoomLevel", &WebFrame::GetZoomLevel)
  396. .SetMethod("setZoomFactor", &WebFrame::SetZoomFactor)
  397. .SetMethod("getZoomFactor", &WebFrame::GetZoomFactor)
  398. .SetMethod("setVisualZoomLevelLimits",
  399. &WebFrame::SetVisualZoomLevelLimits)
  400. .SetMethod("setLayoutZoomLevelLimits",
  401. &WebFrame::SetLayoutZoomLevelLimits)
  402. .SetMethod("registerEmbedderCustomElement",
  403. &WebFrame::RegisterEmbedderCustomElement)
  404. .SetMethod("registerElementResizeCallback",
  405. &WebFrame::RegisterElementResizeCallback)
  406. .SetMethod("attachGuest", &WebFrame::AttachGuest)
  407. .SetMethod("detachGuest", &WebFrame::DetachGuest)
  408. .SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider)
  409. .SetMethod("registerURLSchemeAsBypassingCSP",
  410. &WebFrame::RegisterURLSchemeAsBypassingCSP)
  411. .SetMethod("registerURLSchemeAsPrivileged",
  412. &WebFrame::RegisterURLSchemeAsPrivileged)
  413. .SetMethod("insertText", &WebFrame::InsertText)
  414. .SetMethod("insertCSS", &WebFrame::InsertCSS)
  415. .SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript)
  416. .SetMethod("executeJavaScriptInIsolatedWorld",
  417. &WebFrame::ExecuteJavaScriptInIsolatedWorld)
  418. .SetMethod("setIsolatedWorldSecurityOrigin",
  419. &WebFrame::SetIsolatedWorldSecurityOrigin)
  420. .SetMethod("setIsolatedWorldContentSecurityPolicy",
  421. &WebFrame::SetIsolatedWorldContentSecurityPolicy)
  422. .SetMethod("setIsolatedWorldHumanReadableName",
  423. &WebFrame::SetIsolatedWorldHumanReadableName)
  424. .SetMethod("getResourceUsage", &WebFrame::GetResourceUsage)
  425. .SetMethod("clearCache", &WebFrame::ClearCache)
  426. .SetMethod("getFrameForSelector", &WebFrame::GetFrameForSelector)
  427. .SetMethod("findFrameByName", &WebFrame::FindFrameByName)
  428. .SetProperty("opener", &WebFrame::Opener)
  429. .SetProperty("parent", &WebFrame::Parent)
  430. .SetProperty("top", &WebFrame::Top)
  431. .SetProperty("firstChild", &WebFrame::FirstChild)
  432. .SetProperty("nextSibling", &WebFrame::NextSibling)
  433. .SetProperty("routingId", &WebFrame::RoutingId)
  434. .SetMethod("findFrameByRoutingId", &WebFrame::FindFrameByRoutingId);
  435. }
  436. } // namespace api
  437. } // namespace atom
  438. namespace {
  439. using atom::api::WebFrame;
  440. void Initialize(v8::Local<v8::Object> exports,
  441. v8::Local<v8::Value> unused,
  442. v8::Local<v8::Context> context,
  443. void* priv) {
  444. v8::Isolate* isolate = context->GetIsolate();
  445. mate::Dictionary dict(isolate, exports);
  446. dict.Set("webFrame", WebFrame::Create(isolate));
  447. dict.Set("WebFrame", WebFrame::GetConstructor(isolate)->GetFunction());
  448. }
  449. } // namespace
  450. NODE_BUILTIN_MODULE_CONTEXT_AWARE(atom_renderer_web_frame, Initialize)