~cairo-dock-team/ubuntu/oneiric/cairo-dock/2.3.0-3

« back to all changes in this revision

Viewing changes to src/gldit/cairo-dock-surface-factory.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthieu Baerts (matttbe)
  • Date: 2010-08-09 23:26:12 UTC
  • mto: This revision was merged to the branch mainline in revision 13.
  • Revision ID: james.westby@ubuntu.com-20100809232612-pocdxliaxjdetm37
Tags: upstream-2.2.0~0beta4
ImportĀ upstreamĀ versionĀ 2.2.0~0beta4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
* This file is a part of the Cairo-Dock project
 
3
*
 
4
* Copyright : (C) see the 'copyright' file.
 
5
* E-mail    : see the 'copyright' file.
 
6
*
 
7
* This program is free software; you can redistribute it and/or
 
8
* modify it under the terms of the GNU General Public License
 
9
* as published by the Free Software Foundation; either version 3
 
10
* of the License, or (at your option) any later version.
 
11
*
 
12
* This program is distributed in the hope that it will be useful,
 
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
* GNU General Public License for more details.
 
16
* You should have received a copy of the GNU General Public License
 
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
#include <string.h>
 
21
#include <math.h>
 
22
#include <librsvg/rsvg.h>
 
23
#include <librsvg/rsvg-cairo.h>
 
24
#include <pango/pango.h>
 
25
 
 
26
#include "cairo-dock-log.h"
 
27
#include "cairo-dock-draw.h"
 
28
#include "cairo-dock-launcher-manager.h"
 
29
#include "cairo-dock-container.h"
 
30
#include "cairo-dock-load.h"
 
31
#include "cairo-dock-surface-factory.h"
 
32
 
 
33
extern CairoContainer *g_pPrimaryContainer;
 
34
extern gboolean g_bUseOpenGL;
 
35
 
 
36
static cairo_t *s_pSourceContext = NULL;
 
37
 
 
38
 
 
39
void cairo_dock_calculate_size_fill (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, gboolean bNoZoomUp, double *fZoomWidth, double *fZoomHeight)
 
40
{
 
41
        if (iWidthConstraint != 0)
 
42
        {
 
43
                *fZoomWidth = 1. * iWidthConstraint / (*fImageWidth);
 
44
                if (bNoZoomUp && *fZoomWidth > 1)
 
45
                        *fZoomWidth = 1;
 
46
                else
 
47
                        *fImageWidth = (double) iWidthConstraint;
 
48
        }
 
49
        else
 
50
                *fZoomWidth = 1.;
 
51
        if (iHeightConstraint != 0)
 
52
        {
 
53
                *fZoomHeight = 1. * iHeightConstraint / (*fImageHeight);
 
54
                if (bNoZoomUp && *fZoomHeight > 1)
 
55
                        *fZoomHeight = 1;
 
56
                else
 
57
                        *fImageHeight = (double) iHeightConstraint;
 
58
        }
 
59
        else
 
60
                *fZoomHeight = 1.;
 
61
}
 
62
 
 
63
void cairo_dock_calculate_size_constant_ratio (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, gboolean bNoZoomUp, double *fZoom)
 
64
{
 
65
        if (iWidthConstraint != 0 && iHeightConstraint != 0)
 
66
                *fZoom = MIN (iWidthConstraint / (*fImageWidth), iHeightConstraint / (*fImageHeight));
 
67
        else if (iWidthConstraint != 0)
 
68
                *fZoom = iWidthConstraint / (*fImageWidth);
 
69
        else if (iHeightConstraint != 0)
 
70
                *fZoom = iHeightConstraint / (*fImageHeight);
 
71
        else
 
72
                *fZoom = 1.;
 
73
        if (bNoZoomUp && *fZoom > 1)
 
74
                *fZoom = 1.;
 
75
        *fImageWidth = (*fImageWidth) * (*fZoom);
 
76
        *fImageHeight = (*fImageHeight) * (*fZoom);
 
77
}
 
78
 
 
79
 
 
80
 
 
81
void cairo_dock_calculate_constrainted_size (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, CairoDockLoadImageModifier iLoadingModifier, double *fZoomWidth, double *fZoomHeight)
 
82
{
 
83
        gboolean bFillSpace = iLoadingModifier & CAIRO_DOCK_FILL_SPACE;
 
84
        gboolean bKeepRatio = iLoadingModifier & CAIRO_DOCK_KEEP_RATIO;
 
85
        gboolean bNoZoomUp = iLoadingModifier & CAIRO_DOCK_DONT_ZOOM_IN;
 
86
        gint iOrientation = iLoadingModifier & CAIRO_DOCK_ORIENTATION_MASK;
 
87
        if (iOrientation > CAIRO_DOCK_ORIENTATION_VFLIP)  // inversion x/y
 
88
        {
 
89
                double tmp = *fImageWidth;
 
90
                *fImageWidth = *fImageHeight;
 
91
                *fImageHeight = tmp;
 
92
        }
 
93
        if (bKeepRatio)
 
94
        {
 
95
                cairo_dock_calculate_size_constant_ratio (fImageWidth,
 
96
                        fImageHeight,
 
97
                        iWidthConstraint,
 
98
                        iHeightConstraint,
 
99
                        bNoZoomUp,
 
100
                        fZoomWidth);
 
101
                *fZoomHeight = *fZoomWidth;
 
102
                if (bFillSpace)
 
103
                {
 
104
                        //double fUsefulWidth = *fImageWidth;
 
105
                        //double fUsefulHeight = *fImageHeight;
 
106
                        if (iWidthConstraint != 0)
 
107
                                *fImageWidth = iWidthConstraint;
 
108
                        if (iHeightConstraint != 0)
 
109
                                *fImageHeight = iHeightConstraint;
 
110
                }
 
111
        }
 
112
        else
 
113
        {
 
114
                cairo_dock_calculate_size_fill (fImageWidth,
 
115
                        fImageHeight,
 
116
                        iWidthConstraint,
 
117
                        iHeightConstraint,
 
118
                        bNoZoomUp,
 
119
                        fZoomWidth,
 
120
                        fZoomHeight);
 
121
        }
 
122
}
 
123
 
 
124
 
 
125
#define _get_source_context(...) \
 
126
        __extension__ ({\
 
127
        if (s_pSourceContext == NULL) {\
 
128
                if (g_pPrimaryContainer != NULL)\
 
129
                        s_pSourceContext = cairo_dock_create_drawing_context_generic (g_pPrimaryContainer); }\
 
130
        s_pSourceContext; })
 
131
#define _destroy_source_context(...) do {\
 
132
        if (s_pSourceContext != NULL) {\
 
133
                cairo_destroy (s_pSourceContext);\
 
134
                s_pSourceContext = NULL; } } while (0)
 
135
 
 
136
void cairo_dock_reset_source_context (void)
 
137
{
 
138
        _destroy_source_context ();
 
139
}
 
140
 
 
141
cairo_surface_t *cairo_dock_create_blank_surface (int iWidth, int iHeight)
 
142
{
 
143
        cairo_t *pSourceContext = _get_source_context ();
 
144
        if (pSourceContext != NULL && ! g_bUseOpenGL)
 
145
                return cairo_surface_create_similar (cairo_get_target (pSourceContext),
 
146
                        CAIRO_CONTENT_COLOR_ALPHA,
 
147
                        iWidth,
 
148
                        iHeight);
 
149
        else
 
150
                return cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
 
151
                        iWidth,
 
152
                        iHeight);
 
153
}
 
154
 
 
155
static inline void _apply_orientation_and_scale (cairo_t *pCairoContext, CairoDockLoadImageModifier iLoadingModifier, double fImageWidth, double fImageHeight, double fZoomX, double fZoomY, double fUsefulWidth, double fUsefulheight)
 
156
{
 
157
        int iOrientation = iLoadingModifier & CAIRO_DOCK_ORIENTATION_MASK;
 
158
        
 
159
        cairo_translate (pCairoContext,
 
160
                fImageWidth/2,
 
161
                fImageHeight/2);
 
162
        cairo_scale (pCairoContext,
 
163
                fZoomX,
 
164
                fZoomY);
 
165
        switch (iOrientation)
 
166
        {
 
167
                case CAIRO_DOCK_ORIENTATION_HFLIP :
 
168
                        cd_debug ("orientation : HFLIP");
 
169
                        cairo_scale (pCairoContext, -1., 1.);
 
170
                break ;
 
171
                case CAIRO_DOCK_ORIENTATION_ROT_180 :
 
172
                        cd_debug ("orientation : ROT_180");
 
173
                        cairo_rotate (pCairoContext, G_PI);
 
174
                break ;
 
175
                case CAIRO_DOCK_ORIENTATION_VFLIP :
 
176
                        cd_debug ("orientation : VFLIP");
 
177
                        cairo_scale (pCairoContext, 1., -1.);
 
178
                break ;
 
179
                case CAIRO_DOCK_ORIENTATION_ROT_90_HFLIP :
 
180
                        cd_debug ("orientation : ROT_90_HFLIP");
 
181
                        cairo_scale (pCairoContext, -1., 1.);
 
182
                        cairo_rotate (pCairoContext, + G_PI/2);
 
183
                break ;
 
184
                case CAIRO_DOCK_ORIENTATION_ROT_90 :
 
185
                        cd_debug ("orientation : ROT_90");
 
186
                        cairo_rotate (pCairoContext, + G_PI/2);
 
187
                break ;
 
188
                case CAIRO_DOCK_ORIENTATION_ROT_90_VFLIP :
 
189
                        cd_debug ("orientation : ROT_90_VFLIP");
 
190
                        cairo_scale (pCairoContext, 1., -1.);
 
191
                        cairo_rotate (pCairoContext, + G_PI/2);
 
192
                break ;
 
193
                case CAIRO_DOCK_ORIENTATION_ROT_270 :
 
194
                        cd_debug ("orientation : ROT_270");
 
195
                        cairo_rotate (pCairoContext, - G_PI/2);
 
196
                break ;
 
197
                default :
 
198
                break ;
 
199
        }
 
200
        if (iOrientation < CAIRO_DOCK_ORIENTATION_ROT_90_HFLIP)
 
201
                cairo_translate (pCairoContext,
 
202
                        - fUsefulWidth/2/fZoomX,
 
203
                        - fUsefulheight/2/fZoomY);
 
204
        else
 
205
                cairo_translate (pCairoContext,
 
206
                        - fUsefulheight/2/fZoomY,
 
207
                        - fUsefulWidth/2/fZoomX);
 
208
}
 
209
 
 
210
 
 
211
cairo_surface_t *cairo_dock_create_surface_from_xicon_buffer (gulong *pXIconBuffer, int iBufferNbElements, int iWidth, int iHeight)
 
