summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-09-26 02:05:28 -0300
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-09-28 21:38:12 -0300
commit5a4ade857a505fc1a8948b178d26a0a96eb7f86c (patch)
treef50449cffe0c3180bd1adb35d3b235cd1041bce0
parentcc75fc88ee8939bab6951a67ed514b93fb457e26 (diff)
downloadmutter-gbsneto/paint-nodes.tar.gz
Port ClutterText to ClutterPaintNodegbsneto/paint-nodes
The port to use ClutterPaintNodes basically mirrors what it currently does, with the major benefit of not depending on cogl_get_draw_framebuffer() anymore. There are various factors that influence the number of subnodes: * The background color adds a color subnode; * The selection adds a clip subnode, and a color subnode, or a color and a text subnode; The simplest case is when the text does not overflow and has no background color nor selection. In that case, the render tree is simply: [ Dummy ] ↓ [ Text ] In contrast, the most complex case is when drawing the text with selection, in which case the render tree looks like: [ Dummy ] ↓ [ Clip ] ↓ [ Text ] → [ Clip ] ↓ [ Color ] → [ Text ] Since the selection may have another text color, the selected text must be rendered again, but clipped to only cover the selection rectangle. This is suboptimal, but it's what the current code already does anyway.
-rw-r--r--clutter/clutter/clutter-text.c179
1 files changed, 116 insertions, 63 deletions
diff --git a/clutter/clutter/clutter-text.c b/clutter/clutter/clutter-text.c
index d8c7f2875..4e480fecf 100644
--- a/clutter/clutter/clutter-text.c
+++ b/clutter/clutter/clutter-text.c
@@ -1746,7 +1746,8 @@ add_selection_rectangle_to_path (ClutterText *text,
/* Draws the selected text, its background, and the cursor */
static void
-selection_paint (ClutterText *self)
+paint_selection (ClutterText *self,
+ ClutterPaintNode *node)
{
ClutterTextPrivate *priv = self->priv;
ClutterActor *actor = CLUTTER_ACTOR (self);
@@ -1758,33 +1759,59 @@ selection_paint (ClutterText *self)
if (priv->position == priv->selection_bound)
{
+ g_autoptr(ClutterPaintNode) cursor_node = NULL;
+
/* No selection, just draw the cursor */
if (priv->cursor_color_set)
color = &priv->cursor_color;
else
color = &priv->text_color;
- cogl_set_source_color4ub (color->red,
- color->green,
- color->blue,
- paint_opacity * color->alpha / 255);
-
- cogl_rectangle (priv->cursor_rect.origin.x,
- priv->cursor_rect.origin.y,
- priv->cursor_rect.origin.x + priv->cursor_rect.size.width,
- priv->cursor_rect.origin.y + priv->cursor_rect.size.height);
+ cursor_node = clutter_color_node_new (&(ClutterColor) {
+ color->red,
+ color->green,
+ color->blue,
+ paint_opacity * color->alpha / 255,
+ });
+ clutter_paint_node_set_name (cursor_node, "ClutterText.selection-background");
+ clutter_paint_node_add_child (node, cursor_node);
+
+ clutter_paint_node_add_rectangle (cursor_node,
+ &(ClutterActorBox) {
+ priv->cursor_rect.origin.x,
+ priv->cursor_rect.origin.y,
+ priv->cursor_rect.origin.x + priv->cursor_rect.size.width,
+ priv->cursor_rect.origin.y + priv->cursor_rect.size.height
+ });
}
else
{
/* Paint selection background first */
+ g_autoptr(ClutterPaintNode) selection_background_node = NULL;
+ g_autoptr(ClutterPaintNode) selection_text_node = NULL;
+ g_autoptr(ClutterPaintNode) selection_clip_node = NULL;
PangoLayout *layout = clutter_text_get_layout (self);
+ ClutterActorBox alloc = { 0, };
CoglPath *selection_path = cogl_path_new ();
- CoglColor cogl_color = { 0, };
- CoglFramebuffer *fb;
- fb = cogl_get_draw_framebuffer ();
- if (G_UNLIKELY (fb == NULL))
- return;
+ clutter_text_foreach_selection_rectangle (self,
+ add_selection_rectangle_to_path,
+ selection_path);
+
+ /* Clip against both the actor allocation - we don't want to draw
+ * the selection rectangle outside the actor - and the selection
+ * path - we don't want to render the text over the unselected
+ * text either.
+ */
+ selection_clip_node = clutter_clip_node_new ();
+ clutter_paint_node_set_name (selection_clip_node, "ClutterText.clip-selection");
+ clutter_paint_node_add_child (node, selection_clip_node);
+
+ clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &alloc);
+ clutter_actor_box_set_origin (&alloc, 0, 0);
+
+ clutter_paint_node_add_rectangle (selection_clip_node, &alloc);
+ clutter_paint_node_add_path (selection_clip_node, selection_path);
/* Paint selection background */
if (priv->selection_color_set)
@@ -1794,35 +1821,40 @@ selection_paint (ClutterText *self)
else
color = &priv->text_color;
- cogl_set_source_color4ub (color->red,
- color->green,
- color->blue,
- paint_opacity * color->alpha / 255);
+ selection_background_node = clutter_color_node_new (&(ClutterColor) {
+ color->red,
+ color->green,
+ color->blue,
+ paint_opacity * color->alpha / 255,
+ });
+ clutter_paint_node_set_name (selection_background_node, "ClutterText.selection-background");
+ clutter_paint_node_add_child (selection_clip_node, selection_background_node);
- clutter_text_foreach_selection_rectangle (self,
- add_selection_rectangle_to_path,
- selection_path);
-
- cogl_path_fill (selection_path);
+ clutter_paint_node_add_path (selection_background_node, selection_path);
/* Paint selected text */
- cogl_framebuffer_push_path_clip (fb, selection_path);
- cogl_object_unref (selection_path);
-
if (priv->selected_text_color_set)
color = &priv->selected_text_color;
else
color = &priv->text_color;
- cogl_color_init_from_4ub (&cogl_color,
- color->red,
- color->green,
- color->blue,
- paint_opacity * color->alpha / 255);
+ selection_text_node = clutter_text_node_new (layout,
+ &(ClutterColor) {
+ color->red,
+ color->green,
+ color->blue,
+ paint_opacity * color->alpha / 255,
+ });
+
+ clutter_paint_node_set_name (selection_text_node, "ClutterText.selection-text");
+ clutter_paint_node_add_child (selection_clip_node, selection_text_node);
- cogl_pango_render_layout (layout, priv->text_x, 0, &cogl_color, 0);
+ clutter_paint_node_add_texture_rectangle (selection_text_node,
+ &alloc,
+ priv->text_x, priv->text_y,
+ 1, 1);
- cogl_framebuffer_pop_clip (fb);
+ cogl_object_unref (selection_path);
}
}
@@ -2373,26 +2405,43 @@ clutter_text_compute_layout_offsets (ClutterText *self,
#define TEXT_PADDING 2
+static inline ClutterPaintNode *
+create_clip_node (ClutterPaintNode *node,
+ float width,
+ float height)
+{
+ g_autoptr(ClutterPaintNode) clip_node = NULL;
+
+ clip_node = clutter_clip_node_new ();
+ clutter_paint_node_set_name (clip_node, "ClutterText.clip");
+ clutter_paint_node_add_child (node, clip_node);
+
+ clutter_paint_node_add_rectangle (clip_node,
+ &(ClutterActorBox) {
+ 0, 0,
+ width, height,
+ });
+
+ return g_steal_pointer (&clip_node);
+}
+
static void
-clutter_text_paint (ClutterActor *self)
+clutter_text_paint_node (ClutterActor *self,
+ ClutterPaintNode *node)
{
+ g_autoptr(ClutterPaintNode) text_node = NULL;
ClutterText *text = CLUTTER_TEXT (self);
ClutterTextPrivate *priv = text->priv;
- CoglFramebuffer *fb;
PangoLayout *layout;
ClutterActorBox alloc = { 0, };
- CoglColor color = { 0, };
guint8 real_opacity;
gint text_x = priv->text_x;
gint text_y = priv->text_y;
- gboolean clip_set = FALSE;
gboolean bg_color_set = FALSE;
guint n_chars;
float alloc_width;
float alloc_height;
- fb = cogl_get_draw_framebuffer ();
-
/* Note that if anything in this paint method changes it needs to be
reflected in the get_paint_volume implementation which is tightly
tied to the workings of this function */
@@ -2405,6 +2454,7 @@ clutter_text_paint (ClutterActor *self)
g_object_get (self, "background-color-set", &bg_color_set, NULL);
if (bg_color_set)
{
+ g_autoptr(ClutterPaintNode) background_color_node = NULL;
ClutterColor bg_color;
clutter_actor_get_background_color (self, &bg_color);
@@ -2412,11 +2462,11 @@ clutter_text_paint (ClutterActor *self)
* bg_color.alpha
/ 255;
- cogl_set_source_color4ub (bg_color.red,
- bg_color.green,
- bg_color.blue,
- bg_color.alpha);
- cogl_rectangle (0, 0, alloc_width, alloc_height);
+ background_color_node = clutter_color_node_new (&bg_color);
+ clutter_paint_node_set_name (background_color_node, "ClutterText.background-color");
+ clutter_paint_node_add_child (node, background_color_node);
+
+ clutter_paint_node_add_rectangle (background_color_node, &alloc);
}
/* don't bother painting an empty text actor, unless it's
@@ -2469,8 +2519,7 @@ clutter_text_paint (ClutterActor *self)
pango_layout_get_extents (layout, NULL, &logical_rect);
- cogl_framebuffer_push_rectangle_clip (fb, 0, 0, alloc_width, alloc_height);
- clip_set = TRUE;
+ node = create_clip_node (node, alloc_width, alloc_height);
actor_width = alloc_width - 2 * TEXT_PADDING;
text_width = logical_rect.width / PANGO_SCALE;
@@ -2513,12 +2562,8 @@ clutter_text_paint (ClutterActor *self)
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
/* don't clip if the layout managed to fit inside our allocation */
- if (logical_rect.width > alloc_width ||
- logical_rect.height > alloc_height)
- {
- cogl_framebuffer_push_rectangle_clip (fb, 0, 0, alloc_width, alloc_height);
- clip_set = TRUE;
- }
+ if (logical_rect.width > alloc_width || logical_rect.height > alloc_height)
+ node = create_clip_node (node, alloc_width, alloc_height);
clutter_text_compute_layout_offsets (text, layout, &alloc, &text_x, &text_y);
}
@@ -2541,17 +2586,25 @@ clutter_text_paint (ClutterActor *self)
CLUTTER_NOTE (PAINT, "painting text (text: '%s')",
clutter_text_buffer_get_text (get_buffer (text)));
- cogl_color_init_from_4ub (&color,
- priv->text_color.red,
- priv->text_color.green,
- priv->text_color.blue,
- real_opacity);
- cogl_pango_render_layout (layout, priv->text_x, priv->text_y, &color, 0);
+ text_node = clutter_text_node_new (layout,
+ &(ClutterColor) {
+ priv->text_color.red,
+ priv->text_color.green,
+ priv->text_color.blue,
+ real_opacity
+ });
+
+ clutter_paint_node_set_name (text_node, "ClutterText.text");
+ clutter_paint_node_add_child (node, text_node);
- selection_paint (text);
+ clutter_actor_box_set_origin (&alloc, 0, 0);
+ clutter_paint_node_add_texture_rectangle (text_node,
+ &alloc,
+ priv->text_x,
+ priv->text_y,
+ 1, 1);
- if (clip_set)
- cogl_framebuffer_pop_clip (fb);
+ paint_selection (text, node);
}
static void
@@ -3548,7 +3601,7 @@ clutter_text_class_init (ClutterTextClass *klass)
gobject_class->dispose = clutter_text_dispose;
gobject_class->finalize = clutter_text_finalize;
- actor_class->paint = clutter_text_paint;
+ actor_class->paint_node = clutter_text_paint_node;
actor_class->get_paint_volume = clutter_text_get_paint_volume;
actor_class->get_preferred_width = clutter_text_get_preferred_width;
actor_class->get_preferred_height = clutter_text_get_preferred_height;