1072
* cairo_ps_surface_restrict_to_level:
1073
* @surface: a PostScript #cairo_surface_t
1074
* @level: PostScript level
1076
* Restricts the generated PostSript file to @level. See
1077
* cairo_ps_get_levels() for a list of available level values that
1080
* This function should only be called before any drawing operations
1081
* have been performed on the given surface. The simplest way to do
1082
* this is to call this function immediately after creating the
1088
cairo_ps_surface_restrict_to_level (cairo_surface_t *surface,
1089
cairo_ps_level_t level)
1091
cairo_ps_surface_t *ps_surface = NULL;
1092
cairo_status_t status;
1094
status = _extract_ps_surface (surface, &ps_surface);
1096
status = _cairo_surface_set_error (surface, status);
1100
if (level < CAIRO_PS_LEVEL_LAST)
1101
ps_surface->ps_level = level;
1105
* cairo_ps_get_levels:
1106
* @levels: supported level list
1107
* @num_levels: list length
1109
* Used to retrieve the list of supported levels. See
1110
* cairo_ps_surface_restrict_to_level().
1115
cairo_ps_get_levels (cairo_ps_level_t const **levels,
1119
*levels = _cairo_ps_levels;
1121
if (num_levels != NULL)
1122
*num_levels = CAIRO_PS_LEVEL_LAST;
1126
* cairo_ps_level_to_string:
1127
* @level: a level id
1129
* Get the string representation of the given @level id. This function
1130
* will return NULL if @level id isn't valid. See cairo_ps_get_levels()
1131
* for a way to get the list of valid level ids.
1133
* Return value: the string associated to given level.
1138
cairo_ps_level_to_string (cairo_ps_level_t level)
1140
if (level >= CAIRO_PS_LEVEL_LAST)
1143
return _cairo_ps_level_strings[level];
1147
* cairo_ps_surface_set_eps:
1148
* @surface: a PostScript cairo_surface_t
1149
* @eps: TRUE to output EPS format PostScript
1151
* If @eps is TRUE, the PostScript surface will output Encapsulated
1154
* This function should only be called before any drawing operations
1155
* have been performed on the current page. The simplest way to do
1156
* this is to call this function immediately after creating the
1157
* surface. An Encapsulated Postscript file should never contain more
1163
cairo_ps_surface_set_eps (cairo_surface_t *surface,
1166
cairo_ps_surface_t *ps_surface = NULL;
1167
cairo_status_t status;
1169
status = _extract_ps_surface (surface, &ps_surface);
1171
status = _cairo_surface_set_error (surface, status);
1175
ps_surface->eps = eps;
1179
* cairo_ps_surface_get_eps:
1180
* @surface: a PostScript cairo_surface_t
1182
* Check whether the PostScript surface will output Encapsulated PostScript.
1184
* Return value: TRUE if the surface will output Encapsulated PostScript.
1188
cairo_public cairo_bool_t
1189
cairo_ps_surface_get_eps (cairo_surface_t *surface)
1191
cairo_ps_surface_t *ps_surface = NULL;
1192
cairo_status_t status;
1194
status = _extract_ps_surface (surface, &ps_surface);
1196
status = _cairo_surface_set_error (surface, status);
1200
return ps_surface->eps;
947
1204
* cairo_ps_surface_set_size:
948
1205
* @surface: a PostScript cairo_surface_t
949
1206
* @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
1303
1527
static cairo_bool_t
1304
color_is_gray (cairo_color_t *color)
1528
color_is_gray (double red, double green, double blue)
1306
1530
const double epsilon = 0.00001;
1308
return (fabs (color->red - color->green) < epsilon &&
1309
fabs (color->red - color->blue) < epsilon);
1532
return (fabs (red - green) < epsilon &&
1533
fabs (red - blue) < epsilon);
1536
static cairo_status_t
1537
_analyze_image_transparency (cairo_image_surface_t *image,
1538
cairo_image_transparency_t *transparency)
1540
cairo_status_t status;
1543
if (image->format == CAIRO_FORMAT_RGB24) {
1544
*transparency = CAIRO_IMAGE_IS_OPAQUE;
1545
return CAIRO_STATUS_SUCCESS;
1548
if (image->format != CAIRO_FORMAT_ARGB32) {
1549
/* If the PS surface does not support the image format, assume
1550
* that it does have alpha. The image will be converted to
1551
* rgb24 when the PS surface blends the image into the page
1552
* color to remove the transparency. */
1553
*transparency = CAIRO_IMAGE_HAS_ALPHA;
1554
return CAIRO_STATUS_SUCCESS;
1557
*transparency = CAIRO_IMAGE_IS_OPAQUE;
1558
for (y = 0; y < image->height; y++) {
1560
uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
1562
for (x = 0; x < image->width; x++, pixel++) {
1563
a = (*pixel & 0xff000000) >> 24;
1564
if (a > 0 && a < 255) {
1565
*transparency = CAIRO_IMAGE_HAS_ALPHA;
1566
return CAIRO_STATUS_SUCCESS;
1567
} else if (a == 0) {
1568
*transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
1572
status = CAIRO_STATUS_SUCCESS;
1577
static cairo_int_status_t
1578
_cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface,
1579
cairo_surface_pattern_t *pattern)
1581
cairo_image_surface_t *image;
1583
cairo_int_status_t status;
1584
cairo_image_transparency_t transparency;
1586
status = _cairo_surface_acquire_source_image (pattern->surface,
1592
if (image->base.status)
1593
return image->base.status;
1595
status = _analyze_image_transparency (image, &transparency);
1597
goto RELEASE_SOURCE;
1599
switch (transparency) {
1600
case CAIRO_IMAGE_IS_OPAQUE:
1601
status = CAIRO_STATUS_SUCCESS;
1604
case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
1605
if (surface->ps_level == CAIRO_PS_LEVEL_2)
1606
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1608
status = CAIRO_STATUS_SUCCESS;
1611
case CAIRO_IMAGE_HAS_ALPHA:
1612
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1617
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
1312
1622
static cairo_bool_t
1313
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
1623
surface_pattern_supported (cairo_surface_pattern_t *pattern)
1315
1625
cairo_extend_t extend;
1627
if (_cairo_surface_is_meta (pattern->surface))
1317
1630
if (pattern->surface->backend->acquire_source_image == NULL)
1349
1662
static cairo_bool_t
1350
pattern_supported (const cairo_pattern_t *pattern)
1663
_gradient_pattern_supported (cairo_ps_surface_t *surface,
1664
cairo_pattern_t *pattern)
1666
cairo_extend_t extend;
1668
if (surface->ps_level == CAIRO_PS_LEVEL_2)
1671
extend = cairo_pattern_get_extend (pattern);
1673
if (extend == CAIRO_EXTEND_REPEAT ||
1674
extend == CAIRO_EXTEND_REFLECT) {
1678
/* Radial gradients are currently only supported when one circle
1679
* is inside the other. */
1680
if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
1681
double x1, y1, x2, y2, r1, r2, d;
1682
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
1684
x1 = _cairo_fixed_to_double (radial->c1.x);
1685
y1 = _cairo_fixed_to_double (radial->c1.y);
1686
r1 = _cairo_fixed_to_double (radial->r1);
1687
x2 = _cairo_fixed_to_double (radial->c2.x);
1688
y2 = _cairo_fixed_to_double (radial->c2.y);
1689
r2 = _cairo_fixed_to_double (radial->r2);
1691
d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
1692
if (d > fabs(r2 - r1)) {
1701
pattern_supported (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
1352
1703
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
1706
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
1707
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
1708
return _gradient_pattern_supported (surface, pattern);
1355
1710
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
1356
return surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
1711
return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
1361
1716
static cairo_int_status_t
1362
_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
1363
cairo_operator_t op,
1364
const cairo_pattern_t *pattern)
1366
if (surface->force_fallbacks)
1369
if (! pattern_supported (pattern))
1372
if (_cairo_operator_always_opaque (op))
1717
_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
1718
cairo_operator_t op,
1719
cairo_pattern_t *pattern)
1721
if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
1722
return CAIRO_INT_STATUS_UNSUPPORTED;
1724
if (! pattern_supported (surface, pattern))
1725
return CAIRO_INT_STATUS_UNSUPPORTED;
1727
if (!(op == CAIRO_OPERATOR_SOURCE ||
1728
op == CAIRO_OPERATOR_OVER))
1729
return CAIRO_INT_STATUS_UNSUPPORTED;
1731
if (op == CAIRO_OPERATOR_SOURCE)
1732
return CAIRO_STATUS_SUCCESS;
1734
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1735
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
1737
if ( _cairo_surface_is_meta (surface_pattern->surface))
1738
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
1740
return _cairo_ps_surface_analyze_surface_pattern_transparency (surface,
1744
/* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
1745
* the pattern contains transparency, we return
1746
* CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
1747
* surface. If the analysis surface determines that there is
1748
* anything drawn under this operation, a fallback image will be
1749
* used. Otherwise the operation will be replayed during the
1750
* render stage and we blend the transarency into the white
1751
* background to convert the pattern to opaque.
1754
if (_cairo_pattern_is_opaque (pattern))
1755
return CAIRO_STATUS_SUCCESS;
1757
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
1761
_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
1762
cairo_operator_t op,
1763
cairo_pattern_t *pattern)
1765
if (_cairo_ps_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
1375
if (_cairo_operator_always_translucent (op))
1378
return _cairo_pattern_is_opaque (pattern);
1381
static cairo_int_status_t
1382
_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
1383
cairo_operator_t op,
1384
const cairo_pattern_t *pattern)
1386
if (_cairo_ps_surface_operation_supported (surface, op, pattern))
1387
return CAIRO_STATUS_SUCCESS;
1389
return CAIRO_INT_STATUS_UNSUPPORTED;
1392
1771
/* The "standard" implementation limit for PostScript string sizes is
1513
1894
* surface we can render natively in PS. */
1515
1896
static cairo_status_t
1516
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
1517
cairo_image_surface_t *image,
1897
_cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
1898
cairo_image_surface_t *image,
1899
cairo_image_surface_t **opaque_image)
1520
cairo_status_t status, status2;
1521
unsigned char *rgb, *compressed;
1522
unsigned long rgb_size, compressed_size;
1901
const cairo_color_t *background_color;
1523
1902
cairo_surface_t *opaque;
1524
cairo_image_surface_t *opaque_image;
1525
1903
cairo_pattern_union_t pattern;
1904
cairo_status_t status;
1906
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
1907
background_color = CAIRO_COLOR_WHITE;
1909
background_color = CAIRO_COLOR_BLACK;
1911
opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
1914
if (opaque->status) {
1915
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1919
_cairo_pattern_init_for_surface (&pattern.surface, &image->base);
1921
status = _cairo_surface_fill_rectangle (opaque,
1922
CAIRO_OPERATOR_SOURCE,
1925
image->width, image->height);
1929
status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
1941
_cairo_pattern_fini (&pattern.base);
1942
*opaque_image = (cairo_image_surface_t *) opaque;
1944
return CAIRO_STATUS_SUCCESS;
1947
_cairo_pattern_fini (&pattern.base);
1948
cairo_surface_destroy (opaque);
1953
static cairo_status_t
1954
_cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
1955
unsigned char *data,
1956
unsigned long length)
1958
cairo_output_stream_t *base85_stream, *string_array_stream;
1959
cairo_status_t status, status2;
1961
string_array_stream = _string_array_stream_create (surface->stream);
1962
status = _cairo_output_stream_get_status (string_array_stream);
1966
base85_stream = _cairo_base85_stream_create (string_array_stream);
1967
status = _cairo_output_stream_get_status (base85_stream);
1969
status2 = _cairo_output_stream_destroy (string_array_stream);
1973
_cairo_output_stream_write (base85_stream, data, length);
1975
status = _cairo_output_stream_destroy (base85_stream);
1976
status2 = _cairo_output_stream_destroy (string_array_stream);
1977
if (status == CAIRO_STATUS_SUCCESS)
1983
static cairo_status_t
1984
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
1985
cairo_image_surface_t *image,
1987
cairo_operator_t op)
1989
cairo_status_t status;
1990
unsigned char *rgb, *rgb_compressed;
1991
unsigned long rgb_size, rgb_compressed_size;
1992
unsigned char *mask = NULL, *mask_compressed = NULL;
1993
unsigned long mask_size = 0, mask_compressed_size = 0;
1994
cairo_image_surface_t *opaque_image = NULL;
1527
cairo_output_stream_t *base85_stream, *string_array_stream;
1996
cairo_image_transparency_t transparency;
1997
cairo_bool_t use_mask;
1999
if (image->base.status)
2000
return image->base.status;
2002
status = _analyze_image_transparency (image, &transparency);
1529
2006
/* PostScript can not represent the alpha channel, so we blend the
1530
current image over a white RGB surface to eliminate it. */
1532
if (image->base.status)
1533
return image->base.status;
1535
if (image->format != CAIRO_FORMAT_RGB24) {
1536
opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
1539
if (opaque->status) {
1540
status = CAIRO_STATUS_NO_MEMORY;
1544
_cairo_pattern_init_for_surface (&pattern.surface, &image->base);
1546
status = _cairo_surface_fill_rectangle (opaque,
1547
CAIRO_OPERATOR_SOURCE,
1550
image->width, image->height);
1552
_cairo_pattern_fini (&pattern.base);
1556
status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
1566
_cairo_pattern_fini (&pattern.base);
1570
_cairo_pattern_fini (&pattern.base);
1571
opaque_image = (cairo_image_surface_t *) opaque;
1573
opaque = &image->base;
2007
current image over a white (or black for CONTENT_COLOR
2008
surfaces) RGB surface to eliminate it. */
2010
if (op == CAIRO_OPERATOR_SOURCE ||
2011
transparency == CAIRO_IMAGE_HAS_ALPHA ||
2012
(transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA &&
2013
surface->ps_level == CAIRO_PS_LEVEL_2)) {
2014
_cairo_ps_surface_flatten_image_transparency (surface,
2018
} else if (transparency == CAIRO_IMAGE_IS_OPAQUE) {
1574
2019
opaque_image = image;
1577
rgb_size = 3 * opaque_image->width * opaque_image->height;
2025
rgb_size = 3 * image->width * image->height;
1578
2026
rgb = malloc (rgb_size);
1579
2027
if (rgb == NULL) {
1580
status = CAIRO_STATUS_NO_MEMORY;
2028
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1585
for (y = 0; y < opaque_image->height; y++) {
1586
pixman_bits_t *pixel = (pixman_bits_t *) (opaque_image->data + y * opaque_image->stride);
1587
for (x = 0; x < opaque_image->width; x++, pixel++) {
1588
rgb[i++] = (*pixel & 0x00ff0000) >> 16;
1589
rgb[i++] = (*pixel & 0x0000ff00) >> 8;
1590
rgb[i++] = (*pixel & 0x000000ff) >> 0;
2033
mask_size = (image->width * image->height + 7)/8;
2034
mask = malloc (mask_size);
2036
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2045
for (y = 0; y < image->height; y++) {
2046
uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
2047
for (x = 0; x < image->width; x++, pixel++) {
2050
if (((*pixel & 0xff000000) >> 24) > 0x80)
2051
mask[byte] |= (1 << bit);
2057
rgb[i++] = (*pixel & 0x00ff0000) >> 16;
2058
rgb[i++] = (*pixel & 0x0000ff00) >> 8;
2059
rgb[i++] = (*pixel & 0x000000ff) >> 0;
2064
for (y = 0; y < opaque_image->height; y++) {
2065
uint32_t *pixel = (uint32_t *) (opaque_image->data + y * opaque_image->stride);
2066
for (x = 0; x < opaque_image->width; x++, pixel++) {
2067
rgb[i++] = (*pixel & 0x00ff0000) >> 16;
2068
rgb[i++] = (*pixel & 0x0000ff00) >> 8;
2069
rgb[i++] = (*pixel & 0x000000ff) >> 0;
1594
2074
/* XXX: Should fix cairo-lzw to provide a stream-based interface
1596
compressed_size = rgb_size;
1597
compressed = _cairo_lzw_compress (rgb, &compressed_size);
1598
if (compressed == NULL) {
1599
status = CAIRO_STATUS_NO_MEMORY;
2076
rgb_compressed_size = rgb_size;
2077
rgb_compressed = _cairo_lzw_compress (rgb, &rgb_compressed_size);
2078
if (rgb_compressed == NULL) {
2079
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1603
2083
/* First emit the image data as a base85-encoded string which will
1605
2085
_cairo_output_stream_printf (surface->stream,
1606
2086
"/%sData [\n", name);
1608
string_array_stream = _string_array_stream_create (surface->stream);
1609
base85_stream = _cairo_base85_stream_create (string_array_stream);
1611
_cairo_output_stream_write (base85_stream, compressed, compressed_size);
1613
status = _cairo_output_stream_destroy (base85_stream);
1614
status2 = _cairo_output_stream_destroy (string_array_stream);
1615
if (status == CAIRO_STATUS_SUCCESS)
2088
status = _cairo_ps_surface_emit_base85_string (surface,
2090
rgb_compressed_size);
1620
2094
_cairo_output_stream_printf (surface->stream,
1622
2096
_cairo_output_stream_printf (surface->stream,
1623
2097
"/%sDataIndex 0 def\n", name);
1625
_cairo_output_stream_printf (surface->stream,
1627
" /DeviceRGB setcolorspace\n"
1632
" /BitsPerComponent 8\n"
1633
" /Decode [ 0 1 0 1 0 1 ]\n"
1635
" %sData %sDataIndex get\n"
1636
" /%sDataIndex %sDataIndex 1 add def\n"
1637
" %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
1638
" } /ASCII85Decode filter /LZWDecode filter\n"
1639
" /ImageMatrix [ 1 0 0 1 0 0 ]\n"
1644
opaque_image->width,
1645
opaque_image->height,
1646
name, name, name, name, name, name, name);
2099
/* Emit the mask data as a base85-encoded string which will
2100
* be used as the mask source for the image operator later. */
2102
mask_compressed_size = mask_size;
2103
mask_compressed = _cairo_lzw_compress (mask, &mask_compressed_size);
2104
if (mask_compressed == NULL) {
2105
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2109
_cairo_output_stream_printf (surface->stream,
2110
"/%sMask [\n", name);
2112
status = _cairo_ps_surface_emit_base85_string (surface,
2114
mask_compressed_size);
2118
_cairo_output_stream_printf (surface->stream,
2120
_cairo_output_stream_printf (surface->stream,
2121
"/%sMaskIndex 0 def\n", name);
2125
_cairo_output_stream_printf (surface->stream,
2127
" /DeviceRGB setcolorspace\n"
2130
" /InterleaveType 3\n"
2135
" /BitsPerComponent 8\n"
2136
" /Decode [ 0 1 0 1 0 1 ]\n"
2138
" %sData %sDataIndex get\n"
2139
" /%sDataIndex %sDataIndex 1 add def\n"
2140
" %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
2141
" } /ASCII85Decode filter /LZWDecode filter\n"
2142
" /ImageMatrix [ 1 0 0 1 0 0 ]\n"
2148
" /BitsPerComponent 1\n"
2149
" /Decode [ 1 0 ]\n"
2151
" %sMask %sMaskIndex get\n"
2152
" /%sMaskIndex %sMaskIndex 1 add def\n"
2153
" %sMaskIndex %sMask length 1 sub gt { /%sMaskIndex 0 def } if\n"
2154
" } /ASCII85Decode filter /LZWDecode filter\n"
2155
" /ImageMatrix [ 1 0 0 1 0 0 ]\n"
2163
name, name, name, name, name, name, name,
2166
name, name, name, name, name, name, name);
2168
_cairo_output_stream_printf (surface->stream,
2170
" /DeviceRGB setcolorspace\n"
2175
" /BitsPerComponent 8\n"
2176
" /Decode [ 0 1 0 1 0 1 ]\n"
2178
" %sData %sDataIndex get\n"
2179
" /%sDataIndex %sDataIndex 1 add def\n"
2180
" %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
2181
" } /ASCII85Decode filter /LZWDecode filter\n"
2182
" /ImageMatrix [ 1 0 0 1 0 0 ]\n"
2187
opaque_image->width,
2188
opaque_image->height,
2189
name, name, name, name, name, name, name);
1648
2192
status = CAIRO_STATUS_SUCCESS;
2196
free (mask_compressed);
2198
free (rgb_compressed);
1655
if (opaque_image != image)
1656
cairo_surface_destroy (opaque);
1662
_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
1663
cairo_solid_pattern_t *pattern)
1665
if (color_is_gray (&pattern->color))
2207
if (!use_mask && opaque_image != image)
2208
cairo_surface_destroy (&opaque_image->base);
2213
static cairo_status_t
2214
_cairo_ps_surface_emit_image_surface (cairo_ps_surface_t *surface,
2215
cairo_surface_pattern_t *pattern,
2218
cairo_operator_t op)
2220
cairo_image_surface_t *image;
2222
cairo_status_t status;
2224
status = _cairo_surface_acquire_source_image (pattern->surface,
2230
_cairo_ps_surface_emit_image (surface, image, "CairoPattern", op);
2234
*width = image->width;
2235
*height = image->height;
2238
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
2243
static cairo_status_t
2244
_cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
2245
cairo_surface_t *meta_surface)
2247
double old_width, old_height;
2248
cairo_content_t old_content;
2249
cairo_rectangle_int_t meta_extents;
2250
cairo_status_t status;
2252
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
2256
old_content = surface->content;
2257
old_width = surface->width;
2258
old_height = surface->height;
2259
surface->width = meta_extents.width;
2260
surface->height = meta_extents.height;
2261
_cairo_output_stream_printf (surface->stream,
2265
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
2266
surface->content = CAIRO_CONTENT_COLOR;
2267
_cairo_output_stream_printf (surface->stream,
2268
"0 G 0 0 %f %f rectfill\n",
2273
status = _cairo_meta_surface_replay (meta_surface, &surface->base);
2277
_cairo_output_stream_printf (surface->stream,
2280
surface->content = old_content;
2281
surface->width = old_width;
2282
surface->height = old_height;
2284
return CAIRO_STATUS_SUCCESS;
2288
_cairo_ps_surface_flatten_transparency (cairo_ps_surface_t *surface,
2289
const cairo_color_t *color,
2295
*green = color->green;
2296
*blue = color->blue;
2298
if (!CAIRO_COLOR_IS_OPAQUE(color)) {
2299
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
2300
uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
2302
*red = ((color->red_short >> 8) + one_minus_alpha) / 255.0;
2303
*green = ((color->green_short >> 8) + one_minus_alpha) / 255.0;
2304
*blue = ((color->blue_short >> 8) + one_minus_alpha) / 255.0;
2306
*red = (color->red_short >> 8) / 255.0;
2307
*green = (color->green_short >> 8) / 255.0;
2308
*blue = (color->blue_short >> 8) / 255.0;
2314
_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
2315
cairo_solid_pattern_t *pattern)
2317
double red, green, blue;
2319
_cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue);
2321
if (color_is_gray (red, green, blue))
1666
2322
_cairo_output_stream_printf (surface->stream,
1668
pattern->color.red);
1670
2326
_cairo_output_stream_printf (surface->stream,
1671
2327
"%f %f %f R\n",
1673
pattern->color.green,
1674
pattern->color.blue);
1677
2331
static cairo_status_t
1678
_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
1679
cairo_surface_pattern_t *pattern)
2332
_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
2333
cairo_surface_pattern_t *pattern,
2334
cairo_operator_t op)
1681
2336
cairo_status_t status;
1682
double bbox_width, bbox_height;
2337
int pattern_width = 0; /* squelch bogus compiler warning */
2338
int pattern_height = 0; /* squelch bogus compiler warning */
1683
2339
double xstep, ystep;
1684
2340
cairo_matrix_t inverse = pattern->base.matrix;
1688
2344
assert (status == CAIRO_STATUS_SUCCESS);
1690
2346
if (_cairo_surface_is_meta (pattern->surface)) {
1691
_cairo_output_stream_printf (surface->stream, "/MyPattern {\n");
2347
cairo_surface_t *meta_surface = pattern->surface;
2348
cairo_rectangle_int_t pattern_extents;
1693
status = _cairo_meta_surface_replay (pattern->surface, &surface->base);
2350
status = _cairo_ps_surface_emit_meta_surface (surface,
2352
status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
1697
bbox_width = surface->width;
1698
bbox_height = surface->height;
1699
xstep = surface->width;
1700
ystep = surface->height;
1701
_cairo_output_stream_printf (surface->stream, "} bind def\n");
2355
pattern_width = pattern_extents.width;
2356
pattern_height = pattern_extents.height;
1703
cairo_image_surface_t *image;
1705
cairo_status_t status;
1707
status = _cairo_surface_acquire_source_image (pattern->surface,
1710
assert (status == CAIRO_STATUS_SUCCESS);
1712
_cairo_ps_surface_emit_image (surface, image, "MyPattern");
1714
bbox_width = image->width;
1715
bbox_height = image->height;
1717
switch (pattern->base.extend) {
2358
status = _cairo_ps_surface_emit_image_surface (surface,
2367
switch (pattern->base.extend) {
1718
2368
/* We implement EXTEND_PAD like EXTEND_NONE for now */
1719
case CAIRO_EXTEND_PAD:
1720
case CAIRO_EXTEND_NONE:
1722
/* In PS/PDF, (as far as I can tell), all patterns are
1723
* repeating. So we support cairo's EXTEND_NONE semantics
1724
* by setting the repeat step size to a size large enough
1725
* to guarantee that no more than a single occurrence will
1728
* First, map the surface extents into pattern space (since
1729
* xstep and ystep are in pattern space). Then use an upper
1730
* bound on the length of the diagonal of the pattern image
1731
* and the surface as repeat size. This guarantees to never
1734
double x1 = 0.0, y1 = 0.0;
1735
double x2 = surface->width, y2 = surface->height;
1736
_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
2369
case CAIRO_EXTEND_PAD:
2370
case CAIRO_EXTEND_NONE:
2372
/* In PS/PDF, (as far as I can tell), all patterns are
2373
* repeating. So we support cairo's EXTEND_NONE semantics
2374
* by setting the repeat step size to a size large enough
2375
* to guarantee that no more than a single occurrence will
2378
* First, map the surface extents into pattern space (since
2379
* xstep and ystep are in pattern space). Then use an upper
2380
* bound on the length of the diagonal of the pattern image
2381
* and the surface as repeat size. This guarantees to never
2384
double x1 = 0.0, y1 = 0.0;
2385
double x2 = surface->width, y2 = surface->height;
2386
_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
1740
/* Rather than computing precise bounds of the union, just
1741
* add the surface extents unconditionally. We only
1742
* required an answer that's large enough, we don't really
1743
* care if it's not as tight as possible.*/
1744
xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
1745
image->width + image->height);
1748
case CAIRO_EXTEND_REPEAT:
1749
case CAIRO_EXTEND_REFLECT:
1750
xstep = image->width;
1751
ystep = image->height;
2390
/* Rather than computing precise bounds of the union, just
2391
* add the surface extents unconditionally. We only
2392
* required an answer that's large enough, we don't really
2393
* care if it's not as tight as possible.*/
2394
xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
2395
pattern_width + pattern_height);
2398
case CAIRO_EXTEND_REPEAT:
2399
case CAIRO_EXTEND_REFLECT:
2400
xstep = pattern_width;
2401
ystep = pattern_height;
1753
2403
/* All the rest (if any) should have been analyzed away, so these
1754
2404
* cases should be unreachable. */
1761
_cairo_surface_release_source_image (pattern->surface, image,
1764
2411
_cairo_output_stream_printf (surface->stream,
1765
2412
"<< /PatternType 1\n"
1766
2413
" /PaintType 1\n"
1767
2414
" /TilingType 1\n");
1768
2415
_cairo_output_stream_printf (surface->stream,
1769
" /BBox [0 0 %f %f]\n",
1770
bbox_width, bbox_height);
2416
" /BBox [0 0 %d %d]\n",
2417
pattern_width, pattern_height);
1771
2418
_cairo_output_stream_printf (surface->stream,
1772
2419
" /XStep %f /YStep %f\n",
1774
2421
_cairo_output_stream_printf (surface->stream,
1775
" /PaintProc { MyPattern } bind\n"
1777
_cairo_output_stream_printf (surface->stream,
1778
"[ %f %f %f %f %f %f ]\n",
1779
inverse.xx, inverse.yx,
1780
inverse.xy, inverse.yy,
1781
inverse.x0, inverse.y0);
1782
_cairo_output_stream_printf (surface->stream,
1783
"makepattern setpattern\n");
1785
return CAIRO_STATUS_SUCCESS;
1789
_cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
1790
cairo_linear_pattern_t *pattern)
1796
_cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
1797
cairo_radial_pattern_t *pattern)
1802
static cairo_status_t
1803
_cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
2422
" /PaintProc { CairoPattern } bind\n"
2424
_cairo_output_stream_printf (surface->stream,
2425
"[ %f %f %f %f %f %f ]\n",
2426
inverse.xx, inverse.yx,
2427
inverse.xy, inverse.yy,
2428
inverse.x0, inverse.y0);
2429
_cairo_output_stream_printf (surface->stream,
2430
"makepattern setpattern\n");
2432
return CAIRO_STATUS_SUCCESS;
2435
typedef struct _cairo_ps_color_stop {
2438
} cairo_ps_color_stop_t;
2441
_cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t *surface,
2442
cairo_ps_color_stop_t *stop1,
2443
cairo_ps_color_stop_t *stop2)
2445
_cairo_output_stream_printf (surface->stream,
2446
"<< /FunctionType 2\n"
2447
" /Domain [ 0 1 ]\n"
2448
" /C0 [ %f %f %f ]\n"
2449
" /C1 [ %f %f %f ]\n"
2461
_cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t *surface,
2462
unsigned int n_stops,
2463
cairo_ps_color_stop_t stops[])
2467
_cairo_output_stream_printf (surface->stream,
2468
" << /FunctionType 3\n"
2469
" /Domain [ 0 1 ]\n"
2471
for (i = 0; i < n_stops - 1; i++)
2472
_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]);
2474
_cairo_output_stream_printf (surface->stream, " ]\n");
2476
_cairo_output_stream_printf (surface->stream, " /Bounds [ ");
2477
for (i = 1; i < n_stops-1; i++)
2478
_cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset);
2479
_cairo_output_stream_printf (surface->stream, "]\n");
2481
_cairo_output_stream_printf (surface->stream, " /Encode [ ");
2482
for (i = 1; i < n_stops; i++)
2483
_cairo_output_stream_printf (surface->stream, "0 1 ");
2484
_cairo_output_stream_printf (surface->stream, "]\n");
2486
_cairo_output_stream_printf (surface->stream, " >>\n");
2489
#define COLOR_STOP_EPSILON 1e-6
2491
static cairo_status_t
2492
_cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
2493
cairo_gradient_pattern_t *pattern)
2495
cairo_ps_color_stop_t *allstops, *stops;
2496
unsigned int i, n_stops;
2498
allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t));
2499
if (allstops == NULL)
2500
return CAIRO_STATUS_NO_MEMORY;
2502
stops = &allstops[1];
2503
n_stops = pattern->n_stops;
2505
for (i = 0; i < n_stops; i++) {
2506
double red, green, blue;
2508
_cairo_ps_surface_flatten_transparency (surface,
2509
&pattern->stops[i].color,
2510
&red, &green, &blue);
2511
stops[i].color[0] = red;
2512
stops[i].color[1] = green;
2513
stops[i].color[2] = blue;
2514
stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x);
2517
/* make sure first offset is 0.0 and last offset is 1.0 */
2518
if (stops[0].offset > COLOR_STOP_EPSILON) {
2519
memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t));
2523
stops[0].offset = 0.0;
2525
if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) {
2526
memcpy (&stops[n_stops],
2527
&stops[n_stops - 1],
2528
sizeof (cairo_ps_color_stop_t));
2531
stops[n_stops-1].offset = 1.0;
2534
/* no need for stitched function */
2535
_cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]);
2537
/* multiple stops: stitch. XXX possible optimization: regulary spaced
2538
* stops do not require stitching. XXX */
2539
_cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops,stops);
2544
return CAIRO_STATUS_SUCCESS;
2547
static cairo_status_t
2548
_cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
2549
cairo_linear_pattern_t *pattern)
2551
double x1, y1, x2, y2;
2552
cairo_extend_t extend;
2553
cairo_status_t status;
2554
cairo_matrix_t inverse = pattern->base.base.matrix;
2556
extend = cairo_pattern_get_extend (&pattern->base.base);
2558
status = cairo_matrix_invert (&inverse);
2562
x1 = _cairo_fixed_to_double (pattern->p1.x);
2563
y1 = _cairo_fixed_to_double (pattern->p1.y);
2564
x2 = _cairo_fixed_to_double (pattern->p2.x);
2565
y2 = _cairo_fixed_to_double (pattern->p2.y);
2567
_cairo_output_stream_printf (surface->stream,
2568
"<< /PatternType 2\n"
2570
" << /ShadingType 2\n"
2571
" /ColorSpace /DeviceRGB\n"
2572
" /Coords [ %f %f %f %f ]\n"
2576
status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
2580
if (extend == CAIRO_EXTEND_PAD) {
2581
_cairo_output_stream_printf (surface->stream,
2582
" /Extend [ true true ]\r\n");
2584
_cairo_output_stream_printf (surface->stream,
2585
" /Extend [ false false ]\r\n");
2588
_cairo_output_stream_printf (surface->stream,
2591
_cairo_output_stream_printf (surface->stream,
2592
"[ %f %f %f %f %f %f ]\n",
2593
inverse.xx, inverse.yx,
2594
inverse.xy, inverse.yy,
2595
inverse.x0, inverse.y0);
2596
_cairo_output_stream_printf (surface->stream,
2597
"makepattern setpattern\n");
2602
static cairo_status_t
2603
_cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
2604
cairo_radial_pattern_t *pattern)
2606
double x1, y1, x2, y2, r1, r2;
2607
cairo_extend_t extend;
2608
cairo_status_t status;
2609
cairo_matrix_t inverse = pattern->base.base.matrix;
2611
extend = cairo_pattern_get_extend (&pattern->base.base);
2613
status = cairo_matrix_invert (&inverse);
2617
x1 = _cairo_fixed_to_double (pattern->c1.x);
2618
y1 = _cairo_fixed_to_double (pattern->c1.y);
2619
r1 = _cairo_fixed_to_double (pattern->r1);
2620
x2 = _cairo_fixed_to_double (pattern->c2.x);
2621
y2 = _cairo_fixed_to_double (pattern->c2.y);
2622
r2 = _cairo_fixed_to_double (pattern->r2);
2624
_cairo_output_stream_printf (surface->stream,
2625
"<< /PatternType 2\n"
2627
" << /ShadingType 3\n"
2628
" /ColorSpace /DeviceRGB\n"
2629
" /Coords [ %f %f %f %f %f %f ]\n"
2631
x1, y1, r1, x2, y2, r2);
2633
status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
2637
if (extend == CAIRO_EXTEND_PAD) {
2638
_cairo_output_stream_printf (surface->stream,
2639
" /Extend [ true true ]\r\n");
2641
_cairo_output_stream_printf (surface->stream,
2642
" /Extend [ false false ]\r\n");
2645
_cairo_output_stream_printf (surface->stream,
2648
_cairo_output_stream_printf (surface->stream,
2649
"[ %f %f %f %f %f %f ]\n",
2650
inverse.xx, inverse.yx,
2651
inverse.xy, inverse.yy,
2652
inverse.x0, inverse.y0);
2653
_cairo_output_stream_printf (surface->stream,
2654
"makepattern setpattern\n");
2659
static cairo_status_t
2660
_cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
2661
cairo_pattern_t *pattern,
2662
cairo_operator_t op)
1805
2664
/* FIXME: We should keep track of what pattern is currently set in
1806
2665
* the postscript file and only emit code if we're setting a