212
{
 
213
        cairo_t *pSourceContext = _get_source_context ();
 
214
        g_return_val_if_fail (pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
 
215
 
 
216
        //\____________________ On recupere la plus grosse des icones presentes dans le tampon (meilleur rendu).
 
217
        int iIndex = 0, iBestIndex = 0;
 
218
        while (iIndex + 2 < iBufferNbElements)
 
219
        {
 
220
                if (pXIconBuffer[iIndex] == 0 || pXIconBuffer[iIndex+1] == 0)  // precaution au cas ou un buffer foirreux nous serait retourne, on risque de boucler sans fin.
 
221
                {
 
222
                        cd_warning ("This icon is broken !\nThis means that one of the current applications has sent a buggy icon to X.");
 
223
                        if (iIndex == 0)  // tout le buffer est a jeter.
 
224
                                return NULL;
 
225
                        break;
 
226
                }
 
227
                if (pXIconBuffer[iIndex] > pXIconBuffer[iBestIndex])
 
228
                        iBestIndex = iIndex;
 
229
                iIndex += 2 + pXIconBuffer[iIndex] * pXIconBuffer[iIndex+1];
 
230
        }
 
231
 
 
232
        //\____________________ On pre-multiplie chaque composante par le alpha (necessaire pour libcairo).
 
233
        int w = pXIconBuffer[iBestIndex];
 
234
        int h = pXIconBuffer[iBestIndex+1];
 
235
        iBestIndex += 2;
 
236
        //g_print ("%s (%dx%d)\n", __func__, w, h);
 
237
        
 
238
        int i, n = w * h;
 
239
        if (iBestIndex + n > iBufferNbElements)  // precaution au cas ou le nombre d'elements dans le buffer serait incorrect.
 
240
        {
 
241
                cd_warning ("This icon is broken !\nThis means that one of the current applications has sent a buggy icon to X.");
 
242
                return NULL;
 
243
        }
 
244
        gint pixel, alpha, red, green, blue;
 
245
        float fAlphaFactor;
 
246
        gint *pPixelBuffer = (gint *) &pXIconBuffer[iBestIndex];  // on va ecrire le resultat du filtre directement dans le tableau fourni en entree. C'est ok car sizeof(gulong) >= sizeof(gint), donc le tableau de pixels est plus petit que le buffer fourni en entree. merci a Hannemann pour ses tests et ses screenshots ! :-)
 
247
        for (i = 0; i < n; i ++)
 
248
        {
 
249
                pixel = (gint) pXIconBuffer[iBestIndex+i];
 
250
                alpha = (pixel & 0xFF000000) >> 24;
 
251
                red   = (pixel & 0x00FF0000) >> 16;
 
252
                green = (pixel & 0x0000FF00) >> 8;
 
253
                blue  = (pixel & 0x000000FF);
 
254
                fAlphaFactor = (float) alpha / 255;
 
255
                red *= fAlphaFactor;
 
256
                green *= fAlphaFactor;
 
257
                blue *= fAlphaFactor;
 
258
                pPixelBuffer[i] = (pixel & 0xFF000000) + (red << 16) + (green << 8) + blue;
 
259
        }
 
260
 
 
261
        //\____________________ On cree la surface a partir du tampon.
 
262
        int iStride = w * sizeof (gint);  // nbre d'octets entre le debut de 2 lignes.
 
263
        cairo_surface_t *surface_ini = cairo_image_surface_create_for_data ((guchar *)pPixelBuffer,
 
264
                CAIRO_FORMAT_ARGB32,
 
265
                w,
 
266
                h,
 
267
                iStride);
 
268
        
 
269
        double fWidth = w, fHeight = h;
 
270
        double fIconWidthSaturationFactor = 1., fIconHeightSaturationFactor = 1.;
 
271
        cairo_dock_calculate_constrainted_size (&fWidth,
 
272
                &fHeight,
 
273
                iWidth,
 
274
                iHeight,
 
275
                CAIRO_DOCK_KEEP_RATIO | CAIRO_DOCK_FILL_SPACE,
 
276
                &fIconWidthSaturationFactor,
 
277
                &fIconHeightSaturationFactor);
 
278
        
 
279
        cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
 
280
                iWidth,
 
281
                iHeight);
 
282
        cairo_t *pCairoContext = cairo_create (pNewSurface);
 
283
        
 
284
        double fUsefulWidth = w * fIconWidthSaturationFactor;  // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
 
285
        double fUsefulHeight = h * fIconHeightSaturationFactor;
 
286
        _apply_orientation_and_scale (pCairoContext,
 
287
                CAIRO_DOCK_KEEP_RATIO | CAIRO_DOCK_FILL_SPACE,
 
288
                iWidth, iHeight,
 
289
                fIconWidthSaturationFactor, fIconHeightSaturationFactor,
 
290
                fUsefulWidth, fUsefulHeight);
 
291
        cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
 
292
        cairo_paint (pCairoContext);
 
293
 
 
294
        cairo_surface_destroy (surface_ini);
 
295
        cairo_destroy (pCairoContext);
 
296
 
 
297
        return pNewSurface;
 
298
}
 
299
 
 
300
 
 
301
cairo_surface_t *cairo_dock_create_surface_from_pixbuf (GdkPixbuf *pixbuf, double fMaxScale, int iWidthConstraint, int iHeightConstraint, CairoDockLoadImageModifier iLoadingModifier, double *fImageWidth, double *fImageHeight, double *fZoomX, double *fZoomY)
 
302
{
 
303
        *fImageWidth = gdk_pixbuf_get_width (pixbuf);
 
304
        *fImageHeight = gdk_pixbuf_get_height (pixbuf);
 
305
        double fIconWidthSaturationFactor = 1., fIconHeightSaturationFactor = 1.;
 
306
        cairo_dock_calculate_constrainted_size (fImageWidth,
 
307
                        fImageHeight,
 
308
                        iWidthConstraint,
 
309
                        iHeightConstraint,
 
310
                        iLoadingModifier,
 
311
                        &fIconWidthSaturationFactor,
 
312
                        &fIconHeightSaturationFactor);
 
313
 
 
314
        GdkPixbuf *pPixbufWithAlpha = pixbuf;
 
315
        if (! gdk_pixbuf_get_has_alpha (pixbuf))  // on lui rajoute un canal alpha s'il n'en a pas.
 
316
        {
 
317
                //g_print ("  ajout d'un canal alpha\n");
 
318
                pPixbufWithAlpha = gdk_pixbuf_add_alpha (pixbuf, FALSE, 255, 255, 255);  // TRUE <=> les pixels blancs deviennent transparents.
 
319
        }
 
320
 
 
321
        //\____________________ On pre-multiplie chaque composante par le alpha (necessaire pour libcairo).
 
322
        int iNbChannels = gdk_pixbuf_get_n_channels (pPixbufWithAlpha);
 
323
        int iRowstride = gdk_pixbuf_get_rowstride (pPixbufWithAlpha);
 
324
        int w = gdk_pixbuf_get_width (pPixbufWithAlpha);
 
325
        guchar *p, *pixels = gdk_pixbuf_get_pixels (pPixbufWithAlpha);
 
326
        int h = gdk_pixbuf_get_height (pPixbufWithAlpha);
 
327
        int x, y;
 
328
        int red, green, blue;
 
329
        float fAlphaFactor;
 
330
        for (y = 0; y < h; y ++)
 
331
        {
 
332
                for (x = 0; x < w; x ++)
 
333
                {
 
334
                        p = pixels + y * iRowstride + x * iNbChannels;
 
335
                        fAlphaFactor = (float) p[3] / 255;
 
336
                        red = p[0] * fAlphaFactor;
 
337
                        green = p[1] * fAlphaFactor;
 
338
                        blue = p[2] * fAlphaFactor;
 
339
                        p[0] = blue;
 
340
                        p[1] = green;
 
341
                        p[2] = red;
 
342
                }
 
343
        }
 
344
        
 
345
        cairo_surface_t *surface_ini = cairo_image_surface_create_for_data (pixels,
 
346
                CAIRO_FORMAT_ARGB32,
 
347
                w,
 
348
                h,
 
349
                iRowstride);
 
350
 
 
351
        cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
 
352
                ceil ((*fImageWidth) * fMaxScale),
 
353
                ceil ((*fImageHeight) * fMaxScale));
 
