w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

cairo-svg-surface.c
Go to the documentation of this file.
1 /* vim: set sw=4 sts=4: -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2004 Red Hat, Inc
5  * Copyright © 2005-2007 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
6  * Copyright © 2006 Red Hat, Inc
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it either under the terms of the GNU Lesser General Public
10  * License version 2.1 as published by the Free Software Foundation
11  * (the "LGPL") or, at your option, under the terms of the Mozilla
12  * Public License Version 1.1 (the "MPL"). If you do not alter this
13  * notice, a recipient may use your version of this file under either
14  * the MPL or the LGPL.
15  *
16  * You should have received a copy of the LGPL along with this library
17  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19  * You should have received a copy of the MPL along with this library
20  * in the file COPYING-MPL-1.1
21  *
22  * The contents of this file are subject to the Mozilla Public License
23  * Version 1.1 (the "License"); you may not use this file except in
24  * compliance with the License. You may obtain a copy of the License at
25  * http://www.mozilla.org/MPL/
26  *
27  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29  * the specific language governing rights and limitations.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is University of Southern
34  * California.
35  *
36  * Contributor(s):
37  * Kristian Høgsberg <krh@redhat.com>
38  * Emmanuel Pacaud <emmanuel.pacaud@free.fr>
39  * Carl Worth <cworth@cworth.org>
40  */
41 
42 #define _DEFAULT_SOURCE /* for snprintf() */
43 #include "cairoint.h"
44 
45 #include "cairo-svg.h"
46 
47 #include "cairo-array-private.h"
50 #include "cairo-error-private.h"
61 
62 /**
63  * SECTION:cairo-svg
64  * @Title: SVG Surfaces
65  * @Short_Description: Rendering SVG documents
66  * @See_Also: #cairo_surface_t
67  *
68  * The SVG surface is used to render cairo graphics to
69  * SVG files and is a multi-page vector surface backend.
70  **/
71 
72 /**
73  * CAIRO_HAS_SVG_SURFACE:
74  *
75  * Defined if the SVG surface backend is available.
76  * This macro can be used to conditionally compile backend-specific code.
77  *
78  * Since: 1.2
79  **/
80 
81 typedef struct cairo_svg_page cairo_svg_page_t;
82 
83 static const int invalid_pattern_id = -1;
84 
86 {
89 };
90 
91 #define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions)
92 
93 static const char *_cairo_svg_supported_mime_types[] =
94 {
99  NULL
100 };
101 
102 static void
104  const cairo_path_fixed_t *path,
105  const cairo_matrix_t *ctm_inverse);
106 
107 static cairo_bool_t
109 {
111 }
112 
114 {
115  "SVG 1.1",
116  "SVG 1.2"
117 };
118 
120 {
121  "1.1",
122  "1.2"
123 };
124 
125 static const char * _cairo_svg_unit_strings[] =
126 {
127  "",
128  "em",
129  "ex",
130  "px",
131  "in",
132  "cm",
133  "mm",
134  "pt",
135  "pc",
136  "%"
137 };
138 
139 struct cairo_svg_page {
140  unsigned int surface_id;
141  unsigned int clip_level;
143 };
144 
145 struct cairo_svg_document {
147  unsigned long refcount;
150 
151  double width;
152  double height;
154 
157 
158  unsigned int linear_pattern_id;
159  unsigned int radial_pattern_id;
160  unsigned int pattern_id;
161  unsigned int filter_id;
162  unsigned int clip_id;
163  unsigned int mask_id;
164 
166 
168 
170 };
171 
172 static cairo_status_t
174  double width,
175  double height,
177  cairo_svg_document_t **document_out);
178 
179 static cairo_status_t
181 
182 static cairo_status_t
184 
185 static cairo_svg_document_t *
187 
188 static unsigned int
190 
191 static cairo_surface_t *
194  double width,
195  double height,
196  cairo_bool_t bounded);
197 
198 static cairo_surface_t *
200  double width,
201  double height,
203 
206 
207 /**
208  * cairo_svg_surface_create_for_stream:
209  * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL
210  * to indicate a no-op @write_func. With a no-op @write_func,
211  * the surface may be queried or used as a source without
212  * generating any temporary files.
213  * @closure: the closure argument for @write_func
214  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
215  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
216  *
217  * Creates a SVG surface of the specified size in points to be written
218  * incrementally to the stream represented by @write_func and @closure.
219  *
220  * Return value: a pointer to the newly created surface. The caller
221  * owns the surface and should call cairo_surface_destroy() when done
222  * with it.
223  *
224  * This function always returns a valid pointer, but it will return a
225  * pointer to a "nil" surface if an error such as out of memory
226  * occurs. You can use cairo_surface_status() to check for this.
227  *
228  * Since: 1.2
229  **/
232  void *closure,
233  double width,
234  double height)
235 {
237 
241 
243 }
244 
245 /**
246  * cairo_svg_surface_create:
247  * @filename: a filename for the SVG output (must be writable), %NULL may be
248  * used to specify no output. This will generate a SVG surface that
249  * may be queried and used as a source, without generating a
250  * temporary file.
251  * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
252  * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
253  *
254  * Creates a SVG surface of the specified size in points to be written
255  * to @filename.
256  *
257  * The SVG surface backend recognizes the following MIME types for the
258  * data attached to a surface (see cairo_surface_set_mime_data()) when
259  * it is used as a source pattern for drawing on this surface:
260  * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_PNG,
261  * %CAIRO_MIME_TYPE_URI. If any of them is specified, the SVG backend
262  * emits a href with the content of MIME data instead of a surface
263  * snapshot (PNG, Base64-encoded) in the corresponding image tag.
264  *
265  * The unofficial MIME type %CAIRO_MIME_TYPE_URI is examined
266  * first. If present, the URI is emitted as is: assuring the
267  * correctness of URI is left to the client code.
268  *
269  * If %CAIRO_MIME_TYPE_URI is not present, but %CAIRO_MIME_TYPE_JPEG
270  * or %CAIRO_MIME_TYPE_PNG is specified, the corresponding data is
271  * Base64-encoded and emitted.
272  *
273  * If %CAIRO_MIME_TYPE_UNIQUE_ID is present, all surfaces with the same
274  * unique identifier will only be embedded once.
275  *
276  * Return value: a pointer to the newly created surface. The caller
277  * owns the surface and should call cairo_surface_destroy() when done
278  * with it.
279  *
280  * This function always returns a valid pointer, but it will return a
281  * pointer to a "nil" surface if an error such as out of memory
282  * occurs. You can use cairo_surface_status() to check for this.
283  *
284  * Since: 1.2
285  **/
288  double width,
289  double height)
290 {
292 
296 
298 }
299 
300 static cairo_bool_t
302 {
304 }
305 
306 /* If the abstract_surface is a paginated surface, and that paginated
307  * surface's target is a svg_surface, then set svg_surface to that
308  * target. Otherwise return FALSE.
309  */
310 static cairo_bool_t
312  cairo_svg_surface_t **svg_surface)
313 {
315  cairo_status_t status_ignored;
316 
317  if (surface->status)
318  return FALSE;
319  if (surface->finished) {
320  status_ignored = _cairo_surface_set_error (surface,
322  return FALSE;
323  }
324 
326  status_ignored = _cairo_surface_set_error (surface,
328  return FALSE;
329  }
330 
332  if (target->status) {
333  status_ignored = _cairo_surface_set_error (surface,
334  target->status);
335  return FALSE;
336  }
337  if (target->finished) {
338  status_ignored = _cairo_surface_set_error (surface,
340  return FALSE;
341  }
342 
343  if (! _cairo_surface_is_svg (target)) {
344  status_ignored = _cairo_surface_set_error (surface,
346  return FALSE;
347  }
348 
349  *svg_surface = (cairo_svg_surface_t *) target;
350  return TRUE;
351 }
352 
353 /**
354  * cairo_svg_surface_restrict_to_version:
355  * @surface: a SVG #cairo_surface_t
356  * @version: SVG version
357  *
358  * Restricts the generated SVG file to @version. See cairo_svg_get_versions()
359  * for a list of available version values that can be used here.
360  *
361  * This function should only be called before any drawing operations
362  * have been performed on the given surface. The simplest way to do
363  * this is to call this function immediately after creating the
364  * surface.
365  *
366  * Since: 1.2
367  **/
368 void
371 {
372  cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
373 
374  if (! _extract_svg_surface (abstract_surface, &surface))
375  return;
376 
378  surface->document->svg_version = version;
379 }
380 
381 /**
382  * cairo_svg_get_versions:
383  * @versions: supported version list
384  * @num_versions: list length
385  *
386  * Used to retrieve the list of supported versions. See
387  * cairo_svg_surface_restrict_to_version().
388  *
389  * Since: 1.2
390  **/
391 void
393  int *num_versions)
394 {
395  if (versions != NULL)
396  *versions = _cairo_svg_versions;
397 
398  if (num_versions != NULL)
399  *num_versions = CAIRO_SVG_VERSION_LAST;
400 }
401 
402 /**
403  * cairo_svg_version_to_string:
404  * @version: a version id
405  *
406  * Get the string representation of the given @version id. This function
407  * will return %NULL if @version isn't valid. See cairo_svg_get_versions()
408  * for a way to get the list of valid version ids.
409  *
410  * Return value: the string associated to given version.
411  *
412  * Since: 1.2
413  **/
414 const char *
416 {
418  return NULL;
419 
421 }
422 
423 /**
424  * cairo_svg_surface_set_document_unit:
425  * @surface: a SVG #cairo_surface_t
426  * @unit: SVG unit
427  *
428  * Use the specified unit for the width and height of the generated SVG file.
429  * See #cairo_svg_unit_t for a list of available unit values that can be used
430  * here.
431  *
432  * This function can be called at any time before generating the SVG file.
433  *
434  * However to minimize the risk of ambiguities it's recommended to call it
435  * before any drawing operations have been performed on the given surface, to
436  * make it clearer what the unit used in the drawing operations is.
437  *
438  * The simplest way to do this is to call this function immediately after
439  * creating the SVG surface.
440  *
441  * Note if this function is never called, the default unit for SVG documents
442  * generated by cairo will be "pt". This is for historical reasons.
443  *
444  * Since: 1.16
445  **/
446 void
449 {
450  cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
451 
452  if (! _extract_svg_surface (abstract_surface, &surface))
453  return;
454 
456  surface->document->unit = unit;
457 }
458 
459 /**
460  * cairo_svg_surface_get_document_unit:
461  * @surface: a SVG #cairo_surface_t
462  *
463  * Get the unit of the SVG surface.
464  *
465  * If the surface passed as an argument is not a SVG surface, the function
466  * sets the error status to CAIRO_STATUS_SURFACE_TYPE_MISMATCH and returns
467  * CAIRO_SVG_UNIT_USER.
468  *
469  * Return value: the SVG unit of the SVG surface.
470  *
471  * Since: 1.16
472  **/
475 {
476  cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
477 
478  if (! _extract_svg_surface (abstract_surface, &surface)) {
480  return CAIRO_SVG_UNIT_USER;
481  }
482 
483  return surface->document->unit;
484 }
485 
486 static void
488 {
489  if (key->unique_id && key->unique_id_length > 0) {
491  key->unique_id, key->unique_id_length);
492  } else {
493  key->base.hash = key->id;
494  }
495 }
496 
497 static cairo_bool_t
498 _cairo_svg_source_surface_equal (const void *key_a, const void *key_b)
499 {
500  const cairo_svg_source_surface_t *a = key_a;
501  const cairo_svg_source_surface_t *b = key_b;
502 
503  if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length)
504  return (memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0);
505 
506  return (a->id == b->id);
507 }
508 
509 static void
511 {
512  cairo_svg_source_surface_t *surface_entry = entry;
514 
515  _cairo_hash_table_remove (patterns, &surface_entry->base);
516  free (surface_entry->unique_id);
517  free (surface_entry);
518 }
519 
520 static cairo_status_t
522  cairo_surface_t *source_surface,
523  int *source_id,
524  cairo_bool_t *is_new)
525 {
526  cairo_svg_source_surface_t source_key;
527  cairo_svg_source_surface_t *source_entry;
528  unsigned char *unique_id = NULL;
529  unsigned long unique_id_length = 0;
531 
532  source_key.id = source_surface->unique_id;
534  (const unsigned char **) &source_key.unique_id,
535  &source_key.unique_id_length);
537  source_entry = _cairo_hash_table_lookup (surface->source_surfaces, &source_key.base);
538  if (source_entry) {
539  *source_id = source_entry->id;
540  *is_new = FALSE;
541  return CAIRO_STATUS_SUCCESS;
542  }
543 
544  if (source_key.unique_id && source_key.unique_id_length > 0) {
545  unique_id = _cairo_malloc (source_key.unique_id_length);
546  if (unique_id == NULL) {
548  }
549 
550  unique_id_length = source_key.unique_id_length;
551  memcpy (unique_id, source_key.unique_id, unique_id_length);
552  } else {
553  unique_id = NULL;
554  unique_id_length = 0;
555  }
556 
557  source_entry = malloc (sizeof (cairo_svg_source_surface_t));
558  if (source_entry == NULL) {
560  goto fail;
561  }
562 
563  source_entry->id = source_key.id;
564  source_entry->unique_id_length = unique_id_length;
565  source_entry->unique_id = unique_id;
566  _cairo_svg_source_surface_init_key (source_entry);
567  status = _cairo_hash_table_insert (surface->source_surfaces, &source_entry->base);
568  if (unlikely(status))
569  goto fail;
570 
571  *is_new = TRUE;
572  *source_id = source_entry->id;
573  return CAIRO_STATUS_SUCCESS;
574 
575  fail:
576  free (unique_id);
577  free (source_entry);
578  return status;
579 }
580 
581 static cairo_bool_t
584 {
586 
588  if (box.p1.x <= 0 &&
589  box.p1.y <= 0 &&
590  _cairo_fixed_to_double (box.p2.x) >= surface->width &&
591  _cairo_fixed_to_double (box.p2.y) >= surface->height)
592  {
593  return TRUE;
594  }
595  }
596 
597  return FALSE;
598 }
599 
600 static cairo_status_t
603  cairo_fill_rule_t fill_rule,
604  double tolerance,
606 {
609  clipper);
611  unsigned int i;
612 
613  if (path == NULL) {
614  for (i = 0; i < surface->clip_level; i++)
615  _cairo_output_stream_printf (surface->xml_node, "</g>\n");
616 
617  surface->clip_level = 0;
618  return CAIRO_STATUS_SUCCESS;
619  }
620 
621  /* skip trivial whole-page clips */
623  return CAIRO_STATUS_SUCCESS;
624 
625  _cairo_output_stream_printf (document->xml_node_defs,
626  "<clipPath id=\"clip%d\">\n"
627  " <path ",
628  document->clip_id);
629  _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
630 
631  _cairo_output_stream_printf (document->xml_node_defs,
632  "/>\n"
633  "</clipPath>\n");
634 
636  "<g clip-path=\"url(#clip%d)\" "
637  "clip-rule=\"%s\">\n",
638  document->clip_id,
639  fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
640  "evenodd" : "nonzero");
641 
642  document->clip_id++;
643  surface->clip_level++;
644 
645  return CAIRO_STATUS_SUCCESS;
646 }
647 
648 static cairo_surface_t *
651  double width,
652  double height,
653  cairo_bool_t bounded)
654 {
656  cairo_surface_t *paginated;
657  cairo_status_t status, status_ignored;
658 
660  if (unlikely (surface == NULL))
662 
665  NULL, /* device */
666  content,
667  TRUE); /* is_vector */
668 
669  surface->width = width;
670  surface->height = height;
671  surface->surface_bounded = bounded;
672 
674 
675  surface->clip_level = 0;
678 
679  surface->base_clip = document->clip_id++;
680  surface->is_base_clip_emitted = FALSE;
681 
682  surface->xml_node = _cairo_memory_stream_create ();
684  if (unlikely (status))
685  goto CLEANUP;
686 
688 
689  if (content == CAIRO_CONTENT_COLOR) {
691  "<rect width=\"%f\" height=\"%f\" "
692  "style=\"opacity:1;stroke:none;"
693  "fill:rgb(0,0,0);\"/>\n",
694  width, height);
696  if (unlikely (status))
697  goto CLEANUP;
698  }
699 
700  surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
701  surface->force_fallbacks = FALSE;
703 
705  if (unlikely (surface->source_surfaces == NULL)) {
707  goto CLEANUP;
708  }
709 
710  paginated = _cairo_paginated_surface_create (&surface->base,
711  surface->content,
713  status = paginated->status;
714  if (status == CAIRO_STATUS_SUCCESS) {
715  /* paginated keeps the only reference to surface now, drop ours */
717  return paginated;
718  }
719 
720  /* ignore status as we are on the error path */
721 CLEANUP:
722  status_ignored = _cairo_output_stream_destroy (surface->xml_node);
723  status_ignored = _cairo_svg_document_destroy (document);
724 
725  free (surface);
726 
728 }
729 
730 static cairo_surface_t *
732  double width,
733  double height,
735 {
736  cairo_svg_document_t *document = NULL; /* silence compiler */
739 
741  width, height, version,
742  &document);
743  if (unlikely (status)) {
745  /* consume the output stream on behalf of caller */
747  return surface;
748  }
749 
751  width, height, TRUE);
752  if (surface->status) {
754  return surface;
755  }
756 
757  document->owner = surface;
759  /* the ref count should be 2 at this point */
761 
762  return surface;
763 }
764 
765 static cairo_svg_page_t *
767 {
771  unsigned int i;
772 
776  return NULL;
777  }
778 
779  page.surface_id = surface->base.unique_id;
780  page.clip_level = surface->clip_level;
781  page.xml_node = surface->xml_node;
782 
783  if (_cairo_array_append (&surface->page_set, &page)) {
785  return NULL;
786  }
787 
788  surface->xml_node = stream;
789  surface->clip_level = 0;
790  for (i = 0; i < page.clip_level; i++)
791  _cairo_output_stream_printf (page.xml_node, "</g>\n");
792 
794 
795  return _cairo_array_index (&surface->page_set,
796  surface->page_set.num_elements - 1);
797 }
798 
799 static cairo_int_status_t
800 _cairo_svg_surface_copy_page (void *abstract_surface)
801 {
802  cairo_svg_surface_t *surface = abstract_surface;
804 
806  if (unlikely (page == NULL))
808 
809  _cairo_memory_stream_copy (page->xml_node, surface->xml_node);
810 
811  return CAIRO_STATUS_SUCCESS;
812 }
813 
814 static cairo_int_status_t
815 _cairo_svg_surface_show_page (void *abstract_surface)
816 {
817  cairo_svg_surface_t *surface = abstract_surface;
818 
821 
822  return CAIRO_STATUS_SUCCESS;
823 }
824 
825 static void
827  char const *attribute_str,
828  const cairo_matrix_t *object_matrix,
829  const cairo_matrix_t *parent_matrix)
830 {
831  cairo_matrix_t matrix = *object_matrix;
832 
833  if (parent_matrix != NULL)
834  cairo_matrix_multiply (&matrix, &matrix, parent_matrix);
835 
838  "%s=\"matrix(%f,%f,%f,%f,%f,%f)\"",
839  attribute_str,
840  matrix.xx, matrix.yx,
841  matrix.xy, matrix.yy,
842  matrix.x0, matrix.y0);
843 }
844 
845 typedef struct {
847  const cairo_matrix_t *ctm_inverse;
849 
850 static cairo_status_t
852  const cairo_point_t *point)
853 {
855  double x = _cairo_fixed_to_double (point->x);
856  double y = _cairo_fixed_to_double (point->y);
857 
858  if (info->ctm_inverse)
859  cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
860 
861  _cairo_output_stream_printf (info->output, "M %f %f ", x, y);
862 
863  return CAIRO_STATUS_SUCCESS;
864 }
865 
866 static cairo_status_t
868  const cairo_point_t *point)
869 {
871  double x = _cairo_fixed_to_double (point->x);
872  double y = _cairo_fixed_to_double (point->y);
873 
874  if (info->ctm_inverse)
875  cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
876 
877  _cairo_output_stream_printf (info->output, "L %f %f ", x, y);
878 
879  return CAIRO_STATUS_SUCCESS;
880 }
881 
882 static cairo_status_t
884  const cairo_point_t *b,
885  const cairo_point_t *c,
886  const cairo_point_t *d)
887 {
889  double bx = _cairo_fixed_to_double (b->x);
890  double by = _cairo_fixed_to_double (b->y);
891  double cx = _cairo_fixed_to_double (c->x);
892  double cy = _cairo_fixed_to_double (c->y);
893  double dx = _cairo_fixed_to_double (d->x);
894  double dy = _cairo_fixed_to_double (d->y);
895 
896  if (info->ctm_inverse) {
897  cairo_matrix_transform_point (info->ctm_inverse, &bx, &by);
898  cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy);
899  cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
900  }
901 
903  "C %f %f %f %f %f %f ",
904  bx, by, cx, cy, dx, dy);
905 
906  return CAIRO_STATUS_SUCCESS;
907 }
908 
909 static cairo_status_t
911 {
913 
914  _cairo_output_stream_printf (info->output, "Z ");
915 
916  return CAIRO_STATUS_SUCCESS;
917 }
918 
919 static void
921  const cairo_path_fixed_t *path,
922  const cairo_matrix_t *ctm_inverse)
923 {
926 
928 
929  info.output = output;
930  info.ctm_inverse = ctm_inverse;
936  &info);
938 
940 }
941 
942 static cairo_int_status_t
944  cairo_scaled_font_t *scaled_font,
945  unsigned long glyph_index)
946 {
947  cairo_scaled_glyph_t *scaled_glyph;
949 
950  status = _cairo_scaled_glyph_lookup (scaled_font,
951  glyph_index,
954  &scaled_glyph);
955  if (unlikely (status))
956  return status;
957 
958  _cairo_output_stream_printf (document->xml_node_glyphs,
959  "<path style=\"stroke:none;\" ");
960 
961  _cairo_svg_surface_emit_path (document->xml_node_glyphs,
962  scaled_glyph->path, NULL);
963 
964  _cairo_output_stream_printf (document->xml_node_glyphs,
965  "/>\n");
966 
967  return status;
968 }
969 
970 static cairo_int_status_t
972  cairo_scaled_font_t *scaled_font,
973  unsigned long glyph_index)
974 {
975  cairo_scaled_glyph_t *scaled_glyph;
978  uint8_t *row, *byte;
979  int rows, cols;
980  int x, y, bit;
981 
982  status = _cairo_scaled_glyph_lookup (scaled_font,
983  glyph_index,
986  &scaled_glyph);
987  if (unlikely (status))
988  return status;
989 
992  status = image->base.status;
993  if (unlikely (status))
994  return status;
995 
996  _cairo_output_stream_printf (document->xml_node_glyphs, "<g");
997  _cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform",
998  &image->base.device_transform_inverse, NULL);
999  _cairo_output_stream_printf (document->xml_node_glyphs, ">\n");
1000 
1001  for (y = 0, row = image->data, rows = image->height; rows; row += image->stride, rows--, y++) {
1002  for (x = 0, byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
1004  for (bit = 7; bit >= 0 && x < image->width; bit--, x++) {
1005  if (output_byte & (1 << bit)) {
1006  _cairo_output_stream_printf (document->xml_node_glyphs,
1007  "<rect x=\"%d\" y=\"%d\" width=\"1\" height=\"1\"/>\n",
1008  x, y);
1009  }
1010  }
1011  }
1012  }
1013  _cairo_output_stream_printf (document->xml_node_glyphs, "</g>\n");
1014 
1015  cairo_surface_destroy (&image->base);
1016 
1017  return CAIRO_STATUS_SUCCESS;
1018 }
1019 
1020 static cairo_int_status_t
1022  cairo_scaled_font_t *scaled_font,
1023  unsigned long scaled_font_glyph_index,
1024  unsigned int font_id,
1025  unsigned int subset_glyph_index)
1026 {
1028 
1029  _cairo_output_stream_printf (document->xml_node_glyphs,
1030  "<symbol overflow=\"visible\" id=\"glyph%d-%d\">\n",
1031  font_id,
1032  subset_glyph_index);
1033 
1035  scaled_font,
1036  scaled_font_glyph_index);
1039  scaled_font,
1040  scaled_font_glyph_index);
1041  if (unlikely (status))
1042  return status;
1043 
1044  _cairo_output_stream_printf (document->xml_node_glyphs, "</symbol>\n");
1045 
1046  return CAIRO_INT_STATUS_SUCCESS;
1047 }
1048 
1049 static cairo_int_status_t
1051  void *closure)
1052 {
1055  unsigned int i;
1056 
1058  for (i = 0; i < font_subset->num_glyphs; i++) {
1060  font_subset->scaled_font,
1061  font_subset->glyphs[i],
1062  font_subset->font_id, i);
1063  if (unlikely (status))
1064  break;
1065  }
1067 
1068  return status;
1069 }
1070 
1071 static cairo_status_t
1073 {
1075 
1078  document);
1079  if (unlikely (status))
1080  goto FAIL;
1081 
1084  document);
1085 
1086  FAIL:
1088  document->font_subsets = NULL;
1089 
1090  return status;
1091 }
1092 
1093 static char const *
1095  "clear",
1096 
1097  "src", "src-over", "src-in",
1098  "src-out", "src-atop",
1099 
1100  "dst", "dst-over", "dst-in",
1101  "dst-out", "dst-atop",
1102 
1103  "xor", "plus",
1104  "color-dodge", /* FIXME: saturate ? */
1105 
1106  "multiply", "screen", "overlay",
1107  "darken", "lighten",
1108  "color-dodge", "color-burn",
1109  "hard-light", "soft-light",
1110  "difference", "exclusion"
1111 };
1112 
1113 static cairo_bool_t
1116 {
1117  /* guard against newly added operators */
1120 
1121  /* allow operators being NULL if they are unsupported */
1124 
1125  return CAIRO_STATUS_SUCCESS;
1126 }
1127 
1128 static cairo_int_status_t
1131  const cairo_pattern_t *pattern)
1132 {
1133  cairo_svg_document_t *document = surface->document;
1134 
1135  if (surface->force_fallbacks &&
1136  surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
1137  {
1139  }
1140 
1143 
1144  /* SVG doesn't support extend reflect for image pattern */
1146  pattern->extend == CAIRO_EXTEND_REFLECT)
1148 
1149  if (document->svg_version >= CAIRO_SVG_VERSION_1_2)
1151 
1152  if (op == CAIRO_OPERATOR_OVER)
1153  return CAIRO_STATUS_SUCCESS;
1154 
1155  /* The SOURCE operator is only supported if there is nothing
1156  * painted underneath. */
1157  if (op == CAIRO_OPERATOR_SOURCE)
1159 
1161 }
1162 
1163 static cairo_int_status_t
1166  const cairo_pattern_t *pattern)
1167 {
1169 }
1170 
1171 static cairo_status_t
1172 _cairo_svg_surface_finish (void *abstract_surface)
1173 {
1174  cairo_status_t status, status2;
1175  cairo_svg_surface_t *surface = abstract_surface;
1176  cairo_svg_document_t *document = surface->document;
1178  unsigned int i;
1179 
1180  if (_cairo_paginated_surface_get_target (document->owner) == &surface->base)
1182  else
1184 
1185  if (surface->xml_node != NULL) {
1186  status2 = _cairo_output_stream_destroy (surface->xml_node);
1188  status = status2;
1189  }
1190 
1191  for (i = 0; i < surface->page_set.num_elements; i++) {
1192  page = _cairo_array_index (&surface->page_set, i);
1193  status2 = _cairo_output_stream_destroy (page->xml_node);
1195  status = status2;
1196  }
1197  _cairo_array_fini (&surface->page_set);
1198 
1200 
1201  _cairo_hash_table_foreach (surface->source_surfaces,
1203  surface->source_surfaces);
1204  _cairo_hash_table_destroy (surface->source_surfaces);
1205 
1208  status = status2;
1209 
1210  return status;
1211 }
1212 
1213 
1214 static void
1216 {
1217  if (document->alpha_filter)
1218  return;
1219 
1220  _cairo_output_stream_printf (document->xml_node_defs,
1221  "<filter id=\"alpha\" "
1222  "filterUnits=\"objectBoundingBox\" "
1223  "x=\"0%%\" y=\"0%%\" "
1224  "width=\"100%%\" height=\"100%%\">\n"
1225  " <feColorMatrix type=\"matrix\" "
1226  "in=\"SourceGraphic\" "
1227  "values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0\"/>\n"
1228  "</filter>\n");
1229 
1230  document->alpha_filter = TRUE;
1231 }
1232 
1233 typedef struct {
1235  unsigned int in_mem;
1236  unsigned int trailing;
1237  unsigned char src[3];
1239 
1240 static char const base64_table[64] =
1241 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1242 
1243 static cairo_status_t
1245  const unsigned char *data,
1246  unsigned int length)
1247 {
1249  unsigned int i;
1250  unsigned char *src;
1251 
1252  src = info->src;
1253 
1254  if (info->in_mem + length < 3) {
1255  for (i = 0; i < length; i++) {
1256  src[i + info->in_mem] = *data++;
1257  }
1258  info->in_mem += length;
1259  return CAIRO_STATUS_SUCCESS;
1260  }
1261 
1262  do {
1263  unsigned char dst[4];
1264 
1265  for (i = info->in_mem; i < 3; i++) {
1266  src[i] = *data++;
1267  length--;
1268  }
1269  info->in_mem = 0;
1270 
1271  dst[0] = base64_table[src[0] >> 2];
1272  dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4];
1273  dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6];
1274  dst[3] = base64_table[src[2] & 0xfc >> 2];
1275  /* Special case for the last missing bits */
1276  switch (info->trailing) {
1277  case 2:
1278  dst[2] = '=';
1279  case 1:
1280  dst[3] = '=';
1281  default:
1282  break;
1283  }
1284  _cairo_output_stream_write (info->output, dst, 4);
1285  } while (length >= 3);
1286 
1287  for (i = 0; i < length; i++) {
1288  src[i] = *data++;
1289  }
1290  info->in_mem = length;
1291 
1292  return _cairo_output_stream_get_status (info->output);
1293 }
1294 
1295 static cairo_int_status_t
1298 {
1299  const unsigned char *mime_data;
1300  unsigned long mime_data_length;
1301  cairo_image_info_t image_info;
1304 
1306  &mime_data, &mime_data_length);
1307  if (mime_data == NULL)
1309 
1310  status = _cairo_image_info_get_jpeg_info (&image_info, mime_data, mime_data_length);
1311  if (unlikely (status))
1312  return status;
1313 
1314  if (image_info.num_components == 4)
1316 
1317  _cairo_output_stream_printf (output, "data:image/jpeg;base64,");
1318 
1319  info.output = output;
1320  info.in_mem = 0;
1321  info.trailing = 0;
1322 
1323  status = base64_write_func (&info, mime_data, mime_data_length);
1324  if (unlikely (status))
1325  return status;
1326 
1327  if (info.in_mem > 0) {
1328  memset (info.src + info.in_mem, 0, 3 - info.in_mem);
1329  info.trailing = 3 - info.in_mem;
1330  info.in_mem = 3;
1331  status = base64_write_func (&info, NULL, 0);
1332  }
1333 
1334  return status;
1335 }
1336 
1337 static cairo_int_status_t
1340 {
1341  const unsigned char *mime_data;
1342  unsigned long mime_data_length;
1345 
1347  &mime_data, &mime_data_length);
1348  if (unlikely (surface->status))
1349  return surface->status;
1350  if (mime_data == NULL)
1352 
1353  _cairo_output_stream_printf (output, "data:image/png;base64,");
1354 
1355  info.output = output;
1356  info.in_mem = 0;
1357  info.trailing = 0;
1358 
1359  status = base64_write_func (&info, mime_data, mime_data_length);
1360  if (unlikely (status))
1361  return status;
1362 
1363  if (info.in_mem > 0) {
1364  memset (info.src + info.in_mem, 0, 3 - info.in_mem);
1365  info.trailing = 3 - info.in_mem;
1366  info.in_mem = 3;
1367  status = base64_write_func (&info, NULL, 0);
1368  }
1369 
1370  return status;
1371 }
1372 
1373 static cairo_int_status_t
1376 {
1379 
1382  return status;
1383 
1386  return status;
1387 
1388  info.output = output;
1389  info.in_mem = 0;
1390  info.trailing = 0;
1391 
1392  _cairo_output_stream_printf (info.output, "data:image/png;base64,");
1393 
1395  (void *) &info);
1396 
1397  if (unlikely (status))
1398  return status;
1399 
1400  if (info.in_mem > 0) {
1401  memset (info.src + info.in_mem, 0, 3 - info.in_mem);
1402  info.trailing = 3 - info.in_mem;
1403  info.in_mem = 3;
1404  status = base64_write_func (&info, NULL, 0);
1405  }
1406 
1407  return status;
1408 }
1409 
1410 static void
1414 {
1415  if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2 &&
1416  op != CAIRO_OPERATOR_OVER) {
1419  _cairo_output_stream_printf (output, " clip-to-self=\"true\"");
1420  }
1421 }
1422 
1423 static void
1427 {
1428  if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2 &&
1429  op != CAIRO_OPERATOR_OVER) {
1432  _cairo_output_stream_printf (output, "clip-to-self:true;");
1433  }
1434 }
1435 
1436 /**
1437  * _cairo_svg_surface_emit_attr_value:
1438  *
1439  * Write the value to output the stream as a sequence of characters,
1440  * while escaping those which have special meaning in the XML
1441  * attribute's value context: &amp; and &quot;.
1442  **/
1443 static void
1445  const unsigned char *value,
1446  unsigned int length)
1447 {
1448  const unsigned char *p;
1449  const unsigned char *q;
1450  unsigned int i;
1451 
1452  /* we'll accumulate non-special chars in [q, p) range */
1453  p = value;
1454  q = p;
1455  for (i = 0; i < length; i++, p++) {
1456  if (*p == '&' || *p == '"') {
1457  /* flush what's left before special char */
1458  if (p != q) {
1460  q = p + 1;
1461  }
1462 
1463  if (*p == '&')
1465  else // p == '"'
1466  _cairo_output_stream_printf (stream, "&quot;");
1467  }
1468  }
1469 
1470  /* flush the trailing chars if any */
1471  if (p != q)
1473 }
1474 
1475 static cairo_status_t
1478  int source_id)
1479 {
1481  cairo_bool_t is_bounded;
1483  const unsigned char *uri;
1484  unsigned long uri_len;
1485 
1486  is_bounded = _cairo_surface_get_extents (surface, &extents);
1487  assert (is_bounded);
1488 
1489  _cairo_output_stream_printf (document->xml_node_defs,
1490  "<image id=\"image%d\" width=\"%d\" height=\"%d\"",
1491  source_id,
1492  extents.width, extents.height);
1493 
1494  _cairo_output_stream_printf (document->xml_node_defs, " xlink:href=\"");
1495 
1497  &uri, &uri_len);
1498  if (uri != NULL) {
1500  uri, uri_len);
1501  } else {
1503  document->xml_node_defs);
1504  if (unlikely (status))
1505  return status;
1506  }
1507 
1508  _cairo_output_stream_printf (document->xml_node_defs, "\"/>\n");
1509 
1510  return CAIRO_STATUS_SUCCESS;
1511 }
1512 
1513 static cairo_status_t
1515  cairo_svg_surface_t *svg_surface,
1518  int pattern_id,
1519  const cairo_matrix_t *parent_matrix,
1520  const char *extra_attributes)
1521 {
1523  cairo_matrix_t p2u;
1524  int source_id;
1525  cairo_bool_t is_new;
1526 
1527  p2u = pattern->base.matrix;
1528  status = cairo_matrix_invert (&p2u);
1529  /* cairo_pattern_set_matrix ensures the matrix is invertible */
1531 
1533  pattern->surface,
1534  &source_id,
1535  &is_new);
1536  if (unlikely (status))
1537  return status;
1538 
1539  if (is_new) {
1541  pattern->surface,
1542  source_id);
1543  if (unlikely (status))
1544  return status;
1545  }
1546 
1547  if (pattern_id != invalid_pattern_id) {
1549  cairo_bool_t is_bounded;
1550 
1551  is_bounded = _cairo_surface_get_extents (pattern->surface, &extents);
1552  assert (is_bounded);
1553 
1555  "<pattern id=\"pattern%d\" "
1556  "patternUnits=\"userSpaceOnUse\" "
1557  "width=\"%d\" height=\"%d\" ",
1558  pattern_id,
1559  extents.width, extents.height);
1561  " patternTransform",
1562  &p2u, parent_matrix);
1564  }
1565 
1567  "<use xlink:href=\"#image%d\"",
1568  source_id);
1569  if (extra_attributes)
1570  _cairo_output_stream_printf (output, " %s", extra_attributes);
1571 
1572  if (pattern_id == invalid_pattern_id) {
1573  _cairo_svg_surface_emit_operator (output, svg_surface, op);
1575  " transform",
1576  &p2u, parent_matrix);
1577  }
1579 
1580 
1581  if (pattern_id != invalid_pattern_id)
1582  _cairo_output_stream_printf (output, "</pattern>\n");
1583 
1584  return CAIRO_STATUS_SUCCESS;
1585 }
1586 
1587 static cairo_status_t
1590  int source_id)
1591 {
1593  cairo_surface_t *paginated_surface;
1594  cairo_svg_surface_t *svg_surface;
1595  cairo_array_t *page_set;
1597  cairo_bool_t bounded;
1598  cairo_output_stream_t *contents;
1599 
1600  bounded = _cairo_surface_get_extents (&source->base, &extents);
1601  paginated_surface = _cairo_svg_surface_create_for_document (document,
1602  source->base.content,
1603  extents.width,
1604  extents.height,
1605  bounded);
1606  if (unlikely (paginated_surface->status))
1607  return paginated_surface->status;
1608 
1609  svg_surface = (cairo_svg_surface_t *)
1610  _cairo_paginated_surface_get_target (paginated_surface);
1611  cairo_surface_set_fallback_resolution (paginated_surface,
1612  document->owner->x_fallback_resolution,
1613  document->owner->y_fallback_resolution);
1614  cairo_surface_set_device_offset (&svg_surface->base,
1615  -source->extents_pixels.x,
1616  -source->extents_pixels.y);
1617 
1618  status = _cairo_recording_surface_replay (&source->base, paginated_surface);
1619  if (unlikely (status)) {
1620  cairo_surface_destroy (paginated_surface);
1621  return status;
1622  }
1623 
1624  cairo_surface_show_page (paginated_surface);
1625  status = cairo_surface_status (paginated_surface);
1626  if (unlikely (status)) {
1627  cairo_surface_destroy (paginated_surface);
1628  return status;
1629  }
1630 
1631  if (! svg_surface->is_base_clip_emitted) {
1632  svg_surface->is_base_clip_emitted = TRUE;
1633  if (_cairo_surface_get_extents (&svg_surface->base, &extents)) {
1634  _cairo_output_stream_printf (document->xml_node_defs,
1635  "<clipPath id=\"clip%d\">\n"
1636  " <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
1637  "</clipPath>\n",
1638  svg_surface->base_clip,
1639  extents.x,
1640  extents.y,
1641  extents.width,
1642  extents.height);
1643  }
1644  }
1645 
1646  if (source->base.content == CAIRO_CONTENT_ALPHA) {
1648  _cairo_output_stream_printf (document->xml_node_defs,
1649  "<g id=\"surface%d\" "
1650  "clip-path=\"url(#clip%d)\" "
1651  "filter=\"url(#alpha)\">\n",
1652  source_id,
1653  svg_surface->base_clip);
1654  } else {
1655  _cairo_output_stream_printf (document->xml_node_defs,
1656  "<g id=\"surface%d\" "
1657  "clip-path=\"url(#clip%d)\">\n",
1658  source_id,
1659  svg_surface->base_clip);
1660  }
1661 
1662  contents = svg_surface->xml_node;
1663  page_set = &svg_surface->page_set;
1664 
1665  if (_cairo_memory_stream_length (contents) > 0) {
1666  if (unlikely (_cairo_svg_surface_store_page (svg_surface) == NULL)) {
1667  cairo_surface_destroy (paginated_surface);
1669  }
1670  }
1671 
1672  if (page_set->num_elements > 0) {
1674 
1675  page = _cairo_array_index (page_set, page_set->num_elements - 1);
1676  _cairo_memory_stream_copy (page->xml_node, document->xml_node_defs);
1677  }
1678 
1679  _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
1680 
1681  status = cairo_surface_status (paginated_surface);
1682  cairo_surface_destroy (paginated_surface);
1683 
1684  return status;
1685 }
1686 
1689 {
1690  cairo_surface_t *surface = pattern->surface;
1696 }
1697 
1698 static cairo_status_t
1703  int pattern_id,
1704  const cairo_matrix_t *parent_matrix,
1705  const char *extra_attributes)
1706 {
1707  cairo_svg_document_t *document = surface->document;
1708  cairo_recording_surface_t *recording_surface;
1709  cairo_matrix_t p2u;
1711  int source_id;
1712  cairo_bool_t is_new;
1713 
1714  p2u = pattern->base.matrix;
1715  status = cairo_matrix_invert (&p2u);
1716  /* cairo_pattern_set_matrix ensures the matrix is invertible */
1718 
1720  pattern->surface,
1721  &source_id,
1722  &is_new);
1723  if (unlikely (status))
1724  return status;
1725 
1726  recording_surface = to_recording_surface (pattern);
1727  if (is_new) {
1728  status = _cairo_svg_surface_emit_recording_surface (document, recording_surface, source_id);
1729  if (unlikely (status))
1730  return status;
1731  }
1732 
1733  if (pattern_id != invalid_pattern_id) {
1735  "<pattern id=\"pattern%d\" "
1736  "patternUnits=\"userSpaceOnUse\" "
1737  "width=\"%d\" height=\"%d\"",
1738  pattern_id,
1739  recording_surface->extents.width,
1740  recording_surface->extents.height);
1741  _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
1743  }
1744 
1746  "<use xlink:href=\"#surface%d\"",
1747  source_id);
1748 
1749  if (pattern_id == invalid_pattern_id) {
1751  _cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix);
1752  }
1753 
1754  if (extra_attributes)
1755  _cairo_output_stream_printf (output, " %s", extra_attributes);
1756 
1758 
1759  if (pattern_id != invalid_pattern_id)
1760  _cairo_output_stream_printf (output, "</pattern>\n");
1761 
1762  return CAIRO_STATUS_SUCCESS;
1763 }
1764 
1765 static cairo_status_t
1770  int pattern_id,
1771  const cairo_matrix_t *parent_matrix,
1772  const char *extra_attributes)
1773 {
1774 
1775  if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
1777  op, pattern,
1778  pattern_id,
1779  parent_matrix,
1780  extra_attributes);
1781  }
1782 
1784  op, pattern,
1785  pattern_id,
1786  parent_matrix,
1787  extra_attributes);
1788 }
1789 
1790 static cairo_status_t
1794  cairo_bool_t is_stroke)
1795 {
1796  _cairo_output_stream_printf (style, is_stroke ?
1797  "stroke:rgb(%f%%,%f%%,%f%%);stroke-opacity:%f;":
1798  "fill:rgb(%f%%,%f%%,%f%%);fill-opacity:%f;",
1799  pattern->color.red * 100.0,
1800  pattern->color.green * 100.0,
1801  pattern->color.blue * 100.0,
1802  pattern->color.alpha);
1803 
1804  return CAIRO_STATUS_SUCCESS;
1805 }
1806 
1807 static cairo_status_t
1811  cairo_bool_t is_stroke,
1812  const cairo_matrix_t *parent_matrix)
1813 {
1814  cairo_svg_document_t *document = surface->document;
1816  int pattern_id;
1817 
1818  pattern_id = document->pattern_id++;
1821  pattern_id, parent_matrix, NULL);
1822  if (unlikely (status))
1823  return status;
1824 
1826  "%s:url(#pattern%d);",
1827  is_stroke ? "stroke" : "fill",
1828  pattern_id);
1829 
1830  return CAIRO_STATUS_SUCCESS;
1831 }
1832 
1833 static cairo_status_t
1836  double start_offset,
1837  cairo_bool_t reverse_stops,
1838  cairo_bool_t emulate_reflect)
1839 {
1840  cairo_gradient_stop_t *stops;
1841  double offset;
1842  unsigned int n_stops;
1843  unsigned int i;
1844 
1845  if (pattern->n_stops < 1)
1846  return CAIRO_STATUS_SUCCESS;
1847 
1848  if (pattern->n_stops == 1) {
1850  "<stop offset=\"%f\" style=\""
1851  "stop-color:rgb(%f%%,%f%%,%f%%);"
1852  "stop-opacity:%f;\"/>\n",
1853  pattern->stops[0].offset,
1854  pattern->stops[0].color.red * 100.0,
1855  pattern->stops[0].color.green * 100.0,
1856  pattern->stops[0].color.blue * 100.0,
1857  pattern->stops[0].color.alpha);
1858  return CAIRO_STATUS_SUCCESS;
1859  }
1860 
1861  if (emulate_reflect || reverse_stops) {
1862  n_stops = emulate_reflect ? pattern->n_stops * 2 - 2: pattern->n_stops;
1863  stops = _cairo_malloc_ab (n_stops, sizeof (cairo_gradient_stop_t));
1864  if (unlikely (stops == NULL))
1866 
1867  for (i = 0; i < pattern->n_stops; i++) {
1868  if (reverse_stops) {
1869  stops[i] = pattern->stops[pattern->n_stops - i - 1];
1870  stops[i].offset = 1.0 - stops[i].offset;
1871  } else
1872  stops[i] = pattern->stops[i];
1873  if (emulate_reflect) {
1874  stops[i].offset /= 2;
1875  if (i > 0 && i < (pattern->n_stops - 1)) {
1876  if (reverse_stops) {
1877  stops[i + pattern->n_stops - 1] = pattern->stops[i];
1878  stops[i + pattern->n_stops - 1].offset =
1879  0.5 + 0.5 * stops[i + pattern->n_stops - 1].offset;
1880  } else {
1881  stops[i + pattern->n_stops - 1] = pattern->stops[pattern->n_stops - i - 1];
1882  stops[i + pattern->n_stops - 1].offset =
1883  1 - 0.5 * stops[i + pattern->n_stops - 1].offset;
1884  }
1885  }
1886  }
1887  }
1888  } else {
1889  n_stops = pattern->n_stops;
1890  stops = pattern->stops;
1891  }
1892 
1893  if (start_offset >= 0.0)
1894  for (i = 0; i < n_stops; i++) {
1895  offset = start_offset + (1 - start_offset ) * stops[i].offset;
1897  "<stop offset=\"%f\" style=\""
1898  "stop-color:rgb(%f%%,%f%%,%f%%);"
1899  "stop-opacity:%f;\"/>\n",
1900  offset,
1901  stops[i].color.red * 100.0,
1902  stops[i].color.green * 100.0,
1903  stops[i].color.blue * 100.0,
1904  stops[i].color.alpha);
1905  }
1906  else {
1908  unsigned int offset_index;
1909  cairo_color_stop_t offset_color_start, offset_color_stop;
1910 
1911  for (i = 0; i < n_stops; i++) {
1912  if (stops[i].offset >= -start_offset) {
1913  if (i > 0) {
1914  if (stops[i].offset != stops[i-1].offset) {
1915  double x0, x1;
1916  cairo_color_stop_t *color0, *color1;
1917 
1918  x0 = stops[i-1].offset;
1919  x1 = stops[i].offset;
1920  color0 = &stops[i-1].color;
1921  color1 = &stops[i].color;
1922  offset_color_start.red = color0->red + (color1->red - color0->red)
1923  * (-start_offset - x0) / (x1 - x0);
1924  offset_color_start.green = color0->green + (color1->green - color0->green)
1925  * (-start_offset - x0) / (x1 - x0);
1926  offset_color_start.blue = color0->blue + (color1->blue - color0->blue)
1927  * (-start_offset - x0) / (x1 - x0);
1928  offset_color_start.alpha = color0->alpha + (color1->alpha - color0->alpha)
1929  * (-start_offset - x0) / (x1 - x0);
1930  offset_color_stop = offset_color_start;
1931  } else {
1932  offset_color_stop = stops[i-1].color;
1933  offset_color_start = stops[i].color;
1934  }
1935  } else
1936  offset_color_stop = offset_color_start = stops[i].color;
1937  offset_index = i;
1938  found = TRUE;
1939  break;
1940  }
1941  }
1942 
1943  if (!found) {
1944  offset_index = n_stops - 1;
1945  offset_color_stop = offset_color_start = stops[offset_index].color;
1946  }
1947 
1949  "<stop offset=\"0\" style=\""
1950  "stop-color:rgb(%f%%,%f%%,%f%%);"
1951  "stop-opacity:%f;\"/>\n",
1952  offset_color_start.red * 100.0,
1953  offset_color_start.green * 100.0,
1954  offset_color_start.blue * 100.0,
1955  offset_color_start.alpha);
1956  for (i = offset_index; i < n_stops; i++) {
1958  "<stop offset=\"%f\" style=\""
1959  "stop-color:rgb(%f%%,%f%%,%f%%);"
1960  "stop-opacity:%f;\"/>\n",
1961  stops[i].offset + start_offset,
1962  stops[i].color.red * 100.0,
1963  stops[i].color.green * 100.0,
1964  stops[i].color.blue * 100.0,
1965  stops[i].color.alpha);
1966  }
1967  for (i = 0; i < offset_index; i++) {
1969  "<stop offset=\"%f\" style=\""
1970  "stop-color:rgb(%f%%,%f%%,%f%%);"
1971  "stop-opacity:%f;\"/>\n",
1972  1.0 + stops[i].offset + start_offset,
1973  stops[i].color.red * 100.0,
1974  stops[i].color.green * 100.0,
1975  stops[i].color.blue * 100.0,
1976  stops[i].color.alpha);
1977  }
1978 
1980  "<stop offset=\"1\" style=\""
1981  "stop-color:rgb(%f%%,%f%%,%f%%);"
1982  "stop-opacity:%f;\"/>\n",
1983  offset_color_stop.red * 100.0,
1984  offset_color_stop.green * 100.0,
1985  offset_color_stop.blue * 100.0,
1986  offset_color_stop.alpha);
1987 
1988  }
1989 
1990  if (reverse_stops || emulate_reflect)
1991  free (stops);
1992 
1993  return CAIRO_STATUS_SUCCESS;
1994 }
1995 
1996 static void
1999 {
2000  switch (pattern->extend) {
2001  case CAIRO_EXTEND_REPEAT:
2002  _cairo_output_stream_printf (output, "spreadMethod=\"repeat\" ");
2003  break;
2004  case CAIRO_EXTEND_REFLECT:
2005  _cairo_output_stream_printf (output, "spreadMethod=\"reflect\" ");
2006  break;
2007  case CAIRO_EXTEND_NONE:
2008  case CAIRO_EXTEND_PAD:
2009  break;
2010  }
2011 }
2012 
2013 static cairo_status_t
2017  cairo_bool_t is_stroke,
2018  const cairo_matrix_t *parent_matrix)
2019 {
2020  cairo_svg_document_t *document = surface->document;
2021  cairo_matrix_t p2u;
2023 
2024  p2u = pattern->base.base.matrix;
2025  status = cairo_matrix_invert (&p2u);
2026  /* cairo_pattern_set_matrix ensures the matrix is invertible */
2028 
2029  _cairo_output_stream_printf (document->xml_node_defs,
2030  "<linearGradient id=\"linear%d\" "
2031  "gradientUnits=\"userSpaceOnUse\" "
2032  "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
2033  document->linear_pattern_id,
2034  pattern->pd1.x, pattern->pd1.y,
2035  pattern->pd2.x, pattern->pd2.y);
2036 
2037  _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
2038  _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
2039  _cairo_output_stream_printf (document->xml_node_defs, ">\n");
2040 
2042  &pattern->base, 0.0,
2043  FALSE, FALSE);
2044  if (unlikely (status))
2045  return status;
2046 
2047  _cairo_output_stream_printf (document->xml_node_defs,
2048  "</linearGradient>\n");
2049 
2051  "%s:url(#linear%d);",
2052  is_stroke ? "stroke" : "fill",
2053  document->linear_pattern_id);
2054 
2055  document->linear_pattern_id++;
2056 
2057  return CAIRO_STATUS_SUCCESS;
2058 }
2059 
2060 static cairo_status_t
2064  cairo_bool_t is_stroke,
2065  const cairo_matrix_t *parent_matrix)
2066 {
2067  cairo_svg_document_t *document = surface->document;
2068  cairo_matrix_t p2u;
2070  double x0, y0, x1, y1, r0, r1;
2071  double fx, fy;
2072  cairo_bool_t reverse_stops;
2074  cairo_circle_double_t *c0, *c1;
2075 
2076  extend = pattern->base.base.extend;
2077 
2078  if (pattern->cd1.radius < pattern->cd2.radius) {
2079  c0 = &pattern->cd1;
2080  c1 = &pattern->cd2;
2081  reverse_stops = FALSE;
2082  } else {
2083  c0 = &pattern->cd2;
2084  c1 = &pattern->cd1;
2085  reverse_stops = TRUE;
2086  }
2087 
2088  x0 = c0->center.x;
2089  y0 = c0->center.y;
2090  r0 = c0->radius;
2091  x1 = c1->center.x;
2092  y1 = c1->center.y;
2093  r1 = c1->radius;
2094 
2095  p2u = pattern->base.base.matrix;
2096  status = cairo_matrix_invert (&p2u);
2097  /* cairo_pattern_set_matrix ensures the matrix is invertible */
2099 
2100  if (r0 == r1) {
2101  unsigned int n_stops = pattern->base.n_stops;
2102 
2103  _cairo_output_stream_printf (document->xml_node_defs,
2104  "<radialGradient id=\"radial%d\" "
2105  "gradientUnits=\"userSpaceOnUse\" "
2106  "cx=\"%f\" cy=\"%f\" "
2107  "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
2108  document->radial_pattern_id,
2109  x1, y1,
2110  x1, y1, r1);
2112  "gradientTransform",
2113  &p2u, parent_matrix);
2114  _cairo_output_stream_printf (document->xml_node_defs, ">\n");
2115 
2116  if (extend == CAIRO_EXTEND_NONE || n_stops < 1)
2117  _cairo_output_stream_printf (document->xml_node_defs,
2118  "<stop offset=\"0\" style=\""
2119  "stop-color:rgb(0%%,0%%,0%%);"
2120  "stop-opacity:0;\"/>\n");
2121  else {
2122  _cairo_output_stream_printf (document->xml_node_defs,
2123  "<stop offset=\"0\" style=\""
2124  "stop-color:rgb(%f%%,%f%%,%f%%);"
2125  "stop-opacity %f;\"/>\n",
2126  pattern->base.stops[0].color.red * 100.0,
2127  pattern->base.stops[0].color.green * 100.0,
2128  pattern->base.stops[0].color.blue * 100.0,
2129  pattern->base.stops[0].color.alpha);
2130  if (n_stops > 1)
2131  _cairo_output_stream_printf (document->xml_node_defs,
2132  "<stop offset=\"0\" style=\""
2133  "stop-color:rgb(%f%%,%f%%,%f%%);"
2134  "stop-opacity:%f;\"/>\n",
2135  pattern->base.stops[n_stops - 1].color.red * 100.0,
2136  pattern->base.stops[n_stops - 1].color.green * 100.0,
2137  pattern->base.stops[n_stops - 1].color.blue * 100.0,
2138  pattern->base.stops[n_stops - 1].color.alpha);
2139  }
2140 
2141  } else {
2142  double offset, r, x, y;
2143  cairo_bool_t emulate_reflect = FALSE;
2144 
2145  fx = (r1 * x0 - r0 * x1) / (r1 - r0);
2146  fy = (r1 * y0 - r0 * y1) / (r1 - r0);
2147 
2148  /* SVG doesn't support the inner circle and use instead a gradient focal.
2149  * That means we need to emulate the cairo behaviour by processing the
2150  * cairo gradient stops.
2151  * The CAIRO_EXTENT_NONE and CAIRO_EXTENT_PAD modes are quite easy to handle,
2152  * it's just a matter of stop position translation and calculation of
2153  * the corresponding SVG radial gradient focal.
2154  * The CAIRO_EXTENT_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new
2155  * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT
2156  * case, and 2 * (r1 - r0) in the CAIRO_EXTENT_REFLECT case, and a new gradient stop
2157  * list that maps to the original cairo stop list.
2158  */
2161  && r0 > 0.0) {
2162  double r_org = r1;
2163 
2164  if (extend == CAIRO_EXTEND_REFLECT) {
2165  r1 = 2 * r1 - r0;
2166  emulate_reflect = TRUE;
2167  }
2168 
2169  offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0;
2170  r = r1 - r0;
2171 
2172  /* New position of outer circle. */
2173  x = r * (x1 - fx) / r_org + fx;
2174  y = r * (y1 - fy) / r_org + fy;
2175 
2176  x1 = x;
2177  y1 = y;
2178  r1 = r;
2179  r0 = 0.0;
2180  } else {
2181  offset = r0 / r1;
2182  }
2183 
2184  _cairo_output_stream_printf (document->xml_node_defs,
2185  "<radialGradient id=\"radial%d\" "
2186  "gradientUnits=\"userSpaceOnUse\" "
2187  "cx=\"%f\" cy=\"%f\" "
2188  "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
2189  document->radial_pattern_id,
2190  x1, y1,
2191  fx, fy, r1);
2192 
2193  if (emulate_reflect)
2194  _cairo_output_stream_printf (document->xml_node_defs, "spreadMethod=\"repeat\" ");
2195  else
2196  _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
2197  _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
2198  _cairo_output_stream_printf (document->xml_node_defs, ">\n");
2199 
2200  /* To support cairo's EXTEND_NONE, (for which SVG has no similar
2201  * notion), we add transparent color stops on either end of the
2202  * user-provided stops. */
2203  if (extend == CAIRO_EXTEND_NONE) {
2204  _cairo_output_stream_printf (document->xml_node_defs,
2205  "<stop offset=\"0\" style=\""
2206  "stop-color:rgb(0%%,0%%,0%%);"
2207  "stop-opacity:0;\"/>\n");
2208  if (r0 != 0.0)
2209  _cairo_output_stream_printf (document->xml_node_defs,
2210  "<stop offset=\"%f\" style=\""
2211  "stop-color:rgb(0%%,0%%,0%%);"
2212  "stop-opacity:0;\"/>\n",
2213  r0 / r1);
2214  }
2216  &pattern->base, offset,
2217  reverse_stops,
2218  emulate_reflect);
2219  if (unlikely (status))
2220  return status;
2221 
2222  if (pattern->base.base.extend == CAIRO_EXTEND_NONE)
2223  _cairo_output_stream_printf (document->xml_node_defs,
2224  "<stop offset=\"1.0\" style=\""
2225  "stop-color:rgb(0%%,0%%,0%%);"
2226  "stop-opacity:0;\"/>\n");
2227  }
2228 
2229  _cairo_output_stream_printf (document->xml_node_defs,
2230  "</radialGradient>\n");
2231 
2233  "%s:url(#radial%d);",
2234  is_stroke ? "stroke" : "fill",
2235  document->radial_pattern_id);
2236 
2237  document->radial_pattern_id++;
2238 
2239  return CAIRO_STATUS_SUCCESS;
2240 }
2241 
2242 static cairo_status_t
2244  const cairo_pattern_t *pattern,
2246  cairo_bool_t is_stroke,
2247  const cairo_matrix_t *parent_matrix)
2248 {
2249  switch (pattern->type) {
2252  output, is_stroke);
2253 
2256  output, is_stroke, parent_matrix);
2257 
2260  output, is_stroke, parent_matrix);
2261 
2264  output, is_stroke, parent_matrix);
2265 
2269  }
2271 }
2272 
2273 static cairo_status_t
2277  const cairo_pattern_t *source,
2278  cairo_fill_rule_t fill_rule,
2279  const cairo_matrix_t *parent_matrix)
2280 {
2282  "fill-rule:%s;",
2283  fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
2284  "evenodd" : "nonzero");
2286  return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, parent_matrix);
2287 }
2288 
2289 static cairo_status_t
2293  const cairo_pattern_t *source,
2294  const cairo_stroke_style_t *stroke_style,
2295  const cairo_matrix_t *parent_matrix)
2296 {
2298  const char *line_cap, *line_join;
2299  unsigned int i;
2300 
2301  switch (stroke_style->line_cap) {
2302  case CAIRO_LINE_CAP_BUTT:
2303  line_cap = "butt";
2304  break;
2305  case CAIRO_LINE_CAP_ROUND:
2306  line_cap = "round";
2307  break;
2308  case CAIRO_LINE_CAP_SQUARE:
2309  line_cap = "square";
2310  break;
2311  default:
2313  }
2314 
2315  switch (stroke_style->line_join) {
2316  case CAIRO_LINE_JOIN_MITER:
2317  line_join = "miter";
2318  break;
2319  case CAIRO_LINE_JOIN_ROUND:
2320  line_join = "round";
2321  break;
2322  case CAIRO_LINE_JOIN_BEVEL:
2323  line_join = "bevel";
2324  break;
2325  default:
2327  }
2328 
2330  "stroke-width:%f;"
2331  "stroke-linecap:%s;"
2332  "stroke-linejoin:%s;",
2333  stroke_style->line_width,
2334  line_cap,
2335  line_join);
2336 
2338  if (unlikely (status))
2339  return status;
2340 
2342 
2343  if (stroke_style->num_dashes > 0) {
2344  _cairo_output_stream_printf (output, "stroke-dasharray:");
2345  for (i = 0; i < stroke_style->num_dashes; i++) {
2347  stroke_style->dash[i]);
2348  if (i + 1 < stroke_style->num_dashes)
2350  else
2352  }
2353  if (stroke_style->dash_offset != 0.0) {
2355  "stroke-dashoffset:%f;",
2356  stroke_style->dash_offset);
2357  }
2358  }
2359 
2361  "stroke-miterlimit:%f;",
2362  stroke_style->miter_limit);
2363 
2364  return CAIRO_STATUS_SUCCESS;
2365 }
2366 
2367 static cairo_int_status_t
2368 _cairo_svg_surface_fill_stroke (void *abstract_surface,
2369  cairo_operator_t fill_op,
2370  const cairo_pattern_t *fill_source,
2371  cairo_fill_rule_t fill_rule,
2372  double fill_tolerance,
2373  cairo_antialias_t fill_antialias,
2374  const cairo_path_fixed_t*path,
2375  cairo_operator_t stroke_op,
2376  const cairo_pattern_t *stroke_source,
2377  const cairo_stroke_style_t *stroke_style,
2378  const cairo_matrix_t *stroke_ctm,
2379  const cairo_matrix_t *stroke_ctm_inverse,
2380  double stroke_tolerance,
2381  cairo_antialias_t stroke_antialias,
2382  const cairo_clip_t *clip)
2383 {
2384  cairo_svg_surface_t *surface = abstract_surface;
2386 
2388  if (unlikely (status))
2389  return status;
2390 
2391  _cairo_output_stream_printf (surface->xml_node, "<path style=\"");
2393  fill_source, fill_rule, stroke_ctm_inverse);
2394  if (unlikely (status))
2395  return status;
2396 
2398  stroke_source, stroke_style, stroke_ctm_inverse);
2399  if (unlikely (status))
2400  return status;
2401 
2402  _cairo_output_stream_printf (surface->xml_node, "\" ");
2403 
2404  _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
2405 
2406  _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL);
2407  _cairo_output_stream_printf (surface->xml_node, "/>\n");
2408 
2409  return CAIRO_STATUS_SUCCESS;
2410 }
2411 
2412 static cairo_int_status_t
2413 _cairo_svg_surface_fill (void *abstract_surface,
2415  const cairo_pattern_t *source,
2416  const cairo_path_fixed_t*path,
2417  cairo_fill_rule_t fill_rule,
2418  double tolerance,
2420  const cairo_clip_t *clip)
2421 {
2422  cairo_svg_surface_t *surface = abstract_surface;
2424 
2425  if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
2427 
2429 
2431  if (unlikely (status))
2432  return status;
2433 
2434  _cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;");
2435  status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
2436  if (unlikely (status))
2437  return status;
2438 
2439  _cairo_output_stream_printf (surface->xml_node, "\" ");
2440 
2442 
2443  _cairo_output_stream_printf (surface->xml_node, "/>\n");
2444 
2445  return CAIRO_STATUS_SUCCESS;
2446 }
2447 
2448 static cairo_bool_t
2449 _cairo_svg_surface_get_extents (void *abstract_surface,
2450  cairo_rectangle_int_t *rectangle)
2451 {
2452  cairo_svg_surface_t *surface = abstract_surface;
2453 
2454  rectangle->x = 0;
2455  rectangle->y = 0;
2456 
2457  /* XXX: The conversion to integers here is pretty bogus, (not to
2458  * mention the arbitrary limitation of width to a short(!). We
2459  * may need to come up with a better interface for get_size.
2460  */
2461  rectangle->width = ceil (surface->width);
2462  rectangle->height = ceil (surface->height);
2463 
2464  return surface->surface_bounded;
2465 }
2466 
2467 static cairo_status_t
2471  const cairo_pattern_t *source,
2472  const cairo_pattern_t *mask_source,
2473  const char *extra_attributes)
2474 {
2476 
2478  source->extend == CAIRO_EXTEND_NONE)
2480  surface,
2481  op,
2484  mask_source ? &mask_source->matrix :NULL,
2485  extra_attributes);
2486 
2488  "<rect x=\"0\" y=\"0\" "
2489  "width=\"%f\" height=\"%f\" "
2490  "style=\"",
2491  surface->width, surface->height);
2494  if (unlikely (status))
2495  return status;
2496 
2497  _cairo_output_stream_printf (output, "stroke:none;\"");
2498 
2499  if (extra_attributes)
2500  _cairo_output_stream_printf (output, " %s", extra_attributes);
2501 
2503 
2504  return CAIRO_STATUS_SUCCESS;
2505 }
2506 
2507 static cairo_int_status_t
2508 _cairo_svg_surface_paint (void *abstract_surface,
2510  const cairo_pattern_t *source,
2511  const cairo_clip_t *clip)
2512 {
2514  cairo_svg_surface_t *surface = abstract_surface;
2515 
2516  /* Emulation of clear and source operators, when no clipping region
2517  * is defined. We just delete existing content of surface root node,
2518  * and exit early if operator is clear.
2519  */
2521  clip == NULL)
2522  {
2523  switch (surface->paginated_mode) {
2527  return CAIRO_STATUS_SUCCESS;
2528 
2531  if (unlikely (status)) {
2532  surface->xml_node = NULL;
2533  return status;
2534  }
2535 
2536  surface->xml_node = _cairo_memory_stream_create ();
2537  if (_cairo_output_stream_get_status (surface->xml_node)) {
2539  surface->xml_node = NULL;
2540  return status;
2541  }
2542 
2543  if (op == CAIRO_OPERATOR_CLEAR) {
2546  "<rect "
2547  "width=\"%f\" height=\"%f\" "
2548  "style=\"opacity:1;"
2549  "stroke:none;"
2550  "fill:rgb(0,0,0);\"/>\n",
2551  surface->width, surface->height);
2552  }
2553  return CAIRO_STATUS_SUCCESS;
2554  }
2555  break;
2556  }
2557  } else {
2558  if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
2560 
2562  }
2563 
2565  if (unlikely (status))
2566  return status;
2567 
2568  return _cairo_svg_surface_emit_paint (surface->xml_node,
2569  surface, op, source, 0, NULL);
2570 }
2571 
2572 static cairo_int_status_t
2573 _cairo_svg_surface_mask (void *abstract_surface,
2575  const cairo_pattern_t *source,
2576  const cairo_pattern_t *mask,
2577  const cairo_clip_t *clip)
2578 {
2580  cairo_svg_surface_t *surface = abstract_surface;
2581  cairo_svg_document_t *document = surface->document;
2582  cairo_output_stream_t *mask_stream;
2583  char buffer[64];
2584  cairo_bool_t discard_filter = FALSE;
2585  unsigned int mask_id;
2586 
2587  if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
2588  cairo_status_t source_status, mask_status;
2589 
2591  if (_cairo_status_is_error (source_status))
2592  return source_status;
2593 
2594  if (mask->has_component_alpha) {
2595  mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
2596  } else {
2598  if (_cairo_status_is_error (mask_status))
2599  return mask_status;
2600  }
2601 
2602  return _cairo_analysis_surface_merge_status (source_status,
2603  mask_status);
2604  }
2605 
2608 
2610  if (unlikely (status))
2611  return status;
2612 
2613  if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
2614  const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t*) mask;
2615  cairo_content_t content = surface_pattern->surface->content;
2617  discard_filter = TRUE;
2618  }
2619 
2620  if (!discard_filter)
2622 
2623  /* _cairo_svg_surface_emit_paint() will output a pattern definition to
2624  * document->xml_node_defs so we need to write the mask element to
2625  * a temporary stream and then copy that to xml_node_defs. */
2626  mask_stream = _cairo_memory_stream_create ();
2627  if (_cairo_output_stream_get_status (mask_stream))
2628  return _cairo_output_stream_destroy (mask_stream);
2629 
2631 
2632  _cairo_output_stream_printf (mask_stream,
2633  "<mask id=\"mask%d\">\n"
2634  "%s",
2635  mask_id,
2636  discard_filter ? "" : " <g filter=\"url(#alpha)\">\n");
2638  if (unlikely (status)) {
2640  return status;
2641  (void) ignore;
2642  }
2643 
2644  _cairo_output_stream_printf (mask_stream,
2645  "%s"
2646  "</mask>\n",
2647  discard_filter ? "" : " </g>\n");
2648  _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
2649 
2650  status = _cairo_output_stream_destroy (mask_stream);
2651  if (unlikely (status))
2652  return status;
2653 
2654  snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d)\"",
2655  mask_id);
2657  if (unlikely (status))
2658  return status;
2659 
2660  return CAIRO_STATUS_SUCCESS;
2661 }
2662 
2663 static cairo_int_status_t
2664 _cairo_svg_surface_stroke (void *abstract_dst,
2666  const cairo_pattern_t *source,
2667  const cairo_path_fixed_t*path,
2668  const cairo_stroke_style_t *stroke_style,
2669  const cairo_matrix_t *ctm,
2670  const cairo_matrix_t *ctm_inverse,
2671  double tolerance,
2673  const cairo_clip_t *clip)
2674 {
2675  cairo_svg_surface_t *surface = abstract_dst;
2677 
2678  if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
2680 
2682 
2684  if (unlikely (status))
2685  return status;
2686 
2687  _cairo_output_stream_printf (surface->xml_node, "<path style=\"fill:none;");
2689  source, stroke_style, ctm_inverse);
2690  if (unlikely (status))
2691  return status;
2692 
2693  _cairo_output_stream_printf (surface->xml_node, "\" ");
2694 
2695  _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
2696 
2697  _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL);
2698  _cairo_output_stream_printf (surface->xml_node, "/>\n");
2699 
2700  return CAIRO_STATUS_SUCCESS;
2701 }
2702 
2703 static cairo_int_status_t
2704 _cairo_svg_surface_show_glyphs (void *abstract_surface,
2706  const cairo_pattern_t *pattern,
2708  int num_glyphs,
2709  cairo_scaled_font_t *scaled_font,
2710  const cairo_clip_t *clip)
2711 {
2712  cairo_svg_surface_t *surface = abstract_surface;
2713  cairo_svg_document_t *document = surface->document;
2717  int i;
2718 
2719  if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
2721 
2723 
2724  if (num_glyphs <= 0)
2725  return CAIRO_STATUS_SUCCESS;
2726 
2728  if (unlikely (status))
2729  return status;
2730 
2731  /* FIXME it's probably possible to apply a pattern of a gradient to
2732  * a group of symbols, but I don't know how yet. Gradients or patterns
2733  * are translated by x and y properties of use element. */
2735  goto FALLBACK;
2736 
2737  _cairo_output_stream_printf (surface->xml_node, "<g style=\"");
2739  surface->xml_node, FALSE, NULL);
2740  if (unlikely (status))
2741  return status;
2742 
2744 
2745  _cairo_output_stream_printf (surface->xml_node, "\">\n");
2746 
2747  for (i = 0; i < num_glyphs; i++) {
2749  scaled_font, glyphs[i].index,
2750  NULL, 0,
2751  &subset_glyph);
2753  _cairo_output_stream_printf (surface->xml_node, "</g>\n");
2754 
2755  glyphs += i;
2756  num_glyphs -= i;
2757  goto FALLBACK;
2758  }
2759 
2760  if (unlikely (status))
2761  return status;
2762 
2764  " <use xlink:href=\"#glyph%d-%d\" "
2765  "x=\"%f\" y=\"%f\"/>\n",
2766  subset_glyph.font_id,
2767  subset_glyph.subset_glyph_index,
2768  glyphs[i].x, glyphs[i].y);
2769  }
2770 
2771  _cairo_output_stream_printf (surface->xml_node, "</g>\n");
2772 
2773  return CAIRO_STATUS_SUCCESS;
2774 
2775 FALLBACK:
2777 
2778  status = _cairo_scaled_font_glyph_path (scaled_font,
2779  (cairo_glyph_t *) glyphs,
2780  num_glyphs, &path);
2781 
2782  if (unlikely (status)) {
2784  return status;
2785  }
2786 
2787  status = _cairo_svg_surface_fill (abstract_surface, op, pattern,
2790  clip);
2791 
2793 
2794  return status;
2795 }
2796 
2797 static void
2798 _cairo_svg_surface_get_font_options (void *abstract_surface,
2800 {
2802 
2807 }
2808 
2809 
2810 static const char **
2812 {
2814 }
2815 
2819 
2821 
2822  NULL, /* create_similar: handled by wrapper */
2823  NULL, /* create_similar_image */
2824  NULL, /* map to image */
2825  NULL, /* unmap image */
2826 
2828  NULL, /* acquire_source_image */
2829  NULL, /* release_source_image */
2830  NULL, /* snapshot */
2831 
2834 
2837 
2838  NULL, /* flush */
2839  NULL, /* mark dirty rectangle */
2840 
2847  NULL, /* has_show_text_glyphs */
2848  NULL, /* show_text_glyphs */
2850 };
2851 
2852 static cairo_status_t
2854  double width,
2855  double height,
2857  cairo_svg_document_t **document_out)
2858 {
2860  cairo_status_t status, status_ignored;
2861 
2862  if (output_stream->status)
2863  return output_stream->status;
2864 
2866  if (unlikely (document == NULL))
2868 
2869  /* The use of defs for font glyphs imposes no per-subset limit. */
2871  if (unlikely (document->font_subsets == NULL)) {
2873  goto CLEANUP_DOCUMENT;
2874  }
2875 
2876  document->output_stream = output_stream;
2877  document->refcount = 1;
2878  document->owner = NULL;
2879  document->finished = FALSE;
2880  document->width = width;
2881  document->height = height;
2882  document->unit = CAIRO_SVG_UNIT_PT;
2883 
2884  document->linear_pattern_id = 0;
2885  document->radial_pattern_id = 0;
2886  document->pattern_id = 0;
2887  document->filter_id = 0;
2888  document->clip_id = 0;
2889  document->mask_id = 0;
2890 
2891  document->xml_node_defs = _cairo_memory_stream_create ();
2892  status = _cairo_output_stream_get_status (document->xml_node_defs);
2893  if (unlikely (status))
2894  goto CLEANUP_NODE_DEFS;
2895 
2896  document->xml_node_glyphs = _cairo_memory_stream_create ();
2897  status = _cairo_output_stream_get_status (document->xml_node_glyphs);
2898  if (unlikely (status))
2899  goto CLEANUP_NODE_GLYPHS;
2900 
2901  document->alpha_filter = FALSE;
2902 
2903  document->svg_version = version;
2904 
2905  *document_out = document;
2906  return CAIRO_STATUS_SUCCESS;
2907 
2908  CLEANUP_NODE_GLYPHS:
2909  status_ignored = _cairo_output_stream_destroy (document->xml_node_glyphs);
2910  CLEANUP_NODE_DEFS:
2911  status_ignored = _cairo_output_stream_destroy (document->xml_node_defs);
2913  CLEANUP_DOCUMENT:
2914  free (document);
2915  return status;
2916 }
2917 
2918 static cairo_svg_document_t *
2920 {
2921  document->refcount++;
2922 
2923  return document;
2924 }
2925 
2926 static unsigned int
2928 {
2929  return document->mask_id++;
2930 }
2931 
2932 static cairo_status_t
2934 {
2936 
2937  document->refcount--;
2938  if (document->refcount > 0)
2939  return CAIRO_STATUS_SUCCESS;
2940 
2942 
2943  free (document);
2944 
2945  return status;
2946 }
2947 
2948 static cairo_status_t
2950 {
2951  cairo_status_t status, status2;
2952  cairo_output_stream_t *output = document->output_stream;
2954  unsigned int i;
2955 
2956  if (document->finished)
2957  return CAIRO_STATUS_SUCCESS;
2958 
2959  /*
2960  * Should we add DOCTYPE?
2961  *
2962  * Google says no.
2963  *
2964  * http://tech.groups.yahoo.com/group/svg-developers/message/48562:
2965  * There's a bunch of issues, but just to pick a few:
2966  * - they'll give false positives.
2967  * - they'll give false negatives.
2968  * - they're namespace-unaware.
2969  * - they don't wildcard.
2970  * So when they say OK they really haven't checked anything, when
2971  * they say NOT OK they might be on crack, and like all
2972  * namespace-unaware things they're a dead branch of the XML tree.
2973  *
2974  * http://jwatt.org/svg/authoring/:
2975  * Unfortunately the SVG DTDs are a source of so many issues that the
2976  * SVG WG has decided not to write one for the upcoming SVG 1.2
2977  * standard. In fact SVG WG members are even telling people not to use
2978  * a DOCTYPE declaration in SVG 1.0 and 1.1 documents.
2979  */
2980 
2982  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2983  "<svg xmlns=\"http://www.w3.org/2000/svg\" "
2984  "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
2985  "width=\"%f%s\" height=\"%f%s\" "
2986  "viewBox=\"0 0 %f %f\" version=\"%s\">\n",
2987  document->width, _cairo_svg_unit_strings [document->unit],
2988  document->height, _cairo_svg_unit_strings [document->unit],
2989  document->width, document->height,
2991 
2993 
2994  if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
2995  _cairo_memory_stream_length (document->xml_node_defs) > 0) {
2996  _cairo_output_stream_printf (output, "<defs>\n");
2997  if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
2999  _cairo_memory_stream_copy (document->xml_node_glyphs, output);
3000  _cairo_output_stream_printf (output, "</g>\n");
3001  }
3002  _cairo_memory_stream_copy (document->xml_node_defs, output);
3003  _cairo_output_stream_printf (output, "</defs>\n");
3004  }
3005 
3006  if (document->owner != NULL) {
3008 
3010  if (surface->xml_node != NULL &&
3011  _cairo_memory_stream_length (surface->xml_node) > 0) {
3015  }
3016  }
3017 
3018  if (surface->page_set.num_elements > 1 &&
3020  _cairo_output_stream_printf (output, "<pageSet>\n");
3021  for (i = 0; i < surface->page_set.num_elements; i++) {
3022  page = _cairo_array_index (&surface->page_set, i);
3023  _cairo_output_stream_printf (output, "<page>\n");
3025  "<g id=\"surface%d\">\n",
3026  page->surface_id);
3027  _cairo_memory_stream_copy (page->xml_node, output);
3028  _cairo_output_stream_printf (output, "</g>\n</page>\n");
3029  }
3030  _cairo_output_stream_printf (output, "</pageSet>\n");
3031  } else if (surface->page_set.num_elements > 0) {
3032  page = _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
3034  "<g id=\"surface%d\">\n",
3035  page->surface_id);
3036  _cairo_memory_stream_copy (page->xml_node, output);
3037  _cairo_output_stream_printf (output, "</g>\n");
3038  }
3039  }
3040 
3041  _cairo_output_stream_printf (output, "</svg>\n");
3042 
3043  status2 = _cairo_output_stream_destroy (document->xml_node_glyphs);
3045  status = status2;
3046 
3047  status2 = _cairo_output_stream_destroy (document->xml_node_defs);
3049  status = status2;
3050 
3053  status = status2;
3054 
3055  document->finished = TRUE;
3056 
3057  return status;
3058 }
3059 
3060 static cairo_int_status_t
3062  cairo_paginated_mode_t paginated_mode)
3063 {
3064  cairo_svg_surface_t *surface = abstract_surface;
3065 
3066  surface->paginated_mode = paginated_mode;
3067 
3068  return CAIRO_STATUS_SUCCESS;
3069 }
3070 
3071 static cairo_bool_t
3073 {
3074  cairo_svg_surface_t *surface = abstract_surface;
3076 
3077  if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2) {
3080  }
3081 
3082  return status == CAIRO_INT_STATUS_SUCCESS;
3083 }
3084 
3086  NULL /*_cairo_svg_surface_start_page*/,
3088  NULL, /* _cairo_svg_surface_set_bounding_box */
3089  NULL, /* _cairo_svg_surface_set_fallback_images_required */
3091 
3092 };
double __cdecl fmod(double _X, double _Y)
q
Definition: afm2pl.c:2287
#define y0
#define width(a)
Definition: aptex-macros.h:198
#define tolerance
Definition: aptex-macros.h:786
#define box(a)
Definition: aptex-macros.h:675
#define x0
#define height(a)
Definition: aptex-macros.h:200
static int font_id[65536]
Definition: aptex-src.c:20628
cairo_int_status_t _cairo_analysis_surface_merge_status(cairo_int_status_t status_a, cairo_int_status_t status_b)
void _cairo_array_fini(cairo_array_t *array)
Definition: cairo-array.c:75
void * _cairo_array_index(cairo_array_t *array, unsigned int index)
Definition: cairo-array.c:166
void _cairo_array_init(cairo_array_t *array, unsigned int element_size)
Definition: cairo-array.c:58
cairo_status_t _cairo_array_append(cairo_array_t *array, const void *element)
Definition: cairo-array.c:262
#define CAIRO_INT_STATUS_SUCCESS
unsigned long _cairo_hash_bytes(unsigned long hash, const void *ptr, unsigned int length)
Definition: cairo-cache.c:329
cairo_t * _cairo_default_context_create(void *target)
cairo_status_t _cairo_error(cairo_status_t status)
Definition: cairo-error.c:65
enum _cairo_int_status cairo_int_status_t
#define _cairo_error_throw(status)
@ CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
@ CAIRO_INT_STATUS_UNSUPPORTED
#define _cairo_status_is_error(status)
static double _cairo_fixed_to_double(cairo_fixed_t f)
void cairo_font_options_set_hint_style(cairo_font_options_t *options, cairo_hint_style_t hint_style)
void cairo_font_options_set_antialias(cairo_font_options_t *options, cairo_antialias_t antialias)
void _cairo_font_options_set_round_glyph_positions(cairo_font_options_t *options, cairo_round_glyph_positions_t round)
void _cairo_font_options_init_default(cairo_font_options_t *options)
void cairo_font_options_set_hint_metrics(cairo_font_options_t *options, cairo_hint_metrics_t hint_metrics)
cairo_status_t _cairo_hash_table_insert(cairo_hash_table_t *hash_table, cairo_hash_entry_t *entry)
Definition: cairo-hash.c:455
void _cairo_hash_table_remove(cairo_hash_table_t *hash_table, cairo_hash_entry_t *key)
Definition: cairo-hash.c:520
void _cairo_hash_table_destroy(cairo_hash_table_t *hash_table)
Definition: cairo-hash.c:214
cairo_hash_table_t * _cairo_hash_table_create(cairo_hash_keys_equal_func_t keys_equal)
Definition: cairo-hash.c:163
void * _cairo_hash_table_lookup(cairo_hash_table_t *hash_table, cairo_hash_entry_t *key)
Definition: cairo-hash.c:338
void _cairo_hash_table_foreach(cairo_hash_table_t *hash_table, cairo_hash_callback_func_t hash_callback, void *closure)
Definition: cairo-hash.c:555
cairo_int_status_t _cairo_image_info_get_jpeg_info(cairo_image_info_t *info, const unsigned char *data, long length)
cairo_image_surface_t * _cairo_image_surface_coerce_to_format(cairo_image_surface_t *surface, cairo_format_t format)
#define _cairo_malloc_ab(a, size)
#define _cairo_malloc(size)
cairo_status_t cairo_matrix_invert(cairo_matrix_t *matrix)
Definition: cairo-matrix.c:586
void cairo_matrix_transform_point(const cairo_matrix_t *matrix, double *x, double *y)
Definition: cairo-matrix.c:410
void cairo_matrix_multiply(cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
Definition: cairo-matrix.c:331
cairo_bool_t _cairo_operator_bounded_by_source(cairo_operator_t op)
Definition: cairo-misc.c:425
cairo_output_stream_t * _cairo_output_stream_create_for_filename(const char *filename)
void _cairo_output_stream_write(cairo_output_stream_t *stream, const void *data, size_t length)
cairo_status_t _cairo_output_stream_destroy(cairo_output_stream_t *stream)
cairo_output_stream_t * _cairo_output_stream_create(cairo_write_func_t write_func, cairo_close_func_t close_func, void *closure)
cairo_status_t _cairo_output_stream_get_status(cairo_output_stream_t *stream)
cairo_output_stream_t * _cairo_memory_stream_create(void)
void _cairo_output_stream_printf(cairo_output_stream_t *stream, const char *fmt,...)
void _cairo_memory_stream_copy(cairo_output_stream_t *base, cairo_output_stream_t *dest)
int _cairo_memory_stream_length(cairo_output_stream_t *stream)
cairo_bool_t _cairo_surface_is_paginated(cairo_surface_t *surface)
cairo_surface_t * _cairo_paginated_surface_get_recording(cairo_surface_t *surface)
cairo_surface_t * _cairo_paginated_surface_create(cairo_surface_t *target, cairo_content_t content, const cairo_paginated_surface_backend_t *backend)
cairo_surface_t * _cairo_paginated_surface_get_target(cairo_surface_t *surface)
void _cairo_path_fixed_fini(cairo_path_fixed_t *path)
void _cairo_path_fixed_init(cairo_path_fixed_t *path)
cairo_status_t _cairo_path_fixed_interpret(const cairo_path_fixed_t *path, cairo_path_fixed_move_to_func_t *move_to, cairo_path_fixed_line_to_func_t *line_to, cairo_path_fixed_curve_to_func_t *curve_to, cairo_path_fixed_close_path_func_t *close_path, void *closure)
cairo_bool_t _cairo_path_fixed_is_box(const cairo_path_fixed_t *path, cairo_box_t *box)
cairo_status_t cairo_surface_write_to_png_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure)
Definition: cairo-png.c:432
cairo_status_t _cairo_recording_surface_replay(cairo_surface_t *surface, cairo_surface_t *target)
cairo_scaled_font_subsets_t * _cairo_scaled_font_subsets_create_scaled(void)
void _cairo_scaled_font_subsets_destroy(cairo_scaled_font_subsets_t *font_subsets)
cairo_status_t _cairo_scaled_font_subsets_map_glyph(cairo_scaled_font_subsets_t *font_subsets, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, const char *utf8, int utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph_ret)
cairo_status_t _cairo_scaled_font_subsets_foreach_user(cairo_scaled_font_subsets_t *font_subsets, cairo_scaled_font_subset_callback_func_t font_subset_callback, void *closure)
cairo_status_t _cairo_scaled_font_subsets_foreach_scaled(cairo_scaled_font_subsets_t *font_subsets, cairo_scaled_font_subset_callback_func_t font_subset_callback, void *closure)
cairo_status_t _cairo_scaled_font_glyph_path(cairo_scaled_font_t *scaled_font, const cairo_glyph_t *glyphs, int num_glyphs, cairo_path_fixed_t *path)
void _cairo_scaled_font_thaw_cache(cairo_scaled_font_t *scaled_font)
void _cairo_scaled_font_freeze_cache(cairo_scaled_font_t *scaled_font)
cairo_int_status_t _cairo_scaled_glyph_lookup(cairo_scaled_font_t *scaled_font, unsigned long index, cairo_scaled_glyph_info_t info, cairo_scaled_glyph_t **scaled_glyph_ret)
cairo_surface_t * _cairo_surface_default_source(void *surface, cairo_rectangle_int_t *extents)
void _cairo_surface_clipper_reset(cairo_surface_clipper_t *clipper)
void _cairo_surface_clipper_init(cairo_surface_clipper_t *clipper, cairo_surface_clipper_intersect_clip_path_func_t intersect)
cairo_status_t _cairo_surface_clipper_set_clip(cairo_surface_clipper_t *clipper, const cairo_clip_t *clip)
cairo_surface_t * _cairo_surface_create_in_error(cairo_status_t status)
static cairo_surface_t * _cairo_surface_snapshot_get_target(cairo_surface_t *surface)
static cairo_bool_t _cairo_surface_is_snapshot(cairo_surface_t *surface)
void _cairo_surface_init(cairo_surface_t *surface, const cairo_surface_backend_t *backend, cairo_device_t *device, cairo_content_t content, cairo_bool_t is_vector)
void cairo_surface_destroy(cairo_surface_t *surface)
void cairo_surface_set_device_offset(cairo_surface_t *surface, double x_offset, double y_offset)
cairo_int_status_t _cairo_surface_set_error(cairo_surface_t *surface, cairo_int_status_t status)
void cairo_surface_set_fallback_resolution(cairo_surface_t *surface, double x_pixels_per_inch, double y_pixels_per_inch)
cairo_status_t cairo_surface_status(cairo_surface_t *surface)
void cairo_surface_get_mime_data(cairo_surface_t *surface, const char *mime_type, const unsigned char **data, unsigned long *length)
cairo_bool_t _cairo_surface_get_extents(cairo_surface_t *surface, cairo_rectangle_int_t *extents)
void cairo_surface_show_page(cairo_surface_t *surface)
void cairo_svg_surface_restrict_to_version(cairo_surface_t *abstract_surface, cairo_svg_version_t version)
cairo_svg_unit_t cairo_svg_surface_get_document_unit(cairo_surface_t *abstract_surface)
cairo_surface_t * cairo_svg_surface_create_for_stream(cairo_write_func_t write_func, void *closure, double width, double height)
cairo_surface_t * cairo_svg_surface_create(const char *filename, double width, double height)
void cairo_svg_get_versions(cairo_svg_version_t const **versions, int *num_versions)
const char * cairo_svg_version_to_string(cairo_svg_version_t version)
void cairo_svg_surface_set_document_unit(cairo_surface_t *abstract_surface, cairo_svg_unit_t unit)
@ CAIRO_SVG_UNIT_PT
Definition: cairo-svg.h:91
@ CAIRO_SVG_UNIT_PERCENT
Definition: cairo-svg.h:93
@ CAIRO_SVG_UNIT_USER
Definition: cairo-svg.h:84
enum _cairo_svg_unit cairo_svg_unit_t
@ CAIRO_SVG_VERSION_1_1
Definition: cairo-svg.h:52
@ CAIRO_SVG_VERSION_1_2
Definition: cairo-svg.h:53
enum _cairo_svg_version cairo_svg_version_t
@ CAIRO_PAGINATED_MODE_ANALYZE
@ CAIRO_PAGINATED_MODE_RENDER
@ CAIRO_PAGINATED_MODE_FALLBACK
enum _cairo_paginated_mode cairo_paginated_mode_t
@ CAIRO_ROUND_GLYPH_POS_OFF
enum _cairo_operator cairo_operator_t
@ CAIRO_SURFACE_TYPE_SVG
Definition: cairo.h:2408
@ CAIRO_SURFACE_TYPE_RECORDING
Definition: cairo.h:2414
@ CAIRO_LINE_JOIN_ROUND
Definition: cairo.h:802
@ CAIRO_LINE_JOIN_BEVEL
Definition: cairo.h:803
@ CAIRO_LINE_JOIN_MITER
Definition: cairo.h:801
#define CAIRO_MIME_TYPE_UNIQUE_ID
Definition: cairo.h:2458
enum _cairo_fill_rule cairo_fill_rule_t
enum _cairo_antialias cairo_antialias_t
int cairo_bool_t
Definition: cairo.h:107
@ CAIRO_EXTEND_REFLECT
Definition: cairo.h:2919
@ CAIRO_EXTEND_PAD
Definition: cairo.h:2920
@ CAIRO_EXTEND_NONE
Definition: cairo.h:2917
@ CAIRO_EXTEND_REPEAT
Definition: cairo.h:2918
@ CAIRO_STATUS_SUCCESS
Definition: cairo.h:315
@ CAIRO_STATUS_SURFACE_TYPE_MISMATCH
Definition: cairo.h:329
@ CAIRO_STATUS_SURFACE_FINISHED
Definition: cairo.h:328
@ CAIRO_STATUS_NO_MEMORY
Definition: cairo.h:317
@ CAIRO_STATUS_PATTERN_TYPE_MISMATCH
Definition: cairo.h:330
#define CAIRO_MIME_TYPE_URI
Definition: cairo.h:2457
#define CAIRO_MIME_TYPE_PNG
Definition: cairo.h:2455
@ CAIRO_CONTENT_ALPHA
Definition: cairo.h:381
@ CAIRO_CONTENT_COLOR_ALPHA
Definition: cairo.h:382
@ CAIRO_CONTENT_COLOR
Definition: cairo.h:380
enum _cairo_content cairo_content_t
@ CAIRO_HINT_METRICS_OFF
Definition: cairo.h:1359
#define CAIRO_MIME_TYPE_JPEG
Definition: cairo.h:2454
@ CAIRO_ANTIALIAS_SUBPIXEL
Definition: cairo.h:715
@ CAIRO_ANTIALIAS_GRAY
Definition: cairo.h:714
@ CAIRO_LINE_CAP_ROUND
Definition: cairo.h:778
@ CAIRO_LINE_CAP_BUTT
Definition: cairo.h:777
@ CAIRO_LINE_CAP_SQUARE
Definition: cairo.h:779
@ CAIRO_OPERATOR_CLEAR
Definition: cairo.h:614
@ CAIRO_OPERATOR_SOURCE
Definition: cairo.h:616
@ CAIRO_OPERATOR_OVER
Definition: cairo.h:617
enum _cairo_status cairo_status_t
enum _cairo_extend cairo_extend_t
@ CAIRO_FORMAT_A1
Definition: cairo.h:421
cairo_status_t(* cairo_write_func_t)(void *closure, const unsigned char *data, unsigned int length)
Definition: cairo.h:445
@ CAIRO_HINT_STYLE_NONE
Definition: cairo.h:1336
@ CAIRO_FILL_RULE_EVEN_ODD
Definition: cairo.h:755
@ CAIRO_FILL_RULE_WINDING
Definition: cairo.h:754
@ CAIRO_PATTERN_TYPE_LINEAR
Definition: cairo.h:2827
@ CAIRO_PATTERN_TYPE_SURFACE
Definition: cairo.h:2826
@ CAIRO_PATTERN_TYPE_SOLID
Definition: cairo.h:2825
@ CAIRO_PATTERN_TYPE_RASTER_SOURCE
Definition: cairo.h:2830
@ CAIRO_PATTERN_TYPE_RADIAL
Definition: cairo.h:2828
@ CAIRO_PATTERN_TYPE_MESH
Definition: cairo.h:2829
static cairo_bool_t _cairo_matrix_is_identity(const cairo_matrix_t *matrix)
Definition: cairoint.h:1786
#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c)
Definition: cairoint.h:211
#define ASSERT_NOT_REACHED
Definition: cairoint.h:155
#define cairo_container_of(ptr, type, member)
Definition: cairoint.h:150
@ CAIRO_SCALED_GLYPH_INFO_PATH
Definition: cairoint.h:485
@ CAIRO_SCALED_GLYPH_INFO_SURFACE
Definition: cairoint.h:484
@ CAIRO_SCALED_GLYPH_INFO_METRICS
Definition: cairoint.h:483
#define _CAIRO_HASH_INIT_VALUE
Definition: cairoint.h:421
#define ARRAY_LENGTH(__array)
Definition: cairoint.h:137
static const int invalid_pattern_id
static void _cairo_svg_surface_emit_pattern_extend(cairo_output_stream_t *output, cairo_pattern_t *pattern)
static const char ** _cairo_svg_surface_get_supported_mime_types(void *abstract_surface)
static cairo_status_t _cairo_svg_surface_emit_stroke_style(cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *parent_matrix)
static cairo_svg_document_t * _cairo_svg_document_reference(cairo_svg_document_t *document)
static cairo_int_status_t _cairo_svg_document_emit_font_subset(cairo_scaled_font_subset_t *font_subset, void *closure)
static cairo_int_status_t _cairo_svg_surface_copy_page(void *abstract_surface)
static const char * _cairo_svg_supported_mime_types[]
static cairo_int_status_t _cairo_svg_surface_show_glyphs(void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *pattern, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip)
static void _cairo_svg_surface_emit_attr_value(cairo_output_stream_t *stream, const unsigned char *value, unsigned int length)
static cairo_int_status_t _cairo_svg_surface_fill_stroke(void *abstract_surface, cairo_operator_t fill_op, const cairo_pattern_t *fill_source, cairo_fill_rule_t fill_rule, double fill_tolerance, cairo_antialias_t fill_antialias, const cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *stroke_ctm, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, const cairo_clip_t *clip)
static cairo_status_t _cairo_svg_surface_emit_surface_pattern(cairo_svg_surface_t *surface, cairo_surface_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke, const cairo_matrix_t *parent_matrix)
static cairo_recording_surface_t * to_recording_surface(const cairo_surface_pattern_t *pattern)
static void _cairo_svg_source_surface_init_key(cairo_svg_source_surface_t *key)
static cairo_bool_t _cairo_svg_version_has_page_set_support(cairo_svg_version_t version)
static cairo_status_t _cairo_svg_surface_emit_composite_surface_pattern(cairo_output_stream_t *output, cairo_svg_surface_t *svg_surface, cairo_operator_t op, cairo_surface_pattern_t *pattern, int pattern_id, const cairo_matrix_t *parent_matrix, const char *extra_attributes)
static cairo_status_t _cairo_svg_surface_clipper_intersect_clip_path(cairo_surface_clipper_t *clipper, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias)
static cairo_int_status_t _cairo_svg_document_emit_bitmap_glyph_data(cairo_svg_document_t *document, cairo_scaled_font_t *scaled_font, unsigned long glyph_index)
static void _cairo_svg_source_surface_pluck(void *entry, void *closure)
static char const * _cairo_svg_surface_operators[]
static cairo_status_t _cairo_svg_document_emit_font_subsets(cairo_svg_document_t *document)
static cairo_status_t _cairo_svg_surface_finish(void *abstract_surface)
static cairo_int_status_t _cairo_svg_surface_analyze_operation(cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern)
static cairo_status_t _cairo_svg_surface_emit_composite_recording_pattern(cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, cairo_surface_pattern_t *pattern, int pattern_id, const cairo_matrix_t *parent_matrix, const char *extra_attributes)
static cairo_status_t _cairo_svg_surface_add_source_surface(cairo_svg_surface_t *surface, cairo_surface_t *source_surface, int *source_id, cairo_bool_t *is_new)
static cairo_status_t _cairo_svg_surface_emit_surface(cairo_svg_document_t *document, cairo_surface_t *surface, int source_id)
static cairo_bool_t _cairo_svg_source_surface_equal(const void *key_a, const void *key_b)
static void _cairo_svg_surface_emit_operator_for_style(cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op)
static const cairo_svg_version_t _cairo_svg_versions[]
static cairo_status_t _cairo_svg_surface_emit_paint(cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask_source, const char *extra_attributes)
static cairo_bool_t _cairo_svg_surface_analyze_operator(cairo_svg_surface_t *surface, cairo_operator_t op)
static const char * _cairo_svg_internal_version_strings[((int)(sizeof(_cairo_svg_versions)/sizeof(_cairo_svg_versions[0])))]
static cairo_status_t _cairo_svg_surface_emit_pattern(cairo_svg_surface_t *surface, const cairo_pattern_t *pattern, cairo_output_stream_t *output, cairo_bool_t is_stroke, const cairo_matrix_t *parent_matrix)
static void _cairo_svg_surface_emit_transform(cairo_output_stream_t *output, char const *attribute_str, const cairo_matrix_t *object_matrix, const cairo_matrix_t *parent_matrix)
static cairo_bool_t _cairo_surface_is_svg(cairo_surface_t *surface)
#define CAIRO_SVG_VERSION_LAST
static void _cairo_svg_surface_emit_operator(cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op)
static cairo_int_status_t _cairo_surface_base64_encode(cairo_surface_t *surface, cairo_output_stream_t *output)
static unsigned int _cairo_svg_document_allocate_mask_id(cairo_svg_document_t *document)
static const char * _cairo_svg_unit_strings[]
static cairo_status_t _cairo_svg_path_move_to(void *closure, const cairo_point_t *point)
static cairo_int_status_t _cairo_svg_surface_paint(void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_clip_t *clip)
static cairo_status_t _cairo_svg_document_create(cairo_output_stream_t *stream, double width, double height, cairo_svg_version_t version, cairo_svg_document_t **document_out)
static cairo_status_t _cairo_svg_surface_emit_linear_pattern(cairo_svg_surface_t *surface, cairo_linear_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke, const cairo_matrix_t *parent_matrix)
static cairo_int_status_t _cairo_svg_surface_mask(void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, const cairo_clip_t *clip)
static cairo_int_status_t _cairo_svg_document_emit_outline_glyph_data(cairo_svg_document_t *document, cairo_scaled_font_t *scaled_font, unsigned long glyph_index)
static cairo_surface_t * _cairo_svg_surface_create_for_stream_internal(cairo_output_stream_t *stream, double width, double height, cairo_svg_version_t version)
static cairo_status_t _cairo_svg_surface_emit_radial_pattern(cairo_svg_surface_t *surface, cairo_radial_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke, const cairo_matrix_t *parent_matrix)
static cairo_status_t _cairo_svg_document_destroy(cairo_svg_document_t *document)
static cairo_svg_page_t * _cairo_svg_surface_store_page(cairo_svg_surface_t *surface)
static cairo_status_t _cairo_svg_path_curve_to(void *closure, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d)
static void _cairo_svg_surface_emit_alpha_filter(cairo_svg_document_t *document)
static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend
static cairo_bool_t _extract_svg_surface(cairo_surface_t *surface, cairo_svg_surface_t **svg_surface)
static cairo_int_status_t _cairo_svg_surface_show_page(void *abstract_surface)
static cairo_status_t _cairo_svg_document_finish(cairo_svg_document_t *document)
static cairo_bool_t _cairo_svg_surface_get_extents(void *abstract_surface, cairo_rectangle_int_t *rectangle)
static cairo_int_status_t _cairo_svg_surface_fill(void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip)
static cairo_int_status_t _cairo_svg_document_emit_glyph(cairo_svg_document_t *document, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, unsigned int font_id, unsigned int subset_glyph_index)
static cairo_int_status_t _cairo_svg_surface_set_paginated_mode(void *abstract_surface, cairo_paginated_mode_t paginated_mode)
static cairo_status_t _cairo_svg_surface_emit_solid_pattern(cairo_svg_surface_t *surface, cairo_solid_pattern_t *pattern, cairo_output_stream_t *style, cairo_bool_t is_stroke)
static cairo_status_t _cairo_svg_surface_emit_composite_pattern(cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, cairo_surface_pattern_t *pattern, int pattern_id, const cairo_matrix_t *parent_matrix, const char *extra_attributes)
static void _cairo_svg_surface_emit_path(cairo_output_stream_t *output, const cairo_path_fixed_t *path, const cairo_matrix_t *ctm_inverse)
static const cairo_surface_backend_t cairo_svg_surface_backend
static cairo_status_t _cairo_svg_surface_emit_pattern_stops(cairo_output_stream_t *output, cairo_gradient_pattern_t const *pattern, double start_offset, cairo_bool_t reverse_stops, cairo_bool_t emulate_reflect)
static cairo_status_t _cairo_svg_surface_emit_recording_surface(cairo_svg_document_t *document, cairo_recording_surface_t *source, int source_id)
static cairo_int_status_t _cairo_svg_surface_stroke(void *abstract_dst, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip)
static const char * _cairo_svg_version_strings[((int)(sizeof(_cairo_svg_versions)/sizeof(_cairo_svg_versions[0])))]
static char const base64_table[64]
static cairo_int_status_t _cairo_svg_surface_operation_supported(cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern)
static cairo_status_t _cairo_svg_surface_emit_fill_style(cairo_output_stream_t *output, cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_fill_rule_t fill_rule, const cairo_matrix_t *parent_matrix)
static cairo_bool_t _cliprect_covers_surface(cairo_svg_surface_t *surface, cairo_path_fixed_t *path)
static cairo_status_t _cairo_svg_path_line_to(void *closure, const cairo_point_t *point)
static cairo_int_status_t _cairo_surface_base64_encode_png(cairo_surface_t *surface, cairo_output_stream_t *output)
static cairo_int_status_t _cairo_surface_base64_encode_jpeg(cairo_surface_t *surface, cairo_output_stream_t *output)
static void _cairo_svg_surface_get_font_options(void *abstract_surface, cairo_font_options_t *options)
static cairo_status_t _cairo_svg_path_close_path(void *closure)
static cairo_status_t base64_write_func(void *closure, const unsigned char *data, unsigned int length)
static cairo_bool_t _cairo_svg_surface_supports_fine_grained_fallbacks(void *abstract_surface)
static cairo_surface_t * _cairo_svg_surface_create_for_document(cairo_svg_document_t *document, cairo_content_t content, double width, double height, cairo_bool_t bounded)
#define b
Definition: jpegint.h:372
@ FALSE
Definition: dd.h:101
@ TRUE
Definition: dd.h:102
#define free(a)
Definition: decNumber.cpp:310
void glyphs(int opcode)
Definition: disdvi.c:775
#define info
Definition: dviinfo.c:42
struct rect data
Definition: dvipdfm.c:64
static void
Definition: fpif.c:118
#define r1
#define r0
__gmp_expr< mpf_t, __gmp_unary_expr< __gmp_expr< mpf_t, U >, __gmp_ceil_function > > ceil(const __gmp_expr< mpf_t, U > &expr)
Definition: gmpxx.h:3340
#define c(n)
Definition: gpos-common.c:150
#define a(n)
Definition: gpos-common.c:148
#define d(n)
Definition: gpos-common.c:151
#define memcmp(s1, s2, n)
Definition: gsftopk.c:66
#define memcpy(d, s, n)
Definition: gsftopk.c:64
#define byte
Definition: in_pcx.cpp:28
assert(pcxLoadImage24((char *)((void *) 0), fp, pinfo, hdr))
unsigned char * image
Definition: in_pcx.cpp:323
#define unlikely(x)
Definition: jbig2arith.cc:116
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p
Definition: afcover.h:72
small capitals from c petite p scientific i
Definition: afcover.h:80
sizeof(AF_ModuleRec)
Arabic default style
Definition: afstyles.h:94
kerning y
Definition: ttdriver.c:212
int int cy
Definition: gdfx.h:13
int cx
Definition: gdfx.h:12
unsigned char uint8_t
Definition: stdint.h:78
pdf_obj * entry
Definition: pdfdoc.c:64
char * closure
Definition: font.h:85
#define output
Definition: cpascal.h:54
#define length(c)
Definition: ctangleboot.c:65
#define ignore
Definition: ctangleboot.c:133
#define malloc
Definition: alloca.c:91
#define snprintf
Definition: snprintf.c:41
#define target(code, i)
Definition: lpeg.c:1165
int unit
Definition: tfmread.c:8
float x
Definition: cordic.py:15
#define version
Definition: nup.c:10
union value value
Definition: obx.h:44
static double extend
Definition: otftotfm.cc:277
unsigned char bit
Definition: pbm.h:9
static int rows
Definition: pbmclean.c:15
static int cols
Definition: pbmmask.c:21
sixteenbits patterns[]
Definition: pbmpscale.c:36
char * filename[256]
Definition: pbmtopk.c:46
static cairo_surface_t * surface
Definition: pdftocairo.cc:234
static GooString antialias
Definition: pdftocairo.cc:119
float ** matrix()
int r
Definition: ppmqvga.c:68
static int offset
Definition: ppmtogif.c:642
bstring c int memset(void *s, int c, int length)
static int row
Definition: ps2pk.c:587
#define x1
#define y1
struct stream_s stream
Definition: pts_fax.h:93
#define status
#define glyph_index()
#define mask(n)
Definition: lbitlib.c:93
unsigned int num_elements
cairo_point_double_t center
cairo_color_stop_t color
cairo_matrix_t matrix
unsigned long * glyphs
Definition: cairoint.h:498
unsigned int font_id
Definition: cairoint.h:492
unsigned int num_glyphs
Definition: cairoint.h:503
cairo_scaled_font_t * scaled_font
Definition: cairoint.h:491
cairo_image_surface_t * surface
cairo_line_cap_t line_cap
cairo_line_join_t line_join
cairo_status_t status
cairo_content_t content
unsigned int unique_id
const cairo_surface_backend_t * backend
Definition: jquant2.c:258
Definition: utils.c:300
cairo_surface_t * owner
cairo_svg_version_t svg_version
cairo_output_stream_t * output_stream
unsigned int linear_pattern_id
cairo_bool_t alpha_filter
unsigned int radial_pattern_id
cairo_svg_unit_t unit
unsigned long refcount
cairo_output_stream_t * xml_node_glyphs
cairo_output_stream_t * xml_node_defs
cairo_scaled_font_subsets_t * font_subsets
cairo_output_stream_t * xml_node
unsigned int surface_id
unsigned int clip_level
cairo_svg_document_t * document
cairo_output_stream_t * xml_node
Definition: pdfdev.c:706
Definition: ps.h:63
Definition: drvpic.cpp:36
Definition: sd.h:76
Definition: sh.h:1226
Definition: output.h:18
Definition: mendex.h:14
Definition: tpic.c:45
unsigned int type[8]
Definition: mpost.c:238
double y
Definition: mpost.c:239
double x
Definition: mpost.c:239
Definition: sh.h:1345
int type
Definition: sh.h:1347
Definition: fio.h:71
pointer path
Definition: t1imager.h:36
#define c1
Definition: t1io.c:52
#define key
Definition: tex2xindy.c:753
found
Definition: tex4ht.c:5000
page
Definition: tex4ht.c:3916
static void output_byte(byte b)
Definition: type1asm.c:163
Definition: obx.h:51
#define FAIL(ec)