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-manager.h"
29
#include "cairo-dock-container.h"
30
#include "cairo-dock-load.h"
31
#include "cairo-dock-surface-factory.h"
33
extern CairoContainer *g_pPrimaryContainer;
34
extern gboolean g_bUseOpenGL;
36
static cairo_t *s_pSourceContext = NULL;
39
void cairo_dock_calculate_size_fill (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, gboolean bNoZoomUp, double *fZoomWidth, double *fZoomHeight)
41
if (iWidthConstraint != 0)
43
*fZoomWidth = 1. * iWidthConstraint / (*fImageWidth);
44
if (bNoZoomUp && *fZoomWidth > 1)
47
*fImageWidth = (double) iWidthConstraint;
51
if (iHeightConstraint != 0)
53
*fZoomHeight = 1. * iHeightConstraint / (*fImageHeight);
54
if (bNoZoomUp && *fZoomHeight > 1)
57
*fImageHeight = (double) iHeightConstraint;
63
void cairo_dock_calculate_size_constant_ratio (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, gboolean bNoZoomUp, double *fZoom)
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);
73
if (bNoZoomUp && *fZoom > 1)
75
*fImageWidth = (*fImageWidth) * (*fZoom);
76
*fImageHeight = (*fImageHeight) * (*fZoom);
81
void cairo_dock_calculate_constrainted_size (double *fImageWidth, double *fImageHeight, int iWidthConstraint, int iHeightConstraint, CairoDockLoadImageModifier iLoadingModifier, double *fZoomWidth, double *fZoomHeight)
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
89
double tmp = *fImageWidth;
90
*fImageWidth = *fImageHeight;
95
cairo_dock_calculate_size_constant_ratio (fImageWidth,
101
*fZoomHeight = *fZoomWidth;
104
//double fUsefulWidth = *fImageWidth;
105
//double fUsefulHeight = *fImageHeight;
106
if (iWidthConstraint != 0)
107
*fImageWidth = iWidthConstraint;
108
if (iHeightConstraint != 0)
109
*fImageHeight = iHeightConstraint;
114
cairo_dock_calculate_size_fill (fImageWidth,
125
#define _get_source_context(...) \
127
if (s_pSourceContext == NULL) {\
128
if (g_pPrimaryContainer != NULL)\
129
s_pSourceContext = cairo_dock_create_drawing_context_generic (g_pPrimaryContainer); }\
131
#define _destroy_source_context(...) do {\
132
if (s_pSourceContext != NULL) {\
133
cairo_destroy (s_pSourceContext);\
134
s_pSourceContext = NULL; } } while (0)
136
void cairo_dock_reset_source_context (void)
138
_destroy_source_context ();
141
cairo_surface_t *cairo_dock_create_blank_surface (int iWidth, int iHeight)
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,
150
return cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
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)
157
int iOrientation = iLoadingModifier & CAIRO_DOCK_ORIENTATION_MASK;
159
cairo_translate (pCairoContext,
162
cairo_scale (pCairoContext,
165
switch (iOrientation)
167
case CAIRO_DOCK_ORIENTATION_HFLIP :
168
cd_debug ("orientation : HFLIP");
169
cairo_scale (pCairoContext, -1., 1.);
171
case CAIRO_DOCK_ORIENTATION_ROT_180 :
172
cd_debug ("orientation : ROT_180");
173
cairo_rotate (pCairoContext, G_PI);
175
case CAIRO_DOCK_ORIENTATION_VFLIP :
176
cd_debug ("orientation : VFLIP");
177
cairo_scale (pCairoContext, 1., -1.);
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);
184
case CAIRO_DOCK_ORIENTATION_ROT_90 :
185
cd_debug ("orientation : ROT_90");
186
cairo_rotate (pCairoContext, + G_PI/2);
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);
193
case CAIRO_DOCK_ORIENTATION_ROT_270 :
194
cd_debug ("orientation : ROT_270");
195
cairo_rotate (pCairoContext, - G_PI/2);
200
if (iOrientation < CAIRO_DOCK_ORIENTATION_ROT_90_HFLIP)
201
cairo_translate (pCairoContext,
202
- fUsefulWidth/2/fZoomX,
203
- fUsefulheight/2/fZoomY);
205
cairo_translate (pCairoContext,
206
- fUsefulheight/2/fZoomY,
207
- fUsefulWidth/2/fZoomX);
211
cairo_surface_t *cairo_dock_create_surface_from_xicon_buffer (gulong *pXIconBuffer, int iBufferNbElements, int iWidth, int iHeight)
213
cairo_t *pSourceContext = _get_source_context ();
214
g_return_val_if_fail (pSourceContext != NULL && cairo_status (pSourceContext) == CAIRO_STATUS_SUCCESS, NULL);
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)
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.
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.
227
if (pXIconBuffer[iIndex] > pXIconBuffer[iBestIndex])
229
iIndex += 2 + pXIconBuffer[iIndex] * pXIconBuffer[iIndex+1];
232
//\____________________ On pre-multiplie chaque composante par le alpha (necessaire pour libcairo).
233
int w = pXIconBuffer[iBestIndex];
234
int h = pXIconBuffer[iBestIndex+1];
236
//g_print ("%s (%dx%d)\n", __func__, w, h);
239
if (iBestIndex + n > iBufferNbElements) // precaution au cas ou le nombre d'elements dans le buffer serait incorrect.
241
cd_warning ("This icon is broken !\nThis means that one of the current applications has sent a buggy icon to X.");
244
gint pixel, alpha, red, green, blue;
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 ++)
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;
256
green *= fAlphaFactor;
257
blue *= fAlphaFactor;
258
pPixelBuffer[i] = (pixel & 0xFF000000) + (red << 16) + (green << 8) + blue;
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,
269
double fWidth = w, fHeight = h;
270
double fIconWidthSaturationFactor = 1., fIconHeightSaturationFactor = 1.;
271
cairo_dock_calculate_constrainted_size (&fWidth,
275
CAIRO_DOCK_KEEP_RATIO | CAIRO_DOCK_FILL_SPACE,
276
&fIconWidthSaturationFactor,
277
&fIconHeightSaturationFactor);
279
cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
282
cairo_t *pCairoContext = cairo_create (pNewSurface);
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,
289
fIconWidthSaturationFactor, fIconHeightSaturationFactor,
290
fUsefulWidth, fUsefulHeight);
291
cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
292
cairo_paint (pCairoContext);
294
cairo_surface_destroy (surface_ini);
295
cairo_destroy (pCairoContext);
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)
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,
311
&fIconWidthSaturationFactor,
312
&fIconHeightSaturationFactor);
314
GdkPixbuf *pPixbufWithAlpha = pixbuf;
315
if (! gdk_pixbuf_get_has_alpha (pixbuf)) // on lui rajoute un canal alpha s'il n'en a pas.
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.
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);
328
int red, green, blue;
330
for (y = 0; y < h; y ++)
332
for (x = 0; x < w; x ++)
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;
345
cairo_surface_t *surface_ini = cairo_image_surface_create_for_data (pixels,
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);
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,
360
ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
361
fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
362
fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
364
cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
365
cairo_paint (pCairoContext);
367
cairo_destroy (pCairoContext);
368
cairo_surface_destroy (surface_ini);
369
if (pPixbufWithAlpha != pixbuf)
370
g_object_unref (pPixbufWithAlpha);
373
*fZoomX = fIconWidthSaturationFactor;
375
*fZoomY = fIconHeightSaturationFactor;
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)
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.;
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");
402
if (fgets (buffer, 7, fd) != NULL)
404
if (strncmp (buffer+2, "xml", 3) == 0)
406
else if (strncmp (buffer+1, "PNG", 3) == 0)
408
else if (strncmp (buffer+3, "XPM", 3) == 0)
410
//cd_debug (" format : %d;%d;%d", bIsSVG, bIsPNG, bIsXPM);
416
cd_warning ("This file (%s) doesn't exist or is not readable.", cImagePath);
419
if (! bIsSVG && ! bIsPNG && ! bIsXPM) // sinon en desespoir de cause on se base sur l'extension.
421
//cd_debug (" on se base sur l'extension en desespoir de cause.");
422
if (g_str_has_suffix (cImagePath, ".svg"))
424
else if (g_str_has_suffix (cImagePath, ".png"))
428
bIsPNG = FALSE; /// libcairo 1.6 - 1.8 est bugguee !!!...
431
rsvg_handle = rsvg_handle_new_from_file (cImagePath, &erreur);
434
cd_warning (erreur->message);
435
g_error_free (erreur);
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,
452
&fIconWidthSaturationFactor,
453
&fIconHeightSaturationFactor);
455
pNewSurface = cairo_dock_create_blank_surface (
456
ceil ((*fImageWidth) * fMaxScale),
457
ceil ((*fImageHeight) * fMaxScale));
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,
464
ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
465
fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
466
fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
468
rsvg_handle_render_cairo (rsvg_handle, pCairoContext);
469
cairo_destroy (pCairoContext);
470
g_object_unref (rsvg_handle);
475
surface_ini = cairo_image_surface_create_from_png (cImagePath); // cree un fond noir :-(
476
if (cairo_surface_status (surface_ini) == CAIRO_STATUS_SUCCESS)
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,
487
&fIconWidthSaturationFactor,
488
&fIconHeightSaturationFactor);
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);
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,
503
ceil ((*fImageWidth) * fMaxScale), ceil ((*fImageHeight) * fMaxScale),
504
fMaxScale * fIconWidthSaturationFactor, fMaxScale * fIconHeightSaturationFactor,
505
fUsefulWidth * fMaxScale, fUsefulHeight * fMaxScale);
507
cairo_set_source_surface (pCairoContext, surface_ini, 0, 0);
508
cairo_paint (pCairoContext);
509
cairo_destroy (pCairoContext);
511
cairo_surface_destroy (surface_ini);
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.
515
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (cImagePath, &erreur); // semble se baser sur l'extension pour definir le type !
518
cd_warning (erreur->message);
519
g_error_free (erreur);
522
pNewSurface = cairo_dock_create_surface_from_pixbuf (pixbuf,
529
&fIconWidthSaturationFactor,
530
&fIconHeightSaturationFactor);
531
g_object_unref (pixbuf);
536
*fZoomX = fIconWidthSaturationFactor;
538
*fZoomY = fIconHeightSaturationFactor;
543
cairo_surface_t *cairo_dock_create_surface_from_image_simple (const gchar *cImageFile, double fImageWidth, double fImageHeight)
545
g_return_val_if_fail (cImageFile != NULL, NULL);
546
double fImageWidth_ = fImageWidth, fImageHeight_ = fImageHeight;
548
if (*cImageFile == '/')
549
cImagePath = (gchar *)cImageFile;
551
cImagePath = cairo_dock_generate_file_path (cImageFile);
553
cairo_surface_t *pSurface = cairo_dock_create_surface_from_image (cImagePath,
557
CAIRO_DOCK_FILL_SPACE,
562
if (cImagePath != cImageFile)
567
cairo_surface_t *cairo_dock_create_surface_from_icon (const gchar *cImageFile, double fImageWidth, double fImageHeight)
569
g_return_val_if_fail (cImageFile != NULL, NULL);
570
double fImageWidth_ = fImageWidth, fImageHeight_ = fImageHeight;
572
if (*cImageFile == '/')
573
cIconPath = (gchar *)cImageFile;
575
cIconPath = cairo_dock_search_icon_s_path (cImageFile);
577
cairo_surface_t *pSurface = cairo_dock_create_surface_from_image (cIconPath,
581
CAIRO_DOCK_FILL_SPACE,
586
if (cIconPath != cImageFile)
591
cairo_surface_t *cairo_dock_create_surface_from_pattern (const gchar *cImageFile, double fImageWidth, double fImageHeight, double fAlpha)
593
cairo_surface_t *pNewSurface = NULL;
595
if (cImageFile != NULL)
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,
601
0, // pas de contrainte sur
602
0, // la taille du motif initialement.
603
CAIRO_DOCK_FILL_SPACE,
608
if (pPatternSurface == NULL)
611
pNewSurface = cairo_dock_create_blank_surface (
614
cairo_t *pCairoContext = cairo_create (pNewSurface);
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);
620
cairo_set_source (pCairoContext, pPattern);
621
cairo_paint_with_alpha (pCairoContext, fAlpha);
622
cairo_destroy (pCairoContext);
623
cairo_pattern_destroy (pPattern);
625
cairo_surface_destroy (pPatternSurface);
633
cairo_surface_t * cairo_dock_rotate_surface (cairo_surface_t *pSurface, double fImageWidth, double fImageHeight, double fRotationAngle)
635
g_return_val_if_fail (pSurface != NULL, NULL);
636
if (fRotationAngle != 0)
638
cairo_surface_t *pNewSurfaceRotated;
639
cairo_t *pCairoContext;
640
if (fabs (fRotationAngle) > G_PI / 2)
642
pNewSurfaceRotated = cairo_dock_create_blank_surface (
645
pCairoContext = cairo_create (pNewSurfaceRotated);
647
cairo_translate (pCairoContext, 0, fImageHeight);
648
cairo_scale (pCairoContext, 1, -1);
652
pNewSurfaceRotated = cairo_dock_create_blank_surface (
655
pCairoContext = cairo_create (pNewSurfaceRotated);
657
if (fRotationAngle < 0)
659
cairo_move_to (pCairoContext, fImageHeight, 0);
660
cairo_rotate (pCairoContext, fRotationAngle);
661
cairo_translate (pCairoContext, - fImageWidth, 0);
665
cairo_move_to (pCairoContext, 0, 0);
666
cairo_rotate (pCairoContext, fRotationAngle);
667
cairo_translate (pCairoContext, 0, - fImageHeight);
670
cairo_set_source_surface (pCairoContext, pSurface, 0, 0);
671
cairo_paint (pCairoContext);
673
cairo_destroy (pCairoContext);
674
return pNewSurfaceRotated;
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)
685
//g_print ("%s (%d)\n", __func__, bDirectionUp);
687
//\_______________ On cree la surface d'une fraction hauteur de l'image originale.
688
if (pSurface == NULL || fReflectSize == 0 || fAlbedo == 0)
690
cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
693
cairo_t *pCairoContext = cairo_create (pNewSurface);
695
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
696
cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
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));
703
//\_______________ On applique un degrade en transparence.
704
cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0.,
707
fImageHeight - fReflectSize); // de haut en bas.
708
g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
710
cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE);
711
cairo_pattern_add_color_stop_rgba (pGradationPattern,
716
(bDirectionUp ? fAlbedo : 0.));
717
cairo_pattern_add_color_stop_rgba (pGradationPattern,
722
(bDirectionUp ? 0 : fAlbedo));
724
cairo_mask (pCairoContext, pGradationPattern);
726
cairo_pattern_destroy (pGradationPattern);
727
cairo_destroy (pCairoContext);
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)
733
g_return_val_if_fail (pSurface != NULL, NULL);
735
//\_______________ On cree la surface d'une fraction hauteur de l'image originale.
736
if (fReflectSize == 0 || fAlbedo == 0)
738
cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
741
cairo_t *pCairoContext = cairo_create (pNewSurface);
743
cairo_set_operator (pCairoContext, CAIRO_OPERATOR_OVER);
744
cairo_set_source_rgba (pCairoContext, 0., 0., 0., 0.);
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.);
751
//\_______________ On applique un degrade en transparence.
752
cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (0,
754
fImageHeight - fReflectSize,
755
0.); // de gauche a droite.
756
g_return_val_if_fail (cairo_pattern_status (pGradationPattern) == CAIRO_STATUS_SUCCESS, NULL);
758
cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_REPEAT);
759
cairo_pattern_add_color_stop_rgba (pGradationPattern,
764
(bDirectionUp ? fAlbedo : 0.));
765
cairo_pattern_add_color_stop_rgba (pGradationPattern,
770
(bDirectionUp ? 0. : fAlbedo));
772
cairo_mask (pCairoContext, pGradationPattern);
774
cairo_pattern_destroy (pGradationPattern);
775
cairo_destroy (pCairoContext);
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)
782
return cairo_dock_create_reflection_surface_horizontal (pSurface, fImageWidth, fImageHeight, fReflectSize, fAlbedo, bDirectionUp);
784
return cairo_dock_create_reflection_surface_vertical (pSurface, fImageWidth, fImageHeight, fReflectSize, fAlbedo, bDirectionUp);
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)
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);
794
//\_________________ On ecrit le texte dans un calque Pango.
795
PangoLayout *pLayout = pango_cairo_create_layout (pSourceContext);
796
PangoRectangle ink, log;
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);
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;
810
if (pLabelDescription->bUseMarkup)
811
pango_layout_set_markup (pLayout, cText, -1);
813
pango_layout_set_text (pLayout, cText, -1);
815
//\_________________ On cree une surface aux dimensions du texte.
816
pango_layout_get_pixel_extents (pLayout, &ink, &log);
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.);
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.
826
*iTextWidth = MAX (*iTextWidth, 2 * fRadius + 10);
827
if (iMaxWidth != 0 && *iTextWidth > iMaxWidth)
828
*iTextWidth = iMaxWidth;
830
*iTextHeight = MAX (iMaxSize, ink.height) + iOutlineMargin + 0; // +1 car certaines polices "debordent".
832
cairo_surface_t* pNewSurface = cairo_dock_create_blank_surface (
835
cairo_t* pCairoContext = cairo_create (pNewSurface);
837
//\_________________ On dessine le fond.
838
if (bDrawBackground) // non transparent.
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);
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,
854
-ink.y + dy); // meme remarque pour le +1.
856
//\_________________ On dessine les contours du texte.
857
if (pLabelDescription->bOutlined)
859
cairo_save (pCairoContext);
861
cairo_scale (pCairoContext, fZoomX, 1.);
862
cairo_push_group (pCairoContext);
863
cairo_set_source_rgb (pCairoContext, 0.2, 0.2, 0.2);
865
for (i = 0; i < 2; i++)
867
cairo_move_to (pCairoContext, 0, 2*i-1);
868
pango_cairo_show_layout (pCairoContext, pLayout);
870
for (i = 0; i < 2; i++)
872
cairo_move_to (pCairoContext, 2*i-1, 0);
873
pango_cairo_show_layout (pCairoContext, pLayout);
875
cairo_pop_group_to_source (pCairoContext);
876
//cairo_paint_with_alpha (pCairoContext, .75);
877
cairo_paint (pCairoContext);
878
cairo_restore(pCairoContext);
881
//\_________________ On remplit l'interieur du texte.
882
cairo_pattern_t *pGradationPattern = NULL;
883
if (pLabelDescription->fColorStart != pLabelDescription->fColorStop)
885
if (pLabelDescription->bVerticalPattern)
886
pGradationPattern = cairo_pattern_create_linear (0.,
887
ink.y + 0, // meme remarque pour le +1.
889
ink.y + 0 + ink.height);
891
pGradationPattern = cairo_pattern_create_linear (ink.x + 0,
893
ink.x + 0 + ink.width,
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,
899
pLabelDescription->fColorStart[0],
900
pLabelDescription->fColorStart[1],
901
pLabelDescription->fColorStart[2],
903
cairo_pattern_add_color_stop_rgba (pGradationPattern,
905
pLabelDescription->fColorStop[0],
906
pLabelDescription->fColorStop[1],
907
pLabelDescription->fColorStop[2],
909
cairo_set_source (pCairoContext, pGradationPattern);
912
cairo_set_source_rgb (pCairoContext, pLabelDescription->fColorStart[0], pLabelDescription->fColorStart[1], pLabelDescription->fColorStart[2]);
913
cairo_move_to (pCairoContext, 0, 0);
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);
921
cairo_destroy (pCairoContext);
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.
933
*iTextWidth = *iTextWidth / fMaxScale;
934
*iTextHeight = *iTextHeight / fMaxScale;
936
g_object_unref (pLayout);
941
cairo_surface_t * cairo_dock_duplicate_surface (cairo_surface_t *pSurface, double fWidth, double fHeight, double fDesiredWidth, double fDesiredHeight)
943
g_return_val_if_fail (pSurface != NULL, NULL);
945
//\_______________ On cree la surface de la taille desiree.
946
if (fDesiredWidth == 0)
947
fDesiredWidth = fWidth;
948
if (fDesiredHeight == 0)
949
fDesiredHeight = fHeight;
951
//g_print ("%s (%.2fx%.2f -> %.2fx%.2f)\n", __func__, fWidth, fHeight, fDesiredWidth, fDesiredHeight);
952
cairo_surface_t *pNewSurface = cairo_dock_create_blank_surface (
955
cairo_t *pCairoContext = cairo_create (pNewSurface);
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);
963
cairo_set_source_surface (pCairoContext, pSurface, 0., 0.);
964
cairo_paint (pCairoContext);
965
cairo_destroy (pCairoContext);