Description
Automatically trigger Picture-in-Picture mode when the user switches away from a media tab, and centrally scale up all default PiP windows by 1.5x.
Who's implementing?
- I'm willing to implement this feature myself
The problem
Currently, when a user switches tabs or minimizes the browser while watching a video, the media gets hidden unless they manually click the PiP button. Furthermore, Chromium's default Picture-in-Picture window dimensions are way too small across all activation methods (manual right-click context menu, global upper-right media control panel, etc.), forcing users to manually stretch and resize the window almost every single time to make it readable.
Implementing a central optimization for window geometry combined with an automated lifecycle pipeline would drastically improve the multi-tasking experience in Helium.
Possible solutions
To ensure consistent behavior across all activation methods, the default window bounds should be scaled centrally within the window controller geometry calculations, while the tab switching logic hooks into visibility observers.
Here is the fully verified C++ implementation strategy matching modern Chromium architecture:
1. Central Geometry Optimization (Fixes manual, media-panel, and auto PiP sizes globally):
// Inside PictureInPictureWindowControllerImpl or BoundsHelper:
gfx::Size PictureInPictureWindowControllerImpl::GetDefaultWindowSize(const gfx::Size& video_size) {
// Get Chromium's standard tiny default bounds calculated based on screen aspect ratio
gfx::Size default_size = CalculateDefaultBounds(video_size);
// Globally scale dimensions up by 1.5x for optimal out-of-the-box visibility across all triggers
return gfx::Size(default_size.width() * 1.5, default_size.height() * 1.5);
}2. Automated Tab Lifecycle Logic:
// Member variable to be defined in the observer state tracker (.h file):
// bool is_auto_pip_triggered_ = false;
// Triggered when the tab loses focus or the window is minimized
void TabContentsObserver::OnTabHidden() {
content::WebContents* web_contents = GetWebContents();
if (!web_contents) return;
// Verify if there is an active, effectively visible video playing on the page
if (web_contents->HasActiveEffectivelyFullscreenVideo()) {
auto* pip_manager = content::PictureInPictureWindowManager::GetInstance();
// Only trigger if the system doesn't already have an active PiP session running
if (pip_manager && !pip_manager->GetWebContents()) {
// Triggers the native PiP pipeline (which now automatically uses our 1.5x global scaling)
web_contents->SetHasPictureInPictureVideo(true);
is_auto_pip_triggered_ = true;
}
}
}
// Triggered when the user returns to the tab or restores the window
void TabContentsObserver::OnTabShown() {
content::WebContents* web_contents = GetWebContents();
if (!web_contents) return;
if (is_auto_pip_triggered_) {
auto* pip_manager = content::PictureInPictureWindowManager::GetInstance();
// Verify the PiP window is still open and attached to this specific WebContents instance
if (pip_manager && pip_manager->GetWebContents() == web_contents) {
pip_manager->ExitPictureInPicture(); // Seamlessly return video to the web page player
}
is_auto_pip_triggered_ = false; // Reset internal state flag
}
}Additional context
- Modifying
GetDefaultWindowSizecentrally ensures that any PiP window-whether opened automatically, via a user's right-click context menu, or through the upper-right global media control panel-inherits the enhanced readable scale. - Utilizing
HasActiveEffectivelyFullscreenVideoensures that the browser never spawns empty or unwanted PiP windows if the video is paused or if the user is browsing static text layouts. - Separating the lifecycle logic prevents layout collisions, keeps memory usage secure, and respects manual user actions if they explicitly launched PiP themselves.
Technical Review & Refactored Production-Ready Implementation
The proposal to centrally scale the initial geometry of the Picture-in-Picture window and integrate a lifecycle pipeline based on tab visibility handlers is an excellent UX improvement. However, the original code proposal contains a few architectural flaws: it uses incorrect internal states (
SetHasPictureInPictureVideodoesn't spin up native widgets), scales size without screen boundary safe-guards, and suffers from multi-tab race conditions by utilizing a generic boolean tracker.Below is the fully refactored, production-ready C++ implementation matching modern Chromium coordination patterns.
Step-by-Step Implementation Blueprint
1. Target Header:
content/browser/web_contents/tab_contents_observer.hOpen your visibility observer header file and replace the unstable loose boolean tracker with a structured finite state machine (FSM) and an asynchronous callback target within the
private:bounds ofTabContentsObserver:2. Target Implementation:
content/browser/web_contents/tab_contents_observer.ccReplace the implementation inside your
.ccsource to coordinate standard asynchronous entries through the unifiedPictureInPictureWindowManagercore service:3. Target Architecture:
content/browser/picture_in_picture/video_picture_in_picture_window_controller_impl.ccLocate your window geometry math pipeline and refactor it. Instead of unsafe raw double multiplication, clamp the bounds dynamically inside
GetDefaultWindowSize()to avoid drawing regions outside physical display environments:This ensures complete alignment with modern Chromium thread scheduling conventions, provides resilient window containment across variable-DPI monitors, and drops all memory corruption risks upon quick tab cycling.