frame_impl.cc 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407
  1. // Copyright 2018 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 "fuchsia_web/webengine/browser/frame_impl.h"
  5. #include <fuchsia/ui/gfx/cpp/fidl.h>
  6. #include <lib/fpromise/result.h>
  7. #include <lib/sys/cpp/component_context.h>
  8. #include <lib/ui/scenic/cpp/view_ref_pair.h>
  9. #include <algorithm>
  10. #include <limits>
  11. #include "base/bind.h"
  12. #include "base/callback_helpers.h"
  13. #include "base/command_line.h"
  14. #include "base/fuchsia/fuchsia_logging.h"
  15. #include "base/fuchsia/mem_buffer_util.h"
  16. #include "base/fuchsia/process_context.h"
  17. #include "base/json/json_writer.h"
  18. #include "base/metrics/user_metrics.h"
  19. #include "base/strings/strcat.h"
  20. #include "base/strings/string_piece.h"
  21. #include "base/strings/stringprintf.h"
  22. #include "base/strings/utf_string_conversions.h"
  23. #include "base/threading/thread_task_runner_handle.h"
  24. #include "content/public/browser/browser_accessibility_state.h"
  25. #include "content/public/browser/browser_context.h"
  26. #include "content/public/browser/browser_task_traits.h"
  27. #include "content/public/browser/browser_thread.h"
  28. #include "content/public/browser/host_zoom_map.h"
  29. #include "content/public/browser/media_session.h"
  30. #include "content/public/browser/message_port_provider.h"
  31. #include "content/public/browser/navigation_entry.h"
  32. #include "content/public/browser/navigation_handle.h"
  33. #include "content/public/browser/permission_controller.h"
  34. #include "content/public/browser/render_frame_host.h"
  35. #include "content/public/browser/render_process_host.h"
  36. #include "content/public/browser/render_view_host.h"
  37. #include "content/public/browser/render_widget_host.h"
  38. #include "content/public/browser/render_widget_host_view.h"
  39. #include "content/public/browser/renderer_preferences_util.h"
  40. #include "content/public/browser/web_contents.h"
  41. #include "fuchsia_web/webengine/browser/accessibility_bridge.h"
  42. #include "fuchsia_web/webengine/browser/context_impl.h"
  43. #include "fuchsia_web/webengine/browser/event_filter.h"
  44. #include "fuchsia_web/webengine/browser/frame_layout_manager.h"
  45. #include "fuchsia_web/webengine/browser/frame_window_tree_host.h"
  46. #include "fuchsia_web/webengine/browser/media_player_impl.h"
  47. #include "fuchsia_web/webengine/browser/message_port.h"
  48. #include "fuchsia_web/webengine/browser/navigation_policy_handler.h"
  49. #include "fuchsia_web/webengine/browser/receiver_session_client.h"
  50. #include "fuchsia_web/webengine/browser/url_request_rewrite_type_converters.h"
  51. #include "fuchsia_web/webengine/browser/web_engine_devtools_controller.h"
  52. #include "fuchsia_web/webengine/common/cast_streaming.h"
  53. #include "mojo/public/cpp/bindings/associated_remote.h"
  54. #include "mojo/public/cpp/system/platform_handle.h"
  55. #include "net/base/net_errors.h"
  56. #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
  57. #include "third_party/blink/public/common/logging/logging_utils.h"
  58. #include "third_party/blink/public/common/messaging/web_message_port.h"
  59. #include "third_party/blink/public/common/page/page_zoom.h"
  60. #include "third_party/blink/public/common/permissions/permission_utils.h"
  61. #include "third_party/blink/public/common/web_preferences/web_preferences.h"
  62. #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
  63. #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
  64. #include "third_party/blink/public/mojom/navigation/was_activated_option.mojom.h"
  65. #include "ui/accessibility/platform/fuchsia/semantic_provider_impl.h"
  66. #include "ui/aura/window.h"
  67. #include "ui/compositor/compositor.h"
  68. #include "ui/gfx/switches.h"
  69. #include "ui/ozone/public/ozone_switches.h"
  70. #include "ui/wm/core/base_focus_rules.h"
  71. #include "url/gurl.h"
  72. #include "url/origin.h"
  73. namespace {
  74. // Simulated screen bounds to use when headless rendering is enabled.
  75. constexpr gfx::Size kHeadlessWindowSize = {1, 1};
  76. // Name of the Inspect node that holds accessibility information.
  77. constexpr char kAccessibilityInspectNodeName[] = "accessibility";
  78. // A special value which matches all origins when specified in an origin list.
  79. constexpr char kWildcardOrigin[] = "*";
  80. // Used for attaching popup-related metadata to a WebContents.
  81. constexpr char kPopupCreationInfo[] = "popup-creation-info";
  82. class PopupFrameCreationInfoUserData : public base::SupportsUserData::Data {
  83. public:
  84. fuchsia::web::PopupFrameCreationInfo info;
  85. };
  86. class FrameFocusRules : public wm::BaseFocusRules {
  87. public:
  88. FrameFocusRules() = default;
  89. FrameFocusRules(const FrameFocusRules&) = delete;
  90. FrameFocusRules& operator=(const FrameFocusRules&) = delete;
  91. ~FrameFocusRules() override = default;
  92. // wm::BaseFocusRules implementation.
  93. bool SupportsChildActivation(const aura::Window*) const override;
  94. };
  95. bool FrameFocusRules::SupportsChildActivation(const aura::Window*) const {
  96. // TODO(crbug.com/878439): Return a result based on window properties such as
  97. // visibility.
  98. return true;
  99. }
  100. // TODO(crbug.com/1113289): Use OnLoadScriptInjectorHost's origin matching code.
  101. bool IsUrlMatchedByOriginList(const GURL& url,
  102. const std::vector<std::string>& allowed_origins) {
  103. for (const std::string& origin : allowed_origins) {
  104. if (origin == kWildcardOrigin)
  105. return true;
  106. GURL origin_url(origin);
  107. if (!origin_url.is_valid()) {
  108. DLOG(WARNING)
  109. << "Ignored invalid origin spec when checking allowed list: "
  110. << origin;
  111. continue;
  112. }
  113. if (origin_url != url.DeprecatedGetOriginAsURL())
  114. continue;
  115. return true;
  116. }
  117. return false;
  118. }
  119. FuchsiaLogSeverity FuchsiaWebConsoleLogLevelToFxLogSeverity(
  120. fuchsia::web::ConsoleLogLevel level) {
  121. switch (level) {
  122. case fuchsia::web::ConsoleLogLevel::DEBUG:
  123. return FUCHSIA_LOG_DEBUG;
  124. case fuchsia::web::ConsoleLogLevel::INFO:
  125. return FUCHSIA_LOG_INFO;
  126. case fuchsia::web::ConsoleLogLevel::WARN:
  127. return FUCHSIA_LOG_WARNING;
  128. case fuchsia::web::ConsoleLogLevel::ERROR:
  129. return FUCHSIA_LOG_ERROR;
  130. case fuchsia::web::ConsoleLogLevel::NONE:
  131. return FUCHSIA_LOG_NONE;
  132. default:
  133. // Cope gracefully with callers setting undefined levels.
  134. DLOG(ERROR) << "Unknown log level:"
  135. << static_cast<std::underlying_type<decltype(level)>::type>(
  136. level);
  137. return FUCHSIA_LOG_NONE;
  138. }
  139. }
  140. FuchsiaLogSeverity BlinkConsoleMessageLevelToFxLogSeverity(
  141. blink::mojom::ConsoleMessageLevel level) {
  142. switch (level) {
  143. case blink::mojom::ConsoleMessageLevel::kVerbose:
  144. return FUCHSIA_LOG_DEBUG;
  145. case blink::mojom::ConsoleMessageLevel::kInfo:
  146. return FUCHSIA_LOG_INFO;
  147. case blink::mojom::ConsoleMessageLevel::kWarning:
  148. return FUCHSIA_LOG_WARNING;
  149. case blink::mojom::ConsoleMessageLevel::kError:
  150. return FUCHSIA_LOG_ERROR;
  151. }
  152. // Cope gracefully with callers setting undefined levels.
  153. DLOG(ERROR) << "Unknown log level:"
  154. << static_cast<std::underlying_type<decltype(level)>::type>(
  155. level);
  156. return FUCHSIA_LOG_NONE;
  157. }
  158. bool IsHeadless() {
  159. return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless);
  160. }
  161. using FrameImplMap =
  162. base::small_map<std::map<content::WebContents*, FrameImpl*>>;
  163. FrameImplMap& WebContentsToFrameImplMap() {
  164. static FrameImplMap frame_impl_map;
  165. return frame_impl_map;
  166. }
  167. blink::PermissionType FidlPermissionTypeToContentPermissionType(
  168. fuchsia::web::PermissionType fidl_type) {
  169. switch (fidl_type) {
  170. case fuchsia::web::PermissionType::MICROPHONE:
  171. return blink::PermissionType::AUDIO_CAPTURE;
  172. case fuchsia::web::PermissionType::CAMERA:
  173. return blink::PermissionType::VIDEO_CAPTURE;
  174. case fuchsia::web::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
  175. return blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER;
  176. case fuchsia::web::PermissionType::PERSISTENT_STORAGE:
  177. return blink::PermissionType::DURABLE_STORAGE;
  178. }
  179. }
  180. // Permission request callback for FrameImpl::RequestMediaAccessPermission.
  181. void HandleMediaPermissionsRequestResult(
  182. const content::MediaStreamRequest& request,
  183. content::MediaResponseCallback callback,
  184. const std::vector<blink::mojom::PermissionStatus>& result) {
  185. // TODO(crbug.com/1300883): Generalize to multiple streams.
  186. blink::mojom::StreamDevicesPtr devices = blink::mojom::StreamDevices::New();
  187. int result_pos = 0;
  188. if (request.audio_type ==
  189. blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) {
  190. if (result[result_pos] == blink::mojom::PermissionStatus::GRANTED) {
  191. devices->audio_device = blink::MediaStreamDevice(
  192. request.audio_type, request.requested_audio_device_id,
  193. /*name=*/"");
  194. }
  195. result_pos++;
  196. }
  197. if (request.video_type ==
  198. blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) {
  199. if (result[result_pos] == blink::mojom::PermissionStatus::GRANTED) {
  200. devices->video_device = blink::MediaStreamDevice(
  201. request.video_type, request.requested_video_device_id,
  202. /*name=*/"");
  203. }
  204. }
  205. blink::mojom::StreamDevicesSet stream_devices_set;
  206. if (devices->audio_device.has_value() || devices->video_device.has_value()) {
  207. stream_devices_set.stream_devices.emplace_back(std::move(devices));
  208. }
  209. std::move(callback).Run(
  210. stream_devices_set,
  211. stream_devices_set.stream_devices.empty()
  212. ? blink::mojom::MediaStreamRequestResult::NO_HARDWARE
  213. : blink::mojom::MediaStreamRequestResult::OK,
  214. nullptr);
  215. }
  216. absl::optional<url::Origin> ParseAndValidateWebOrigin(
  217. const std::string& origin_str) {
  218. GURL origin_url(origin_str);
  219. if (!origin_url.username().empty() || !origin_url.password().empty() ||
  220. !origin_url.query().empty() || !origin_url.ref().empty()) {
  221. return absl::nullopt;
  222. }
  223. if (!origin_url.path().empty() && origin_url.path() != "/")
  224. return absl::nullopt;
  225. auto origin = url::Origin::Create(origin_url);
  226. if (origin.opaque())
  227. return absl::nullopt;
  228. return origin;
  229. }
  230. } // namespace
  231. FrameImpl::PendingPopup::PendingPopup(
  232. FrameImpl* frame_ptr,
  233. fidl::InterfaceHandle<fuchsia::web::Frame> handle,
  234. fuchsia::web::PopupFrameCreationInfo creation_info)
  235. : frame_ptr(std::move(frame_ptr)),
  236. handle(std::move(handle)),
  237. creation_info(std::move(creation_info)) {}
  238. FrameImpl::PendingPopup::PendingPopup(PendingPopup&& other) = default;
  239. FrameImpl::PendingPopup::~PendingPopup() = default;
  240. // static
  241. FrameImpl* FrameImpl::FromWebContents(content::WebContents* web_contents) {
  242. if (!web_contents)
  243. return nullptr;
  244. auto& map = WebContentsToFrameImplMap();
  245. auto it = map.find(web_contents);
  246. if (it == map.end())
  247. return nullptr;
  248. return it->second;
  249. }
  250. // static
  251. FrameImpl* FrameImpl::FromRenderFrameHost(
  252. content::RenderFrameHost* render_frame_host) {
  253. return FromWebContents(
  254. content::WebContents::FromRenderFrameHost(render_frame_host));
  255. }
  256. FrameImpl::FrameImpl(std::unique_ptr<content::WebContents> web_contents,
  257. ContextImpl* context,
  258. fuchsia::web::CreateFrameParams params,
  259. inspect::Node inspect_node,
  260. fidl::InterfaceRequest<fuchsia::web::Frame> frame_request)
  261. : web_contents_(std::move(web_contents)),
  262. context_(context),
  263. console_log_tag_(params.has_debug_name() ? params.debug_name()
  264. : std::string()),
  265. params_for_popups_(std::move(params)),
  266. navigation_controller_(web_contents_.get()),
  267. permission_controller_(web_contents_.get()),
  268. binding_(this, std::move(frame_request)),
  269. media_blocker_(web_contents_.get()),
  270. theme_manager_(web_contents_.get(),
  271. base::BindOnce(&FrameImpl::OnThemeManagerError,
  272. base::Unretained(this))),
  273. inspect_node_(std::move(inspect_node)),
  274. inspect_name_property_(
  275. params_for_popups_.has_debug_name()
  276. ? inspect_node_.CreateString("name",
  277. params_for_popups_.debug_name())
  278. : inspect::StringProperty()) {
  279. DCHECK(!WebContentsToFrameImplMap()[web_contents_.get()]);
  280. WebContentsToFrameImplMap()[web_contents_.get()] = this;
  281. web_contents_->SetDelegate(this);
  282. web_contents_->SetPageBaseBackgroundColor(SK_AlphaTRANSPARENT);
  283. Observe(web_contents_.get());
  284. url_request_rewrite_rules_manager_.AddWebContents(web_contents_.get());
  285. binding_.set_error_handler([this](zx_status_t status) {
  286. ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
  287. << " Frame disconnected.";
  288. context_->DestroyFrame(this);
  289. });
  290. content::UpdateFontRendererPreferencesFromSystemSettings(
  291. web_contents_->GetMutableRendererPrefs());
  292. // TODO(http://crbug.com/1254073): Deprecate autoplay_policy in
  293. // CreateFrameParams.
  294. if (params_for_popups_.has_autoplay_policy()) {
  295. content_area_settings_.set_autoplay_policy(
  296. params_for_popups_.autoplay_policy());
  297. }
  298. }
  299. FrameImpl::~FrameImpl() {
  300. DestroyWindowTreeHost();
  301. context_->devtools_controller()->OnFrameDestroyed(web_contents_.get());
  302. auto& map = WebContentsToFrameImplMap();
  303. auto it = WebContentsToFrameImplMap().find(web_contents_.get());
  304. DCHECK(it != map.end() && it->second == this);
  305. map.erase(it);
  306. }
  307. zx::unowned_channel FrameImpl::GetBindingChannelForTest() const {
  308. return zx::unowned_channel(binding_.channel());
  309. }
  310. aura::Window* FrameImpl::root_window() const {
  311. return window_tree_host_->window();
  312. }
  313. void FrameImpl::ExecuteJavaScriptInternal(std::vector<std::string> origins,
  314. fuchsia::mem::Buffer script,
  315. ExecuteJavaScriptCallback callback,
  316. bool need_result) {
  317. if (!context_->IsJavaScriptInjectionAllowed()) {
  318. callback(fpromise::error(fuchsia::web::FrameError::INTERNAL_ERROR));
  319. return;
  320. }
  321. // Prevents script injection into the wrong document if the renderer recently
  322. // navigated to a different origin.
  323. if (!IsUrlMatchedByOriginList(web_contents_->GetLastCommittedURL(),
  324. origins)) {
  325. callback(fpromise::error(fuchsia::web::FrameError::INVALID_ORIGIN));
  326. return;
  327. }
  328. absl::optional<std::u16string> script_utf16 =
  329. base::ReadUTF8FromVMOAsUTF16(script);
  330. if (!script_utf16) {
  331. callback(fpromise::error(fuchsia::web::FrameError::BUFFER_NOT_UTF8));
  332. return;
  333. }
  334. content::RenderFrameHost::JavaScriptResultCallback result_callback;
  335. if (need_result) {
  336. result_callback = base::BindOnce(
  337. [](ExecuteJavaScriptCallback callback, base::Value result_value) {
  338. std::string result_json;
  339. if (!base::JSONWriter::Write(result_value, &result_json)) {
  340. callback(fpromise::error(fuchsia::web::FrameError::INTERNAL_ERROR));
  341. return;
  342. }
  343. callback(fpromise::ok(base::MemBufferFromString(
  344. std::move(result_json), "cr-execute-js-response")));
  345. },
  346. std::move(callback));
  347. }
  348. web_contents_->GetPrimaryMainFrame()->ExecuteJavaScript(
  349. *script_utf16, std::move(result_callback));
  350. if (!need_result) {
  351. // If no result is required then invoke callback() immediately.
  352. callback(fpromise::ok(fuchsia::mem::Buffer()));
  353. }
  354. }
  355. bool FrameImpl::IsWebContentsCreationOverridden(
  356. content::SiteInstance* source_site_instance,
  357. content::mojom::WindowContainerType window_container_type,
  358. const GURL& opener_url,
  359. const std::string& frame_name,
  360. const GURL& target_url) {
  361. // Specify a generous upper bound for unacknowledged popup windows, so that we
  362. // can catch bad client behavior while not interfering with normal operation.
  363. constexpr size_t kMaxPendingWebContentsCount = 10;
  364. if (!popup_listener_)
  365. return true;
  366. if (pending_popups_.size() >= kMaxPendingWebContentsCount) {
  367. // The content is producing popups faster than the embedder can process
  368. // them. Drop the popups so as to prevent resource exhaustion.
  369. LOG(WARNING) << "Too many pending popups, ignoring request.";
  370. // Don't produce a WebContents for this popup.
  371. return true;
  372. }
  373. return false;
  374. }
  375. void FrameImpl::AddNewContents(
  376. content::WebContents* source,
  377. std::unique_ptr<content::WebContents> new_contents,
  378. const GURL& target_url,
  379. WindowOpenDisposition disposition,
  380. const gfx::Rect& initial_rect,
  381. bool user_gesture,
  382. bool* was_blocked) {
  383. DCHECK_EQ(source, web_contents_.get());
  384. // TODO(crbug.com/995395): Add window disposition to the FIDL interface.
  385. switch (disposition) {
  386. case WindowOpenDisposition::NEW_FOREGROUND_TAB:
  387. case WindowOpenDisposition::NEW_BACKGROUND_TAB:
  388. case WindowOpenDisposition::NEW_PICTURE_IN_PICTURE:
  389. case WindowOpenDisposition::NEW_POPUP:
  390. case WindowOpenDisposition::NEW_WINDOW: {
  391. if (url_request_rewrite_rules_manager_.GetCachedRules()) {
  392. // There is no support for URL request rules rewriting with popups.
  393. *was_blocked = true;
  394. return;
  395. }
  396. auto* popup_creation_info =
  397. reinterpret_cast<PopupFrameCreationInfoUserData*>(
  398. new_contents->GetUserData(kPopupCreationInfo));
  399. fuchsia::web::PopupFrameCreationInfo popup_frame_creation_info =
  400. std::move(popup_creation_info->info);
  401. popup_frame_creation_info.set_initiated_by_user(user_gesture);
  402. // The PopupFrameCreationInfo won't be needed anymore, so clear it out.
  403. new_contents->SetUserData(kPopupCreationInfo, nullptr);
  404. // ContextImpl::CreateFrameInternal() verified that |params_for_popups_|
  405. // can be cloned, so it cannot fail here.
  406. fuchsia::web::CreateFrameParams params;
  407. zx_status_t status = params_for_popups_.Clone(&params);
  408. ZX_DCHECK(status == ZX_OK, status);
  409. fidl::InterfaceHandle<fuchsia::web::Frame> frame_handle;
  410. auto* popup_frame = context_->CreateFrameForWebContents(
  411. std::move(new_contents), std::move(params),
  412. frame_handle.NewRequest());
  413. fuchsia::web::ContentAreaSettings settings;
  414. status = content_area_settings_.Clone(&settings);
  415. ZX_DCHECK(status == ZX_OK, status);
  416. popup_frame->SetContentAreaSettings(std::move(settings));
  417. pending_popups_.emplace_back(popup_frame, std::move(frame_handle),
  418. std::move(popup_frame_creation_info));
  419. MaybeSendPopup();
  420. return;
  421. }
  422. // These kinds of windows don't produce Frames.
  423. case WindowOpenDisposition::CURRENT_TAB:
  424. case WindowOpenDisposition::SINGLETON_TAB:
  425. case WindowOpenDisposition::SAVE_TO_DISK:
  426. case WindowOpenDisposition::OFF_THE_RECORD:
  427. case WindowOpenDisposition::IGNORE_ACTION:
  428. case WindowOpenDisposition::SWITCH_TO_TAB:
  429. case WindowOpenDisposition::UNKNOWN:
  430. NOTIMPLEMENTED() << "Dropped new web contents (disposition: "
  431. << static_cast<int>(disposition) << ")";
  432. return;
  433. }
  434. }
  435. void FrameImpl::WebContentsCreated(content::WebContents* source_contents,
  436. int opener_render_process_id,
  437. int opener_render_frame_id,
  438. const std::string& frame_name,
  439. const GURL& target_url,
  440. content::WebContents* new_contents) {
  441. auto creation_info = std::make_unique<PopupFrameCreationInfoUserData>();
  442. creation_info->info.set_initial_url(target_url.spec());
  443. new_contents->SetUserData(kPopupCreationInfo, std::move(creation_info));
  444. }
  445. void FrameImpl::MaybeSendPopup() {
  446. if (!popup_listener_)
  447. return;
  448. if (popup_ack_outstanding_ || pending_popups_.empty())
  449. return;
  450. auto popup = std::move(pending_popups_.front());
  451. pending_popups_.pop_front();
  452. popup_listener_->OnPopupFrameCreated(std::move(popup.handle),
  453. std::move(popup.creation_info), [this] {
  454. popup_ack_outstanding_ = false;
  455. MaybeSendPopup();
  456. });
  457. popup_ack_outstanding_ = true;
  458. }
  459. void FrameImpl::DestroyWindowTreeHost() {
  460. if (!window_tree_host_)
  461. return;
  462. aura::client::SetFocusClient(root_window(), nullptr);
  463. wm::SetActivationClient(root_window(), nullptr);
  464. root_window()->RemovePreTargetHandler(&event_filter_);
  465. root_window()->RemovePreTargetHandler(focus_controller_.get());
  466. web_contents_->GetNativeView()->Hide();
  467. window_tree_host_->Hide();
  468. window_tree_host_->compositor()->SetVisible(false);
  469. window_tree_host_.reset();
  470. accessibility_bridge_.reset();
  471. v2_accessibility_bridge_.reset();
  472. // Allows posted focus events to process before the FocusController is torn
  473. // down.
  474. content::GetUIThreadTaskRunner({})->DeleteSoon(FROM_HERE,
  475. std::move(focus_controller_));
  476. }
  477. void FrameImpl::CloseAndDestroyFrame(zx_status_t error) {
  478. DCHECK(binding_.is_bound());
  479. binding_.Close(error);
  480. context_->DestroyFrame(this);
  481. }
  482. void FrameImpl::OnPopupListenerDisconnected(zx_status_t status) {
  483. ZX_LOG_IF(WARNING, status != ZX_ERR_PEER_CLOSED, status)
  484. << "Popup listener disconnected.";
  485. pending_popups_.clear();
  486. }
  487. void FrameImpl::OnMediaPlayerDisconnect() {
  488. media_player_ = nullptr;
  489. }
  490. bool FrameImpl::OnAccessibilityError(zx_status_t error) {
  491. // The task is posted so |accessibility_bridge_| does not tear |this| down
  492. // while events are still being processed.
  493. base::ThreadTaskRunnerHandle::Get()->PostTask(
  494. FROM_HERE, base::BindOnce(&FrameImpl::CloseAndDestroyFrame,
  495. weak_factory_.GetWeakPtr(), error));
  496. // The return value indicates to the accessibility bridge whether we should
  497. // attempt to reconnect. Since the frame has been destroyed, no reconnect
  498. // attempt should be made.
  499. return false;
  500. }
  501. bool FrameImpl::MaybeHandleCastStreamingMessage(
  502. std::string* origin,
  503. fuchsia::web::WebMessage* message,
  504. PostMessageCallback* callback) {
  505. if (!context_->has_cast_streaming_enabled()) {
  506. return false;
  507. }
  508. if (!IsCastStreamingAppOrigin(*origin)) {
  509. return false;
  510. }
  511. if (receiver_session_client_ || !IsValidCastStreamingMessage(*message)) {
  512. // The Cast Streaming MessagePort should only be set once and |message|
  513. // should be a valid Cast Streaming Message.
  514. (*callback)(fpromise::error(fuchsia::web::FrameError::INVALID_ORIGIN));
  515. return true;
  516. }
  517. receiver_session_client_ = std::make_unique<ReceiverSessionClient>(
  518. std::move((*message->mutable_outgoing_transfer())[0].message_port()),
  519. IsCastStreamingVideoOnlyAppOrigin(*origin));
  520. (*callback)(fpromise::ok());
  521. return true;
  522. }
  523. void FrameImpl::MaybeStartCastStreaming(
  524. content::NavigationHandle* navigation_handle) {
  525. if (!context_->has_cast_streaming_enabled() || !receiver_session_client_ ||
  526. receiver_session_client_->HasReceiverSession()) {
  527. return;
  528. }
  529. mojo::AssociatedRemote<cast_streaming::mojom::DemuxerConnector>
  530. demuxer_connector;
  531. navigation_handle->GetRenderFrameHost()
  532. ->GetRemoteAssociatedInterfaces()
  533. ->GetInterface(&demuxer_connector);
  534. receiver_session_client_->SetDemuxerConnector(std::move(demuxer_connector));
  535. }
  536. void FrameImpl::UpdateRenderViewZoomLevel(
  537. content::RenderViewHost* render_view_host) {
  538. float page_scale = content_area_settings_.has_page_scale()
  539. ? content_area_settings_.page_scale()
  540. : 1.0;
  541. content::HostZoomMap* host_zoom_map =
  542. content::HostZoomMap::GetForWebContents(web_contents_.get());
  543. host_zoom_map->SetTemporaryZoomLevel(
  544. render_view_host->GetProcess()->GetID(), render_view_host->GetRoutingID(),
  545. blink::PageZoomFactorToZoomLevel(page_scale));
  546. }
  547. void FrameImpl::ConnectToAccessibilityBridge() {
  548. if (use_v2_accessibility_bridge_) {
  549. // TODO(crbug.com/1291613): Replace callbacks with an interface that
  550. // FrameImpl implements.
  551. v2_accessibility_bridge_ =
  552. std::make_unique<ui::AccessibilityBridgeFuchsiaImpl>(
  553. root_window(), window_tree_host_->CreateViewRef(),
  554. base::BindRepeating(&FrameImpl::SetAccessibilityEnabled,
  555. base::Unretained(this)),
  556. base::BindRepeating(&FrameImpl::OnAccessibilityError,
  557. base::Unretained(this)),
  558. inspect_node_.CreateChild(kAccessibilityInspectNodeName));
  559. } else {
  560. fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager;
  561. if (!semantics_manager_for_test_) {
  562. semantics_manager =
  563. base::ComponentContextForProcess()
  564. ->svc()
  565. ->Connect<fuchsia::accessibility::semantics::SemanticsManager>();
  566. }
  567. // If the SemanticTree owned by |accessibility_bridge_| is disconnected, it
  568. // will cause |this| to be closed.
  569. accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
  570. semantics_manager_for_test_ ? semantics_manager_for_test_
  571. : semantics_manager.get(),
  572. window_tree_host_.get(), web_contents_.get(),
  573. base::BindOnce(&FrameImpl::OnAccessibilityError,
  574. base::Unretained(this)),
  575. inspect_node_.CreateChild(kAccessibilityInspectNodeName));
  576. }
  577. }
  578. void FrameImpl::CreateView(fuchsia::ui::views::ViewToken view_token) {
  579. scenic::ViewRefPair view_ref_pair = scenic::ViewRefPair::New();
  580. CreateViewWithViewRef(std::move(view_token),
  581. std::move(view_ref_pair.control_ref),
  582. std::move(view_ref_pair.view_ref));
  583. }
  584. void FrameImpl::CreateViewWithViewRef(
  585. fuchsia::ui::views::ViewToken view_token,
  586. fuchsia::ui::views::ViewRefControl control_ref,
  587. fuchsia::ui::views::ViewRef view_ref) {
  588. if (IsHeadless()) {
  589. LOG(WARNING) << "CreateView() called on a HEADLESS Context.";
  590. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  591. return;
  592. }
  593. if (!view_token.value.is_valid()) {
  594. LOG(WARNING) << "CreateView() called with invalid view_token.";
  595. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  596. return;
  597. }
  598. // If a View to this Frame is already active then disconnect it.
  599. DestroyWindowTreeHost();
  600. scenic::ViewRefPair view_ref_pair;
  601. view_ref_pair.control_ref = std::move(control_ref);
  602. view_ref_pair.view_ref = std::move(view_ref);
  603. SetupWindowTreeHost(std::move(view_token), std::move(view_ref_pair));
  604. ConnectToAccessibilityBridge();
  605. }
  606. void FrameImpl::CreateView2(fuchsia::web::CreateView2Args view_args) {
  607. if (IsHeadless()) {
  608. LOG(WARNING) << "CreateView2() called on a HEADLESS Context.";
  609. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  610. return;
  611. }
  612. if (!view_args.has_view_creation_token() ||
  613. !view_args.view_creation_token().value.is_valid()) {
  614. LOG(WARNING) << "CreateView2() called with invalid view_creation_token.";
  615. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  616. return;
  617. }
  618. // If a View to this Frame is already active then disconnect it.
  619. DestroyWindowTreeHost();
  620. scenic::ViewRefPair view_ref_pair = scenic::ViewRefPair::New();
  621. SetupWindowTreeHost(std::move(*view_args.mutable_view_creation_token()),
  622. std::move(view_ref_pair));
  623. ConnectToAccessibilityBridge();
  624. }
  625. void FrameImpl::GetMediaPlayer(
  626. fidl::InterfaceRequest<fuchsia::media::sessions2::Player> player) {
  627. media_player_ = std::make_unique<MediaPlayerImpl>(
  628. content::MediaSession::Get(web_contents_.get()), std::move(player),
  629. base::BindOnce(&FrameImpl::OnMediaPlayerDisconnect,
  630. base::Unretained(this)));
  631. }
  632. void FrameImpl::GetNavigationController(
  633. fidl::InterfaceRequest<fuchsia::web::NavigationController> controller) {
  634. navigation_controller_.AddBinding(std::move(controller));
  635. }
  636. void FrameImpl::ExecuteJavaScript(std::vector<std::string> origins,
  637. fuchsia::mem::Buffer script,
  638. ExecuteJavaScriptCallback callback) {
  639. ExecuteJavaScriptInternal(std::move(origins), std::move(script),
  640. std::move(callback), true);
  641. }
  642. void FrameImpl::ExecuteJavaScriptNoResult(
  643. std::vector<std::string> origins,
  644. fuchsia::mem::Buffer script,
  645. ExecuteJavaScriptNoResultCallback callback) {
  646. ExecuteJavaScriptInternal(
  647. std::move(origins), std::move(script),
  648. [callback = std::move(callback)](
  649. fuchsia::web::Frame_ExecuteJavaScript_Result result_with_value) {
  650. if (result_with_value.is_err()) {
  651. callback(fpromise::error(result_with_value.err()));
  652. } else {
  653. callback(fpromise::ok());
  654. }
  655. },
  656. false);
  657. }
  658. void FrameImpl::AddBeforeLoadJavaScript(
  659. uint64_t id,
  660. std::vector<std::string> origins,
  661. fuchsia::mem::Buffer script,
  662. AddBeforeLoadJavaScriptCallback callback) {
  663. constexpr char kWildcardOrigin[] = "*";
  664. if (!context_->IsJavaScriptInjectionAllowed()) {
  665. callback(fpromise::error(fuchsia::web::FrameError::INTERNAL_ERROR));
  666. return;
  667. }
  668. absl::optional<std::string> script_as_string =
  669. base::StringFromMemBuffer(script);
  670. if (!script_as_string) {
  671. LOG(ERROR) << "Couldn't read script from buffer.";
  672. callback(fpromise::error(fuchsia::web::FrameError::INTERNAL_ERROR));
  673. return;
  674. }
  675. // TODO(crbug.com/1108607): Only allow wildcards to be specified standalone.
  676. if (std::any_of(origins.begin(), origins.end(),
  677. [kWildcardOrigin](base::StringPiece origin) {
  678. return origin == kWildcardOrigin;
  679. })) {
  680. script_injector_.AddScriptForAllOrigins(id, *script_as_string);
  681. } else {
  682. std::vector<url::Origin> origins_converted;
  683. for (const std::string& origin : origins) {
  684. url::Origin origin_parsed = url::Origin::Create(GURL(origin));
  685. if (origin_parsed.opaque()) {
  686. callback(fpromise::error(fuchsia::web::FrameError::INVALID_ORIGIN));
  687. return;
  688. }
  689. origins_converted.push_back(origin_parsed);
  690. }
  691. script_injector_.AddScript(id, origins_converted, *script_as_string);
  692. }
  693. callback(fpromise::ok());
  694. }
  695. void FrameImpl::RemoveBeforeLoadJavaScript(uint64_t id) {
  696. script_injector_.RemoveScript(id);
  697. }
  698. void FrameImpl::PostMessage(std::string origin,
  699. fuchsia::web::WebMessage message,
  700. PostMessageCallback callback) {
  701. if (MaybeHandleCastStreamingMessage(&origin, &message, &callback))
  702. return;
  703. fuchsia::web::Frame_PostMessage_Result result;
  704. if (origin.empty()) {
  705. callback(fpromise::error(fuchsia::web::FrameError::INVALID_ORIGIN));
  706. return;
  707. }
  708. if (!message.has_data()) {
  709. callback(fpromise::error(fuchsia::web::FrameError::NO_DATA_IN_MESSAGE));
  710. return;
  711. }
  712. absl::optional<std::u16string> origin_utf16;
  713. if (origin != kWildcardOrigin)
  714. origin_utf16 = base::UTF8ToUTF16(origin);
  715. absl::optional<std::u16string> data_utf16 =
  716. base::ReadUTF8FromVMOAsUTF16(message.data());
  717. if (!data_utf16) {
  718. callback(fpromise::error(fuchsia::web::FrameError::BUFFER_NOT_UTF8));
  719. return;
  720. }
  721. // Convert and pass along any MessagePorts contained in the message.
  722. std::vector<blink::WebMessagePort> message_ports;
  723. if (message.has_outgoing_transfer()) {
  724. for (const fuchsia::web::OutgoingTransferable& outgoing :
  725. message.outgoing_transfer()) {
  726. if (!outgoing.is_message_port()) {
  727. callback(fpromise::error(fuchsia::web::FrameError::INTERNAL_ERROR));
  728. return;
  729. }
  730. }
  731. for (fuchsia::web::OutgoingTransferable& outgoing :
  732. *message.mutable_outgoing_transfer()) {
  733. blink::WebMessagePort blink_port =
  734. BlinkMessagePortFromFidl(std::move(outgoing.message_port()));
  735. if (!blink_port.IsValid()) {
  736. callback(fpromise::error(fuchsia::web::FrameError::INTERNAL_ERROR));
  737. return;
  738. }
  739. message_ports.push_back(std::move(blink_port));
  740. }
  741. }
  742. content::MessagePortProvider::PostMessageToFrame(
  743. web_contents_->GetPrimaryPage(), std::u16string(), origin_utf16,
  744. std::move(*data_utf16), std::move(message_ports));
  745. callback(fpromise::ok());
  746. }
  747. void FrameImpl::SetNavigationEventListener(
  748. fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener) {
  749. SetNavigationEventListener2(std::move(listener), /*flags=*/{});
  750. }
  751. void FrameImpl::SetNavigationEventListener2(
  752. fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener,
  753. fuchsia::web::NavigationEventListenerFlags flags) {
  754. navigation_controller_.SetEventListener(std::move(listener), flags);
  755. }
  756. void FrameImpl::SetJavaScriptLogLevel(fuchsia::web::ConsoleLogLevel level) {
  757. log_level_ = FuchsiaWebConsoleLogLevelToFxLogSeverity(level);
  758. }
  759. void FrameImpl::SetConsoleLogSink(fuchsia::logger::LogSinkHandle sink) {
  760. if (sink) {
  761. console_logger_ = base::ScopedFxLogger::CreateFromLogSink(
  762. std::move(sink), {console_log_tag_});
  763. } else {
  764. console_logger_ = {};
  765. }
  766. }
  767. void FrameImpl::ConfigureInputTypes(fuchsia::web::InputTypes types,
  768. fuchsia::web::AllowInputState allow) {
  769. event_filter_.ConfigureInputTypes(types, allow);
  770. }
  771. void FrameImpl::SetPopupFrameCreationListener(
  772. fidl::InterfaceHandle<fuchsia::web::PopupFrameCreationListener> listener) {
  773. popup_listener_ = listener.Bind();
  774. popup_listener_.set_error_handler(
  775. fit::bind_member(this, &FrameImpl::OnPopupListenerDisconnected));
  776. }
  777. void FrameImpl::SetUrlRequestRewriteRules(
  778. std::vector<fuchsia::web::UrlRequestRewriteRule> rules,
  779. SetUrlRequestRewriteRulesCallback callback) {
  780. auto mojom_rules =
  781. mojo::ConvertTo<url_rewrite::mojom::UrlRequestRewriteRulesPtr>(
  782. std::move(rules));
  783. if (url_request_rewrite_rules_manager_.OnRulesUpdated(
  784. std::move(mojom_rules))) {
  785. std::move(callback)();
  786. } else {
  787. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  788. }
  789. }
  790. void FrameImpl::EnableHeadlessRendering() {
  791. if (!IsHeadless()) {
  792. LOG(ERROR) << "EnableHeadlessRendering() on non-HEADLESS Context.";
  793. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  794. return;
  795. }
  796. scenic::ViewRefPair view_ref_pair = scenic::ViewRefPair::New();
  797. SetupWindowTreeHost(fuchsia::ui::views::ViewToken(),
  798. std::move(view_ref_pair));
  799. gfx::Rect bounds(kHeadlessWindowSize);
  800. if (window_size_for_test_) {
  801. ConnectToAccessibilityBridge();
  802. bounds.set_size(*window_size_for_test_);
  803. }
  804. window_tree_host_->SetBoundsInPixels(bounds);
  805. // FrameWindowTreeHost will Show() itself when the View is attached, but
  806. // in headless mode there is no View, so Show() it explicitly.
  807. window_tree_host_->Show();
  808. }
  809. void FrameImpl::DisableHeadlessRendering() {
  810. if (!IsHeadless()) {
  811. LOG(ERROR)
  812. << "Attempted to disable headless rendering on non-HEADLESS Context.";
  813. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  814. return;
  815. }
  816. DestroyWindowTreeHost();
  817. }
  818. void FrameImpl::SetupWindowTreeHost(fuchsia::ui::views::ViewToken view_token,
  819. scenic::ViewRefPair view_ref_pair) {
  820. DCHECK(!window_tree_host_);
  821. window_tree_host_ = std::make_unique<FrameWindowTreeHost>(
  822. std::move(view_token), std::move(view_ref_pair), web_contents_.get(),
  823. base::BindRepeating(&FrameImpl::OnPixelScaleUpdate,
  824. base::Unretained(this)));
  825. InitWindowTreeHost();
  826. }
  827. void FrameImpl::SetupWindowTreeHost(
  828. fuchsia::ui::views::ViewCreationToken view_creation_token,
  829. scenic::ViewRefPair view_ref_pair) {
  830. DCHECK(!window_tree_host_);
  831. window_tree_host_ = std::make_unique<FrameWindowTreeHost>(
  832. std::move(view_creation_token), std::move(view_ref_pair),
  833. web_contents_.get(),
  834. base::BindRepeating(&FrameImpl::OnPixelScaleUpdate,
  835. base::Unretained(this)));
  836. InitWindowTreeHost();
  837. }
  838. void FrameImpl::InitWindowTreeHost() {
  839. DCHECK(window_tree_host_);
  840. window_tree_host_->InitHost();
  841. root_window()->AddPreTargetHandler(&event_filter_);
  842. // Add hooks which automatically set the focus state when input events are
  843. // received.
  844. focus_controller_ =
  845. std::make_unique<wm::FocusController>(new FrameFocusRules);
  846. root_window()->AddPreTargetHandler(focus_controller_.get());
  847. aura::client::SetFocusClient(root_window(), focus_controller_.get());
  848. wm::SetActivationClient(root_window(), focus_controller_.get());
  849. layout_manager_ = new FrameLayoutManager;
  850. root_window()->SetLayoutManager(layout_manager_); // Transfers ownership.
  851. if (!render_size_override_.IsEmpty())
  852. layout_manager_->ForceContentDimensions(render_size_override_);
  853. root_window()->AddChild(web_contents_->GetNativeView());
  854. web_contents_->GetNativeView()->Show();
  855. // FrameWindowTreeHost will Show() itself when the View is actually attached
  856. // to the view-tree to be displayed. See https://crbug.com/1109270
  857. }
  858. void FrameImpl::SetMediaSettings(
  859. fuchsia::web::FrameMediaSettings media_settings) {
  860. media_settings_ = std::move(media_settings);
  861. }
  862. void FrameImpl::MediaStartedPlaying(const MediaPlayerInfo& video_type,
  863. const content::MediaPlayerId& id) {
  864. base::RecordComputedAction("MediaPlay");
  865. }
  866. void FrameImpl::MediaStoppedPlaying(
  867. const MediaPlayerInfo& video_type,
  868. const content::MediaPlayerId& id,
  869. WebContentsObserver::MediaStoppedReason reason) {
  870. base::RecordComputedAction("MediaPause");
  871. }
  872. void FrameImpl::GetPrivateMemorySize(GetPrivateMemorySizeCallback callback) {
  873. if (!web_contents_->GetPrimaryMainFrame()->GetProcess()->IsReady()) {
  874. // Renderer process is not yet started.
  875. callback(0);
  876. return;
  877. }
  878. zx_info_task_stats_t task_stats;
  879. zx_status_t status = zx_object_get_info(
  880. web_contents_->GetPrimaryMainFrame()->GetProcess()->GetProcess().Handle(),
  881. ZX_INFO_TASK_STATS, &task_stats, sizeof(task_stats), nullptr, nullptr);
  882. if (status != ZX_OK) {
  883. // Fail gracefully by returning zero.
  884. ZX_LOG(WARNING, status) << "zx_object_get_info(ZX_INFO_TASK_STATS)";
  885. callback(0);
  886. return;
  887. }
  888. callback(task_stats.mem_private_bytes);
  889. }
  890. void FrameImpl::SetNavigationPolicyProvider(
  891. fuchsia::web::NavigationPolicyProviderParams params,
  892. fidl::InterfaceHandle<fuchsia::web::NavigationPolicyProvider> provider) {
  893. navigation_policy_handler_ = std::make_unique<NavigationPolicyHandler>(
  894. std::move(params), std::move(provider));
  895. }
  896. void FrameImpl::OnThemeManagerError() {
  897. // TODO(crbug.com/1148454): Destroy the frame once a fake Display service is
  898. // implemented.
  899. // this->CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  900. }
  901. void FrameImpl::SetPreferredTheme(fuchsia::settings::ThemeType theme) {
  902. fuchsia::web::ContentAreaSettings settings;
  903. settings.set_theme(theme);
  904. SetContentAreaSettings(std::move(settings));
  905. }
  906. void FrameImpl::SetPageScale(float scale) {
  907. fuchsia::web::ContentAreaSettings settings;
  908. settings.set_page_scale(scale);
  909. SetContentAreaSettings(std::move(settings));
  910. }
  911. void FrameImpl::SetContentAreaSettings(
  912. fuchsia::web::ContentAreaSettings settings) {
  913. if (settings.has_hide_scrollbars())
  914. content_area_settings_.set_hide_scrollbars(settings.hide_scrollbars());
  915. if (settings.has_autoplay_policy())
  916. content_area_settings_.set_autoplay_policy(settings.autoplay_policy());
  917. if (settings.has_theme()) {
  918. content_area_settings_.set_theme(settings.theme());
  919. theme_manager_.SetTheme(settings.theme());
  920. }
  921. if (settings.has_page_scale()) {
  922. if (settings.page_scale() <= 0.0) {
  923. LOG(ERROR) << "SetPageScale() called with nonpositive scale.";
  924. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  925. return;
  926. }
  927. if (!(content_area_settings_.has_page_scale() &&
  928. (settings.page_scale() == content_area_settings_.page_scale()))) {
  929. content_area_settings_.set_page_scale(settings.page_scale());
  930. UpdateRenderViewZoomLevel(web_contents_->GetRenderViewHost());
  931. }
  932. }
  933. web_contents_->OnWebPreferencesChanged();
  934. }
  935. void FrameImpl::ResetContentAreaSettings() {
  936. content_area_settings_ = fuchsia::web::ContentAreaSettings();
  937. web_contents_->OnWebPreferencesChanged();
  938. UpdateRenderViewZoomLevel(web_contents_->GetRenderViewHost());
  939. }
  940. void FrameImpl::OverrideWebPreferences(
  941. blink::web_pref::WebPreferences* web_prefs) {
  942. if (content_area_settings_.has_hide_scrollbars()) {
  943. web_prefs->hide_scrollbars = content_area_settings_.hide_scrollbars();
  944. } else {
  945. // Verify that hide_scrollbars defaults to false, per FIDL API.
  946. DCHECK(!web_prefs->hide_scrollbars);
  947. }
  948. if (content_area_settings_.has_autoplay_policy()) {
  949. switch (content_area_settings_.autoplay_policy()) {
  950. case fuchsia::web::AutoplayPolicy::ALLOW:
  951. web_prefs->autoplay_policy =
  952. blink::mojom::AutoplayPolicy::kNoUserGestureRequired;
  953. break;
  954. case fuchsia::web::AutoplayPolicy::REQUIRE_USER_ACTIVATION:
  955. web_prefs->autoplay_policy =
  956. blink::mojom::AutoplayPolicy::kDocumentUserActivationRequired;
  957. break;
  958. }
  959. } else {
  960. // REQUIRE_USER_ACTIVATION is the default per the FIDL API.
  961. web_prefs->autoplay_policy =
  962. blink::mojom::AutoplayPolicy::kDocumentUserActivationRequired;
  963. }
  964. theme_manager_.ApplyThemeToWebPreferences(web_prefs);
  965. }
  966. void FrameImpl::ForceContentDimensions(
  967. std::unique_ptr<fuchsia::ui::gfx::vec2> web_dips) {
  968. if (!web_dips) {
  969. render_size_override_ = {};
  970. if (layout_manager_)
  971. layout_manager_->ForceContentDimensions({});
  972. return;
  973. }
  974. gfx::Size web_dips_converted(web_dips->x, web_dips->y);
  975. if (web_dips_converted.IsEmpty()) {
  976. LOG(ERROR) << "Rejecting zero-area size for ForceContentDimensions().";
  977. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  978. return;
  979. }
  980. render_size_override_ = web_dips_converted;
  981. if (layout_manager_)
  982. layout_manager_->ForceContentDimensions(web_dips_converted);
  983. }
  984. void FrameImpl::SetPermissionState(
  985. fuchsia::web::PermissionDescriptor fidl_permission,
  986. std::string web_origin_string,
  987. fuchsia::web::PermissionState fidl_state) {
  988. if (!fidl_permission.has_type()) {
  989. LOG(ERROR) << "PermissionDescriptor.type is not specified in "
  990. "SetPermissionState().";
  991. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  992. return;
  993. }
  994. blink::PermissionType type =
  995. FidlPermissionTypeToContentPermissionType(fidl_permission.type());
  996. blink::mojom::PermissionStatus state =
  997. (fidl_state == fuchsia::web::PermissionState::GRANTED)
  998. ? blink::mojom::PermissionStatus::GRANTED
  999. : blink::mojom::PermissionStatus::DENIED;
  1000. // TODO(crbug.com/1136994): Remove this once the PermissionManager API is
  1001. // available.
  1002. if (web_origin_string == "*" &&
  1003. type == blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER) {
  1004. permission_controller_.SetDefaultPermissionState(type, state);
  1005. return;
  1006. }
  1007. // Handle per-origin permissions specifications.
  1008. auto web_origin = ParseAndValidateWebOrigin(web_origin_string);
  1009. if (!web_origin) {
  1010. LOG(ERROR) << "SetPermissionState() called with invalid web_origin: "
  1011. << web_origin_string;
  1012. CloseAndDestroyFrame(ZX_ERR_INVALID_ARGS);
  1013. return;
  1014. }
  1015. permission_controller_.SetPermissionState(type, web_origin.value(), state);
  1016. }
  1017. void FrameImpl::CloseContents(content::WebContents* source) {
  1018. DCHECK_EQ(source, web_contents_.get());
  1019. CloseAndDestroyFrame(ZX_OK);
  1020. }
  1021. void FrameImpl::SetBlockMediaLoading(bool blocked) {
  1022. media_blocker_.BlockMediaLoading(blocked);
  1023. }
  1024. bool FrameImpl::DidAddMessageToConsole(
  1025. content::WebContents* source,
  1026. blink::mojom::ConsoleMessageLevel log_level,
  1027. const std::u16string& message,
  1028. int32_t line_no,
  1029. const std::u16string& source_id) {
  1030. // Prevent logging when log_level_ is 0. See crbug.com/1292187.
  1031. // TODO(crbug.com/1292208): Convert to DCHECK when FUCHSIA_LOG_NONE
  1032. // is defined to be greater than other log levels.
  1033. if (log_level_ == 0) {
  1034. // Prevent the default logging mechanism from logging the message.
  1035. return true;
  1036. }
  1037. FuchsiaLogSeverity severity =
  1038. BlinkConsoleMessageLevelToFxLogSeverity(log_level);
  1039. if (severity < log_level_) {
  1040. // Prevent the default logging mechanism from logging the message.
  1041. return true;
  1042. }
  1043. if (!console_logger_.is_valid()) {
  1044. // Log via the process' LogSink service if none was set on the Frame.
  1045. // Connect on-demand, so that embedders need not provide a LogSink in the
  1046. // CreateContextParams services, unless they actually enable logging.
  1047. console_logger_ = base::ScopedFxLogger::CreateFromLogSink(
  1048. base::ComponentContextForProcess()
  1049. ->svc()
  1050. ->Connect<fuchsia::logger::LogSink>(),
  1051. {console_log_tag_});
  1052. if (!console_logger_.is_valid())
  1053. return false;
  1054. }
  1055. std::string source_id_utf8 = base::UTF16ToUTF8(source_id);
  1056. std::string message_utf8 = base::UTF16ToUTF8(message);
  1057. console_logger_.LogMessage(source_id_utf8, line_no, message_utf8, severity);
  1058. return true;
  1059. }
  1060. void FrameImpl::RequestMediaAccessPermission(
  1061. content::WebContents* web_contents,
  1062. const content::MediaStreamRequest& request,
  1063. content::MediaResponseCallback callback) {
  1064. DCHECK_EQ(web_contents_.get(), web_contents);
  1065. std::vector<blink::PermissionType> permissions;
  1066. if (request.audio_type ==
  1067. blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) {
  1068. permissions.push_back(blink::PermissionType::AUDIO_CAPTURE);
  1069. } else if (request.audio_type != blink::mojom::MediaStreamType::NO_SERVICE) {
  1070. std::move(callback).Run(
  1071. blink::mojom::StreamDevicesSet(),
  1072. blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
  1073. return;
  1074. }
  1075. if (request.video_type ==
  1076. blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) {
  1077. permissions.push_back(blink::PermissionType::VIDEO_CAPTURE);
  1078. } else if (request.video_type != blink::mojom::MediaStreamType::NO_SERVICE) {
  1079. std::move(callback).Run(
  1080. blink::mojom::StreamDevicesSet(),
  1081. blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
  1082. return;
  1083. }
  1084. auto* render_frame_host = content::RenderFrameHost::FromID(
  1085. request.render_process_id, request.render_frame_id);
  1086. if (!render_frame_host) {
  1087. std::move(callback).Run(
  1088. blink::mojom::StreamDevicesSet(),
  1089. blink::mojom::MediaStreamRequestResult::INVALID_STATE, nullptr);
  1090. return;
  1091. }
  1092. if (url::Origin::Create(request.security_origin) !=
  1093. render_frame_host->GetLastCommittedOrigin()) {
  1094. std::move(callback).Run(
  1095. blink::mojom::StreamDevicesSet(),
  1096. blink::mojom::MediaStreamRequestResult::INVALID_SECURITY_ORIGIN,
  1097. nullptr);
  1098. return;
  1099. }
  1100. content::PermissionController* permission_controller =
  1101. web_contents_->GetBrowserContext()->GetPermissionController();
  1102. DCHECK(permission_controller);
  1103. permission_controller->RequestPermissionsFromCurrentDocument(
  1104. permissions, render_frame_host, request.user_gesture,
  1105. base::BindOnce(&HandleMediaPermissionsRequestResult, request,
  1106. std::move(callback)));
  1107. }
  1108. bool FrameImpl::CheckMediaAccessPermission(
  1109. content::RenderFrameHost* render_frame_host,
  1110. const GURL& security_origin,
  1111. blink::mojom::MediaStreamType type) {
  1112. blink::PermissionType permission;
  1113. switch (type) {
  1114. case blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE:
  1115. permission = blink::PermissionType::AUDIO_CAPTURE;
  1116. break;
  1117. case blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE:
  1118. permission = blink::PermissionType::VIDEO_CAPTURE;
  1119. break;
  1120. default:
  1121. NOTREACHED();
  1122. return false;
  1123. }
  1124. // TODO(crbug.com/1321100): Remove `security_origin`.
  1125. if (url::Origin::Create(security_origin) !=
  1126. render_frame_host->GetLastCommittedOrigin()) {
  1127. return false;
  1128. }
  1129. content::PermissionController* permission_controller =
  1130. web_contents_->GetBrowserContext()->GetPermissionController();
  1131. DCHECK(permission_controller);
  1132. return permission_controller->GetPermissionStatusForCurrentDocument(
  1133. permission, render_frame_host) ==
  1134. blink::mojom::PermissionStatus::GRANTED;
  1135. }
  1136. bool FrameImpl::CanOverscrollContent() {
  1137. // Don't process "overscroll" events (e.g. pull-to-refresh, swipe back,
  1138. // swipe forward).
  1139. // TODO(crbug/1177399): Add overscroll toggle to Frame API.
  1140. return false;
  1141. }
  1142. void FrameImpl::ReadyToCommitNavigation(
  1143. content::NavigationHandle* navigation_handle) {
  1144. if (!navigation_handle->IsInPrimaryMainFrame() ||
  1145. navigation_handle->IsSameDocument() || navigation_handle->IsErrorPage()) {
  1146. return;
  1147. }
  1148. script_injector_.InjectScriptsForURL(navigation_handle->GetURL(),
  1149. navigation_handle->GetRenderFrameHost());
  1150. MaybeStartCastStreaming(navigation_handle);
  1151. }
  1152. void FrameImpl::DidFinishLoad(content::RenderFrameHost* render_frame_host,
  1153. const GURL& validated_url) {
  1154. context_->devtools_controller()->OnFrameLoaded(web_contents_.get());
  1155. }
  1156. void FrameImpl::RenderFrameCreated(content::RenderFrameHost* frame_host) {
  1157. // The top-level frame is given a transparent background color.
  1158. // GetView() is guaranteed to be non-null until |frame_host| teardown.
  1159. if (!frame_host->GetParentOrOuterDocument()) {
  1160. frame_host->GetView()->SetBackgroundColor(SK_AlphaTRANSPARENT);
  1161. }
  1162. }
  1163. void FrameImpl::RenderViewHostChanged(content::RenderViewHost* old_host,
  1164. content::RenderViewHost* new_host) {
  1165. // UpdateRenderViewZoomLevel() sets temporary zoom level for the current
  1166. // RenderView. It needs to be called again whenever main RenderView is
  1167. // changed.
  1168. UpdateRenderViewZoomLevel(new_host);
  1169. }
  1170. void FrameImpl::DidFirstVisuallyNonEmptyPaint() {
  1171. base::RecordComputedAction("AppFirstPaint");
  1172. }
  1173. void FrameImpl::ResourceLoadComplete(
  1174. content::RenderFrameHost* render_frame_host,
  1175. const content::GlobalRequestID& request_id,
  1176. const blink::mojom::ResourceLoadInfo& resource_load_info) {
  1177. int net_error = resource_load_info.net_error;
  1178. if (net_error != net::OK) {
  1179. base::RecordComputedAction(
  1180. base::StringPrintf("WebEngine.ResourceRequestError:%d", net_error));
  1181. }
  1182. }
  1183. // TODO(crbug.com/1136681#c6): Move below GetBindingChannelForTest when fixed.
  1184. void FrameImpl::EnableExplicitSitesFilter(std::string error_page) {
  1185. explicit_sites_filter_error_page_ = std::move(error_page);
  1186. }
  1187. void FrameImpl::SetAccessibilityEnabled(bool enabled) {
  1188. auto* browser_accessibility_state =
  1189. content::BrowserAccessibilityState::GetInstance();
  1190. if (enabled) {
  1191. browser_accessibility_state->AddAccessibilityModeFlags(ui::kAXModeComplete);
  1192. } else {
  1193. browser_accessibility_state->RemoveAccessibilityModeFlags(
  1194. ui::kAXModeComplete);
  1195. }
  1196. }
  1197. void FrameImpl::OnPixelScaleUpdate(float pixel_scale) {
  1198. if (v2_accessibility_bridge_) {
  1199. v2_accessibility_bridge_->SetPixelScale(pixel_scale);
  1200. }
  1201. }