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); + 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); - 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); + 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, + }); - cogl_pango_render_layout (layout, priv->text_x, 0, &cogl_color, 0); + clutter_paint_node_set_name (selection_text_node, "ClutterText.selection-text"); + clutter_paint_node_add_child (selection_clip_node, selection_text_node); - cogl_framebuffer_pop_clip (fb); + clutter_paint_node_add_texture_rectangle (selection_text_node, + &alloc, + priv->text_x, priv->text_y, + 1, 1); + + cogl_object_unref (selection_path); } } @@ -2373,26 +2405,43 @@ clutter_text_compute_layout_offsets (ClutterText *self, #define TEXT_PADDING 2 -static void -clutter_text_paint (ClutterActor *self) +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_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 + }); - selection_paint (text); + clutter_paint_node_set_name (text_node, "ClutterText.text"); + clutter_paint_node_add_child (node, text_node); - if (clip_set) - cogl_framebuffer_pop_clip (fb); + 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); + + 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;