guest_view_base.cc 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/guest_view/browser/guest_view_base.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/lazy_instance.h"
  9. #include "base/memory/ptr_util.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "components/guest_view/browser/guest_view_event.h"
  12. #include "components/guest_view/browser/guest_view_manager.h"
  13. #include "components/guest_view/common/guest_view_constants.h"
  14. #include "components/zoom/zoom_controller.h"
  15. #include "content/public/browser/file_select_listener.h"
  16. #include "content/public/browser/navigation_handle.h"
  17. #include "content/public/browser/render_process_host.h"
  18. #include "content/public/browser/render_view_host.h"
  19. #include "content/public/browser/render_widget_host.h"
  20. #include "content/public/browser/render_widget_host_view.h"
  21. #include "content/public/browser/site_instance.h"
  22. #include "content/public/browser/web_contents.h"
  23. #include "third_party/blink/public/common/input/web_gesture_event.h"
  24. #include "third_party/blink/public/common/page/page_zoom.h"
  25. using content::WebContents;
  26. namespace guest_view {
  27. namespace {
  28. using WebContentsGuestViewMap = std::map<const WebContents*, GuestViewBase*>;
  29. base::LazyInstance<WebContentsGuestViewMap>::Leaky g_webcontents_guestview_map =
  30. LAZY_INSTANCE_INITIALIZER;
  31. } // namespace
  32. SetSizeParams::SetSizeParams() = default;
  33. SetSizeParams::~SetSizeParams() = default;
  34. // TODO(832879): It would be better to have proper ownership semantics than
  35. // manually destroying guests and their WebContents.
  36. //
  37. // This observer ensures that the GuestViewBase destroys itself when its
  38. // embedder goes away. It also tracks when the embedder's fullscreen is
  39. // toggled so the guest can change itself accordingly.
  40. class GuestViewBase::OwnerContentsObserver : public WebContentsObserver {
  41. public:
  42. OwnerContentsObserver(GuestViewBase* guest,
  43. WebContents* embedder_web_contents)
  44. : WebContentsObserver(embedder_web_contents),
  45. is_fullscreen_(false),
  46. destroyed_(false),
  47. guest_(guest) {}
  48. OwnerContentsObserver(const OwnerContentsObserver&) = delete;
  49. OwnerContentsObserver& operator=(const OwnerContentsObserver&) = delete;
  50. ~OwnerContentsObserver() override = default;
  51. // WebContentsObserver implementation.
  52. void WebContentsDestroyed() override {
  53. // If the embedder is destroyed then destroy the guest.
  54. Destroy();
  55. }
  56. void PrimaryPageChanged(content::Page& page) override {
  57. // TODO(1206312, 1205920): It is incorrect to assume that a navigation will
  58. // destroy the embedder.
  59. // If the embedder navigates to a different page then destroy the guest.
  60. Destroy();
  61. }
  62. void PrimaryMainFrameRenderProcessGone(
  63. base::TerminationStatus status) override {
  64. if (destroyed_)
  65. return;
  66. // If the embedder process is destroyed, then destroy the guest.
  67. Destroy();
  68. }
  69. void DidToggleFullscreenModeForTab(bool entered_fullscreen,
  70. bool will_cause_resize) override {
  71. if (destroyed_)
  72. return;
  73. is_fullscreen_ = entered_fullscreen;
  74. guest_->EmbedderFullscreenToggled(is_fullscreen_);
  75. }
  76. void PrimaryMainFrameWasResized(bool width_changed) override {
  77. if (destroyed_ || !web_contents()->GetDelegate())
  78. return;
  79. bool current_fullscreen =
  80. web_contents()->GetDelegate()->IsFullscreenForTabOrPending(
  81. web_contents());
  82. if (is_fullscreen_ && !current_fullscreen) {
  83. is_fullscreen_ = false;
  84. guest_->EmbedderFullscreenToggled(is_fullscreen_);
  85. }
  86. }
  87. void DidUpdateAudioMutingState(bool muted) override {
  88. if (destroyed_)
  89. return;
  90. guest_->web_contents()->SetAudioMuted(muted);
  91. }
  92. void RenderFrameDeleted(content::RenderFrameHost* rfh) override {
  93. guest_->OnRenderFrameHostDeleted(rfh->GetProcess()->GetID(),
  94. rfh->GetRoutingID());
  95. }
  96. private:
  97. bool is_fullscreen_;
  98. bool destroyed_;
  99. raw_ptr<GuestViewBase> guest_;
  100. void Destroy() {
  101. if (destroyed_)
  102. return;
  103. destroyed_ = true;
  104. // The outer WebContents have ownership of attached OOPIF-based guests, so
  105. // we are not responsible for their deletion.
  106. bool also_delete = !guest_->web_contents()->GetOuterWebContents();
  107. guest_->Destroy(also_delete);
  108. }
  109. };
  110. // This observer ensures that the GuestViewBase destroys itself if its opener
  111. // WebContents goes away before the GuestViewBase is attached.
  112. class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
  113. public:
  114. explicit OpenerLifetimeObserver(GuestViewBase* guest)
  115. : WebContentsObserver(guest->GetOpener()->web_contents()),
  116. guest_(guest) {}
  117. OpenerLifetimeObserver(const OpenerLifetimeObserver&) = delete;
  118. OpenerLifetimeObserver& operator=(const OpenerLifetimeObserver&) = delete;
  119. ~OpenerLifetimeObserver() override = default;
  120. // WebContentsObserver implementation.
  121. void WebContentsDestroyed() override {
  122. if (guest_->attached())
  123. return;
  124. // If the opener is destroyed then destroy the guest.
  125. guest_->Destroy(true);
  126. }
  127. private:
  128. raw_ptr<GuestViewBase> guest_;
  129. };
  130. GuestViewBase::GuestViewBase(WebContents* owner_web_contents)
  131. : owner_web_contents_(owner_web_contents),
  132. browser_context_(owner_web_contents->GetBrowserContext()),
  133. guest_instance_id_(GetGuestViewManager()->GetNextInstanceID()),
  134. view_instance_id_(kInstanceIDNone),
  135. element_instance_id_(kInstanceIDNone),
  136. attach_in_progress_(false),
  137. initialized_(false),
  138. is_being_destroyed_(false),
  139. guest_host_(nullptr),
  140. auto_size_enabled_(false),
  141. is_full_page_plugin_(false) {
  142. SetOwnerHost();
  143. }
  144. GuestViewBase::~GuestViewBase() {}
  145. void GuestViewBase::Init(const base::Value::Dict& create_params,
  146. WebContentsCreatedCallback callback) {
  147. if (initialized_)
  148. return;
  149. initialized_ = true;
  150. if (!GetGuestViewManager()->IsGuestAvailableToContext(this)) {
  151. // The derived class did not create a WebContents so this class serves no
  152. // purpose. Let's self-destruct.
  153. delete this;
  154. std::move(callback).Run(nullptr);
  155. return;
  156. }
  157. CreateWebContents(create_params,
  158. base::BindOnce(&GuestViewBase::CompleteInit,
  159. weak_ptr_factory_.GetWeakPtr(),
  160. create_params.Clone(), std::move(callback)));
  161. }
  162. void GuestViewBase::InitWithWebContents(const base::Value::Dict& create_params,
  163. WebContents* guest_web_contents) {
  164. DCHECK(guest_web_contents);
  165. // Create a ZoomController to allow the guest's contents to be zoomed.
  166. // Do this before adding the GuestView as a WebContents Observer so that
  167. // the GuestView and its derived classes can re-configure the ZoomController
  168. // after the latter has handled WebContentsObserver events (observers are
  169. // notified of events in the same order they are added as observers). For
  170. // example, GuestViewBase may wish to put its guest into isolated zoom mode
  171. // in DidFinishNavigation, but since ZoomController always resets to default
  172. // zoom mode on this event, GuestViewBase would need to do so after
  173. // ZoomController::DidFinishNavigation has completed.
  174. zoom::ZoomController::CreateForWebContents(guest_web_contents);
  175. // At this point, we have just created the guest WebContents, we need to add
  176. // an observer to the owner WebContents. This observer will be responsible
  177. // for destroying the guest WebContents if the owner goes away.
  178. owner_contents_observer_ =
  179. std::make_unique<OwnerContentsObserver>(this, owner_web_contents_);
  180. WebContentsObserver::Observe(guest_web_contents);
  181. guest_web_contents->SetDelegate(this);
  182. g_webcontents_guestview_map.Get().insert(
  183. std::make_pair(guest_web_contents, this));
  184. GetGuestViewManager()->AddGuest(guest_instance_id_, guest_web_contents);
  185. // Populate the view instance ID if we have it on creation.
  186. view_instance_id_ =
  187. create_params.FindInt(kParameterInstanceId).value_or(view_instance_id_);
  188. SetUpSizing(create_params);
  189. // Observe guest zoom changes.
  190. auto* zoom_controller = zoom::ZoomController::FromWebContents(web_contents());
  191. zoom_controller->AddObserver(this);
  192. // Give the derived class an opportunity to perform additional initialization.
  193. DidInitialize(create_params);
  194. }
  195. void GuestViewBase::DispatchOnResizeEvent(const gfx::Size& old_size,
  196. const gfx::Size& new_size) {
  197. if (new_size == old_size)
  198. return;
  199. // Dispatch the onResize event.
  200. auto args = std::make_unique<base::DictionaryValue>();
  201. args->SetInteger(kOldWidth, old_size.width());
  202. args->SetInteger(kOldHeight, old_size.height());
  203. args->SetInteger(kNewWidth, new_size.width());
  204. args->SetInteger(kNewHeight, new_size.height());
  205. DispatchEventToGuestProxy(
  206. std::make_unique<GuestViewEvent>(kEventResize, std::move(args)));
  207. }
  208. gfx::Size GuestViewBase::GetDefaultSize() const {
  209. if (!is_full_page_plugin())
  210. return gfx::Size(kDefaultWidth, kDefaultHeight);
  211. // Full page plugins default to the size of the owner's viewport.
  212. return owner_web_contents()
  213. ->GetRenderWidgetHostView()
  214. ->GetVisibleViewportSize();
  215. }
  216. void GuestViewBase::SetSize(const SetSizeParams& params) {
  217. bool enable_auto_size =
  218. params.enable_auto_size ? *params.enable_auto_size : auto_size_enabled_;
  219. gfx::Size min_size = params.min_size ? *params.min_size : min_auto_size_;
  220. gfx::Size max_size = params.max_size ? *params.max_size : max_auto_size_;
  221. if (params.normal_size)
  222. normal_size_ = *params.normal_size;
  223. min_auto_size_ = min_size;
  224. min_auto_size_.SetToMin(max_size);
  225. max_auto_size_ = max_size;
  226. max_auto_size_.SetToMax(min_size);
  227. enable_auto_size &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() &&
  228. IsAutoSizeSupported();
  229. content::RenderWidgetHostView* rwhv =
  230. web_contents()->GetRenderWidgetHostView();
  231. if (enable_auto_size) {
  232. // Autosize is being enabled.
  233. if (rwhv)
  234. rwhv->EnableAutoResize(min_auto_size_, max_auto_size_);
  235. normal_size_.SetSize(0, 0);
  236. } else {
  237. // Autosize is being disabled.
  238. // Use default width/height if missing from partially defined normal size.
  239. if (normal_size_.width() && !normal_size_.height())
  240. normal_size_.set_height(GetDefaultSize().height());
  241. if (!normal_size_.width() && normal_size_.height())
  242. normal_size_.set_width(GetDefaultSize().width());
  243. gfx::Size new_size;
  244. if (!normal_size_.IsEmpty()) {
  245. new_size = normal_size_;
  246. } else if (!guest_size_.IsEmpty()) {
  247. new_size = guest_size_;
  248. } else {
  249. new_size = GetDefaultSize();
  250. }
  251. bool changed_due_to_auto_resize = false;
  252. if (auto_size_enabled_) {
  253. // Autosize was previously enabled.
  254. if (rwhv)
  255. rwhv->DisableAutoResize(new_size);
  256. changed_due_to_auto_resize = true;
  257. } else {
  258. // Autosize was already disabled. The RenderWidgetHostView is responsible
  259. // for the GuestView's size.
  260. }
  261. UpdateGuestSize(new_size, changed_due_to_auto_resize);
  262. }
  263. auto_size_enabled_ = enable_auto_size;
  264. }
  265. // static
  266. GuestViewBase* GuestViewBase::FromWebContents(const WebContents* web_contents) {
  267. WebContentsGuestViewMap* guest_map = g_webcontents_guestview_map.Pointer();
  268. auto it = guest_map->find(web_contents);
  269. return it == guest_map->end() ? nullptr : it->second;
  270. }
  271. // static
  272. GuestViewBase* GuestViewBase::From(int owner_process_id,
  273. int guest_instance_id) {
  274. auto* host = content::RenderProcessHost::FromID(owner_process_id);
  275. if (!host)
  276. return nullptr;
  277. WebContents* guest_web_contents =
  278. GuestViewManager::FromBrowserContext(host->GetBrowserContext())
  279. ->GetGuestByInstanceIDSafely(guest_instance_id, owner_process_id);
  280. if (!guest_web_contents)
  281. return nullptr;
  282. return GuestViewBase::FromWebContents(guest_web_contents);
  283. }
  284. // static
  285. WebContents* GuestViewBase::GetTopLevelWebContents(WebContents* web_contents) {
  286. while (GuestViewBase* guest = FromWebContents(web_contents))
  287. web_contents = guest->owner_web_contents();
  288. return web_contents;
  289. }
  290. // static
  291. bool GuestViewBase::IsGuest(WebContents* web_contents) {
  292. return !!GuestViewBase::FromWebContents(web_contents);
  293. }
  294. bool GuestViewBase::IsAutoSizeSupported() const {
  295. return false;
  296. }
  297. bool GuestViewBase::IsPreferredSizeModeEnabled() const {
  298. return false;
  299. }
  300. bool GuestViewBase::ZoomPropagatesFromEmbedderToGuest() const {
  301. return true;
  302. }
  303. GuestViewManager* GuestViewBase::GetGuestViewManager() {
  304. return GuestViewManager::FromBrowserContext(browser_context());
  305. }
  306. WebContents* GuestViewBase::CreateNewGuestWindow(
  307. const WebContents::CreateParams& create_params) {
  308. return GetGuestViewManager()->CreateGuestWithWebContentsParams(
  309. GetViewType(), owner_web_contents(), create_params);
  310. }
  311. void GuestViewBase::OnRenderFrameHostDeleted(int process_id, int routing_id) {}
  312. void GuestViewBase::DidAttach() {
  313. DCHECK(attach_in_progress_);
  314. // Clear this flag here, as functions called below may check attached().
  315. attach_in_progress_ = false;
  316. opener_lifetime_observer_.reset();
  317. SetUpSizing(attach_params());
  318. // The guest should have the same muting state as the owner.
  319. web_contents()->SetAudioMuted(owner_web_contents()->IsAudioMuted());
  320. // Give the derived class an opportunity to perform some actions.
  321. DidAttachToEmbedder();
  322. SendQueuedEvents();
  323. }
  324. WebContents* GuestViewBase::GetOwnerWebContents() {
  325. return owner_web_contents_;
  326. }
  327. const GURL& GuestViewBase::GetOwnerSiteURL() const {
  328. return owner_web_contents()
  329. ->GetPrimaryMainFrame()
  330. ->GetSiteInstance()
  331. ->GetSiteURL();
  332. }
  333. void GuestViewBase::Destroy(bool also_delete) {
  334. if (is_being_destroyed_)
  335. return;
  336. is_being_destroyed_ = true;
  337. // It is important to clear owner_web_contents_ after the call to
  338. // StopTrackingEmbedderZoomLevel(), but before the rest of
  339. // the statements in this function.
  340. StopTrackingEmbedderZoomLevel();
  341. owner_web_contents_ = nullptr;
  342. DCHECK(web_contents());
  343. // Give the derived class an opportunity to perform some cleanup.
  344. WillDestroy();
  345. // Invalidate weak pointers now so that bound callbacks cannot be called late
  346. // into destruction. We must call this after WillDestroy because derived types
  347. // may wish to access their openers.
  348. weak_ptr_factory_.InvalidateWeakPtrs();
  349. // Give the content module an opportunity to perform some cleanup.
  350. guest_host_->WillDestroy();
  351. guest_host_ = nullptr;
  352. g_webcontents_guestview_map.Get().erase(web_contents());
  353. GetGuestViewManager()->RemoveGuest(guest_instance_id_);
  354. pending_events_.clear();
  355. if (also_delete)
  356. delete web_contents();
  357. }
  358. void GuestViewBase::SetAttachParams(const base::Value::Dict& params) {
  359. attach_params_ = params.Clone();
  360. view_instance_id_ =
  361. attach_params_.FindInt(kParameterInstanceId).value_or(view_instance_id_);
  362. }
  363. void GuestViewBase::SetOpener(GuestViewBase* guest) {
  364. if (guest) {
  365. opener_ = guest->weak_ptr_factory_.GetWeakPtr();
  366. if (!attached()) {
  367. opener_lifetime_observer_ =
  368. std::make_unique<OpenerLifetimeObserver>(this);
  369. }
  370. } else {
  371. opener_ = base::WeakPtr<GuestViewBase>();
  372. opener_lifetime_observer_.reset();
  373. }
  374. }
  375. void GuestViewBase::SetGuestHost(content::GuestHost* guest_host) {
  376. guest_host_ = guest_host;
  377. }
  378. void GuestViewBase::WillAttach(WebContents* embedder_web_contents,
  379. int element_instance_id,
  380. bool is_full_page_plugin,
  381. base::OnceClosure completion_callback) {
  382. WillAttach(embedder_web_contents, nullptr, element_instance_id,
  383. is_full_page_plugin, std::move(completion_callback),
  384. base::NullCallback());
  385. }
  386. void GuestViewBase::WillAttach(
  387. WebContents* embedder_web_contents,
  388. content::RenderFrameHost* outer_contents_frame,
  389. int element_instance_id,
  390. bool is_full_page_plugin,
  391. base::OnceClosure completion_callback,
  392. GuestViewMessageHandler::AttachToEmbedderFrameCallback
  393. attachment_callback) {
  394. // Stop tracking the old embedder's zoom level.
  395. if (owner_web_contents())
  396. StopTrackingEmbedderZoomLevel();
  397. if (owner_web_contents_ != embedder_web_contents) {
  398. DCHECK_EQ(owner_contents_observer_->web_contents(), owner_web_contents_);
  399. owner_web_contents_ = embedder_web_contents;
  400. owner_contents_observer_ =
  401. std::make_unique<OwnerContentsObserver>(this, embedder_web_contents);
  402. SetOwnerHost();
  403. }
  404. // Start tracking the new embedder's zoom level.
  405. StartTrackingEmbedderZoomLevel();
  406. attach_in_progress_ = true;
  407. element_instance_id_ = element_instance_id;
  408. is_full_page_plugin_ = is_full_page_plugin;
  409. WillAttachToEmbedder();
  410. web_contents()->ResumeLoadingCreatedWebContents();
  411. // Since this inner WebContents is created from the browser side we do
  412. // not have RemoteFrame mojo channels so we pass in
  413. // NullAssociatedRemote/Receivers. New channels will be bound when the
  414. // `CreateView` IPC is sent.
  415. owner_web_contents_->AttachInnerWebContents(
  416. base::WrapUnique<WebContents>(web_contents()), outer_contents_frame,
  417. /*remote_frame=*/mojo::NullAssociatedRemote(),
  418. /*remote_frame_host_receiver=*/mojo::NullAssociatedReceiver(),
  419. is_full_page_plugin);
  420. // We don't ACK until after AttachToOuterWebContentsFrame, so that
  421. // |outer_contents_frame| gets swapped before the AttachToEmbedderFrame
  422. // callback is run. We also need to send the ACK before queued events are sent
  423. // in DidAttach.
  424. if (attachment_callback)
  425. std::move(attachment_callback).Run();
  426. // Completing attachment will resume suspended resource loads and then send
  427. // queued events.
  428. SignalWhenReady(std::move(completion_callback));
  429. }
  430. void GuestViewBase::SignalWhenReady(base::OnceClosure callback) {
  431. // The default behavior is to call the |callback| immediately. Derived classes
  432. // can implement an alternative signal for readiness.
  433. std::move(callback).Run();
  434. }
  435. int GuestViewBase::LogicalPixelsToPhysicalPixels(double logical_pixels) const {
  436. DCHECK(logical_pixels >= 0);
  437. double zoom_factor = GetEmbedderZoomFactor();
  438. return lround(logical_pixels * zoom_factor);
  439. }
  440. double GuestViewBase::PhysicalPixelsToLogicalPixels(int physical_pixels) const {
  441. DCHECK(physical_pixels >= 0);
  442. double zoom_factor = GetEmbedderZoomFactor();
  443. return physical_pixels / zoom_factor;
  444. }
  445. void GuestViewBase::DidStopLoading() {
  446. content::RenderViewHost* rvh =
  447. web_contents()->GetPrimaryMainFrame()->GetRenderViewHost();
  448. if (IsPreferredSizeModeEnabled())
  449. rvh->EnablePreferredSizeMode();
  450. GuestViewDidStopLoading();
  451. }
  452. void GuestViewBase::RenderViewReady() {
  453. GuestReady();
  454. }
  455. void GuestViewBase::WebContentsDestroyed() {
  456. Destroy(false);
  457. // Let the derived class know that its WebContents is in the process of
  458. // being destroyed. web_contents() is still valid at this point.
  459. // TODO(fsamuel): This allows for reentrant code into WebContents during
  460. // destruction. This could potentially lead to bugs. Perhaps we should get rid
  461. // of this?
  462. GuestDestroyed();
  463. // Self-destruct.
  464. delete this;
  465. }
  466. void GuestViewBase::DidFinishNavigation(
  467. content::NavigationHandle* navigation_handle) {
  468. // TODO(crbug.com/1261928): Due to the use of inner WebContents, a
  469. // GuestViewBase's main frame is considered primary. This will no
  470. // longer be the case once we migrate guest views to MPArch.
  471. if (!navigation_handle->IsInPrimaryMainFrame() ||
  472. !navigation_handle->HasCommitted())
  473. return;
  474. if (attached() && ZoomPropagatesFromEmbedderToGuest())
  475. SetGuestZoomLevelToMatchEmbedder();
  476. }
  477. void GuestViewBase::ActivateContents(WebContents* web_contents) {
  478. if (!attached() || !embedder_web_contents()->GetDelegate())
  479. return;
  480. embedder_web_contents()->GetDelegate()->ActivateContents(
  481. embedder_web_contents());
  482. }
  483. void GuestViewBase::ContentsMouseEvent(WebContents* source,
  484. bool motion,
  485. bool exited) {
  486. if (!attached() || !embedder_web_contents()->GetDelegate())
  487. return;
  488. embedder_web_contents()->GetDelegate()->ContentsMouseEvent(
  489. embedder_web_contents(), motion, exited);
  490. }
  491. void GuestViewBase::ContentsZoomChange(bool zoom_in) {
  492. if (!attached() || !embedder_web_contents()->GetDelegate())
  493. return;
  494. embedder_web_contents()->GetDelegate()->ContentsZoomChange(zoom_in);
  495. }
  496. bool GuestViewBase::HandleKeyboardEvent(
  497. WebContents* source,
  498. const content::NativeWebKeyboardEvent& event) {
  499. if (!attached() || !embedder_web_contents()->GetDelegate())
  500. return false;
  501. // Send the keyboard events back to the embedder to reprocess them.
  502. return embedder_web_contents()->GetDelegate()->HandleKeyboardEvent(
  503. embedder_web_contents(), event);
  504. }
  505. void GuestViewBase::LoadingStateChanged(WebContents* source,
  506. bool should_show_loading_ui) {
  507. if (!attached() || !embedder_web_contents()->GetDelegate())
  508. return;
  509. embedder_web_contents()->GetDelegate()->LoadingStateChanged(
  510. embedder_web_contents(), should_show_loading_ui);
  511. }
  512. void GuestViewBase::ResizeDueToAutoResize(WebContents* web_contents,
  513. const gfx::Size& new_size) {
  514. UpdateGuestSize(new_size, auto_size_enabled_);
  515. }
  516. void GuestViewBase::RunFileChooser(
  517. content::RenderFrameHost* render_frame_host,
  518. scoped_refptr<content::FileSelectListener> listener,
  519. const blink::mojom::FileChooserParams& params) {
  520. if (!attached() || !embedder_web_contents()->GetDelegate()) {
  521. listener->FileSelectionCanceled();
  522. return;
  523. }
  524. embedder_web_contents()->GetDelegate()->RunFileChooser(
  525. render_frame_host, std::move(listener), params);
  526. }
  527. bool GuestViewBase::ShouldFocusPageAfterCrash() {
  528. // Focus is managed elsewhere.
  529. return false;
  530. }
  531. bool GuestViewBase::PreHandleGestureEvent(WebContents* source,
  532. const blink::WebGestureEvent& event) {
  533. // Pinch events which cause a scale change should not be routed to a guest.
  534. // We still allow synthetic wheel events for touchpad pinch to go to the page.
  535. DCHECK(!blink::WebInputEvent::IsPinchGestureEventType(event.GetType()) ||
  536. (event.SourceDevice() == blink::WebGestureDevice::kTouchpad &&
  537. event.NeedsWheelEvent()));
  538. return false;
  539. }
  540. void GuestViewBase::UpdatePreferredSize(WebContents* target_web_contents,
  541. const gfx::Size& pref_size) {
  542. // In theory it's not necessary to check IsPreferredSizeModeEnabled() because
  543. // there will only be events if it was enabled in the first place. However,
  544. // something else may have turned on preferred size mode, so double check.
  545. DCHECK_EQ(web_contents(), target_web_contents);
  546. if (IsPreferredSizeModeEnabled()) {
  547. OnPreferredSizeChanged(pref_size);
  548. }
  549. }
  550. content::WebContents* GuestViewBase::GetResponsibleWebContents(
  551. content::WebContents* source) {
  552. return owner_web_contents();
  553. }
  554. void GuestViewBase::UpdateTargetURL(WebContents* source, const GURL& url) {
  555. if (!attached() || !embedder_web_contents()->GetDelegate())
  556. return;
  557. embedder_web_contents()->GetDelegate()->UpdateTargetURL(
  558. embedder_web_contents(), url);
  559. }
  560. bool GuestViewBase::ShouldResumeRequestsForCreatedWindow() {
  561. // Delay so that the embedder page has a chance to call APIs such as
  562. // webRequest in time to be applied to the initial navigation in the new guest
  563. // contents. We resume during WillAttach.
  564. return false;
  565. }
  566. content::RenderWidgetHost* GuestViewBase::GetOwnerRenderWidgetHost() {
  567. // We assume guests live inside an owner RenderFrame but the RenderFrame may
  568. // not be cross-process. In case a type of guest should be allowed to be
  569. // embedded in a cross-process frame, this method should be overrode for that
  570. // specific guest type. For all other guests, the owner RenderWidgetHost is
  571. // that of the owner WebContents.
  572. DCHECK(!CanBeEmbeddedInsideCrossProcessFrames());
  573. auto* owner = GetOwnerWebContents();
  574. if (owner && owner->GetRenderWidgetHostView())
  575. return owner->GetRenderWidgetHostView()->GetRenderWidgetHost();
  576. return nullptr;
  577. }
  578. content::SiteInstance* GuestViewBase::GetOwnerSiteInstance() {
  579. // We assume guests live inside an owner RenderFrame but the RenderFrame may
  580. // not be cross-process. In case a type of guest should be allowed to be
  581. // embedded in a cross-process frame, this method should be overrode for that
  582. // specific guest type. For all other guests, the owner site instance can be
  583. // from the owner WebContents.
  584. DCHECK(!CanBeEmbeddedInsideCrossProcessFrames());
  585. if (auto* owner_contents = GetOwnerWebContents())
  586. return owner_contents->GetSiteInstance();
  587. return nullptr;
  588. }
  589. void GuestViewBase::AttachToOuterWebContentsFrame(
  590. content::RenderFrameHost* embedder_frame,
  591. int32_t element_instance_id,
  592. bool is_full_page_plugin,
  593. GuestViewMessageHandler::AttachToEmbedderFrameCallback
  594. attachment_callback) {
  595. auto completion_callback =
  596. base::BindOnce(&GuestViewBase::DidAttach, weak_ptr_factory_.GetWeakPtr());
  597. WillAttach(WebContents::FromRenderFrameHost(embedder_frame), embedder_frame,
  598. element_instance_id, is_full_page_plugin,
  599. std::move(completion_callback), std::move(attachment_callback));
  600. }
  601. void GuestViewBase::OnZoomChanged(
  602. const zoom::ZoomController::ZoomChangedEventData& data) {
  603. if (data.web_contents == embedder_web_contents()) {
  604. // The embedder's zoom level has changed.
  605. auto* guest_zoom_controller =
  606. zoom::ZoomController::FromWebContents(web_contents());
  607. if (blink::PageZoomValuesEqual(data.new_zoom_level,
  608. guest_zoom_controller->GetZoomLevel())) {
  609. return;
  610. }
  611. // When the embedder's zoom level doesn't match the guest's, then update the
  612. // guest's zoom level to match.
  613. guest_zoom_controller->SetZoomLevel(data.new_zoom_level);
  614. return;
  615. }
  616. if (data.web_contents == web_contents()) {
  617. // The guest's zoom level has changed.
  618. GuestZoomChanged(data.old_zoom_level, data.new_zoom_level);
  619. }
  620. }
  621. void GuestViewBase::DispatchEventToGuestProxy(
  622. std::unique_ptr<GuestViewEvent> event) {
  623. event->Dispatch(this, guest_instance_id_);
  624. }
  625. void GuestViewBase::DispatchEventToView(std::unique_ptr<GuestViewEvent> event) {
  626. if (attached() && pending_events_.empty()) {
  627. event->Dispatch(this, view_instance_id_);
  628. return;
  629. }
  630. pending_events_.push_back(std::move(event));
  631. }
  632. void GuestViewBase::SendQueuedEvents() {
  633. if (!attached())
  634. return;
  635. while (!pending_events_.empty()) {
  636. std::unique_ptr<GuestViewEvent> event_ptr =
  637. std::move(pending_events_.front());
  638. pending_events_.pop_front();
  639. event_ptr->Dispatch(this, view_instance_id_);
  640. }
  641. }
  642. void GuestViewBase::CompleteInit(base::Value::Dict create_params,
  643. WebContentsCreatedCallback callback,
  644. WebContents* guest_web_contents) {
  645. if (!guest_web_contents) {
  646. // The derived class did not create a WebContents so this class serves no
  647. // purpose. Let's self-destruct.
  648. delete this;
  649. std::move(callback).Run(nullptr);
  650. return;
  651. }
  652. InitWithWebContents(create_params, guest_web_contents);
  653. std::move(callback).Run(guest_web_contents);
  654. }
  655. double GuestViewBase::GetEmbedderZoomFactor() const {
  656. if (!embedder_web_contents())
  657. return 1.0;
  658. return blink::PageZoomLevelToZoomFactor(
  659. zoom::ZoomController::GetZoomLevelForWebContents(
  660. embedder_web_contents()));
  661. }
  662. void GuestViewBase::SetUpSizing(const base::Value::Dict& params) {
  663. // Read the autosize parameters passed in from the embedder.
  664. absl::optional<bool> auto_size_enabled_opt =
  665. params.FindBool(kAttributeAutoSize);
  666. bool auto_size_enabled = auto_size_enabled_opt.value_or(auto_size_enabled_);
  667. int max_height =
  668. params.FindInt(kAttributeMaxHeight).value_or(max_auto_size_.height());
  669. int max_width =
  670. params.FindInt(kAttributeMaxWidth).value_or(max_auto_size_.width());
  671. int min_height =
  672. params.FindInt(kAttributeMinHeight).value_or(min_auto_size_.height());
  673. int min_width =
  674. params.FindInt(kAttributeMinWidth).value_or(min_auto_size_.width());
  675. double element_height = params.FindDouble(kElementHeight).value_or(0.0);
  676. double element_width = params.FindDouble(kElementWidth).value_or(0.0);
  677. // Set the normal size to the element size so that the guestview will fit
  678. // the element initially if autosize is disabled.
  679. int normal_height = normal_size_.height();
  680. int normal_width = normal_size_.width();
  681. // If the element size was provided in logical units (versus physical), then
  682. // it will be converted to physical units.
  683. absl::optional<bool> element_size_is_logical_opt =
  684. params.FindBool(kElementSizeIsLogical);
  685. bool element_size_is_logical = element_size_is_logical_opt.value_or(false);
  686. if (element_size_is_logical) {
  687. // Convert the element size from logical pixels to physical pixels.
  688. normal_height = LogicalPixelsToPhysicalPixels(element_height);
  689. normal_width = LogicalPixelsToPhysicalPixels(element_width);
  690. } else {
  691. normal_height = lround(element_height);
  692. normal_width = lround(element_width);
  693. }
  694. SetSizeParams set_size_params;
  695. set_size_params.enable_auto_size = std::make_unique<bool>(auto_size_enabled);
  696. set_size_params.min_size = std::make_unique<gfx::Size>(min_width, min_height);
  697. set_size_params.max_size = std::make_unique<gfx::Size>(max_width, max_height);
  698. set_size_params.normal_size =
  699. std::make_unique<gfx::Size>(normal_width, normal_height);
  700. // Call SetSize to apply all the appropriate validation and clipping of
  701. // values.
  702. SetSize(set_size_params);
  703. }
  704. void GuestViewBase::SetGuestZoomLevelToMatchEmbedder() {
  705. auto* embedder_zoom_controller =
  706. zoom::ZoomController::FromWebContents(owner_web_contents());
  707. if (!embedder_zoom_controller)
  708. return;
  709. zoom::ZoomController::FromWebContents(web_contents())
  710. ->SetZoomLevel(embedder_zoom_controller->GetZoomLevel());
  711. }
  712. void GuestViewBase::StartTrackingEmbedderZoomLevel() {
  713. if (!ZoomPropagatesFromEmbedderToGuest())
  714. return;
  715. auto* embedder_zoom_controller =
  716. zoom::ZoomController::FromWebContents(owner_web_contents());
  717. // Chrome Apps do not have a ZoomController.
  718. if (!embedder_zoom_controller)
  719. return;
  720. // Listen to the embedder's zoom changes.
  721. embedder_zoom_controller->AddObserver(this);
  722. // Set the guest's initial zoom level to be equal to the embedder's.
  723. SetGuestZoomLevelToMatchEmbedder();
  724. }
  725. void GuestViewBase::StopTrackingEmbedderZoomLevel() {
  726. // TODO(wjmaclean): Remove the observer any time the GuestWebView transitions
  727. // from propagating to not-propagating the zoom from the embedder.
  728. auto* embedder_zoom_controller =
  729. zoom::ZoomController::FromWebContents(owner_web_contents());
  730. // Chrome Apps do not have a ZoomController.
  731. if (!embedder_zoom_controller)
  732. return;
  733. // It is safe to remove an observer that was never registed.
  734. embedder_zoom_controller->RemoveObserver(this);
  735. }
  736. void GuestViewBase::UpdateGuestSize(const gfx::Size& new_size,
  737. bool due_to_auto_resize) {
  738. if (due_to_auto_resize)
  739. GuestSizeChangedDueToAutoSize(guest_size_, new_size);
  740. DispatchOnResizeEvent(guest_size_, new_size);
  741. guest_size_ = new_size;
  742. }
  743. void GuestViewBase::SetOwnerHost() {
  744. auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
  745. owner_host_ = manager->IsOwnedByExtension(this)
  746. ? owner_web_contents()->GetLastCommittedURL().host()
  747. : std::string();
  748. }
  749. bool GuestViewBase::CanBeEmbeddedInsideCrossProcessFrames() const {
  750. return false;
  751. }
  752. content::RenderFrameHost* GuestViewBase::GetGuestMainFrame() const {
  753. // TODO(crbug/1261928): Migrate the implementation for MPArch.
  754. return web_contents()->GetPrimaryMainFrame();
  755. }
  756. } // namespace guest_view