]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/dcpsg.cpp
(char*)(const char*)xxx.mb_str() is not a good
[wxWidgets.git] / src / generic / dcpsg.cpp
index 2a541dd0c6e62ac98f06657ba665ff217a96dd9f..47421d57b1ac6d94c0d64928f891e64aabada395 100644 (file)
@@ -26,6 +26,8 @@
 
 #if wxUSE_POSTSCRIPT
 
+#include "wx/setup.h"
+
 #include "wx/window.h"
 #include "wx/dcmemory.h"
 #include "wx/utils.h"
 // start and end of document/page
 //-----------------------------------------------------------------------------
 
+static const char *wxPostScriptHeaderConicTo = "\
+/conicto {\n\
+    /to_y exch def\n\
+    /to_x exch def\n\
+    /conic_cntrl_y exch def\n\
+    /conic_cntrl_x exch def\n\
+    currentpoint\n\
+    /p0_y exch def\n\
+    /p0_x exch def\n\
+    /p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def\n\
+    /p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def\n\
+    /p2_x p1_x to_x p0_x sub 1 3 div mul add def\n\
+    /p2_y p1_y to_y p0_y sub 1 3 div mul add def\n\
+    p1_x p1_y p2_x p2_y to_x to_y curveto\n\
+}  bind def\n\
+/start_ol { gsave 1.0 72 div dup scale } bind def\n\
+/end_ol { closepath fill grestore } bind def\n\
+";
+      
 static const char *wxPostScriptHeaderEllipse = "\
 /ellipsedict 8 dict def\n\
 ellipsedict /mtrx matrix put\n\
@@ -185,6 +206,7 @@ static const char *wxPostScriptHeaderColourImage = "\
   } ifelse          %% end of 'false' case\n\
 ";
 
+#ifndef __WXGTK20__
 static char wxPostScriptHeaderReencodeISO1[] =
     "\n/reencodeISO {\n"
 "dup dup findfont dup length dict begin\n"
@@ -225,6 +247,7 @@ static char wxPostScriptHeaderReencodeISO2[] =
 "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n"
 "/yacute/thorn/ydieresis\n"
         "] def\n\n";
+#endif
 
 //-------------------------------------------------------------------------------
 // wxPostScriptDC
@@ -264,7 +287,7 @@ wxPostScriptDC::wxPostScriptDC ()
 
     // Compatibility only
     // HH: Doesn't seem to work for wxMSW...
-    #ifndef __WXMSW__
+    #if !defined(__WXMSW__)
     m_printData = * wxThePrintSetupData;
     #endif
 }
@@ -937,6 +960,7 @@ void wxPostScriptDC::SetFont( const wxFont& font )
 
     m_font = font;
 
+#ifndef __WXGTK20__
     int Style = m_font.GetStyle();
     int Weight = m_font.GetWeight();
 
@@ -1021,6 +1045,7 @@ void wxPostScriptDC::SetFont( const wxFont& font )
     for (int i = 0; i < 100; i++)
         if (buffer[i] == ',') buffer[i] = '.';
     fprintf( m_pstream, buffer );
+#endif
 }
 
 void wxPostScriptDC::SetPen( const wxPen& pen )
@@ -1166,10 +1191,256 @@ void wxPostScriptDC::SetBrush( const wxBrush& brush )
     }
 }
 