354
        cairo_t *pCairoContext = cairo_create (pNewSurface);
 
355
        
 
356
        double fUsefulWidth = w * fIconWidthSaturationFactor;  // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
 
357
        double fUsefulHeight = h * fIconHeightSaturationFactor;
 
358
        _apply_orientation_and_scale (pCairoContext,
 
359
                iLoadingModifier,
 
360
                ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
 
361
                fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
 
362
                fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
 
363
        
 
364
        cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
 
365
        cairo_paint (pCairoContext);
 
366
        
 
367
        cairo_destroy (pCairoContext);
 
368
        cairo_surface_destroy (surface_ini);
 
369
        if (pPixbufWithAlpha != pixbuf)
 
370
                g_object_unref (pPixbufWithAlpha);
 
371
        
 
372
        if (fZoomX != NULL)
 
373
                *fZoomX = fIconWidthSaturationFactor;
 
374
        if (fZoomY != NULL)
 
375
                *fZoomY = fIconHeightSaturationFactor;
 
376
        
 
377
        return pNewSurface;
 
378
}
 
379
 
 
380
 
 
381
cairo_surface_t *cairo_dock_create_surface_from_image (const gchar *cImagePath, double fMaxScale, int iWidthConstraint, int iHeightConstraint, CairoDockLoadImageModifier iLoadingModifier, double *fImageWidth, double *fImageHeight, double *fZoomX, double *fZoomY)
 
