Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-cogl-gradient.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2011 Intel Corporation.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it either under the terms of the GNU Lesser General Public
7  * License version 2.1 as published by the Free Software Foundation
8  * (the "LGPL") or, at your option, under the terms of the Mozilla
9  * Public License Version 1.1 (the "MPL"). If you do not alter this
10  * notice, a recipient may use your version of this file under either
11  * the MPL or the LGPL.
12  *
13  * You should have received a copy of the LGPL along with this library
14  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License at
22  * http://www.mozilla.og/MPL/
23  *
24  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26  * the specific language governing rights and limitations.
27  *
28  * Contributor(s):
29  *      Robert Bragg <robert@linux.intel.com>
30  */
31 //#include "cairoint.h"
32
33 #include "cairo-cogl-private.h"
34 #include "cairo-cogl-gradient-private.h"
35 #include "cairo-image-surface-private.h"
36
37 #include <cogl/cogl2-experimental.h>
38 #include <glib.h>
39
40 #define DUMP_GRADIENTS_TO_PNG
41
42 static unsigned long
43 _cairo_cogl_linear_gradient_hash (unsigned int                  n_stops,
44                                   const cairo_gradient_stop_t  *stops)
45 {
46     return _cairo_hash_bytes (n_stops, stops,
47                               sizeof (cairo_gradient_stop_t) * n_stops);
48 }
49
50 static cairo_cogl_linear_gradient_t *
51 _cairo_cogl_linear_gradient_lookup (cairo_cogl_device_t         *ctx,
52                                     unsigned long                 hash,
53                                     unsigned int                  n_stops,
54                                     const cairo_gradient_stop_t  *stops)
55 {
56     cairo_cogl_linear_gradient_t lookup;
57
58     lookup.cache_entry.hash = hash,
59     lookup.n_stops = n_stops;
60     lookup.stops = stops;
61
62     return _cairo_cache_lookup (&ctx->linear_cache, &lookup.cache_entry);
63 }
64
65 cairo_bool_t
66 _cairo_cogl_linear_gradient_equal (const void *key_a, const void *key_b)
67 {
68     const cairo_cogl_linear_gradient_t *a = key_a;
69     const cairo_cogl_linear_gradient_t *b = key_b;
70
71     if (a->n_stops != b->n_stops)
72         return FALSE;
73
74     return memcmp (a->stops, b->stops, a->n_stops * sizeof (cairo_gradient_stop_t)) == 0;
75 }
76
77 cairo_cogl_linear_gradient_t *
78 _cairo_cogl_linear_gradient_reference (cairo_cogl_linear_gradient_t *gradient)
79 {
80     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
81
82     _cairo_reference_count_inc (&gradient->ref_count);
83
84     return gradient;
85 }
86
87 void
88 _cairo_cogl_linear_gradient_destroy (cairo_cogl_linear_gradient_t *gradient)
89 {
90     GList *l;
91
92     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
93
94     if (! _cairo_reference_count_dec_and_test (&gradient->ref_count))
95         return;
96
97     for (l = gradient->textures; l; l = l->next) {
98         cairo_cogl_linear_texture_entry_t *entry = l->data;
99         cogl_object_unref (entry->texture);
100         free (entry);
101     }
102     g_list_free (gradient->textures);
103
104     free (gradient);
105 }
106
107 static int
108 _cairo_cogl_util_next_p2 (int a)
109 {
110   int rval = 1;
111
112   while (rval < a)
113     rval <<= 1;
114
115   return rval;
116 }
117
118 static float
119 get_max_color_component_range (const cairo_color_stop_t *color0, const cairo_color_stop_t *color1)
120 {
121     float range;
122     float max = 0;
123
124     range = fabs (color0->red - color1->red);
125     max = MAX (range, max);
126     range = fabs (color0->green - color1->green);
127     max = MAX (range, max);
128     range = fabs (color0->blue - color1->blue);
129     max = MAX (range, max);
130     range = fabs (color0->alpha - color1->alpha);
131     max = MAX (range, max);
132
133     return max;
134 }
135
136 static int
137 _cairo_cogl_linear_gradient_width_for_stops (cairo_extend_t               extend,
138                                              unsigned int                 n_stops,
139                                              const cairo_gradient_stop_t *stops)
140 {
141     unsigned int n;
142     float max_texels_per_unit_offset = 0;
143     float total_offset_range;
144
145     /* Find the stop pair demanding the most precision because we are
146      * interpolating the largest color-component range.
147      *
148      * From that we can define the relative sizes of all the other
149      * stop pairs within our texture and thus the overall size.
150      *
151      * To determine the maximum number of texels for a given gap we
152      * look at the range of colors we are expected to interpolate (so
153      * long as the stop offsets are not degenerate) and we simply
154      * assume we want one texel for each unique color value possible
155      * for a one byte-per-component representation.
156      * XXX: maybe this is overkill and just allowing 128 levels
157      * instead of 256 would be enough and then we'd rely on the
158      * bilinear filtering to give the full range.
159      *
160      * XXX: potentially we could try and map offsets to pixels to come
161      * up with a more precise mapping, but we are aiming to cache
162      * the gradients so we can't make assumptions about how it will be
163      * scaled in the future.
164      */
165     for (n = 1; n < n_stops; n++) {
166         float color_range;
167         float offset_range;
168         float texels;
169         float texels_per_unit_offset;
170
171         /* note: degenerate stops don't need to be represented in the
172          * texture but we want to be sure that solid gaps get at least
173          * one texel and all other gaps get at least 2 texels.
174          */
175
176         if (stops[n].offset == stops[n-1].offset)
177             continue;
178
179         color_range = get_max_color_component_range (&stops[n].color, &stops[n-1].color);
180         if (color_range == 0)
181             texels = 1;
182         else
183             texels = MAX (2, 256.0f * color_range);
184
185         /* So how many texels would we need to map over the full [0,1]
186          * gradient range so this gap would have enough texels? ... */
187         offset_range = stops[n].offset - stops[n - 1].offset;
188         texels_per_unit_offset = texels / offset_range;
189
190         if (texels_per_unit_offset > max_texels_per_unit_offset)
191             max_texels_per_unit_offset = texels_per_unit_offset;
192     }
193
194     total_offset_range = fabs (stops[n_stops - 1].offset - stops[0].offset);
195     return max_texels_per_unit_offset * total_offset_range;
196 }
197
198 /* Aim to create gradient textures without an alpha component so we can avoid
199  * needing to use blending... */
200 static CoglPixelFormat
201 _cairo_cogl_linear_gradient_format_for_stops (cairo_extend_t               extend,
202                                               unsigned int                 n_stops,
203                                               const cairo_gradient_stop_t *stops)
204 {
205     unsigned int n;
206
207     /* We have to add extra transparent texels to the end of the gradient to
208      * handle CAIRO_EXTEND_NONE... */
209     if (extend == CAIRO_EXTEND_NONE)
210         return COGL_PIXEL_FORMAT_BGRA_8888_PRE;
211
212     for (n = 1; n < n_stops; n++) {
213         if (stops[n].color.alpha != 1.0)
214             return COGL_PIXEL_FORMAT_BGRA_8888_PRE;
215     }
216
217     return COGL_PIXEL_FORMAT_BGR_888;
218 }
219
220 static cairo_cogl_gradient_compatibility_t
221 _cairo_cogl_compatibility_from_extend_mode (cairo_extend_t extend_mode)
222 {
223     switch (extend_mode)
224     {
225     case CAIRO_EXTEND_NONE:
226         return CAIRO_COGL_GRADIENT_CAN_EXTEND_NONE;
227     case CAIRO_EXTEND_PAD:
228         return CAIRO_COGL_GRADIENT_CAN_EXTEND_PAD;
229     case CAIRO_EXTEND_REPEAT:
230         return CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT;
231     case CAIRO_EXTEND_REFLECT:
232         return CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT;
233     }
234
235     assert (0); /* not reached */
236     return CAIRO_EXTEND_NONE;
237 }
238
239 cairo_cogl_linear_texture_entry_t *
240 _cairo_cogl_linear_gradient_texture_for_extend (cairo_cogl_linear_gradient_t *gradient,
241                                                 cairo_extend_t extend_mode)
242 {
243     GList *l;
244     cairo_cogl_gradient_compatibility_t compatibility =
245         _cairo_cogl_compatibility_from_extend_mode (extend_mode);
246     for (l = gradient->textures; l; l = l->next) {
247         cairo_cogl_linear_texture_entry_t *entry = l->data;
248         if (entry->compatibility & compatibility)
249             return entry;
250     }
251     return NULL;
252 }
253
254 static void
255 color_stop_lerp (const cairo_color_stop_t *c0,
256                  const cairo_color_stop_t *c1,
257                  float factor,
258                  cairo_color_stop_t *dest)
259 {
260     /* NB: we always ignore the short members in this file so we don't need to
261      * worry about initializing them here. */
262     dest->red = c0->red * (1.0f-factor) + c1->red * factor;
263     dest->green = c0->green * (1.0f-factor) + c1->green * factor;
264     dest->blue = c0->blue * (1.0f-factor) + c1->blue * factor;
265     dest->alpha = c0->alpha * (1.0f-factor) + c1->alpha * factor;
266 }
267
268 static size_t
269 _cairo_cogl_linear_gradient_size (cairo_cogl_linear_gradient_t *gradient)
270 {
271     GList *l;
272     size_t size = 0;
273     for (l = gradient->textures; l; l = l->next) {
274         cairo_cogl_linear_texture_entry_t *entry = l->data;
275         size += cogl_texture_get_width (entry->texture) * 4;
276     }
277     return size;
278 }
279
280 static void
281 emit_stop (CoglVertexP2C4 **position,
282            float left,
283            float right,
284            const cairo_color_stop_t *left_color,
285            const cairo_color_stop_t *right_color)
286 {
287     CoglVertexP2C4 *p = *position;
288
289     guint8 lr = left_color->red * 255;
290     guint8 lg = left_color->green * 255;
291     guint8 lb = left_color->blue * 255;
292     guint8 la = left_color->alpha * 255;
293
294     guint8 rr = right_color->red * 255;
295     guint8 rg = right_color->green * 255;
296     guint8 rb = right_color->blue * 255;
297     guint8 ra = right_color->alpha * 255;
298
299     p[0].x = left;
300     p[0].y = 0;
301     p[0].r = lr; p[0].g = lg; p[0].b = lb; p[0].a = la;
302     p[1].x = left;
303     p[1].y = 1;
304     p[1].r = lr; p[1].g = lg; p[1].b = lb; p[1].a = la;
305     p[2].x = right;
306     p[2].y = 1;
307     p[2].r = rr; p[2].g = rg; p[2].b = rb; p[2].a = ra;
308
309     p[3].x = left;
310     p[3].y = 0;
311     p[3].r = lr; p[3].g = lg; p[3].b = lb; p[3].a = la;
312     p[4].x = right;
313     p[4].y = 1;
314     p[4].r = rr; p[4].g = rg; p[4].b = rb; p[4].a = ra;
315     p[5].x = right;
316     p[5].y = 0;
317     p[5].r = rr; p[5].g = rg; p[5].b = rb; p[5].a = ra;
318
319     *position = &p[6];
320 }
321
322 #ifdef DUMP_GRADIENTS_TO_PNG
323 static void
324 dump_gradient_to_png (CoglTexture *texture)
325 {
326     cairo_image_surface_t *image = (cairo_image_surface_t *)
327         cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
328                                     cogl_texture_get_width (texture),
329                                     cogl_texture_get_height (texture));
330     CoglPixelFormat format;
331     static int gradient_id = 0;
332     char *gradient_name;
333
334     if (image->base.status)
335         return;
336
337 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
338     format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
339 #else
340     format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
341 #endif
342     cogl_texture_get_data (texture,
343                            format,
344                            0,
345                            image->data);
346     gradient_name = g_strdup_printf ("./gradient%d.png", gradient_id++);
347     g_print ("writing gradient: %s\n", gradient_name);
348     cairo_surface_write_to_png ((cairo_surface_t *)image, gradient_name);
349     g_free (gradient_name);
350 }
351 #endif
352
353 cairo_int_status_t
354 _cairo_cogl_get_linear_gradient (cairo_cogl_device_t *device,
355                                  cairo_extend_t extend_mode,
356                                  int n_stops,
357                                  const cairo_gradient_stop_t *stops,
358                                  cairo_cogl_linear_gradient_t **gradient_out)
359 {
360     unsigned long hash;
361     cairo_cogl_linear_gradient_t *gradient;
362     cairo_cogl_linear_texture_entry_t *entry;
363     cairo_gradient_stop_t *internal_stops;
364     int stop_offset;
365     int n_internal_stops;
366     int n;
367     cairo_cogl_gradient_compatibility_t compatibilities;
368     int width;
369     int left_padding = 0;
370     cairo_color_stop_t left_padding_color;
371     int right_padding = 0;
372     cairo_color_stop_t right_padding_color;
373     CoglPixelFormat format;
374     CoglTexture2D *tex;
375     GError *error = NULL;
376     int un_padded_width;
377     CoglHandle offscreen;
378     cairo_int_status_t status;
379     int n_quads;
380     int n_vertices;
381     float prev;
382     float right;
383     CoglVertexP2C4 *vertices;
384     CoglVertexP2C4 *p;
385     CoglPrimitive *prim;
386
387     hash = _cairo_cogl_linear_gradient_hash (n_stops, stops);
388
389     gradient = _cairo_cogl_linear_gradient_lookup (device, hash, n_stops, stops);
390     if (gradient) {
391         cairo_cogl_linear_texture_entry_t *entry =
392             _cairo_cogl_linear_gradient_texture_for_extend (gradient, extend_mode);
393         if (entry) {
394             *gradient_out = _cairo_cogl_linear_gradient_reference (gradient);
395             return CAIRO_INT_STATUS_SUCCESS;
396         }
397     }
398
399     if (!gradient) {
400         gradient = malloc (sizeof (cairo_cogl_linear_gradient_t) +
401                            sizeof (cairo_gradient_stop_t) * (n_stops - 1));
402         if (!gradient)
403             return CAIRO_INT_STATUS_NO_MEMORY;
404
405         CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);
406         /* NB: we update the cache_entry size at the end before
407          * [re]adding it to the cache. */
408         gradient->cache_entry.hash = hash;
409         gradient->textures = NULL;
410         gradient->n_stops = n_stops;
411         gradient->stops = gradient->stops_embedded;
412         memcpy (gradient->stops_embedded, stops, sizeof (cairo_gradient_stop_t) * n_stops);
413     } else
414         _cairo_cogl_linear_gradient_reference (gradient);
415
416     entry = malloc (sizeof (cairo_cogl_linear_texture_entry_t));
417     if (!entry) {
418         status = CAIRO_INT_STATUS_NO_MEMORY;
419         goto BAIL;
420     }
421
422     compatibilities = _cairo_cogl_compatibility_from_extend_mode (extend_mode);
423
424     n_internal_stops = n_stops;
425     stop_offset = 0;
426
427     /* We really need stops covering the full [0,1] range for repeat/reflect
428      * if we want to use sampler REPEAT/MIRROR wrap modes so we may need
429      * to add some extra stops... */
430     if (extend_mode == CAIRO_EXTEND_REPEAT || extend_mode == CAIRO_EXTEND_REFLECT)
431     {
432         /* If we don't need any extra stops then actually the texture
433          * will be shareable for repeat and reflect... */
434         compatibilities = (CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT |
435                            CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT);
436
437         if (stops[0].offset != 0) {
438             n_internal_stops++;
439             stop_offset++;
440         }
441
442         if (stops[n_stops - 1].offset != 1)
443             n_internal_stops++;
444     }
445
446     internal_stops = alloca (n_internal_stops * sizeof (cairo_gradient_stop_t));
447     memcpy (&internal_stops[stop_offset], stops, sizeof (cairo_gradient_stop_t) * n_stops);
448
449     /* cairo_color_stop_t values are all unpremultiplied but we need to
450      * interpolate premultiplied colors so we premultiply all the double
451      * components now. (skipping any extra stops added for repeat/reflect)
452      *
453      * Anothing thing to note is that by premultiplying the colors
454      * early we'll also reduce the range of colors to interpolate
455      * which can result in smaller gradient textures.
456      */
457     for (n = stop_offset; n < n_stops; n++) {
458         cairo_color_stop_t *color = &internal_stops[n].color;
459         color->red *= color->alpha;
460         color->green *= color->alpha;
461         color->blue *= color->alpha;
462     }
463
464     if (n_internal_stops != n_stops)
465     {
466         if (extend_mode == CAIRO_EXTEND_REPEAT) {
467             compatibilities &= ~CAIRO_COGL_GRADIENT_CAN_EXTEND_REFLECT;
468             if (stops[0].offset != 0) {
469                 /* what's the wrap-around distance between the user's end-stops? */
470                 double dx = (1.0 - stops[n_stops - 1].offset) + stops[0].offset;
471                 internal_stops[0].offset = 0;
472                 color_stop_lerp (&stops[0].color,
473                                  &stops[n_stops - 1].color,
474                                  stops[0].offset / dx,
475                                  &internal_stops[0].color);
476             }
477             if (stops[n_stops - 1].offset != 1) {
478                 internal_stops[n_internal_stops - 1].offset = 1;
479                 internal_stops[n_internal_stops - 1].color = internal_stops[0].color;
480             }
481         } else if (extend_mode == CAIRO_EXTEND_REFLECT) {
482             compatibilities &= ~CAIRO_COGL_GRADIENT_CAN_EXTEND_REPEAT;
483             if (stops[0].offset != 0) {
484                 internal_stops[0].offset = 0;
485                 internal_stops[0].color = stops[n_stops - 1].color;
486             }
487             if (stops[n_stops - 1].offset != 1) {
488                 internal_stops[n_internal_stops - 1].offset = 1;
489                 internal_stops[n_internal_stops - 1].color = stops[0].color;
490             }
491         }
492     }
493
494     stops = internal_stops;
495     n_stops = n_internal_stops;
496
497     width = _cairo_cogl_linear_gradient_width_for_stops (extend_mode, n_stops, stops);
498
499     if (extend_mode == CAIRO_EXTEND_PAD) {
500
501         /* Here we need to guarantee that the edge texels of our
502          * texture correspond to the desired padding color so we
503          * can use CLAMP_TO_EDGE.
504          *
505          * For short stop-gaps and especially for degenerate stops
506          * it's possible that without special consideration the
507          * user's end stop colors would not be present in our final
508          * texture.
509          *
510          * To handle this we forcibly add two extra padding texels
511          * at the edges which extend beyond the [0,1] range of the
512          * gradient itself and we will later report a translate and
513          * scale transform to compensate for this.
514          */
515
516         /* XXX: If we consider generating a mipmap for our 1d texture
517          * at some point then we also need to consider how much
518          * padding to add to be sure lower mipmap levels still have
519          * the desired edge color (as opposed to a linear blend with
520          * other colors of the gradient).
521          */
522
523         left_padding = 1;
524         left_padding_color = stops[0].color;
525         right_padding = 1;
526         right_padding_color = stops[n_stops - 1].color;
527     } else if (extend_mode == CAIRO_EXTEND_NONE) {
528         /* We handle EXTEND_NONE by adding two extra, transparent, texels at
529          * the ends of the texture and use CLAMP_TO_EDGE.
530          *
531          * We add a scale and translate transform so to account for our texels
532          * extending beyond the [0,1] range. */
533
534         left_padding = 1;
535         left_padding_color.red = 0;
536         left_padding_color.green = 0;
537         left_padding_color.blue = 0;
538         left_padding_color.alpha = 0;
539         right_padding = 1;
540         right_padding_color = left_padding_color;
541     }
542
543     /* If we still have stops that don't cover the full [0,1] range
544      * then we need to define a texture-coordinate scale + translate
545      * transform to account for that... */
546     if (stops[n_stops - 1].offset - stops[0].offset < 1) {
547         float range = stops[n_stops - 1].offset - stops[0].offset;
548         entry->scale_x = 1.0 / range;
549         entry->translate_x = -(stops[0].offset * entry->scale_x);
550     }
551
552     width += left_padding + right_padding;
553
554     width = _cairo_cogl_util_next_p2 (width);
555     width = MIN (4096, width); /* lets not go too stupidly big! */
556     format = _cairo_cogl_linear_gradient_format_for_stops (extend_mode, n_stops, stops);
557
558     do {
559         tex = cogl_texture_2d_new_with_size (device->cogl_context,
560                                              width,
561                                              1,
562                                              format,
563                                              &error);
564         if (!tex)
565             g_error_free (error);
566     } while (tex == NULL && width >> 1);
567
568     if (!tex) {
569         status = CAIRO_INT_STATUS_NO_MEMORY;
570         goto BAIL;
571     }
572
573     entry->texture = COGL_TEXTURE (tex);
574     entry->compatibility = compatibilities;
575
576     un_padded_width = width - left_padding - right_padding;
577
578     /* XXX: only when we know the final texture width can we calculate the
579      * scale and translate factors needed to account for padding... */
580     if (un_padded_width != width)
581         entry->scale_x *= (float)un_padded_width / (float)width;
582     if (left_padding)
583         entry->translate_x += (entry->scale_x / (float)un_padded_width) * (float)left_padding;
584
585     offscreen = cogl_offscreen_new_to_texture (tex);
586     cogl_push_framebuffer (COGL_FRAMEBUFFER (offscreen));
587     cogl_ortho (0, width, 1, 0, -1, 100);
588     cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
589                               COGL_BUFFER_BIT_COLOR,
590                               0, 0, 0, 0);
591
592     n_quads = n_stops - 1 + !!left_padding + !!right_padding;
593     n_vertices = 6 * n_quads;
594     vertices = alloca (sizeof (CoglVertexP2C4) * n_vertices);
595     p = vertices;
596     if (left_padding)
597         emit_stop (&p, 0, left_padding, &left_padding_color, &left_padding_color);
598     prev = (float)left_padding;
599     for (n = 1; n < n_stops; n++) {
600         right = (float)left_padding + (float)un_padded_width * stops[n].offset;
601         emit_stop (&p, prev, right, &stops[n-1].color, &stops[n].color);
602         prev = right;
603     }
604     if (right_padding)
605         emit_stop (&p, prev, width, &right_padding_color, &right_padding_color);
606
607     prim = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
608                                     n_vertices,
609                                     vertices);
610     /* Just use this as the simplest way to setup a default pipeline... */
611     cogl_set_source_color4f (0, 0, 0, 0);
612     cogl_primitive_draw (prim);
613     cogl_object_unref (prim);
614
615     cogl_pop_framebuffer ();
616     cogl_object_unref (offscreen);
617
618     gradient->textures = g_list_prepend (gradient->textures, entry);
619     gradient->cache_entry.size = _cairo_cogl_linear_gradient_size (gradient);
620
621 #ifdef DUMP_GRADIENTS_TO_PNG
622     dump_gradient_to_png (COGL_TEXTURE (tex));
623 #endif
624
625 #warning "FIXME:"
626     /* XXX: it seems the documentation of _cairo_cache_insert isn't true - it
627      * doesn't handle re-adding the same entry gracefully - the cache will
628      * just keep on growing and then it will start randomly evicting things
629      * pointlessly */
630     /* we ignore errors here and just return an uncached gradient */
631     if (likely (! _cairo_cache_insert (&device->linear_cache, &gradient->cache_entry)))
632         _cairo_cogl_linear_gradient_reference (gradient);
633
634     *gradient_out = gradient;
635     return CAIRO_INT_STATUS_SUCCESS;
636
637 BAIL:
638     free (entry);
639     if (gradient)
640         _cairo_cogl_linear_gradient_destroy (gradient);
641     return status;
642 }