+#ifdef __WXGTK20__
+
+#include "wx/gtk/private.h"
+#include "wx/fontutil.h"
+#include "gtk/gtk.h"
+#include <pango/pangoft2.h>
+#include <freetype/ftglyph.h>
+
+#ifndef FT_Outline_Decompose
+  FT_EXPORT( FT_Error )  FT_Outline_Decompose(
+                           FT_Outline*              outline,
+                           const FT_Outline_Funcs*  interface,
+                           void*                    user );
+#endif
+
+typedef struct _OutlineInfo OutlineInfo;
+struct _OutlineInfo {
+  FILE *OUT;
+  FT_Vector glyph_origin;
+  int dpi;
+};
+
+static int paps_move_to( FT_Vector* to,
+                        void *user_data)
+{
+  OutlineInfo *outline_info = (OutlineInfo*)user_data;
+  fprintf(outline_info->OUT, "%d %d moveto\n",
+         (int)to->x ,
+         (int)to->y );
+  return 0;
+}
+
+static int paps_line_to( FT_Vector*  to,
+                        void *user_data)
+{
+  OutlineInfo *outline_info = (OutlineInfo*)user_data;
+  fprintf(outline_info->OUT, "%d %d lineto\n",
+         (int)to->x ,
+         (int)to->y );
+  return 0;
+}
+
+static int paps_conic_to( FT_Vector*  control,
+                         FT_Vector*  to,
+                         void *user_data)
+{
+  OutlineInfo *outline_info = (OutlineInfo*)user_data;
+  fprintf(outline_info->OUT, "%d %d %d %d conicto\n",
+         (int)control->x  ,
+         (int)control->y  ,
+         (int)to->x   ,
+         (int)to->y  );
+  return 0;
+}
+
+static int paps_cubic_to( FT_Vector*  control1,
+                         FT_Vector*  control2,
+                         FT_Vector*  to,
+                         void *user_data)
+{
+  OutlineInfo *outline_info = (OutlineInfo*)user_data;
+  fprintf(outline_info->OUT,
+         "%d %d %d %d %d %d curveto\n",
+         (int)control1->x , 
+         (int)control1->y ,
+         (int)control2->x ,
+         (int)control2->y ,
+         (int)to->x ,
+         (int)to->y );
+  return 0;
+}
+
+static void draw_bezier_outline(FILE *OUT,
+                        int dpi,
+                        FT_Face face,
+                        FT_UInt glyph_index,
+                        wxCoord pos_x,
+                        wxCoord pos_y
+                        )
+{
+  FT_Int load_flags = FT_LOAD_DEFAULT;
+  FT_Glyph glyph;
+
+  /* Output outline */
+  FT_Outline_Funcs outlinefunc = 
+  {
+    paps_move_to,
+    paps_line_to,
+    paps_conic_to,
+    paps_cubic_to
+  };
+  OutlineInfo outline_info;
+
+  outline_info.glyph_origin.x = (FT_Pos) pos_x;
+  outline_info.glyph_origin.y = (FT_Pos) pos_y;
+  outline_info.dpi = dpi;
+  outline_info.OUT = OUT;
+
+  fprintf(OUT, "gsave %d %d translate 0 0 0 setrgbcolor\n", pos_x, pos_y);
+  fprintf(OUT, "start_ol\n");
+
+  FT_Load_Glyph(face, glyph_index, load_flags);
+  FT_Get_Glyph (face->glyph, &glyph);
+  FT_Outline_Decompose (&(((FT_OutlineGlyph)glyph)->outline),
+                        &outlinefunc, &outline_info);
+  fprintf(OUT, "end_ol grestore \n");
+  
+  FT_Done_Glyph (glyph);
+}
+
+
+#endif
+
 void wxPostScriptDC::DoDrawText( const wxString& text, wxCoord x, wxCoord y )
 {
     wxCHECK_RET( m_ok && m_pstream, wxT("invalid postscript dc") );
 
+#ifdef __WXGTK20__
+    int dpi = GetResolution() * 2;
+
+    PangoContext *context = pango_ft2_get_context ( dpi, dpi );
+
+    // What are these for?
+    pango_context_set_language (context, pango_language_from_string ("en_US"));
+    pango_context_set_base_dir (context, PANGO_DIRECTION_LTR );
+
+    // Set the font
+    pango_context_set_font_description (context, m_font.GetNativeFontInfo()->description );
+
+    // Create layout 
+    PangoLayout *layout = layout = pango_layout_new (context);
+#if wxUSE_UNICODE
+    wxCharBuffer buffer = wxConvUTF8.cWC2MB( text );
+#else
+    wxCharBuffer buffer = wxConvUTF8.cWC2MB( wxConvLocal.cWX2WC( text ) );
+#endif
+       pango_layout_set_text( layout, (const char*) buffer, strlen(buffer) );
+
+#if 1
+    double xx = LogicalToDeviceX(x);
+    double yy = LogicalToDeviceY(y /*+ bitmap.GetHeight()*/ );
+
+    // Loop over lines in layout
+    int num_lines = pango_layout_get_line_count( layout );
+    for (int i = 0; i < num_lines; i++)
+    {
+        PangoLayoutLine *line = pango_layout_get_line( layout, i );
+        
+        // Loop over runs in line
+        GSList *runs_list = line->runs;
+        while (runs_list)
+        {
+            PangoLayoutRun *run = (PangoLayoutRun*) runs_list->data;
+            PangoItem *item = run->item;
+            PangoGlyphString *glyphs = run->glyphs;
+            PangoAnalysis *analysis = &item->analysis;
+            PangoFont *font = analysis->font;
+            FT_Face ft_face = pango_ft2_font_get_face(font);
+            
+            int num_glyphs = glyphs->num_glyphs;
+            for (int glyph_idx = 0; glyph_idx < num_glyphs; glyph_idx++)
+            {
+                PangoGlyphGeometry geometry = glyphs->glyphs[glyph_idx].geometry;
+                double pos_x = xx + 1.0 * geometry.x_offset / PANGO_SCALE;   
+                double pos_y = yy - 1.0 * geometry.y_offset / PANGO_SCALE;
+                xx += 1.0 * geometry.width / PANGO_SCALE;
+
+                draw_bezier_outline( m_pstream, dpi, ft_face,
+                             (FT_UInt)(glyphs->glyphs[glyph_idx].glyph),
+                             (wxCoord)pos_x, (wxCoord)pos_y );
+            }
+            runs_list = runs_list->next;
+        }
+       }
+#else    
+    // Find out extent for the bitmap
+    int height = 0;
+    int width = 0;
+    PangoRectangle logical_rect;
+    pango_layout_get_extents (layout, NULL, &logical_rect);
+    height = PANGO_PIXELS (logical_rect.height);
+    width = PANGO_PIXELS (logical_rect.width);
+    
+    // printf( "h %d w %d lh %d lw %d\n", height, width, logical_rect.height, logical_rect.width );
+
+    // Allocate FreeType 2 bitmap
+    int byte_width = (width + 7)/8 * 8;
+    FT_Bitmap bitmap;
+    guchar *buf = (guchar*) g_malloc (byte_width * height);
+    memset (buf, 0x00, byte_width * height);
+    bitmap.rows = height;
+    bitmap.width = byte_width;
+       bitmap.pitch = byte_width;
+       bitmap.buffer = buf;
+       bitmap.num_grays = 256;
+       bitmap.pixel_mode = ft_pixel_mode_grays;
+       
+    // Render bitmap
+       pango_ft2_render_layout (&bitmap, layout, 0, 0);
+
+       // Invert bitmap to get black text on white background
+    for (int pix_idx = 0; pix_idx < width * height; pix_idx++)
+        buf[pix_idx] = 255-buf[pix_idx];
+
+    // Write PS output
+    wxCoord xx = LogicalToDeviceX(x);
+    wxCoord yy = LogicalToDeviceY(y /*+ bitmap.GetHeight()*/ );
+
+    fprintf(m_pstream, "gsave\n");
+    fprintf(m_pstream, "%d %d translate\n", xx, yy);
+    fprintf(m_pstream, "/img_width %d def\n", bitmap.width);
+    fprintf(m_pstream, "/img_height %d def\n", bitmap.rows);
+    fprintf(m_pstream, "/picstr img_width 8 idiv string def\n");
+
+    fprintf(m_pstream,
+         "  img_width 72 15 div mul\n"
+          "  img_height 72 15 div mul scale\n"
+         "  0 setgray\n"
+         "  img_width img_height\n"
+         "  true\n"
+         "  [img_width 0 0 img_height neg 0 img_height 0.67 mul]\n"
+         "  { currentfile\n"
+         "    picstr readhexstring pop }\n"
+         "  imagemask"
+         );
+
+
+    for (int b_idx= 0; b_idx < bitmap.width/8 * bitmap.rows; b_idx++)
+    {
+      guchar packed_b = 0;
+      int bit_idx;
+
+      if (b_idx % (bitmap.width/8) == 0)
+       fprintf(m_pstream, "\n");
+      
+      for (bit_idx = 0; bit_idx < 8; bit_idx++)
+       {
+         guchar this_bit = bitmap.buffer[b_idx * 8+bit_idx]<128;
+         packed_b = (packed_b << 1) + this_bit;
+       }
+      fprintf(m_pstream, "%02x", packed_b);
+    }
+  
+    fprintf(m_pstream, "\ngrestore\n" );
+    
+    // Free memory
+    g_free( buf );
+#endif
+
+#else
     wxCoord text_w, text_h, text_descent;
 
     GetTextExtent(text, &text_w, &text_h, &text_descent);
@@ -1274,6 +1545,7 @@ void wxPostScriptDC::DoDrawText( const wxString& text, wxCoord x, wxCoord y )
 
     CalcBoundingBox( x, y );
     CalcBoundingBox( x + size * text.Length() * 2/3 , y );
+#endif
 }
 
 void wxPostScriptDC::DoDrawRotatedText( const wxString& text, wxCoord x, wxCoord y, double angle )
