[cairo-commit] cairo/src cairo-output-stream.c, 1.2, 1.3 cairo-pdf-surface.c, 1.33, 1.34 cairoint.h, 1.140, 1.141

Kristian Hogsberg commit at pdx.freedesktop.org
Fri May 13 14:04:25 PDT 2005


Committed by: krh

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv31059/src

Modified Files:
	cairo-output-stream.c cairo-pdf-surface.c cairoint.h 
Log Message:
2005-05-13  Kristian Høgsberg  <krh at redhat.com>

        * src/cairo-pdf-surface.c (_cairo_pdf_document_open_stream): Make
        this a varg function and use the new
        _cairo_output_stream_vprintf() function to format extra dict
        contents.

        * src/cairo-output-stream.c (_cairo_output_stream_vprintf):
        Reimplement the printf logic so we can special case formatting of
        doubles to be locale independent and trim trailing zeros.



Index: cairo-output-stream.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-output-stream.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- cairo-output-stream.c	6 Apr 2005 20:01:13 -0000	1.2
+++ cairo-output-stream.c	13 May 2005 21:04:22 -0000	1.3
@@ -34,8 +34,9 @@
  *	Kristian Høgsberg <krh at redhat.com>
  */
 
-#include <stdarg.h>
 #include <stdio.h>
+#include <locale.h>
+#include <ctype.h>
 #include "cairoint.h"
 
 struct _cairo_output_stream {
@@ -77,33 +78,162 @@
 _cairo_output_stream_write (cairo_output_stream_t *stream,
 			    const void *data, size_t length)
 {
+    if (length == 0)
+	return CAIRO_STATUS_SUCCESS;
+
     stream->status = stream->write_data (stream->closure, data, length);
     stream->position += length;
 
     return stream->status;
 }
 
+/* Format a double in a locale independent way and trim trailing
+ * zeros.  Based on code from Alex Larson <alexl at redhat.com>.
+ * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
+ */
+
+static int
+dtostr (char *buffer, size_t size, double d)
+{
+  struct lconv *locale_data;
+  const char *decimal_point;
+  int decimal_point_len;
+  char *p;
+  int decimal_len;
+
+  snprintf (buffer, size, "%f", d);
+    
+  locale_data = localeconv ();
+  decimal_point = locale_data->decimal_point;
+  decimal_point_len = strlen (decimal_point);
+  
+  assert (decimal_point_len != 0);
+  p = buffer;
+			    
+  if (*p == '+' || *p == '-')
+      p++;
+
+  while (isdigit (*p))
+      p++;
+					
+  if (strncmp (p, decimal_point, decimal_point_len) == 0) {
+      *p = '.';
+      decimal_len = strlen (p + decimal_point_len);
+      memmove (p + 1, p + decimal_point_len, decimal_len);
+      p[1 + decimal_len] = 0;
+
+      /* Remove trailing zeros and decimal point if possible. */
+      for (p = p + decimal_len; *p == '0'; p--)
+	  *p = 0;
+
+      if (*p == '.') {
+	  *p = 0;
+	  p--;
+      }
+  }
+					        
+  return p + 1 - buffer;
+}
+
+
+enum {
+    LENGTH_MODIFIER_LONG = 0x100
+};
+
+/* Here's a limited reimplementation of printf.  The reason for doing
+ * this is primarily to special case handling of doubles.  We want
+ * locale independent formatting of doubles and we want to trim
+ * trailing zeros.  This is handled by dtostr() above, and the code
+ * below handles everything else by calling snprintf() to do the
+ * formatting.  This functionality is only for internal use and we
+ * only implement the formats we actually use.
+ */
+
+cairo_status_t
+_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
+			      const char *fmt, va_list ap)
+{
+    char buffer[512];
+    char *p;
+    const char *f;
+    int length_modifier;
+
+    f = fmt;
+    p = buffer;
+    while (*f != '\0') {
+	if (p == buffer + sizeof (buffer)) {
+	    _cairo_output_stream_write (stream, buffer, sizeof (buffer));
+	    p = buffer;
+	}
+
+	if (*f != '%') {
+	    *p++ = *f++;
+	    continue;
+	}
+
+	f++;
+
+	_cairo_output_stream_write (stream, buffer, p - buffer);
+	p = buffer;
+
+	length_modifier = 0;
+	if (*f == 'l') {
+	    length_modifier = LENGTH_MODIFIER_LONG;
+	    f++;
+	}
+
+	switch (*f | length_modifier) {
+	case '%':
+	    p[0] = *f;
+	    p[1] = 0;
+	    break;
+	case 'd':
+	    snprintf (buffer, sizeof buffer, "%d", va_arg (ap, int));
+	    break;
+	case 'd' | LENGTH_MODIFIER_LONG:
+	    snprintf (buffer, sizeof buffer, "%ld", va_arg (ap, long int));
+	    break;
+	case 'u':
+	    snprintf (buffer, sizeof buffer, "%u", va_arg (ap, unsigned int));
+	    break;
+	case 'u' | LENGTH_MODIFIER_LONG:
+	    snprintf (buffer, sizeof buffer, "%lu", va_arg (ap, long unsigned int));
+	    break;
+	case 'o':
+	    snprintf (buffer, sizeof buffer, "%o", va_arg (ap, int));
+	    break;
+	case 's':
+	    snprintf (buffer, sizeof buffer, "%s", va_arg (ap, const char *));
+	    break;
+	case 'f':
+	    dtostr (buffer, sizeof buffer, va_arg (ap, double));
+	    break;
+	default:
+	    ASSERT_NOT_REACHED;
+	}
+	p = buffer + strlen (buffer);
+	f++;
+    }
+    
+    _cairo_output_stream_write (stream, buffer, p - buffer);
+
+    return stream->status;
+}
+
 cairo_status_t
 _cairo_output_stream_printf (cairo_output_stream_t *stream,
 			     const char *fmt, ...)
 {
-    unsigned char buffer[512];
-    int length;
     va_list ap;
+    cairo_status_t status;    
 
     va_start (ap, fmt);
-    length = vsnprintf ((char *)buffer, sizeof buffer, fmt, ap);
-    va_end (ap);
 
-    /* FIXME: This function is only for internal use and callers are
-     * required to ensure the length of the output fits in this
-     * buffer.  If this is not good enough, we have to do the va_copy
-     * thing, which requires some autoconf magic to do portably. */
-    assert (length < sizeof buffer);
-    stream->status = stream->write_data (stream->closure, buffer, length);
-    stream->position += length;
+    status = _cairo_output_stream_vprintf (stream, fmt, ap);
 
-    return stream->status;
+    va_end (ap);
+
+    return status;
 }
 
 long

