2
* This file is a part of the Cairo-Dock project
4
* Copyright : (C) see the 'copyright' file.
5
* E-mail : see the 'copyright' file.
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.
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/>.
22
#include <librsvg/rsvg.h>
23
#include <librsvg/rsvg-cairo.h>
24
#include <pango/pango.h>
26
#include "cairo-dock-log.h"
27
#include "cairo-dock-draw.h"
28
#include "cairo-dock-launcher-factory.h"
29
#include "cairo-dock-load.h"
30
#include "cairo-dock-surface-factory.h"
32
extern gboolean g_bUseOpenGL;
35
void cairo_dock_calculate_size_fill (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, gboolean bNoZoomUp, double *fZoomWidth, double *fZoomHeight)
37
if (iWidthConstraint != 0)
39
*fZoomWidth = 1. * iWidthConstraint / (*fImageWidth);
40
if (bNoZoomUp && *fZoomWidth > 1)
43
*fImageWidth = (double) iWidthConstraint;
47
if (iHeightConstraint != 0)
49
*fZoomHeight = 1. * iHeightConstraint / (*fImageHeight);
50
if (bNoZoomUp && *fZoomHeight > 1)
53
*fImageHeight = (double) iHeightConstraint;
59
void cairo_dock_calculate_size_constant_ratio (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, gboolean bNoZoomUp, double *fZoom)
61
if (iWidthConstraint != 0 && iHeightConstraint != 0)
62
*fZoom = MIN (iWidthConstraint / (*fImageWidth), iHeightConstraint / (*fImageHeight));
63
else if (iWidthConstraint != 0)
64
*fZoom = iWidthConstraint / (*fImageWidth);
65
else if (iHeightConstraint != 0)
66
*fZoom = iHeightConstraint / (*fImageHeight);
69
if (bNoZoomUp && *fZoom > 1)
71
*fImageWidth = (*fImageWidth) * (*fZoom);
72
*fImageHeight = (*fImageHeight) * (*fZoom);
77
void cairo_dock_calculate_constrainted_size (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, CairoDockLoadImageModifier iLoadingModifier, double *fZoomWidth, double *fZoomHeight)
79
gboolean bFillSpace = iLoadingModifier & CAIRO_DOCK_FILL_SPACE;
80
gboolean bKeepRatio = iLoadingModifier & CAIRO_DOCK_KEEP_RATIO;
81
gboolean bNoZoomUp = iLoadingModifier & CAIRO_DOCK_DONT_ZOOM_IN;
82
gint iOrientation = iLoadingModifier & CAIRO_DOCK_ORIENTATION_MASK;
83
if (iOrientation > CAIRO_DOCK_ORIENTATION_VFLIP) // inversion x/y
85
double tmp = *fImageWidth;
86
*fImageWidth = *fImageHeight;
91
cairo_dock_calculate_size_constant_ratio (fImageWidth,
97
*fZoomHeight = *fZoomWidth;
100
//double fUsefulWidth = *fImageWidth;
101
//double fUsefulHeight = *fImageHeight;
102
if (iWidthConstraint != 0)
103
*fImageWidth = iWidthConstraint;
104
if (iHeightConstraint != 0)
105
*fImageHeight = iHeightConstraint;
110
cairo_dock_calculate_size_fill (fImageWidth,
120
cairo_surface_t *_cairo_dock_create_blank_surface (cairo_t *pSourceContext, int iWidth, int iHeight)
122
if (pSourceContext != NULL && ! g_bUseOpenGL)
123
return cairo_surface_create_similar (cairo_get_target (pSourceContext),
124
CAIRO_CONTENT_COLOR_ALPHA,
128
return cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
133
static inline void _apply_orientation_and_scale (cairo_t *pCairoContext, CairoDockLoadImageModifier iLoadingModifier, double fImageWidth, double fImageHeight, double fZoomX, double fZoomY, double fUsefulWidth, double fUsefulheight)
135
int iOrientation = iLoadingModifier & CAIRO_DOCK_ORIENTATION_MASK;
137
cairo_translate (pCairoContext,
140
cairo_scale (pCairoContext,
143
switch (iOrientation)
145
case CAIRO_DOCK_ORIENTATION_HFLIP :
146
g_print ("orientation : HFLIP\n");
147
cairo_scale (pCairoContext, -1., 1.);
149
case CAIRO_DOCK_ORIENTATION_ROT_180 :
150
g_print ("orientation : ROT_180\n");
151
cairo_rotate (pCairoContext, G_PI);
153
case CAIRO_DOCK_ORIENTATION_VFLIP :
154
g_print ("orientation : VFLIP\n");
155
cairo_scale (pCairoContext, 1., -1.);
157
case CAIRO_DOCK_ORIENTATION_ROT_90_HFLIP :
158
g_print ("orientation : ROT_90_HFLIP\n");
159
cairo_scale (pCairoContext, -1., 1.);
160
cairo_rotate (pCairoContext, + G_PI/2);
162
case CAIRO_DOCK_ORIENTATION_ROT_90 :
163
g_print ("orientation : ROT_90\n");
164
cairo_rotate (pCairoContext, + G_PI/2);
166
case CAIRO_DOCK_ORIENTATION_ROT_90_VFLIP :
167
g_print ("orientation : ROT_90_VFLIP\n");
168
cairo_scale (pCairoContext, 1., -1.);
169
cairo_rotate (pCairoContext, + G_PI/2);
171
case CAIRO_DOCK_ORIENTATION_ROT_270 :
172
g_print ("orientation : ROT_270\n");
173
cairo_rotate (pCairoContext, - G_PI/2);
178
if (iOrientation < CAIRO_DOCK_ORIENTATION_ROT_90_HFLIP)
179
cairo_translate (pCairoContext,
180
- fUsefulWidth/2/fZoomX,
181
- fUsefulheight/2/fZoomY);
183
cairo_translate (pCairoContext,
184
- fUsefulheight/2/fZoomY,
185
- fUsefulWidth/2/fZoomX);
189
cairo_surface_t *cairo_dock_create_surface_from_xicon_buffer (gulong *pXIconBuffer, int iBufferNbElements, cairo_t *pSourceContext, double fConstraintWidth, double fConstraintHeight, double fMaxScale, double *fWidth, double *fHeight)
191
g_return_val_if_fail (cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
193
//\____________________ On recupere la plus grosse des icones presentes dans le tampon (meilleur rendu).
194
int iIndex = 0, iBestIndex = 0;
195
while (iIndex + 2 < iBufferNbElements)
197
if (pXIconBuffer[iIndex] > pXIconBuffer[iBestIndex])
199
iIndex += 2 + pXIconBuffer[iIndex] * pXIconBuffer[iIndex+1];
202
//\____________________ On pre-multiplie chaque composante par le alpha (necessaire pour libcairo).
203
int w = pXIconBuffer[iBestIndex];
204
int h = pXIconBuffer[iBestIndex+1];
206
//g_print ("%s (%dx%d)\n", __func__, w, h);
209
if (iBestIndex + n > iBufferNbElements) // precaution au cas ou le nombre d'elements dans le buffer serait incorrect.
211
cd_warning ("This icon is broken !\nThis means that one of the current applications has sent a buggy icon to X.");
214
gint pixel, alpha, red, green, blue;
216
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 ! :-)
217
for (i = 0; i < n; i ++)
219
pixel = (gint) pXIconBuffer[iBestIndex+i];
220
alpha = (pixel & 0xFF000000) >> 24;
221
red = (pixel & 0x00FF0000) >> 16;
222
green = (pixel & 0x0000FF00) >> 8;
223
blue = (pixel & 0x000000FF);
224
fAlphaFactor = (float) alpha / 255;
226
green *= fAlphaFactor;
227
blue *= fAlphaFactor;
228
pPixelBuffer[i] = (pixel & 0xFF000000) + (red << 16) + (green << 8) + blue;
231
//\____________________ On cree la surface a partir du tampon.
232
int iStride = w * sizeof (gint); // nbre d'octets entre le debut de 2 lignes.
233
cairo_surface_t *surface_ini = cairo_image_surface_create_for_data ((guchar *)pPixelBuffer,
239
*fWidth = (double) w;
240
*fHeight = (double) h;
241
double fIconWidthSaturationFactor = 1., fIconHeightSaturationFactor = 1.;
242
cairo_dock_calculate_constrainted_size (fWidth,
246
CAIRO_DOCK_KEEP_RATIO | CAIRO_DOCK_FILL_SPACE,
247
&fIconWidthSaturationFactor,
248
&fIconHeightSaturationFactor);
250
cairo_surface_t *pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
251
ceil (*fWidth * fMaxScale),
252
ceil (*fHeight * fMaxScale));
253
cairo_t *pCairoContext = cairo_create (pNewSurface);
255
double fUsefulWidth = w * fIconWidthSaturationFactor; // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
256
double fUsefulHeight = h * fIconHeightSaturationFactor;
257
_apply_orientation_and_scale (pCairoContext,
258
CAIRO_DOCK_KEEP_RATIO | CAIRO_DOCK_FILL_SPACE,
259
ceil ((*fWidth) * fMaxScale), ceil ((*fHeight) * fMaxScale),
260
fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
261
fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
262
cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
263
cairo_paint (pCairoContext);
265
cairo_surface_destroy (surface_ini);
266
cairo_destroy (pCairoContext);
272
cairo_surface_t *cairo_dock_create_surface_from_pixbuf (GdkPixbuf *pixbuf, cairo_t *pSourceContext, double fMaxScale, int iWidthConstraint, int iHeightConstraint, CairoDockLoadImageModifier iLoadingModifier, double *fImageWidth, double *fImageHeight, double *fZoomX, double *fZoomY)
274
*fImageWidth = gdk_pixbuf_get_width (pixbuf);
275
*fImageHeight = gdk_pixbuf_get_height (pixbuf);
276
double fIconWidthSaturationFactor = 1., fIconHeightSaturationFactor = 1.;
277
cairo_dock_calculate_constrainted_size (fImageWidth,
282
&fIconWidthSaturationFactor,
283
&fIconHeightSaturationFactor);
285
GdkPixbuf *pPixbufWithAlpha = pixbuf;
286
if (! gdk_pixbuf_get_has_alpha (pixbuf)) // on lui rajoute un canal alpha s'il n'en a pas.
288
//g_print (" ajout d'un canal alpha\n");
289
pPixbufWithAlpha = gdk_pixbuf_add_alpha (pixbuf, FALSE, 255, 255, 255); // TRUE <=> les pixels blancs deviennent transparents.
292
//\____________________ On pre-multiplie chaque composante par le alpha (necessaire pour libcairo).
293
int iNbChannels = gdk_pixbuf_get_n_channels (pPixbufWithAlpha);
294
int iRowstride = gdk_pixbuf_get_rowstride (pPixbufWithAlpha);
295
int w = gdk_pixbuf_get_width (pPixbufWithAlpha);
296
guchar *p, *pixels = gdk_pixbuf_get_pixels (pPixbufWithAlpha);
297
int h = gdk_pixbuf_get_height (pPixbufWithAlpha);
299
int red, green, blue;
301
for (y = 0; y < h; y ++)
303
for (x = 0; x < w; x ++)
305
p = pixels + y * iRowstride + x * iNbChannels;
306
fAlphaFactor = (float) p[3] / 255;
307
red = p[0] * fAlphaFactor;
308
green = p[1] * fAlphaFactor;
309
blue = p[2] * fAlphaFactor;
316
cairo_surface_t *surface_ini = cairo_image_surface_create_for_data (pixels,
322
cairo_surface_t *pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
323
ceil ((*fImageWidth) * fMaxScale),
324
ceil ((*fImageHeight) * fMaxScale));
325
cairo_t *pCairoContext = cairo_create (pNewSurface);
327
double fUsefulWidth = w * fIconWidthSaturationFactor; // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
328
double fUsefulHeight = h * fIconHeightSaturationFactor;
329
_apply_orientation_and_scale (pCairoContext,
331
ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
332
fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
333
fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
335
cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
336
cairo_paint (pCairoContext);
338
cairo_destroy (pCairoContext);
339
cairo_surface_destroy (surface_ini);
340
if (pPixbufWithAlpha != pixbuf)
341
g_object_unref (pPixbufWithAlpha);
344
*fZoomX = fIconWidthSaturationFactor;
346
*fZoomY = fIconHeightSaturationFactor;
352
cairo_surface_t *cairo_dock_create_surface_from_image (const gchar *cImagePath, cairo_t* pSourceContext, double fMaxScale, int iWidthConstraint, int iHeightConstraint, CairoDockLoadImageModifier iLoadingModifier, double *fImageWidth, double *fImageHeight, double *fZoomX, double *fZoomY)
354
//g_print ("%s (%s, %dx%dx%.2f, %d)\n", __func__, cImagePath, iWidthConstraint, iHeightConstraint, fMaxScale, iLoadingModifier);
355
g_return_val_if_fail (cImagePath != NULL && pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
356
GError *erreur = NULL;
357
RsvgDimensionData rsvg_dimension_data;
358
RsvgHandle *rsvg_handle = NULL;
359
cairo_surface_t* surface_ini;
360
cairo_surface_t* pNewSurface = NULL;
361
cairo_t* pCairoContext = NULL;
362
double fIconWidthSaturationFactor = 1.;
363
double fIconHeightSaturationFactor = 1.;
365
//\_______________ On cherche a determiner le type de l'image. En effet, les SVG et les PNG sont charges differemment des autres.
366
gboolean bIsSVG = FALSE, bIsPNG = FALSE, bIsXPM = FALSE;
367
FILE *fd = fopen (cImagePath, "r");
371
if (fgets (buffer, 7, fd) != NULL)
373
if (strncmp (buffer+2, "xml", 3) == 0)
375
else if (strncmp (buffer+1, "PNG", 3) == 0)
377
else if (strncmp (buffer+3, "XPM", 3) == 0)
379
//cd_debug (" format : %d;%d;%d", bIsSVG, bIsPNG, bIsXPM);
383
if (! bIsSVG && ! bIsPNG && ! bIsXPM) // sinon en desespoir de cause on se base sur l'extension.
385
//cd_debug (" on se base sur l'extension en desespoir de cause.");
386
if (g_str_has_suffix (cImagePath, ".svg"))
388
else if (g_str_has_suffix (cImagePath, ".png"))
392
bIsPNG = FALSE; /// libcairo 1.6 - 1.8 est bugguee !!!...
395
rsvg_handle = rsvg_handle_new_from_file (cImagePath, &erreur);
398
cd_warning (erreur->message);
399
g_error_free (erreur);
404
g_return_val_if_fail (rsvg_handle != NULL, NULL);
405
rsvg_handle_get_dimensions (rsvg_handle, &rsvg_dimension_data);
406
int w = rsvg_dimension_data.width;
407
int h = rsvg_dimension_data.height;
408
*fImageWidth = (gdouble) w;
409
*fImageHeight = (gdouble) h;
410
//g_print ("%.2fx%.2f\n", *fImageWidth, *fImageHeight);
411
cairo_dock_calculate_constrainted_size (fImageWidth,
416
&fIconWidthSaturationFactor,
417
&fIconHeightSaturationFactor);
419
pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
420
ceil ((*fImageWidth) * fMaxScale),
421
ceil ((*fImageHeight) * fMaxScale));
423
pCairoContext = cairo_create (pNewSurface);
424
double fUsefulWidth = w * fIconWidthSaturationFactor; // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
425
double fUsefulHeight = h * fIconHeightSaturationFactor;
426
_apply_orientation_and_scale (pCairoContext,
428
ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
429
fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
430
fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
432
rsvg_handle_render_cairo (rsvg_handle, pCairoContext);
433
cairo_destroy (pCairoContext);
434
g_object_unref (rsvg_handle);
439
surface_ini = cairo_image_surface_create_from_png (cImagePath); // cree un fond noir :-(
440
if (cairo_surface_status (surface_ini) == CAIRO_STATUS_SUCCESS)
442
int w = cairo_image_surface_get_width (surface_ini);
443
int h = cairo_image_surface_get_height (surface_ini);
444
*fImageWidth = (double) w;
445
*fImageHeight = (double) h;
446
cairo_dock_calculate_constrainted_size (fImageWidth,
451
&fIconWidthSaturationFactor,
452
&fIconHeightSaturationFactor);
454
pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
455
ceil ((*fImageWidth) * fMaxScale),
456
ceil ((*fImageHeight) * fMaxScale));
457
pCairoContext = cairo_create (pNewSurface);
458
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_SOURCE);
459
cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
460
cairo_paint (pCairoContext);
461
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
463
double fUsefulWidth = w * fIconWidthSaturationFactor; // a part dans le cas fill && keep ratio, c'est la meme chose que fImageWidth et fImageHeight.
464
double fUsefulHeight = h * fIconHeightSaturationFactor;
465
_apply_orientation_and_scale (pCairoContext,
467
ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
468
fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
469
fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
471
cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
472
cairo_paint (pCairoContext);
473
cairo_destroy (pCairoContext);
475
cairo_surface_destroy (surface_ini);
477
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.
479
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (cImagePath, &erreur); // semble se baser sur l'extension pour definir le type !
482
cd_warning (erreur->message);
483
g_error_free (erreur);
486
pNewSurface = cairo_dock_create_surface_from_pixbuf (pixbuf,
494
&fIconWidthSaturationFactor,
495
&fIconHeightSaturationFactor);
496
g_object_unref (pixbuf);
501
*fZoomX = fIconWidthSaturationFactor;
503
*fZoomY = fIconHeightSaturationFactor;
508
cairo_surface_t *cairo_dock_create_surface_from_image_simple (const gchar *cImageFile, cairo_t* pSourceContext, double fImageWidth, double fImageHeight)
510
g_return_val_if_fail (cImageFile != NULL, NULL);
511
double fImageWidth_ = fImageWidth, fImageHeight_ = fImageHeight;
513
if (*cImageFile == '/')
514
cImagePath = (gchar *)cImageFile;
516
cImagePath = cairo_dock_generate_file_path (cImageFile);
518
cairo_surface_t *pSurface = cairo_dock_create_surface_from_image (cImagePath,
523
CAIRO_DOCK_FILL_SPACE,
528
if (cImagePath != cImageFile)
533
cairo_surface_t *cairo_dock_create_surface_from_icon (const gchar *cImageFile, cairo_t* pSourceContext, double fImageWidth, double fImageHeight)
535
g_return_val_if_fail (cImageFile != NULL, NULL);
536
double fImageWidth_ = fImageWidth, fImageHeight_ = fImageHeight;
538
if (*cImageFile == '/')
539
cIconPath = (gchar *)cImageFile;
541
cIconPath = cairo_dock_search_icon_s_path (cImageFile);
543
cairo_surface_t *pSurface = cairo_dock_create_surface_from_image (cIconPath,
548
CAIRO_DOCK_FILL_SPACE,
553
if (cIconPath != cImageFile)
558
cairo_surface_t *cairo_dock_create_surface_from_pattern (const gchar *cImageFile, cairo_t *pSourceContext, double fImageWidth, double fImageHeight, double fAlpha)
560
g_return_val_if_fail (cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
561
cairo_surface_t *pNewSurface = NULL;
563
if (cImageFile != NULL)
565
gchar *cImagePath = cairo_dock_generate_file_path (cImageFile);
566
double fImageWidth, fImageHeight;
567
cairo_surface_t *pPatternSurface = cairo_dock_create_surface_from_image (cImagePath,
570
0, // pas de contrainte sur
571
0, // la taille du motif initialement.
572
CAIRO_DOCK_FILL_SPACE,
577
if (pPatternSurface == NULL)
580
pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
583
cairo_t *pCairoContext = cairo_create (pNewSurface);
585
cairo_pattern_t* pPattern = cairo_pattern_create_for_surface (pPatternSurface);
586
g_return_val_if_fail (cairo_pattern_status (pPattern) == CAIRO_STATUS_SUCCESS, NULL);
587
cairo_pattern_set_extend (pPattern, CAIRO_EXTEND_REPEAT);
589
cairo_set_source (pCairoContext, pPattern);
590
cairo_paint_with_alpha (pCairoContext, fAlpha);
591
cairo_destroy (pCairoContext);
592
cairo_pattern_destroy (pPattern);
594
cairo_surface_destroy (pPatternSurface);
602
cairo_surface_t * cairo_dock_rotate_surface (cairo_surface_t *pSurface, cairo_t *pSourceContext, double fImageWidth, double fImageHeight, double fRotationAngle)
604
g_return_val_if_fail (pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS && pSurface != NULL, NULL);
605
if (fRotationAngle != 0)
607
cairo_surface_t *pNewSurfaceRotated;
608
cairo_t *pCairoContext;
609
if (fabs (fRotationAngle) > G_PI / 2)
611
pNewSurfaceRotated = _cairo_dock_create_blank_surface (pSourceContext,
614
pCairoContext = cairo_create (pNewSurfaceRotated);
616
cairo_translate (pCairoContext, 0, fImageHeight);
617
cairo_scale (pCairoContext, 1, -1);
621
pNewSurfaceRotated = _cairo_dock_create_blank_surface (pSourceContext,
624
pCairoContext = cairo_create (pNewSurfaceRotated);
626
if (fRotationAngle < 0)
628
cairo_move_to (pCairoContext, fImageHeight, 0);
629
cairo_rotate (pCairoContext, fRotationAngle);
630
cairo_translate (pCairoContext, - fImageWidth, 0);
634
cairo_move_to (pCairoContext, 0, 0);
635
cairo_rotate (pCairoContext, fRotationAngle);
636
cairo_translate (pCairoContext, 0, - fImageHeight);
639
cairo_set_source_surface (pCairoContext, pSurface, 0, 0);
640
cairo_paint (pCairoContext);
642
cairo_destroy (pCairoContext);
643
return pNewSurfaceRotated;
652
static cairo_surface_t * cairo_dock_create_reflection_surface_horizontal (cairo_surface_t *pSurface, cairo_t *pSourceContext, double fImageWidth, double fImageHeight, double fReflectSize, double fAlbedo, gboolean bDirectionUp)
654
g_return_val_if_fail (pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
655
//g_print ("%s (%d)\n", __func__, bDirectionUp);
657
//\_______________ On cree la surface d'une fraction hauteur de l'image originale.
658
if (pSurface == NULL || fReflectSize == 0 || fAlbedo == 0)
660
cairo_surface_t *pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
663
cairo_t *pCairoContext = cairo_create (pNewSurface);
665
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
666
cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
668
//\_______________ On dessine l'image originale inversee.
669
cairo_translate (pCairoContext, 0, fImageHeight);
670
cairo_scale (pCairoContext, 1., -1.);
671
cairo_set_source_surface (pCairoContext, pSurface, 0, (bDirectionUp ? 0 : fImageHeight - fReflectSize));
673
//\_______________ On applique un degrade en transparence.
674
/**cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0.,
677
fReflectHeight); // de haut en bas.*/
678
cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0.,
681
fImageHeight - fReflectSize); // de haut en bas.
682
g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
684
cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE);
685
cairo_pattern_add_color_stop_rgba (pGradationPattern,
690
(bDirectionUp ? fAlbedo : 0.));
691
cairo_pattern_add_color_stop_rgba (pGradationPattern,
696
(bDirectionUp ? 0 : fAlbedo));
698
cairo_mask (pCairoContext, pGradationPattern);
700
cairo_pattern_destroy (pGradationPattern);
701
cairo_destroy (pCairoContext);
705
static cairo_surface_t * cairo_dock_create_reflection_surface_vertical (cairo_surface_t *pSurface, cairo_t *pSourceContext, double fImageWidth, double fImageHeight, double fReflectSize, double fAlbedo, gboolean bDirectionUp)
707
g_return_val_if_fail (pSurface != NULL && pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
709
//\_______________ On cree la surface d'une fraction hauteur de l'image originale.
710
if (fReflectSize == 0 || fAlbedo == 0)
712
cairo_surface_t *pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
715
cairo_t *pCairoContext = cairo_create (pNewSurface);
717
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
718
cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
720
//\_______________ On dessine l'image originale inversee.
721
cairo_translate (pCairoContext, fImageWidth, 0);
722
cairo_scale (pCairoContext, -1., 1.);
723
cairo_set_source_surface (pCairoContext, pSurface, (bDirectionUp ? 0. : fImageHeight - fReflectSize), 0.);
725
//\_______________ On applique un degrade en transparence.
726
cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0,
728
fImageHeight - fReflectSize,
729
0.); // de gauche a droite.
730
g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
732
cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_REPEAT);
733
cairo_pattern_add_color_stop_rgba (pGradationPattern,
738
(bDirectionUp ? fAlbedo : 0.));
739
cairo_pattern_add_color_stop_rgba (pGradationPattern,
744
(bDirectionUp ? 0. : fAlbedo));
746
cairo_mask (pCairoContext, pGradationPattern);
748
cairo_pattern_destroy (pGradationPattern);
749
cairo_destroy (pCairoContext);
753
cairo_surface_t * cairo_dock_create_reflection_surface (cairo_surface_t *pSurface, cairo_t *pSourceContext, double fImageWidth, double fImageHeight, double fReflectSize, double fAlbedo, gboolean bIsHorizontal, gboolean bDirectionUp)
756
return cairo_dock_create_reflection_surface_horizontal (pSurface, pSourceContext, fImageWidth, fImageHeight, fReflectSize, fAlbedo, bDirectionUp);
758
return cairo_dock_create_reflection_surface_vertical (pSurface, pSourceContext, fImageWidth, fImageHeight, fReflectSize, fAlbedo, bDirectionUp);
762
cairo_surface_t *cairo_dock_create_surface_from_text_full (const gchar *cText, cairo_t* pSourceContext, CairoDockLabelDescription *pLabelDescription, double fMaxScale, int iMaxWidth, int *iTextWidth, int *iTextHeight, double *fTextXOffset, double *fTextYOffset)
764
g_return_val_if_fail (cText != NULL && pLabelDescription != NULL && pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
766
//\_________________ On ecrit le texte dans un calque Pango.
767
PangoLayout *pLayout = pango_cairo_create_layout (pSourceContext);
769
PangoFontDescription *pDesc = pango_font_description_new ();
770
pango_font_description_set_absolute_size (pDesc, fMaxScale * pLabelDescription->iSize * PANGO_SCALE);
771
pango_font_description_set_family_static (pDesc, pLabelDescription->cFont);
772
pango_font_description_set_weight (pDesc, pLabelDescription->iWeight);
773
pango_font_description_set_style (pDesc, pLabelDescription->iStyle);
774
pango_layout_set_font_description (pLayout, pDesc);
775
pango_font_description_free (pDesc);
777
pango_layout_set_text (pLayout, cText, -1);
779
//\_________________ On cree une surface aux dimensions du texte.
780
PangoRectangle ink, log;
781
pango_layout_get_pixel_extents (pLayout, &ink, &log);
783
int iOutlineMargin = 2*pLabelDescription->iMargin + (pLabelDescription->bOutlined ? 2 : 0); // outlined => +1 tout autour des lettres.
784
double fZoomX = ((iMaxWidth != 0 && ink.width + iOutlineMargin > iMaxWidth) ? 1.*iMaxWidth / (ink.width + iOutlineMargin) : 1.);
786
*iTextWidth = (ink.width + iOutlineMargin) * fZoomX;
787
*iTextHeight = ink.height + iOutlineMargin + 0; // +1 car certaines polices "debordent".
788
//Test du zoom en W ET H *iTextHeight = (ink.height + 2 + 1) * fZoom;
790
cairo_surface_t* pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
793
cairo_t* pCairoContext = cairo_create (pNewSurface);
795
//\_________________ On dessine le fond.
796
if (pLabelDescription->fBackgroundColor != NULL && pLabelDescription->fBackgroundColor[3] > 0) // non transparent.
798
cairo_save (pCairoContext);
799
double fRadius = fMaxScale * MAX (pLabelDescription->iMargin, MIN (6, pLabelDescription->iSize/3)); // permet d'avoir un rayon meme si on n'a pas de marge.
800
double fLineWidth = 0.;
801
double fFrameWidth = *iTextWidth - 2 * fRadius - fLineWidth;
802
double fFrameHeight = *iTextHeight - fLineWidth;
803
cairo_dock_draw_rounded_rectangle (pCairoContext, fRadius, fLineWidth, fFrameWidth, fFrameHeight);
804
cairo_set_source_rgba (pCairoContext, pLabelDescription->fBackgroundColor[0], pLabelDescription->fBackgroundColor[1], pLabelDescription->fBackgroundColor[2], pLabelDescription->fBackgroundColor[3]);
805
cairo_fill (pCairoContext);
806
cairo_restore(pCairoContext);
809
//g_print ("%s : ink = %d;%d\n", cText, (int) ink.x, (int) ink.y);
810
cairo_translate (pCairoContext, -ink.x*fZoomX + iOutlineMargin/2, -ink.y + iOutlineMargin/2); // meme remarque pour le +1.
812
//\_________________ On dessine les contours du texte.
813
if (pLabelDescription->bOutlined)
815
cairo_save (pCairoContext);
817
cairo_scale (pCairoContext, fZoomX, 1.);
818
cairo_push_group (pCairoContext);
819
cairo_set_source_rgb (pCairoContext, 0.2, 0.2, 0.2);
821
for (i = 0; i < 2; i++)
823
cairo_move_to (pCairoContext, 0, 2*i-1);
824
pango_cairo_show_layout (pCairoContext, pLayout);
826
for (i = 0; i < 2; i++)
828
cairo_move_to (pCairoContext, 2*i-1, 0);
829
pango_cairo_show_layout (pCairoContext, pLayout);
831
cairo_pop_group_to_source (pCairoContext);
832
//cairo_paint_with_alpha (pCairoContext, .75);
833
cairo_paint (pCairoContext);
834
cairo_restore(pCairoContext);
837
//\_________________ On remplit l'interieur du texte.
838
cairo_pattern_t *pGradationPattern = NULL;
839
if (pLabelDescription->fColorStart != pLabelDescription->fColorStop)
841
if (pLabelDescription->bVerticalPattern)
842
pGradationPattern = cairo_pattern_create_linear (0.,
843
ink.y + 0, // meme remarque pour le +1.
845
ink.y + 0 + ink.height);
847
pGradationPattern = cairo_pattern_create_linear (ink.x + 0,
849
ink.x + 0 + ink.width,
851
g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
852
cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE);
853
cairo_pattern_add_color_stop_rgba (pGradationPattern,
855
pLabelDescription->fColorStart[0],
856
pLabelDescription->fColorStart[1],
857
pLabelDescription->fColorStart[2],
859
cairo_pattern_add_color_stop_rgba (pGradationPattern,
861
pLabelDescription->fColorStop[0],
862
pLabelDescription->fColorStop[1],
863
pLabelDescription->fColorStop[2],
865
cairo_set_source (pCairoContext, pGradationPattern);
868
cairo_set_source_rgb (pCairoContext, pLabelDescription->fColorStart[0], pLabelDescription->fColorStart[1], pLabelDescription->fColorStart[2]);
869
cairo_move_to (pCairoContext, 0, 0);
871
cairo_scale (pCairoContext, fZoomX, 1.);
872
//if (pLabelDescription->bOutlined)
873
// cairo_move_to (pCairoContext, 1,1);
874
pango_cairo_show_layout (pCairoContext, pLayout);
875
cairo_pattern_destroy (pGradationPattern);
877
cairo_destroy (pCairoContext);
879
/* set_device_offset is buggy, doesn't work for positive offsets. so we use explicit offsets... so unfortunate.
880
cairo_surface_set_device_offset (pNewSurface,
881
log.width / 2. - ink.x,
882
log.height - ink.y);*/
883
if (fTextXOffset != NULL)
884
*fTextXOffset = (log.width * fZoomX / 2. - ink.x) / fMaxScale;
885
if (fTextYOffset != NULL)
886
*fTextYOffset = - (pLabelDescription->iSize - (log.height - ink.y)) / fMaxScale ; // en tenant compte de l'ecart du bas du texte.
887
// *fTextYOffset = - (ink.y) / fMaxScale; // pour tenir compte de l'ecart du bas du texte.
889
*iTextWidth = *iTextWidth / fMaxScale;
890
*iTextHeight = *iTextHeight / fMaxScale;
892
g_object_unref (pLayout);
897
cairo_surface_t * cairo_dock_duplicate_surface (cairo_surface_t *pSurface, cairo_t *pSourceContext, double fWidth, double fHeight, double fDesiredWidth, double fDesiredHeight)
899
g_return_val_if_fail (pSurface != NULL && pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
901
//\_______________ On cree la surface de la taille desiree.
902
if (fDesiredWidth == 0)
903
fDesiredWidth = fWidth;
904
if (fDesiredHeight == 0)
905
fDesiredHeight = fHeight;
907
//g_print ("%s (%.2fx%.2f -> %.2fx%.2f)\n", __func__, fWidth, fHeight, fDesiredWidth, fDesiredHeight);
908
cairo_surface_t *pNewSurface = _cairo_dock_create_blank_surface (pSourceContext,
911
cairo_t *pCairoContext = cairo_create (pNewSurface);
913
//\_______________ On plaque la surface originale dessus.
914
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
915
cairo_scale (pCairoContext,
916
fDesiredWidth / fWidth,
917
fDesiredHeight / fHeight);
919
cairo_set_source_surface (pCairoContext, pSurface, 0., 0.);
920
cairo_paint (pCairoContext);
921
cairo_destroy (pCairoContext);