@@ -1577,7 +1849,7 @@ bool wxPostScriptDC::StartDoc( const wxString& message )
         m_printData.SetFilename(filename);
     }
 
-    m_pstream = wxFopen( m_printData.GetFilename().fn_str(), wxT("w+") );
+    m_pstream = wxFopen( m_printData.GetFilename().c_str(), wxT("w+") );  // FIXME: use fn_str() here under Unicode?
 
     if (!m_pstream)
     {
@@ -1589,11 +1861,14 @@ bool wxPostScriptDC::StartDoc( const wxString& message )
     m_ok = TRUE;
 
     fprintf( m_pstream, "%%%%BeginProlog\n" );
+    fprintf( m_pstream, wxPostScriptHeaderConicTo );
     fprintf( m_pstream, wxPostScriptHeaderEllipse );
     fprintf( m_pstream, wxPostScriptHeaderEllipticArc );
     fprintf( m_pstream, wxPostScriptHeaderColourImage );
+#ifndef __WXGTK20__
     fprintf( m_pstream, wxPostScriptHeaderReencodeISO1 );
     fprintf( m_pstream, wxPostScriptHeaderReencodeISO2 );
+#endif
     if (wxPostScriptHeaderSpline)
         fprintf( m_pstream, wxPostScriptHeaderSpline );
     fprintf( m_pstream, "%%%%EndProlog\n" );
@@ -1627,26 +1902,13 @@ void wxPostScriptDC::EndDoc ()
 
     wxChar *header_file = wxGetTempFileName("ps");
 
-    m_pstream = fopen( wxConvFile.cWX2MB(header_file) , "w+" );
+    m_pstream = wxFopen( header_file, wxT("w+") );
 
     fprintf( m_pstream, "%%!PS-Adobe-2.0\n" );                     // PostScript magic strings
     fprintf( m_pstream, "%%%%Title: %s\n", (const char *)m_title.mb_str() );
-    fprintf( m_pstream, "%%%%Creator: %s\n", (const char*)wxConvCurrent->cWX2MB(wxTheApp->argv[0]) );
+    fprintf( m_pstream, "%%%%Creator: wxWindows PostScript renderer\n" );
     fprintf( m_pstream, "%%%%CreationDate: %s\n", (const char *)wxNow().mb_str() );
 
-    wxChar userID[256];
-    if ( wxGetEmailAddress(userID, sizeof(userID)) )
-    {
-        fprintf( m_pstream, "%%%%For: %s ", wxMBSTRINGCAST wxConvCurrent->cWX2MB(userID) );
-        wxChar userName[245];
-        if (wxGetUserName(userName, sizeof(userName)))
-            fprintf( m_pstream, " (%s)", wxMBSTRINGCAST wxConvCurrent->cWX2MB(userName) );
-        fprintf( m_pstream, "\n" );
-    }
-    else if ( wxGetUserName(userID, sizeof(userID)) )
-    {
-        fprintf( m_pstream, "%%%%For: %s\n", wxMBSTRINGCAST wxConvCurrent->cWX2MB(userID) );;
-    }
 
     // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com>
 
@@ -1748,7 +2010,10 @@ void wxPostScriptDC::EndDoc ()
                 argv[0] = WXSTRINGCAST previewCommand;
                 argv[1] = WXSTRINGCAST filename;
                 argv[2] = (wxChar*) NULL;
+#if defined(__WXGTK20__) && wxUSE_UNICODE
+#else
                 wxExecute( argv, TRUE );
+#endif
                 wxRemoveFile( m_printData.GetFilename() );
             }
             break;
