summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2020-10-28 17:19:05 +0100
committerGitHub <noreply@github.com>2020-10-28 17:19:05 +0100
commit8accc6e8409819316fa296642c1d23e5638fcb2d (patch)
tree33c6237919989f120f2179cb1e7b410cb7cdd01e
parentf718943e6fbcf89297e61466068405452d7f8ae6 (diff)
Pango ps (#148)
Use cairo-PostScript to output PostScript when pango is available. This allows to draw in vectorial form any script. Before, only the Latin script could be drawn to PostScript in vectorial form.
-rw-r--r--CMake/options.cmake15
-rw-r--r--FL/Fl_PostScript.H271
-rw-r--r--configure.ac9
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/Fl_Printer.cxx8
-rw-r--r--src/Fl_x.cxx10
-rw-r--r--src/drivers/Posix/Fl_Posix_Printer_Driver.cxx5
-rw-r--r--src/drivers/PostScript/Fl_PostScript.cxx976
-rw-r--r--src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H231
-rw-r--r--src/drivers/PostScript/Fl_PostScript_image.cxx215
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H5
-rw-r--r--test/device.cxx9
12 files changed, 1288 insertions, 474 deletions
diff --git a/CMake/options.cmake b/CMake/options.cmake
index ac7fa5bb6..2bb439ae6 100644
--- a/CMake/options.cmake
+++ b/CMake/options.cmake
@@ -463,18 +463,23 @@ endif (OPTION_USE_PANGO)
#######################################################################
if (X11_Xft_FOUND AND OPTION_USE_PANGO)
pkg_check_modules(PANGOXFT pangoxft)
+ pkg_check_modules(PANGOCAIRO pangocairo)
+ pkg_check_modules(CAIRO cairo)
# message (STATUS "PANGOXFT_FOUND=" ${PANGOXFT_FOUND})
- if (PANGOXFT_FOUND)
- include_directories (${PANGOXFT_INCLUDE_DIRS})
+ if (PANGOXFT_FOUND AND PANGOCAIRO_FOUND AND CAIRO_FOUND)
+ include_directories (${PANGOXFT_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS})
find_library(HAVE_LIB_PANGO pango-1.0 ${CMAKE_LIBRARY_PATH})
find_library(HAVE_LIB_PANGOXFT pangoxft-1.0 ${CMAKE_LIBRARY_PATH})
+ find_library(HAVE_LIB_PANGOCAIRO pangocairo-1.0 ${CMAKE_LIBRARY_PATH})
+ find_library(HAVE_LIB_CAIRO cairo ${CMAKE_LIBRARY_PATH})
+ find_library(HAVE_LIB_GOBJECT gobject-2.0 ${CMAKE_LIBRARY_PATH})
set (USE_PANGO TRUE)
- list (APPEND FLTK_LDLIBS -lpango-1.0 -lpangoxft-1.0 -lgobject-2.0)
+ list (APPEND FLTK_LDLIBS -lpango-1.0 -lpangoxft-1.0 -lpangocairo-1.0 -lcairo -lgobject-2.0)
if (APPLE)
get_filename_component(PANGO_L_PATH ${HAVE_LIB_PANGO} PATH)
set (LDFLAGS "${LDFLAGS} -L${PANGO_L_PATH}")
endif (APPLE)
- else(PANGOXFT_FOUND)
+ else(PANGOXFT_FOUND AND PANGOCAIRO_FOUND AND CAIRO_FOUND)
# this covers Debian, Ubuntu, FreeBSD, NetBSD, Darwin
if (APPLE AND OPTION_APPLE_X11)
@@ -511,7 +516,7 @@ if (X11_Xft_FOUND AND OPTION_USE_PANGO)
include_directories (${PANGO_H_PREFIX}/pango-1.0 ${GLIB_H_PATH} ${PANGOLIB_DIR}/glib-2.0/include)
list (APPEND FLTK_LDLIBS -lpango-1.0 -lpangoxft-1.0 -lgobject-2.0)
endif (HAVE_LIB_PANGO AND HAVE_LIB_PANGOXFT AND HAVE_LIB_GOBJECT)
-endif (PANGOXFT_FOUND)
+endif (PANGOXFT_FOUND AND PANGOCAIRO_FOUND AND CAIRO_FOUND)
endif (X11_Xft_FOUND AND OPTION_USE_PANGO)
if (OPTION_USE_XFT)
diff --git a/FL/Fl_PostScript.H b/FL/Fl_PostScript.H
index 489916d6b..dc31cb116 100644
--- a/FL/Fl_PostScript.H
+++ b/FL/Fl_PostScript.H
@@ -15,7 +15,7 @@
//
/** \file Fl_PostScript.H
- \brief declaration of classes Fl_PostScript_Graphics_Driver, Fl_PostScript_File_Device.
+ \brief declaration of classes Fl_PostScript_File_Device and Fl_EPS_File_Surface.
*/
#ifndef Fl_PostScript_H
@@ -25,204 +25,23 @@
#include <FL/fl_draw.H>
#include <stdarg.h>
-/* Signature of Fl_PostScript::close_command() functions passed as parameters. */
+/** Signature of Fl_PostScript::close_command() functions passed as parameters. */
extern "C" {
- typedef int (Fl_PostScript_Close_Command)(FILE *);
+ typedef int (*Fl_PostScript_Close_Command)(FILE *);
}
-/**
- \cond DriverDev
- \addtogroup DriverDeveloper
- \{
- */
-
-/**
- PostScript graphical backend.
- */
-class FL_EXPORT Fl_PostScript_Graphics_Driver : public Fl_Graphics_Driver {
-private:
- void transformed_draw_extra(const char* str, int n, double x, double y, int w, bool rtl);
- void *prepare_rle85();
- void write_rle85(uchar b, void *data);
- void close_rle85(void *data);
- void *prepare85();
- void write85(void *data, const uchar *p, int len);
- void close85(void *data);
- int scale_for_image_(Fl_Image *img, int XP, int YP, int WP, int HP,int cx, int cy);
-protected:
- uchar **mask_bitmap() {return &mask;}
-public:
- Fl_PostScript_Graphics_Driver();
-#ifndef FL_DOXYGEN
- enum SHAPE{NONE=0, LINE, LOOP, POLYGON, POINTS};
-
- class Clip {
- public:
- int x, y, w, h;
- Clip *prev;
- };
- Clip * clip_;
-
- int lang_level_;
- int gap_;
- int pages_;
-
- double width_;
- double height_;
-
- int shape_;
- int linewidth_;// need for clipping, lang level 1-2
- int linestyle_;//
- int interpolate_; //interpolation of images
- unsigned char cr_,cg_,cb_;
- char linedash_[256];//should be enough
- void concat(); // transform ror scalable dradings...
- void reconcat(); //invert
- void recover(); //recovers the state after grestore (such as line styles...)
- void reset();
-
- uchar * mask;
- int mx; // width of mask;
- int my; // mask lines
- //Fl_Color bg_;
- Fl_PostScript_Close_Command* close_cmd_;
- int page_policy_;
- int nPages;
- int orientation_;
-
- float scale_x;
- float scale_y;
- float angle;
- int left_margin;
- int top_margin;
-
- FILE *output;
- double pw_, ph_;
-
- uchar bg_r, bg_g, bg_b;
- int start_postscript (int pagecount, enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout);
- /* int alpha_mask(const uchar * data, int w, int h, int D, int LD=0);
- */
- void transformed_draw(const char* s, int n, double x, double y); //precise text placing
- void transformed_draw(const char* s, double x, double y);
- int alpha_mask(const uchar * data, int w, int h, int D, int LD=0);
-
- enum Fl_Paged_Device::Page_Format page_format_;
- char *ps_filename_;
-
- void page_policy(int p);
- int page_policy(){return page_policy_;};
- void close_command(Fl_PostScript_Close_Command* cmd){close_cmd_=cmd;};
- FILE * file() {return output;};
- //void orientation (int o);
- //Fl_PostScript_Graphics_Driver(FILE *o, int lang_level, int pages = 0); // ps (also multi-page) constructor
- //Fl_PostScript_Graphics_Driver(FILE *o, int lang_level, int x, int y, int w, int h); //eps constructor
- void interpolate(int i){interpolate_=i;};
- int interpolate(){return interpolate_;}
-
- void page(double pw, double ph, int media = 0);
- void page(int format);
-#endif // FL_DOXYGEN
-
- // implementation of drawing methods
- void color(Fl_Color c);
- void color(uchar r, uchar g, uchar b);
-
- void push_clip(int x, int y, int w, int h);
- int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H);
- int not_clipped(int x, int y, int w, int h);
- void push_no_clip();
- void pop_clip();
-
- void line_style(int style, int width=0, char* dashes=0);
-
- void rect(int x, int y, int w, int h);
- void rectf(int x, int y, int w, int h);
-
- void xyline(int x, int y, int x1);
- void xyline(int x, int y, int x1, int y2);
- void xyline(int x, int y, int x1, int y2, int x3);
-
- void yxline(int x, int y, int y1);
- void yxline(int x, int y, int y1, int x2);
- void yxline(int x, int y, int y1, int x2, int y3);
-
- void line(int x1, int y1, int x2, int y2);
- void line(int x1, int y1, int x2, int y2, int x3, int y3);
-
- void loop(int x0, int y0, int x1, int y1, int x2, int y2);
- void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
- void polygon(int x0, int y0, int x1, int y1, int x2, int y2);
- void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
- void point(int x, int y);
-
- void begin_points();
- void begin_line();
- void begin_loop();
- void begin_polygon();
- void vertex(double x, double y);
- void curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3);
- void circle(double x, double y, double r);
- void arc(double x, double y, double r, double start, double a);
- void arc(int x, int y, int w, int h, double a1, double a2);
- void pie(int x, int y, int w, int h, double a1, double a2);
- void end_points();
- void end_line();
- void end_loop();
- void end_polygon();
- void begin_complex_polygon(){begin_polygon();};
- void gap(){gap_=1;};
- void end_complex_polygon(){end_polygon();};
- void transformed_vertex(double x, double y);
-
- void draw_image(const uchar* d, int x,int y,int w,int h, int delta=3, int ldelta=0);
- void draw_image_mono(const uchar* d, int x,int y,int w,int h, int delta=1, int ld=0);
- void draw_image(Fl_Draw_Image_Cb call, void* data, int x,int y, int w, int h, int delta=3);
- void draw_image_mono(Fl_Draw_Image_Cb call, void* data, int x,int y, int w, int h, int delta=1);
-
- void draw(const char* s, int nBytes, int x, int y) {transformed_draw(s,nBytes,x,y); };
- void draw(const char* s, int nBytes, float x, float y) {transformed_draw(s,nBytes,x,y); };
- void draw(int angle, const char *str, int n, int x, int y);
- void rtl_draw(const char* s, int n, int x, int y);
- void font(int face, int size);
- double width(const char *, int);
- double width(unsigned int u);
- void text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h);
- int height();
- int descent();
- void draw_pixmap(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy);
- void draw_bitmap(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy);
- void draw_rgb(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy);
- /** Shields output PostScript data from modifications of the current locale.
- It typically avoids PostScript errors caused if the current locale uses comma instead of dot
- as "decimal point".
- \param format directives controlling output PostScript data
- \return value returned by vfprintf() call
- */
- int clocale_printf(const char *format, ...);
- ~Fl_PostScript_Graphics_Driver();
- // ---
- Fl_Bitmask create_bitmask(int w, int h, const uchar *array) { return 0L; }
- virtual int has_feature(driver_feature feature_mask) { return feature_mask & PRINTER; }
-
- int start_eps(int width, int height);
- void ps_origin(int x, int y);
- void ps_translate(int, int);
- void ps_untranslate();
-};
-
-/**
- \}
- \endcond
- */
+class Fl_PostScript_Graphics_Driver;
/**
To send graphical output to a PostScript file.
This class is used exactly as the Fl_Printer class except for the begin_job() call,
two variants of which are usable and allow to specify what page format and layout are desired.
- PostScript text uses vectorial fonts when using the FLTK standard fonts
- and the latin alphabet or a few other characters listed in the following table.
+ <b>Processing of text</b>: Text uses vectorial fonts under the X11 + pango platform.
+ With other platforms, only text restricted to the Latin alphabet (and a few other characters
+ listed in the table below) and to FLTK standard fonts is vectorized. All other unicode characters
+ or all other fonts (FL_FREE_FONT and above) are output as a bitmap.
+ FLTK standard fonts are output using the corresponding PostScript standard fonts.
The latin alphabet means all unicode characters between U+0020 and U+017F, or, in other words,
the ASCII, Latin-1 Supplement and Latin Extended-A charts.
<table>
@@ -241,37 +60,31 @@ public:
<tr><td>‘</td><td>U+2018</td><td>quoteleft</td><td>/</td><td>U+2044</td><td>fraction</td><td>fl</td><td>U+FB02</td><td>fl</td></tr>
<tr><td>’</td><td>U+2019</td><td>quoteright</td><td>€</td><td>U+20AC</td><td>Euro</td><td></td><td>U+F8FF</td><td>apple (Mac OS only)</td></tr>
</table>
- <br> All other unicode characters or all other fonts (FL_FREE_FONT and above) are output as a bitmap.
- <br> FLTK standard fonts are output using the corresponding PostScript standard fonts.
-
+
*/
class FL_EXPORT Fl_PostScript_File_Device : public Fl_Paged_Device {
protected:
/**
\brief Returns the PostScript driver of this drawing surface.
*/
- Fl_PostScript_Graphics_Driver *driver();
+ inline Fl_PostScript_Graphics_Driver *driver() { return (Fl_PostScript_Graphics_Driver*)Fl_Surface_Device::driver(); }
public:
- /**
- @brief The constructor.
- */
- Fl_PostScript_File_Device();
- /**
- @brief The destructor.
- */
+ /** The constructor. */
+ Fl_PostScript_File_Device();
+ /** The destructor. */
~Fl_PostScript_File_Device();
/** Don't use with this class. */
int begin_job(int pagecount, int* from, int* to, char **perr_message);
- /**
- @brief Begins the session where all graphics requests will go to a local PostScript file.
- *
- Opens a file dialog entitled with Fl_PostScript_File_Device::file_chooser_title to select an output PostScript file.
+ /** Begins the session where all graphics requests will go to a local PostScript file.
+ Opens a file dialog to select an output PostScript file.
+ This member function makes end_job() close the resulting PostScript file and display an
+ alert message with fl_alert() in case of any output error.
@param pagecount The total number of pages to be created. Use 0 if this number is unknown when this function is called.
@param format Desired page format.
@param layout Desired page layout.
@return 0 if OK, 1 if user cancelled the file dialog, 2 if fopen failed on user-selected output file.
*/
- int begin_job(int pagecount = 0, enum Fl_Paged_Device::Page_Format format = Fl_Paged_Device::A4,
+ int begin_job(int pagecount = 0, enum Fl_Paged_Device::Page_Format format = Fl_Paged_Device::A4,
enum Fl_Paged_Device::Page_Layout layout = Fl_Paged_Device::PORTRAIT);
/** Synonym of begin_job().
For API compatibility with FLTK 1.3.x */
@@ -279,9 +92,9 @@ public:
enum Fl_Paged_Device::Page_Layout layout = Fl_Paged_Device::PORTRAIT) {
return begin_job(pagecount, format, layout);
}
- /**
- @brief Begins the session where all graphics requests will go to FILE pointer.
- *
+ /** Begins the session where all graphics requests will go to FILE pointer.
+ This member function prevents end_job() from closing \p ps_output, so the user can check with \p ferror(ps_output)
+ for output errors.
@param ps_output A writable FILE pointer that will receive PostScript output and that should not be closed
until after end_job() has been called.
@param pagecount The total number of pages to be created. Use 0 if this number is unknown when this function is called.
@@ -308,11 +121,14 @@ public:
void translate(int x, int y);
void untranslate(void);
int end_page (void);
+ /** Finishes all PostScript output.
+ This also closes the underlying \p fclose(file()) unless close_command() was used to set another function.
+ */
void end_job(void);
- /** \brief Label of the PostScript file chooser window */
+ /** Label of the PostScript file chooser window */
static const char *file_chooser_title;
/** Returns the underlying FILE* receiving all PostScript data */
- FILE *file() { return driver()->file(); }
+ FILE *file();
};
/** Encapsulated PostScript drawing surface.
@@ -329,13 +145,10 @@ public:
surface->draw_decorated_window(win);
Fl_Surface_Device::pop_current();
delete surface; // the .eps file is not complete until the destructor was run
- fclose(eps);
}
\endcode
*/
class FL_EXPORT Fl_EPS_File_Surface : public Fl_Widget_Surface {
-private:
- void complete_();
protected:
/** Returns the PostScript driver of this drawing surface. */
inline Fl_PostScript_Graphics_Driver *driver() { return (Fl_PostScript_Graphics_Driver*)Fl_Surface_Device::driver(); }
@@ -343,27 +156,37 @@ public:
/**
Constructor.
\param width,height Width and height of the EPS drawing area
- \param eps A writable FILE pointer where the Encapsulated PostScript data will be sent
- \param background Color expected to cover the background of the EPS drawing area.
- This parameter affects only the drawing of transparent Fl_RGB_Image objects:
- transparent areas of RGB images are blended with the \p background color.
+ \param eps_output A writable FILE pointer where the Encapsulated PostScript data will be sent
+ \param background Color expected to cover the background of the EPS drawing area.
+ This parameter affects only the drawing of transparent Fl_RGB_Image objects:
+ transparent areas of RGB images are blended with the \p background color.
+ Under the X11 + pango platform, transparent RGB images are correctly blended to their background,
+ thus this parameter has no effect.
+ \param closef If not NULL, the destructor or close() will call \p closef(eps_output) after all
+ EPS data has been sent. If NULL, \p fclose(eps_output) is called instead. This allows to close the FILE
+ pointer by, e.g., \p pclose, or, using a function such as \p "int keep_open(FILE*){return 0;}", to keep it open after
+ completion of all output to \p eps_output. Function \p closef should return non zero to indicate an error.
*/
- Fl_EPS_File_Surface(int width, int height, FILE *eps, Fl_Color background = FL_WHITE);
+ Fl_EPS_File_Surface(int width, int height, FILE *eps_output,
+ Fl_Color background = FL_WHITE, Fl_PostScript_Close_Command closef = NULL);
/**
Destructor.
- The underlying FILE pointer remains open after destruction of the Fl_EPS_File_Surface object
- unless close() was called.
+ By default, the destructor closes with function \p fclose() the underlying FILE. See the constructor for how
+ to close it differently or to keep it open. Use close() before object destruction to receive the status code
+ of output operations. If close() is not used and if EPS output results in error, the destructor displays an alert message
+ with fl_alert().
*/
~Fl_EPS_File_Surface();
virtual int printable_rect(int *w, int *h);
/** Returns the underlying FILE pointer */
- FILE *file() { return driver() ? driver()->output : NULL; }
+ FILE *file();
virtual void origin(int x, int y);
virtual void origin(int *px, int *py);
virtual void translate(int x, int y);
virtual void untranslate();
- /** Closes using fclose() the underlying FILE pointer.
- The only operation possible with the Fl_EPS_File_Surface object after calling close() is its destruction. */
+ /** Completes all EPS output.
+ The only operation possible with the Fl_EPS_File_Surface object after calling close() is its destruction.
+ \return The status code of output operations to the FILE object. 0 indicates success. */
int close();
};
diff --git a/configure.ac b/configure.ac
index 800ef780a..d2202c469 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1108,7 +1108,14 @@ case $host_os_gui in
if test x$PKGCONFIG != x; then
CXXFLAGS="`$PKGCONFIG --cflags pangoxft` $CXXFLAGS"
LIBS="`$PKGCONFIG --libs pangoxft` $LIBS"
- else
+ CXXFLAGS="`$PKGCONFIG --cflags pangocairo` $CXXFLAGS"
+ LIBS="`$PKGCONFIG --libs pangocairo` $LIBS"
+ case $host_os in
+ darwin*)
+ LDFLAGS="-L/opt/sw/lib -L/sw/lib $LDFLAGS"
+ ;;
+ esac
+ else
case $host_os in
linux*)
CXXFLAGS="-I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include $CXXFLAGS"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d5eee5dc8..ff15cf04a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -529,10 +529,10 @@ if (HAVE_XRENDER)
endif (HAVE_XRENDER)
if (USE_PANGO)
- list (APPEND OPTIONAL_LIBS ${HAVE_LIB_PANGO} ${HAVE_LIB_PANGOXFT})
- if (NOT APPLE)
- list (APPEND OPTIONAL_LIBS ${HAVE_LIB_GOBJECT} )
- endif (NOT APPLE)
+ list (APPEND OPTIONAL_LIBS ${HAVE_LIB_PANGO} ${HAVE_LIB_PANGOXFT} ${HAVE_LIB_PANGOCAIRO} ${HAVE_LIB_CAIRO} ${HAVE_LIB_GOBJECT})
+ #if (NOT APPLE)
+ # list (APPEND OPTIONAL_LIBS ${HAVE_LIB_GOBJECT} )
+ #endif (NOT APPLE)
endif (USE_PANGO)
if (USE_XFT)
diff --git a/src/Fl_Printer.cxx b/src/Fl_Printer.cxx
index 8c587afb9..015592332 100644
--- a/src/Fl_Printer.cxx
+++ b/src/Fl_Printer.cxx
@@ -2,7 +2,7 @@
// Encompasses platform-specific printing-support code and
// PostScript output code for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2010-2016 by Bill Spitzak and others.
+// Copyright 2010-2020 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -80,15 +80,19 @@ void Fl_PostScript_File_Device::translate(int x, int y) {}
void Fl_PostScript_File_Device::untranslate(void) {}
int Fl_PostScript_File_Device::end_page (void) {return 1;}
void Fl_PostScript_File_Device::end_job(void) {}
+FILE* Fl_PostScript_File_Device::file() {return NULL;}
Fl_PostScript_File_Device::~Fl_PostScript_File_Device(void) {}
-Fl_EPS_File_Surface::Fl_EPS_File_Surface(int width, int height, FILE *eps, Fl_Color background) : Fl_Widget_Surface(NULL) {}
+Fl_EPS_File_Surface::Fl_EPS_File_Surface(int width, int height, FILE *eps_output,
+ Fl_Color background, Fl_PostScript_Close_Command closef) : Fl_Widget_Surface(NULL) {}
Fl_EPS_File_Surface::~Fl_EPS_File_Surface() {}
void Fl_EPS_File_Surface::origin(int, int) {}
void Fl_EPS_File_Surface::origin(int*, int*) {}
int Fl_EPS_File_Surface::printable_rect(int*, int*) {return 1;}
void Fl_EPS_File_Surface::translate(int, int) {}
void Fl_EPS_File_Surface::untranslate() {}
+FILE* Fl_EPS_File_Surface::file() {return NULL;}
+int Fl_EPS_File_Surface::close() {return 1;}
#else
diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx
index 947203679..31a76f4e9 100644
--- a/src/Fl_x.cxx
+++ b/src/Fl_x.cxx
@@ -3087,7 +3087,7 @@ void Fl_X11_Window_Driver::show() {
}
-//#define USE_PRINT_BUTTON 1
+#define USE_PRINT_BUTTON 1
#ifdef USE_PRINT_BUTTON
// to test the Fl_Printer class creating a "Print front window" button in a separate window
@@ -3112,6 +3112,7 @@ void printFront(Fl_Widget *o, void *data)
scale = (float)w/ww;
if ((float)h/wh < scale) scale = (float)h/wh;
printer.scale(scale, scale);
+ printer.printable_rect(&w, &h);
}
// #define ROTATE 20.0
@@ -3120,11 +3121,12 @@ void printFront(Fl_Widget *o, void *data)
printer.printable_rect(&w, &h);
printer.origin(w/2, h/2 );
printer.rotate(ROTATE);
- printer.print_widget( win, - win->w()/2, - win->h()/2 );
+ printer.print_window( win, - win->w()/2, - win->h()/2);
//printer.print_window_part( win, 0,0, win->w(), win->h(), - win->w()/2, - win->h()/2 );
#else
- printer.print_window(win);
- //printer.print_window_part( win, 0,0, win->w(), win->h(), 0,0 );
+ printer.origin(w/2, h/2 );
+ printer.print_window(win, -ww/2, -wh/2);
+ //printer.print_window_part( win, 0,0, win->w(), win->h(), -ww/2, -wh/2 );
#endif
printer.end_page();
diff --git a/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx b/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx
index dbb966a76..5fcb4645a 100644
--- a/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx
+++ b/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx
@@ -1,7 +1,7 @@
//
// PostScript priting support for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2010-2016 by Bill Spitzak and others.
+// Copyright 2010-2020 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -19,6 +19,7 @@
#if defined(FL_CFG_PRN_PS) && !defined(FL_NO_PRINT_SUPPORT)
#include <FL/Fl_PostScript.H>
+#include "../PostScript/Fl_PostScript_Graphics_Driver.H"
#include <FL/Fl_Printer.H>
#include <FL/fl_ask.H>
@@ -326,7 +327,7 @@ int Fl_Posix_Printer_Driver::begin_job(int pages, int *firstpage, int *lastpage,
return 2;
}
ps->close_command(pclose);
- this->set_current();
+ Fl_Surface_Device::push_current(this);
return ps->start_postscript(pages, format, layout); // start printing
}
diff --git a/src/drivers/PostScript/Fl_PostScript.cxx b/src/drivers/PostScript/Fl_PostScript.cxx
index 5adf20562..958bbd1a6 100644
--- a/src/drivers/PostScript/Fl_PostScript.cxx
+++ b/src/drivers/PostScript/Fl_PostScript.cxx
@@ -20,57 +20,32 @@
#include <FL/fl_ask.H>
#include <FL/fl_draw.H>
#include <stdio.h>
+#include "Fl_PostScript_Graphics_Driver.H"
#include <FL/Fl_PostScript.H>
#include <FL/Fl_Native_File_Chooser.H>
#include "../../Fl_System_Driver.H"
#include <FL/fl_string.h>
+#include <FL/platform.H>
#include <stdarg.h>
#include <time.h>
+#if USE_PANGO
+#include <FL/math.h> // for M_PI
+#include <pango/pangocairo.h>
+#include <cairo/cairo-ps.h>
+#include "../Xlib/Fl_Xlib_Graphics_Driver.H"
+#endif
const char *Fl_PostScript_File_Device::file_chooser_title = "Select a .ps file";
-/**
- \cond DriverDev
- \addtogroup DriverDeveloper
- \{
- */
-
-/**
- \brief The constructor.
- */
-Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void)
-{
- close_cmd_ = 0;
- //lang_level_ = 3;
- lang_level_ = 2;
- mask = 0;
- ps_filename_ = NULL;
- scale_x = scale_y = 1.;
- bg_r = bg_g = bg_b = 255;
-}
-
-/** \brief The destructor. */
-Fl_PostScript_Graphics_Driver::~Fl_PostScript_Graphics_Driver() {
- if(ps_filename_) free(ps_filename_);
-}
-
-/**
- \}
- \endcond
- */
-
-
Fl_PostScript_File_Device::Fl_PostScript_File_Device(void)
{
Fl_Surface_Device::driver( new Fl_PostScript_Graphics_Driver() );
}
-Fl_PostScript_Graphics_Driver *Fl_PostScript_File_Device::driver()
-{
- return (Fl_PostScript_Graphics_Driver*)Fl_Surface_Device::driver();
+FILE *Fl_PostScript_File_Device::file() {
+ return driver()->file();
}
-
int Fl_PostScript_File_Device::begin_job (int pagecount, enum Fl_Paged_Device::Page_Format format,
enum Fl_Paged_Device::Page_Layout layout)
{
@@ -86,7 +61,7 @@ int Fl_PostScript_File_Device::begin_job (int pagecount, enum Fl_Paged_Device::P
if(ps->output == NULL) return 2;
ps->ps_filename_ = fl_strdup(fnfc.filename());
ps->start_postscript(pagecount, format, layout);
- this->set_current();
+ Fl_Surface_Device::push_current(this);
return 0;
}
@@ -105,7 +80,7 @@ int Fl_PostScript_File_Device::begin_job (FILE *ps_output, int pagecount,
ps->ps_filename_ = NULL;
ps->start_postscript(pagecount, format, layout);
ps->close_command(dont_close); // so that end_job() doesn't close the file
- this->set_current();
+ Fl_Surface_Device::push_current(this);
return 0;
}
@@ -125,6 +100,158 @@ Fl_PostScript_File_Device::~Fl_PostScript_File_Device() {
\{
*/
+static const int dashes_flat[5][7]={
+{-1,0,0,0,0,0,0},
+{3,1,-1,0,0,0,0},
+{1,1,-1,0,0,0,0},
+{3,1,1,1,-1,0,0},
+{3,1,1,1,1,1,-1}
+};
+
+//yeah, hack...
+static const double dashes_cap[5][7]={
+{-1,0,0,0,0,0,0},
+{2,2,-1,0,0,0,0},
+{0.01,1.99,-1,0,0,0,0},
+{2,2,0.01,1.99,-1,0,0},
+{2,2,0.01,1.99,0.01,1.99,-1}
+};
+
+/**
+ \brief The constructor.
+ */
+Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void)
+{
+ close_cmd_ = 0;
+ //lang_level_ = 3;
+ lang_level_ = 2;
+ mask = 0;
+ ps_filename_ = NULL;
+ scale_x = scale_y = 1.;
+ bg_r = bg_g = bg_b = 255;
+ clip_ = NULL;
+}
+
+/** \brief The destructor. */
+Fl_PostScript_Graphics_Driver::~Fl_PostScript_Graphics_Driver() {
+ if(ps_filename_) free(ps_filename_);
+}
+
+
+#if ! USE_PANGO
+static const char *_fontNames[] = {
+"Helvetica2B",
+"Helvetica-Bold2B",
+"Helvetica-Oblique2B",
+"Helvetica-BoldOblique2B",
+"Courier2B",
+"Courier-Bold2B",
+"Courier-Oblique2B",
+"Courier-BoldOblique2B",
+"Times-Roman2B",
+"Times-Bold2B",
+"Times-Italic2B",
+"Times-BoldItalic2B",
+"Symbol",
+"Courier2B",
+"Courier-Bold2B",
+"ZapfDingbats"
+};
+#endif
+
+void Fl_PostScript_Graphics_Driver::font(int f, int s) {
+ Fl_Graphics_Driver& driver = Fl_Graphics_Driver::default_driver();
+ driver.font(f,s); // Use display fonts for font measurement
+ Fl_Graphics_Driver::font(f, s);
+ Fl_Font_Descriptor *desc = driver.font_descriptor();
+ this->font_descriptor(desc);
+#if ! USE_PANGO
+ if (f < FL_FREE_FONT) {
+ fprintf(output, "/%s SF\n" , _fontNames[f]);
+ float ps_size = driver.scale_font_for_PostScript(desc, s);
+ clocale_printf("%.1f FS\n", ps_size);
+ }
+#endif
+}
+
+double Fl_PostScript_Graphics_Driver::width(const char *s, int n) {
+ return Fl_Graphics_Driver::default_driver().width(s, n);
+}
+
+double Fl_PostScript_Graphics_Driver::width(unsigned u) {
+ return Fl_Graphics_Driver::default_driver().width(u);
+}
+
+int Fl_PostScript_Graphics_Driver::height() {
+ return Fl_Graphics_Driver::default_driver().height();
+}
+
+int Fl_PostScript_Graphics_Driver::descent() {
+ return Fl_Graphics_Driver::default_driver().descent();
+}
+
+void Fl_PostScript_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
+ Fl_Graphics_Driver::default_driver().text_extents(c, n, dx, dy, w, h);
+}
+
+
+void Fl_PostScript_Graphics_Driver::color(Fl_Color c) {
+ Fl::get_color(c, cr_, cg_, cb_);
+ color(cr_, cg_, cb_);
+}
+
+void Fl_PostScript_Graphics_Driver::point(int x, int y){
+ rectf(x,y,1,1);
+}
+
+int Fl_PostScript_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
+ if (!clip_) return 1;
+ if (clip_->w < 0) return 1;
+ int X = 0, Y = 0, W = 0, H = 0;
+ clip_box(x, y, w, h, X, Y, W, H);
+ if (W) return 1;
+ return 0;
+}
+
+int Fl_PostScript_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) {
+ if (!clip_) {
+ X = x; Y = y; W = w; H = h;
+ return 0;
+ }
+ if (clip_->w < 0) {
+ X = x; Y = y; W = w; H = h;
+ return 1;
+ }
+ int ret = 0;
+ if (x > (X=clip_->x)) {X=x; ret=1;}
+ if (y > (Y=clip_->y)) {Y=y; ret=1;}
+ if ((x+w) < (clip_->x+clip_->w)) {
+ W=x+w-X;
+
+ ret=1;
+
+ }else
+ W = clip_->x + clip_->w - X;
+ if(W<0){
+ W=0;
+ return 1;
+ }
+ if ((y+h) < (clip_->y+clip_->h)) {
+ H=y+h-Y;
+ ret=1;
+ }else
+ H = clip_->y + clip_->h - Y;
+ if(H<0){
+ W=0;
+ H=0;
+ return 1;
+ }
+ return ret;
+}
+
+
+#if ! USE_PANGO
+
int Fl_PostScript_Graphics_Driver::clocale_printf(const char *format, ...)
{
va_list args;
@@ -583,8 +710,8 @@ int Fl_PostScript_Graphics_Driver::start_postscript (int pagecount,
}
int Fl_PostScript_Graphics_Driver::start_eps (int width, int height) {
- width_ = width;
- height_ = height;
+ pw_ = width;
+ ph_ = height;
fputs("%!PS-Adobe-3.0 EPSF-3.0\n", output);
fputs("%%Creator: (FLTK)\n", output);
fprintf(output,"%%%%BoundingBox: 1 1 %d %d\n", width, height);
@@ -610,7 +737,7 @@ int Fl_PostScript_Graphics_Driver::start_eps (int width, int height) {
reset();
nPages=0;
fprintf(output, "GS\n");
- clocale_printf( "%g %g TR\n", (double)0, height_);
+ clocale_printf( "%g %g TR\n", (double)0, ph_);
fprintf(output, "1 -1 SC\n");
line_style(0);
fprintf(output, "GS GS\n");
@@ -854,29 +981,6 @@ void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int
fprintf(output, "GR\n");
}
-void Fl_PostScript_Graphics_Driver::point(int x, int y){
- rectf(x,y,1,1);
-}
-
-static const int dashes_flat[5][7]={
-{-1,0,0,0,0,0,0},
-{3,1,-1,0,0,0,0},
-{1,1,-1,0,0,0,0},
-{3,1,1,1,-1,0,0},
-{3,1,1,1,1,1,-1}
-};
-
-
-//yeah, hack...
-static const double dashes_cap[5][7]={
-{-1,0,0,0,0,0,0},
-{2,2,-1,0,0,0,0},
-{0.01,1.99,-1,0,0,0,0},
-{2,2,0.01,1.99,-1,0,0},
-{2,2,0.01,1.99,0.01,1.99,-1}
-};
-
-
void Fl_PostScript_Graphics_Driver::line_style(int style, int width, char* dashes){
//line_styled_=1;
@@ -935,64 +1039,6 @@ void Fl_PostScript_Graphics_Driver::line_style(int style, int width, char* dashe
fprintf(output, "] 0 setdash\n");
}
-static const char *_fontNames[] = {
-"Helvetica2B",
-"Helvetica-Bold2B",
-"Helvetica-Oblique2B",
-"Helvetica-BoldOblique2B",
-"Courier2B",
-"Courier-Bold2B",
-"Courier-Oblique2B",
-"Courier-BoldOblique2B",
-"Times-Roman2B",
-"Times-Bold2B",
-"Times-Italic2B",
-"Times-BoldItalic2B",
-"Symbol",
-"Courier2B",
-"Courier-Bold2B",
-"ZapfDingbats"
-};
-
-void Fl_PostScript_Graphics_Driver::font(int f, int s) {
- Fl_Graphics_Driver& driver = Fl_Graphics_Driver::default_driver();
- driver.font(f,s); // Use display fonts for font measurement
- Fl_Graphics_Driver::font(f, s);
- Fl_Font_Descriptor *desc = driver.font_descriptor();
- this->font_descriptor(desc);
- if (f < FL_FREE_FONT) {
- fprintf(output, "/%s SF\n" , _fontNames[f]);
- float ps_size = driver.scale_font_for_PostScript(desc, s);
- clocale_printf("%.1f FS\n", ps_size);
- }
-}
-
-double Fl_PostScript_Graphics_Driver::width(const char *s, int n) {
- return Fl_Graphics_Driver::default_driver().width(s, n);
-}
-
-double Fl_PostScript_Graphics_Driver::width(unsigned u) {
- return Fl_Graphics_Driver::default_driver().width(u);
-}
-
-int Fl_PostScript_Graphics_Driver::height() {
- return Fl_Graphics_Driver::default_driver().height();
-}
-
-int Fl_PostScript_Graphics_Driver::descent() {
- return Fl_Graphics_Driver::default_driver().descent();
-}
-
-void Fl_PostScript_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
- Fl_Graphics_Driver::default_driver().text_extents(c, n, dx, dy, w, h);
-}
-
-
-void Fl_PostScript_Graphics_Driver::color(Fl_Color c) {
- Fl::get_color(c, cr_, cg_, cb_);
- color(cr_, cg_, cb_);
-}
-
void Fl_PostScript_Graphics_Driver::color(unsigned char r, unsigned char g, unsigned char b) {
Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) );
cr_ = r; cg_ = g; cb_ = b;
@@ -1375,67 +1421,530 @@ void Fl_PostScript_Graphics_Driver::pop_clip() {
recover();
}
-int Fl_PostScript_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) {
- if (!clip_) {
- X = x; Y = y; W = w; H = h;
- return 0;
+void Fl_PostScript_Graphics_Driver::ps_origin(int x, int y)
+{
+ clocale_printf("GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n",
+ left_margin, top_margin, scale_x, scale_y, x, y, angle);
+}
+
+void Fl_PostScript_Graphics_Driver::ps_translate(int x, int y)
+{
+ fprintf(output, "GS %d %d translate GS\n", x, y);
+}
+
+void Fl_PostScript_Graphics_Driver::ps_untranslate(void)
+{
+ fprintf(output, "GR GR\n");
+}
+
+# else
+
+/* Cairo-based implementation of the PostScript graphics driver */
+
+static cairo_status_t write_to_cairo_stream(FILE *output, unsigned char *data, unsigned int length) {
+ size_t l = fwrite(data, 1, length, output);
+ return (l == length ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR);
+}
+
+static int init_cairo_postscript(FILE* output, cairo_t* &cairo_, PangoLayout* &pango_layout,
+ int w, int h) {
+ cairo_surface_t* cs = cairo_ps_surface_create_for_stream((cairo_write_func_t)write_to_cairo_stream, output, w, h);
+ if (cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) return 1;
+ cairo_ps_surface_restrict_to_level(cs, CAIRO_PS_LEVEL_2);
+ cairo_ = cairo_create(cs);
+ pango_layout = pango_cairo_create_layout(cairo_);
+ return 0;
+}
+
+int Fl_PostScript_Graphics_Driver::start_postscript(int pagecount,
+ enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout)
+//returns 0 iff OK
+{
+ if (format == Fl_Paged_Device::A4) {
+ left_margin = 18;
+ top_margin = 18;
}
- if (clip_->w < 0) {
- X = x; Y = y; W = w; H = h;
- return 1;
+ else {
+ left_margin = 12;
+ top_margin = 12;
}
- int ret = 0;
- if (x > (X=clip_->x)) {X=x; ret=1;}
- if (y > (Y=clip_->y)) {Y=y; ret=1;}
- if ((x+w) < (clip_->x+clip_->w)) {
- W=x+w-X;
+ page_format_ = (enum Fl_Paged_Device::Page_Format)(format | layout);
+ if (layout & Fl_Paged_Device::LANDSCAPE){
+ ph_ = Fl_Paged_Device::page_formats[format].width;
+ pw_ = Fl_Paged_Device::page_formats[format].height;
+ } else {
+ pw_ = Fl_Paged_Device::page_formats[format].width;
+ ph_ = Fl_Paged_Device::page_formats[format].height;
+ }
+ if (init_cairo_postscript(output, cairo_, pango_layout_, Fl_Paged_Device::page_formats[format].width, Fl_Paged_Device::page_formats[format].height)) return 1;
+ nPages=0;
+ char feature[250];
+ sprintf(feature, "%%%%BeginFeature: *PageSize %s\n<</PageSize[%d %d]>>setpagedevice\n%%%%EndFeature",
+ Fl_Paged_Device::page_formats[format].name, Fl_Paged_Device::page_formats[format].width, Fl_Paged_Device::page_formats[format].height);
+ cairo_ps_surface_dsc_comment(cairo_get_target(cairo_), feature);
+ return 0;
+}
- ret=1;
+int Fl_PostScript_Graphics_Driver::start_eps(int width, int height) {
+ pw_ = width;
+ ph_ = height;
+ if (init_cairo_postscript(output, cairo_, pango_layout_, width, height)) return 1;
+ cairo_ps_surface_set_eps(cairo_get_target(cairo_), true);
+ nPages=0; //useful?
+ return 0;
+}
- }else
- W = clip_->x + clip_->w - X;
- if(W<0){
- W=0;
- return 1;
+void Fl_PostScript_Graphics_Driver::rectf(int x, int y, int w, int h) {
+ cairo_rectangle(cairo_, x, y, w, h);
+ cairo_fill(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::rect(int x, int y, int w, int h) {
+ cairo_rectangle(cairo_, x, y, w, h);
+ cairo_stroke(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::line(int x1, int y1, int x2, int y2) {
+ cairo_new_path(cairo_);
+ cairo_move_to(cairo_, x1, y1);
+ cairo_line_to(cairo_, x2, y2);
+ cairo_stroke(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::line(int x0, int y0, int x1, int y1, int x2, int y2) {
+ cairo_new_path(cairo_);
+ cairo_move_to(cairo_, x0, y0);
+ cairo_line_to(cairo_, x1, y1);
+ cairo_line_to(cairo_, x2, y2);
+ cairo_stroke(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1) {
+ cairo_move_to(cairo_, x, y);
+ cairo_line_to(cairo_, x1, y);
+ cairo_stroke(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
+ cairo_move_to(cairo_, x, y);
+ cairo_line_to(cairo_, x1, y);
+ cairo_line_to(cairo_, x1, y2);
+ cairo_stroke(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
+ cairo_move_to(cairo_, x, y);
+ cairo_line_to(cairo_, x1, y);
+ cairo_line_to(cairo_, x1, y2);
+ cairo_line_to(cairo_, x3, y2);
+ cairo_stroke(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1) {
+ cairo_move_to(cairo_, x, y);
+ cairo_line_to(cairo_, x, y1);
+ cairo_stroke(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
+ cairo_move_to(cairo_, x, y);
+ cairo_line_to(cairo_, x, y1);
+ cairo_line_to(cairo_, x2, y1);
+ cairo_stroke(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
+ cairo_move_to(cairo_, x, y);
+ cairo_line_to(cairo_, x, y1);
+ cairo_line_to(cairo_, x2, y1);
+ cairo_line_to(cairo_, x2, y3);
+ cairo_stroke(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) {
+ cairo_save(cairo_);
+ cairo_new_path(cairo_);
+ cairo_move_to(cairo_, x0, y0);
+ cairo_line_to(cairo_, x1, y1);
+ cairo_line_to(cairo_, x2, y2);
+ cairo_close_path(cairo_);
+ cairo_stroke(cairo_);
+ cairo_restore(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
+ cairo_save(cairo_);
+ cairo_new_path(cairo_);
+ cairo_move_to(cairo_, x0, y0);
+ cairo_line_to(cairo_, x1, y1);
+ cairo_line_to(cairo_, x2, y2);
+ cairo_line_to(cairo_, x3, y3);
+ cairo_close_path(cairo_);
+ cairo_stroke(cairo_);
+ cairo_restore(cairo_);
+
+}
+
+void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) {
+ cairo_save(cairo_);
+ cairo_new_path(cairo_);
+ cairo_move_to(cairo_, x0, y0);
+ cairo_line_to(cairo_, x1, y1);
+ cairo_line_to(cairo_, x2, y2);
+ cairo_close_path(cairo_);
+ cairo_fill(cairo_);
+ cairo_restore(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
+ cairo_save(cairo_);
+ cairo_new_path(cairo_);
+ cairo_move_to(cairo_, x0, y0);
+ cairo_line_to(cairo_, x1, y1);
+ cairo_line_to(cairo_, x2, y2);
+ cairo_line_to(cairo_, x3, y3);
+ cairo_close_path(cairo_);
+ cairo_fill(cairo_);
+ cairo_restore(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::line_style(int style, int width, char* dashes) {
+ linewidth_=width;
+ linestyle_=style;
+ if(dashes){
+ if(dashes != linedash_)
+ strcpy(linedash_,dashes);
+
+ } else
+ linedash_[0]=0;
+ char width0 = 0;
+ if (!width){
+ width=1; //for screen drawing compatibility
+ width0=1;
}
- if ((y+h) < (clip_->y+clip_->h)) {
- H=y+h-Y;
- ret=1;
- }else
- H = clip_->y + clip_->h - Y;
- if(H<0){
- W=0;
- H=0;
- return 1;
+ cairo_set_line_width(cairo_, width);
+
+ if(!style && (!dashes || !(*dashes)) && width0) //system lines
+ style = FL_CAP_SQUARE;
+
+ int cap = (style &0xf00);
+ cairo_line_cap_t c_cap;
+ if (cap == FL_CAP_SQUARE) c_cap = CAIRO_LINE_CAP_SQUARE;
+ else if (cap == FL_CAP_FLAT) c_cap = CAIRO_LINE_CAP_BUTT;
+ else if (cap == FL_CAP_ROUND) c_cap = CAIRO_LINE_CAP_ROUND;
+ else c_cap = CAIRO_LINE_CAP_BUTT;
+ cairo_set_line_cap(cairo_, c_cap);
+
+ int join = (style & 0xf000);
+ cairo_line_join_t c_join;
+ if (join == FL_JOIN_MITER) c_join = CAIRO_LINE_JOIN_MITER;
+ else if (join == FL_JOIN_ROUND)c_join = CAIRO_LINE_JOIN_ROUND;
+ else if (join == FL_JOIN_BEVEL) c_join = CAIRO_LINE_JOIN_BEVEL;
+ else c_join = CAIRO_LINE_JOIN_MITER;
+ cairo_set_line_join(cairo_, c_join);
+
+ double *ddashes = NULL;
+ int l = 0;
+ if (dashes && *dashes){
+ ddashes = new double[strlen(dashes)];
+ while (dashes[l]) {ddashes[l] = dashes[l]; l++; }
+ } else if (style & 0xff) {
+ ddashes = new double[6];
+ if (style & 0x200){ // round and square caps, dash length need to be adjusted
+ const double *dt = dashes_cap[style & 0xff];
+ while (*dt >= 0){
+ ddashes[l++] = width * (*dt);
+ dt++;
+ }
+ } else {
+ const int *ds = dashes_flat[style & 0xff];
+ while (*ds >= 0){
+ ddashes[l++] = width * (*ds);
+ ds++;
+ }
+ }
}
- return ret;
+ cairo_set_dash(cairo_, ddashes, l, 0);
+ delete[] ddashes;
+ check_status();
}
-int Fl_PostScript_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
- if (!clip_) return 1;
- if (clip_->w < 0) return 1;
- int X = 0, Y = 0, W = 0, H = 0;
- clip_box(x, y, w, h, X, Y, W, H);
- if (W) return 1;
- return 0;
+void Fl_PostScript_Graphics_Driver::color(unsigned char r, unsigned char g, unsigned char b) {
+ Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) );
+ cr_ = r; cg_ = g; cb_ = b;
+ double fr, fg, fb;
+ fr = r/255.0;
+ fg = g/255.0;
+ fb = b/255.0;
+ cairo_set_source_rgb(cairo_, fr, fg, fb);
+ check_status();
}
-void Fl_PostScript_Graphics_Driver::ps_origin(int x, int y)
+void Fl_PostScript_Graphics_Driver::draw(int rotation, const char *str, int n, int x, int y)
{
- clocale_printf("GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n",
- left_margin, top_margin, scale_x, scale_y, x, y, angle);
+ cairo_save(cairo_);
+ cairo_translate(cairo_, x, y);
+ cairo_rotate(cairo_, -rotation * M_PI / 180);
+ this->transformed_draw(str, n, 0, 0);
+ cairo_restore(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) {
+ if (!n) return;
+ pango_layout_set_font_description(pango_layout_, Fl_Xlib_Graphics_Driver::pango_font_description(Fl_Graphics_Driver::font()));
+ int pwidth, pheight;
+ cairo_save(cairo_);
+ pango_layout_set_text(pango_layout_, str, n);
+ pango_layout_get_size(pango_layout_, &pwidth, &pheight);
+ if (pwidth > 0) {
+ double s = width(str, n);
+ cairo_translate(cairo_, x, y - height() + descent());
+ s = (s/pwidth) * PANGO_SCALE;
+ cairo_scale(cairo_, s, s);
+ pango_cairo_show_layout(cairo_, pango_layout_);
+ }
+ cairo_restore(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) {
+ int w = (int)width(str, n);
+ transformed_draw(str, n, x - w, y);
+}
+
+void Fl_PostScript_Graphics_Driver::concat(){
+ cairo_matrix_t mat = {fl_matrix->a , fl_matrix->b , fl_matrix->c , fl_matrix->d , fl_matrix->x , fl_matrix->y};
+ cairo_transform(cairo_, &mat);
+}
+
+void Fl_PostScript_Graphics_Driver::reconcat(){
+ cairo_matrix_t mat = {fl_matrix->a , fl_matrix->b , fl_matrix->c , fl_matrix->d , fl_matrix->x , fl_matrix->y};
+ cairo_status_t stat = cairo_matrix_invert(&mat);
+ if (stat != CAIRO_STATUS_SUCCESS) {
+ fputs("error in cairo_matrix_invert\n", stderr);
+ }
+ cairo_transform(cairo_, &mat);
+}
+
+void Fl_PostScript_Graphics_Driver::begin_points() {
+ cairo_save(cairo_);
+ concat();
+ cairo_new_path(cairo_);
+ gap_=1;
+ shape_=POINTS;
+}
+
+void Fl_PostScript_Graphics_Driver::begin_line() {
+ cairo_save(cairo_);
+ concat();
+ cairo_new_path(cairo_);
+ gap_=1;
+ shape_=LINE;
+}
+
+void Fl_PostScript_Graphics_Driver::begin_loop() {
+ cairo_save(cairo_);
+ concat();
+ cairo_new_path(cairo_);
+ gap_=1;
+ shape_=LOOP;
+}
+
+void Fl_PostScript_Graphics_Driver::begin_polygon() {
+ cairo_save(cairo_);
+ concat();
+ cairo_new_path(cairo_);
+ gap_=1;
+ shape_=POLYGON;
+}
+
+void Fl_PostScript_Graphics_Driver::vertex(double x, double y) {
+ if(shape_==POINTS){
+ cairo_move_to(cairo_, x, y);
+ gap_=1;
+ return;
+ }
+ if(gap_){
+ cairo_move_to(cairo_, x, y);
+ gap_=0;
+ }else
+ cairo_line_to(cairo_, x, y);
+}
+
+void Fl_PostScript_Graphics_Driver::curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3)
+{
+ if(shape_==NONE) return;
+ if(gap_)
+ cairo_move_to(cairo_, x, y);
+ else
+ cairo_line_to(cairo_, x, y);
+ gap_=0;
+ cairo_curve_to(cairo_, x1 , y1 , x2 , y2 , x3 , y3);
+}
+
+void Fl_PostScript_Graphics_Driver::circle(double x, double y, double r){
+ if (shape_==NONE){
+ cairo_save(cairo_);
+ concat();
+ cairo_arc(cairo_, x, y, r, 0, 2*M_PI);
+ reconcat();
+ cairo_restore(cairo_);
+ } else
+ cairo_arc(cairo_, x, y, r, 0, 2*M_PI);
+}
+
+void Fl_PostScript_Graphics_Driver::arc(double x, double y, double r, double start, double a){
+ if (shape_==NONE) return;
+ gap_ = 0;
+ if(start > a)
+ cairo_arc(cairo_, x, y, r, -start*M_PI/180, -a*M_PI/180);
+ else
+ cairo_arc_negative(cairo_, x, y, r, -start*M_PI/180, -a*M_PI/180);
+}
+
+void Fl_PostScript_Graphics_Driver::arc(int x, int y, int w, int h, double a1, double a2) {
+ if (w <= 1 || h <= 1) return;
+ cairo_save(cairo_);
+ begin_line();
+ cairo_translate(cairo_, x + w/2.0 -0.5 , y + h/2.0 - 0.5);
+ cairo_scale(cairo_, (w-1)/2.0 , (h-1)/2.0);
+ arc(0,0,1,a2,a1);
+ cairo_scale(cairo_, 2.0/(w-1) , 2.0/(h-1));
+ cairo_translate(cairo_, -x - w/2.0 +0.5 , -y - h/2.0 +0.5);
+ end_line();
+ cairo_restore(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::pie(int x, int y, int w, int h, double a1, double a2) {
+ cairo_save(cairo_);
+ begin_polygon();
+ cairo_translate(cairo_, x + w/2.0 -0.5 , y + h/2.0 - 0.5);
+ cairo_scale(cairo_, (w-1)/2.0 , (h-1)/2.0);
+ vertex(0,0);
+ arc(0.0,0.0, 1, a2, a1);
+ end_polygon();
+ cairo_restore(cairo_);
+}
+
+void Fl_PostScript_Graphics_Driver::end_points() {
+ end_line();
+}
+
+void Fl_PostScript_Graphics_Driver::end_line() {
+ gap_=1;
+ reconcat();
+ cairo_stroke(cairo_);
+ cairo_restore(cairo_);
+ shape_=NONE;
+}
+
+void Fl_PostScript_Graphics_Driver::end_loop(){
+ gap_=1;
+ reconcat();
+ cairo_close_path(cairo_);
+ cairo_stroke(cairo_);
+ cairo_restore(cairo_);
+ shape_=NONE;
+}
+
+void Fl_PostScript_Graphics_Driver::end_polygon() {
+ gap_=1;
+ reconcat();
+ cairo_close_path(cairo_);
+ cairo_fill(cairo_);
+ cairo_restore(cairo_);
+ shape_=NONE;
+}
+
+void Fl_PostScript_Graphics_Driver::transformed_vertex(double x, double y) {
+ reconcat();
+ if(gap_){
+ cairo_move_to(cairo_, x, y);
+ gap_=0;
+ }else
+ cairo_line_to(cairo_, x, y);
+ concat();
+}
+
+void Fl_PostScript_Graphics_Driver::push_clip(int x, int y, int w, int h) {
+ Clip * c=new Clip();
+ clip_box(x,y,w,h,c->x,c->y,c->w,c->h);
+ c->prev=clip_;
+ clip_=c;
+ cairo_save(cairo_);
+ cairo_rectangle(cairo_, clip_->x-0.5 , clip_->y-0.5 , clip_->w , clip_->h);
+ cairo_clip(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::push_no_clip() {
+ Clip * c = new Clip();
+ c->prev=clip_;
+ clip_=c;
+ clip_->x = clip_->y = clip_->w = clip_->h = -1;
+ cairo_save(cairo_);
+ cairo_reset_clip(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::pop_clip() {
+ if(!clip_)return;
+ Clip * c=clip_;
+ clip_=clip_->prev;
+ delete c;
+ cairo_restore(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::ps_origin(int x, int y) {
+ cairo_restore(cairo_);
+ cairo_restore(cairo_);
+ cairo_save(cairo_);
+ cairo_scale(cairo_, scale_x, scale_y);
+ cairo_translate(cairo_, x, y);
+ cairo_rotate(cairo_, angle * M_PI / 180);
+ cairo_save(cairo_);
+ check_status();
}
void Fl_PostScript_Graphics_Driver::ps_translate(int x, int y)
{
- fprintf(output, "GS %d %d translate GS\n", x, y);
+ cairo_save(cairo_);
+ cairo_translate(cairo_, x, y);
+ cairo_save(cairo_);
+ check_status();
}
void Fl_PostScript_Graphics_Driver::ps_untranslate(void)
{
- fprintf(output, "GR GR\n");
+ cairo_restore(cairo_);
+ cairo_restore(cairo_);
+ check_status();
+}
+
+void Fl_PostScript_Graphics_Driver::check_status(void) {
+#ifdef DEBUG
+ if (cairo_status(cairo_) != CAIRO_STATUS_SUCCESS) {
+ fprintf(stderr,"we have a problem");
+ }
+#endif
}
+#endif // USE_PANGO
+
+/**
+\}
+\endcond
+*/
+
void Fl_PostScript_File_Device::margins(int *left, int *top, int *right, int *bottom) // to implement
{
Fl_PostScript_Graphics_Driver *ps = driver();
@@ -1472,16 +1981,35 @@ void Fl_PostScript_File_Device::scale (float s_x, float s_y)
Fl_PostScript_Graphics_Driver *ps = driver();
ps->scale_x = s_x;
ps->scale_y = s_y;
+#if USE_PANGO
+ cairo_restore(ps->cr());
+ cairo_restore(ps->cr());
+ cairo_save(ps->cr());
+ cairo_scale(ps->cr(), s_x, s_y);
+ cairo_rotate(ps->cr(), ps->angle * M_PI / 180);
+ cairo_save(ps->cr());
+#else
ps->clocale_printf("GR GR GS %d %d TR %f %f SC %f rotate GS\n",
ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, ps->angle);
+#endif
}
void Fl_PostScript_File_Device::rotate (float rot_angle)
{
Fl_PostScript_Graphics_Driver *ps = driver();
ps->angle = - rot_angle;
+#if USE_PANGO
+ cairo_restore(ps->cr());
+ cairo_restore(ps->cr());
+ cairo_save(ps->cr());
+ cairo_scale(ps->cr(), ps->scale_x, ps->scale_y);
+ cairo_translate(ps->cr(), x_offset, y_offset);
+ cairo_rotate(ps->cr(), ps->angle * M_PI / 180);
+ cairo_save(ps->cr());
+#else
ps->clocale_printf("GR GR GS %d %d TR %f %f SC %d %d TR %f rotate GS\n",
ps->left_margin, ps->top_margin, ps->scale_x, ps->scale_y, x_offset, y_offset, ps->angle);
+#endif
}
void Fl_PostScript_File_Device::translate(int x, int y)
@@ -1497,17 +2025,45 @@ void Fl_PostScript_File_Device::untranslate(void)
int Fl_PostScript_File_Device::begin_page (void)
{
Fl_PostScript_Graphics_Driver *ps = driver();
+#if USE_PANGO
+ cairo_ps_surface_dsc_begin_page_setup(cairo_get_target(ps->cr()));
+ char feature[200];
+ sprintf(feature, "%%%%PageOrientation: %s", ps->pw_ > ps->ph_ ? "Landscape" : "Portrait");
+ cairo_ps_surface_dsc_comment(cairo_get_target(ps->cr()), feature);
+ if (ps->pw_ > ps->ph_) {
+ cairo_translate(ps->cr(), 0, ps->pw_);
+ cairo_rotate(ps->cr(), -M_PI/2);
+ }
+ cairo_translate(ps->cr(), ps->left_margin, ps->top_margin);
+ cairo_set_line_width(ps->cr(), 1);
+ cairo_set_source_rgb(ps->cr(), 1.0, 1.0, 1.0); // white background
+ cairo_save(ps->cr());
+ cairo_save(ps->cr());
+ cairo_save(ps->cr());
+ ps->check_status();
+#else
ps->page(ps->page_format_);
+#endif
x_offset = 0;
y_offset = 0;
ps->scale_x = ps->scale_y = 1.;
ps->angle = 0;
+#if ! USE_PANGO
fprintf(ps->output, "GR GR GS %d %d translate GS\n", ps->left_margin, ps->top_margin);
+#endif
return 0;
}
int Fl_PostScript_File_Device::end_page (void)
{
+#if USE_PANGO
+ Fl_PostScript_Graphics_Driver *ps = (Fl_PostScript_Graphics_Driver*)driver();
+ cairo_restore(ps->cr());
+ cairo_restore(ps->cr());
+ cairo_restore(ps->cr());
+ cairo_show_page(ps->cr());
+ ps->check_status();
+#endif
return 0;
}
@@ -1515,6 +2071,20 @@ void Fl_PostScript_File_Device::end_job (void)
// finishes PostScript & closes file
{
Fl_PostScript_Graphics_Driver *ps = driver();
+ int error = 0;
+#if USE_PANGO
+ cairo_surface_t *s = cairo_get_target(ps->cr());
+ cairo_surface_finish(s);
+ error = cairo_surface_status(s);
+ if (error) {
+ fclose(ps->output);
+ fputs("\n", ps->output); // creates an stdio error
+ }
+ cairo_destroy(ps->cr());
+ cairo_surface_destroy(s);
+ g_object_unref(ps->pango_layout());
+ if (!error) error = fflush(ps->output);
+#else
if (ps->nPages) { // for eps nPages is 0 so it is fine ....
fprintf(ps->output, "CR\nGR\nGR\nGR\nSP\n restore\n");
if (!ps->pages_){
@@ -1524,81 +2094,103 @@ void Fl_PostScript_File_Device::end_job (void)
} else
fprintf(ps->output, "GR\n restore\n");
fputs("%%EOF",ps->output);
- ps->reset();
fflush(ps->output);
- if(ferror(ps->output)) {
- fl_alert ("Error during PostScript data output.");
- }
- if (ps->close_cmd_) {
- (*ps->close_cmd_)(ps->output);
- } else {
- fclose(ps->output);
- }
+ error = ferror(ps->output);
+ ps->reset();
+#endif
while (ps->clip_){
Fl_PostScript_Graphics_Driver::Clip * c= ps->clip_;
ps->clip_= ps->clip_->prev;
delete c;
}
- Fl_Display_Device::display_device()->set_current();
+ Fl_Surface_Device::pop_current();
+ int err2 = (ps->close_cmd_ ? (ps->close_cmd_)(ps->output) : fclose(ps->output) );
+ if (!error) error = err2;
+ if (error && ps->close_cmd_ == NULL) {
+ fl_alert ("Error during PostScript data output.");
+ }
}
-/**
-\}
-\endcond
-*/
-
-Fl_EPS_File_Surface::Fl_EPS_File_Surface(int width, int height, FILE *eps, Fl_Color background) :
+Fl_EPS_File_Surface::Fl_EPS_File_Surface(int width, int height, FILE *eps, Fl_Color background, Fl_PostScript_Close_Command closef) :
Fl_Widget_Surface(new Fl_PostScript_Graphics_Driver()) {
Fl_PostScript_Graphics_Driver *ps = driver();
ps->output = eps;
+ ps->close_cmd_ = closef;
if (ps->output) {
float s = Fl::screen_scale(0);
ps->start_eps(width*s, height*s);
+#if USE_PANGO
+ cairo_save(ps->cr());
+ ps->left_margin = ps->top_margin = 0;
+ cairo_scale(ps->cr(), s, s);
+ cairo_set_line_width(ps->cr(), 1);
+ cairo_set_source_rgb(ps->cr(), 1.0, 1.0, 1.0); // white background
+ cairo_save(ps->cr());
+ cairo_save(ps->cr());
+ ps->check_status();
+#else
if (s != 1) {
ps->clocale_printf("GR GR GS %f %f SC GS\n", s, s);
- ps->scale_x = ps->scale_y = s;
}
+#endif
+ ps->scale_x = ps->scale_y = s;
Fl::get_color(background, ps->bg_r, ps->bg_g, ps->bg_b);
}
}
-void Fl_EPS_File_Surface::complete_() {
+int Fl_EPS_File_Surface::close() {
+ int error = 0;
Fl_PostScript_Graphics_Driver *ps = driver();
+#if USE_PANGO
+ cairo_surface_t *s = cairo_get_target(ps->cr());
+ cairo_surface_finish(s);
+ cairo_status_t status = cairo_surface_status(s);
+ cairo_destroy(ps->cr());
+ cairo_surface_destroy(s);
+ g_object_unref(ps->pango_layout());
+ fflush(ps->output);
+ error = ferror(ps->output);
+ if (status != CAIRO_STATUS_SUCCESS) error = status;
+#else
if(ps->output) {
fputs("GR\nend %matches begin of FLTK dict\n", ps->output);
fputs("restore\n", ps->output);
fputs("%%EOF\n", ps->output);
ps->reset();
fflush(ps->output);
- if(ferror(ps->output)) {
- fl_alert ("Error during PostScript data output.");
- }
+ error = ferror(ps->output);
}
+#endif
+ int err2 = (ps->close_cmd_ ? (ps->close_cmd_)(ps->output) : fclose(ps->output));
+ if (err2) error = err2;
while (ps->clip_){
Fl_PostScript_Graphics_Driver::Clip * c= ps->clip_;
ps->clip_= ps->clip_->prev;
delete c;
}
+ ps->output = NULL;
+ return error;
}
Fl_EPS_File_Surface::~Fl_EPS_File_Surface() {
- Fl_PostScript_Graphics_Driver *ps = driver();
- if(ps->output) complete_();
- delete ps;
+ if (driver()->output) {
+ if ( close() ) {
+ fl_open_display();
+ fl_alert ("Error during encapsulated PostScript data output.");
+ }
+ }
+ delete driver();
}
-int Fl_EPS_File_Surface::close() {
- complete_();
+FILE *Fl_EPS_File_Surface::file() {
Fl_PostScript_Graphics_Driver *ps = driver();
- int retval = fclose(ps->output);
- ps->output = NULL;
- return retval;
+ return ps ? ps->output : NULL;
}
int Fl_EPS_File_Surface::printable_rect(int *w, int *h) {
Fl_PostScript_Graphics_Driver *ps = driver();
- *w = ps->width_;
- *h = ps->height_;
+ *w = int(ps->pw_);
+ *h = int(ps->ph_);
return 0;
}
diff --git a/src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H b/src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H
new file mode 100644
index 000000000..6491872bc
--- /dev/null
+++ b/src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H
@@ -0,0 +1,231 @@
+//
+// Support for graphics output to PostScript file for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2010-2020 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+/** \file Fl_Pango_PostScript_Graphics_Driver.H
+ Declaration of class Fl_PostScript_Graphics_Driver.
+*/
+
+#ifndef FL_POSTSCRIPT_GRAPHICS_DRIVER_H
+#define FL_POSTSCRIPT_GRAPHICS_DRIVER_H
+
+#include "../../config_lib.h"
+#include <FL/Fl_PostScript.H>
+
+#ifndef USE_PANGO
+#define USE_PANGO 0
+#endif
+
+#if USE_PANGO
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo cairo_t;
+typedef struct _PangoLayout PangoLayout;
+#endif
+
+/**
+ \cond DriverDev
+ \addtogroup DriverDeveloper
+ \{
+ */
+
+/**
+ PostScript graphical backend.
+ */
+
+class FL_EXPORT Fl_PostScript_Graphics_Driver : public Fl_Graphics_Driver {
+private:
+#if USE_PANGO
+ cairo_t *cairo_;
+ PangoLayout *pango_layout_;
+ void draw_rgb_bitmap_(Fl_Image *img,int XP, int YP, int WP, int HP, int cx, int cy);
+#else
+ void transformed_draw_extra(const char* str, int n, double x, double y, int w, bool rtl);
+ void *prepare_rle85();
+ void write_rle85(uchar b, void *data);
+ void close_rle85(void *data);
+ void *prepare85();
+ void write85(void *data, const uchar *p, int len);
+ void close85(void *data);
+ int scale_for_image_(Fl_Image *img, int XP, int YP, int WP, int HP,int cx, int cy);
+#endif
+protected:
+ uchar **mask_bitmap() {return &mask;}
+public:
+ Fl_PostScript_Graphics_Driver();
+#ifndef FL_DOXYGEN
+ enum SHAPE{NONE=0, LINE, LOOP, POLYGON, POINTS};
+
+ class Clip {
+ public:
+ int x, y, w, h;
+ Clip *prev;
+ };
+ Clip * clip_;
+
+ int lang_level_;
+ int gap_;
+ int pages_;
+
+ int shape_;
+ int linewidth_;// need for clipping, lang level 1-2
+ int linestyle_;//
+ int interpolate_; //interpolation of images
+ unsigned char cr_,cg_,cb_;
+ char linedash_[256];//should be enough
+ void concat(); // transform ror scalable dradings...
+ void reconcat(); //invert
+ void recover(); //recovers the state after grestore (such as line styles...)
+ void reset();
+
+ uchar * mask;
+ int mx; // width of mask;
+ int my; // mask lines
+ Fl_PostScript_Close_Command close_cmd_;
+ int page_policy_;
+ int nPages;
+ int orientation_;
+
+ float scale_x;
+ float scale_y;
+ float angle;
+ int left_margin;
+ int top_margin;
+
+ FILE *output;
+ double pw_, ph_;
+
+ uchar bg_r, bg_g, bg_b;
+ int start_postscript (int pagecount, enum Fl_Paged_Device::Page_Format format, enum Fl_Paged_Device::Page_Layout layout);
+ int start_eps(int width, int height);
+ /* int alpha_mask(const uchar * data, int w, int h, int D, int LD=0);
+ */
+ void transformed_draw(const char* s, int n, double x, double y); //precise text placing
+ void transformed_draw(const char* s, double x, double y);
+ int alpha_mask(const uchar * data, int w, int h, int D, int LD=0);
+
+ enum Fl_Paged_Device::Page_Format page_format_;
+ char *ps_filename_;
+
+ void page_policy(int p);
+ int page_policy(){return page_policy_;};
+ void close_command(Fl_PostScript_Close_Command cmd){close_cmd_=cmd;};
+ FILE * file() {return output;};
+ //void orientation (int o);
+ //Fl_PostScript_Graphics_Driver(FILE *o, int lang_level, int pages = 0); // ps (also multi-page) constructor
+ void interpolate(int i){interpolate_=i;};
+ int interpolate(){return interpolate_;}
+
+ void page(double pw, double ph, int media = 0);
+ void page(int format);
+#endif // FL_DOXYGEN
+
+ // implementation of drawing methods
+ void color(Fl_Color c);
+ void color(uchar r, uchar g, uchar b);
+
+ void push_clip(int x, int y, int w, int h);
+ int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H);
+ int not_clipped(int x, int y, int w, int h);
+ void push_no_clip();
+ void pop_clip();
+
+ void line_style(int style, int width=0, char* dashes=0);
+
+ void rect(int x, int y, int w, int h);
+ void rectf(int x, int y, int w, int h);
+
+ void xyline(int x, int y, int x1);
+ void xyline(int x, int y, int x1, int y2);
+ void xyline(int x, int y, int x1, int y2, int x3);
+
+ void yxline(int x, int y, int y1);
+ void yxline(int x, int y, int y1, int x2);
+ void yxline(int x, int y, int y1, int x2, int y3);
+
+ void line(int x1, int y1, int x2, int y2);
+ void line(int x1, int y1, int x2, int y2, int x3, int y3);
+
+ void loop(int x0, int y0, int x1, int y1, int x2, int y2);
+ void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
+ void polygon(int x0, int y0, int x1, int y1, int x2, int y2);
+ void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
+ void point(int x, int y);
+
+ void begin_points();
+ void begin_line();
+ void begin_loop();
+ void begin_polygon();
+ void vertex(double x, double y);
+ void curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3);
+ void circle(double x, double y, double r);
+ void arc(double x, double y, double r, double start, double a);
+ void arc(int x, int y, int w, int h, double a1, double a2);
+ void pie(int x, int y, int w, int h, double a1, double a2);
+ void end_points();
+ void end_line();
+ void end_loop();
+ void end_polygon();
+ void begin_complex_polygon(){begin_polygon();};
+ void gap(){gap_=1;};
+ void end_complex_polygon(){end_polygon();};
+ void transformed_vertex(double x, double y);
+
+ void draw_image(const uchar* d, int x,int y,int w,int h, int delta=3, int ldelta=0);
+ void draw_image_mono(const uchar* d, int x,int y,int w,int h, int delta=1, int ld=0);
+ void draw_image(Fl_Draw_Image_Cb call, void* data, int x,int y, int w, int h, int delta=3);
+ void draw_image_mono(Fl_Draw_Image_Cb call, void* data, int x,int y, int w, int h, int delta=1);
+
+ void draw(const char* s, int nBytes, int x, int y) {transformed_draw(s,nBytes,x,y); };
+ void draw(const char* s, int nBytes, float x, float y) {transformed_draw(s,nBytes,x,y); };
+ void draw(int angle, const char *str, int n, int x, int y);
+ void rtl_draw(const char* s, int n, int x, int y);
+ void font(int face, int size);
+ double width(const char *, int);
+ double width(unsigned int u);
+ void text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h);
+ int height();
+ int descent();
+ void draw_pixmap(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy);
+ void draw_bitmap(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy);
+ void draw_rgb(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy);
+#if USE_PANGO
+ cairo_t *cr() { return cairo_; }
+ PangoLayout *pango_layout() {return pango_layout_;};
+ void check_status(void);
+#else
+ /** Shields output PostScript data from modifications of the current locale.
+ It typically avoids PostScript errors caused if the current locale uses comma instead of dot
+ as "decimal point".
+ \param format directives controlling output PostScript data
+ \return value returned by vfprintf() call
+ */
+ int clocale_printf(const char *format, ...);
+#endif
+ ~Fl_PostScript_Graphics_Driver();
+ // ---
+ Fl_Bitmask create_bitmask(int w, int h, const uchar *array) { return 0L; }
+ virtual int has_feature(driver_feature feature_mask) { return feature_mask & PRINTER; }
+
+ void ps_origin(int x, int y);
+ void ps_translate(int, int);
+ void ps_untranslate();
+};
+
+/**
+\}
+\endcond
+*/
+
+#endif // FL_POSTSCRIPT_GRAPHICS_DRIVER_H
diff --git a/src/drivers/PostScript/Fl_PostScript_image.cxx b/src/drivers/PostScript/Fl_PostScript_image.cxx
index 43f9b36c2..5c1f1d1f7 100644
--- a/src/drivers/PostScript/Fl_PostScript_image.cxx
+++ b/src/drivers/PostScript/Fl_PostScript_image.cxx
@@ -1,7 +1,7 @@
//
// Postscript image drawing implementation for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2015 by Bill Spitzak and others.
+// Copyright 1998-2020 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -22,10 +22,48 @@
#include <string.h>
#include <FL/Fl_PostScript.H>
+#include "Fl_PostScript_Graphics_Driver.H"
#include <FL/Fl.H>
#include <FL/Fl_Pixmap.H>
#include <FL/Fl_Bitmap.H>
+#if USE_PANGO
+#include <cairo/cairo.h>
+#endif
+
+struct callback_data {
+ const uchar *data;
+ int D, LD;
+};
+
+static void draw_image_cb(void *data, int x, int y, int w, uchar *buf) {
+ struct callback_data *cb_data;
+ const uchar *curdata;
+
+ cb_data = (struct callback_data*)data;
+ curdata = cb_data->data + x*cb_data->D + y*cb_data->LD;
+
+ memcpy(buf, curdata, w*cb_data->D);
+}
+
+void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
+ if (D<3){ //mono
+ draw_image_mono(data, ix, iy, iw, ih, D, LD);
+ return;
+ }
+
+ struct callback_data cb_data;
+
+ if (!LD) LD = iw*D;
+
+ cb_data.data = data;
+ cb_data.D = D;
+ cb_data.LD = LD;
+
+ draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, D);
+}
+
+#if ! USE_PANGO
//
// Implementation of the /ASCII85Encode PostScript filter
@@ -345,41 +383,6 @@ static inline uchar swap_byte(const uchar b) {
return (swapped[b & 0xF] << 4) | swapped[b >> 4];
}
-
-struct callback_data {
- const uchar *data;
- int D, LD;
-};
-
-
-static void draw_image_cb(void *data, int x, int y, int w, uchar *buf) {
- struct callback_data *cb_data;
- const uchar *curdata;
-
- cb_data = (struct callback_data*)data;
- curdata = cb_data->data + x*cb_data->D + y*cb_data->LD;
-
- memcpy(buf, curdata, w*cb_data->D);
-}
-
-
-void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
- if (D<3){ //mono
- draw_image_mono(data, ix, iy, iw, ih, D, LD);
- return;
- }
-
- struct callback_data cb_data;
-
- if (!LD) LD = iw*D;
-
- cb_data.data = data;
- cb_data.D = D;
- cb_data.LD = LD;
-
- draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, D);
-}
-
void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) {
double x = ix, y = iy, w = iw, h = ih;
@@ -628,4 +631,144 @@ int Fl_PostScript_Graphics_Driver::scale_for_image_(Fl_Image *img, int XP, int Y
return 0;
}
+#else
+
+void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D)
+{
+ uchar *array = new uchar[iw * D * ih];
+ for (int l = 0; l < ih; l++) {
+ call(data, 0, l, iw, array + l*D*iw);
+ if (D%2 == 0) for (int i = 0; i < iw; i++) {
+ *(array + l*D*iw + i*D + D-1) = 0xff;
+ }
+ }
+ Fl_RGB_Image *rgb = new Fl_RGB_Image(array, iw, ih, D);
+ rgb->alloc_array = 1;
+ draw_rgb(rgb, ix, iy, iw, ih, 0, 0);
+ delete rgb;
+}
+
+void Fl_PostScript_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD)
+{
+ struct callback_data cb_data;
+ if (!LD) LD = iw*D;
+ cb_data.data = data;
+ cb_data.D = D;
+ cb_data.LD = LD;
+ draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, D);
+}
+
+void Fl_PostScript_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D)
+{
+ draw_image(call, data, ix, iy, iw, ih, D);
+}
+
+static void destroy_BGRA(void *data) {
+ delete[] (uchar*)data;
+}
+
+void Fl_PostScript_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm,int XP, int YP, int WP, int HP, int cx, int cy) {
+ Fl_RGB_Image *rgb = new Fl_RGB_Image(pxm);
+ draw_rgb_bitmap_(rgb, XP, YP, WP, HP, cx, cy);
+ delete rgb;
+}
+
+void Fl_PostScript_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy) {
+ draw_rgb_bitmap_(rgb, XP, YP, WP, HP, cx, cy);
+}
+
+void Fl_PostScript_Graphics_Driver::draw_bitmap(Fl_Bitmap *bitmap,int XP, int YP, int WP, int HP, int cx, int cy) {
+ draw_rgb_bitmap_(bitmap, XP, YP, WP, HP, cx, cy);
+}
+
+void Fl_PostScript_Graphics_Driver::draw_rgb_bitmap_(Fl_Image *img,int XP, int YP, int WP, int HP, int cx, int cy)
+{
+ cairo_surface_t *surf;
+ cairo_format_t format = (img->d() >= 1 ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A1);
+ int stride = cairo_format_stride_for_width(format, img->data_w());
+ uchar *BGRA = new uchar[stride * img->data_h()];
+ memset(BGRA, 0, stride * img->data_h());
+ if (img->d() >= 1) { // process Fl_RGB_Image of all depths
+ Fl_RGB_Image *rgb = (Fl_RGB_Image*)img;
+ int lrgb = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d();
+ uchar A = 0xff, R,G,B, *q;
+ const uchar *r;
+ float f = 1;
+ if (rgb->d() >= 3) { // color images
+ for (int j = 0; j < rgb->data_h(); j++) {
+ r = rgb->array + j * lrgb;
+ q = BGRA + j * stride;
+ for (int i = 0; i < rgb->data_w(); i++) {
+ R = *r;
+ G = *(r+1);
+ B = *(r+2);
+ if (rgb->d() == 4) {
+ A = *(r+3);
+ f = float(A)/0xff;
+ }
+ *q = B * f;
+ *(q+1) = G * f;
+ *(q+2) = R * f;
+ *(q+3) = A;
+ r += rgb->d(); q += 4;
+ }
+ }
+ } else if (rgb->d() == 1 || rgb->d() == 2) { // B&W
+ for (int j = 0; j < rgb->data_h(); j++) {
+ r = rgb->array + j * lrgb;
+ q = BGRA + j * stride;
+ for (int i = 0; i < rgb->data_w(); i++) {
+ G = *r;
+ if (rgb->d() == 2) {
+ A = *(r+1);
+ f = float(A)/0xff;
+ }
+ *(q) = G * f;
+ *(q+1) = G * f;
+ *(q+2) = G * f;
+ *(q+3) = A;
+ r += rgb->d(); q += 4;
+ }
+ }
+ }
+ } else {
+ Fl_Bitmap *bm = (Fl_Bitmap*)img;
+ uchar *r, p;
+ unsigned *q;
+ for (int j = 0; j < bm->data_h(); j++) {
+ r = (uchar*)bm->array + j * ((bm->data_w() + 7)/8);
+ q = (unsigned*)(BGRA + j * stride);
+ unsigned k = 0, mask32 = 1;
+ p = *r;
+ for (int i = 0; i < bm->data_w(); i++) {
+ if (p&1) (*q) |= mask32;
+ k++;
+ if (k % 8 != 0) p >>= 1; else p = *(++r);
+ if (k % 32 != 0) mask32 <<= 1; else {q++; mask32 = 1;}
+ }
+ }
+ }
+ surf = cairo_image_surface_create_for_data(BGRA, format, img->data_w(), img->data_h(), stride);
+ if (cairo_surface_status(surf) == CAIRO_STATUS_SUCCESS) {
+ static cairo_user_data_key_t key = {};
+ (void)cairo_surface_set_user_data(surf, &key, BGRA, destroy_BGRA);
+ cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf);
+ cairo_save(cairo_);
+ cairo_rectangle(cairo_, XP-0.5, YP-0.5, WP+1, HP+1);
+ cairo_clip(cairo_); // still to be tested
+ if (img->d() >= 1) cairo_set_source(cairo_, pat);
+ cairo_matrix_t matrix;
+ cairo_matrix_init_scale(&matrix, double(img->data_w())/img->w(), double(img->data_h())/img->h());
+ cairo_matrix_translate(&matrix, -XP+cx, -YP+cy);
+ cairo_pattern_set_matrix(pat, &matrix);
+ cairo_mask(cairo_, pat);
+ cairo_pattern_destroy(pat);
+ cairo_surface_destroy(surf);
+ cairo_restore(cairo_);
+ check_status();
+ }
+}
+
+#endif // USE_PANGO
+
#endif // !defined(FL_DOXYGEN) && !defined(FL_NO_PRINT_SUPPORT)
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H
index 322b45c68..4f1906d59 100644
--- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H
@@ -1,7 +1,7 @@
//
// Definition of class Fl_Xlib_Graphics_Driver for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2010-2018 by Bill Spitzak and others.
+// Copyright 2010-2020 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -82,6 +82,9 @@ protected:
static PangoContext *pctxt_;
static PangoFontMap *pfmap_;
static PangoLayout *playout_;
+public:
+ static PangoFontDescription* pango_font_description(Fl_Font fnum) { return pfd_array[fnum]; }
+private:
static PangoFontDescription **pfd_array; // one array element for each Fl_Font
static int pfd_array_length;
void do_draw(int from_right, const char *str, int n, int x, int y);
diff --git a/test/device.cxx b/test/device.cxx
index 154bdb844..8b04e53d2 100644
--- a/test/device.cxx
+++ b/test/device.cxx
@@ -617,7 +617,12 @@ void copy(Fl_Widget *, void *data) {
}
if (!err) {
p->begin_page();
- if (target->as_window()) p->print_window(target->as_window());
+ if (target->as_window()) {
+ int w, h;
+ p->printable_rect(&w, &h);
+ p->origin(w/2, h/2);
+ p->print_window(target->as_window(), -target->w()/2, -target->h()/2);
+ }
else p->print_widget(target);
p->end_page();
p->end_job();
@@ -646,10 +651,8 @@ void copy(Fl_Widget *, void *data) {
if (p.file()) {
if (target->as_window()) p.draw_decorated_window(target->as_window());
else p.draw(target);
- //p.close();
}
}
- fclose(eps);
}
}