382
{
 
383
        //g_print ("%s (%s, %dx%dx%.2f, %d)\n", __func__, cImagePath, iWidthConstraint, iHeightConstraint, fMaxScale, iLoadingModifier);
 
384
        g_return_val_if_fail (cImagePath != NULL, NULL);
 
385
        cairo_t *pSourceContext = _get_source_context ();
 
386
        g_return_val_if_fail (pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
 
387
        GError *erreur = NULL;
 
388
        RsvgDimensionData rsvg_dimension_data;
 
389
        RsvgHandle *rsvg_handle = NULL;
 
390
        cairo_surface_t* surface_ini;
 
391
        cairo_surface_t* pNewSurface = NULL;
 
392
        cairo_t* pCairoContext = NULL;
 
393
        double fIconWidthSaturationFactor = 1.;
 
394
        double fIconHeightSaturationFactor = 1.;
 
395
        
 
396
        //\_______________ On cherche a determiner le type de l'image. En effet, les SVG et les PNG sont charges differemment des autres.
 
397
        gboolean bIsSVG = FALSE, bIsPNG = FALSE, bIsXPM = FALSE;
 
398
        FILE *fd = fopen (cImagePath, "r");
 
399
        if (fd != NULL)
 
400
        {
 
401
                char buffer[8];
 
402
                if (fgets (buffer, 7, fd) != NULL)
 
403
                {
 
404
                        if (strncmp (buffer+2, "xml", 3) == 0)
 
405
                                bIsSVG = TRUE;
 
406
                        else if (strncmp (buffer+1, "PNG", 3) == 0)
 
407
                                bIsPNG = TRUE;
 
408
                        else if (strncmp (buffer+3, "XPM", 3) == 0)
 
409
                                bIsXPM = TRUE;
 
410
                        //cd_debug ("  format : %d;%d;%d", bIsSVG, bIsPNG, bIsXPM);
 
411
                }
 
412
                fclose (fd);
 
413
        }
 
414
        else
 
415
        {
 
416
                cd_warning ("This file (%s) doesn't exist or is not readable.", cImagePath);
 
417
                return NULL;
 
418
        }
 
419
        if (! bIsSVG && ! bIsPNG && ! bIsXPM)  // sinon en desespoir de cause on se base sur l'extension.
 
420
        {
 
421
                //cd_debug ("  on se base sur l'extension en desespoir de cause.");
 
422
                if (g_str_has_suffix (cImagePath, ".svg"))
 
423
                        bIsSVG = TRUE;
 
424
                else if (g_str_has_suffix (cImagePath, ".png"))
 
425
                        bIsPNG = TRUE;
 
426
        }
 
427
        
 
428
        bIsPNG = FALSE;  /// libcairo 1.6 - 1.8 est bugguee !!!...
 
429
        if (bIsSVG)
 
430
        {
 
431
                rsvg_handle = rsvg_handle_new_from_file (cImagePath, &erreur);
 
432
                if (erreur != NULL)
 
433
                {
 
434
                        cd_warning (erreur->message);
 
435
                        g_error_free (erreur);
 
436
                        return NULL;
 
437
                }
 
438
                else
 
439
                {
 
440
                        g_return_val_if_fail (rsvg_handle != NULL, NULL);
 
441
                        rsvg_handle_get_dimensions (rsvg_handle, &rsvg_dimension_data);
 
442
                        int w = rsvg_dimension_data.width;
 
443
                        int h = rsvg_dimension_data.height;
 
444
                        *fImageWidth = (gdouble) w;
 
445
                        *fImageHeight = (gdouble) h;
 
446
                        //g_print ("%.2fx%.2f\n", *fImageWidth, *fImageHeight);
 
447
                        cairo_dock_calculate_constrainted_size (fImageWidth,
 
448
                                fImageHeight,
 
449
                                iWidthConstraint,
 
450
                                iHeightConstraint,
 
451
                                iLoadingModifier,
 
452
                                &fIconWidthSaturationFactor,
 
453
                                &fIconHeightSaturationFactor);
 
454
                        
 
455
                        pNewSurface = cairo_dock_create_blank_surface (
 
456
                                ceil ((*fImageWidth) * fMaxScale),
 
457
                                ceil ((*fImageHeight) * fMaxScale));
 
458
 
 
459
                        pCairoContext = cairo_create (pNewSurface);
 
460
                        double fUsefulWidth = w * fIconWidthSaturationFactor;  // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
 
461
                        double fUsefulHeight = h * fIconHeightSaturationFactor;
 
462
                        _apply_orientation_and_scale (pCairoContext,
 
463
                                iLoadingModifier,
 
464
                                ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
 
465
                                fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
 
466
                                fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
 
467
 
 
468
                        rsvg_handle_render_cairo (rsvg_handle, pCairoContext);
 
469
                        cairo_destroy (pCairoContext);
 
470
                        g_object_unref (rsvg_handle);
 
471
                }
 
472
        }
 
473
        else if (bIsPNG)
 
474
        {
 
475
                surface_ini = cairo_image_surface_create_from_png (cImagePath);  // cree un fond noir :-(
 
476
                if (cairo_surface_status (surface_ini) == CAIRO_STATUS_SUCCESS)
 
477
                {
 
478
                        int w = cairo_image_surface_get_width (surface_ini);
 
479
                        int h = cairo_image_surface_get_height (surface_ini);
 
480
                        *fImageWidth = (double) w;
 
481
                        *fImageHeight = (double) h;
 
482
                        cairo_dock_calculate_constrainted_size (fImageWidth,
 
483
                                fImageHeight,
 
484
                                iWidthConstraint,
 
485
                                iHeightConstraint,
 
486
                                iLoadingModifier,
 
487
                                &fIconWidthSaturationFactor,
 
488
                                &fIconHeightSaturationFactor);
 
489
                        
 
490
                        pNewSurface = cairo_dock_create_blank_surface (
 
491
                                ceil ((*fImageWidth) * fMaxScale),
 
492
                                ceil ((*fImageHeight) * fMaxScale));
 
493
                        pCairoContext = cairo_create (pNewSurface);
 
494
                        cairo_set_operator (pCairoContext, CAIRO_OPERATOR_SOURCE);
 
495
                        cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
 
496
                        cairo_paint (pCairoContext);
 
497
                        cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
 
498
                        
 
499
                        double fUsefulWidth = w * fIconWidthSaturationFactor;  // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
 
500
                        double fUsefulHeight = h * fIconHeightSaturationFactor;
 
501
                        _apply_orientation_and_scale (pCairoContext,
 
502
                                iLoadingModifier,
 
503
                                ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
 
504
                                fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
 
505
                                fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
 
506
                        
 
507
                        cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
 
508
                        cairo_paint (pCairoContext);
 
509
                        cairo_destroy (pCairoContext);
 
510
                }
 
511
                cairo_surface_destroy (surface_ini);
 
512
        }
 
513
        else  // le code suivant permet de charger tout type d'image, mais en fait c'est un peu idiot d'utiliser des icones n'ayant pas de transparence.
 
514
        {
 
515
                GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (cImagePath, &erreur);  // semble se baser sur l'extension pour definir le type !
 
516
                if (erreur != NULL)
 
517
                {
 
518
                        cd_warning (erreur->message);
 
519
                        g_error_free (erreur);
 
520
                        return NULL;
 
521
                }
 
522
                pNewSurface = cairo_dock_create_surface_from_pixbuf (pixbuf,
 
523
                        fMaxScale,
 
524
                        iWidthConstraint,
 
525
                        iHeightConstraint,
 
526
                        iLoadingModifier,
 
527
                        fImageWidth,
 
528
                        fImageHeight,
 
529
                        &fIconWidthSaturationFactor,
 
530
                        &fIconHeightSaturationFactor);
 
531
                g_object_unref (pixbuf);
 
532
                
 
533
        }
 
534
        
 
535
        if (fZoomX != NULL)
 
536
                *fZoomX = fIconWidthSaturationFactor;
 
537
        if (fZoomY != NULL)
 
538
                *fZoomY = fIconHeightSaturationFactor;
 
539
        
 
540
        return pNewSurface;
 
541
}
 
542
 
 
543
cairo_surface_t *cairo_dock_create_surface_from_image_simple (const gchar *cImageFile, double fImageWidth, double fImageHeight)
 
544
{
 
545
        g_return_val_if_fail (cImageFile != NULL, NULL);
 
546
        double fImageWidth_ = fImageWidth, fImageHeight_ = fImageHeight;
 
547
        gchar *cImagePath;
 
548
        if (*cImageFile == '/')
 
549
                cImagePath = (gchar *)cImageFile;
 
550
        else
 
551
                cImagePath = cairo_dock_generate_file_path (cImageFile);
 
552
                
 
553
        cairo_surface_t *pSurface = cairo_dock_create_surface_from_image (cImagePath,
 
554
                1.,
 
555
                fImageWidth,
 
556
                fImageHeight,
 
557
                CAIRO_DOCK_FILL_SPACE,
 
558
                &fImageWidth_,
 
559
                &fImageHeight_,
 
560
                NULL,
 
561
                NULL);
 
562
        if (cImagePath != cImageFile)
 
563
                g_free (cImagePath);
 
564
        return pSurface;
 
565
}
 
566
 
 
567
cairo_surface_t *cairo_dock_create_surface_from_icon (const gchar *cImageFile, double fImageWidth, double fImageHeight)
 
568
{
 
569
        g_return_val_if_fail (cImageFile != NULL, NULL);
 
570
        double fImageWidth_ = fImageWidth, fImageHeight_ = fImageHeight;
 
571
        gchar *cIconPath;
 
572
        if (*cImageFile == '/')
 
573
                cIconPath = (gchar *)cImageFile;
 
574
        else
 
575
                cIconPath = cairo_dock_search_icon_s_path (cImageFile);
 
576
                
 
577
        cairo_surface_t *pSurface = cairo_dock_create_surface_from_image (cIconPath,
 
578
                1.,
 
579
                fImageWidth,
 
580
                fImageHeight,
 
581
                CAIRO_DOCK_FILL_SPACE,
 
582
                &fImageWidth_,
 
583
                &fImageHeight_,
 
584
                NULL,
 
585
                NULL);
 
586
        if (cIconPath != cImageFile)
 
587
                g_free (cIconPath);
 
588
        return pSurface;
 
589
}
 
590
 
 
591
cairo_surface_t *cairo_dock_create_surface_from_pattern (const gchar *cImageFile, double fImageWidth, double fImageHeight, double fAlpha)
 
592
{
 
593
        cairo_surface_t *pNewSurface = NULL;
 
594
 
 
595
        if (cImageFile != NULL)
 
596
        {
 
597
                gchar *cImagePath = cairo_dock_generate_file_path (cImageFile);
 
598
                double fImageWidth, fImageHeight;
 
599
                cairo_surface_t *pPatternSurface = cairo_dock_create_surface_from_image (cImagePath,
 
600
                        1.,
 
601
                        0,  // pas de contrainte sur
 
602
                        0,  // la taille du motif initialement.
 
603
                        CAIRO_DOCK_FILL_SPACE,
 
604
                        &fImageWidth,
 
605
                        &fImageHeight,
 
606
                        NULL, NULL);
 
607
                g_free (cImagePath);
 
608
                if (pPatternSurface == NULL)
 
609
                        return NULL;
 
610
                
 
611
                pNewSurface = cairo_dock_create_blank_surface (
 
612
                        fImageWidth,
 
613
                        fImageHeight);
 
614
                cairo_t *pCairoContext = cairo_create (pNewSurface);
 
615
 
 
616
                cairo_pattern_t* pPattern = cairo_pattern_create_for_surface (pPatternSurface);
 
617
                g_return_val_if_fail (cairo_pattern_status (pPattern) == CAIRO_STATUS_SUCCESS, NULL);
 
618
                cairo_pattern_set_extend (pPattern, CAIRO_EXTEND_REPEAT);
 
619
 
 
620
                cairo_set_source (pCairoContext, pPattern);
 
621
                cairo_paint_with_alpha (pCairoContext, fAlpha);
 
622
                cairo_destroy (pCairoContext);
 
623
                cairo_pattern_destroy (pPattern);
 
624
                
 
625
                cairo_surface_destroy (pPatternSurface);
 
626
        }
 
627
        
 
628
        return pNewSurface;
 
629
}
 
630
 
 
631
 
 
632
 
 
633
cairo_surface_t * cairo_dock_rotate_surface (cairo_surface_t *pSurface, double fImageWidth, double fImageHeight, double fRotationAngle)
 
634
{
 
635
        g_return_val_if_fail (pSurface != NULL, NULL);
 
636
        if (fRotationAngle != 0)
 
637
        {
 
638
                cairo_surface_t *pNewSurfaceRotated;
 
639
                cairo_t *pCairoContext;
 
640
                if (fabs (fRotationAngle) > G_PI / 2)
 
641
                {
 
642
                        pNewSurfaceRotated = cairo_dock_create_blank_surface (
 
643
                                fImageWidth,
 
644
                                fImageHeight);
 
645
                        pCairoContext = cairo_create (pNewSurfaceRotated);
 
646
 
 
647
                        cairo_translate (pCairoContext, 0, fImageHeight);
 
648
                        cairo_scale (pCairoContext, 1, -1);
 
649
                }
 
650
                else
 
651
                {
 
652
                        pNewSurfaceRotated = cairo_dock_create_blank_surface (
 
653
                                fImageHeight,
 
654
                                fImageWidth);
 
655
                        pCairoContext = cairo_create (pNewSurfaceRotated);
 
656
 
 
657
                        if (fRotationAngle < 0)
 
658
                        {
 
659
                                cairo_move_to (pCairoContext, fImageHeight, 0);
 
660
                                cairo_rotate (pCairoContext, fRotationAngle);
 
661
                                cairo_translate (pCairoContext, - fImageWidth, 0);
 
662
                        }
 
663
                        else
 
664
                        {
 
665
                                cairo_move_to (pCairoContext, 0, 0);
 
666
                                cairo_rotate (pCairoContext, fRotationAngle);
 
667
                                cairo_translate (pCairoContext, 0, - fImageHeight);
 
668
                        }
 
669
                }
 
670
                cairo_set_source_surface (pCairoContext, pSurface, 0, 0);
 
671
                cairo_paint (pCairoContext);
 
672
 
 
673
                cairo_destroy (pCairoContext);
 
674
                return pNewSurfaceRotated;
 
675
        }
 
676
        else
 
677
        {
 
678
                return NULL;
 
679
        }
 
680
}
 
681
 
 
682
 
 
683
static cairo_surface_t * cairo_dock_create_reflection_surface_horizontal (cairo_surface_t *pSurface, double fImageWidth, double fImageHeight, double fReflectSize, double fAlbedo, gboolean bDirectionUp)
 
684
{
 
685
        //g_print ("%s (%d)\n", __func__, bDirectionUp);
 
686
 
 
687
        //\_______________ On cree la surface d'une fraction hauteur de l'image originale.
 
688
        if (pSurface == NULL || fReflectSize == 0 || fAlbedo == 0)
 
689
                return NULL;
 
690
        cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
 
691
                fImageWidth,
 
692
                fReflectSize);
 
693
        cairo_t *pCairoContext = cairo_create (pNewSurface);
 
694
        
 
695
        cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
 
696
        cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
 
697
        
 
698
        //\_______________ On dessine l'image originale inversee.
 
699
        cairo_translate (pCairoContext, 0, fImageHeight);
 
700
        cairo_scale (pCairoContext, 1., -1.);
 
701
        cairo_set_source_surface (pCairoContext, pSurface, 0, (bDirectionUp ? 0 : fImageHeight - fReflectSize));
 
702
        
 
703
        //\_______________ On applique un degrade en transparence.
 
704
        cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0.,
 
705
                fImageHeight,
 
706
                0.,
 
707
                fImageHeight - fReflectSize);  // de haut en bas.
 
708
        g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
 
709
 
 
710
        cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE);
 
711
        cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
712
                0.,
 
713
                0.,
 
714
                0.,
 
715
                0.,
 
716
                (bDirectionUp ? fAlbedo : 0.));
 