@@ -1766,7 +2031,10 @@ void wxPostScriptDC::EndDoc ()
 
                 argv[argc++] = WXSTRINGCAST filename;
                 argv[argc++] = (wxChar *) NULL;
+#if defined(__WXGTK20__) && wxUSE_UNICODE
+#else
                 wxExecute( argv, TRUE );
+#endif
                 wxRemoveFile( filename );
             }
             break;
@@ -2048,7 +2316,7 @@ void wxPostScriptDC::DoGetTextExtent(const wxString& string,
 
         if (afmFile==NULL)
         {
-            wxLogDebug( wxT("GetTextExtent: can't open AFM file '%hs'"), afmName.c_str() );
+            wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName.c_str() );
             wxLogDebug( wxT("               using approximate values"));
             for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */
             lastDescender = -150; /* dito. */
@@ -2071,7 +2339,7 @@ void wxPostScriptDC::DoGetTextExtent(const wxString& string,
                     if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) ||
                             (strcmp(descString,"Descender")!=0))
                     {
-                        wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad descender)"), afmName.c_str(),line );
+                        wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName.c_str(),line );
                     }
                 }
                 /* JC 1.) check for UnderlinePosition */
@@ -2080,7 +2348,7 @@ void wxPostScriptDC::DoGetTextExtent(const wxString& string,
                     if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) ||
                             (strcmp(upString,"UnderlinePosition")!=0))
                     {
-                        wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad UnderlinePosition)"), afmName.c_str(), line );
+                        wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName.c_str(), line );
                     }
                 }
                 /* JC 2.) check for UnderlineThickness */
