123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "weblayer/browser/navigation_controller_impl.h"
- #include <utility>
- #include "base/auto_reset.h"
- #include "base/containers/contains.h"
- #include "base/memory/raw_ptr.h"
- #include "base/strings/utf_string_conversions.h"
- #include "build/build_config.h"
- #include "content/public/browser/navigation_controller.h"
- #include "content/public/browser/navigation_entry.h"
- #include "content/public/browser/navigation_handle.h"
- #include "content/public/browser/navigation_throttle.h"
- #include "content/public/browser/web_contents.h"
- #include "third_party/blink/public/mojom/navigation/was_activated_option.mojom-shared.h"
- #include "ui/base/page_transition_types.h"
- #include "weblayer/browser/navigation_entry_data.h"
- #include "weblayer/browser/navigation_ui_data_impl.h"
- #include "weblayer/browser/page_impl.h"
- #include "weblayer/browser/tab_impl.h"
- #include "weblayer/public/navigation_observer.h"
- #if BUILDFLAG(IS_ANDROID)
- #include "base/android/jni_string.h"
- #include "base/trace_event/trace_event.h"
- #include "components/embedder_support/android/util/web_resource_response.h"
- #include "weblayer/browser/java/jni/NavigationControllerImpl_jni.h"
- #endif
- #if BUILDFLAG(IS_ANDROID)
- using base::android::AttachCurrentThread;
- using base::android::JavaParamRef;
- using base::android::ScopedJavaLocalRef;
- #endif
- namespace weblayer {
- class NavigationControllerImpl::DelayDeletionHelper {
- public:
- explicit DelayDeletionHelper(NavigationControllerImpl* controller)
- : controller_(controller->weak_ptr_factory_.GetWeakPtr()) {
- // This should never be called reentrantly.
- DCHECK(!controller->should_delay_web_contents_deletion_);
- controller->should_delay_web_contents_deletion_ = true;
- }
- DelayDeletionHelper(const DelayDeletionHelper&) = delete;
- DelayDeletionHelper& operator=(const DelayDeletionHelper&) = delete;
- ~DelayDeletionHelper() {
- if (controller_)
- controller_->should_delay_web_contents_deletion_ = false;
- }
- bool WasControllerDeleted() { return controller_.get() == nullptr; }
- private:
- base::WeakPtr<NavigationControllerImpl> controller_;
- };
- // NavigationThrottle implementation responsible for delaying certain
- // operations and performing them when safe. This is necessary as content
- // does allow certain operations to be called at certain times. For example,
- // content does not allow calling WebContents::Stop() from
- // WebContentsObserver::DidStartNavigation() (to do so crashes). To work around
- // this NavigationControllerImpl detects these scenarios and delays processing
- // until safe.
- //
- // Most of the support for these scenarios is handled by a custom
- // NavigationThrottle. To make things interesting, the NavigationThrottle is
- // created after some of the scenarios this code wants to handle. As such,
- // NavigationImpl does some amount of caching until the NavigationThrottle is
- // created.
- class NavigationControllerImpl::NavigationThrottleImpl
- : public content::NavigationThrottle {
- public:
- NavigationThrottleImpl(NavigationControllerImpl* controller,
- content::NavigationHandle* handle)
- : NavigationThrottle(handle), controller_(controller) {}
- NavigationThrottleImpl(const NavigationThrottleImpl&) = delete;
- NavigationThrottleImpl& operator=(const NavigationThrottleImpl&) = delete;
- ~NavigationThrottleImpl() override = default;
- void ScheduleCancel() { should_cancel_ = true; }
- // content::NavigationThrottle:
- ThrottleCheckResult WillStartRequest() override {
- return should_cancel_ ? CANCEL : PROCEED;
- }
- ThrottleCheckResult WillRedirectRequest() override {
- controller_->WillRedirectRequest(this, navigation_handle());
- return should_cancel_ ? CANCEL : PROCEED;
- }
- const char* GetNameForLogging() override {
- return "WebLayerNavigationControllerThrottle";
- }
- private:
- raw_ptr<NavigationControllerImpl> controller_;
- bool should_cancel_ = false;
- };
- NavigationControllerImpl::NavigationControllerImpl(TabImpl* tab)
- : WebContentsObserver(tab->web_contents()) {}
- NavigationControllerImpl::~NavigationControllerImpl() = default;
- std::unique_ptr<content::NavigationThrottle>
- NavigationControllerImpl::CreateNavigationThrottle(
- content::NavigationHandle* handle) {
- if (!handle->IsInMainFrame())
- return nullptr;
- auto throttle = std::make_unique<NavigationThrottleImpl>(this, handle);
- DCHECK(navigation_map_.find(handle) != navigation_map_.end());
- auto* navigation = navigation_map_[handle].get();
- if (navigation->should_stop_when_throttle_created())
- throttle->ScheduleCancel();
- return throttle;
- }
- NavigationImpl* NavigationControllerImpl::GetNavigationImplFromHandle(
- content::NavigationHandle* handle) {
- auto iter = navigation_map_.find(handle);
- return iter == navigation_map_.end() ? nullptr : iter->second.get();
- }
- NavigationImpl* NavigationControllerImpl::GetNavigationImplFromId(
- int64_t navigation_id) {
- for (const auto& iter : navigation_map_) {
- if (iter.first->GetNavigationId() == navigation_id)
- return iter.second.get();
- }
- return nullptr;
- }
- void NavigationControllerImpl::OnFirstContentfulPaint(
- const base::TimeTicks& navigation_start,
- const base::TimeDelta& first_contentful_paint) {
- #if BUILDFLAG(IS_ANDROID)
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_onFirstContentfulPaint2");
- int64_t first_contentful_paint_ms = first_contentful_paint.InMilliseconds();
- Java_NavigationControllerImpl_onFirstContentfulPaint2(
- AttachCurrentThread(), java_controller_,
- navigation_start.ToUptimeMillis(), first_contentful_paint_ms);
- #endif
- for (auto& observer : observers_)
- observer.OnFirstContentfulPaint(navigation_start, first_contentful_paint);
- }
- void NavigationControllerImpl::OnLargestContentfulPaint(
- const base::TimeTicks& navigation_start,
- const base::TimeDelta& largest_contentful_paint) {
- #if BUILDFLAG(IS_ANDROID)
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_onLargestContentfulPaint2");
- int64_t largest_contentful_paint_ms =
- largest_contentful_paint.InMilliseconds();
- Java_NavigationControllerImpl_onLargestContentfulPaint(
- AttachCurrentThread(), java_controller_,
- navigation_start.ToUptimeMillis(), largest_contentful_paint_ms);
- #endif
- for (auto& observer : observers_)
- observer.OnLargestContentfulPaint(navigation_start,
- largest_contentful_paint);
- }
- void NavigationControllerImpl::OnPageDestroyed(Page* page) {
- for (auto& observer : observers_)
- observer.OnPageDestroyed(page);
- }
- void NavigationControllerImpl::OnPageLanguageDetermined(
- Page* page,
- const std::string& language) {
- #if BUILDFLAG(IS_ANDROID)
- JNIEnv* env = AttachCurrentThread();
- Java_NavigationControllerImpl_onPageLanguageDetermined(
- env, java_controller_, static_cast<PageImpl*>(page)->java_page(),
- base::android::ConvertUTF8ToJavaString(env, language));
- #endif
- for (auto& observer : observers_)
- observer.OnPageLanguageDetermined(page, language);
- }
- #if BUILDFLAG(IS_ANDROID)
- void NavigationControllerImpl::SetNavigationControllerImpl(
- JNIEnv* env,
- const JavaParamRef<jobject>& java_controller) {
- java_controller_ = java_controller;
- }
- void NavigationControllerImpl::Navigate(
- JNIEnv* env,
- const JavaParamRef<jstring>& url,
- jboolean should_replace_current_entry,
- jboolean disable_intent_processing,
- jboolean allow_intent_launches_in_background,
- jboolean disable_network_error_auto_reload,
- jboolean enable_auto_play,
- const base::android::JavaParamRef<jobject>& response) {
- auto params = std::make_unique<content::NavigationController::LoadURLParams>(
- GURL(base::android::ConvertJavaStringToUTF8(env, url)));
- params->should_replace_current_entry = should_replace_current_entry;
- // On android, the transition type largely dictates whether intent processing
- // happens. PAGE_TRANSITION_TYPED does not process intents, where as
- // PAGE_TRANSITION_LINK will (with the caveat that even links may not trigger
- // intent processing under some circumstances).
- params->transition_type = disable_intent_processing
- ? ui::PAGE_TRANSITION_TYPED
- : ui::PAGE_TRANSITION_LINK;
- auto data = std::make_unique<NavigationUIDataImpl>();
- if (disable_network_error_auto_reload)
- data->set_disable_network_error_auto_reload(true);
- data->set_allow_intent_launches_in_background(
- allow_intent_launches_in_background);
- if (!response.is_null()) {
- data->SetResponse(
- std::make_unique<embedder_support::WebResourceResponse>(response));
- }
- params->navigation_ui_data = std::move(data);
- if (enable_auto_play)
- params->was_activated = blink::mojom::WasActivatedOption::kYes;
- DoNavigate(std::move(params));
- }
- ScopedJavaLocalRef<jstring>
- NavigationControllerImpl::GetNavigationEntryDisplayUri(JNIEnv* env, int index) {
- return ScopedJavaLocalRef<jstring>(base::android::ConvertUTF8ToJavaString(
- env, GetNavigationEntryDisplayURL(index).spec()));
- }
- ScopedJavaLocalRef<jstring> NavigationControllerImpl::GetNavigationEntryTitle(
- JNIEnv* env,
- int index) {
- return ScopedJavaLocalRef<jstring>(base::android::ConvertUTF8ToJavaString(
- env, GetNavigationEntryTitle(index)));
- }
- bool NavigationControllerImpl::IsNavigationEntrySkippable(JNIEnv* env,
- int index) {
- return IsNavigationEntrySkippable(index);
- }
- base::android::ScopedJavaGlobalRef<jobject>
- NavigationControllerImpl::GetNavigationImplFromId(JNIEnv* env, int64_t id) {
- auto* navigation_impl = GetNavigationImplFromId(id);
- return navigation_impl ? navigation_impl->java_navigation() : nullptr;
- }
- #endif
- void NavigationControllerImpl::WillRedirectRequest(
- NavigationThrottleImpl* throttle,
- content::NavigationHandle* navigation_handle) {
- DCHECK(navigation_handle->IsInMainFrame());
- DCHECK(navigation_map_.find(navigation_handle) != navigation_map_.end());
- auto* navigation = navigation_map_[navigation_handle].get();
- navigation->set_safe_to_set_request_headers(true);
- DCHECK(!active_throttle_);
- base::AutoReset<NavigationThrottleImpl*> auto_reset(&active_throttle_,
- throttle);
- #if BUILDFLAG(IS_ANDROID)
- if (java_controller_) {
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_navigationRedirected");
- Java_NavigationControllerImpl_navigationRedirected(
- AttachCurrentThread(), java_controller_, navigation->java_navigation());
- }
- #endif
- for (auto& observer : observers_)
- observer.NavigationRedirected(navigation);
- navigation->set_safe_to_set_request_headers(false);
- }
- void NavigationControllerImpl::AddObserver(NavigationObserver* observer) {
- observers_.AddObserver(observer);
- }
- void NavigationControllerImpl::RemoveObserver(NavigationObserver* observer) {
- observers_.RemoveObserver(observer);
- }
- void NavigationControllerImpl::Navigate(const GURL& url) {
- DoNavigate(
- std::make_unique<content::NavigationController::LoadURLParams>(url));
- }
- void NavigationControllerImpl::Navigate(
- const GURL& url,
- const NavigationController::NavigateParams& params) {
- auto load_params =
- std::make_unique<content::NavigationController::LoadURLParams>(url);
- load_params->should_replace_current_entry =
- params.should_replace_current_entry;
- if (params.enable_auto_play)
- load_params->was_activated = blink::mojom::WasActivatedOption::kYes;
- DoNavigate(std::move(load_params));
- }
- void NavigationControllerImpl::GoBack() {
- web_contents()->GetController().GoBack();
- }
- void NavigationControllerImpl::GoForward() {
- web_contents()->GetController().GoForward();
- }
- bool NavigationControllerImpl::CanGoBack() {
- return web_contents()->GetController().CanGoBack();
- }
- bool NavigationControllerImpl::CanGoForward() {
- return web_contents()->GetController().CanGoForward();
- }
- void NavigationControllerImpl::GoToIndex(int index) {
- web_contents()->GetController().GoToIndex(index);
- }
- void NavigationControllerImpl::Reload() {
- web_contents()->GetController().Reload(content::ReloadType::NORMAL, true);
- }
- void NavigationControllerImpl::Stop() {
- CancelDelayedLoad();
- NavigationImpl* navigation = nullptr;
- if (navigation_starting_) {
- navigation_starting_->set_should_stop_when_throttle_created();
- navigation = navigation_starting_;
- } else if (active_throttle_) {
- active_throttle_->ScheduleCancel();
- DCHECK(navigation_map_.find(active_throttle_->navigation_handle()) !=
- navigation_map_.end());
- navigation = navigation_map_[active_throttle_->navigation_handle()].get();
- } else {
- web_contents()->Stop();
- }
- if (navigation)
- navigation->set_was_stopped();
- }
- int NavigationControllerImpl::GetNavigationListSize() {
- content::NavigationEntry* current_entry =
- web_contents()->GetController().GetLastCommittedEntry();
- if (current_entry && current_entry->IsInitialEntry()) {
- // If we're currently on the initial NavigationEntry, no navigation has
- // committed, so the initial NavigationEntry should not be part of the
- // "Navigation List", and we should return 0 as the navigation list size.
- // This also preserves the old behavior where we used to not have the
- // initial NavigationEntry.
- return 0;
- }
- return web_contents()->GetController().GetEntryCount();
- }
- int NavigationControllerImpl::GetNavigationListCurrentIndex() {
- content::NavigationEntry* current_entry =
- web_contents()->GetController().GetLastCommittedEntry();
- if (current_entry && current_entry->IsInitialEntry()) {
- // If we're currently on the initial NavigationEntry, no navigation has
- // committed, so the initial NavigationEntry should not be part of the
- // "Navigation List", and we should return -1 as the current index. This
- // also preserves the old behavior where we used to not have the initial
- // NavigationEntry.
- return -1;
- }
- return web_contents()->GetController().GetCurrentEntryIndex();
- }
- GURL NavigationControllerImpl::GetNavigationEntryDisplayURL(int index) {
- auto* entry = web_contents()->GetController().GetEntryAtIndex(index);
- // This function should never be called when GetNavigationListSize() is 0
- // because `index` should be between 0 and GetNavigationListSize() - 1, which
- // also means `entry` must not be the initial NavigationEntry.
- DCHECK_NE(0, GetNavigationListSize());
- DCHECK(!entry->IsInitialEntry());
- return entry->GetVirtualURL();
- }
- std::string NavigationControllerImpl::GetNavigationEntryTitle(int index) {
- auto* entry = web_contents()->GetController().GetEntryAtIndex(index);
- // This function should never be called when GetNavigationListSize() is 0
- // because `index` should be between 0 and GetNavigationListSize() - 1, which
- // also means `entry` must not be the initial NavigationEntry.
- DCHECK_NE(0, GetNavigationListSize());
- DCHECK(!entry->IsInitialEntry());
- return base::UTF16ToUTF8(entry->GetTitle());
- }
- bool NavigationControllerImpl::IsNavigationEntrySkippable(int index) {
- return web_contents()->GetController().IsEntryMarkedToBeSkipped(index);
- }
- void NavigationControllerImpl::DidStartNavigation(
- content::NavigationHandle* navigation_handle) {
- // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
- // frames. This caller was converted automatically to the primary main frame
- // to preserve its semantics. Follow up to confirm correctness.
- if (!navigation_handle->IsInPrimaryMainFrame())
- return;
- // This function should not be called reentrantly.
- DCHECK(!navigation_starting_);
- DCHECK(!base::Contains(navigation_map_, navigation_handle));
- navigation_map_[navigation_handle] =
- std::make_unique<NavigationImpl>(navigation_handle);
- auto* navigation = navigation_map_[navigation_handle].get();
- base::AutoReset<NavigationImpl*> auto_reset(&navigation_starting_,
- navigation);
- navigation->set_safe_to_set_request_headers(true);
- navigation->set_safe_to_disable_network_error_auto_reload(true);
- navigation->set_safe_to_disable_intent_processing(true);
- #if BUILDFLAG(IS_ANDROID)
- // Desktop mode and per-navigation UA use the same mechanism and so don't
- // interact well. It's not possible to support both at the same time since
- // if there's a per-navigation UA active and desktop mode is turned on, or
- // was on previously, the WebContent's state would have to change before
- // navigation even though that would be wrong for the previous navigation if
- // the new navigation didn't commit.
- if (!TabImpl::FromWebContents(web_contents())->desktop_user_agent_enabled())
- #endif
- navigation->set_safe_to_set_user_agent(true);
- #if BUILDFLAG(IS_ANDROID)
- NavigationUIDataImpl* navigation_ui_data = static_cast<NavigationUIDataImpl*>(
- navigation_handle->GetNavigationUIData());
- if (navigation_ui_data) {
- auto response = navigation_ui_data->TakeResponse();
- if (response)
- navigation->SetResponse(std::move(response));
- }
- if (java_controller_) {
- JNIEnv* env = AttachCurrentThread();
- {
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_createNavigation");
- ScopedJavaLocalRef<jobject> java_navigation =
- Java_NavigationControllerImpl_createNavigation(
- env, java_controller_, reinterpret_cast<jlong>(navigation));
- navigation->SetJavaNavigation(
- base::android::ScopedJavaGlobalRef<jobject>(java_navigation));
- }
- TRACE_EVENT0("weblayer", "Java_NavigationControllerImpl_navigationStarted");
- Java_NavigationControllerImpl_navigationStarted(
- env, java_controller_, navigation->java_navigation());
- }
- #endif
- for (auto& observer : observers_)
- observer.NavigationStarted(navigation);
- navigation->set_safe_to_set_user_agent(false);
- navigation->set_safe_to_set_request_headers(false);
- navigation->set_safe_to_disable_network_error_auto_reload(false);
- navigation->set_safe_to_disable_intent_processing(false);
- }
- void NavigationControllerImpl::DidRedirectNavigation(
- content::NavigationHandle* navigation_handle) {
- // NOTE: this implementation should remain empty. Real implementation is in
- // WillRedirectNavigation(). See description of NavigationThrottleImpl for
- // more information.
- }
- void NavigationControllerImpl::ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) {
- #if BUILDFLAG(IS_ANDROID)
- // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
- // frames. This caller was converted automatically to the primary main frame
- // to preserve its semantics. Follow up to confirm correctness.
- if (!navigation_handle->IsInPrimaryMainFrame())
- return;
- DCHECK(navigation_map_.find(navigation_handle) != navigation_map_.end());
- auto* navigation = navigation_map_[navigation_handle].get();
- if (java_controller_) {
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_readyToCommitNavigation");
- Java_NavigationControllerImpl_readyToCommitNavigation(
- AttachCurrentThread(), java_controller_, navigation->java_navigation());
- }
- #endif
- }
- void NavigationControllerImpl::DidFinishNavigation(
- content::NavigationHandle* navigation_handle) {
- // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
- // frames. This caller was converted automatically to the primary main frame
- // to preserve its semantics. Follow up to confirm correctness.
- if (!navigation_handle->IsInPrimaryMainFrame())
- return;
- DelayDeletionHelper deletion_helper(this);
- DCHECK(navigation_map_.find(navigation_handle) != navigation_map_.end());
- auto* navigation = navigation_map_[navigation_handle].get();
- navigation->set_finished();
- if (navigation_handle->HasCommitted()) {
- // Set state on NavigationEntry user data if a per-navigation user agent was
- // specified. This can't be done earlier because a NavigationEntry might not
- // have existed at the time that SetUserAgentString was called.
- if (navigation->set_user_agent_string_called()) {
- auto* entry = web_contents()->GetController().GetLastCommittedEntry();
- if (entry) {
- auto* entry_data = NavigationEntryData::Get(entry);
- if (entry_data)
- entry_data->set_per_navigation_user_agent_override(true);
- }
- }
- auto* rfh = navigation_handle->GetRenderFrameHost();
- PageImpl::GetOrCreateForPage(rfh->GetPage());
- navigation->set_safe_to_get_page();
- #if BUILDFLAG(IS_ANDROID)
- // Ensure that the Java-side Page object for this navigation is
- // populated from and linked to the native Page object. Without this
- // call, the Java-side navigation object won't be created and linked to
- // the native object until/unless the client calls Navigation#getPage(),
- // which is problematic when implementation-side callers need to bridge
- // the C++ Page object into Java (e.g., to fire
- // NavigationCallback#onPageLanguageDetermined()).
- Java_NavigationControllerImpl_getOrCreatePageForNavigation(
- AttachCurrentThread(), java_controller_, navigation->java_navigation());
- #endif
- }
- // In some corner cases (e.g., a tab closing with an ongoing navigation)
- // navigations finish without committing but without any other error state.
- // Such navigations are regarded as failed by WebLayer.
- if (navigation_handle->HasCommitted() &&
- navigation_handle->GetNetErrorCode() == net::OK &&
- !navigation_handle->IsErrorPage()) {
- #if BUILDFLAG(IS_ANDROID)
- if (java_controller_) {
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_navigationCompleted");
- Java_NavigationControllerImpl_navigationCompleted(
- AttachCurrentThread(), java_controller_,
- navigation->java_navigation());
- if (deletion_helper.WasControllerDeleted())
- return;
- }
- #endif
- for (auto& observer : observers_) {
- observer.NavigationCompleted(navigation);
- if (deletion_helper.WasControllerDeleted())
- return;
- }
- } else {
- #if BUILDFLAG(IS_ANDROID)
- if (java_controller_) {
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_navigationFailed");
- Java_NavigationControllerImpl_navigationFailed(
- AttachCurrentThread(), java_controller_,
- navigation->java_navigation());
- if (deletion_helper.WasControllerDeleted())
- return;
- }
- #endif
- for (auto& observer : observers_) {
- observer.NavigationFailed(navigation);
- if (deletion_helper.WasControllerDeleted())
- return;
- }
- }
- // Note InsertVisualStateCallback currently does not take into account
- // any delays from surface sync, ie a frame submitted by renderer may not
- // be displayed immediately. Such situations should be rare however, so
- // this should be good enough for the purposes needed.
- web_contents()->GetPrimaryMainFrame()->InsertVisualStateCallback(
- base::BindOnce(&NavigationControllerImpl::OldPageNoLongerRendered,
- weak_ptr_factory_.GetWeakPtr(),
- navigation_handle->GetURL()));
- navigation_map_.erase(navigation_map_.find(navigation_handle));
- }
- void NavigationControllerImpl::DidStartLoading() {
- NotifyLoadStateChanged();
- }
- void NavigationControllerImpl::DidStopLoading() {
- NotifyLoadStateChanged();
- }
- void NavigationControllerImpl::LoadProgressChanged(double progress) {
- #if BUILDFLAG(IS_ANDROID)
- if (java_controller_) {
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_loadProgressChanged");
- Java_NavigationControllerImpl_loadProgressChanged(
- AttachCurrentThread(), java_controller_, progress);
- }
- #endif
- for (auto& observer : observers_)
- observer.LoadProgressChanged(progress);
- }
- void NavigationControllerImpl::DidFirstVisuallyNonEmptyPaint() {
- #if BUILDFLAG(IS_ANDROID)
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_onFirstContentfulPaint");
- Java_NavigationControllerImpl_onFirstContentfulPaint(AttachCurrentThread(),
- java_controller_);
- #endif
- for (auto& observer : observers_)
- observer.OnFirstContentfulPaint();
- }
- void NavigationControllerImpl::OldPageNoLongerRendered(const GURL& url,
- bool success) {
- #if BUILDFLAG(IS_ANDROID)
- TRACE_EVENT0("weblayer",
- "Java_NavigationControllerImpl_onOldPageNoLongerRendered");
- JNIEnv* env = AttachCurrentThread();
- Java_NavigationControllerImpl_onOldPageNoLongerRendered(
- env, java_controller_,
- base::android::ConvertUTF8ToJavaString(env, url.spec()));
- #endif
- for (auto& observer : observers_)
- observer.OnOldPageNoLongerRendered(url);
- }
- void NavigationControllerImpl::NotifyLoadStateChanged() {
- #if BUILDFLAG(IS_ANDROID)
- if (java_controller_) {
- TRACE_EVENT0("weblayer", "Java_NavigationControllerImpl_loadStateChanged");
- Java_NavigationControllerImpl_loadStateChanged(
- AttachCurrentThread(), java_controller_, web_contents()->IsLoading(),
- web_contents()->ShouldShowLoadingUI());
- }
- #endif
- for (auto& observer : observers_) {
- observer.LoadStateChanged(web_contents()->IsLoading(),
- web_contents()->ShouldShowLoadingUI());
- }
- }
- void NavigationControllerImpl::DoNavigate(
- std::unique_ptr<content::NavigationController::LoadURLParams> params) {
- CancelDelayedLoad();
- // Navigations should use the default user-agent (which may be overridden if
- // desktop mode is turned on). If the embedder wants a custom user-agent, the
- // embedder will call Navigation::SetUserAgentString() in DidStartNavigation.
- #if BUILDFLAG(IS_ANDROID)
- // We need to set UA_OVERRIDE_FALSE if per navigation UA is set. However at
- // this point we don't know if the embedder will call that later. Since we
- // ensure that the two can't be set at the same time, it's sufficient to
- // not enable it if desktop mode is turned on.
- if (!TabImpl::FromWebContents(web_contents())->desktop_user_agent_enabled())
- #endif
- params->override_user_agent =
- content::NavigationController::UA_OVERRIDE_FALSE;
- if (navigation_starting_ || active_throttle_) {
- // DoNavigate() is being called reentrantly. Delay processing until it's
- // safe.
- Stop();
- ScheduleDelayedLoad(std::move(params));
- return;
- }
- params->has_user_gesture = true;
- web_contents()->GetController().LoadURLWithParams(*params);
- // So that if the user had entered the UI in a bar it stops flashing the
- // caret.
- web_contents()->Focus();
- }
- void NavigationControllerImpl::ScheduleDelayedLoad(
- std::unique_ptr<content::NavigationController::LoadURLParams> params) {
- delayed_load_params_ = std::move(params);
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&NavigationControllerImpl::ProcessDelayedLoad,
- weak_ptr_factory_.GetWeakPtr()));
- }
- void NavigationControllerImpl::CancelDelayedLoad() {
- delayed_load_params_.reset();
- }
- void NavigationControllerImpl::ProcessDelayedLoad() {
- if (delayed_load_params_)
- DoNavigate(std::move(delayed_load_params_));
- }
- #if BUILDFLAG(IS_ANDROID)
- static jlong JNI_NavigationControllerImpl_GetNavigationController(JNIEnv* env,
- jlong tab) {
- return reinterpret_cast<jlong>(
- reinterpret_cast<Tab*>(tab)->GetNavigationController());
- }
- #endif
- } // namespace weblayer
|