mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-08 07:58:02 +02:00
PS: Add meta surface pattern support
This commit is contained in:
parent
e5b01e6797
commit
8520ce31be
3 changed files with 176 additions and 92 deletions
|
|
@ -262,16 +262,7 @@ static cairo_boilerplate_target_t targets[] =
|
|||
_cairo_boilerplate_ps_surface_write_to_png,
|
||||
_cairo_boilerplate_ps_cleanup,
|
||||
NULL, TRUE },
|
||||
|
||||
/* XXX: We expect type image here only due to a limitation in
|
||||
* the current PS/meta-surface code. A PS surface is
|
||||
* "naturally" COLOR_ALPHA, so the COLOR-only variant goes
|
||||
* through create_similar in _cairo_boilerplate_ps_create_surface which results
|
||||
* in the similar surface being used as a source. We do not yet
|
||||
* have source support for PS/meta-surfaces, so the
|
||||
* create_similar path for all paginated surfaces currently
|
||||
* returns an image surface.*/
|
||||
{ "ps", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
|
||||
{ "ps", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
|
||||
_cairo_boilerplate_ps_create_surface,
|
||||
_cairo_boilerplate_ps_surface_write_to_png,
|
||||
_cairo_boilerplate_ps_cleanup,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ typedef struct cairo_ps_surface {
|
|||
cairo_output_stream_t *stream;
|
||||
|
||||
cairo_bool_t eps;
|
||||
|
||||
cairo_content_t content;
|
||||
double width;
|
||||
double height;
|
||||
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
|
||||
|
|
|
|||
|
|
@ -844,6 +844,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
|
|||
surface->height = height;
|
||||
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
|
||||
surface->force_fallbacks = FALSE;
|
||||
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
|
||||
|
||||
surface->num_pages = 0;
|
||||
|
||||
|
|
@ -1288,6 +1289,15 @@ cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
|
|||
}
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
_cairo_ps_surface_create_similar (void *abstract_surface,
|
||||
cairo_content_t content,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
return _cairo_meta_surface_create (content, width, height);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_finish (void *abstract_surface)
|
||||
{
|
||||
|
|
@ -1379,6 +1389,9 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
|
|||
{
|
||||
cairo_extend_t extend;
|
||||
|
||||
if (_cairo_surface_is_meta (pattern->surface))
|
||||
return TRUE;
|
||||
|
||||
if (pattern->surface->backend->acquire_source_image == NULL)
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -1434,12 +1447,20 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
|
|||
if (! pattern_supported (pattern))
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (!(op == CAIRO_OPERATOR_SOURCE ||
|
||||
op == CAIRO_OPERATOR_OVER))
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
||||
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
|
||||
if ( _cairo_surface_is_meta (surface_pattern->surface)) {
|
||||
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
|
||||
}
|
||||
}
|
||||
|
||||
if (op == CAIRO_OPERATOR_SOURCE)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (op != CAIRO_OPERATOR_OVER)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
/* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
|
||||
* the pattern contains transparency, we return
|
||||
* CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
|
||||
|
|
@ -1613,12 +1634,20 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
|
|||
cairo_output_stream_t *base85_stream, *string_array_stream;
|
||||
|
||||
/* PostScript can not represent the alpha channel, so we blend the
|
||||
current image over a white RGB surface to eliminate it. */
|
||||
current image over a white (or black for CONTENT_COLOR
|
||||
surfaces) RGB surface to eliminate it. */
|
||||
|
||||
if (image->base.status)
|
||||
return image->base.status;
|
||||
|
||||
if (image->format != CAIRO_FORMAT_RGB24) {
|
||||
const cairo_color_t *background_color;
|
||||
|
||||
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
|
||||
background_color = CAIRO_COLOR_WHITE;
|
||||
else
|
||||
background_color = CAIRO_COLOR_BLACK;
|
||||
|
||||
opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
|
||||
image->width,
|
||||
image->height);
|
||||
|
|
@ -1632,7 +1661,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
|
|||
|
||||
status = _cairo_surface_fill_rectangle (opaque,
|
||||
CAIRO_OPERATOR_SOURCE,
|
||||
CAIRO_COLOR_WHITE,
|
||||
background_color,
|
||||
0, 0,
|
||||
image->width, image->height);
|
||||
if (status) {
|
||||
|
|
@ -1753,6 +1782,79 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
|
|||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_emit_image_surface (cairo_ps_surface_t *surface,
|
||||
cairo_surface_pattern_t *pattern,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
cairo_image_surface_t *image;
|
||||
void *image_extra;
|
||||
cairo_status_t status;
|
||||
|
||||
status = _cairo_surface_acquire_source_image (pattern->surface,
|
||||
&image,
|
||||
&image_extra);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_ps_surface_emit_image (surface, image, "CairoPattern");
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
*width = image->width;
|
||||
*height = image->height;
|
||||
|
||||
fail:
|
||||
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
|
||||
cairo_surface_t *meta_surface)
|
||||
{
|
||||
double old_width, old_height;
|
||||
cairo_content_t old_content;
|
||||
cairo_rectangle_int_t meta_extents;
|
||||
cairo_status_t status;
|
||||
|
||||
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
old_content = surface->content;
|
||||
old_width = surface->width;
|
||||
old_height = surface->height;
|
||||
surface->width = meta_extents.width;
|
||||
surface->height = meta_extents.height;
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"/CairoPattern {\n"
|
||||
"gsave\n");
|
||||
|
||||
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
|
||||
surface->content = CAIRO_CONTENT_COLOR;
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"0 G 0 0 %f %f rectfill\n",
|
||||
surface->width,
|
||||
surface->height);
|
||||
}
|
||||
|
||||
status = _cairo_meta_surface_replay (meta_surface, &surface->base);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"grestore\n"
|
||||
"} bind def\n");
|
||||
surface->content = old_content;
|
||||
surface->width = old_width;
|
||||
surface->height = old_height;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
|
||||
cairo_solid_pattern_t *pattern)
|
||||
|
|
@ -1765,11 +1867,17 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
|
|||
blue = color->blue;
|
||||
|
||||
if (!CAIRO_COLOR_IS_OPAQUE(color)) {
|
||||
uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
|
||||
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
|
||||
uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
|
||||
|
||||
red = ((color->red_short >> 8) + one_minus_alpha) / 255.0;
|
||||
green = ((color->green_short >> 8) + one_minus_alpha) / 255.0;
|
||||
blue = ((color->blue_short >> 8) + one_minus_alpha) / 255.0;
|
||||
red = ((color->red_short >> 8) + one_minus_alpha) / 255.0;
|
||||
green = ((color->green_short >> 8) + one_minus_alpha) / 255.0;
|
||||
blue = ((color->blue_short >> 8) + one_minus_alpha) / 255.0;
|
||||
} else {
|
||||
red = (color->red_short >> 8) / 255.0;
|
||||
green = (color->green_short >> 8) / 255.0;
|
||||
blue = (color->blue_short >> 8) / 255.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (color_is_gray (color))
|
||||
|
|
@ -1787,7 +1895,8 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
|
|||
cairo_surface_pattern_t *pattern)
|
||||
{
|
||||
cairo_status_t status;
|
||||
double bbox_width, bbox_height;
|
||||
int pattern_width = 0; /* squelch bogus compiler warning */
|
||||
int pattern_height = 0; /* squelch bogus compiler warning */
|
||||
double xstep, ystep;
|
||||
cairo_matrix_t inverse = pattern->base.matrix;
|
||||
|
||||
|
|
@ -1796,97 +1905,81 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
|
|||
assert (status == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
if (_cairo_surface_is_meta (pattern->surface)) {
|
||||
_cairo_output_stream_printf (surface->stream, "/MyPattern {\n");
|
||||
cairo_surface_t *meta_surface = pattern->surface;
|
||||
cairo_rectangle_int_t pattern_extents;
|
||||
|
||||
status = _cairo_meta_surface_replay (pattern->surface, &surface->base);
|
||||
status = _cairo_ps_surface_emit_meta_surface (surface,
|
||||
meta_surface);
|
||||
status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
bbox_width = surface->width;
|
||||
bbox_height = surface->height;
|
||||
xstep = surface->width;
|
||||
ystep = surface->height;
|
||||
_cairo_output_stream_printf (surface->stream, "} bind def\n");
|
||||
pattern_width = pattern_extents.width;
|
||||
pattern_height = pattern_extents.height;
|
||||
} else {
|
||||
cairo_image_surface_t *image;
|
||||
void *image_extra;
|
||||
cairo_status_t status;
|
||||
|
||||
status = _cairo_surface_acquire_source_image (pattern->surface,
|
||||
&image,
|
||||
&image_extra);
|
||||
status = _cairo_ps_surface_emit_image_surface (surface,
|
||||
pattern,
|
||||
&pattern_width,
|
||||
&pattern_height);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
status = _cairo_ps_surface_emit_image (surface, image, "MyPattern");
|
||||
if (status) {
|
||||
_cairo_surface_release_source_image (pattern->surface,
|
||||
image, image_extra);
|
||||
return status;
|
||||
}
|
||||
|
||||
bbox_width = image->width;
|
||||
bbox_height = image->height;
|
||||
|
||||
switch (pattern->base.extend) {
|
||||
switch (pattern->base.extend) {
|
||||
/* We implement EXTEND_PAD like EXTEND_NONE for now */
|
||||
case CAIRO_EXTEND_PAD:
|
||||
case CAIRO_EXTEND_NONE:
|
||||
{
|
||||
/* In PS/PDF, (as far as I can tell), all patterns are
|
||||
* repeating. So we support cairo's EXTEND_NONE semantics
|
||||
* by setting the repeat step size to a size large enough
|
||||
* to guarantee that no more than a single occurrence will
|
||||
* be visible.
|
||||
*
|
||||
* First, map the surface extents into pattern space (since
|
||||
* xstep and ystep are in pattern space). Then use an upper
|
||||
* bound on the length of the diagonal of the pattern image
|
||||
* and the surface as repeat size. This guarantees to never
|
||||
* repeat visibly.
|
||||
*/
|
||||
double x1 = 0.0, y1 = 0.0;
|
||||
double x2 = surface->width, y2 = surface->height;
|
||||
_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
|
||||
&x1, &y1, &x2, &y2,
|
||||
NULL);
|
||||
case CAIRO_EXTEND_PAD:
|
||||
case CAIRO_EXTEND_NONE:
|
||||
{
|
||||
/* In PS/PDF, (as far as I can tell), all patterns are
|
||||
* repeating. So we support cairo's EXTEND_NONE semantics
|
||||
* by setting the repeat step size to a size large enough
|
||||
* to guarantee that no more than a single occurrence will
|
||||
* be visible.
|
||||
*
|
||||
* First, map the surface extents into pattern space (since
|
||||
* xstep and ystep are in pattern space). Then use an upper
|
||||
* bound on the length of the diagonal of the pattern image
|
||||
* and the surface as repeat size. This guarantees to never
|
||||
* repeat visibly.
|
||||
*/
|
||||
double x1 = 0.0, y1 = 0.0;
|
||||
double x2 = surface->width, y2 = surface->height;
|
||||
_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
|
||||
&x1, &y1, &x2, &y2,
|
||||
NULL);
|
||||
|
||||
/* Rather than computing precise bounds of the union, just
|
||||
* add the surface extents unconditionally. We only
|
||||
* required an answer that's large enough, we don't really
|
||||
* care if it's not as tight as possible.*/
|
||||
xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
|
||||
image->width + image->height);
|
||||
break;
|
||||
}
|
||||
case CAIRO_EXTEND_REPEAT:
|
||||
case CAIRO_EXTEND_REFLECT:
|
||||
xstep = image->width;
|
||||
ystep = image->height;
|
||||
break;
|
||||
/* Rather than computing precise bounds of the union, just
|
||||
* add the surface extents unconditionally. We only
|
||||
* required an answer that's large enough, we don't really
|
||||
* care if it's not as tight as possible.*/
|
||||
xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
|
||||
pattern_width + pattern_height);
|
||||
break;
|
||||
}
|
||||
case CAIRO_EXTEND_REPEAT:
|
||||
case CAIRO_EXTEND_REFLECT:
|
||||
xstep = pattern_width;
|
||||
ystep = pattern_height;
|
||||
break;
|
||||
/* All the rest (if any) should have been analyzed away, so these
|
||||
* cases should be unreachable. */
|
||||
default:
|
||||
ASSERT_NOT_REACHED;
|
||||
xstep = 0;
|
||||
ystep = 0;
|
||||
}
|
||||
|
||||
_cairo_surface_release_source_image (pattern->surface,
|
||||
image, image_extra);
|
||||
default:
|
||||
ASSERT_NOT_REACHED;
|
||||
xstep = 0;
|
||||
ystep = 0;
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"<< /PatternType 1\n"
|
||||
" /PaintType 1\n"
|
||||
" /TilingType 1\n");
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
" /BBox [0 0 %f %f]\n",
|
||||
bbox_width, bbox_height);
|
||||
" /BBox [0 0 %d %d]\n",
|
||||
pattern_width, pattern_height);
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
" /XStep %f /YStep %f\n",
|
||||
xstep, ystep);
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
" /PaintProc { MyPattern } bind\n"
|
||||
" /PaintProc { CairoPattern } bind\n"
|
||||
">>\n");
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"[ %f %f %f %f %f %f ]\n",
|
||||
|
|
@ -2527,7 +2620,7 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
|
|||
|
||||
static const cairo_surface_backend_t cairo_ps_surface_backend = {
|
||||
CAIRO_SURFACE_TYPE_PS,
|
||||
NULL, /* create_similar */
|
||||
_cairo_ps_surface_create_similar,
|
||||
_cairo_ps_surface_finish,
|
||||
NULL, /* acquire_source_image */
|
||||
NULL, /* release_source_image */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue