Make FlRenderable interface (#55763)
Added to make testing of FlRenderer easier.
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 078e1ee..ef13edb 100644
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -44834,6 +44834,8 @@
ORIGIN: ../../../flutter/shell/platform/linux/fl_plugin_registrar_private.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_plugin_registrar_test.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_plugin_registry.cc + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/shell/platform/linux/fl_renderable.cc + ../../../flutter/LICENSE
+ORIGIN: ../../../flutter/shell/platform/linux/fl_renderable.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_renderer_gdk.cc + ../../../flutter/LICENSE
@@ -47739,6 +47741,8 @@
FILE: ../../../flutter/shell/platform/linux/fl_plugin_registrar_private.h
FILE: ../../../flutter/shell/platform/linux/fl_plugin_registrar_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_plugin_registry.cc
+FILE: ../../../flutter/shell/platform/linux/fl_renderable.cc
+FILE: ../../../flutter/shell/platform/linux/fl_renderable.h
FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer.h
FILE: ../../../flutter/shell/platform/linux/fl_renderer_gdk.cc
diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn
index 36045a9..9cbcc9f 100644
--- a/shell/platform/linux/BUILD.gn
+++ b/shell/platform/linux/BUILD.gn
@@ -129,6 +129,7 @@
"fl_platform_handler.cc",
"fl_plugin_registrar.cc",
"fl_plugin_registry.cc",
+ "fl_renderable.cc",
"fl_renderer.cc",
"fl_renderer_gdk.cc",
"fl_renderer_headless.cc",
diff --git a/shell/platform/linux/fl_renderable.cc b/shell/platform/linux/fl_renderable.cc
new file mode 100644
index 0000000..b8a44a5
--- /dev/null
+++ b/shell/platform/linux/fl_renderable.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "flutter/shell/platform/linux/fl_renderable.h"
+
+G_DEFINE_INTERFACE(FlRenderable, fl_renderable, G_TYPE_OBJECT)
+
+static void fl_renderable_default_init(FlRenderableInterface* iface) {}
+
+void fl_renderable_redraw(FlRenderable* self) {
+ g_return_if_fail(FL_IS_RENDERABLE(self));
+
+ FL_RENDERABLE_GET_IFACE(self)->redraw(self);
+}
diff --git a/shell/platform/linux/fl_renderable.h b/shell/platform/linux/fl_renderable.h
new file mode 100644
index 0000000..8a17caa
--- /dev/null
+++ b/shell/platform/linux/fl_renderable.h
@@ -0,0 +1,42 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERABLE_H_
+#define FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERABLE_H_
+
+#include <gdk/gdk.h>
+
+#include "flutter/shell/platform/embedder/embedder.h"
+
+G_BEGIN_DECLS
+
+G_DECLARE_INTERFACE(FlRenderable, fl_renderable, FL, RENDERABLE, GObject);
+
+/**
+ * FlRenderable:
+ *
+ * An interface for a class that can render views from #FlRenderer.
+ *
+ * This interface is typically implemented by #FlView and is provided to make
+ * #FlRenderer easier to test.
+ */
+
+struct _FlRenderableInterface {
+ GTypeInterface g_iface;
+
+ void (*redraw)(FlRenderable* renderable);
+};
+
+/**
+ * fl_renderable_redraw:
+ * @renderable: an #FlRenderable
+ *
+ * Indicate the renderable needs to redraw. When ready, the renderable should
+ * call fl_renderer_draw().
+ */
+void fl_renderable_redraw(FlRenderable* renderable);
+
+G_END_DECLS
+
+#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERABLE_H_
diff --git a/shell/platform/linux/fl_renderer.cc b/shell/platform/linux/fl_renderer.cc
index 52aa9de..64a891b 100644
--- a/shell/platform/linux/fl_renderer.cc
+++ b/shell/platform/linux/fl_renderer.cc
@@ -10,7 +10,6 @@
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/fl_engine_private.h"
#include "flutter/shell/platform/linux/fl_framebuffer.h"
-#include "flutter/shell/platform/linux/fl_view_private.h"
// Vertex shader to draw Flutter window contents.
static const char* vertex_shader_src =
@@ -77,6 +76,12 @@
G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
+static void free_weak_ref(gpointer value) {
+ GWeakRef* ref = static_cast<GWeakRef*>(value);
+ g_weak_ref_clear(ref);
+ free(ref);
+}
+
// Check if running on an NVIDIA driver.
static gboolean is_nvidia() {
const gchar* vendor = reinterpret_cast<const gchar*>(glGetString(GL_VENDOR));
@@ -295,8 +300,8 @@
static void fl_renderer_init(FlRenderer* self) {
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
fl_renderer_get_instance_private(self));
- priv->views =
- g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, nullptr);
+ priv->views = g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr,
+ free_weak_ref);
priv->framebuffers_by_view_id =
g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr,
(GDestroyNotify)g_ptr_array_unref);
@@ -311,15 +316,17 @@
g_weak_ref_init(&priv->engine, engine);
}
-void fl_renderer_add_view(FlRenderer* self,
- FlutterViewId view_id,
- FlView* view) {
+void fl_renderer_add_renderable(FlRenderer* self,
+ FlutterViewId view_id,
+ FlRenderable* renderable) {
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
fl_renderer_get_instance_private(self));
g_return_if_fail(FL_IS_RENDERER(self));
- g_hash_table_insert(priv->views, GINT_TO_POINTER(view_id), view);
+ GWeakRef* ref = g_new(GWeakRef, 1);
+ g_weak_ref_init(ref, G_OBJECT(renderable));
+ g_hash_table_insert(priv->views, GINT_TO_POINTER(view_id), ref);
}
void fl_renderer_remove_view(FlRenderer* self, FlutterViewId view_id) {
@@ -472,10 +479,12 @@
}
}
- FlView* view =
- FL_VIEW(g_hash_table_lookup(priv->views, GINT_TO_POINTER(view_id)));
- if (view != nullptr) {
- fl_view_redraw(view);
+ GWeakRef* ref = static_cast<GWeakRef*>(
+ g_hash_table_lookup(priv->views, GINT_TO_POINTER(view_id)));
+ g_autoptr(FlRenderable) renderable =
+ ref != nullptr ? FL_RENDERABLE(g_weak_ref_get(ref)) : nullptr;
+ if (renderable != nullptr) {
+ fl_renderable_redraw(renderable);
}
return TRUE;
diff --git a/shell/platform/linux/fl_renderer.h b/shell/platform/linux/fl_renderer.h
index 35d3669..b107442 100644
--- a/shell/platform/linux/fl_renderer.h
+++ b/shell/platform/linux/fl_renderer.h
@@ -7,11 +7,11 @@
#include <gtk/gtk.h>
-#include "flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h"
-#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
-
#include "flutter/shell/platform/embedder/embedder.h"
+#include "flutter/shell/platform/linux/fl_renderable.h"
+#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
+
G_BEGIN_DECLS
/**
@@ -79,16 +79,16 @@
void fl_renderer_set_engine(FlRenderer* renderer, FlEngine* engine);
/**
- * fl_renderer_add_view:
+ * fl_renderer_add_renderable:
* @renderer: an #FlRenderer.
* @view_id: the ID of the view.
- * @view: the view Flutter is renderering to.
+ * @renderable: object that is to be rendered on.
*
* Add a view to render on.
*/
-void fl_renderer_add_view(FlRenderer* renderer,
- FlutterViewId view_id,
- FlView* view);
+void fl_renderer_add_renderable(FlRenderer* renderer,
+ FlutterViewId view_id,
+ FlRenderable* renderable);
/**
* fl_renderer_remove_view:
diff --git a/shell/platform/linux/fl_renderer_test.cc b/shell/platform/linux/fl_renderer_test.cc
index b9336a1..7c4d83c 100644
--- a/shell/platform/linux/fl_renderer_test.cc
+++ b/shell/platform/linux/fl_renderer_test.cc
@@ -6,7 +6,6 @@
#include "flutter/fml/logging.h"
#include "flutter/shell/platform/linux/fl_framebuffer.h"
-#include "flutter/shell/platform/linux/testing/fl_test_gtk_logs.h"
#include "flutter/shell/platform/linux/testing/mock_epoxy.h"
#include "flutter/shell/platform/linux/testing/mock_renderer.h"
@@ -48,14 +47,12 @@
constexpr int kWidth = 100;
constexpr int kHeight = 100;
- flutter::testing::fl_ensure_gtk_init();
- g_autoptr(FlDartProject) project = fl_dart_project_new();
- g_autoptr(FlView) view = fl_view_new(project);
+ g_autoptr(FlRenderable) renderable = FL_RENDERABLE(fl_mock_renderable_new());
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
g_autoptr(FlFramebuffer) framebuffer =
fl_framebuffer_new(GL_RGB, kWidth, kHeight);
- fl_renderer_add_view(FL_RENDERER(renderer), 0, view);
+ fl_renderer_add_renderable(FL_RENDERER(renderer), 0, renderable);
fl_renderer_wait_for_frame(FL_RENDERER(renderer), kWidth, kHeight);
FlutterBackingStore backing_store;
@@ -84,8 +81,6 @@
glGetIntegerv(GL_TEXTURE_BINDING_2D,
reinterpret_cast<GLint*>(&texture_2d_binding));
EXPECT_EQ(texture_2d_binding, kFakeTextureName);
-
- g_object_ref_sink(view);
}
static constexpr double kExpectedRefreshRate = 120.0;
@@ -94,8 +89,6 @@
}
TEST(FlRendererTest, RefreshRate) {
- flutter::testing::fl_ensure_gtk_init();
- g_autoptr(FlDartProject) project = fl_dart_project_new();
g_autoptr(FlMockRenderer) renderer =
fl_mock_renderer_new(&renderer_get_refresh_rate);
diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc
index e84b144..5a68647 100644
--- a/shell/platform/linux/fl_view.cc
+++ b/shell/platform/linux/fl_view.cc
@@ -91,6 +91,8 @@
static guint fl_view_signals[kSignalLastSignal];
+static void fl_renderable_iface_init(FlRenderableInterface* iface);
+
static void fl_view_plugin_registry_iface_init(
FlPluginRegistryInterface* iface);
@@ -107,14 +109,16 @@
FlView,
fl_view,
GTK_TYPE_BOX,
- G_IMPLEMENT_INTERFACE(fl_plugin_registry_get_type(),
- fl_view_plugin_registry_iface_init)
- G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(),
- fl_view_keyboard_delegate_iface_init)
- G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(),
- fl_view_scrolling_delegate_iface_init)
- G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(),
- fl_view_text_input_delegate_iface_init))
+ G_IMPLEMENT_INTERFACE(fl_renderable_get_type(), fl_renderable_iface_init)
+ G_IMPLEMENT_INTERFACE(fl_plugin_registry_get_type(),
+ fl_view_plugin_registry_iface_init)
+ G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(),
+ fl_view_keyboard_delegate_iface_init)
+ G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(),
+ fl_view_scrolling_delegate_iface_init)
+ G_IMPLEMENT_INTERFACE(
+ fl_text_input_view_delegate_get_type(),
+ fl_view_text_input_delegate_iface_init))
// Emit the first frame signal in the main thread.
static gboolean first_frame_idle_cb(gpointer user_data) {
@@ -317,6 +321,20 @@
init_scrolling(self);
}
+// Implements FlRenderable::redraw
+static void fl_view_redraw(FlRenderable* renderable) {
+ FlView* self = FL_VIEW(renderable);
+
+ gtk_widget_queue_draw(GTK_WIDGET(self->gl_area));
+
+ if (!self->have_first_frame) {
+ self->have_first_frame = TRUE;
+ // This is not the main thread, so the signal needs to be done via an idle
+ // callback.
+ g_idle_add(first_frame_idle_cb, self);
+ }
+}
+
// Implements FlPluginRegistry::get_registrar_for_plugin.
static FlPluginRegistrar* fl_view_get_registrar_for_plugin(
FlPluginRegistry* registry,
@@ -328,6 +346,10 @@
fl_engine_get_texture_registrar(self->engine));
}
+static void fl_renderable_iface_init(FlRenderableInterface* iface) {
+ iface->redraw = fl_view_redraw;
+}
+
static void fl_view_plugin_registry_iface_init(
FlPluginRegistryInterface* iface) {
iface->get_registrar_for_plugin = fl_view_get_registrar_for_plugin;
@@ -621,7 +643,8 @@
init_keyboard(self);
- fl_renderer_add_view(FL_RENDERER(self->renderer), self->view_id, self);
+ fl_renderer_add_renderable(FL_RENDERER(self->renderer), self->view_id,
+ FL_RENDERABLE(self));
if (!fl_engine_start(self->engine, &error)) {
g_warning("Failed to start Flutter engine: %s", error->message);
@@ -866,7 +889,8 @@
self->view_id = fl_engine_add_view(self->engine, 1, 1, 1.0, self->cancellable,
view_added_cb, self);
- fl_renderer_add_view(FL_RENDERER(self->renderer), self->view_id, self);
+ fl_renderer_add_renderable(FL_RENDERER(self->renderer), self->view_id,
+ FL_RENDERABLE(self));
return self;
}
@@ -889,19 +913,6 @@
self->background_color = gdk_rgba_copy(color);
}
-void fl_view_redraw(FlView* self) {
- g_return_if_fail(FL_IS_VIEW(self));
-
- gtk_widget_queue_draw(GTK_WIDGET(self->gl_area));
-
- if (!self->have_first_frame) {
- self->have_first_frame = TRUE;
- // This is not the main thread, so the signal needs to be done via an idle
- // callback.
- g_idle_add(first_frame_idle_cb, self);
- }
-}
-
GHashTable* fl_view_get_keyboard_state(FlView* self) {
g_return_val_if_fail(FL_IS_VIEW(self), nullptr);
return fl_keyboard_handler_get_pressed_state(self->keyboard_handler);
diff --git a/shell/platform/linux/fl_view_private.h b/shell/platform/linux/fl_view_private.h
index de3fc9c..e23b178 100644
--- a/shell/platform/linux/fl_view_private.h
+++ b/shell/platform/linux/fl_view_private.h
@@ -8,14 +8,6 @@
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
/**
- * fl_view_redraw:
- * @view: an #FlView.
- *
- * Indicate the view needs to redraw.
- */
-void fl_view_redraw(FlView* view);
-
-/**
* fl_view_get_keyboard_state:
* @view: an #FlView.
*
diff --git a/shell/platform/linux/fl_view_test.cc b/shell/platform/linux/fl_view_test.cc
index 8abc8a1..acf1bca 100644
--- a/shell/platform/linux/fl_view_test.cc
+++ b/shell/platform/linux/fl_view_test.cc
@@ -50,7 +50,7 @@
EXPECT_FALSE(first_frame_emitted);
- fl_view_redraw(view);
+ fl_renderable_redraw(FL_RENDERABLE(view));
// Signal is emitted in idle, clear the main loop.
while (g_main_context_iteration(g_main_context_default(), FALSE)) {
diff --git a/shell/platform/linux/testing/mock_renderer.cc b/shell/platform/linux/testing/mock_renderer.cc
index c70980b..1106554 100644
--- a/shell/platform/linux/testing/mock_renderer.cc
+++ b/shell/platform/linux/testing/mock_renderer.cc
@@ -9,8 +9,20 @@
FlMockRendererGetRefreshRate get_refresh_rate;
};
+struct _FlMockRenderable {
+ GObject parent_instance;
+};
+
G_DEFINE_TYPE(FlMockRenderer, fl_mock_renderer, fl_renderer_get_type())
+static void mock_renderable_iface_init(FlRenderableInterface* iface);
+
+G_DEFINE_TYPE_WITH_CODE(FlMockRenderable,
+ fl_mock_renderable,
+ g_object_get_type(),
+ G_IMPLEMENT_INTERFACE(fl_renderable_get_type(),
+ mock_renderable_iface_init))
+
// Implements FlRenderer::make_current.
static void fl_mock_renderer_make_current(FlRenderer* renderer) {}
@@ -40,11 +52,27 @@
static void fl_mock_renderer_init(FlMockRenderer* self) {}
+static void mock_renderable_redraw(FlRenderable* renderable) {}
+
+static void mock_renderable_iface_init(FlRenderableInterface* iface) {
+ iface->redraw = mock_renderable_redraw;
+}
+
+static void fl_mock_renderable_class_init(FlMockRenderableClass* klass) {}
+
+static void fl_mock_renderable_init(FlMockRenderable* self) {}
+
// Creates a stub renderer
FlMockRenderer* fl_mock_renderer_new(
FlMockRendererGetRefreshRate get_refresh_rate) {
- FlMockRenderer* fl_mock_renderer = FL_MOCK_RENDERER(
- g_object_new_valist(fl_mock_renderer_get_type(), nullptr, nullptr));
- fl_mock_renderer->get_refresh_rate = get_refresh_rate;
- return fl_mock_renderer;
+ FlMockRenderer* self =
+ FL_MOCK_RENDERER(g_object_new(fl_mock_renderer_get_type(), nullptr));
+ self->get_refresh_rate = get_refresh_rate;
+ return self;
+}
+
+// Creates a sub renderable.
+FlMockRenderable* fl_mock_renderable_new() {
+ return FL_MOCK_RENDERABLE(
+ g_object_new(fl_mock_renderable_get_type(), nullptr));
}
diff --git a/shell/platform/linux/testing/mock_renderer.h b/shell/platform/linux/testing/mock_renderer.h
index 2dbbe08..0838708 100644
--- a/shell/platform/linux/testing/mock_renderer.h
+++ b/shell/platform/linux/testing/mock_renderer.h
@@ -5,6 +5,7 @@
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_RENDERER_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_RENDERER_H_
+#include "flutter/shell/platform/linux/fl_renderable.h"
#include "flutter/shell/platform/linux/fl_renderer.h"
G_BEGIN_DECLS
@@ -15,11 +16,19 @@
MOCK_RENDERER,
FlRenderer)
+G_DECLARE_FINAL_TYPE(FlMockRenderable,
+ fl_mock_renderable,
+ FL,
+ MOCK_RENDERABLE,
+ GObject)
+
typedef gdouble (*FlMockRendererGetRefreshRate)(FlRenderer* renderer);
FlMockRenderer* fl_mock_renderer_new(
FlMockRendererGetRefreshRate get_refresh_rate = nullptr);
+FlMockRenderable* fl_mock_renderable_new();
+
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_RENDERER_H_