Index: cairo-pdf-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pdf-surface.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- cairo-pdf-surface.c	13 May 2005 16:26:20 -0000	1.33
+++ cairo-pdf-surface.c	13 May 2005 21:04:22 -0000	1.34
@@ -218,7 +218,8 @@
 
 static cairo_pdf_stream_t *
 _cairo_pdf_document_open_stream (cairo_pdf_document_t	*document,
-				 const char		*extra_entries);
+				 const char		*fmt,
+				 ...);
 static cairo_surface_t *
 _cairo_pdf_surface_create_for_document (cairo_pdf_document_t	*document,
 					double			width,
@@ -1023,10 +1024,12 @@
 
 static cairo_pdf_stream_t *
 _cairo_pdf_document_open_stream (cairo_pdf_document_t	*document,
-				 const char		*extra_entries)
+				 const char		*fmt,
+				 ...)
 {
     cairo_output_stream_t *output_stream = document->output_stream;
     cairo_pdf_stream_t *stream;
+    va_list ap;
 
     stream = malloc (sizeof (cairo_pdf_stream_t));
     if (stream == NULL) {
@@ -1038,13 +1041,19 @@
 
     _cairo_output_stream_printf (output_stream,
 				 "%d 0 obj\r\n"
-				 "<< /Length %d 0 R\r\n"
-				 "%s"
-				 ">>\r\n"
-				 "stream\r\n",
+				 "<< /Length %d 0 R\r\n",
 				 stream->id,
-				 stream->length_id,
-				 extra_entries);
+				 stream->length_id);
+
+    if (fmt != NULL) {
+	va_start (ap, fmt);
+	_cairo_output_stream_vprintf (output_stream, fmt, ap);
+	va_end (ap);
+    }
+
+    _cairo_output_stream_printf (output_stream,
+				 ">>\r\n"
+				 "stream\r\n");
 
     stream->start_offset = _cairo_output_stream_get_position (output_stream);
 
@@ -1107,18 +1116,17 @@
     cairo_pdf_document_t *document = surface->document;
     cairo_pdf_stream_t *stream;
     cairo_output_stream_t *output = document->output_stream;
-    char extra[200];
 
     if (document->current_stream == NULL ||
 	document->current_stream != surface->current_stream) {
 	_cairo_pdf_document_close_stream (document);
-	snprintf (extra, sizeof extra,
-		  "   /Type /XObject\r\n"
-		  "   /Subtype /Form\r\n"
-		  "   /BBox [ 0 0 %f %f ]\r\n",
-		  surface->width,
-		  surface->height);
-	stream = _cairo_pdf_document_open_stream (document, extra);
+	stream = _cairo_pdf_document_open_stream (document,
+						  "   /Type /XObject\r\n"
+						  "   /Subtype /Form\r\n"
+						  "   /BBox [ 0 0 %f %f ]\r\n",
+						  surface->width,
+						  surface->height);
+
 	_cairo_pdf_surface_add_stream (surface, stream);
 
 	/* If this is the first stream we open for this surface,
@@ -1153,7 +1161,6 @@
 {
     cairo_output_stream_t *output = document->output_stream;
     cairo_pdf_stream_t *stream;
-    char entries[200];
     char *rgb, *compressed;
     int i, x, y;
     unsigned long rgb_size, compressed_size;
@@ -1183,17 +1190,16 @@
 
     _cairo_pdf_document_close_stream (document);
 
-    snprintf (entries, sizeof entries, 
-	      "   /Type /XObject\r\n"
-	      "   /Subtype /Image\r\n"
-	      "   /Width %d\r\n"
-	      "   /Height %d\r\n"
-	      "   /ColorSpace /DeviceRGB\r\n"
-	      "   /BitsPerComponent 8\r\n"
-	      "   /Filter /FlateDecode\r\n",
-	      image->width, image->height);
+    stream = _cairo_pdf_document_open_stream (document, 
+					      "   /Type /XObject\r\n"
+					      "   /Subtype /Image\r\n"
+					      "   /Width %d\r\n"
+					      "   /Height %d\r\n"
+					      "   /ColorSpace /DeviceRGB\r\n"
+					      "   /BitsPerComponent 8\r\n"
+					      "   /Filter /FlateDecode\r\n",
+					      image->width, image->height);
 
-    stream = _cairo_pdf_document_open_stream (document, entries);
     _cairo_output_stream_write (output, compressed, compressed_size);
     _cairo_output_stream_printf (output,
 				 "\r\n");
@@ -1387,7 +1393,6 @@
     cairo_image_surface_t *image;
     void *image_extra;
     cairo_status_t status;
-    char entries[250];
     unsigned int id, alpha;
     cairo_matrix_t pm;
 
@@ -1411,17 +1416,16 @@
     pm = pattern->base.matrix;
     cairo_matrix_invert (&pm);
 
-    snprintf (entries, sizeof entries,
-	      "   /BBox [ 0 0 256 256 ]\r\n"
-	      "   /XStep 256\r\n"
-	      "   /YStep 256\r\n"
-	      "   /PatternType 1\r\n"
-	      "   /TilingType 1\r\n"
-	      "   /PaintType 1\r\n"
-	      "   /Resources << /XObject << /res%d %d 0 R >> >>\r\n",
-	      id, id);
+    stream = _cairo_pdf_document_open_stream (document,
+					      "   /BBox [ 0 0 256 256 ]\r\n"
+					      "   /XStep 256\r\n"
+					      "   /YStep 256\r\n"
+					      "   /PatternType 1\r\n"
+					      "   /TilingType 1\r\n"
+					      "   /PaintType 1\r\n"
+					      "   /Resources << /XObject << /res%d %d 0 R >> >>\r\n",
+					      id, id);
 
-    stream = _cairo_pdf_document_open_stream (document, entries);
 
     _cairo_output_stream_printf (output,
 				 " /res%d Do\r\n",
@@ -2134,6 +2138,7 @@
     cairo_pdf_object_t *object;
     int num_objects, i;
     long offset;
+    char buffer[11];
 
     num_objects = _cairo_array_num_elements (&document->objects);
 
@@ -2147,8 +2152,9 @@
 				 "0000000000 65535 f\r\n");
     for (i = 0; i < num_objects; i++) {
 	object = _cairo_array_index (&document->objects, i);
+	snprintf (buffer, sizeof buffer, "%010ld", object->offset);
 	_cairo_output_stream_printf (output,
-				     "%010ld 00000 n\r\n", object->offset);
+				     "%s 00000 n\r\n", buffer);
     }
 
     return offset;

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -d -r1.140 -r1.141
--- cairoint.h	13 May 2005 06:11:55 -0000	1.140
+++ cairoint.h	13 May 2005 21:04:22 -0000	1.141
@@ -53,6 +53,7 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 
 #ifdef _MSC_VER
 #define _USE_MATH_DEFINES
@@ -1783,6 +1784,10 @@
 			    const void *data, size_t length);
 
 cairo_private cairo_status_t
+_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
+			      const char *fmt, va_list ap);
+
+cairo_private cairo_status_t
 _cairo_output_stream_printf (cairo_output_stream_t *stream,
 			     const char *fmt, ...);
 




More information about the cairo-commit mailing list