Theming in Chromium

One day I was using Safari and noticed that they change the titlebar color based on the website. I discovered that there's a special tag called theme-color that the website can define to change it. Even Chrome for Android, Safari on iOS, and Samsung internet do it, however only Safari was doing it for desktop.

It seemed fancy, and I wanted to to have it for Chromium desktop, so I decided to implement it. The first thought was to create a patch to Chromium, and in hindsight there might have been easier ways to do it with a browser extension, but oh well, I already started cloning the entire repo.

How to get & compile Chromium? Google has a guide. Chromium has this gclient thing which is Google's custom way of managing modular dependencies. Sounds similar to git submodules? Yes, in fact Google is trying to replace gclient with standard git submodules soon. Anyway, so I used gclient to fetch the code, which took a day or two, and then compiled it with the Ninja build system.

I somehow ended up using 100GB of storage at the end, so I deleted half of my system for this. Must be all those object files. Note, once you compile the development build, they are a bit slow to run at times.

After digging through the code for hours, I found a place that takes a base color and then computes the color pallete for the browser.

I tried it with some pages, here Google, YouTube, Twitter and ForTomorrow. So while Google & ForTomorrow theme seem similar to their page, Youtube & Twitter don't. I suppose this could be due to some weird color pallete computation occuring due to slightly tinted dark colors, since the logged color values seem fine.

Note, I enable the #chrome-refresh-2023 flag for this code to work. I'm going to take a look at this deeper once the Chrome refresh code is complete, right now it's under heavy development.

I set the color for the BrowserFrame in ui/views/frame/browser_frame.cc by extracting the web contents from the active tab to get the theme color and returning it.

absl::optional BrowserFrame::GetUserColor() const {

#if BUILDFLAG(IS_CHROMEOS_ASH)
  // ChromeOS SystemWebApps use the OS theme all the time.
  if (ash::IsSystemWebApp(browser_view_->browser())) {
    return views::Widget::GetUserColor();
  }
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

  // Incognito profiles should always fall back to the material baseline.
  if (IsIncognitoBrowser()) {
    return absl::nullopt;
  }
  
++   content::WebContents* web_contents = browser_view_->browser()->tab_strip_model()->GetActiveWebContents();
++   
++   if (web_contents) {
++       absl::optional color = web_contents->GetThemeColor();
++       if (color){
++           if (color.has_value()) {
++               LOG(INFO) << "theme-color: " << std::hex << color.value() << std::setw(6) << std::setfill('0');
++               return SkColorSetA(color.value(), SK_AlphaOPAQUE);
++           }
++       }
++   }

  const auto* theme_service =
      ThemeServiceFactory::GetForProfile(browser_view_->browser()->profile());
  return theme_service->UsingAutogeneratedTheme()
             ? absl::optional(
                   theme_service->GetAutogeneratedThemeColor())
             : views::Widget::GetUserColor();
}

This patch was made on commit 22be531a290d556fda7fa1b42d714265142cae55. Hv Fun!!