File: cairo-texture.c

package info (click to toggle)
clutter-1.0 1.26.4%2Bgit2779b932%2Bdfsg-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 16,672 kB
  • sloc: ansic: 130,756; xml: 1,641; makefile: 1,607; sh: 980; perl: 192; ruby: 167
file content (198 lines) | stat: -rw-r--r-- 5,519 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include <clutter/clutter.h>
#include <cogl/cogl.h>

#include "test-conform-common.h"

#define BLOCK_SIZE 16

/* Number of pixels at the border of a block to skip when verifying */
#define TEST_INSET 1

static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };

typedef enum
{
  /* The first frame is drawn using clutter_cairo_texture_create. The
     second frame is an update of the first frame using
     clutter_cairo_texture_create_region. The states are stored like
     this because the cairo drawing is done on idle and the validation
     is done during paint and we need to synchronize the two */
  TEST_BEFORE_DRAW_FIRST_FRAME,
  TEST_BEFORE_VALIDATE_FIRST_FRAME,
  TEST_BEFORE_DRAW_SECOND_FRAME,
  TEST_BEFORE_VALIDATE_SECOND_FRAME,
  TEST_DONE
} TestProgress;

typedef struct _TestState
{
  ClutterActor *stage;
  ClutterActor *ct;
  guint frame;
  TestProgress progress;
} TestState;

static void
validate_part (int block_x, int block_y, const ClutterColor *color)
{
  guint8 data[BLOCK_SIZE * BLOCK_SIZE * 4];
  int x, y;

  cogl_read_pixels (block_x * BLOCK_SIZE,
                    block_y * BLOCK_SIZE,
                    BLOCK_SIZE, BLOCK_SIZE,
                    COGL_READ_PIXELS_COLOR_BUFFER,
                    COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                    data);

  for (x = 0; x < BLOCK_SIZE - TEST_INSET * 2; x++)
    for (y = 0; y < BLOCK_SIZE - TEST_INSET * 2; y++)
      {
        const guint8 *p = data + ((x + TEST_INSET) * 4 +
                                  (y + TEST_INSET) * BLOCK_SIZE * 4);

        g_assert_cmpint (p[0], ==, color->red);
        g_assert_cmpint (p[1], ==, color->green);
        g_assert_cmpint (p[2], ==, color->blue);
      }
}

static void
paint_cb (ClutterActor *actor, TestState *state)
{
  static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff };
  static const ClutterColor green = { 0x00, 0xff, 0x00, 0xff };
  static const ClutterColor blue = { 0x00, 0x00, 0xff, 0xff };

  if (state->frame++ < 2)
    return;

  switch (state->progress)
    {
    case TEST_BEFORE_DRAW_FIRST_FRAME:
    case TEST_BEFORE_DRAW_SECOND_FRAME:
    case TEST_DONE:
      /* Handled by the idle callback */
      break;

    case TEST_BEFORE_VALIDATE_FIRST_FRAME:
      /* In the first frame there is a red rectangle next to a green
         rectangle */
      validate_part (0, 0, &red);
      validate_part (1, 0, &green);

      state->progress = TEST_BEFORE_DRAW_SECOND_FRAME;
      break;

    case TEST_BEFORE_VALIDATE_SECOND_FRAME:
      /* The second frame is the same except the green rectangle is
         replaced with a blue one */
      validate_part (0, 0, &red);
      validate_part (1, 0, &blue);

      state->progress = TEST_DONE;
      break;
    }
}

static gboolean
idle_cb (gpointer data)
{
  TestState *state = data;
  cairo_t *cr;

  if (state->frame < 2)
    clutter_actor_queue_redraw (CLUTTER_ACTOR (state->stage));
  else
    switch (state->progress)
      {
      case TEST_BEFORE_DRAW_FIRST_FRAME:
        /* Draw two different colour rectangles */
        cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (state->ct));

        cairo_save (cr);
        cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);

        cairo_save (cr);
        cairo_rectangle (cr, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
        cairo_clip (cr);
        cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
        cairo_paint (cr);
        cairo_restore (cr);

        cairo_rectangle (cr, BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE);
        cairo_clip (cr);
        cairo_set_source_rgb (cr, 0.0, 1.0, 0.0);
        cairo_paint (cr);

        cairo_restore (cr);

        cairo_destroy (cr);

        state->progress = TEST_BEFORE_VALIDATE_FIRST_FRAME;

        break;

      case TEST_BEFORE_DRAW_SECOND_FRAME:
        /* Replace the second rectangle with a blue one */
        cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (state->ct));

        cairo_rectangle (cr, BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE);
        cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
        cairo_fill (cr);

        cairo_destroy (cr);

        state->progress = TEST_BEFORE_VALIDATE_SECOND_FRAME;

        break;

      case TEST_BEFORE_VALIDATE_FIRST_FRAME:
      case TEST_BEFORE_VALIDATE_SECOND_FRAME:
        /* Handled by the paint callback */
        break;

      case TEST_DONE:
        clutter_main_quit ();
        break;
      }

  return G_SOURCE_CONTINUE;
}

void
texture_cairo (TestConformSimpleFixture *fixture,
               gconstpointer data)
{
  TestState state;
  unsigned int idle_source;
  unsigned int paint_handler;

  state.frame = 0;
  state.stage = clutter_stage_new ();
  state.progress = TEST_BEFORE_DRAW_FIRST_FRAME;

  state.ct = clutter_cairo_texture_new (BLOCK_SIZE * 2, BLOCK_SIZE);
  clutter_container_add_actor (CLUTTER_CONTAINER (state.stage), state.ct);

  clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);

  /* We force continuous redrawing of the stage, since we need to skip
   * the first few frames, and we wont be doing anything else that
   * will trigger redrawing. */
  idle_source = clutter_threads_add_idle (idle_cb, &state);
  paint_handler = g_signal_connect_after (state.stage, "paint",
                                          G_CALLBACK (paint_cb), &state);

  clutter_actor_show (state.stage);
  clutter_main ();

  g_signal_handler_disconnect (state.stage, paint_handler);
  g_source_remove (idle_source);

  if (g_test_verbose ())
    g_print ("OK\n");

  clutter_actor_destroy (state.stage);
}