717
        cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
718
                1.,
 
719
                0.,
 
720
                0.,
 
721
                0.,
 
722
                (bDirectionUp ? 0 : fAlbedo));
 
723
 
 
724
        cairo_mask (pCairoContext, pGradationPattern);
 
725
 
 
726
        cairo_pattern_destroy (pGradationPattern);
 
727
        cairo_destroy (pCairoContext);
 
728
        return pNewSurface;
 
729
}
 
730
 
 
731
static cairo_surface_t * cairo_dock_create_reflection_surface_vertical (cairo_surface_t *pSurface, double fImageWidth, double fImageHeight, double fReflectSize, double fAlbedo, gboolean bDirectionUp)
 
732
{
 
733
        g_return_val_if_fail (pSurface != NULL, NULL);
 
734
 
 
735
        //\_______________ On cree la surface d'une fraction hauteur de l'image originale.
 
736
        if (fReflectSize == 0 || fAlbedo == 0)
 
737
                return NULL;
 
738
        cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
 
739
                fReflectSize,
 
740
                fImageHeight);
 
741
        cairo_t *pCairoContext = cairo_create (pNewSurface);
 
742
 
 
743
        cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
 
744
        cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
 
745
        
 
746
        //\_______________ On dessine l'image originale inversee.
 
747
        cairo_translate (pCairoContext, fImageWidth, 0);
 
748
        cairo_scale (pCairoContext, -1., 1.);
 
