browser_controls_navigation_state_handler.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright 2020 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 "weblayer/browser/browser_controls_navigation_state_handler.h"
  5. #include "base/feature_list.h"
  6. #include "build/build_config.h"
  7. #include "components/security_state/content/content_utils.h"
  8. #include "components/security_state/core/security_state.h"
  9. #include "content/public/browser/navigation_controller.h"
  10. #include "content/public/browser/navigation_entry.h"
  11. #include "content/public/browser/navigation_handle.h"
  12. #include "content/public/browser/render_frame_host.h"
  13. #include "content/public/browser/render_process_host.h"
  14. #include "content/public/browser/render_widget_host.h"
  15. #include "content/public/browser/render_widget_host_view.h"
  16. #include "content/public/browser/web_contents.h"
  17. #include "content/public/common/url_constants.h"
  18. #include "weblayer/browser/browser_controls_navigation_state_handler_delegate.h"
  19. #include "weblayer/browser/controls_visibility_reason.h"
  20. #include "weblayer/browser/weblayer_features.h"
  21. namespace weblayer {
  22. namespace {
  23. // The time that must elapse after a navigation before the browser controls can
  24. // be hidden. This value matches what chrome has in
  25. // TabStateBrowserControlsVisibilityDelegate.
  26. base::TimeDelta GetBrowserControlsAllowHideDelay() {
  27. if (base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest))
  28. return base::TimeDelta();
  29. return base::Seconds(3);
  30. }
  31. } // namespace
  32. BrowserControlsNavigationStateHandler::BrowserControlsNavigationStateHandler(
  33. content::WebContents* web_contents,
  34. BrowserControlsNavigationStateHandlerDelegate* delegate)
  35. : WebContentsObserver(web_contents), delegate_(delegate) {}
  36. BrowserControlsNavigationStateHandler::
  37. ~BrowserControlsNavigationStateHandler() = default;
  38. bool BrowserControlsNavigationStateHandler::IsRendererControllingOffsets() {
  39. if (IsRendererHungOrCrashed())
  40. return false;
  41. return !web_contents()->GetPrimaryMainFrame()->GetProcess()->IsBlocked();
  42. }
  43. void BrowserControlsNavigationStateHandler::DidStartNavigation(
  44. content::NavigationHandle* navigation_handle) {
  45. is_crashed_ = false;
  46. if (navigation_handle->IsInPrimaryMainFrame() &&
  47. !navigation_handle->IsSameDocument()) {
  48. forced_show_during_load_timer_.Stop();
  49. SetForceShowDuringLoad(true);
  50. }
  51. }
  52. void BrowserControlsNavigationStateHandler::DidFinishNavigation(
  53. content::NavigationHandle* navigation_handle) {
  54. if (navigation_handle->IsInPrimaryMainFrame()) {
  55. if (!navigation_handle->HasCommitted()) {
  56. // There will be no DidFinishLoad or DidFailLoad, so hide the topview
  57. ScheduleStopDelayedForceShow();
  58. }
  59. delegate_->OnUpdateBrowserControlsStateBecauseOfProcessSwitch(
  60. navigation_handle->HasCommitted());
  61. }
  62. }
  63. void BrowserControlsNavigationStateHandler::DidFinishLoad(
  64. content::RenderFrameHost* render_frame_host,
  65. const GURL& validated_url) {
  66. if (render_frame_host->IsInPrimaryMainFrame())
  67. ScheduleStopDelayedForceShow();
  68. }
  69. void BrowserControlsNavigationStateHandler::DidFailLoad(
  70. content::RenderFrameHost* render_frame_host,
  71. const GURL& validated_url,
  72. int error_code) {
  73. if (render_frame_host->IsInPrimaryMainFrame()) {
  74. ScheduleStopDelayedForceShow();
  75. UpdateState();
  76. }
  77. }
  78. void BrowserControlsNavigationStateHandler::DidChangeVisibleSecurityState() {
  79. UpdateState();
  80. }
  81. void BrowserControlsNavigationStateHandler::PrimaryMainFrameRenderProcessGone(
  82. base::TerminationStatus status) {
  83. is_crashed_ = true;
  84. UpdateState();
  85. }
  86. void BrowserControlsNavigationStateHandler::OnRendererUnresponsive(
  87. content::RenderProcessHost* render_process_host) {
  88. UpdateState();
  89. }
  90. void BrowserControlsNavigationStateHandler::OnRendererResponsive(
  91. content::RenderProcessHost* render_process_host) {
  92. UpdateState();
  93. }
  94. void BrowserControlsNavigationStateHandler::SetForceShowDuringLoad(bool value) {
  95. if (force_show_during_load_ == value)
  96. return;
  97. force_show_during_load_ = value;
  98. UpdateState();
  99. }
  100. void BrowserControlsNavigationStateHandler::ScheduleStopDelayedForceShow() {
  101. forced_show_during_load_timer_.Start(
  102. FROM_HERE, GetBrowserControlsAllowHideDelay(),
  103. base::BindOnce(
  104. &BrowserControlsNavigationStateHandler::SetForceShowDuringLoad,
  105. base::Unretained(this), false));
  106. }
  107. void BrowserControlsNavigationStateHandler::UpdateState() {
  108. const cc::BrowserControlsState renderer_availability_state =
  109. CalculateStateForReasonRendererAvailability();
  110. if (renderer_availability_state != last_renderer_availability_state_) {
  111. last_renderer_availability_state_ = renderer_availability_state;
  112. delegate_->OnBrowserControlsStateStateChanged(
  113. ControlsVisibilityReason::kRendererUnavailable,
  114. last_renderer_availability_state_);
  115. }
  116. const cc::BrowserControlsState other_state = CalculateStateForReasonOther();
  117. if (other_state != last_other_state_) {
  118. last_other_state_ = other_state;
  119. delegate_->OnBrowserControlsStateStateChanged(
  120. ControlsVisibilityReason::kOther, last_other_state_);
  121. }
  122. }
  123. cc::BrowserControlsState BrowserControlsNavigationStateHandler::
  124. CalculateStateForReasonRendererAvailability() {
  125. if (!IsRendererControllingOffsets() || web_contents()->IsBeingDestroyed() ||
  126. web_contents()->IsCrashed()) {
  127. return cc::BrowserControlsState::kShown;
  128. }
  129. return cc::BrowserControlsState::kBoth;
  130. }
  131. cc::BrowserControlsState
  132. BrowserControlsNavigationStateHandler::CalculateStateForReasonOther() {
  133. // TODO(sky): this needs to force SHOWN if a11y enabled, see
  134. // AccessibilityUtil.isAccessibilityEnabled().
  135. if (force_show_during_load_ || web_contents()->IsFullscreen() ||
  136. web_contents()->IsFocusedElementEditable()) {
  137. return cc::BrowserControlsState::kShown;
  138. }
  139. content::NavigationEntry* entry =
  140. web_contents()->GetController().GetVisibleEntry();
  141. if (!entry || entry->GetPageType() != content::PAGE_TYPE_NORMAL)
  142. return cc::BrowserControlsState::kShown;
  143. if (entry->GetURL().SchemeIs(content::kChromeUIScheme))
  144. return cc::BrowserControlsState::kShown;
  145. const security_state::SecurityLevel security_level =
  146. security_state::GetSecurityLevel(
  147. *security_state::GetVisibleSecurityState(web_contents()),
  148. /* used_policy_installed_certificate= */ false);
  149. switch (security_level) {
  150. case security_state::WARNING:
  151. case security_state::DANGEROUS:
  152. return cc::BrowserControlsState::kShown;
  153. case security_state::NONE:
  154. case security_state::SECURE:
  155. case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
  156. case security_state::SECURITY_LEVEL_COUNT:
  157. break;
  158. }
  159. return cc::BrowserControlsState::kBoth;
  160. }
  161. bool BrowserControlsNavigationStateHandler::IsRendererHungOrCrashed() {
  162. if (is_crashed_)
  163. return true;
  164. content::RenderWidgetHostView* view =
  165. web_contents()->GetRenderWidgetHostView();
  166. if (view && view->GetRenderWidgetHost() &&
  167. view->GetRenderWidgetHost()->IsCurrentlyUnresponsive()) {
  168. // Renderer is hung.
  169. return true;
  170. }
  171. return web_contents()->IsCrashed();
  172. }
  173. } // namespace weblayer