---
# System prepended metadata

title: Border Paint on Linux
tags: [Chromium-Graphics, elkurin-daily-note]

---

# Border Paint on Linux

This note digs into the Border Painting on Linux to understand how insets should be handled on Lacros.

OpaqueBrowserFrameView is a view used for usual browser.  
In here, this note only focuses on the logic to paint border.

## OnPaint
[OpaqueBrowserFrameView::OnPaint](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/opaque_browser_frame_view.cc;l=606;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) paints the frame on `canvas`.

This paints the border.  
If the frame is fullscreen, there is no visible boarder, so we can ignore this call. The code does so.

If it's not fullscreen nor maximized, it calls [PaintRestoredFrameBorder](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/opaque_browser_frame_view.cc;l=642;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771).  
[PaintRestoredFrameBorder](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/opaque_browser_frame_view.h;l=141;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) apints various sub components of the view related to borders.  
Its default implementation is in [OpaqueBrowserFrameView](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/opaque_browser_frame_view.cc;l=816;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771). It set side images and corner images to [FrameBackground](https://source.chromium.org/chromium/chromium/src/+/main:ui/views/window/frame_background.h;l=30;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) class and request it to PaintRestored. FrameBackground class is a background pianter of the window frame.  
This default implementation is used by ChromeOS platforms, but different for Linux. In this note, we focus on Linux pass.

Linux has its own implementation of OpaqueBrowserFrameView which is [BrowserFrameViewLinux](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_linux.h;l=19;drc=dd4721f4f8ebef4e9dc2910d4578174378320d31) and [BrowserFrameViewLinuxNative](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_linux_native.h;l=15;drc=9251d14a62102464b7d2b5318fa51def390fc87c).  

Let's see BrowserFrameViewLinux pass first.
[BrowserFrameViewLinux::PaintRestoredFrameBorder](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_linux.cc;l=76;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) -> [PaintRestoredFrameBorderLinux](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_paint_utils_linux.cc;l=15;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771).  
The border inset is calculated from [BrowserFrameViewLayoutLinux::MirroedFrameBorderInsets](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_layout_linux.cc;l=30;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) which returns [RestoredFrameBorderInsets](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc;l=310;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771). It seems to be returning `kFrameBorderThickness`, but again Linux has its own implementation [BrowserFrameViewLayoutLinux::RestoredFrameBorderInsets](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_layout_linux.cc;l=48;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771).

Now let's see BrowserFrameViewLinuxNative pass.  
[BrowserFrameViewLinuxNative::PaintRestoredFrameBorder](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_linux_native.cc;l=76;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) uses [`window_frame_provider_`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_frame_view_linux_native.h;l=62;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) to calculate borders and so on. In PaintRestoredFrameBorder, it calls WindowFrameProvider::PaintWindowFrame.  
[WindowFrameProvider](https://source.chromium.org/chromium/chromium/src/+/main:ui/linux/window_frame_provider.h;l=18;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) is a virtual class showing methods we have. Methods listed here are to get corner radius and frame thickness, and also can paint the window frame.  
The actual implementation is in [gfx::WindowFrameProviderGtk](https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/window_frame_provider_gtk.cc;l=239;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771).  
Going back to the call stack, [WindowFrameProviderGtk::PaintWindowFrame](https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/window_frame_provider_gtk.cc;l=239;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) calls [MaybeUpdateBitmaps](https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/window_frame_provider_gtk.cc;l=345;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) and it calculates [`assets_`](https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/window_frame_provider_gtk.h;l=74;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771).  
`assets_` is `base::flat_map<int, Asset>` type where [Asset](https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/window_frame_provider_gtk.h;l=36;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) struct carries the data of size and bitmap. This flat_map's key is scale. So, it holds the data for each scale.  
MaybeUpdateBitmaps calculates [`frame_thickness_dip_`](https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/window_frame_provider_gtk.h;l=69;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) and also set it to `assets_`. This value is refered from [GetFrameThiknessDip](https://source.chromium.org/chromium/chromium/src/+/main:ui/gtk/window_frame_provider_gtk.cc;l=234;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771).

After MaybeUpdateBitmaps completes, now we can refer to `frame_thickness_px` value to calculate the border.  
PaintWindowFrame continues the operation with calculating `effective_frame_thickness_px` using the thickness registered to asset and add it to `client_bounds_px`. On the other hand, it's subtracted from `src_rect` since the src does not include the border.

## What is BrowserFrameViewLinuxNative
BrowserFrameViewLinux is able to render frame buttons using the native toolkit.

Which of OpaqueBrowserFrameView, BrowserFrameViewLinux or BrowserFrameViewLinuxNative is used is decided in [CreateOpaqueBrowserFrameView](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc;l=33;drc=6c20536e80b8c16ce976c7d15352b2391005112e) implementation.  
If it's not linux, it just returns OpaqueBrowserFrameView object.  
If linux ui theme + nav button is supported, it uses BrowserFrameViewLinuxNative. User BrowserFrameViewLinux otherwise.

For the current usage, Native seems to be used in the most case.

## gfx::Canvas
[gfx::Canvas](https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/canvas.h;l=54;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) is a class to provide methos for common operations used for painting. it's a wrapper of [cc::PaintCanvas](https://source.chromium.org/chromium/chromium/src/+/main:cc/paint/paint_canvas.h;l=51;drc=f5bdc89c7395ed24f1b8d196a3bdd6232d5bf771) which is a wrapper of SkCanvas.