@@ -2089,7 +2357,7 @@ void wxPostScriptDC::DoGetTextExtent(const wxString& string,
                     if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) ||
                             (strcmp(utString,"UnderlineThickness")!=0))
                     {
-                        wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad UnderlineThickness)"), afmName.c_str(), line );
+                        wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName.c_str(), line );
                     }
                 }
                 /* JC 3.) check for EncodingScheme */
@@ -2098,11 +2366,11 @@ void wxPostScriptDC::DoGetTextExtent(const wxString& string,
                     if ((sscanf(line,"%s%s",utString,encString)!=2) ||
                             (strcmp(utString,"EncodingScheme")!=0))
                     {
-                        wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (bad EncodingScheme)"), afmName.c_str(), line );
+                        wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName.c_str(), line );
                     }
                     else if (strncmp(encString, "AdobeStandardEncoding", 21))
                     {
-                        wxLogDebug( wxT("AFM-file '%hs': line '%hs' has error (unsupported EncodingScheme %hs)"),
+                        wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"),
                                 afmName.c_str(),line, encString);
                     }
                 }
@@ -2111,11 +2379,11 @@ void wxPostScriptDC::DoGetTextExtent(const wxString& string,
                 {
                     if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5)
                     {
-                        wxLogDebug(wxT("AFM-file '%hs': line '%hs' has an error (bad character width)"),afmName.c_str(),line);
+                        wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName.c_str(),line);
                     }
                     if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0)
                     {
-                        wxLogDebug(wxT("AFM-file '%hs': line '%hs' has a format error"),afmName.c_str(),line);
+                        wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName.c_str(),line);
                     }
                     /* printf("            char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */
                     if (ascii>=0 && ascii<256)
@@ -2167,7 +2435,7 @@ void wxPostScriptDC::DoGetTextExtent(const wxString& string,
     {
         if(lastWidths[*p]== INT_MIN)
         {
-            wxLogDebug(wxT("GetTextExtent: undefined width for character '%hc' (%d)"), *p,*p);
+            wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p,*p);
             sum += lastWidths[' ']; /* assume space */
         }
         else