blob: e29e6ba27308f430b9025799ee97053feb75b50f [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/web_contents/slow_web_preference_cache.h"
#include "base/command_line.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/system/sys_info.h"
#include "base/trace_event/optional_trace_event.h"
#include "build/blink_buildflags.h"
#include "content/public/common/content_switches.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "ui/base/pointer/pointer_device.h"
#include "ui/gl/gpu_switching_manager.h"
#if BUILDFLAG(IS_WIN)
#include "ui/events/devices/input_device_observer_win.h"
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "ui/events/devices/device_data_manager.h"
#elif BUILDFLAG(IS_ANDROID)
#include "ui/base/device_form_factor.h"
#include "ui/events/devices/input_device_observer_android.h"
#elif BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS) && BUILDFLAG(USE_BLINK)
#include "ui/events/devices/input_device_observer_ios.h"
#endif
namespace content {
namespace {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class AllPointerTypes {
kNone = 0,
kCoarse = 1,
kFine = 2,
kBoth = 3,
kMaxValue = kBoth
};
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class PrimaryPointerType {
kNone = 0,
kCoarse = 1,
kFine = 2,
kMaxValue = kFine
};
} // namespace
SlowWebPreferenceCacheObserver::~SlowWebPreferenceCacheObserver() = default;
SlowWebPreferenceCache::SlowWebPreferenceCache() {
gpu_switch_observation_.Observe(ui::GpuSwitchingManager::GetInstance());
#if BUILDFLAG(IS_WIN)
ui::InputDeviceObserverWin::GetInstance()->AddObserver(this);
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
ui::DeviceDataManager::GetInstance()->AddObserver(this);
#elif BUILDFLAG(IS_ANDROID)
ui::InputDeviceObserverAndroid::GetInstance()->AddObserver(this);
#elif BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS) && BUILDFLAG(USE_BLINK)
ui::InputDeviceObserverIOS::GetInstance()->AddObserver(this);
#endif
}
SlowWebPreferenceCache::~SlowWebPreferenceCache() {
#if BUILDFLAG(IS_WIN)
ui::InputDeviceObserverWin::GetInstance()->RemoveObserver(this);
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
#elif BUILDFLAG(IS_ANDROID)
ui::InputDeviceObserverAndroid::GetInstance()->RemoveObserver(this);
#elif BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS) && BUILDFLAG(USE_BLINK)
ui::InputDeviceObserverIOS::GetInstance()->RemoveObserver(this);
#endif
}
// static
SlowWebPreferenceCache* SlowWebPreferenceCache::GetInstance() {
static base::NoDestructor<SlowWebPreferenceCache> instance;
return instance.get();
}
void SlowWebPreferenceCache::AddObserver(
SlowWebPreferenceCacheObserver* observer) {
observers_.AddObserver(observer);
}
void SlowWebPreferenceCache::RemoveObserver(
SlowWebPreferenceCacheObserver* observer) {
observers_.RemoveObserver(observer);
}
void SlowWebPreferenceCache::Load(blink::web_pref::WebPreferences* prefs) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_initialized_) {
Update();
}
#define SET_FROM_CACHE(prefs, field) prefs->field = field##_
SET_FROM_CACHE(prefs, touch_event_feature_detection_enabled);
SET_FROM_CACHE(prefs, available_pointer_types);
SET_FROM_CACHE(prefs, available_hover_types);
SET_FROM_CACHE(prefs, primary_pointer_type);
SET_FROM_CACHE(prefs, primary_hover_type);
SET_FROM_CACHE(prefs, pointer_events_max_touch_points);
SET_FROM_CACHE(prefs, number_of_cpu_cores);
#if BUILDFLAG(IS_ANDROID)
SET_FROM_CACHE(prefs, video_fullscreen_orientation_lock_enabled);
SET_FROM_CACHE(prefs, video_rotate_to_fullscreen_enabled);
#endif
#undef SET_FROM_CACHE
}
void SlowWebPreferenceCache::OnInputDeviceConfigurationChanged(uint8_t) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (Update()) {
observers_.Notify(
&SlowWebPreferenceCacheObserver::OnSlowWebPreferenceChanged);
}
}
void SlowWebPreferenceCache::OnGpuSwitched(gl::GpuPreference) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (Update()) {
observers_.Notify(
&SlowWebPreferenceCacheObserver::OnSlowWebPreferenceChanged);
}
}
bool SlowWebPreferenceCache::Update() {
OPTIONAL_TRACE_EVENT0("content", "SlowWebPreferenceCache::Update");
bool prev_touch_event_feature_detection_enabled =
touch_event_feature_detection_enabled_;
int prev_available_pointer_types = available_pointer_types_;
int prev_available_hover_types = available_hover_types_;
blink::mojom::PointerType prev_primary_pointer_type = primary_pointer_type_;
blink::mojom::HoverType prev_primary_hover_type = primary_hover_type_;
int prev_pointer_events_max_touch_points = pointer_events_max_touch_points_;
int prev_number_of_cpu_cores = number_of_cpu_cores_;
#if BUILDFLAG(IS_ANDROID)
bool prev_video_fullscreen_orientation_lock_enabled =
video_fullscreen_orientation_lock_enabled_;
bool prev_video_rotate_to_fullscreen_enabled =
video_rotate_to_fullscreen_enabled_;
#endif // BUILDFLAG(IS_ANDROID)
is_initialized_ = true;
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
// On Android and iOS, Touch event feature detection is enabled by default,
// Otherwise default is disabled.
std::string touch_enabled_default_switch =
switches::kTouchEventFeatureDetectionDisabled;
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
touch_enabled_default_switch = switches::kTouchEventFeatureDetectionEnabled;
#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string touch_enabled_switch =
command_line.HasSwitch(switches::kTouchEventFeatureDetection)
? command_line.GetSwitchValueASCII(
switches::kTouchEventFeatureDetection)
: touch_enabled_default_switch;
touch_event_feature_detection_enabled_ =
(touch_enabled_switch == switches::kTouchEventFeatureDetectionAuto)
? (ui::GetTouchScreensAvailability() ==
ui::TouchScreensAvailability::ENABLED)
: (touch_enabled_switch.empty() ||
touch_enabled_switch ==
switches::kTouchEventFeatureDetectionEnabled);
std::tie(available_pointer_types_, available_hover_types_) =
GetAvailablePointerAndHoverTypes();
primary_pointer_type_ = static_cast<blink::mojom::PointerType>(
ui::GetPrimaryPointerType(available_pointer_types_));
primary_hover_type_ = static_cast<blink::mojom::HoverType>(
ui::GetPrimaryHoverType(available_hover_types_));
pointer_events_max_touch_points_ = ui::MaxTouchPoints();
number_of_cpu_cores_ = base::SysInfo::NumberOfProcessors();
AllPointerTypes all_pointer_types = AllPointerTypes::kNone;
if (available_pointer_types_ & ui::POINTER_TYPE_COARSE &&
available_pointer_types_ & ui::POINTER_TYPE_FINE) {
all_pointer_types = AllPointerTypes::kBoth;
} else if (available_pointer_types_ & ui::POINTER_TYPE_COARSE) {
all_pointer_types = AllPointerTypes::kCoarse;
} else if (available_pointer_types_ & ui::POINTER_TYPE_FINE) {
all_pointer_types = AllPointerTypes::kFine;
}
PrimaryPointerType primary_pointer = PrimaryPointerType::kNone;
if (primary_pointer_type_ == blink::mojom::PointerType::kPointerCoarseType) {
primary_pointer = PrimaryPointerType::kCoarse;
} else if (primary_pointer_type_ ==
blink::mojom::PointerType::kPointerFineType) {
primary_pointer = PrimaryPointerType::kFine;
}
base::UmaHistogramEnumeration("Input.PointerTypesAll", all_pointer_types);
base::UmaHistogramEnumeration("Input.PointerTypePrimary", primary_pointer);
#if BUILDFLAG(IS_ANDROID)
const bool device_is_phone =
ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE;
video_fullscreen_orientation_lock_enabled_ = device_is_phone;
video_rotate_to_fullscreen_enabled_ = device_is_phone;
if (video_fullscreen_orientation_lock_enabled_ !=
prev_video_fullscreen_orientation_lock_enabled ||
video_rotate_to_fullscreen_enabled_ !=
prev_video_rotate_to_fullscreen_enabled) {
return true;
}
#endif
return touch_event_feature_detection_enabled_ !=
prev_touch_event_feature_detection_enabled ||
available_pointer_types_ != prev_available_pointer_types ||
available_hover_types_ != prev_available_hover_types ||
primary_pointer_type_ != prev_primary_pointer_type ||
primary_hover_type_ != prev_primary_hover_type ||
pointer_events_max_touch_points_ !=
prev_pointer_events_max_touch_points ||
number_of_cpu_cores_ != prev_number_of_cpu_cores;
}
// static
std::pair<int, int> SlowWebPreferenceCache::GetAvailablePointerAndHoverTypes() {
// On Windows we have to temporarily allow blocking calls since
// ui::GetAvailablePointerAndHoverTypes needs to call some in order to
// figure out tablet device details in base::win::IsDeviceUsedAsATablet,
// see https://crbug.com/1262162.
#if BUILDFLAG(IS_WIN)
base::ScopedAllowBlocking scoped_allow_blocking;
#endif
return ui::GetAvailablePointerAndHoverTypes();
}
} // namespace content