blob: f62d6d26dfc0707d59717770f69a15f94ad01a98 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/tabs/tab_renderer_data.h"
#include "base/process/kill.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/favicon/favicon_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom-shared.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/performance_controls/memory_saver_utils.h"
#include "chrome/browser/ui/tab_ui_helper.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
#include "chrome/browser/ui/tabs/tab_utils.h"
#include "chrome/browser/ui/thumbnails/thumbnail_tab_helper.h"
#include "chrome/browser/ui/web_applications/web_app_browser_controller.h"
#include "chrome/browser/ui/web_applications/web_app_tabbed_utils.h"
#include "components/performance_manager/public/features.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/feature_list.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// static
TabRendererData TabRendererData::FromTabInModel(const TabStripModel* model,
int index) {
content::WebContents* const contents = model->GetWebContentsAt(index);
// If the tab is showing a lookalike interstitial ("Did you mean example.com"
// on éxample.com), don't show the URL in the hover card because it's
// misleading.
security_interstitials::SecurityInterstitialTabHelper*
security_interstitial_tab_helper = security_interstitials::
SecurityInterstitialTabHelper::FromWebContents(contents);
bool should_display_url =
!security_interstitial_tab_helper ||
!security_interstitial_tab_helper->IsDisplayingInterstitial() ||
security_interstitial_tab_helper->ShouldDisplayURL();
TabRendererData data;
TabUIHelper* const tab_ui_helper = TabUIHelper::FromWebContents(contents);
data.favicon = tab_ui_helper->GetFavicon();
// Tabbed web apps should use the app icon on the home tab.
Browser* app_browser = chrome::FindBrowserWithTab(contents);
if (app_browser && app_browser->app_controller() &&
app_browser->app_controller()->ShouldShowAppIconOnTab(index)) {
web_app::WebAppBrowserController* app_controller =
app_browser->app_controller()->AsWebAppBrowserController();
if (app_controller) {
gfx::ImageSkia home_tab_icon = app_controller->GetHomeTabIcon();
if (!home_tab_icon.isNull()) {
data.is_monochrome_favicon = true;
data.favicon = ui::ImageModel::FromImageSkia(home_tab_icon);
} else {
home_tab_icon = app_controller->GetFallbackHomeTabIcon();
if (!home_tab_icon.isNull()) {
data.favicon = ui::ImageModel::FromImageSkia(home_tab_icon);
}
}
}
}
ThumbnailTabHelper* const thumbnail_tab_helper =
ThumbnailTabHelper::FromWebContents(contents);
if (thumbnail_tab_helper) {
data.thumbnail = thumbnail_tab_helper->thumbnail();
}
data.is_tab_discarded = contents->WasDiscarded();
data.network_state = TabNetworkStateForWebContents(contents);
data.title = tab_ui_helper->GetTitle();
data.visible_url = contents->GetVisibleURL();
// Allow empty title for chrome-untrusted:// URLs.
if (data.title.empty() &&
data.visible_url.SchemeIs(content::kChromeUIUntrustedScheme)) {
data.should_render_empty_title = true;
}
data.last_committed_url = contents->GetLastCommittedURL();
data.should_display_url = should_display_url;
data.crashed_status = contents->GetCrashedStatus();
data.incognito = contents->GetBrowserContext()->IsOffTheRecord();
data.pinned = model->IsTabPinned(index);
data.show_icon =
data.pinned || model->delegate()->ShouldDisplayFavicon(contents);
data.blocked = model->IsTabBlocked(index);
data.should_hide_throbber = tab_ui_helper->ShouldHideThrobber();
data.alert_state = chrome::GetTabAlertStatesForContents(contents);
content::NavigationEntry* entry =
contents->GetController().GetLastCommittedEntry();
data.should_themify_favicon =
entry && favicon::ShouldThemifyFaviconForEntry(entry);
std::optional<mojom::LifecycleUnitDiscardReason> discard_reason =
memory_saver::GetDiscardReason(contents);
// Only show discard status for tabs that were proactively discarded to
// prevent confusion to users on why a tab was discarded. Also, the favicon
// discard animation may use resources so the animation should be limited
// to proactive discards to prevent performance issues.
data.should_show_discard_status =
memory_saver::IsURLSupported(contents->GetURL()) &&
contents->WasDiscarded() && discard_reason.has_value() &&
discard_reason.value() == mojom::LifecycleUnitDiscardReason::PROACTIVE;
if (contents->WasDiscarded()) {
data.discarded_memory_savings_in_bytes =
memory_saver::GetDiscardedMemorySavingsInBytes(contents);
}
const auto* const resource_tab_helper =
performance_manager::user_tuning::UserPerformanceTuningManager::
ResourceUsageTabHelper::FromWebContents(contents);
if (resource_tab_helper) {
data.tab_resource_usage = resource_tab_helper->resource_usage();
}
return data;
}
TabRendererData::TabRendererData() = default;
TabRendererData::TabRendererData(const TabRendererData& other) = default;
TabRendererData::TabRendererData(TabRendererData&& other) = default;
TabRendererData& TabRendererData::operator=(const TabRendererData& other) =
default;
TabRendererData& TabRendererData::operator=(TabRendererData&& other) = default;
TabRendererData::~TabRendererData() = default;
bool TabRendererData::operator==(const TabRendererData& other) const {
return favicon == other.favicon && thumbnail == other.thumbnail &&
network_state == other.network_state && title == other.title &&
visible_url == other.visible_url &&
last_committed_url == other.last_committed_url &&
should_display_url == other.should_display_url &&
crashed_status == other.crashed_status &&
incognito == other.incognito && show_icon == other.show_icon &&
pinned == other.pinned && blocked == other.blocked &&
alert_state == other.alert_state &&
should_hide_throbber == other.should_hide_throbber &&
is_tab_discarded == other.is_tab_discarded &&
should_show_discard_status == other.should_show_discard_status &&
discarded_memory_savings_in_bytes ==
other.discarded_memory_savings_in_bytes &&
tab_resource_usage == other.tab_resource_usage;
}
bool TabRendererData::IsCrashed() const {
return (crashed_status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ||
#if BUILDFLAG(IS_CHROMEOS)
crashed_status ==
base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM ||
#endif
crashed_status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
crashed_status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
crashed_status == base::TERMINATION_STATUS_LAUNCH_FAILED);
}