Skip to content

Commit

Permalink
[GTK] Bring GTK4 Chrome up to par with GTK3 Chrome
Browse files Browse the repository at this point in the history
The previous CLs just got the build working.  This CL
fixes crashes, misused APIs, and visual issues to the
point where GTK4 is usable, and at feature parity with
GKT3 (except for key bindings, which were removed in
GTK4).

R=nickdiego

Bug: 876586
Change-Id: Ia16243b36e36ef19bd1854d3eff95c989f6a44dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2769661
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Nick Yamane <nickdiego@igalia.com>
Reviewed-by: Nick Yamane <nickdiego@igalia.com>
Cr-Commit-Position: refs/heads/master@{#866895}
  • Loading branch information
tanderson-google authored and Chromium LUCI CQ committed Mar 26, 2021
1 parent b673f79 commit 6a8b2d1
Show file tree
Hide file tree
Showing 15 changed files with 329 additions and 198 deletions.
1 change: 1 addition & 0 deletions ui/gfx/x/x11_atom_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ constexpr const char* kAtomsToCache[] = {
"_NET_WM_USER_TIME",
"_NET_WM_WINDOW_OPACITY",
"_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_DIALOG",
"_NET_WM_WINDOW_TYPE_DND",
"_NET_WM_WINDOW_TYPE_MENU",
"_NET_WM_WINDOW_TYPE_NORMAL",
Expand Down
24 changes: 8 additions & 16 deletions ui/gtk/gtk_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -513,20 +513,16 @@ gfx::Image GtkUi::GetIconForContentType(const std::string& content_type,
auto* paintable = GDK_PAINTABLE(icon_paintable);
auto* snapshot = gtk_snapshot_new();
gdk_paintable_snapshot(paintable, snapshot, size, size);
auto node = TakeGObject(gtk_snapshot_free_to_node(snapshot));
auto rect = GRAPHENE_RECT_INIT(0, 0, size, size);
auto renderer = TakeGObject(gsk_cairo_renderer_new());
auto texture =
TakeGObject(gsk_renderer_render_texture(renderer, node, &rect));
auto* node = gtk_snapshot_free_to_node(snapshot);
GdkTexture* texture = GetTextureFromRenderNode(node);

SkBitmap bitmap;
bitmap.allocN32Pixels(size, size);
bitmap.eraseColor(SK_ColorTRANSPARENT);
bitmap.allocN32Pixels(gdk_texture_get_width(texture),
gdk_texture_get_height(texture));
gdk_texture_download(texture, static_cast<guchar*>(bitmap.getAddr(0, 0)),
bitmap.rowBytes());

CairoSurface surface(bitmap);
cairo_t* cr = surface.cairo();
gtk_render_icon(gtk_widget_get_style_context(GetDummyWindow()), cr, texture,
0, 0);
gsk_render_node_unref(node);
#else
auto icon_info = TakeGObject(gtk_icon_theme_lookup_by_gicon(
theme, icon.get(), size,
Expand Down Expand Up @@ -1002,8 +998,7 @@ void GtkUi::UpdateColors() {
void GtkUi::UpdateDefaultFont() {
gfx::SetFontRenderParamsDeviceScaleFactor(device_scale_factor_);

GtkWidget* fake_label = gtk_label_new(nullptr);
g_object_ref_sink(fake_label); // Remove the floating reference.
auto fake_label = TakeGObject(gtk_label_new(nullptr));
PangoContext* pc = gtk_widget_get_pango_context(fake_label);
const PangoFontDescription* desc = pango_context_get_font_description(pc);

Expand Down Expand Up @@ -1040,9 +1035,6 @@ void GtkUi::UpdateDefaultFont() {
default_font_render_params_ =
gfx::GetFontRenderParams(query, &default_font_family_);
default_font_style_ = query.style;

GtkWindowDestroy(fake_label);
g_object_unref(fake_label);
}

float GtkUi::GetRawDeviceScaleFactor() {
Expand Down
7 changes: 1 addition & 6 deletions ui/gtk/gtk_ui_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,7 @@
using GdkKeymap = struct _GdkKeymap;
using GtkWindow = struct _GtkWindow;
using GtkWidget = struct _GtkWidget;

#if BUILDFLAG(GTK_VERSION) == 3
using GdkWindow = struct _GdkWindow;
#else
using GdkWindow = struct _GdkSurface;
#endif

namespace ui {

Expand Down Expand Up @@ -56,7 +51,7 @@ class COMPONENT_EXPORT(GTK) GtkUiDelegate {

// Gtk dialog windows must be set transient for the browser window. This
// function abstracts away such functionality.
virtual bool SetGdkWindowTransientFor(GdkWindow* window,
virtual bool SetGtkWidgetTransientFor(GtkWidget* widget,
gfx::AcceleratedWidget parent) = 0;
virtual void ClearTransientFor(gfx::AcceleratedWidget parent) = 0;

Expand Down
88 changes: 71 additions & 17 deletions ui/gtk/gtk_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,14 @@ GdkModifierType GetIbusFlags(const ui::KeyEvent& key_event) {
<< ui::kPropertyKeyboardIBusFlagOffset);
}

#if BUILDFLAG(GTK_VERSION) < 4
float GetDeviceScaleFactor() {
views::LinuxUI* linux_ui = views::LinuxUI::instance();
return linux_ui ? linux_ui->GetDeviceScaleFactor() : 1;
}
#endif

GtkCssContext AppendCssNodeToStyleContextImpl(
GtkCssContext context,
GType gtype,
const std::string& name,
const std::string& object_name,
const std::vector<std::string>& classes,
GtkStateFlags state) {
GtkStateFlags state,
float scale) {
#if BUILDFLAG(GTK_VERSION) >= 4
// GTK_TYPE_BOX is used instead of GTK_TYPE_WIDGET because:
// 1. Widgets are abstract and cannot be created directly.
Expand All @@ -127,6 +121,9 @@ GtkCssContext AppendCssNodeToStyleContextImpl(

if (context)
gtk_widget_set_parent(widget, context);

gtk_style_context_set_scale(gtk_widget_get_style_context(widget), scale);

return GtkCssContext(widget, context ? context.root() : widget);
#else
GtkWidgetPath* path =
Expand Down Expand Up @@ -166,8 +163,11 @@ GtkCssContext AppendCssNodeToStyleContextImpl(
}
gtk_style_context_set_state(child_context, child_state);
}
gtk_style_context_set_scale(child_context, std::ceil(GetDeviceScaleFactor()));

gtk_style_context_set_scale(child_context, scale);

gtk_style_context_set_parent(child_context, context);

gtk_widget_path_unref(path);
return GtkCssContext(child_context);
#endif
Expand All @@ -194,13 +194,8 @@ void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
return;

gtk_widget_realize(dialog);
#if BUILDFLAG(GTK_VERSION) >= 4
GdkWindow* gdk_window = gtk_native_get_surface(gtk_widget_get_native(dialog));
#else
GdkWindow* gdk_window = gtk_widget_get_window(dialog);
#endif
gfx::AcceleratedWidget parent_id = parent->GetHost()->GetAcceleratedWidget();
GtkUi::GetDelegate()->SetGdkWindowTransientFor(gdk_window, parent_id);
GtkUi::GetDelegate()->SetGtkWidgetTransientFor(dialog, parent_id);

// We also set the |parent| as a property of |dialog|, so that we can unlink
// the two later.
Expand Down Expand Up @@ -436,8 +431,10 @@ GtkCssContext AppendCssNodeToStyleContext(GtkCssContext context,
// widgets specially if they want to.
classes.push_back("chromium");

float scale = std::round(GetDeviceScaleFactor());

return AppendCssNodeToStyleContextImpl(context, gtype, name, object_name,
classes, state);
classes, state, scale);
}

GtkCssContext GetStyleContextFromCss(const std::string& css_selector) {
Expand All @@ -453,7 +450,7 @@ GtkCssContext GetStyleContextFromCss(const std::string& css_selector) {
return context;
}

SkColor GetFgColorFromStyleContext(GtkCssContext context) {
SkColor GetFgColorFromStyleContext(GtkStyleContext* context) {
GdkRGBA color;
#if GTK_CHECK_VERSION(3, 90, 0)
gtk_style_context_get_color(context, &color);
Expand Down Expand Up @@ -714,4 +711,61 @@ gfx::Size GetSeparatorSize(bool horizontal) {
return {natural_size.width, natural_size.height};
}

float GetDeviceScaleFactor() {
views::LinuxUI* linux_ui = views::LinuxUI::instance();
return linux_ui ? linux_ui->GetDeviceScaleFactor() : 1;
}

#if BUILDFLAG(GTK_VERSION) >= 4
GdkTexture* GetTextureFromRenderNode(GskRenderNode* node) {
struct {
GskRenderNodeType node_type;
GskRenderNode* (*get_child)(GskRenderNode*);
} constexpr simple_getters[] = {
{GSK_TRANSFORM_NODE, gsk_transform_node_get_child},
{GSK_OPACITY_NODE, gsk_opacity_node_get_child},
{GSK_COLOR_MATRIX_NODE, gsk_color_matrix_node_get_child},
{GSK_REPEAT_NODE, gsk_repeat_node_get_child},
{GSK_CLIP_NODE, gsk_clip_node_get_child},
{GSK_ROUNDED_CLIP_NODE, gsk_rounded_clip_node_get_child},
{GSK_SHADOW_NODE, gsk_shadow_node_get_child},
{GSK_BLUR_NODE, gsk_blur_node_get_child},
{GSK_DEBUG_NODE, gsk_debug_node_get_child},
};
struct {
GskRenderNodeType node_type;
guint (*get_n_children)(GskRenderNode*);
GskRenderNode* (*get_child)(GskRenderNode*, guint);
} constexpr container_getters[] = {
{GSK_CONTAINER_NODE, gsk_container_node_get_n_children,
gsk_container_node_get_child},
{GSK_GL_SHADER_NODE, gsk_gl_shader_node_get_n_children,
gsk_gl_shader_node_get_child},
};

if (!node)
return nullptr;

auto node_type = gsk_render_node_get_node_type(node);
if (node_type == GSK_TEXTURE_NODE)
return gsk_texture_node_get_texture(node);
for (const auto& getter : simple_getters) {
if (node_type == getter.node_type) {
if (auto* texture = GetTextureFromRenderNode(getter.get_child(node)))
return texture;
}
}
for (const auto& getter : container_getters) {
if (node_type != getter.node_type)
continue;
for (guint i = 0; i < getter.get_n_children(node); ++i) {
if (auto* texture = GetTextureFromRenderNode(getter.get_child(node, i)))
return texture;
}
return nullptr;
}
return nullptr;
}
#endif

} // namespace gtk
8 changes: 7 additions & 1 deletion ui/gtk/gtk_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ GtkCssContext AppendCssNodeToStyleContext(GtkCssContext context,
// must g_object_unref() the returned context.
GtkCssContext GetStyleContextFromCss(const std::string& css_selector);

SkColor GetFgColorFromStyleContext(GtkCssContext context);
SkColor GetFgColorFromStyleContext(GtkStyleContext* context);

SkColor GetBgColorFromStyleContext(GtkCssContext context);

Expand Down Expand Up @@ -254,6 +254,12 @@ GtkWidget* GetDummyWindow();

gfx::Size GetSeparatorSize(bool horizontal);

float GetDeviceScaleFactor();

#if BUILDFLAG(GTK_VERSION) >= 4
GdkTexture* GetTextureFromRenderNode(GskRenderNode* node);
#endif

} // namespace gtk

#endif // UI_GTK_GTK_UTIL_H_
30 changes: 9 additions & 21 deletions ui/gtk/input_method_context_impl_gtk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,20 +116,13 @@ bool InputMethodContextImplGtk::DispatchKeyEvent(

// Convert the last known caret bounds relative to the screen coordinates
// to a GdkRectangle relative to the client window.
gint win_x = 0;
gint win_y = 0;
#if BUILDFLAG(GTK_VERSION) >= 4
gint factor = gtk_widget_get_scale_factor(GetDummyWindow());
#else
gdk_window_get_origin(target_window, &win_x, &win_y);
gint factor = gdk_window_get_scale_factor(target_window);
#endif

gint caret_x = last_caret_bounds_.x() / factor;
gint caret_y = last_caret_bounds_.y() / factor;
gint caret_w = last_caret_bounds_.width() / factor;
gint caret_h = last_caret_bounds_.height() / factor;

aura::Window* window = static_cast<aura::Window*>(key_event.target());
gint win_x = window->GetBoundsInScreen().x();
gint win_y = window->GetBoundsInScreen().y();
gint caret_x = last_caret_bounds_.x();
gint caret_y = last_caret_bounds_.y();
gint caret_w = last_caret_bounds_.width();
gint caret_h = last_caret_bounds_.height();
GdkRectangle gdk_rect = {caret_x - win_x, caret_y - win_y, caret_w, caret_h};
gtk_im_context_set_cursor_location(gtk_context_, &gdk_rect);

Expand Down Expand Up @@ -183,14 +176,9 @@ void InputMethodContextImplGtk::SetCursorLocation(const gfx::Rect& rect) {
// Remember the caret bounds so that we can set the cursor location later.
// gtk_im_context_set_cursor_location() takes the location relative to the
// client window, which is unknown at this point. So we'll call
// gtk_im_context_set_cursor_location() later in ProcessKeyEvent() where
// gtk_im_context_set_cursor_location() later in DispatchKeyEvent() where
// (and only where) we know the client window.
if (views::LinuxUI::instance()) {
last_caret_bounds_ = gfx::ToEnclosingRect(gfx::ConvertRectToPixels(
rect, views::LinuxUI::instance()->GetDeviceScaleFactor()));
} else {
last_caret_bounds_ = rect;
}
last_caret_bounds_ = rect;
}

void InputMethodContextImplGtk::SetSurroundingText(
Expand Down
9 changes: 2 additions & 7 deletions ui/gtk/input_method_context_impl_gtk.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gtk/gtk_buildflags.h"

typedef struct _GtkIMContext GtkIMContext;

#if BUILDFLAG(GTK_VERSION) == 3
using GtkIMContext = struct _GtkIMContext;
using GdkWindow = struct _GdkWindow;
#else
using GdkWindow = struct _GdkSurface;
#endif

namespace gtk {

Expand Down Expand Up @@ -84,7 +79,7 @@ class InputMethodContextImplGtk : public ui::LinuxInputMethodContext {
gpointer gdk_last_set_client_window_ = nullptr;
#endif

// Last known caret bounds relative to the screen coordinates.
// Last known caret bounds relative to the screen coordinates, in DIPs.
gfx::Rect last_caret_bounds_;

DISALLOW_COPY_AND_ASSIGN(InputMethodContextImplGtk);
Expand Down
Loading

0 comments on commit 6a8b2d1

Please sign in to comment.