Index: src/cairo-pdf-surface.c =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-pdf-surface.c,v retrieving revision 1.58 diff -u -r1.58 cairo-pdf-surface.c --- src/cairo-pdf-surface.c 19 Aug 2005 21:05:14 -0000 1.58 +++ src/cairo-pdf-surface.c 3 Oct 2005 14:01:34 -0000 @@ -51,8 +51,8 @@ * could add generation counters to surfaces and remember the stream * ID for a particular generation for a particular surface. * - * - Multi stop gradients. What are the exponential interpolation - * functions, could they be used for gradients? + * - Multi stop gradients. Need to fix support for non-regular spacing + * using Type 3 (Stiching) Functions. * * - Clipping: must be able to reset clipping * @@ -843,13 +843,34 @@ _cairo_surface_release_source_image (pattern->surface, image, image_extra); } -static unsigned int +typedef struct _cairo_pdf_color_stop { + cairo_fixed_t offset; + int id; + unsigned char color_char[4]; +} cairo_pdf_color_stop_t; + +static int +_cairo_pdf_color_stop_compare (const void *elem1, const void *elem2) +{ + cairo_pdf_color_stop_t *s1 = (cairo_pdf_color_stop_t *) elem1; + cairo_pdf_color_stop_t *s2 = (cairo_pdf_color_stop_t *) elem2; + + return + (s1->offset == s2->offset) ? + /* equal offsets, sort on id */ + ((s1->id < s2->id) ? -1 : 1) : + /* sort on offset */ + ((s1->offset < s2->offset) ? -1 : 1); +} + +static int emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; cairo_output_stream_t *output = document->output_stream; unsigned int function_id; - char stops[2][3]; + cairo_pdf_color_stop_t *stops; + int i; function_id = _cairo_pdf_document_new_object (document); @@ -857,22 +878,41 @@ "%d 0 obj\r\n" "<< /FunctionType 0\r\n" " /Domain [ 0.0 1.0 ]\r\n" - " /Size [ 2 ]\r\n" + " /Size [ %d ]\r\n" " /BitsPerSample 8\r\n" " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n" - " /Length 6\r\n" + " /Length %d\r\n" ">>\r\n" "stream\r\n", - function_id); + function_id, + pattern->n_stops, + pattern->n_stops * 3); - stops[0][0] = pattern->stops[0].color.red * 0xff + 0.5; - stops[0][1] = pattern->stops[0].color.green * 0xff + 0.5; - stops[0][2] = pattern->stops[0].color.blue * 0xff + 0.5; - stops[1][0] = pattern->stops[1].color.red * 0xff + 0.5; - stops[1][1] = pattern->stops[1].color.green * 0xff + 0.5; - stops[1][2] = pattern->stops[1].color.blue * 0xff + 0.5; - - _cairo_output_stream_write (output, stops, sizeof (stops)); + stops = malloc(pattern->n_stops * sizeof(cairo_pdf_color_stop_t)); + if (!stops) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return -CAIRO_STATUS_NO_MEMORY; + } + + for (i = 0; i < pattern->n_stops; i++) + { + stops[i].color_char[0] = pattern->stops[i].color.red * 0xff + 0.5; + stops[i].color_char[1] = pattern->stops[i].color.green * 0xff + 0.5; + stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff + 0.5; + stops[i].color_char[3] = pattern->stops[i].color.alpha * 0xff + 0.5; + stops[i].offset = pattern->stops[i].offset; + stops[i].id = i; + } + + /* sort stops in ascending order */ + qsort (stops, pattern->n_stops, sizeof (cairo_pdf_color_stop_t), + _cairo_pdf_color_stop_compare); + + for (i = 0; i < pattern->n_stops; i++) + { + _cairo_output_stream_write (output, stops[i].color_char, 3); + } + free(stops); _cairo_output_stream_printf (output, "\r\n" @@ -882,7 +922,7 @@ return function_id; } -static void +static cairo_status_t emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; @@ -894,6 +934,8 @@ _cairo_pdf_document_close_stream (document); function_id = emit_pattern_stops (surface, &pattern->base); + if (function_id < 0) + return -function_id; p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); @@ -934,9 +976,10 @@ _cairo_output_stream_printf (output, "/Pattern cs /res%d scn /a%d gs\r\n", pattern_id, alpha); + return CAIRO_STATUS_SUCCESS; } -static void +static int emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; @@ -948,6 +991,8 @@ _cairo_pdf_document_close_stream (document); function_id = emit_pattern_stops (surface, &pattern->base); + if (function_id < 0) + return function_id; p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); @@ -1001,9 +1046,10 @@ _cairo_output_stream_printf (output, "/Pattern cs /res%d scn /a%d gs\r\n", pattern_id, alpha); + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) { switch (pattern->type) { @@ -1016,13 +1062,14 @@ break; case CAIRO_PATTERN_LINEAR: - emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); + return emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); break; case CAIRO_PATTERN_RADIAL: - emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); + return emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); break; } + return CAIRO_STATUS_SUCCESS; } static double @@ -1121,7 +1168,9 @@ cairo_status_t status; pdf_path_info_t info; - emit_pattern (surface, pattern); + status = emit_pattern (surface, pattern); + if (status) + return status; /* After the above switch the current stream should belong to this * surface, so no need to _cairo_pdf_surface_ensure_stream() */ @@ -1174,9 +1223,12 @@ cairo_pdf_surface_t *surface = abstract_dst; cairo_pdf_document_t *document = surface->document; cairo_output_stream_t *output = document->output_stream; + cairo_int_status_t status; int i; - emit_pattern (surface, pattern); + status = emit_pattern (surface, pattern); + if (status) + return status; /* After the above switch the current stream should belong to this * surface, so no need to _cairo_pdf_surface_ensure_stream() */ @@ -1305,6 +1357,7 @@ cairo_pdf_document_t *document = surface->document; cairo_output_stream_t *output = document->output_stream; cairo_font_subset_t *pdf_font; + cairo_int_status_t status; int i, index; double det; @@ -1323,7 +1376,9 @@ if (fabs (det) < 0.000001) return CAIRO_STATUS_SUCCESS; - emit_pattern (surface, pattern); + status = emit_pattern (surface, pattern); + if (status) + return status; _cairo_output_stream_printf (output, "BT /res%u 1 Tf", pdf_font->font_id);