749
        cairo_set_source_surface (pCairoContext, pSurface, (bDirectionUp ? 0. : fImageHeight - fReflectSize), 0.);
 
750
        
 
751
        //\_______________ On applique un degrade en transparence.
 
752
        cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0,
 
753
                0.,
 
754
                fImageHeight - fReflectSize,
 
755
                0.);  // de gauche a droite.
 
756
        g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
 
757
 
 
758
        cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_REPEAT);
 
759
        cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
760
                0.,
 
761
                0.,
 
762
                0.,
 
763
                0.,
 
764
                (bDirectionUp ? fAlbedo : 0.));
 
765
        cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
766
                1.,
 
767
                0.,
 
768
                0.,
 
769
                0.,
 
770
                (bDirectionUp ? 0. : fAlbedo));
 
771
 
 
772
        cairo_mask (pCairoContext, pGradationPattern);
 
773
 
 
774
        cairo_pattern_destroy (pGradationPattern);
 
775
        cairo_destroy (pCairoContext);
 
776
        return pNewSurface;
 
777
}
 
778
 
 
779
cairo_surface_t * cairo_dock_create_reflection_surface (cairo_surface_t *pSurface, double fImageWidth, double fImageHeight, double fReflectSize, double fAlbedo, gboolean bIsHorizontal, gboolean bDirectionUp)
 
780
{
 
781
        if (bIsHorizontal)
 
782
                return cairo_dock_create_reflection_surface_horizontal (pSurface, fImageWidth, fImageHeight, fReflectSize, fAlbedo, bDirectionUp);
 
783
        else
 
784
                return cairo_dock_create_reflection_surface_vertical (pSurface, fImageWidth, fImageHeight, fReflectSize, fAlbedo, bDirectionUp);
 
785
}
 
786
 
 
787
 
 
788
cairo_surface_t *cairo_dock_create_surface_from_text_full (const gchar *cText, CairoDockLabelDescription *pLabelDescription, double fMaxScale, int iMaxWidth, int *iTextWidth, int *iTextHeight, double *fTextXOffset, double *fTextYOffset)
 
789
{
 
790
        g_return_val_if_fail (cText != NULL && pLabelDescription != NULL, NULL);
 
791
        cairo_t *pSourceContext = _get_source_context ();
 
792
        g_return_val_if_fail (pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
 
793
        
 
794
        //\_________________ On ecrit le texte dans un calque Pango.
 
795
        PangoLayout *pLayout = pango_cairo_create_layout (pSourceContext);
 
796
        PangoRectangle ink, log;
 
797
        
 
798
        PangoFontDescription *pDesc = pango_font_description_new ();
 
799
        pango_font_description_set_absolute_size (pDesc, fMaxScale * pLabelDescription->iSize * PANGO_SCALE);
 
800
        pango_font_description_set_family_static (pDesc, pLabelDescription->cFont);
 
801
        pango_font_description_set_weight (pDesc, pLabelDescription->iWeight);
 
802
        pango_font_description_set_style (pDesc, pLabelDescription->iStyle);
 
803
        pango_layout_set_font_description (pLayout, pDesc);
 
804
        pango_font_description_free (pDesc);
 
805
        
 
806
        pango_layout_set_text (pLayout, "|", -1);  // donne la hauteur max des lettres.
 
807
        pango_layout_get_pixel_extents (pLayout, &ink, &log);
 
808
        int iMaxSize = ink.height;
 
809
        
 
810
        if (pLabelDescription->bUseMarkup)
 
811
                pango_layout_set_markup (pLayout, cText, -1);
 
812
        else
 
813
                pango_layout_set_text (pLayout, cText, -1);
 
814
        
 
815
        //\_________________ On cree une surface aux dimensions du texte.
 
816
        pango_layout_get_pixel_extents (pLayout, &ink, &log);
 
817
        
 
818
        gboolean bDrawBackground = (pLabelDescription->fBackgroundColor != NULL && pLabelDescription->fBackgroundColor[3] > 0);
 
819
        double fRadius = fMaxScale * MAX (pLabelDescription->iMargin, MIN (6, pLabelDescription->iSize/3));  // permet d'avoir un rayon meme si on n'a pas de marge.
 
820
        int iOutlineMargin = 2*pLabelDescription->iMargin + (pLabelDescription->bOutlined ? 2 : 0);  // outlined => +1 tout autour des lettres.
 
821
        double fZoomX = ((iMaxWidth != 0 && ink.width + iOutlineMargin > iMaxWidth) ? 1.*iMaxWidth / (ink.width + iOutlineMargin) : 1.);
 
822
        
 
823
        *iTextWidth = (ink.width + iOutlineMargin) * fZoomX;  // le texte + la marge de chaque cote.
 
824
        if (bDrawBackground)  // quand on trace le cadre, on evite qu'avec des petits textes genre "1" on obtienne un fond tout rond.
 
825
        {
 
826
                *iTextWidth = MAX (*iTextWidth, 2 * fRadius + 10);
 
827
                if (iMaxWidth != 0 && *iTextWidth > iMaxWidth)
 
828
                        *iTextWidth = iMaxWidth;
 
829
        }
 
830
        *iTextHeight = MAX (iMaxSize, ink.height) + iOutlineMargin + 0; // +1 car certaines polices "debordent".
 
831
        
 
832
        cairo_surface_t* pNewSurface = cairo_dock_create_blank_surface (
 
833
                *iTextWidth,
 
834
                *iTextHeight);
 
835
        cairo_t* pCairoContext = cairo_create (pNewSurface);
 
836
        
 
837
        //\_________________ On dessine le fond.
 
838
        if (bDrawBackground)  // non transparent.
 
839
        {
 
840
                cairo_save (pCairoContext);
 
841
                double fFrameWidth = *iTextWidth - 2 * fRadius;
 
842
                double fFrameHeight = *iTextHeight;
 
843
                cairo_dock_draw_rounded_rectangle (pCairoContext, fRadius, 0., fFrameWidth, fFrameHeight);
 
844
                cairo_set_source_rgba (pCairoContext, pLabelDescription->fBackgroundColor[0], pLabelDescription->fBackgroundColor[1], pLabelDescription->fBackgroundColor[2], pLabelDescription->fBackgroundColor[3]);
 
845
                cairo_fill (pCairoContext);
 
846
                cairo_restore(pCairoContext);
 
847
        }
 
848
        
 
849
        //g_print ("%s : ink = %d;%d\n", cText, (int) ink.x, (int) ink.y);
 
850
        int dx = (*iTextWidth - ink.width * fZoomX)/2;  // pour se centrer.
 
851
        int dy = (*iTextHeight - ink.height)/2;  // pour se centrer.
 
852
        cairo_translate (pCairoContext,
 
853
                -ink.x*fZoomX + dx,
 
854
                -ink.y + dy);  // meme remarque pour le +1.
 
855
        
 
856
        //\_________________ On dessine les contours du texte.
 
857
        if (pLabelDescription->bOutlined)
 
858
        {
 
859
                cairo_save (pCairoContext);
 
860
                if (fZoomX != 1)
 
861
                        cairo_scale (pCairoContext, fZoomX, 1.);
 
862
                cairo_push_group (pCairoContext);
 
863
                cairo_set_source_rgb (pCairoContext, 0.2, 0.2, 0.2);
 
864
                int i;
 
865
                for (i = 0; i < 2; i++)
 
866
                {
 
867
                        cairo_move_to (pCairoContext, 0, 2*i-1);
 
868
                        pango_cairo_show_layout (pCairoContext, pLayout);
 
869
                }
 
870
                for (i = 0; i < 2; i++)
 
871
                {
 
872
                        cairo_move_to (pCairoContext, 2*i-1, 0);
 
873
                        pango_cairo_show_layout (pCairoContext, pLayout);
 
874
                }
 
875
                cairo_pop_group_to_source (pCairoContext);
 
876
                //cairo_paint_with_alpha (pCairoContext, .75);
 
877
                cairo_paint (pCairoContext);
 
878
                cairo_restore(pCairoContext);
 
879
        }
 
880
 
 
881
        //\_________________ On remplit l'interieur du texte.
 
882
        cairo_pattern_t *pGradationPattern = NULL;
 
883
        if (pLabelDescription->fColorStart != pLabelDescription->fColorStop)
 
884
        {
 
885
                if (pLabelDescription->bVerticalPattern)
 
886
                        pGradationPattern = cairo_pattern_create_linear (0.,
 
887
                                ink.y + 0,  // meme remarque pour le +1.
 
888
                                0.,
 
889
                                ink.y + 0 + ink.height);
 
890
                else
 
891
                        pGradationPattern = cairo_pattern_create_linear (ink.x + 0,
 
892
                                0.,
 
893
                                ink.x + 0 + ink.width,
 
894
                                0.);
 
895
                g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
 
896
                cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE);
 
897
                cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
898
                        0.,
 
899
                        pLabelDescription->fColorStart[0],
 
900
                        pLabelDescription->fColorStart[1],
 
901
                        pLabelDescription->fColorStart[2],
 
902
                        1.);
 
903
                cairo_pattern_add_color_stop_rgba (pGradationPattern,
 
904
                        1.,
 
905
                        pLabelDescription->fColorStop[0],
 
906
                        pLabelDescription->fColorStop[1],
 
907
                        pLabelDescription->fColorStop[2],
 
908
                        1.);
 
909
                cairo_set_source (pCairoContext, pGradationPattern);
 
910
        }
 
