1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2010 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <math.h>
24 #include <string.h>
25 #include "cairo-utils.h"
26 #include "cairo-scale.h"
27 #include "gth-image-utils.h"
28
29
30 G_DEFINE_BOXED_TYPE (GthCairoSurface,
31 gth_cairo_surface,
32 (GBoxedCopyFunc) cairo_surface_reference,
33 (GBoxedFreeFunc) cairo_surface_destroy)
34
35
36 const unsigned char cairo_channel[4] = { CAIRO_RED, CAIRO_GREEN, CAIRO_BLUE, CAIRO_ALPHA };
37
38
39 static cairo_user_data_key_t surface_metadata_key;
40
41
42 static void
surface_metadata_free(void * data)43 surface_metadata_free (void *data)
44 {
45 cairo_surface_metadata_t *metadata = data;
46 g_free (metadata);
47 }
48
49
50 inline int
_cairo_multiply_alpha(int color,int alpha)51 _cairo_multiply_alpha (int color,
52 int alpha)
53 {
54 int temp = (alpha * color) + 0x80;
55 return ((temp + (temp >> 8)) >> 8);
56 }
57
58
59 gboolean
_cairo_rectangle_contains_point(cairo_rectangle_int_t * rect,int x,int y)60 _cairo_rectangle_contains_point (cairo_rectangle_int_t *rect,
61 int x,
62 int y)
63 {
64 return ((x >= rect->x)
65 && (y >= rect->y)
66 && (x <= rect->x + rect->width)
67 && (y <= rect->y + rect->height));
68 }
69
70
71 void
_gdk_color_to_cairo_color(GdkColor * g_color,GdkRGBA * c_color)72 _gdk_color_to_cairo_color (GdkColor *g_color,
73 GdkRGBA *c_color)
74 {
75 c_color->red = (double) g_color->red / 65535;
76 c_color->green = (double) g_color->green / 65535;
77 c_color->blue = (double) g_color->blue / 65535;
78 c_color->alpha = 1.0;
79 }
80
81
82 void
_gdk_color_to_cairo_color_255(GdkColor * g_color,cairo_color_255_t * c_color)83 _gdk_color_to_cairo_color_255 (GdkColor *g_color,
84 cairo_color_255_t *c_color)
85 {
86 c_color->r = (guchar) 255.0 * g_color->red / 65535.0;
87 c_color->g = (guchar) 255.0 * g_color->green / 65535.0;
88 c_color->b = (guchar) 255.0 * g_color->blue / 65535.0;
89 c_color->a = 0xff;
90 }
91
92
93 void
_gdk_rgba_to_cairo_color_255(GdkRGBA * g_color,cairo_color_255_t * c_color)94 _gdk_rgba_to_cairo_color_255 (GdkRGBA *g_color,
95 cairo_color_255_t *c_color)
96 {
97 c_color->r = (guchar) 255.0 * g_color->red;
98 c_color->g = (guchar) 255.0 * g_color->green;
99 c_color->b = (guchar) 255.0 * g_color->blue;
100 c_color->a = (guchar) 255.0 * g_color->alpha;
101 }
102
103
104 void
_cairo_metadata_set_has_alpha(cairo_surface_metadata_t * metadata,gboolean has_alpha)105 _cairo_metadata_set_has_alpha (cairo_surface_metadata_t *metadata,
106 gboolean has_alpha)
107 {
108 g_return_if_fail (metadata != NULL);
109
110 metadata->valid_data |= _CAIRO_METADATA_FLAG_HAS_ALPHA;
111 metadata->has_alpha = has_alpha ? TRUE : FALSE;
112 }
113
114
115 void
_cairo_metadata_set_original_size(cairo_surface_metadata_t * metadata,int width,int height)116 _cairo_metadata_set_original_size (cairo_surface_metadata_t *metadata,
117 int width,
118 int height)
119 {
120 g_return_if_fail (metadata != NULL);
121
122 metadata->valid_data |= _CAIRO_METADATA_FLAG_ORIGINAL_SIZE;
123 metadata->original_width = width;
124 metadata->original_height = height;
125 }
126
127
128 void
_cairo_metadata_set_thumbnail_size(cairo_surface_metadata_t * metadata,int width,int height)129 _cairo_metadata_set_thumbnail_size (cairo_surface_metadata_t *metadata,
130 int width,
131 int height)
132 {
133 g_return_if_fail (metadata != NULL);
134
135 metadata->valid_data |= _CAIRO_METADATA_FLAG_THUMBNAIL_SIZE;
136 metadata->thumbnail.image_width = width;
137 metadata->thumbnail.image_height = height;
138 }
139
140
141 void
_cairo_clear_surface(cairo_surface_t ** surface)142 _cairo_clear_surface (cairo_surface_t **surface)
143 {
144 if (surface == NULL)
145 return;
146 if (*surface == NULL)
147 return;
148
149 cairo_surface_destroy (*surface);
150 *surface = NULL;
151 }
152
153
154 unsigned char *
_cairo_image_surface_flush_and_get_data(cairo_surface_t * surface)155 _cairo_image_surface_flush_and_get_data (cairo_surface_t *surface)
156 {
157 g_return_val_if_fail (surface != NULL, NULL);
158
159 cairo_surface_flush (surface);
160 return cairo_image_surface_get_data (surface);
161 }
162
163
164 static void
_cairo_surface_metadata_init(cairo_surface_metadata_t * metadata)165 _cairo_surface_metadata_init (cairo_surface_metadata_t *metadata)
166 {
167 g_return_if_fail (metadata != NULL);
168
169 metadata->valid_data = _CAIRO_METADATA_FLAG_NONE;
170 metadata->has_alpha = FALSE;
171 metadata->original_width = 0;
172 metadata->original_height = 0;
173 metadata->thumbnail.image_width = 0;
174 metadata->thumbnail.image_height = 0;
175 }
176
177
178 cairo_surface_metadata_t *
_cairo_image_surface_get_metadata(cairo_surface_t * surface)179 _cairo_image_surface_get_metadata (cairo_surface_t *surface)
180 {
181 cairo_surface_metadata_t *metadata;
182
183 g_return_val_if_fail (surface != NULL, NULL);
184
185 metadata = cairo_surface_get_user_data (surface, &surface_metadata_key);
186 if (metadata == NULL) {
187 metadata = g_new0 (cairo_surface_metadata_t, 1);
188 _cairo_surface_metadata_init (metadata);
189 cairo_surface_set_user_data (surface, &surface_metadata_key, metadata, surface_metadata_free);
190 }
191
192 return metadata;
193 }
194
195
196 void
_cairo_image_surface_copy_metadata(cairo_surface_t * src,cairo_surface_t * dest)197 _cairo_image_surface_copy_metadata (cairo_surface_t *src,
198 cairo_surface_t *dest)
199 {
200 cairo_surface_metadata_t *src_metadata;
201 cairo_surface_metadata_t *dest_metadata;
202
203 g_return_if_fail (src != NULL);
204 g_return_if_fail (dest != NULL);
205
206 src_metadata = _cairo_image_surface_get_metadata (src);
207 dest_metadata = _cairo_image_surface_get_metadata (dest);
208
209 dest_metadata->valid_data = src_metadata->valid_data;
210 dest_metadata->has_alpha = src_metadata->has_alpha;
211 dest_metadata->original_width = src_metadata->original_width;
212 dest_metadata->original_height = src_metadata->original_height;
213 dest_metadata->thumbnail.image_width = src_metadata->thumbnail.image_width;
214 dest_metadata->thumbnail.image_height = src_metadata->thumbnail.image_height;
215
216 }
217
218
219 void
_cairo_image_surface_clear_metadata(cairo_surface_t * surface)220 _cairo_image_surface_clear_metadata (cairo_surface_t *surface)
221 {
222 cairo_surface_metadata_t *metadata;
223
224 g_return_if_fail (surface != NULL);
225
226 metadata = _cairo_image_surface_get_metadata (surface);
227 _cairo_surface_metadata_init (metadata);
228 }
229
230
231 gboolean
_cairo_image_surface_get_has_alpha(cairo_surface_t * surface)232 _cairo_image_surface_get_has_alpha (cairo_surface_t *surface)
233 {
234 cairo_surface_metadata_t *metadata;
235 gboolean has_alpha;
236 int width;
237 int height;
238 int row_stride;
239 guchar *row;
240 int h, w;
241
242 if (surface == NULL)
243 return FALSE;
244
245 metadata = _cairo_image_surface_get_metadata (surface);
246 if ((metadata != NULL) && (metadata->valid_data & _CAIRO_METADATA_FLAG_HAS_ALPHA))
247 return metadata->has_alpha;
248
249 has_alpha = FALSE;
250 if (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32) {
251 /* search an alpha value lower than 255 */
252
253 width = cairo_image_surface_get_width (surface);
254 height = cairo_image_surface_get_height (surface);
255 row_stride = cairo_image_surface_get_stride (surface);
256 row = _cairo_image_surface_flush_and_get_data (surface);
257
258 for (h = 0; ! has_alpha && (h < height); h++) {
259 guchar *pixel = row;
260 for (w = 0; w < width; w++) {
261 if (pixel[CAIRO_ALPHA] < 255) {
262 has_alpha = TRUE;
263 break;
264 }
265 pixel += 4;
266 }
267 row += row_stride;
268 }
269 }
270 _cairo_metadata_set_has_alpha (metadata, has_alpha);
271
272 return has_alpha;
273 }
274
275
276 gboolean
_cairo_image_surface_get_original_size(cairo_surface_t * surface,int * original_width,int * original_height)277 _cairo_image_surface_get_original_size (cairo_surface_t *surface,
278 int *original_width,
279 int *original_height)
280 {
281 cairo_surface_metadata_t *metadata;
282
283 if (surface == NULL)
284 return FALSE;
285
286 metadata = cairo_surface_get_user_data (surface, &surface_metadata_key);
287 if (metadata == NULL)
288 return FALSE;
289
290 if ((metadata->valid_data & _CAIRO_METADATA_FLAG_ORIGINAL_SIZE) == 0)
291 return FALSE;
292
293 if (original_width)
294 *original_width = metadata->original_width;
295 if (original_height)
296 *original_height = metadata->original_height;
297
298 return TRUE;
299 }
300
301
302 cairo_surface_t *
_cairo_image_surface_create(cairo_format_t format,int width,int height)303 _cairo_image_surface_create (cairo_format_t format,
304 int width,
305 int height)
306 {
307 cairo_surface_t *result;
308 cairo_status_t status;
309
310 result = cairo_image_surface_create (format, width, height);
311 status = cairo_surface_status (result);
312 if (status != CAIRO_STATUS_SUCCESS) {
313 g_warning ("_cairo_image_surface_create: could not create the surface: %s", cairo_status_to_string (status));
314 cairo_surface_destroy (result);
315 return NULL;
316 }
317
318 return result;
319 }
320
321
322 cairo_surface_t *
_cairo_image_surface_copy(cairo_surface_t * source)323 _cairo_image_surface_copy (cairo_surface_t *source)
324 {
325 cairo_surface_t *result;
326 unsigned char *p_source;
327 unsigned char *p_destination;
328
329 if (source == NULL)
330 return NULL;
331
332 result = _cairo_image_surface_create (cairo_image_surface_get_format (source),
333 cairo_image_surface_get_width (source),
334 cairo_image_surface_get_height (source));
335 if (result == NULL)
336 return NULL;
337
338 p_source = _cairo_image_surface_flush_and_get_data (source);
339 p_destination = _cairo_image_surface_flush_and_get_data (result);
340 memcpy (p_destination, p_source, cairo_image_surface_get_stride (source) * cairo_image_surface_get_height (source));
341 cairo_surface_mark_dirty (result);
342
343 return result;
344 }
345
346
347 cairo_surface_t *
_cairo_image_surface_copy_subsurface(cairo_surface_t * source,int src_x,int src_y,int width,int height)348 _cairo_image_surface_copy_subsurface (cairo_surface_t *source,
349 int src_x,
350 int src_y,
351 int width,
352 int height)
353 {
354 cairo_surface_t *destination;
355 cairo_status_t status;
356 int source_stride;
357 int destination_stride;
358 unsigned char *p_source;
359 unsigned char *p_destination;
360 int row_size;
361
362 g_return_val_if_fail (source != NULL, NULL);
363 g_return_val_if_fail (src_x + width <= cairo_image_surface_get_width (source), NULL);
364 g_return_val_if_fail (src_y + height <= cairo_image_surface_get_height (source), NULL);
365
366 destination = cairo_image_surface_create (cairo_image_surface_get_format (source), width, height);
367 status = cairo_surface_status (destination);
368 if (status != CAIRO_STATUS_SUCCESS) {
369 g_warning ("_cairo_image_surface_copy_subsurface: could not create the surface: %s", cairo_status_to_string (status));
370 cairo_surface_destroy (destination);
371 return NULL;
372 }
373
374 source_stride = cairo_image_surface_get_stride (source);
375 destination_stride = cairo_image_surface_get_stride (destination);
376 p_source = _cairo_image_surface_flush_and_get_data (source) + (src_y * source_stride) + (src_x * 4);
377 p_destination = _cairo_image_surface_flush_and_get_data (destination);
378 row_size = width * 4;
379 while (height-- > 0) {
380 memcpy (p_destination, p_source, row_size);
381
382 p_source += source_stride;
383 p_destination += destination_stride;
384 }
385
386 cairo_surface_mark_dirty (destination);
387
388 return destination;
389 }
390
391
392 cairo_surface_t *
_cairo_image_surface_create_from_pixbuf(GdkPixbuf * pixbuf)393 _cairo_image_surface_create_from_pixbuf (GdkPixbuf *pixbuf)
394 {
395 cairo_surface_t *surface;
396 cairo_surface_metadata_t *metadata;
397 int width;
398 int height;
399 int p_stride;
400 int p_n_channels;
401 guchar *p_pixels;
402 int s_stride;
403 unsigned char *s_pixels;
404 int h, w;
405 guint32 pixel;
406 guchar r, g, b, a;
407
408 if (pixbuf == NULL)
409 return NULL;
410
411 g_object_get (G_OBJECT (pixbuf),
412 "width", &width,
413 "height", &height,
414 "rowstride", &p_stride,
415 "n-channels", &p_n_channels,
416 "pixels", &p_pixels,
417 NULL );
418 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
419 s_stride = cairo_image_surface_get_stride (surface);
420 s_pixels = _cairo_image_surface_flush_and_get_data (surface);
421
422 metadata = _cairo_image_surface_get_metadata (surface);
423 _cairo_metadata_set_has_alpha (metadata, (p_n_channels == 4));
424
425 if (p_n_channels == 4) {
426 guchar *s_iter;
427 guchar *p_iter;
428
429 for (h = 0; h < height; h++) {
430 s_iter = s_pixels;
431 p_iter = p_pixels;
432
433 for (w = 0; w < width; w++) {
434 a = p_iter[3];
435 if (a == 0xff) {
436 pixel = CAIRO_RGBA_TO_UINT32 (p_iter[0], p_iter[1], p_iter[2], 0xff);
437 }
438 else if (a == 0) {
439 pixel = 0;
440 }
441 else {
442 r = _cairo_multiply_alpha (p_iter[0], a);
443 g = _cairo_multiply_alpha (p_iter[1], a);
444 b = _cairo_multiply_alpha (p_iter[2], a);
445 pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, a);
446 }
447 memcpy (s_iter, &pixel, sizeof (guint32));
448
449 s_iter += 4;
450 p_iter += p_n_channels;
451 }
452
453 s_pixels += s_stride;
454 p_pixels += p_stride;
455 }
456 }
457 else {
458 guchar *s_iter;
459 guchar *p_iter;
460
461 for (h = 0; h < height; h++) {
462 s_iter = s_pixels;
463 p_iter = p_pixels;
464
465 for (w = 0; w < width; w++) {
466 pixel = CAIRO_RGBA_TO_UINT32 (p_iter[0], p_iter[1], p_iter[2], 0xff);
467 memcpy (s_iter, &pixel, sizeof (guint32));
468
469 s_iter += 4;
470 p_iter += p_n_channels;
471 }
472
473 s_pixels += s_stride;
474 p_pixels += p_stride;
475 }
476 }
477
478 cairo_surface_mark_dirty (surface);
479
480 return surface;
481 }
482
483
484 cairo_surface_t *
_cairo_image_surface_create_compatible(cairo_surface_t * surface)485 _cairo_image_surface_create_compatible (cairo_surface_t *surface)
486 {
487 return cairo_image_surface_create (cairo_image_surface_get_format (surface),
488 cairo_image_surface_get_width (surface),
489 cairo_image_surface_get_height (surface));
490 }
491
492
493 void
_cairo_image_surface_transform_get_steps(cairo_format_t format,int width,int height,GthTransform transform,int * destination_width_p,int * destination_height_p,int * line_start_p,int * line_step_p,int * pixel_step_p)494 _cairo_image_surface_transform_get_steps (cairo_format_t format,
495 int width,
496 int height,
497 GthTransform transform,
498 int *destination_width_p,
499 int *destination_height_p,
500 int *line_start_p,
501 int *line_step_p,
502 int *pixel_step_p)
503 {
504 int destination_stride;
505 int destination_width = 0;
506 int destination_height = 0;
507 int line_start = 0;
508 int line_step = 0;
509 int pixel_step = 0;
510
511 switch (transform) {
512 case GTH_TRANSFORM_NONE:
513 default:
514 destination_width = width;
515 destination_height = height;
516 destination_stride = cairo_format_stride_for_width (format, destination_width);
517 line_start = 0;
518 line_step = destination_stride;
519 pixel_step = 4;
520 break;
521
522 case GTH_TRANSFORM_FLIP_H:
523 destination_width = width;
524 destination_height = height;
525 destination_stride = cairo_format_stride_for_width (format, destination_width);
526 line_start = (destination_width - 1) * 4;
527 line_step = destination_stride;
528 pixel_step = -4;
529 break;
530
531 case GTH_TRANSFORM_ROTATE_180:
532 destination_width = width;
533 destination_height = height;
534 destination_stride = cairo_format_stride_for_width (format, destination_width);
535 line_start = ((destination_height - 1) * destination_stride) + ((destination_width - 1) * 4);
536 line_step = -destination_stride;
537 pixel_step = -4;
538 break;
539
540 case GTH_TRANSFORM_FLIP_V:
541 destination_width = width;
542 destination_height = height;
543 destination_stride = cairo_format_stride_for_width (format, destination_width);
544 line_start = (destination_height - 1) * destination_stride;
545 line_step = -destination_stride;
546 pixel_step = 4;
547 break;
548
549 case GTH_TRANSFORM_TRANSPOSE:
550 destination_width = height;
551 destination_height = width;
552 destination_stride = cairo_format_stride_for_width (format, destination_width);
553 line_start = 0;
554 line_step = 4;
555 pixel_step = destination_stride;
556 break;
557
558 case GTH_TRANSFORM_ROTATE_90:
559 destination_width = height;
560 destination_height = width;
561 destination_stride = cairo_format_stride_for_width (format, destination_width);
562 line_start = (destination_width - 1) * 4;
563 line_step = -4;
564 pixel_step = destination_stride;
565 break;
566
567 case GTH_TRANSFORM_TRANSVERSE:
568 destination_width = height;
569 destination_height = width;
570 destination_stride = cairo_format_stride_for_width (format, destination_width);
571 line_start = ((destination_height - 1) * destination_stride) + ((destination_width - 1) * 4);
572 line_step = -4;
573 pixel_step = -destination_stride;
574 break;
575
576 case GTH_TRANSFORM_ROTATE_270:
577 destination_width = height;
578 destination_height = width;
579 destination_stride = cairo_format_stride_for_width (format, destination_width);
580 line_start = (destination_height - 1) * destination_stride;
581 line_step = 4;
582 pixel_step = -destination_stride;
583 break;
584 }
585
586 if (destination_width_p != NULL)
587 *destination_width_p = destination_width;
588 if (destination_height_p != NULL)
589 *destination_height_p = destination_height;
590 if (line_start_p != NULL)
591 *line_start_p = line_start;
592 if (line_step_p != NULL)
593 *line_step_p = line_step;
594 if (pixel_step_p != NULL)
595 *pixel_step_p = pixel_step;
596 }
597
598
599 cairo_surface_t *
_cairo_image_surface_transform(cairo_surface_t * source,GthTransform transform)600 _cairo_image_surface_transform (cairo_surface_t *source,
601 GthTransform transform)
602 {
603 cairo_surface_t *destination = NULL;
604 cairo_format_t format;
605 int width;
606 int height;
607 int source_stride;
608 int destination_width;
609 int destination_height;
610 int line_start;
611 int line_step;
612 int pixel_step;
613 unsigned char *p_source_line;
614 unsigned char *p_destination_line;
615 unsigned char *p_source;
616 unsigned char *p_destination;
617 int x;
618
619 if (source == NULL)
620 return NULL;
621
622 format = cairo_image_surface_get_format (source);
623 width = cairo_image_surface_get_width (source);
624 height = cairo_image_surface_get_height (source);
625 source_stride = cairo_image_surface_get_stride (source);
626
627 _cairo_image_surface_transform_get_steps (format,
628 width,
629 height,
630 transform,
631 &destination_width,
632 &destination_height,
633 &line_start,
634 &line_step,
635 &pixel_step);
636
637 destination = cairo_image_surface_create (format, destination_width, destination_height);
638 p_source_line = _cairo_image_surface_flush_and_get_data (source);
639 p_destination_line = _cairo_image_surface_flush_and_get_data (destination) + line_start;
640 while (height-- > 0) {
641 p_source = p_source_line;
642 p_destination = p_destination_line;
643 for (x = 0; x < width; x++) {
644 memcpy (p_destination, p_source, 4);
645 p_source += 4;
646 p_destination += pixel_step;
647 }
648 p_source_line += source_stride;
649 p_destination_line += line_step;
650 }
651
652 cairo_surface_mark_dirty (destination);
653
654 return destination;
655 }
656
657
658 cairo_surface_t *
_cairo_image_surface_color_shift(cairo_surface_t * image,int shift)659 _cairo_image_surface_color_shift (cairo_surface_t *image,
660 int shift)
661 {
662 cairo_surface_t *shifted;
663 int i, j;
664 int width, height, src_stride, dest_stride;
665 guchar *src_pixels, *src_row, *src_pixel;
666 guchar *dest_pixels, *dest_row, *dest_pixel;
667 int val, temp;
668 guchar r, g, b, a;
669
670 shifted = _cairo_image_surface_create_compatible (image);
671
672 width = cairo_image_surface_get_width (image);
673 height = cairo_image_surface_get_height (image);
674 src_stride = cairo_image_surface_get_stride (image);
675 src_pixels = _cairo_image_surface_flush_and_get_data (image);
676 dest_stride = cairo_image_surface_get_stride (shifted);
677 dest_pixels = _cairo_image_surface_flush_and_get_data (shifted);
678
679 src_row = src_pixels;
680 dest_row = dest_pixels;
681 for (i = 0; i < height; i++) {
682 src_pixel = src_row;
683 dest_pixel = dest_row;
684
685 for (j = 0; j < width; j++) {
686 CAIRO_GET_RGBA (src_pixel, r, g, b, a);
687
688 val = r + shift;
689 r = CLAMP (val, 0, 255);
690
691 val = g + shift;
692 g = CLAMP (val, 0, 255);
693
694 val = b + shift;
695 b = CLAMP (val, 0, 255);
696
697 CAIRO_SET_RGBA (dest_pixel, r, g, b, a);
698
699 src_pixel += 4;
700 dest_pixel += 4;
701 }
702
703 src_row += src_stride;
704 dest_row += dest_stride;
705 }
706
707 cairo_surface_mark_dirty (shifted);
708
709 return shifted;
710 }
711
712
713 void
_cairo_copy_line_as_rgba_big_endian(guchar * dest,guchar * src,guint width,guint alpha)714 _cairo_copy_line_as_rgba_big_endian (guchar *dest,
715 guchar *src,
716 guint width,
717 guint alpha)
718 {
719 guint x;
720
721 if (alpha) {
722 int temp;
723
724 for (x = 0; x < width; x++) {
725 CAIRO_GET_RGBA (src, dest[0], dest[1], dest[2], dest[3]);
726
727 src += 4;
728 dest += 4;
729 }
730 }
731 else {
732 for (x = 0; x < width; x++) {
733 CAIRO_GET_RGB (src, dest[0], dest[1], dest[2]);
734
735 src += 4;
736 dest += 3;
737 }
738 }
739 }
740
741
742 void
_cairo_copy_line_as_rgba_little_endian(guchar * dest,guchar * src,guint width,guint alpha)743 _cairo_copy_line_as_rgba_little_endian (guchar *dest,
744 guchar *src,
745 guint width,
746 guint alpha)
747 {
748 guint x;
749
750 if (alpha) {
751 int r, g, b, a, temp;
752
753 for (x = 0; x < width; x++) {
754 CAIRO_GET_RGBA (src, r, g, b, a);
755 dest[0] = b;
756 dest[1] = g;
757 dest[2] = r;
758 dest[3] = a;
759
760 src += 4;
761 dest += 4;
762 }
763 }
764 else {
765 for (x = 0; x < width; x++) {
766 dest[0] = src[CAIRO_BLUE];
767 dest[1] = src[CAIRO_GREEN];
768 dest[2] = src[CAIRO_RED];
769
770 src += 4;
771 dest += 3;
772 }
773 }
774 }
775
776
777 void
_cairo_paint_full_gradient(cairo_surface_t * surface,GdkRGBA * h_color1,GdkRGBA * h_color2,GdkRGBA * v_color1,GdkRGBA * v_color2)778 _cairo_paint_full_gradient (cairo_surface_t *surface,
779 GdkRGBA *h_color1,
780 GdkRGBA *h_color2,
781 GdkRGBA *v_color1,
782 GdkRGBA *v_color2)
783 {
784 cairo_color_255_t hcolor1;
785 cairo_color_255_t hcolor2;
786 cairo_color_255_t vcolor1;
787 cairo_color_255_t vcolor2;
788 int width;
789 int height;
790 int s_stride;
791 unsigned char *s_pixels;
792 int h, w;
793 double x, y;
794 double x_y, x_1_y, y_1_x, _1_x_1_y;
795 guchar red, green, blue;
796
797 if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
798 return;
799
800 _gdk_rgba_to_cairo_color_255 (h_color1, &hcolor1);
801 _gdk_rgba_to_cairo_color_255 (h_color2, &hcolor2);
802 _gdk_rgba_to_cairo_color_255 (v_color1, &vcolor1);
803 _gdk_rgba_to_cairo_color_255 (v_color2, &vcolor2);
804
805 width = cairo_image_surface_get_width (surface);
806 height = cairo_image_surface_get_height (surface);
807 s_stride = cairo_image_surface_get_stride (surface);
808 s_pixels = _cairo_image_surface_flush_and_get_data (surface);
809
810 for (h = 0; h < height; h++) {
811 guchar *s_iter = s_pixels;
812
813 x = (double) (height - h) / height;
814
815 for (w = 0; w < width; w++) {
816 y = (double) (width - w) / width;
817 x_y = x * y;
818 x_1_y = x * (1.0 - y);
819 y_1_x = y * (1.0 - x);
820 _1_x_1_y = (1.0 - x) * (1.0 - y);
821
822 red = hcolor1.r * x_y + hcolor2.r * x_1_y + vcolor1.r * y_1_x + vcolor2.r * _1_x_1_y;
823 green = hcolor1.g * x_y + hcolor2.g * x_1_y + vcolor1.g * y_1_x + vcolor2.g * _1_x_1_y;
824 blue = hcolor1.b * x_y + hcolor2.b * x_1_y + vcolor1.b * y_1_x + vcolor2.b * _1_x_1_y;
825
826 CAIRO_SET_RGB (s_iter, red, green, blue);
827
828 s_iter += 4;
829 }
830
831 s_pixels += s_stride;
832 }
833
834 cairo_surface_mark_dirty (surface);
835 }
836
837
838 void
_cairo_draw_rounded_box(cairo_t * cr,double x,double y,double w,double h,double r)839 _cairo_draw_rounded_box (cairo_t *cr,
840 double x,
841 double y,
842 double w,
843 double h,
844 double r)
845 {
846 if (r == 0) {
847 cairo_rectangle (cr, x, y, w, h);
848 }
849 else {
850 cairo_move_to (cr, x, y + r);
851 cairo_arc (cr, x + r, y + r, r, 1.0 * M_PI, 1.5 * M_PI);
852 cairo_rel_line_to (cr, w - (r * 2), 0);
853 cairo_arc (cr, x + w - r, y + r, r, 1.5 * M_PI, 2.0 * M_PI);
854 cairo_rel_line_to (cr, 0, h - (r * 2));
855 cairo_arc (cr, x + w - r, y + h - r, r, 0.0 * M_PI, 0.5 * M_PI);
856 cairo_rel_line_to (cr, - (w - (r * 2)), 0);
857 cairo_arc (cr, x + r, y + h - r, r, 0.5 * M_PI, 1.0 * M_PI);
858 cairo_rel_line_to (cr, 0, - (h - (r * 2)));
859 }
860 }
861
862
863 void
_cairo_draw_drop_shadow(cairo_t * cr,double x,double y,double w,double h,double r)864 _cairo_draw_drop_shadow (cairo_t *cr,
865 double x,
866 double y,
867 double w,
868 double h,
869 double r)
870 {
871 int i;
872
873 cairo_save (cr);
874 cairo_set_line_width (cr, 1);
875 for (i = r; i >= 0; i--) {
876 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, (0.1 / r)* (r - i + 1));
877 _cairo_draw_rounded_box (cr,
878 x + r - i,
879 y + r - i,
880 w + (i * 2),
881 h + (i * 2),
882 r);
883 cairo_fill (cr);
884 }
885 cairo_restore (cr);
886 }
887
888
889 void
_cairo_draw_frame(cairo_t * cr,double x,double y,double w,double h,double r)890 _cairo_draw_frame (cairo_t *cr,
891 double x,
892 double y,
893 double w,
894 double h,
895 double r)
896 {
897 cairo_save (cr);
898 cairo_set_line_width (cr, r);
899 cairo_rectangle (cr, x - (r / 2), y - (r / 2), w + r, h + r);
900 cairo_stroke (cr);
901 cairo_restore (cr);
902 }
903
904
905 void
_cairo_draw_slide(cairo_t * cr,double frame_x,double frame_y,double frame_width,double frame_height,double image_width,double image_height,GdkRGBA * frame_color,gboolean draw_inner_border)906 _cairo_draw_slide (cairo_t *cr,
907 double frame_x,
908 double frame_y,
909 double frame_width,
910 double frame_height,
911 double image_width,
912 double image_height,
913 GdkRGBA *frame_color,
914 gboolean draw_inner_border)
915 {
916 const double dark_gray = 0.60;
917 const double mid_gray = 0.80;
918 const double darker_gray = 0.45;
919 const double light_gray = 0.99;
920 double frame_x2;
921 double frame_y2;
922
923 frame_x += 0.5;
924 frame_y += 0.5;
925
926 frame_x2 = frame_x + frame_width;
927 frame_y2 = frame_y + frame_height;
928
929 cairo_save (cr);
930 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
931 cairo_set_line_width (cr, 1.0);
932
933 /* background. */
934
935 gdk_cairo_set_source_rgba (cr, frame_color);
936 cairo_rectangle (cr,
937 frame_x,
938 frame_y,
939 frame_width,
940 frame_height);
941 cairo_fill (cr);
942
943 if ((image_width > 0) && (image_height > 0)) {
944 double image_x, image_y;
945
946 image_x = frame_x + (frame_width - image_width) / 2 - 0.5;
947 image_y = frame_y + (frame_height - image_height) / 2 - 0.5;
948
949 /* inner border. */
950
951 if (draw_inner_border) {
952 double image_x2, image_y2;
953
954 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
955 cairo_rectangle (cr,
956 image_x,
957 image_y,
958 image_width,
959 image_height);
960 cairo_fill (cr);
961
962 image_x2 = image_x + image_width + 1;
963 image_y2 = image_y + image_height + 1;
964
965 cairo_set_source_rgb (cr, dark_gray, dark_gray, dark_gray);
966 cairo_move_to (cr, image_x, image_y);
967 cairo_line_to (cr, image_x2, image_y);
968 cairo_move_to (cr, image_x, image_y);
969 cairo_line_to (cr, image_x, image_y2);
970 cairo_stroke (cr);
971
972 cairo_set_source_rgb (cr, mid_gray, mid_gray, mid_gray);
973 cairo_move_to (cr, image_x2, image_y);
974 cairo_line_to (cr, image_x2, image_y2);
975 cairo_move_to (cr, image_x, image_y2);
976 cairo_line_to (cr, image_x2, image_y2);
977 cairo_stroke (cr);
978 }
979 }
980
981 /* outer border. */
982
983 cairo_set_source_rgb (cr, mid_gray, mid_gray, mid_gray);
984 cairo_move_to (cr, frame_x, frame_y);
985 cairo_line_to (cr, frame_x2, frame_y);
986 cairo_move_to (cr, frame_x, frame_y);
987 cairo_line_to (cr, frame_x, frame_y2);
988 cairo_stroke (cr);
989
990 cairo_set_source_rgb (cr, darker_gray, darker_gray, darker_gray);
991 cairo_move_to (cr, frame_x2, frame_y);
992 cairo_line_to (cr, frame_x2, frame_y2);
993 cairo_move_to (cr, frame_x, frame_y2);
994 cairo_line_to (cr, frame_x2, frame_y2);
995 cairo_stroke (cr);
996
997 cairo_set_source_rgb (cr, light_gray, light_gray, light_gray);
998 cairo_move_to (cr, frame_x, frame_y);
999 cairo_line_to (cr, frame_x2, frame_y);
1000 cairo_move_to (cr, frame_x, frame_y);
1001 cairo_line_to (cr, frame_x, frame_y2);
1002 cairo_stroke (cr);
1003
1004 cairo_set_source_rgb (cr, dark_gray, dark_gray, dark_gray);
1005 cairo_move_to (cr, frame_x2, frame_y);
1006 cairo_line_to (cr, frame_x2, frame_y2);
1007 cairo_move_to (cr, frame_x, frame_y2);
1008 cairo_line_to (cr, frame_x2, frame_y2);
1009 cairo_stroke (cr);
1010
1011 cairo_restore (cr);
1012 }
1013
1014
1015 #define GOLDEN_RATIO 1.6180339887
1016 #define GOLDER_RATIO_FACTOR (GOLDEN_RATIO / (1.0 + 2.0 * GOLDEN_RATIO))
1017 #define GRID_STEP_1 10
1018 #define GRID_STEP_2 (GRID_STEP_1 * 5)
1019 #define GRID_STEP_3 (GRID_STEP_2 * 2)
1020 #define MAX_GRID_LINES 50
1021
1022
1023 void
_cairo_paint_grid(cairo_t * cr,cairo_rectangle_int_t * rectangle,GthGridType grid_type)1024 _cairo_paint_grid (cairo_t *cr,
1025 cairo_rectangle_int_t *rectangle,
1026 GthGridType grid_type)
1027 {
1028 double ux, uy;
1029
1030 cairo_save (cr);
1031
1032 ux = uy = 1.0;
1033 cairo_device_to_user_distance (cr, &ux, &uy);
1034 cairo_set_line_width (cr, MAX (ux, uy));
1035
1036 cairo_rectangle (cr, rectangle->x - ux + 0.5, rectangle->y - uy + 0.5, rectangle->width + (ux * 2), rectangle->height + (uy * 2));
1037 cairo_clip (cr);
1038
1039 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 9, 2)
1040 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
1041 #endif
1042
1043 cairo_rectangle (cr, rectangle->x + 0.5, rectangle->y + 0.5, rectangle->width - 0.5, rectangle->height - 0.5);
1044 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
1045 cairo_stroke (cr);
1046
1047 if (grid_type == GTH_GRID_NONE) {
1048 cairo_restore (cr);
1049 return;
1050 }
1051
1052 if (grid_type == GTH_GRID_THIRDS) {
1053 int i;
1054
1055 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.60);
1056 for (i = 1; i < 3; i++) {
1057 cairo_move_to (cr, rectangle->x + rectangle->width * i / 3 + 0.5, rectangle->y + 1.5);
1058 cairo_line_to (cr, rectangle->x + rectangle->width * i / 3 + 0.5, rectangle->y + rectangle->height - 0.5);
1059
1060 cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height * i / 3 + 0.5);
1061 cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height * i / 3 + 0.5);
1062 }
1063 cairo_stroke (cr);
1064
1065 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.10);
1066 for (i = 1; i < 9; i++) {
1067
1068 if (i % 3 == 0)
1069 continue;
1070
1071 cairo_move_to (cr, rectangle->x + rectangle->width * i / 9 + 0.5, rectangle->y + 1.5);
1072 cairo_line_to (cr, rectangle->x + rectangle->width * i / 9 + 0.5, rectangle->y + rectangle->height - 0.5);
1073
1074 cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height * i / 9 + 0.5);
1075 cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height * i / 9 + 0.5);
1076 }
1077 cairo_stroke (cr);
1078 }
1079 else if (grid_type == GTH_GRID_GOLDEN) {
1080 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.60);
1081
1082 int grid_x0, grid_x1, grid_x2, grid_x3;
1083 int grid_y0, grid_y1, grid_y2, grid_y3;
1084 int x_delta, y_delta;
1085
1086 grid_x0 = rectangle->x;
1087 grid_x3 = rectangle->x + rectangle->width;
1088
1089 grid_y0 = rectangle->y;
1090 grid_y3 = rectangle->y + rectangle->height;
1091
1092 x_delta = rectangle->width * GOLDER_RATIO_FACTOR;
1093 y_delta = rectangle->height * GOLDER_RATIO_FACTOR;
1094
1095 grid_x1 = grid_x0 + x_delta;
1096 grid_x2 = grid_x3 - x_delta;
1097 grid_y1 = grid_y0 + y_delta;
1098 grid_y2 = grid_y3 - y_delta;
1099
1100 cairo_move_to (cr, grid_x1 + 0.5, grid_y0 + 0.5);
1101 cairo_line_to (cr, grid_x1 + 0.5, grid_y3 + 0.5);
1102
1103 if (x_delta < rectangle->width / 2) {
1104 cairo_move_to (cr, grid_x2 + 0.5, grid_y0 + 0.5);
1105 cairo_line_to (cr, grid_x2 + 0.5, grid_y3 + 0.5);
1106 }
1107
1108 cairo_move_to (cr, grid_x0 + 0.5, grid_y1 + 0.5);
1109 cairo_line_to (cr, grid_x3 + 0.5, grid_y1 + 0.5);
1110
1111 if (y_delta < rectangle->height / 2) {
1112 cairo_move_to (cr, grid_x0 + 0.5, grid_y2 + 0.5);
1113 cairo_line_to (cr, grid_x3 + 0.5, grid_y2 + 0.5);
1114 }
1115
1116 cairo_stroke (cr);
1117 }
1118 else if (grid_type == GTH_GRID_CENTER) {
1119 int i;
1120
1121 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.60);
1122 cairo_move_to (cr, rectangle->x + rectangle->width / 2 + 0.5, rectangle->y + 1.5);
1123 cairo_line_to (cr, rectangle->x + rectangle->width / 2 + 0.5, rectangle->y + rectangle->height - 0.5);
1124 cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height / 2 + 0.5);
1125 cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height / 2 + 0.5);
1126 cairo_stroke (cr);
1127
1128 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.10);
1129 for (i = 1; i < 4; i++) {
1130
1131 if (i == 2)
1132 continue;
1133
1134 cairo_move_to (cr, rectangle->x + rectangle->width * i / 4 + 0.5, rectangle->y + 1.5);
1135 cairo_line_to (cr, rectangle->x + rectangle->width * i / 4 + 0.5, rectangle->y + rectangle->height - 0.5);
1136 cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + rectangle->height * i / 4 + 0.5);
1137 cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + rectangle->height * i / 4 + 0.5);
1138 }
1139 cairo_stroke (cr);
1140 }
1141 else if (grid_type == GTH_GRID_UNIFORM) {
1142
1143 int x;
1144 int y;
1145
1146 if (rectangle->width / GRID_STEP_3 <= MAX_GRID_LINES) {
1147 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.40);
1148 for (x = GRID_STEP_3; x < rectangle->width; x += GRID_STEP_3) {
1149 cairo_move_to (cr, rectangle->x + x + 0.5, rectangle->y + 1.5);
1150 cairo_line_to (cr, rectangle->x + x + 0.5, rectangle->y + rectangle->height - 0.5);
1151 }
1152 for (y = GRID_STEP_3; y < rectangle->height; y += GRID_STEP_3) {
1153 cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + y + 0.5);
1154 cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + y + 0.5);
1155 }
1156 cairo_stroke (cr);
1157 }
1158
1159 if (rectangle->width / GRID_STEP_2 <= MAX_GRID_LINES) {
1160 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.20);
1161 for (x = GRID_STEP_2; x < rectangle->width; x += GRID_STEP_2) {
1162 if (x % GRID_STEP_3 == 0)
1163 continue;
1164 cairo_move_to (cr, rectangle->x + x + 0.5, rectangle->y + 1.5);
1165 cairo_line_to (cr, rectangle->x + x + 0.5, rectangle->y + rectangle->height - 0.5);
1166 }
1167 for (y = GRID_STEP_2; y < rectangle->height; y += GRID_STEP_2) {
1168 if (y % GRID_STEP_3 == 0)
1169 continue;
1170 cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + y + 0.5);
1171 cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + y + 0.5);
1172 }
1173 cairo_stroke (cr);
1174 }
1175
1176 if (rectangle->width / GRID_STEP_1 <= MAX_GRID_LINES) {
1177 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.10);
1178 for (x = GRID_STEP_1; x < rectangle->width; x += GRID_STEP_1) {
1179 if (x % GRID_STEP_2 == 0)
1180 continue;
1181 cairo_move_to (cr, rectangle->x + x + 0.5, rectangle->y + 1.5);
1182 cairo_line_to (cr, rectangle->x + x + 0.5, rectangle->y + rectangle->height - 0.5);
1183 }
1184 for (y = GRID_STEP_1; y < rectangle->height; y += GRID_STEP_1) {
1185 if (y % GRID_STEP_2 == 0)
1186 continue;
1187 cairo_move_to (cr, rectangle->x + 1.5, rectangle->y + y + 0.5);
1188 cairo_line_to (cr, rectangle->x + rectangle->width - 0.5, rectangle->y + y + 0.5);
1189 }
1190 }
1191 cairo_stroke (cr);
1192 }
1193
1194 cairo_restore (cr);
1195 }
1196
1197
1198 cairo_pattern_t *
_cairo_create_checked_pattern(int size)1199 _cairo_create_checked_pattern (int size)
1200 {
1201 int h_size;
1202 cairo_surface_t *surface;
1203 cairo_t *ctx;
1204 cairo_pattern_t *pattern;
1205
1206 h_size = size / 2;
1207 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, size, size);
1208 ctx = cairo_create (surface);
1209
1210 cairo_set_source_rgba (ctx, 0.4, 0.4, 0.4, 1.0);
1211 cairo_rectangle (ctx, 0, 0, h_size, h_size);
1212 cairo_fill (ctx);
1213 cairo_rectangle (ctx, h_size, h_size, h_size, h_size);
1214 cairo_fill (ctx);
1215
1216 cairo_set_source_rgba (ctx, 0.5, 0.5, 0.5, 1.0);
1217 cairo_rectangle (ctx, h_size, 0, h_size, h_size);
1218 cairo_fill (ctx);
1219 cairo_rectangle (ctx, 0, h_size, h_size, h_size);
1220 cairo_fill (ctx);
1221
1222 pattern = cairo_pattern_create_for_surface (surface);
1223 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
1224
1225 cairo_surface_destroy (surface);
1226 cairo_destroy (ctx);
1227
1228 return pattern;
1229 }
1230
1231
1232 void
_cairo_draw_thumbnail_frame(cairo_t * cr,int x,int y,int width,int height)1233 _cairo_draw_thumbnail_frame (cairo_t *cr,
1234 int x,
1235 int y,
1236 int width,
1237 int height)
1238 {
1239 cairo_save (cr);
1240 cairo_translate (cr, 0.5, 0.5);
1241 cairo_set_line_width (cr, 0.5);
1242 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
1243
1244 /* the drop shadow */
1245
1246 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.33);
1247 _cairo_draw_rounded_box (cr,
1248 x + 2,
1249 y + 2,
1250 width - 1,
1251 height - 1,
1252 0);
1253 cairo_fill (cr);
1254
1255 /* the outer frame */
1256
1257 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
1258 _cairo_draw_rounded_box (cr,
1259 x,
1260 y,
1261 width - 1,
1262 height - 1,
1263 0);
1264 cairo_fill_preserve (cr);
1265
1266 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.55);
1267 cairo_stroke (cr);
1268
1269 cairo_restore (cr);
1270 }
1271
1272
1273 void
_cairo_draw_film_background(cairo_t * cr,int x,int y,int width,int height)1274 _cairo_draw_film_background (cairo_t *cr,
1275 int x,
1276 int y,
1277 int width,
1278 int height)
1279 {
1280 cairo_save (cr);
1281
1282 /* the drop shadow */
1283
1284 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.33);
1285 cairo_rectangle (cr,
1286 x + 2,
1287 y + 2,
1288 width,
1289 height);
1290 cairo_fill (cr);
1291
1292 /* dark background */
1293
1294 cairo_set_source_rgb (cr, 0.1, 0.1, 0.1);
1295 cairo_rectangle (cr,
1296 x,
1297 y ,
1298 width,
1299 height);
1300 cairo_fill (cr);
1301
1302 cairo_restore (cr);
1303 }
1304
1305
1306 static cairo_pattern_t *
_cairo_film_pattern_create(void)1307 _cairo_film_pattern_create (void)
1308 {
1309 static cairo_pattern_t *film_pattern = NULL;
1310 cairo_pattern_t *pattern;
1311 static GMutex mutex;
1312
1313 g_mutex_lock (&mutex);
1314 if (film_pattern == NULL) {
1315 char *filename;
1316 cairo_surface_t *surface;
1317
1318 filename = g_build_filename (GTHUMB_ICON_DIR, "filmholes.png", NULL);
1319 surface = cairo_image_surface_create_from_png (filename);
1320 film_pattern = cairo_pattern_create_for_surface (surface);
1321 cairo_pattern_set_filter (film_pattern, CAIRO_FILTER_GOOD);
1322 cairo_pattern_set_extend (film_pattern, CAIRO_EXTEND_REPEAT);
1323
1324 cairo_surface_destroy (surface);
1325 g_free (filename);
1326
1327 }
1328 pattern = cairo_pattern_reference (film_pattern);
1329 g_mutex_unlock (&mutex);
1330
1331 return pattern;
1332 }
1333
1334
1335 void
_cairo_draw_film_foreground(cairo_t * cr,int x,int y,int width,int height,int thumbnail_size)1336 _cairo_draw_film_foreground (cairo_t *cr,
1337 int x,
1338 int y,
1339 int width,
1340 int height,
1341 int thumbnail_size)
1342 {
1343 cairo_pattern_t *pattern;
1344 double film_scale;
1345 cairo_matrix_t matrix;
1346 double film_strip;
1347
1348 /* left film strip */
1349
1350 pattern = _cairo_film_pattern_create ();
1351
1352 if (thumbnail_size > 128)
1353 film_scale = 256.0 / thumbnail_size;
1354 else
1355 film_scale = 128.0 / thumbnail_size;
1356 film_strip = 9.0 / film_scale;
1357
1358 cairo_matrix_init_identity (&matrix);
1359 cairo_matrix_scale (&matrix, film_scale, film_scale);
1360 cairo_matrix_translate (&matrix, -x, 0);
1361 cairo_pattern_set_matrix (pattern, &matrix);
1362 cairo_set_source (cr, pattern);
1363 cairo_rectangle (cr,
1364 x,
1365 y,
1366 film_strip,
1367 height);
1368 cairo_fill (cr);
1369
1370 /* right film strip */
1371
1372 x = x + width - film_strip;
1373 cairo_matrix_init_identity (&matrix);
1374 cairo_matrix_scale (&matrix, film_scale, film_scale);
1375 cairo_matrix_translate (&matrix, -x, 0);
1376 cairo_pattern_set_matrix (pattern, &matrix);
1377 cairo_set_source (cr, pattern);
1378 cairo_rectangle (cr,
1379 x,
1380 y,
1381 film_strip,
1382 height);
1383 cairo_fill (cr);
1384
1385 cairo_pattern_destroy (pattern);
1386 }
1387
1388
1389 #define DRAG_ICON_THUMBNAIL_OFFSET 4
1390
1391
1392 cairo_surface_t *
_cairo_create_dnd_icon(cairo_surface_t * image,int icon_size,ItemStyle style,gboolean multi_dnd)1393 _cairo_create_dnd_icon (cairo_surface_t *image,
1394 int icon_size,
1395 ItemStyle style,
1396 gboolean multi_dnd)
1397 {
1398 cairo_rectangle_int_t thumbnail_rect;
1399 cairo_surface_t *thumbnail;
1400 cairo_rectangle_int_t icon_rect;
1401 int icon_padding;
1402 cairo_rectangle_int_t frame_rect;
1403 cairo_surface_t *icon;
1404 cairo_t *cr;
1405
1406 thumbnail_rect.width = cairo_image_surface_get_width (image);
1407 thumbnail_rect.height = cairo_image_surface_get_height (image);
1408 if (scale_keeping_ratio (&thumbnail_rect.width, &thumbnail_rect.height, icon_size, icon_size, FALSE))
1409 thumbnail = _cairo_image_surface_scale_fast (image, thumbnail_rect.width, thumbnail_rect.height);
1410 else
1411 thumbnail = cairo_surface_reference (image);
1412
1413 switch (style) {
1414 case ITEM_STYLE_ICON:
1415 icon_padding = 8;
1416 icon_rect.width = icon_size + icon_padding;
1417 icon_rect.height = icon_size + icon_padding;
1418 thumbnail_rect.x = round ((double) (icon_rect.width - thumbnail_rect.width) / 2.0);
1419 thumbnail_rect.y = round ((double) (icon_rect.height - thumbnail_rect.height) / 2.0);
1420 frame_rect.x = 0;
1421 frame_rect.y = 0;
1422 frame_rect.width = icon_rect.width;
1423 frame_rect.height = icon_rect.height;
1424 break;
1425
1426 case ITEM_STYLE_IMAGE:
1427 icon_padding = 8; /* padding for the frame border */
1428 icon_rect.width = thumbnail_rect.width + icon_padding;
1429 icon_rect.height = thumbnail_rect.height + icon_padding;
1430 thumbnail_rect.x = 3;
1431 thumbnail_rect.y = 3;
1432 frame_rect.x = 0;
1433 frame_rect.y = 0;
1434 frame_rect.width = thumbnail_rect.width + icon_padding - 2;
1435 frame_rect.height = thumbnail_rect.height + icon_padding - 2;
1436 break;
1437
1438 case ITEM_STYLE_VIDEO:
1439 icon_padding = 4; /* padding for the drop shadow effect */
1440 icon_rect.width = thumbnail_rect.width + icon_padding;
1441 icon_rect.height = icon_size + icon_padding;
1442 thumbnail_rect.x = 0;
1443 thumbnail_rect.y = round ((double) (icon_size - thumbnail_rect.height) / 2.0);
1444 frame_rect.x = thumbnail_rect.x;
1445 frame_rect.y = 0;
1446 frame_rect.width = thumbnail_rect.width;
1447 frame_rect.height = icon_size;
1448 break;
1449 }
1450
1451 if (multi_dnd) {
1452 icon_rect.width += DRAG_ICON_THUMBNAIL_OFFSET;
1453 icon_rect.height += DRAG_ICON_THUMBNAIL_OFFSET;
1454 }
1455 icon = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, icon_rect.width, icon_rect.height);
1456 cr = cairo_create (icon);
1457
1458 switch (style) {
1459 case ITEM_STYLE_ICON:
1460 cairo_save (cr);
1461 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.2);
1462 _cairo_draw_rounded_box (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height, 4);
1463 cairo_fill (cr);
1464 cairo_restore (cr);
1465 break;
1466
1467 case ITEM_STYLE_IMAGE:
1468 if (multi_dnd)
1469 _cairo_draw_thumbnail_frame (cr, frame_rect.x + DRAG_ICON_THUMBNAIL_OFFSET, frame_rect.y + DRAG_ICON_THUMBNAIL_OFFSET, frame_rect.width, frame_rect.height);
1470 _cairo_draw_thumbnail_frame (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height);
1471 break;
1472
1473 case ITEM_STYLE_VIDEO:
1474 _cairo_draw_film_background (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height);
1475 break;
1476 }
1477
1478 cairo_save (cr);
1479 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
1480 cairo_set_source_surface (cr, thumbnail, thumbnail_rect.x, thumbnail_rect.y);
1481 cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
1482 cairo_rectangle (cr, thumbnail_rect.x, thumbnail_rect.y, thumbnail_rect.width, thumbnail_rect.height);
1483 cairo_fill (cr);
1484 cairo_restore (cr);
1485
1486 if (style == ITEM_STYLE_VIDEO)
1487 _cairo_draw_film_foreground (cr, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height, icon_size);
1488
1489 cairo_surface_set_device_offset (icon, -icon_rect.width / 2, -icon_rect.height / 2);
1490
1491 cairo_surface_destroy (thumbnail);
1492 cairo_destroy (cr);
1493
1494 return icon;
1495 }
1496