/* Swfdec * Copyright (C) 2006-2007 Benjamin Otte * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "swfdec_gradient_pattern.h" #include "swfdec_color.h" #include "swfdec_debug.h" #include "swfdec_path.h" G_DEFINE_TYPE (SwfdecGradientPattern, swfdec_gradient_pattern, SWFDEC_TYPE_PATTERN); static void swfdec_gradient_pattern_morph (SwfdecDraw *dest, SwfdecDraw *source, guint ratio) { guint i; SwfdecGradientPattern *dpattern = SWFDEC_GRADIENT_PATTERN (dest); SwfdecGradientPattern *spattern = SWFDEC_GRADIENT_PATTERN (source); g_return_if_fail (spattern->end_gradient != NULL); dpattern->radial = spattern->radial; dpattern->focus = spattern->focus; dpattern->extend = spattern->extend; dpattern->n_gradients = spattern->n_gradients; for (i = 0; i < spattern->n_gradients; i++) { dpattern->gradient[i].color = swfdec_color_apply_morph (spattern->gradient[i].color, spattern->end_gradient[i].color, ratio); dpattern->gradient[i].ratio = (spattern->gradient[i].ratio * (65535 - ratio) + spattern->end_gradient[i].ratio * ratio) / 65535; dpattern->end_gradient[i].color = dpattern->gradient[i].color; dpattern->end_gradient[i].color = dpattern->gradient[i].color; } SWFDEC_DRAW_CLASS (swfdec_gradient_pattern_parent_class)->morph (dest, source, ratio); } static cairo_pattern_t * swfdec_gradient_pattern_get_pattern (SwfdecPattern *pat, SwfdecRenderer *renderer, const SwfdecColorTransform *trans) { guint i, ratio; cairo_pattern_t *pattern; SwfdecColor color; double offset; SwfdecGradientPattern *gradient = SWFDEC_GRADIENT_PATTERN (pat); if (gradient->n_gradients == 0) { /* cairo interprets an empty gradient as translucent, not as solid black */ return cairo_pattern_create_rgb (0, 0, 0); } #if 0 /* use this when https://bugs.freedesktop.org/show_bug.cgi?id=8341 is fixed */ if (gradient->radial) pattern = cairo_pattern_create_radial (0, 0, 0, 0, 0, 16384); else pattern = cairo_pattern_create_linear (-16384.0, 0, 16384.0, 0); cairo_pattern_set_matrix (pattern, &pat->transform); #else { cairo_matrix_t mat = pat->transform; if (gradient->radial) { pattern = cairo_pattern_create_radial ((16384.0 / 256.0) * gradient->focus, 0, 0, 0, 0, 16384 / 256.0); } else { pattern = cairo_pattern_create_linear (-16384.0 / 256.0, 0, 16384.0 / 256.0, 0); } cairo_matrix_scale (&mat, 1 / 256.0, 1 / 256.0); mat.x0 /= 256.0; mat.y0 /= 256.0; cairo_pattern_set_matrix (pattern, &mat); } #endif cairo_pattern_set_extend (pattern, gradient->extend); /* we check here that ratios increase linearly, because both gradients parsed * from the SWF and gradients created with beginGradientFill have this * behavior */ ratio = 0; for (i = 0; i < gradient->n_gradients; i++){ color = swfdec_color_apply_transform (gradient->gradient[i].color, trans); ratio = MAX (ratio, gradient->gradient[i].ratio); offset = ratio / 255.0; cairo_pattern_add_color_stop_rgba (pattern, offset, SWFDEC_COLOR_RED (color) / 255.0, SWFDEC_COLOR_GREEN (color) / 255.0, SWFDEC_COLOR_BLUE (color) / 255.0, SWFDEC_COLOR_ALPHA (color) / 255.0); if (++ratio > 255) break; } return pattern; } static void swfdec_gradient_pattern_class_init (SwfdecGradientPatternClass *klass) { SWFDEC_DRAW_CLASS (klass)->morph = swfdec_gradient_pattern_morph; SWFDEC_PATTERN_CLASS (klass)->get_pattern = swfdec_gradient_pattern_get_pattern; } static void swfdec_gradient_pattern_init (SwfdecGradientPattern *gradient) { gradient->extend = CAIRO_EXTEND_PAD; } SwfdecDraw * swfdec_gradient_pattern_new (void) { return g_object_new (SWFDEC_TYPE_GRADIENT_PATTERN, NULL); }