911
        else
 
912
                cairo_set_source_rgb (pCairoContext, pLabelDescription->fColorStart[0], pLabelDescription->fColorStart[1], pLabelDescription->fColorStart[2]);
 
913
        cairo_move_to (pCairoContext, 0, 0);
 
914
        if (fZoomX != 1)
 
915
                cairo_scale (pCairoContext, fZoomX, 1.);
 
916
        //if (pLabelDescription->bOutlined)
 
917
        //      cairo_move_to (pCairoContext, 1,1);
 
918
        pango_cairo_show_layout (pCairoContext, pLayout);
 
919
        cairo_pattern_destroy (pGradationPattern);
 
920
        
 
921
        cairo_destroy (pCairoContext);
 
922
        
 
923
        /* set_device_offset is buggy, doesn't work for positive offsets. so we use explicit offsets... so unfortunate.
 
924
        cairo_surface_set_device_offset (pNewSurface,
 
925
                                         log.width / 2. - ink.x,
 
926
                                         log.height     - ink.y);*/
 
927
        if (fTextXOffset != NULL)
 
928
                *fTextXOffset = (log.width * fZoomX / 2. - ink.x) / fMaxScale;
 
929
        if (fTextYOffset != NULL)
 
930
                *fTextYOffset = - (pLabelDescription->iSize - (log.height - ink.y)) / fMaxScale ;  // en tenant compte de l'ecart du bas du texte.
 
931
        // *fTextYOffset = - (ink.y) / fMaxScale;  // pour tenir compte de l'ecart du bas du texte.
 
932
        
 
933
        *iTextWidth = *iTextWidth / fMaxScale;
 
934
        *iTextHeight = *iTextHeight / fMaxScale;
 
935
        
 
936
        g_object_unref (pLayout);
 
937
        return pNewSurface;
 
938
}
 
939
 
 
940
 
 
941
cairo_surface_t * cairo_dock_duplicate_surface (cairo_surface_t *pSurface, double fWidth, double fHeight, double fDesiredWidth, double fDesiredHeight)
 
942
{
 
943
        g_return_val_if_fail (pSurface != NULL, NULL);
 
944
 
 
945
        //\_______________ On cree la surface de la taille desiree.
 
946
        if (fDesiredWidth == 0)
 
947
                fDesiredWidth = fWidth;
 
948
        if (fDesiredHeight == 0)
 
949
                fDesiredHeight = fHeight;
 
950
        
 
951
        //g_print ("%s (%.2fx%.2f -> %.2fx%.2f)\n", __func__, fWidth, fHeight, fDesiredWidth, fDesiredHeight);
 
952
        cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
 
953
                fDesiredWidth,
 
954
                fDesiredHeight);
 
955
        cairo_t *pCairoContext = cairo_create (pNewSurface);
 
956
 
 
957
        //\_______________ On plaque la surface originale dessus.
 
958
        cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
 
959
        cairo_scale (pCairoContext,
 
960
                fDesiredWidth / fWidth,
 
961
                fDesiredHeight / fHeight);
 
962
        
 
963
        cairo_set_source_surface (pCairoContext, pSurface, 0., 0.);
 
964
        cairo_paint (pCairoContext);
 
965
        cairo_destroy (pCairoContext);
 
966
        
 
967
        return pNewSurface;
 
968
}