From 5892993cbcf77e322f51475820d19f8307375df7 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Tue, 26 Jan 2016 20:17:47 +0000 Subject: Preliminary commit of porting Xlib drivers to the new naming scheme git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11053 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- src/cfg_gfx/xlib.H | 112 -- src/cfg_gfx/xlib_arci.cxx | 42 - src/cfg_gfx/xlib_color.cxx | 351 ------- src/cfg_gfx/xlib_line_style.cxx | 71 -- src/cfg_gfx/xlib_rect.cxx | 339 ------ src/cfg_gfx/xlib_vertex.cxx | 116 --- src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h | 112 ++ src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx | 42 + src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx | 351 +++++++ .../Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx | 676 ++++++++++++ .../Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx | 1081 ++++++++++++++++++++ .../Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx | 71 ++ src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx | 339 ++++++ .../Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx | 116 +++ src/fl_arci.cxx | 2 +- src/fl_color.cxx | 2 +- src/fl_font.cxx | 3 +- src/fl_font_x.cxx | 335 ------ src/fl_font_xft.cxx | 697 ------------- src/fl_line_style.cxx | 2 +- src/fl_rect.cxx | 27 +- src/fl_set_fonts.cxx | 2 +- src/fl_set_fonts_x.cxx | 341 ------ src/fl_set_fonts_xft.cxx | 384 ------- src/fl_vertex.cxx | 2 +- 25 files changed, 2796 insertions(+), 2820 deletions(-) delete mode 100644 src/cfg_gfx/xlib.H delete mode 100644 src/cfg_gfx/xlib_arci.cxx delete mode 100644 src/cfg_gfx/xlib_color.cxx delete mode 100644 src/cfg_gfx/xlib_line_style.cxx delete mode 100644 src/cfg_gfx/xlib_rect.cxx delete mode 100644 src/cfg_gfx/xlib_vertex.cxx create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx create mode 100644 src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx delete mode 100644 src/fl_font_x.cxx delete mode 100644 src/fl_font_xft.cxx delete mode 100644 src/fl_set_fonts_x.cxx delete mode 100644 src/fl_set_fonts_xft.cxx diff --git a/src/cfg_gfx/xlib.H b/src/cfg_gfx/xlib.H deleted file mode 100644 index 4ce00b426..000000000 --- a/src/cfg_gfx/xlib.H +++ /dev/null @@ -1,112 +0,0 @@ -// -// "$Id$" -// -// Definition of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device -// for the Fast Light Tool Kit (FLTK). -// -// Copyright 2010-2014 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -/** - \file xlib.H - \brief Definition of X11 Xlib graphics driver. - */ - -#ifndef FL_CFG_GFX_XLIB_H -#define FL_CFG_GFX_XLIB_H - -#include - -/** - \brief The Xlib-specific graphics class. - * - This class is implemented only on the Xlib platform. - */ -class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Graphics_Driver { -public: - static const char *class_id; - const char *class_name() {return class_id;}; - void draw(const char* str, int n, int x, int y); - void draw(int angle, const char *str, int n, int x, int y); - void rtl_draw(const char* str, int n, int x, int y); - void font(Fl_Font face, Fl_Fontsize size); - void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); - void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); - void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); - void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); - void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); - void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); - void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); - double width(const char *str, int n); - double width(unsigned int c); - void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); - int height(); - int descent(); - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); -#if ! defined(FL_DOXYGEN) - void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); -#endif -protected: - // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx - void point(int x, int y); - void rect(int x, int y, int w, int h); - void rectf(int x, int y, int w, int h); - void line(int x, int y, int x1, int y1); - void line(int x, int y, int x1, int y1, int x2, int y2); - 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 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); - // --- clipping - 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 restore_clip(); - // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx - void begin_complex_polygon(); - void transformed_vertex(double xf, double yf); - void vertex(double x, double y); - void end_points(); - void end_line(); - void end_loop(); - void end_polygon(); - void end_complex_polygon(); - void gap(); - void circle(double x, double y, double r); - // --- implementation is in src/fl_arc.cxx which includes src/cfg_gfx/xxx_arc.cxx if needed - // using void Fl_Graphics_Driver::arc(double x, double y, double r, double start, double end); - // --- implementation is in src/fl_arci.cxx which includes src/cfg_gfx/xxx_arci.cxx - 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); - // --- implementation is in src/fl_line_style.cxx which includes src/cfg_gfx/xxx_line_style.cxx - void line_style(int style, int width=0, char* dashes=0); - // --- implementation is in src/fl_color.cxx which includes src/cfg_gfx/xxx_color.cxx - void color(Fl_Color c); - Fl_Color color() { return color_; } - void color(uchar r, uchar g, uchar b); -}; - - -#endif // FL_CFG_GFX_XLIB_H - -// -// End of "$Id$". -// diff --git a/src/cfg_gfx/xlib_arci.cxx b/src/cfg_gfx/xlib_arci.cxx deleted file mode 100644 index 118e683a1..000000000 --- a/src/cfg_gfx/xlib_arci.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// -// "$Id$" -// -// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2010 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -#ifndef FL_CFG_GFX_XLIB_ARCI_CXX -#define FL_CFG_GFX_XLIB_ARCI_CXX - -/** - \file xlib_arci.cxx - \brief Utility functions for drawing circles using integers -*/ - -void Fl_Xlib_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { - if (w <= 0 || h <= 0) return; - XDrawArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); -} - -void Fl_Xlib_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { - if (w <= 0 || h <= 0) return; - XDrawArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); - XFillArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); -} - -#endif // FL_CFG_GFX_XLIB_ARCI_CXX - -// -// End of "$Id$". -// diff --git a/src/cfg_gfx/xlib_color.cxx b/src/cfg_gfx/xlib_color.cxx deleted file mode 100644 index e7e9d0cf7..000000000 --- a/src/cfg_gfx/xlib_color.cxx +++ /dev/null @@ -1,351 +0,0 @@ -// -// "$Id$" -// -// Color functions for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2010 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -// Implementation of fl_color(i), fl_color(r,g,b). - -// FIXME: all the global functions in this file should probably be protected -// members of the driver class. Starting with 1.4 we will allow multiple drivers -// to co-exist, creating conflicts with multipe mapping. - -// FIXME: maybe we can forget about color mapping and assume RGB? - -// Also code to look at the X visual and figure out the best way to turn -// a color into a pixel value. - -// SGI compiler seems to have problems with unsigned char arguments -// being used to index arrays. So I always copy them to an integer -// before use. - -# include "../Fl_XColor.H" -# include -# include -# include - -//////////////////////////////////////////////////////////////// -// figure_out_visual() calculates masks & shifts for generating -// pixels in true-color visuals: - -uchar fl_redmask; /**< color mask used in current color map handling */ -uchar fl_greenmask; /**< color mask used in current color map handling */ -uchar fl_bluemask; /**< color mask used in current color map handling */ - -int fl_redshift; /**< color shift used in current color map handling */ -int fl_greenshift; /**< color shift used in current color map handling */ -int fl_blueshift; /**< color shift used in current color map handling */ -int fl_extrashift; /**< color shift used in current color map handling */ - -static uchar beenhere; - -static void figure_out_visual() { - beenhere = 1; - if (!fl_visual->red_mask || !fl_visual->green_mask || !fl_visual->blue_mask){ -# if USE_COLORMAP - fl_redmask = 0; - return; -# else - Fl::fatal("Requires true color visual"); -# endif - } - - // get the bit masks into a more useful form: - int i,j,m; - - for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->red_mask & m) break; - for (j = i; m; j++, m<<=1) if (!(fl_visual->red_mask & m)) break; - fl_redshift = j-8; - fl_redmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); - - for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->green_mask & m) break; - for (j = i; m; j++, m<<=1) if (!(fl_visual->green_mask & m)) break; - fl_greenshift = j-8; - fl_greenmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); - - for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->blue_mask & m) break; - for (j = i; m; j++, m<<=1) if (!(fl_visual->blue_mask & m)) break; - fl_blueshift = j-8; - fl_bluemask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); - - i = fl_redshift; - if (fl_greenshift < i) i = fl_greenshift; - if (fl_blueshift < i) i = fl_blueshift; - if (i < 0) { - fl_extrashift = -i; - fl_redshift -= i; fl_greenshift -= i; fl_blueshift -= i; - } else - fl_extrashift = 0; - -} - -static unsigned fl_cmap[256] = { -#include "../fl_cmap.h" // this is a file produced by "cmap.cxx": -}; - -# if HAVE_OVERLAY -/** HAVE_OVERLAY determines whether fl_xmap is one or two planes */ -Fl_XColor fl_xmap[2][256]; -/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */ -uchar fl_overlay; -Colormap fl_overlay_colormap; -XVisualInfo* fl_overlay_visual; -ulong fl_transparent_pixel; -# else -/** HAVE_OVERLAY determines whether fl_xmap is one or two planes */ -Fl_XColor fl_xmap[1][256]; -/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */ -# define fl_overlay 0 -# endif - -void Fl_Xlib_Graphics_Driver::color(Fl_Color i) { - if (i & 0xffffff00) { - unsigned rgb = (unsigned)i; - fl_color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8)); - } else { - Fl_Graphics_Driver::color(i); - if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid - XSetForeground(fl_display, fl_gc, fl_xpixel(i)); - } -} - -void Fl_Xlib_Graphics_Driver::color(uchar r,uchar g,uchar b) { - Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); - if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid - XSetForeground(fl_display, fl_gc, fl_xpixel(r,g,b)); -} - -/** \addtogroup fl_attributes - @{ */ -//////////////////////////////////////////////////////////////// -// Get an rgb color. This is easy for a truecolor visual. For -// colormapped it picks the closest color out of the cube in the -// fltk colormap. However if this color cube entry has been -// requested before, you will get the earlier requested color, and -// even this may be approximated if the X colormap was full. - -/** - Returns the X pixel number used to draw the given rgb color. - This is the X pixel that fl_color() would use. - \param[in] r,g,b color components - \return X pixel number -*/ -ulong fl_xpixel(uchar r,uchar g,uchar b) { - if (!beenhere) figure_out_visual(); -# if USE_COLORMAP - if (!fl_redmask) { - // find closest entry in the colormap: - Fl_Color i = - fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); - Fl_XColor &xmap = fl_xmap[fl_overlay][i]; - if (xmap.mapped) return xmap.pixel; - // if not black or white, change the entry to be an exact match: - if (i != FL_COLOR_CUBE && i != 0xFF) - fl_cmap[i] = (r<<24)|(g<<16)|(b<<8); - return fl_xpixel(i); // allocate an X color - } -# endif - return - (((r&fl_redmask) << fl_redshift)+ - ((g&fl_greenmask)<> fl_extrashift; -} - -//////////////////////////////////////////////////////////////// -// Get a color out of the fltk colormap. Again for truecolor -// visuals this is easy. For colormap this actually tries to allocate -// an X color, and does a least-squares match to find the closest -// color if X cannot allocate that color. - -// calculate what color is actually on the screen for a mask: -static inline uchar realcolor(uchar color, uchar mask) { -# if 0 - // accurate version if the display has linear gamma, but fl_draw_image - // works better with the simpler version on most screens... - uchar m = mask; - uchar result = color&m; - for (;;) { - while (m&mask) {m>>=1; color>>=1;} - if (!m) break; - mask = m; - result |= color&m; - } - return result; -# else - return (color&mask) | ( (~mask)&(mask>>1) ); -# endif -} - -/** - Returns the X pixel number used to draw the given FLTK color index. - This is the X pixel that fl_color() would use. - \param[in] i color index - \return X pixel number -*/ -ulong fl_xpixel(Fl_Color i) { - if (i & 0xffffff00) { - return fl_xpixel((i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255); - } - - Fl_XColor &xmap = fl_xmap[fl_overlay][i]; - if (xmap.mapped) return xmap.pixel; - - if (!beenhere) figure_out_visual(); - - uchar r,g,b; - {unsigned c = fl_cmap[i]; r=uchar(c>>24); g=uchar(c>>16); b=uchar(c>>8);} - -# if USE_COLORMAP - Colormap colormap = fl_colormap; -# if HAVE_OVERLAY - if (fl_overlay) colormap = fl_overlay_colormap; else -# endif - if (fl_redmask) { -# endif - // return color for a truecolor visual: - xmap.mapped = 2; // 2 prevents XFreeColor from being called - xmap.r = realcolor(r, fl_redmask); - xmap.g = realcolor(g, fl_greenmask); - xmap.b = realcolor(b, fl_bluemask); - return xmap.pixel = - (((r&fl_redmask) << fl_redshift)+ - ((g&fl_greenmask)<> fl_extrashift; -# if USE_COLORMAP - } -# if HAVE_OVERLAY - static XColor* ac[2]; - XColor*& allcolors = ac[fl_overlay]; - static int nc[2]; - int& numcolors = nc[fl_overlay]; -# else - static XColor *allcolors; - static int numcolors; -# endif - - // I don't try to allocate colors with XAllocColor once it fails - // with any color. It is possible that it will work, since a color - // may have been freed, but some servers are extremely slow and this - // avoids one round trip: - if (!numcolors) { // don't try after a failure - XColor xcol; - xcol.red = r<<8; xcol.green = g<<8; xcol.blue = b<<8; - if (XAllocColor(fl_display, colormap, &xcol)) { - xmap.mapped = 1; - xmap.r = xcol.red>>8; - xmap.g = xcol.green>>8; - xmap.b = xcol.blue>>8; - return xmap.pixel = xcol.pixel; - } - - // I only read the colormap once. Again this is due to the slowness - // of round-trips to the X server, even though other programs may alter - // the colormap after this and make decisions here wrong. -# if HAVE_OVERLAY - if (fl_overlay) numcolors = fl_overlay_visual->colormap_size; else -# endif - numcolors = fl_visual->colormap_size; - if (!allcolors) allcolors = new XColor[numcolors]; - for (int p = numcolors; p--;) allcolors[p].pixel = p; - XQueryColors(fl_display, colormap, allcolors, numcolors); - } - - // find least-squares match: - int mindist = 0x7FFFFFFF; - unsigned int bestmatch = 0; - for (unsigned int n = numcolors; n--;) { -# if HAVE_OVERLAY - if (fl_overlay && n == fl_transparent_pixel) continue; -# endif - XColor &a = allcolors[n]; - int d, t; - t = int(r)-int(a.red>>8); d = t*t; - t = int(g)-int(a.green>>8); d += t*t; - t = int(b)-int(a.blue>>8); d += t*t; - if (d <= mindist) {bestmatch = n; mindist = d;} - } - XColor &p = allcolors[bestmatch]; - - // It appears to "work" to not call this XAllocColor, which will - // avoid another round-trip to the server. But then X does not - // know that this program "owns" this value, and can (and will) - // change it when the program that did allocate it exits: - if (XAllocColor(fl_display, colormap, &p)) { - xmap.mapped = 1; - xmap.pixel = p.pixel; - } else { - // However, if that XAllocColor fails, I have to give up and - // assume the pixel is ok for the duration of the program. This - // is due to bugs (?) in the Solaris X and some X terminals - // where XAllocColor *always* fails when the colormap is full, - // even if we ask for a color already in it... - xmap.mapped = 2; // 2 prevents XFreeColor from being called - xmap.pixel = bestmatch; - } - xmap.r = p.red>>8; - xmap.g = p.green>>8; - xmap.b = p.blue>>8; - return xmap.pixel; -# endif -} - -/** - Free color \p i if used, and clear mapping table entry. - \param[in] i color index - \param[in] overlay 0 for normal, 1 for overlay color -*/ -void Fl::free_color(Fl_Color i, int overlay) { -# if HAVE_OVERLAY -# else - if (overlay) return; -# endif - if (fl_xmap[overlay][i].mapped) { -# if USE_COLORMAP -# if HAVE_OVERLAY - Colormap colormap = overlay ? fl_overlay_colormap : fl_colormap; -# else - Colormap colormap = fl_colormap; -# endif - if (fl_xmap[overlay][i].mapped == 1) - XFreeColors(fl_display, colormap, &(fl_xmap[overlay][i].pixel), 1, 0); -# endif - fl_xmap[overlay][i].mapped = 0; - } -} - -/** - Set color mapping table entry \p i to color \p c - \param[in] i color index - \param[in] c color -*/ -void Fl::set_color(Fl_Color i, unsigned c) { - if (fl_cmap[i] != c) { - free_color(i,0); -# if HAVE_OVERLAY - free_color(i,1); -# endif - fl_cmap[i] = c; - } -} - -/** - @} - */ - -// -// End of "$Id$". -// diff --git a/src/cfg_gfx/xlib_line_style.cxx b/src/cfg_gfx/xlib_line_style.cxx deleted file mode 100644 index 55e759a61..000000000 --- a/src/cfg_gfx/xlib_line_style.cxx +++ /dev/null @@ -1,71 +0,0 @@ -// -// "$Id$" -// -// Line style code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2016 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -#ifndef FL_CFG_GFX_XLIB_LINE_STYLE_CXX -#define FL_CFG_GFX_XLIB_LINE_STYLE_CXX - -/** - \file xlib_line_style.cxx - \brief Line style drawing utility hiding different platforms. -*/ - -#include "xlib.H" - -void Fl_Xlib_Graphics_Driver::line_style(int style, int width, char* dashes) { - - // save line width in global variable for X11 clipping - if (width == 0) fl_line_width_ = 1; - else fl_line_width_ = width>0 ? width : -width; - - int ndashes = dashes ? strlen(dashes) : 0; - // emulate the WIN32 dash patterns on X - char buf[7]; - if (!ndashes && (style&0xff)) { - int w = width ? width : 1; - char dash, dot, gap; - // adjust lengths to account for cap: - if (style & 0x200) { - dash = char(2*w); - dot = 1; // unfortunately 0 does not work - gap = char(2*w-1); - } else { - dash = char(3*w); - dot = gap = char(w); - } - char* p = dashes = buf; - switch (style & 0xff) { - case FL_DASH: *p++ = dash; *p++ = gap; break; - case FL_DOT: *p++ = dot; *p++ = gap; break; - case FL_DASHDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; break; - case FL_DASHDOTDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; *p++ = dot; *p++ = gap; break; - } - ndashes = p-buf; - } - static int Cap[4] = {CapButt, CapButt, CapRound, CapProjecting}; - static int Join[4] = {JoinMiter, JoinMiter, JoinRound, JoinBevel}; - XSetLineAttributes(fl_display, fl_gc, width, - ndashes ? LineOnOffDash : LineSolid, - Cap[(style>>8)&3], Join[(style>>12)&3]); - if (ndashes) XSetDashes(fl_display, fl_gc, 0, dashes, ndashes); -} - -#endif // FL_CFG_GFX_XLIB_LINE_STYLE_CXX - -// -// End of "$Id$". -// diff --git a/src/cfg_gfx/xlib_rect.cxx b/src/cfg_gfx/xlib_rect.cxx deleted file mode 100644 index fc5ff1474..000000000 --- a/src/cfg_gfx/xlib_rect.cxx +++ /dev/null @@ -1,339 +0,0 @@ -// -// "$Id$" -// -// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2012 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - - -#ifndef FL_CFG_GFX_XLIB_RECT_CXX -#define FL_CFG_GFX_XLIB_RECT_CXX - - -/** - \file xlib_rect.cxx - \brief X11 Xlib specific line and polygon drawing with integer coordinates. - */ - - -#include "xlib.H" - - -#ifndef SHRT_MAX -#define SHRT_MAX (32767) -#endif - -/* - We need to check some coordinates for areas for clipping before we - use X functions, because X can't handle coordinates outside the 16-bit - range. Since all windows use relative coordinates > 0, we do also - check for negative values. X11 only, see also STR #2304. - - Note that this is only necessary for large objects, where only a - part of the object is visible. The draw() functions (e.g. box - drawing) must be clipped correctly. This is usually only a matter - for large container widgets. The individual child widgets will be - clipped completely. - - We define the usable X coordinate space as [ -LW : SHRT_MAX - LW ] - where LW = current line width for drawing. This is done so that - horizontal and vertical line drawing works correctly, even in real - border cases, e.g. drawing a rectangle slightly outside the top left - window corner, but with a line width so that a part of the line should - be visible (in this case 2 of 5 pixels): - - fl_line_style (FL_SOLID,5); // line width = 5 - fl_rect (-1,-1,100,100); // top/left: 2 pixels visible - - In this example case, no clipping would be done, because X can - handle it and clip unneeded pixels. - - Note that we must also take care of the case where fl_line_width_ - is zero (maybe unitialized). If this is the case, we assume a line - width of 1. - - Todo: Arbitrary line drawings (e.g. polygons) and clip regions - are not yet done. - - Note: - - We could use max. screen coordinates instead of SHRT_MAX, but that - would need more work and would probably be slower. We assume that - all window coordinates are >= 0 and that no window extends up to - 32767 - LW (where LW = current line width). Thus it is safe to clip - all coordinates to this range before calling X functions. If this - is not true, then clip_to_short() and clip_x() must be redefined. - - It would be somewhat easier if we had fl_clip_w and fl_clip_h, as - defined in FLTK 2.0 (for the upper clipping bounds)... - */ - -/* - clip_to_short() returns 1, if the area is invisible (clipped), - because ... - - (a) w or h are <= 0 i.e. nothing is visible - (b) x+w or y+h are < kmin i.e. left of or above visible area - (c) x or y are > kmax i.e. right of or below visible area - - kmin and kmax are the minimal and maximal X coordinate values, - as defined above. In this case x, y, w, and h are not changed. - - It returns 0, if the area is potentially visible and X can handle - clipping. x, y, w, and h may have been adjusted to fit into the - X coordinate space. - - Use this for clipping rectangles, as used in fl_rect() and - fl_rectf(). - */ -static int clip_to_short(int &x, int &y, int &w, int &h) { - - int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; - int kmin = -lw; - int kmax = SHRT_MAX - lw; - - if (w <= 0 || h <= 0) return 1; // (a) - if (x+w < kmin || y+h < kmin) return 1; // (b) - if (x > kmax || y > kmax) return 1; // (c) - - if (x < kmin) { w -= (kmin-x); x = kmin; } - if (y < kmin) { h -= (kmin-y); y = kmin; } - if (x+w > kmax) w = kmax - x; - if (y+h > kmax) h = kmax - y; - - return 0; -} - -/* - clip_x() returns a coordinate value clipped to the 16-bit coordinate - space (see above). This can be used to draw horizontal and vertical - lines that can be handled by X11. Each single coordinate value can - be clipped individually, and the result can be used directly, e.g. - in fl_xyline() and fl_yxline(). Note that this can't be used for - arbitrary lines (not horizontal or vertical). - */ -static int clip_x (int x) { - - int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; - int kmin = -lw; - int kmax = SHRT_MAX - lw; - - if (x < kmin) - x = kmin; - else if (x > kmax) - x = kmax; - return x; -} - -// Missing X call: (is this the fastest way to init a 1-rectangle region?) -// MSWindows equivalent exists, implemented inline in win32.H -Fl_Region XRectangleRegion(int x, int y, int w, int h) { - XRectangle R; - clip_to_short(x, y, w, h); - R.x = x; R.y = y; R.width = w; R.height = h; - Fl_Region r = XCreateRegion(); - XUnionRectWithRegion(&R, r, r); - return r; -} - -// --- line and polygon drawing with integer coordinates - -void Fl_Xlib_Graphics_Driver::point(int x, int y) { - XDrawPoint(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y)); -} - -void Fl_Xlib_Graphics_Driver::rect(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - if (!clip_to_short(x, y, w, h)) - XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1); -} - -void Fl_Xlib_Graphics_Driver::rectf(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - if (!clip_to_short(x, y, w, h)) - XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h); -} - -void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1) { - XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1); -} - -void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { - XPoint p[3]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); -} - -void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1) { - XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x1), clip_x(y)); -} - -void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2) { - XPoint p[3]; - p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); - p[1].x = p[2].x = clip_x(x1); p[2].y = clip_x(y2); - XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); -} - -void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { - XPoint p[4]; - p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); - p[1].x = p[2].x = clip_x(x1); p[2].y = p[3].y = clip_x(y2); - p[3].x = clip_x(x3); - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -} - -void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1) { - XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x), clip_x(y1)); -} - -void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2) { - XPoint p[3]; - p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); - p[1].y = p[2].y = clip_x(y1); p[2].x = clip_x(x2); - XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); -} - -void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { - XPoint p[4]; - p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); - p[1].y = p[2].y = clip_x(y1); p[2].x = p[3].x = clip_x(x2); - p[3].y = clip_x(y3); - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -} - -void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { - XPoint p[4]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x; p[3].y = y; - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -} - -void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - XPoint p[5]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x3; p[3].y = y3; - p[4].x = x; p[4].y = y; - XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); -} - -void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { - XPoint p[4]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x; p[3].y = y; - XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0); - XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); -} - -void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { - XPoint p[5]; - p[0].x = x; p[0].y = y; - p[1].x = x1; p[1].y = y1; - p[2].x = x2; p[2].y = y2; - p[3].x = x3; p[3].y = y3; - p[4].x = x; p[4].y = y; - XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0); - XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); -} - -// --- clipping - -void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) { - Fl_Region r; - if (w > 0 && h > 0) { - r = XRectangleRegion(x,y,w,h); - Fl_Region current = rstack[rstackptr]; - if (current) { - Fl_Region temp = XCreateRegion(); - XIntersectRegion(current, r, temp); - XDestroyRegion(r); - r = temp; - } - } else { // make empty clip region: - r = XCreateRegion(); - } - if (rstackptr < region_stack_max) rstack[++rstackptr] = r; - else Fl::warning("Fl_Xlib_Graphics_Driver::push_clip: clip stack overflow!\n"); - fl_restore_clip(); -} - -int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ - X = x; Y = y; W = w; H = h; - Fl_Region r = rstack[rstackptr]; - if (!r) return 0; - switch (XRectInRegion(r, x, y, w, h)) { - case 0: // completely outside - W = H = 0; - return 2; - case 1: // completely inside: - return 0; - default: // partial: - break; - } - Fl_Region rr = XRectangleRegion(x,y,w,h); - Fl_Region temp = XCreateRegion(); - XIntersectRegion(r, rr, temp); - XRectangle rect; - XClipBox(temp, &rect); - X = rect.x; Y = rect.y; W = rect.width; H = rect.height; - XDestroyRegion(temp); - XDestroyRegion(rr); - return 1; -} - -int Fl_Xlib_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - if (x+w <= 0 || y+h <= 0) return 0; - Fl_Region r = rstack[rstackptr]; - if (!r) return 1; - // get rid of coordinates outside the 16-bit range the X calls take. - if (clip_to_short(x,y,w,h)) return 0; // clipped - return XRectInRegion(r, x, y, w, h); -} - -// make there be no clip (used by fl_begin_offscreen() only!) -void Fl_Xlib_Graphics_Driver::push_no_clip() { - if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; - else Fl::warning("fl_push_no_cFl_Xlib_Graphics_Driver::push_no_cliplip: clip stack overflow!\n"); - fl_restore_clip(); -} - -// pop back to previous clip: -void Fl_Xlib_Graphics_Driver::pop_clip() { - if (rstackptr > 0) { - Fl_Region oldr = rstack[rstackptr--]; - if (oldr) XDestroyRegion(oldr); - } else Fl::warning("Fl_Xlib_Graphics_Driver::pop_clip: clip stack underflow!\n"); - fl_restore_clip(); -} - -void Fl_Xlib_Graphics_Driver::restore_clip() { - fl_clip_state_number++; - Fl_Region r = rstack[rstackptr]; - if (r) XSetRegion(fl_display, fl_gc, r); - else XSetClipMask(fl_display, fl_gc, 0); -} - -#endif // FL_CFG_GFX_XLIB_RECT_CXX - -// -// End of "$Id$". -// diff --git a/src/cfg_gfx/xlib_vertex.cxx b/src/cfg_gfx/xlib_vertex.cxx deleted file mode 100644 index 9fe73a27c..000000000 --- a/src/cfg_gfx/xlib_vertex.cxx +++ /dev/null @@ -1,116 +0,0 @@ -// -// "$Id$" -// -// Portable drawing routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2016 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -#ifndef FL_CFG_GFX_XLIB_VERTEX_CXX -#define FL_CFG_GFX_XLIB_VERTEX_CXX - -/** - \file xlib_vertex.cxx - \brief Portable drawing code for drawing arbitrary shapes with - simple 2D transformations, implemented for X11 Xlib. - */ - -#include "xlib.H" - -#include -#include -#include - - -void Fl_Xlib_Graphics_Driver::transformed_vertex(double xf, double yf) { - transformed_vertex0(COORD_T(rint(xf)), COORD_T(rint(yf))); -} - -void Fl_Xlib_Graphics_Driver::vertex(double x,double y) { - transformed_vertex0(COORD_T(x*m.a + y*m.c + m.x), COORD_T(x*m.b + y*m.d + m.y)); -} - -void Fl_Xlib_Graphics_Driver::end_points() { - if (n>1) XDrawPoints(fl_display, fl_window, fl_gc, p, n, 0); -} - -void Fl_Xlib_Graphics_Driver::end_line() { - if (n < 2) { - end_points(); - return; - } - if (n>1) XDrawLines(fl_display, fl_window, fl_gc, p, n, 0); -} - -void Fl_Xlib_Graphics_Driver::end_loop() { - fixloop(); - if (n>2) transformed_vertex((COORD_T)p[0].x, (COORD_T)p[0].y); - end_line(); -} - -void Fl_Xlib_Graphics_Driver::end_polygon() { - fixloop(); - if (n < 3) { - end_line(); - return; - } - if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, Convex, 0); -} - -void Fl_Xlib_Graphics_Driver::begin_complex_polygon() { - begin_polygon(); - gap_ = 0; -} - -void Fl_Xlib_Graphics_Driver::gap() { - while (n>gap_+2 && p[n-1].x == p[gap_].x && p[n-1].y == p[gap_].y) n--; - if (n > gap_+2) { - transformed_vertex((COORD_T)p[gap_].x, (COORD_T)p[gap_].y); - gap_ = n; - } else { - n = gap_; - } -} - -void Fl_Xlib_Graphics_Driver::end_complex_polygon() { - gap(); - if (n < 3) { - end_line(); - return; - } - if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, 0, 0); -} - -// shortcut the closed circles so they use XDrawArc: -// warning: these do not draw rotated ellipses correctly! -// See fl_arc.c for portable version. - -void Fl_Xlib_Graphics_Driver::circle(double x, double y,double r) { - double xt = transform_x(x,y); - double yt = transform_y(x,y); - double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); - double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); - int llx = (int)rint(xt-rx); - int w = (int)rint(xt+rx)-llx; - int lly = (int)rint(yt-ry); - int h = (int)rint(yt+ry)-lly; - - (what == POLYGON ? XFillArc : XDrawArc) - (fl_display, fl_window, fl_gc, llx, lly, w, h, 0, 360*64); -} - -#endif // FL_CFG_GFX_XLIB_VERTEX_CXX - -// -// End of "$Id$". -// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h new file mode 100644 index 000000000..255e5f16b --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h @@ -0,0 +1,112 @@ +// +// "$Id$" +// +// Definition of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device +// for the Fast Light Tool Kit (FLTK). +// +// Copyright 2010-2014 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +/** + \file Fl_Xlib_Graphics_Driver.h + \brief Definition of X11 Xlib graphics driver. + */ + +#ifndef FL_CFG_GFX_XLIB_H +#define FL_CFG_GFX_XLIB_H + +#include + +/** + \brief The Xlib-specific graphics class. + * + This class is implemented only on the Xlib platform. + */ +class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + void draw(const char* str, int n, int x, int y); + void draw(int angle, const char *str, int n, int x, int y); + void rtl_draw(const char* str, int n, int x, int y); + void font(Fl_Font face, Fl_Fontsize size); + void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + double width(const char *str, int n); + double width(unsigned int c); + void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h); + int height(); + int descent(); + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +#if ! defined(FL_DOXYGEN) + void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +#endif +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx + void point(int x, int y); + void rect(int x, int y, int w, int h); + void rectf(int x, int y, int w, int h); + void line(int x, int y, int x1, int y1); + void line(int x, int y, int x1, int y1, int x2, int y2); + 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 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); + // --- clipping + 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 restore_clip(); + // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx + void begin_complex_polygon(); + void transformed_vertex(double xf, double yf); + void vertex(double x, double y); + void end_points(); + void end_line(); + void end_loop(); + void end_polygon(); + void end_complex_polygon(); + void gap(); + void circle(double x, double y, double r); + // --- implementation is in src/fl_arc.cxx which includes src/cfg_gfx/xxx_arc.cxx if needed + // using void Fl_Graphics_Driver::arc(double x, double y, double r, double start, double end); + // --- implementation is in src/fl_arci.cxx which includes src/cfg_gfx/xxx_arci.cxx + 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); + // --- implementation is in src/fl_line_style.cxx which includes src/cfg_gfx/xxx_line_style.cxx + void line_style(int style, int width=0, char* dashes=0); + // --- implementation is in src/fl_color.cxx which includes src/cfg_gfx/xxx_color.cxx + void color(Fl_Color c); + Fl_Color color() { return color_; } + void color(uchar r, uchar g, uchar b); +}; + + +#endif // FL_CFG_GFX_XLIB_H + +// +// End of "$Id$". +// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx new file mode 100644 index 000000000..118e683a1 --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx @@ -0,0 +1,42 @@ +// +// "$Id$" +// +// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2010 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#ifndef FL_CFG_GFX_XLIB_ARCI_CXX +#define FL_CFG_GFX_XLIB_ARCI_CXX + +/** + \file xlib_arci.cxx + \brief Utility functions for drawing circles using integers +*/ + +void Fl_Xlib_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { + if (w <= 0 || h <= 0) return; + XDrawArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); +} + +void Fl_Xlib_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { + if (w <= 0 || h <= 0) return; + XDrawArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); + XFillArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); +} + +#endif // FL_CFG_GFX_XLIB_ARCI_CXX + +// +// End of "$Id$". +// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx new file mode 100644 index 000000000..e7e9d0cf7 --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx @@ -0,0 +1,351 @@ +// +// "$Id$" +// +// Color functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2010 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Implementation of fl_color(i), fl_color(r,g,b). + +// FIXME: all the global functions in this file should probably be protected +// members of the driver class. Starting with 1.4 we will allow multiple drivers +// to co-exist, creating conflicts with multipe mapping. + +// FIXME: maybe we can forget about color mapping and assume RGB? + +// Also code to look at the X visual and figure out the best way to turn +// a color into a pixel value. + +// SGI compiler seems to have problems with unsigned char arguments +// being used to index arrays. So I always copy them to an integer +// before use. + +# include "../Fl_XColor.H" +# include +# include +# include + +//////////////////////////////////////////////////////////////// +// figure_out_visual() calculates masks & shifts for generating +// pixels in true-color visuals: + +uchar fl_redmask; /**< color mask used in current color map handling */ +uchar fl_greenmask; /**< color mask used in current color map handling */ +uchar fl_bluemask; /**< color mask used in current color map handling */ + +int fl_redshift; /**< color shift used in current color map handling */ +int fl_greenshift; /**< color shift used in current color map handling */ +int fl_blueshift; /**< color shift used in current color map handling */ +int fl_extrashift; /**< color shift used in current color map handling */ + +static uchar beenhere; + +static void figure_out_visual() { + beenhere = 1; + if (!fl_visual->red_mask || !fl_visual->green_mask || !fl_visual->blue_mask){ +# if USE_COLORMAP + fl_redmask = 0; + return; +# else + Fl::fatal("Requires true color visual"); +# endif + } + + // get the bit masks into a more useful form: + int i,j,m; + + for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->red_mask & m) break; + for (j = i; m; j++, m<<=1) if (!(fl_visual->red_mask & m)) break; + fl_redshift = j-8; + fl_redmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); + + for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->green_mask & m) break; + for (j = i; m; j++, m<<=1) if (!(fl_visual->green_mask & m)) break; + fl_greenshift = j-8; + fl_greenmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); + + for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->blue_mask & m) break; + for (j = i; m; j++, m<<=1) if (!(fl_visual->blue_mask & m)) break; + fl_blueshift = j-8; + fl_bluemask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); + + i = fl_redshift; + if (fl_greenshift < i) i = fl_greenshift; + if (fl_blueshift < i) i = fl_blueshift; + if (i < 0) { + fl_extrashift = -i; + fl_redshift -= i; fl_greenshift -= i; fl_blueshift -= i; + } else + fl_extrashift = 0; + +} + +static unsigned fl_cmap[256] = { +#include "../fl_cmap.h" // this is a file produced by "cmap.cxx": +}; + +# if HAVE_OVERLAY +/** HAVE_OVERLAY determines whether fl_xmap is one or two planes */ +Fl_XColor fl_xmap[2][256]; +/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */ +uchar fl_overlay; +Colormap fl_overlay_colormap; +XVisualInfo* fl_overlay_visual; +ulong fl_transparent_pixel; +# else +/** HAVE_OVERLAY determines whether fl_xmap is one or two planes */ +Fl_XColor fl_xmap[1][256]; +/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */ +# define fl_overlay 0 +# endif + +void Fl_Xlib_Graphics_Driver::color(Fl_Color i) { + if (i & 0xffffff00) { + unsigned rgb = (unsigned)i; + fl_color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8)); + } else { + Fl_Graphics_Driver::color(i); + if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid + XSetForeground(fl_display, fl_gc, fl_xpixel(i)); + } +} + +void Fl_Xlib_Graphics_Driver::color(uchar r,uchar g,uchar b) { + Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); + if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid + XSetForeground(fl_display, fl_gc, fl_xpixel(r,g,b)); +} + +/** \addtogroup fl_attributes + @{ */ +//////////////////////////////////////////////////////////////// +// Get an rgb color. This is easy for a truecolor visual. For +// colormapped it picks the closest color out of the cube in the +// fltk colormap. However if this color cube entry has been +// requested before, you will get the earlier requested color, and +// even this may be approximated if the X colormap was full. + +/** + Returns the X pixel number used to draw the given rgb color. + This is the X pixel that fl_color() would use. + \param[in] r,g,b color components + \return X pixel number +*/ +ulong fl_xpixel(uchar r,uchar g,uchar b) { + if (!beenhere) figure_out_visual(); +# if USE_COLORMAP + if (!fl_redmask) { + // find closest entry in the colormap: + Fl_Color i = + fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); + Fl_XColor &xmap = fl_xmap[fl_overlay][i]; + if (xmap.mapped) return xmap.pixel; + // if not black or white, change the entry to be an exact match: + if (i != FL_COLOR_CUBE && i != 0xFF) + fl_cmap[i] = (r<<24)|(g<<16)|(b<<8); + return fl_xpixel(i); // allocate an X color + } +# endif + return + (((r&fl_redmask) << fl_redshift)+ + ((g&fl_greenmask)<> fl_extrashift; +} + +//////////////////////////////////////////////////////////////// +// Get a color out of the fltk colormap. Again for truecolor +// visuals this is easy. For colormap this actually tries to allocate +// an X color, and does a least-squares match to find the closest +// color if X cannot allocate that color. + +// calculate what color is actually on the screen for a mask: +static inline uchar realcolor(uchar color, uchar mask) { +# if 0 + // accurate version if the display has linear gamma, but fl_draw_image + // works better with the simpler version on most screens... + uchar m = mask; + uchar result = color&m; + for (;;) { + while (m&mask) {m>>=1; color>>=1;} + if (!m) break; + mask = m; + result |= color&m; + } + return result; +# else + return (color&mask) | ( (~mask)&(mask>>1) ); +# endif +} + +/** + Returns the X pixel number used to draw the given FLTK color index. + This is the X pixel that fl_color() would use. + \param[in] i color index + \return X pixel number +*/ +ulong fl_xpixel(Fl_Color i) { + if (i & 0xffffff00) { + return fl_xpixel((i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255); + } + + Fl_XColor &xmap = fl_xmap[fl_overlay][i]; + if (xmap.mapped) return xmap.pixel; + + if (!beenhere) figure_out_visual(); + + uchar r,g,b; + {unsigned c = fl_cmap[i]; r=uchar(c>>24); g=uchar(c>>16); b=uchar(c>>8);} + +# if USE_COLORMAP + Colormap colormap = fl_colormap; +# if HAVE_OVERLAY + if (fl_overlay) colormap = fl_overlay_colormap; else +# endif + if (fl_redmask) { +# endif + // return color for a truecolor visual: + xmap.mapped = 2; // 2 prevents XFreeColor from being called + xmap.r = realcolor(r, fl_redmask); + xmap.g = realcolor(g, fl_greenmask); + xmap.b = realcolor(b, fl_bluemask); + return xmap.pixel = + (((r&fl_redmask) << fl_redshift)+ + ((g&fl_greenmask)<> fl_extrashift; +# if USE_COLORMAP + } +# if HAVE_OVERLAY + static XColor* ac[2]; + XColor*& allcolors = ac[fl_overlay]; + static int nc[2]; + int& numcolors = nc[fl_overlay]; +# else + static XColor *allcolors; + static int numcolors; +# endif + + // I don't try to allocate colors with XAllocColor once it fails + // with any color. It is possible that it will work, since a color + // may have been freed, but some servers are extremely slow and this + // avoids one round trip: + if (!numcolors) { // don't try after a failure + XColor xcol; + xcol.red = r<<8; xcol.green = g<<8; xcol.blue = b<<8; + if (XAllocColor(fl_display, colormap, &xcol)) { + xmap.mapped = 1; + xmap.r = xcol.red>>8; + xmap.g = xcol.green>>8; + xmap.b = xcol.blue>>8; + return xmap.pixel = xcol.pixel; + } + + // I only read the colormap once. Again this is due to the slowness + // of round-trips to the X server, even though other programs may alter + // the colormap after this and make decisions here wrong. +# if HAVE_OVERLAY + if (fl_overlay) numcolors = fl_overlay_visual->colormap_size; else +# endif + numcolors = fl_visual->colormap_size; + if (!allcolors) allcolors = new XColor[numcolors]; + for (int p = numcolors; p--;) allcolors[p].pixel = p; + XQueryColors(fl_display, colormap, allcolors, numcolors); + } + + // find least-squares match: + int mindist = 0x7FFFFFFF; + unsigned int bestmatch = 0; + for (unsigned int n = numcolors; n--;) { +# if HAVE_OVERLAY + if (fl_overlay && n == fl_transparent_pixel) continue; +# endif + XColor &a = allcolors[n]; + int d, t; + t = int(r)-int(a.red>>8); d = t*t; + t = int(g)-int(a.green>>8); d += t*t; + t = int(b)-int(a.blue>>8); d += t*t; + if (d <= mindist) {bestmatch = n; mindist = d;} + } + XColor &p = allcolors[bestmatch]; + + // It appears to "work" to not call this XAllocColor, which will + // avoid another round-trip to the server. But then X does not + // know that this program "owns" this value, and can (and will) + // change it when the program that did allocate it exits: + if (XAllocColor(fl_display, colormap, &p)) { + xmap.mapped = 1; + xmap.pixel = p.pixel; + } else { + // However, if that XAllocColor fails, I have to give up and + // assume the pixel is ok for the duration of the program. This + // is due to bugs (?) in the Solaris X and some X terminals + // where XAllocColor *always* fails when the colormap is full, + // even if we ask for a color already in it... + xmap.mapped = 2; // 2 prevents XFreeColor from being called + xmap.pixel = bestmatch; + } + xmap.r = p.red>>8; + xmap.g = p.green>>8; + xmap.b = p.blue>>8; + return xmap.pixel; +# endif +} + +/** + Free color \p i if used, and clear mapping table entry. + \param[in] i color index + \param[in] overlay 0 for normal, 1 for overlay color +*/ +void Fl::free_color(Fl_Color i, int overlay) { +# if HAVE_OVERLAY +# else + if (overlay) return; +# endif + if (fl_xmap[overlay][i].mapped) { +# if USE_COLORMAP +# if HAVE_OVERLAY + Colormap colormap = overlay ? fl_overlay_colormap : fl_colormap; +# else + Colormap colormap = fl_colormap; +# endif + if (fl_xmap[overlay][i].mapped == 1) + XFreeColors(fl_display, colormap, &(fl_xmap[overlay][i].pixel), 1, 0); +# endif + fl_xmap[overlay][i].mapped = 0; + } +} + +/** + Set color mapping table entry \p i to color \p c + \param[in] i color index + \param[in] c color +*/ +void Fl::set_color(Fl_Color i, unsigned c) { + if (fl_cmap[i] != c) { + free_color(i,0); +# if HAVE_OVERLAY + free_color(i,1); +# endif + fl_cmap[i] = c; + } +} + +/** + @} + */ + +// +// End of "$Id$". +// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx new file mode 100644 index 000000000..cec910f30 --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx @@ -0,0 +1,676 @@ +// +// "$Id$" +// +// X11 font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2010 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This function fills in the fltk font table with all the fonts that +// are found on the X server. It tries to place the fonts into families +// and to sort them so the first 4 in a family are normal, bold, italic, +// and bold italic. + +// Standard X fonts are matched by a pattern that is always of +// this form, and this pattern is put in the table: +// "-*-family-weight-slant-width1-style-*-registry-encoding" + +// Non-standard font names (those not starting with '-') are matched +// by a pattern of the form "prefix*suffix", where the '*' is where +// fltk thinks the point size is, or by the actual font name if no +// point size is found. + +// Fltk knows how to pull an "attribute" out of a font name, such as +// bold or italic, by matching known x font field values. All words +// that don't match a known attribute are combined into the "name" +// of the font. Names are compared before attributes for sorting, this +// makes the bold and plain version of a font come out next to each +// other despite the poor X font naming scheme. + +// By default fl_set_fonts() only does iso8859-1 encoded fonts. You can +// do all normal X fonts by passing "-*" or every possible font with "*". + +// Fl::set_font will take strings other than the ones this stores +// and can identify any font on X that way. You may want to write your +// own system of font management and not use this code. + +// turn word N of a X font name into either some attribute bits +// (right now 0, FL_BOLD, or FL_ITALIC), or into -1 indicating that +// the word should be put into the name: + +static int attribute(int n, const char *p) { + // don't put blank things into name: + if (!*p || *p=='-' || *p=='*') return 0; + if (n == 3) { // weight + if (!strncmp(p,"normal",6) || + !strncmp(p,"light",5) || + !strncmp(p,"medium",6) || + !strncmp(p,"book",4)) return 0; + if (!strncmp(p,"bold",4) || !strncmp(p,"demi",4)) return FL_BOLD; + } else if (n == 4) { // slant + if (*p == 'r') return 0; + if (*p == 'i' || *p == 'o') return FL_ITALIC; + } else if (n == 5) { // sWidth + if (!strncmp(p,"normal",6)) return 0; + } + return -1; +} + +// return non-zero if the registry-encoding should be used: +extern const char* fl_encoding; +static int use_registry(const char *p) { + return *p && *p!='*' && strcmp(p,fl_encoding); +} + +// Bug: older versions calculated the value for *ap as a side effect of +// making the name, and then forgot about it. To avoid having to change +// the header files I decided to store this value in the last character +// of the font name array. +#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 + +// turn a stored (with *'s) X font name into a pretty name: +const char* Fl::get_font_name(Fl_Font fnum, int* ap) { + Fl_Fontdesc *f = fl_fonts + fnum; + if (!f->fontname[0]) { + int type = 0; + const char* p = f->name; + if (!p) { + if (ap) *ap = 0; + return ""; + } + char *o = f->fontname; + + if (*p != '-') { // non-standard font, just replace * with spaces: + if (strstr(p,"bold")) type = FL_BOLD; + if (strstr(p,"ital")) type |= FL_ITALIC; + for (;*p; p++) { + if (*p == '*' || *p == ' ' || *p == '-') { + do p++; while (*p == '*' || *p == ' ' || *p == '-'); + if (!*p) break; + if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' '; + } + if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = *p; + } + *o = 0; + + } else { // standard dash-separated font: + + // get the family: + const char *x = fl_font_word(p,2); if (*x) x++; if (*x=='*') x++; + if (!*x) { + if (ap) *ap = 0; + return p; + } + const char *e = fl_font_word(x,1); + if ((e - x) < (int)(ENDOFBUFFER - 1)) { + // MRS: we want strncpy here, not strlcpy... + strncpy(o,x,e-x); + o += e-x; + } else { + strlcpy(f->fontname, x, ENDOFBUFFER); + o = f->fontname+ENDOFBUFFER-1; + } + + // collect all the attribute words: + for (int n = 3; n <= 6; n++) { + // get the next word: + if (*e) e++; x = e; e = fl_font_word(x,1); + int t = attribute(n,x); + if (t < 0) { + if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' '; + if ((e - x) < (int)(ENDOFBUFFER - (o - f->fontname) - 1)) { + // MRS: we want strncpy here, not strlcpy... + strncpy(o,x,e-x); + o += e-x; + } else { + strlcpy(o,x, ENDOFBUFFER - (o - f->fontname) - 1); + o = f->fontname+ENDOFBUFFER-1; + } + } else type |= t; + } + + // skip over the '*' for the size and get the registry-encoding: + x = fl_font_word(e,2); + if (*x) {x++; *o++ = '('; while (*x) *o++ = *x++; *o++ = ')';} + + *o = 0; + if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); + if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); + } + f->fontname[ENDOFBUFFER] = (char)type; + } + if (ap) *ap = f->fontname[ENDOFBUFFER]; + return f->fontname; +} + +extern "C" { +// sort raw (non-'*') X font names into perfect order: + +static int ultrasort(const void *aa, const void *bb) { + const char *a = *(char **)aa; + const char *b = *(char **)bb; + + // sort all non x-fonts at the end: + if (*a != '-') { + if (*b == '-') return 1; + // 2 non-x fonts are matched by "numeric sort" + int ret = 0; + for (;;) { + if (isdigit(*a) && isdigit(*b)) { + int na = strtol(a, (char **)&a, 10); + int nb = strtol(b, (char **)&b, 10); + if (!ret) ret = na-nb; + } else if (*a != *b) { + return (*a-*b); + } else if (!*a) { + return ret; + } else { + a++; b++; + } + } + } else { + if (*b != '-') return -1; + } + + // skip the foundry (assume equal): + for (a++; *a && *a++!='-';); + for (b++; *b && *b++!='-';); + + // compare the family and all the attribute words: + int atype = 0; + int btype = 0; + for (int n = 2; n <= 6; n++) { + int at = attribute(n,a); + int bt = attribute(n,b); + if (at < 0) { + if (bt >= 0) return 1; + for (;;) {if (*a!=*b) return *a-*b; b++; if (!*a || *a++=='-') break;} + } else { + if (bt < 0) return -1; + a = fl_font_word(a,1); if (*a) a++; + b = fl_font_word(b,1); if (*b) b++; + atype |= at; btype |= bt; + } + } + + // remember the pixel size: + int asize = atoi(a); + int bsize = atoi(b); + + // compare the registry/encoding: + a = fl_font_word(a,6); if (*a) a++; + b = fl_font_word(b,6); if (*b) b++; + if (use_registry(a)) { + if (!use_registry(b)) return 1; + int r = strcmp(a,b); if (r) return r; + } else { + if (use_registry(b)) return -1; + } + + if (atype != btype) return atype-btype; + if (asize != bsize) return asize-bsize; + + // something wrong, just do a string compare... + return strcmp(*(char**)aa, *(char**)bb); +} +} + +// converts a X font name to a standard starname, returns point size: +static int to_canonical(char *to, const char *from, size_t tolen) { + char* c = fl_find_fontsize((char*)from); + if (!c) return -1; // no point size found... + const char* endptr; + int size = strtol(c,(char**)&endptr,10); + if (from[0] == '-') { + // replace the "foundry" with -*-: + *to++ = '-'; *to++ = '*'; + for (from++; *from && *from != '-'; from++); + // skip to the registry-encoding: + endptr = (char*)fl_font_word(endptr,6); + if (*endptr && !use_registry(endptr+1)) endptr = ""; + } + int n = c-from; + // MRS: we want strncpy here, not strlcpy... + if (n > (int)(tolen - 1)) return -1; + strncpy(to,from,n); + to[n++] = '*'; + strlcpy(to+n,endptr, tolen - n); + return size; +} + +static unsigned int fl_free_font = FL_FREE_FONT; + +Fl_Font Fl::set_fonts(const char* xstarname) { + if (fl_free_font > (unsigned)FL_FREE_FONT) // already been here + return (Fl_Font)fl_free_font; + fl_open_display(); + int xlistsize; + char buf[20]; + if (!xstarname) { + strcpy(buf,"-*-"); strcpy(buf+3,fl_encoding); + xstarname = buf; + } + char **xlist = XListFonts(fl_display, xstarname, 10000, &xlistsize); + if (!xlist) return (Fl_Font)fl_free_font; + qsort(xlist, xlistsize, sizeof(*xlist), ultrasort); + int used_xlist = 0; + for (int i=0; i= 0) { + for (;;) { // find all matching fonts: + if (i >= xlistsize) break; + const char *q = xlist[i]; + char this_canon[1024]; + if (to_canonical(this_canon, q, sizeof(this_canon)) < 0) break; + if (strcmp(canon, this_canon)) break; + i++; + } + /*if (*p=='-' || i > first_xlist+1)*/ p = canon; + } + unsigned int j; + for (j = 0;; j++) { + /*if (j < FL_FREE_FONT) { + // see if it is one of our built-in fonts: + // if so, set the list of x fonts, since we have it anyway + if (fl_fonts[j].name && !strcmp(fl_fonts[j].name, p)) break; + } else */{ + j = fl_free_font++; + if (p == canon) p = strdup(p); else used_xlist = 1; + Fl::set_font((Fl_Font)j, p); + break; + } + } + if (!fl_fonts[j].xlist) { + fl_fonts[j].xlist = xlist+first_xlist; + fl_fonts[j].n = -(i-first_xlist); + used_xlist = 1; + } + } + if (!used_xlist) XFreeFontNames(xlist); + return (Fl_Font)fl_free_font; +} + +int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { + Fl_Fontdesc *s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 + if (!s->xlist) { + fl_open_display(); + s->xlist = XListFonts(fl_display, s->name, 100, &(s->n)); + if (!s->xlist) return 0; + } + int listsize = s->n; if (listsize<0) listsize = -listsize; + static int sizes[128]; + int numsizes = 0; + for (int i = 0; i < listsize; i++) { + char *q = s->xlist[i]; + char *d = fl_find_fontsize(q); + if (!d) continue; + int s = strtol(d,0,10); + if (!numsizes || sizes[numsizes-1] < s) { + sizes[numsizes++] = s; + } else { + // insert-sort the new size into list: + int n; + for (n = numsizes-1; n > 0; n--) if (sizes[n-1] < s) break; + if (sizes[n] != s) { + for (int m = numsizes; m > n; m--) sizes[m] = sizes[m-1]; + sizes[n] = s; + numsizes++; + } + } + } + sizep = sizes; + return numsizes; +} + +// +// End of "$Id$". +// +// +// "$Id$" +// +// Standard X11 font selection code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2011 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +#ifndef FL_DOXYGEN + +Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name) { + font = XCreateUtf8FontStruct(fl_display, name); + if (!font) { + Fl::warning("bad font: %s", name); + font = XCreateUtf8FontStruct(fl_display, "fixed"); + } +# if HAVE_GL + listbase = 0; + for (int u = 0; u < 64; u++) glok[u] = 0; +# endif +} + +Fl_XFont_On_Demand fl_xfont; + +Fl_Font_Descriptor::~Fl_Font_Descriptor() { +# if HAVE_GL +// Delete list created by gl_draw(). This is not done by this code +// as it will link in GL unnecessarily. There should be some kind +// of "free" routine pointer, or a subclass? +// if (listbase) { +// int base = font->min_char_or_byte2; +// int size = font->max_char_or_byte2-base+1; +// int base = 0; int size = 256; +// glDeleteLists(listbase+base,size); +// } +# endif + if (this == fl_graphics_driver->font_descriptor()) { + fl_graphics_driver->font_descriptor(NULL); + fl_xfont = 0; + } + XFreeUtf8FontStruct(fl_display, font); +} + +//////////////////////////////////////////////////////////////// + +// WARNING: if you add to this table, you must redefine FL_FREE_FONT +// in Enumerations.H & recompile!! +static Fl_Fontdesc built_in_table[] = { +{"-*-helvetica-medium-r-normal--*"}, +{"-*-helvetica-bold-r-normal--*"}, +{"-*-helvetica-medium-o-normal--*"}, +{"-*-helvetica-bold-o-normal--*"}, +{"-*-courier-medium-r-normal--*"}, +{"-*-courier-bold-r-normal--*"}, +{"-*-courier-medium-o-normal--*"}, +{"-*-courier-bold-o-normal--*"}, +{"-*-times-medium-r-normal--*"}, +{"-*-times-bold-r-normal--*"}, +{"-*-times-medium-i-normal--*"}, +{"-*-times-bold-i-normal--*"}, +{"-*-symbol-*"}, +{"-*-lucidatypewriter-medium-r-normal-sans-*"}, +{"-*-lucidatypewriter-bold-r-normal-sans-*"}, +{"-*-*zapf dingbats-*"} +}; + +Fl_Fontdesc* fl_fonts = built_in_table; + +#define MAXSIZE 32767 + +// return dash number N, or pointer to ending null if none: +const char* fl_font_word(const char* p, int n) { + while (*p) {if (*p=='-') {if (!--n) break;} p++;} + return p; +} + +// return a pointer to a number we think is "point size": +char* fl_find_fontsize(char* name) { + char* c = name; + // for standard x font names, try after 7th dash: + if (*c == '-') { + c = (char*)fl_font_word(c,7); + if (*c++ && isdigit(*c)) return c; + return 0; // malformed x font name? + } + char* r = 0; + // find last set of digits: + for (c++;* c; c++) + if (isdigit(*c) && !isdigit(*(c-1))) r = c; + return r; +} + +//const char* fl_encoding = "iso8859-1"; +const char* fl_encoding = "iso10646-1"; + +// return true if this matches fl_encoding: +int fl_correct_encoding(const char* name) { + if (*name != '-') return 0; + const char* c = fl_font_word(name,13); + return (*c++ && !strcmp(c,fl_encoding)); +} + +static const char *find_best_font(const char *fname, int size) { + int cnt; + static char **list = NULL; +// locate or create an Fl_Font_Descriptor for a given Fl_Fontdesc and size: + if (list) XFreeFontNames(list); + list = XListFonts(fl_display, fname, 100, &cnt); + if (!list) return "fixed"; + + // search for largest <= font size: + char* name = list[0]; int ptsize = 0; // best one found so far + int matchedlength = 32767; + char namebuffer[1024]; // holds scalable font name + int found_encoding = 0; + int m = cnt; if (m<0) m = -m; + for (int n=0; n < m; n++) { + char* thisname = list[n]; + if (fl_correct_encoding(thisname)) { + if (!found_encoding) ptsize = 0; // force it to choose this + found_encoding = 1; + } else { + if (found_encoding) continue; + } + char* c = (char*)fl_find_fontsize(thisname); + int thissize = c ? atoi(c) : MAXSIZE; + int thislength = strlen(thisname); + if (thissize == size && thislength < matchedlength) { + // exact match, use it: + name = thisname; + ptsize = size; + matchedlength = thislength; + } else if (!thissize && ptsize!=size) { + // whoa! A scalable font! Use unless exact match found: + int l = c-thisname; + memcpy(namebuffer,thisname,l); + l += sprintf(namebuffer+l,"%d",size); + while (*c == '0') c++; + strcpy(namebuffer+l,c); + name = namebuffer; + ptsize = size; + } else if (!ptsize || // no fonts yet + (thissize < ptsize && ptsize > size) || // current font too big + (thissize > ptsize && thissize <= size) // current too small + ) { + name = thisname; + ptsize = thissize; + matchedlength = thislength; + } + } + +// if (ptsize != size) { // see if we already found this unscalable font: +// for (f = s->first; f; f = f->next) { +// if (f->minsize <= ptsize && f->maxsize >= ptsize) { +// if (f->minsize > size) f->minsize = size; +// if (f->maxsize < size) f->maxsize = size; +// return f; +// } +// } +// } +// +// // okay, we definately have some name, make the font: +// f = new Fl_Font_Descriptor(name); +// if (ptsize < size) {f->minsize = ptsize; f->maxsize = size;} +// else {f->minsize = size; f->maxsize = ptsize;} +// f->next = s->first; +// s->first = f; +// return f; + + return name; +} + +static char *put_font_size(const char *n, int size) +{ + int i = 0; + char *buf; + const char *ptr; + const char *f; + char *name; + int nbf = 1; + name = strdup(n); + while (name[i]) { + if (name[i] == ',') {nbf++; name[i] = '\0';} + i++; + } + + buf = (char*) malloc(nbf * 256); + buf[0] = '\0'; + ptr = name; + i = 0; + while (ptr && nbf > 0) { + f = find_best_font(ptr, size); + while (*f) { + buf[i] = *f; + f++; i++; + } + nbf--; + while (*ptr) ptr++; + if (nbf) { + ptr++; + buf[i] = ','; + i++; + } + while(isspace(*ptr)) ptr++; + } + buf[i] = '\0'; + free(name); + return buf; +} + + +char *fl_get_font_xfld(int fnum, int size) { + Fl_Fontdesc* s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // use font 0 if still undefined + fl_open_display(); + return put_font_size(s->name, size); +} + +// locate or create an Fl_Font_Descriptor for a given Fl_Fontdesc and size: +static Fl_Font_Descriptor* find(int fnum, int size) { + char *name; + Fl_Fontdesc* s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // use font 0 if still undefined + Fl_Font_Descriptor* f; + for (f = s->first; f; f = f->next) + if (f->size == size) return f; + fl_open_display(); + + name = put_font_size(s->name, size); + f = new Fl_Font_Descriptor(name); + f->size = size; + f->next = s->first; + s->first = f; + free(name); + return f; +} + + +//////////////////////////////////////////////////////////////// +// Public interface: + +void *fl_xftfont = 0; +static GC font_gc; + +XFontStruct* Fl_XFont_On_Demand::value() { + return ptr; +} + +void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { + if (fnum==-1) { + Fl_Graphics_Driver::font(0, 0); + return; + } + if (fnum == Fl_Graphics_Driver::font() && size == Fl_Graphics_Driver::size()) return; + Fl_Graphics_Driver::font(fnum, size); + Fl_Font_Descriptor* f = find(fnum, size); + if (f != this->font_descriptor()) { + this->font_descriptor(f); + fl_xfont = f->font->fonts[0]; + font_gc = 0; + } +} + +int Fl_Xlib_Graphics_Driver::height() { + if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent; + else return -1; +} + +int Fl_Xlib_Graphics_Driver::descent() { + if (font_descriptor()) return font_descriptor()->font->descent; + else return -1; +} + +double Fl_Xlib_Graphics_Driver::width(const char* c, int n) { + if (font_descriptor()) return (double) XUtf8TextWidth(font_descriptor()->font, c, n); + else return -1; +} + +double Fl_Xlib_Graphics_Driver::width(unsigned int c) { + if (font_descriptor()) return (double) XUtf8UcsWidth(font_descriptor()->font, c); + else return -1; +} + +void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &W, int &H) { + if (font_gc != fl_gc) { + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + font_gc = fl_gc; + XSetFont(fl_display, fl_gc, font_descriptor()->font->fid); + } + int xx, yy, ww, hh; + xx = yy = ww = hh = 0; + if (fl_gc) XUtf8_measure_extents(fl_display, fl_window, font_descriptor()->font, fl_gc, &xx, &yy, &ww, &hh, c, n); + + W = ww; H = hh; dx = xx; dy = yy; +// This is the safe but mostly wrong thing we used to do... +// W = 0; H = 0; +// fl_measure(c, W, H, 0); +// dx = 0; +// dy = fl_descent() - H; +} + +void Fl_Xlib_Graphics_Driver::draw(const char* c, int n, int x, int y) { + if (font_gc != fl_gc) { + if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); + font_gc = fl_gc; + XSetFont(fl_display, fl_gc, font_descriptor()->font->fid); + } + if (fl_gc) XUtf8DrawString(fl_display, fl_window, font_descriptor()->font, fl_gc, x, y, c, n); +} + +void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { + fprintf(stderr,"ROTATING TEXT NOT IMPLEMENTED\n"); + this->draw(str, n, (int)x, (int)y); +} + +void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { + if (font_gc != fl_gc) { + if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); + font_gc = fl_gc; + } + if (fl_gc) XUtf8DrawRtlString(fl_display, fl_window, font_descriptor()->font, fl_gc, x, y, c, n); +} +#endif // FL_DOXYGEN +// +// End of "$Id$". +// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx new file mode 100644 index 000000000..91ee460ce --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx @@ -0,0 +1,1081 @@ +// +// "$Id$" +// +// More font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2011 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +// This function fills in the fltk font table with all the fonts that +// are found on the X server. It tries to place the fonts into families +// and to sort them so the first 4 in a family are normal, bold, italic, +// and bold italic. + +// Bug: older versions calculated the value for *ap as a side effect of +// making the name, and then forgot about it. To avoid having to change +// the header files I decided to store this value in the last character +// of the font name array. +#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 + +// turn a stored font name in "fltk format" into a pretty name: +const char* Fl::get_font_name(Fl_Font fnum, int* ap) { + Fl_Fontdesc *f = fl_fonts + fnum; + if (!f->fontname[0]) { + const char* p = f->name; + int type; + switch (p[0]) { + case 'B': type = FL_BOLD; break; + case 'I': type = FL_ITALIC; break; + case 'P': type = FL_BOLD | FL_ITALIC; break; + default: type = 0; break; + } + + // NOTE: This can cause duplications in fonts that already have Bold or Italic in + // their "name". Maybe we need to find a cleverer way? + strlcpy(f->fontname, p+1, ENDOFBUFFER); + if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); + if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); + f->fontname[ENDOFBUFFER] = (char)type; + } + if (ap) *ap = f->fontname[ENDOFBUFFER]; + return f->fontname; +} + +/////////////////////////////////////////////////////////// +#define LOCAL_RAW_NAME_MAX 256 + +extern "C" { +// sort returned fontconfig font names +static int name_sort(const void *aa, const void *bb) { + // What should we do here? Just do a string compare for now... + // NOTE: This yeilds some oddities - in particular a Blah Bold font will be + // listed before Blah... + // Also - the fontconfig listing returns some faces that are effectively duplicates + // as far as fltk is concerned, e.g. where there are ko or ja variants that we + // can't distinguish (since we are not yet fully UTF-*) - should we strip them here? + return fl_ascii_strcasecmp(*(char**)aa, *(char**)bb); +} // end of name_sort +} // end of extern C section + + +// Read the "pretty" name we have derived from fontconfig then convert +// it into the format fltk uses internally for Xft names... +// This is just a mess - I should have tokenised the strings and gone from there, +// but I really thought this would be easier! +static void make_raw_name(char *raw, char *pretty) +{ + // Input name will be "Some Name:style = Bold Italic" or whatever + // The plan is this: + // - the first char in the "raw" name becomes either I, B, P or " " for + // italic, bold, bold italic or normal - this seems to be the fltk way... + + char *style = strchr(pretty, ':'); + + if (style) + { + *style = 0; // Terminate "name" string + style ++; // point to start of style section + } + + // It is still possible that the "pretty" name has multiple comma separated entries + // I've seen this often in CJK fonts, for example... Keep only the first one... This + // is not ideal, the CJK fonts often have the name in utf8 in several languages. What + // we ought to do is use fontconfig to query the available languages and pick one... But which? +#if 0 // loop to keep the LAST name entry... + char *nm1 = pretty; + char *nm2 = strchr(nm1, ','); + while(nm2) { + nm1 = nm2 + 1; + nm2 = strchr(nm1, ','); + } + raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text + strncat(raw, nm1, LOCAL_RAW_NAME_MAX-1); // only copy MAX-1 chars, we have already set cell 0 + // Ensure raw is terminated, just in case the given name is infeasibly long... + raw[LOCAL_RAW_NAME_MAX-1] = 0; +#else // keep the first remaining name entry + char *nm2 = strchr(pretty, ','); + if(nm2) *nm2 = 0; // terminate name after first entry + raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text + strncat(raw, pretty, LOCAL_RAW_NAME_MAX-1); // only copy MAX-1 chars, we have already set cell 0 + // Ensure raw is terminated, just in case the given name is infeasibly long... + raw[LOCAL_RAW_NAME_MAX-1] = 0; +#endif + // At this point, the name is "marked" as regular... + if (style) + { +#define PLAIN 0 +#define BOLD 1 +#define ITALIC 2 +#define BITALIC (BOLD | ITALIC) + + int mods = PLAIN; + char *last = style + strlen(style) - 2; + + // Now try and parse the style string - look for the "=" sign + style = strchr(style, '='); + while ((style) && (style < last)) + { + int type; + while ((*style == '=') || (*style == ' ') || (*style == '\t') || (*style == ',')) + { + style++; // Start of Style string + if ((style >= last) || (*style == 0)) continue; + } + type = toupper(style[0]); + switch (type) + { + // Things we might see: Regular Normal Bold Italic Oblique (??what??) Medium + // Roman Light Demi Sans SemiCondensed SuperBold Book... etc... + // Things we actually care about: Bold Italic Oblique SuperBold - Others??? + case 'I': + if (strncasecmp(style, "Italic", 6) == 0) + { + mods |= ITALIC; + } + goto NEXT_STYLE; + + case 'B': + if (strncasecmp(style, "Bold", 4) == 0) + { + mods |= BOLD; + } + goto NEXT_STYLE; + + case 'O': + if (strncasecmp(style, "Oblique", 7) == 0) + { + mods |= ITALIC; + } + goto NEXT_STYLE; + + case 'S': + if (strncasecmp(style, "SuperBold", 9) == 0) + { + mods |= BOLD; + } + goto NEXT_STYLE; + + default: // find the next gap + goto NEXT_STYLE; + } // switch end +NEXT_STYLE: + while ((*style != ' ') && (*style != '\t') && (*style != ',')) + { + style++; + if ((style >= last) || (*style == 0)) goto STYLE_DONE; + } + } +STYLE_DONE: + // Set the "modifier" character in the raw string + switch(mods) + { + case BOLD: raw[0] = 'B'; + break; + case ITALIC: raw[0] = 'I'; + break; + case BITALIC: raw[0] = 'P'; + break; + default: raw[0] = ' '; + break; + } + } +} // make_raw_name + +/////////////////////////////////////////////////////////// + +static int fl_free_font = FL_FREE_FONT; + +// Uses the fontconfig lib to construct a list of all installed fonts. +// I tried using XftListFonts for this, but the API is tricky - and when +// I looked at the XftList* code, it calls the Fc* functions anyway, so... +// +// Also, for now I'm ignoring the "pattern_name" and just getting everything... +// AND I don't try and skip the fonts we've already loaded in the defaults. +// Blimey! What a hack! +Fl_Font Fl::set_fonts(const char* pattern_name) +{ + FcFontSet *fnt_set; // Will hold the list of fonts we find + FcPattern *fnt_pattern; // Holds the generic "match all names" pattern + FcObjectSet *fnt_obj_set = 0; // Holds the generic "match all objects" + + int j; // loop iterator variable + int font_count; // Total number of fonts found to process + char **full_list; // The list of font names we build + + if (fl_free_font > FL_FREE_FONT) // already been here + return (Fl_Font)fl_free_font; + + fl_open_display(); // Just in case... + + // Make sure fontconfig is ready... is this necessary? The docs say it is + // safe to call it multiple times, so just go for it anyway! + if (!FcInit()) + { + // What to do? Just return defaults... + return FL_FREE_FONT; + } + + // Create a search pattern that will match every font name - I think this + // does the Right Thing, but am not certain... + // + // This could possibly be "enhanced" to pay attention to the requested + // "pattern_name"? + fnt_pattern = FcPatternCreate(); + fnt_obj_set = FcObjectSetBuild(FC_FAMILY, FC_STYLE, (void *)0); + + // Hopefully, this is a set of all the fonts... + fnt_set = FcFontList(0, fnt_pattern, fnt_obj_set); + + // We don't need the fnt_pattern and fnt_obj_set any more, release them + FcPatternDestroy(fnt_pattern); + FcObjectSetDestroy(fnt_obj_set); + + // Now, if we got any fonts, iterate through them... + if (fnt_set) + { + char *stop; + char *start; + char *first; + + font_count = fnt_set->nfont; // How many fonts? + + // Allocate array of char*'s to hold the name strings + full_list = (char **)malloc(sizeof(char *) * font_count); + + // iterate through all the font patterns and get the names out... + for (j = 0; j < font_count; j++) + { + // NOTE: FcChar8 is a typedef of "unsigned char"... + FcChar8 *font; // String to hold the font's name + + // Convert from fontconfig internal pattern to human readable name + // NOTE: This WILL malloc storage, so we need to free it later... + font = FcNameUnparse(fnt_set->fonts[j]); + + // The returned strings look like this... + // Century Schoolbook:style=Bold Italic,fed kursiv,Fett Kursiv,... + // So the bit we want is up to the first comma - BUT some strings have + // more than one name, separated by, guess what?, a comma... + stop = start = first = 0; + stop = strchr((char *)font, ','); + start = strchr((char *)font, ':'); + if ((stop) && (start) && (stop < start)) + { + first = stop + 1; // discard first version of name + // find first comma *after* the end of the name + stop = strchr((char *)start, ','); + } + else + { + first = (char *)font; // name is just what was returned + } + // Truncate the name after the (english) modifiers description + // Matt: Actually, there is no guarantee that the *first* description is the English one. + // Matt: So we keep the entire description, just in case. + //if (stop) + //{ + // *stop = 0; // Terminate the string at the first comma, if there is one + //} + + // Copy the font description into our list + if (first == (char *)font) + { // The listed name is still OK + full_list[j] = (char *)font; + } + else + { // The listed name has been modified + full_list[j] = strdup(first); + // Free the font name storage + free (font); + } + // replace "style=Regular" so strcmp sorts it first + if (start) { + char *reg = strstr(full_list[j], "=Regular"); + if (reg) reg[1]='.'; + } + } + + // Release the fnt_set - we don't need it any more + FcFontSetDestroy(fnt_set); + + // Sort the list into alphabetic order + qsort(full_list, font_count, sizeof(*full_list), name_sort); + + // Now let us add the names we got to fltk's font list... + for (j = 0; j < font_count; j++) + { + if (full_list[j]) + { + char xft_name[LOCAL_RAW_NAME_MAX]; + char *stored_name; + // Parse the strings into FLTK-XFT style.. + make_raw_name(xft_name, full_list[j]); + // NOTE: This just adds on AFTER the default fonts - no attempt is made + // to identify already loaded fonts. Is this bad? + stored_name = strdup(xft_name); + Fl::set_font((Fl_Font)(j + FL_FREE_FONT), stored_name); + fl_free_font ++; + + free(full_list[j]); // release that name from our internal array + } + } + // Now we are done with the list, release it fully + free(full_list); + } + return (Fl_Font)fl_free_font; +} // ::set_fonts +//////////////////////////////////////////////////////////////// + + +extern "C" { +static int int_sort(const void *aa, const void *bb) { + return (*(int*)aa)-(*(int*)bb); +} +} + +//////////////////////////////////////////////////////////////// + +// Return all the point sizes supported by this font: +// Suprisingly enough Xft works exactly like fltk does and returns +// the same list. Except there is no way to tell if the font is scalable. +int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { + Fl_Fontdesc *s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 + + fl_open_display(); + XftFontSet* fs = XftListFonts(fl_display, fl_screen, + XFT_FAMILY, XftTypeString, s->name+1, + (void *)0, + XFT_PIXEL_SIZE, + (void *)0); + static int* array = 0; + static int array_size = 0; + if (fs->nfont >= array_size) { + delete[] array; + array = new int[array_size = fs->nfont+1]; + } + array[0] = 0; int j = 1; // claim all fonts are scalable + for (int i = 0; i < fs->nfont; i++) { + double v; + if (XftPatternGetDouble(fs->fonts[i], XFT_PIXEL_SIZE, 0, &v) == XftResultMatch) { + array[j++] = int(v); + } + } + qsort(array+1, j-1, sizeof(int), int_sort); + XftFontSetDestroy(fs); + sizep = array; + return j; +} + +// +// End of "$Id$". +// +// +// "$Id$" +// +// Xft font code for the Fast Light Tool Kit (FLTK). +// +// Copyright 2001-2011 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// +// Draw fonts using Keith Packard's Xft library to provide anti- +// aliased text. Yow! +// +// Many thanks to Carl for making the original version of this. +// +// This font code only requires libXft to work. Contrary to popular +// belief there is no need to have FreeType, or the Xrender extension +// available to use this code. You will just get normal Xlib fonts +// (Xft calls them "core" fonts) The Xft algorithms for choosing +// these is about as good as the FLTK ones (I hope to fix it so it is +// exactly as good...), plus it can cache its results and share them +// between programs, so using this should be a win in all cases. Also +// it should be obvious by comparing this file and fl_font_x.cxx that +// it is a lot easier to program with Xft than with Xlib. +// +// Also, Xft supports UTF-8 text rendering directly, which will allow +// us to support UTF-8 on all platforms more easily. +// +// To actually get antialiasing you need the following: +// +// 1. You have XFree86 4 +// 2. You have the XRender extension +// 3. Your X device driver supports the render extension +// 4. You have libXft +// 5. Your libXft has FreeType2 support compiled in +// 6. You have the FreeType2 library +// +// Distributions that have XFree86 4.0.3 or later should have all of this... +// +// Unlike some other Xft packages, I tried to keep this simple and not +// to work around the current problems in Xft by making the "patterns" +// complicated. I believe doing this defeats our ability to improve Xft +// itself. You should edit the ~/.xftconfig file to "fix" things, there +// are several web pages of information on how to do this. +// +#ifndef FL_DOXYGEN + +#include + +#include + +// The predefined fonts that FLTK has: +static Fl_Fontdesc built_in_table[] = { +#if 1 +{" sans"}, +{"Bsans"}, +{"Isans"}, +{"Psans"}, +{" mono"}, +{"Bmono"}, +{"Imono"}, +{"Pmono"}, +{" serif"}, +{"Bserif"}, +{"Iserif"}, +{"Pserif"}, +{" symbol"}, +{" screen"}, +{"Bscreen"}, +{" zapf dingbats"}, +#else +{" helvetica"}, +{"Bhelvetica"}, +{"Ihelvetica"}, +{"Phelvetica"}, +{" courier"}, +{"Bcourier"}, +{"Icourier"}, +{"Pcourier"}, +{" times"}, +{"Btimes"}, +{"Itimes"}, +{"Ptimes"}, +{" symbol"}, +{" lucidatypewriter"}, +{"Blucidatypewriter"}, +{" zapf dingbats"}, +#endif +}; + +Fl_Fontdesc* fl_fonts = built_in_table; + +Fl_XFont_On_Demand fl_xfont; +void *fl_xftfont = 0; +//static const char* fl_encoding_ = "iso8859-1"; +static const char* fl_encoding_ = "iso10646-1"; + +static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, int angle) { + if (fnum==-1) { // special case to stop font caching + driver->Fl_Graphics_Driver::font(0, 0); + return; + } + Fl_Font_Descriptor* f = driver->font_descriptor(); + if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size() && f && f->angle == angle) + return; + driver->Fl_Graphics_Driver::font(fnum, size); + Fl_Fontdesc *font = fl_fonts + fnum; + // search the fontsizes we have generated already + for (f = font->first; f; f = f->next) { + if (f->size == size && f->angle == angle)// && !strcasecmp(f->encoding, fl_encoding_)) + break; + } + if (!f) { + f = new Fl_Font_Descriptor(font->name, size, angle); + f->next = font->first; + font->first = f; + } + driver->font_descriptor(f); +#if XFT_MAJOR < 2 + fl_xfont = f->font->u.core.font; +#else + fl_xfont = NULL; // invalidate +#endif // XFT_MAJOR < 2 + fl_xftfont = (void*)f->font; +} + +void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { + fl_xft_font(this,fnum,size,0); +} + +static XftFont* fontopen(const char* name, Fl_Fontsize size, bool core, int angle) { + // Check: does it look like we have been passed an old-school XLFD fontname? + bool is_xlfd = false; + int hyphen_count = 0; + int comma_count = 0; + unsigned len = strlen(name); + if (len > 512) len = 512; // ensure we are not passed an unbounded font name + for(unsigned idx = 0; idx < len; idx++) { + if(name[idx] == '-') hyphen_count++; // check for XLFD hyphens + if(name[idx] == ',') comma_count++; // are there multiple names? + } + if(hyphen_count >= 14) is_xlfd = true; // Not a robust check, but good enough? + + fl_open_display(); + + if(!is_xlfd) { // Not an XLFD - open as a XFT style name + XftFont *the_font = NULL; // the font we will return; + XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for matching + int slant = XFT_SLANT_ROMAN; + int weight = XFT_WEIGHT_MEDIUM; + + /* This "converts" FLTK-style font names back into "regular" names, extracting + * the BOLD and ITALIC codes as it does so - all FLTK font names are prefixed + * by 'I' (italic) 'B' (bold) 'P' (bold italic) or ' ' (regular) modifiers. + * This gives a fairly limited font selection ability, but is retained for + * compatibility reasons. If you really need a more complex choice, you are best + * calling Fl::set_fonts(*) then selecting the font by font-index rather than by + * name anyway. Probably. + * If you want to load a font who's name does actually begin with I, B or P, you + * MUST use a leading space OR simply use lowercase for the name... + */ + /* This may be efficient, but it is non-obvious. */ + switch (*name++) { + case 'I': slant = XFT_SLANT_ITALIC; break; // italic + case 'P': slant = XFT_SLANT_ITALIC; // bold-italic (falls-through) + case 'B': weight = XFT_WEIGHT_BOLD; break; // bold + case ' ': break; // regular + default: name--; // no prefix, restore name + } + + if(comma_count) { // multiple comma-separated names were passed + char *local_name = strdup(name); // duplicate the full name so we can edit the copy + char *curr = local_name; // points to first name in string + char *nxt; // next name in string + do { + nxt = strchr(curr, ','); // find comma separator + if (nxt) { + *nxt = 0; // terminate first name + nxt++; // first char of next name + } + + // Add the current name to the match pattern + XftPatternAddString(fnt_pat, XFT_FAMILY, curr); + + if(nxt) curr = nxt; // move onto next name (if it exists) + // Now do a cut-down version of the FLTK name conversion. + // NOTE: we only use the slant and weight of the first name, + // subsequent names we ignore this for... But we still need to do the check. + switch (*curr++) { + case 'I': break; // italic + case 'P': // bold-italic (falls-through) + case 'B': break; // bold + case ' ': break; // regular + default: curr--; // no prefix, restore name + } + + comma_count--; // decrement name sections count + } while (comma_count >= 0); + free(local_name); // release our local copy of font names + } + else { // single name was passed - add it directly + XftPatternAddString(fnt_pat, XFT_FAMILY, name); + } + + // Construct a match pattern for the font we want... + XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight); + XftPatternAddInteger(fnt_pat, XFT_SLANT, slant); + XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)size); + XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_); + + // rotate font if angle!=0 + if (angle !=0) { + XftMatrix m; + XftMatrixInit(&m); + XftMatrixRotate(&m,cos(M_PI*angle/180.),sin(M_PI*angle/180.)); + XftPatternAddMatrix (fnt_pat, XFT_MATRIX,&m); + } + + if (core) { + XftPatternAddBool(fnt_pat, XFT_CORE, FcTrue); + XftPatternAddBool(fnt_pat, XFT_RENDER, FcFalse); + } + + XftPattern *match_pat; // the best available match on the system + XftResult match_result; // the result of our matching attempt + + // query the system to find a match for this font + match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result); + +#if 0 // the XftResult never seems to get set to anything... abandon this code? + switch(match_result) { // how good a match is this font for our request? + case XftResultMatch: + puts("Object exists with the specified ID"); + break; + + case XftResultTypeMismatch: + puts("Object exists, but the type does not match"); + break; + + case XftResultNoId: + puts("Object exists, but has fewer values than specified"); + break; + + case FcResultOutOfMemory: + puts("FcResult: Malloc failed"); + break; + + case XftResultNoMatch: + puts("Object does not exist at all"); + break; + + default: + printf("Invalid XftResult status %d \n", match_result); + break; + } +#endif + +#if 0 // diagnostic to print the "full name" of the font we matched. This works. + FcChar8 *picked_name = FcNameUnparse(match_pat); + printf("Match: %s\n", picked_name); + free(picked_name); +#endif + + // open the matched font + if (match_pat) the_font = XftFontOpenPattern(fl_display, match_pat); + + if (!match_pat || !the_font) { + // last chance, just open any font in the right size + the_font = XftFontOpen (fl_display, fl_screen, + XFT_FAMILY, XftTypeString, "sans", + XFT_SIZE, XftTypeDouble, (double)size, + NULL); + XftPatternDestroy(fnt_pat); + if (!the_font) { + Fl::error("Unable to find fonts. Check your FontConfig configuration.\n"); + exit(1); + } + return the_font; + } + +#if 0 // diagnostic to print the "full name" of the font we actually opened. This works. + FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern); + printf("Open : %s\n", picked_name2); + free(picked_name2); +#endif + + XftPatternDestroy(fnt_pat); +// XftPatternDestroy(match_pat); // FontConfig will destroy this resource for us. We must not! + + return the_font; + } + else { // We were passed a font name in XLFD format + /* OksiD's X font code could handle being passed a comma separated list + * of XLFD's. It then attempted to find which font was "best" from this list. + * But XftFontOpenXlfd can not do this, so if a list is passed, we just + * terminate it at the first comma. + * A "better" solution might be to use XftXlfdParse() on each of the passed + * XLFD's to construct a "super-pattern" that incorporates attributes from all + * XLFD's and use that to perform a XftFontMatch(). Maybe... + */ + char *local_name = strdup(name); + if(comma_count) { // This means we were passed multiple XLFD's + char *pc = strchr(local_name, ','); + *pc = 0; // terminate the XLFD at the first comma + } + XftFont *the_font = XftFontOpenXlfd(fl_display, fl_screen, local_name); + free(local_name); +#if 0 // diagnostic to print the "full name" of the font we actually opened. This works. +puts("Font Opened"); fflush(stdout); + FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern); + printf("Open : %s\n", picked_name2); fflush(stdout); + free(picked_name2); +#endif + return the_font; + } +} // end of fontopen + +Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize fsize, int fangle) { +// encoding = fl_encoding_; + size = fsize; + angle = fangle; +#if HAVE_GL + listbase = 0; +#endif // HAVE_GL + font = fontopen(name, fsize, false, angle); +} + +Fl_Font_Descriptor::~Fl_Font_Descriptor() { + if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL); +// XftFontClose(fl_display, font); +} + +/* decodes the input UTF-8 string into a series of wchar_t characters. + n is set upon return to the number of characters. + Don't deallocate the returned memory. + */ +static const wchar_t *utf8reformat(const char *str, int& n) +{ + static const wchar_t empty[] = {0}; + static wchar_t *buffer; + static int lbuf = 0; + int newn; + if (n == 0) return empty; + newn = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf); + if (newn >= lbuf) { + lbuf = newn + 100; + if (buffer) free(buffer); + buffer = (wchar_t*)malloc(lbuf * sizeof(wchar_t)); + n = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf); + } else { + n = newn; + } + return buffer; +} + +static void utf8extents(Fl_Font_Descriptor *desc, const char *str, int n, XGlyphInfo *extents) +{ + memset(extents, 0, sizeof(XGlyphInfo)); + const wchar_t *buffer = utf8reformat(str, n); +#ifdef __CYGWIN__ + XftTextExtents16(fl_display, desc->font, (XftChar16 *)buffer, n, extents); +#else + XftTextExtents32(fl_display, desc->font, (XftChar32 *)buffer, n, extents); +#endif +} + +int Fl_Xlib_Graphics_Driver::height() { + if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent; + else return -1; +} + +int Fl_Xlib_Graphics_Driver::descent() { + if (font_descriptor()) return font_descriptor()->font->descent; + else return -1; +} + +double Fl_Xlib_Graphics_Driver::width(const char* str, int n) { + if (!font_descriptor()) return -1.0; + XGlyphInfo i; + utf8extents(font_descriptor(), str, n, &i); + return i.xOff; +} + +/*double fl_width(uchar c) { + return fl_graphics_driver->width((const char *)(&c), 1); +}*/ + +static double fl_xft_width(Fl_Font_Descriptor *desc, FcChar32 *str, int n) { + if (!desc) return -1.0; + XGlyphInfo i; + XftTextExtents32(fl_display, desc->font, str, n, &i); + return i.xOff; +} + +double Fl_Xlib_Graphics_Driver::width(unsigned int c) { + return fl_xft_width(font_descriptor(), (FcChar32 *)(&c), 1); +} + +void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { + if (!font_descriptor()) { + w = h = 0; + dx = dy = 0; + return; + } + XGlyphInfo gi; + utf8extents(font_descriptor(), c, n, &gi); + + w = gi.width; + h = gi.height; + dx = -gi.x; + dy = -gi.y; +} // fl_text_extents + + +/* This code is used (mainly by opengl) to get a bitmapped font. The + * original XFT-1 code used XFT's "core" fonts methods to load an XFT + * font that was actually a X-bitmap font, that could then be readily + * used with GL. But XFT-2 does not provide that ability, and there + * is no easy method to use an XFT font directly with GL. So... +*/ + +# if XFT_MAJOR > 1 +// This function attempts, on XFT2 systems, to find a suitable "core" Xfont +// for GL or other bitmap font needs (we dont have an XglUseXftFont(...) function.) +// There's probably a better way to do this. I can't believe it is this hard... +// Anyway... This code attempts to make an XLFD out of the fltk-style font +// name it is passed, then tries to load that font. Surprisingly, this quite +// often works - boxes that have XFT generally also have a fontserver that +// can serve TTF and other fonts to X, and so the font name that fltk makes +// from the XFT name often also "exists" as an "core" X font... +// If this code fails to load the requested font, it falls back through a +// series of tried 'n tested alternatives, ultimately resorting to what the +// original fltk code did. +// NOTE: On my test boxes (FC6, FC7, FC8, ubuntu8.04, 9.04, 9.10) this works +// well for the fltk "built-in" font names. +static XFontStruct* load_xfont_for_xft2(Fl_Graphics_Driver *driver) { + XFontStruct* xgl_font = 0; + int size = driver->size(); + int fnum = driver->font(); + const char *wt_med = "medium"; + const char *wt_bold = "bold"; + const char *weight = wt_med; // no specifc weight requested - accept any + char slant = 'r'; // regular non-italic by default + char xlfd[128]; // we will put our synthetic XLFD in here + char *pc = strdup(fl_fonts[fnum].name); // what font were we asked for? + const char *name = pc; // keep a handle to the original name for freeing later + // Parse the "fltk-name" of the font + switch (*name++) { + case 'I': slant = 'i'; break; // italic + case 'P': slant = 'i'; // bold-italic (falls-through) + case 'B': weight = wt_bold; break; // bold + case ' ': break; // regular + default: name--; // no prefix, restore name + } + + // first, we do a query with no prefered size, to see if the font exists at all + snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-*-*-*-*-*-*-*", name, weight, slant); // make up xlfd style name + xgl_font = XLoadQueryFont(fl_display, xlfd); + if(xgl_font) { // the face exists, but can we get it in a suitable size? + XFreeFont(fl_display, xgl_font); // release the non-sized version + snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10)); + xgl_font = XLoadQueryFont(fl_display, xlfd); // attempt to load the font at the right size + } +//puts(xlfd); + + // try alternative names + if (!xgl_font) { + if (!strcmp(name, "sans")) { + name = "helvetica"; + } else if (!strcmp(name, "mono")) { + name = "courier"; + } else if (!strcmp(name, "serif")) { + name = "times"; + } else if (!strcmp(name, "screen")) { + name = "lucidatypewriter"; + } else if (!strcmp(name, "dingbats")) { + name = "zapf dingbats"; + } + snprintf(xlfd, 128, "-*-*%s*-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10)); + xgl_font = XLoadQueryFont(fl_display, xlfd); + } + free(pc); // release our copy of the font name + + // if we have nothing loaded, try a generic proportional font + if(!xgl_font) { + snprintf(xlfd, 128, "-*-helvetica-*-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10)); + xgl_font = XLoadQueryFont(fl_display, xlfd); + } + // If that still didn't work, try this instead + if(!xgl_font) { + snprintf(xlfd, 128, "-*-courier-medium-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10)); + xgl_font = XLoadQueryFont(fl_display, xlfd); + } +//printf("glf: %d\n%s\n%s\n", size, xlfd, fl_fonts[fl_font_].name); +//if(xgl_font) puts("ok"); + + // Last chance fallback - this usually loads something... + if (!xgl_font) xgl_font = XLoadQueryFont(fl_display, "fixed"); + + return xgl_font; +} // end of load_xfont_for_xft2 +# endif + +static XFontStruct* fl_xxfont(Fl_Graphics_Driver *driver) { +# if XFT_MAJOR > 1 + // kludge! XFT 2 and later does not provide core fonts for us to use with GL + // try to load a bitmap X font instead + static XFontStruct* xgl_font = 0; + static int glsize = 0; + static int glfont = -1; + // Do we need to load a new font? + if ((!xgl_font) || (glsize != driver->size()) || (glfont != driver->font())) { + // create a dummy XLFD for some font of the appropriate size... + if (xgl_font) XFreeFont(fl_display, xgl_font); // font already loaded, free it - this *might* be a Bad Idea + glsize = driver->size(); // record current font size + glfont = driver->font(); // and face + xgl_font = load_xfont_for_xft2(driver); + } + return xgl_font; +# else // XFT-1 provides a means to load a "core" font directly + if (driver->font_descriptor()->font->core) { + return driver->font_descriptor()->font->u.core.font; // is the current font a "core" font? If so, use it. + } + static XftFont* xftfont; + if (xftfont) XftFontClose (fl_display, xftfont); + xftfont = fontopen(fl_fonts[driver->font()].name, driver->size(), true, 0); // else request XFT to load a suitable "core" font instead. + return xftfont->u.core.font; +# endif // XFT_MAJOR > 1 +} + +XFontStruct* Fl_XFont_On_Demand::value() { + if (!ptr) ptr = fl_xxfont(fl_graphics_driver); + return ptr; +} + +#if USE_OVERLAY +// Currently Xft does not work with colormapped visuals, so this probably +// does not work unless you have a true-color overlay. +extern bool fl_overlay; +extern Colormap fl_overlay_colormap; +extern XVisualInfo* fl_overlay_visual; +#endif + +// For some reason Xft produces errors if you destroy a window whose id +// still exists in an XftDraw structure. It would be nice if this is not +// true, a lot of junk is needed to try to stop this: + +static XftDraw* draw_; +static Window draw_window; +#if USE_OVERLAY +static XftDraw* draw_overlay; +static Window draw_overlay_window; +#endif + +void fl_destroy_xft_draw(Window id) { + if (id == draw_window) + XftDrawChange(draw_, draw_window = fl_message_window); +#if USE_OVERLAY + if (id == draw_overlay_window) + XftDrawChange(draw_overlay, draw_overlay_window = fl_message_window); +#endif +} + +void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) { + if ( !this->font_descriptor() ) { + this->font(FL_HELVETICA, FL_NORMAL_SIZE); + } +#if USE_OVERLAY + XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_; + if (fl_overlay) { + if (!draw_) + draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window, + fl_overlay_visual->visual, fl_overlay_colormap); + else //if (draw_overlay_window != fl_window) + XftDrawChange(draw_, draw_overlay_window = fl_window); + } else +#endif + if (!draw_) + draw_ = XftDrawCreate(fl_display, draw_window = fl_window, + fl_visual->visual, fl_colormap); + else //if (draw_window != fl_window) + XftDrawChange(draw_, draw_window = fl_window); + + Region region = fl_clip_region(); + if (region && XEmptyRegion(region)) return; + XftDrawSetClip(draw_, region); + + // Use fltk's color allocator, copy the results to match what + // XftCollorAllocValue returns: + XftColor color; + color.pixel = fl_xpixel(Fl_Graphics_Driver::color()); + uchar r,g,b; Fl::get_color(Fl_Graphics_Driver::color(), r,g,b); + color.color.red = ((int)r)*0x101; + color.color.green = ((int)g)*0x101; + color.color.blue = ((int)b)*0x101; + color.color.alpha = 0xffff; + + const wchar_t *buffer = utf8reformat(str, n); +#ifdef __CYGWIN__ + XftDrawString16(draw_, &color, font_descriptor()->font, x, y, (XftChar16 *)buffer, n); +#else + XftDrawString32(draw_, &color, font_descriptor()->font, x, y, (XftChar32 *)buffer, n); +#endif +} + +void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { + fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), angle); + this->draw(str, n, (int)x, (int)y); + fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), 0); +} + +static void fl_drawUCS4(Fl_Graphics_Driver *driver, const FcChar32 *str, int n, int x, int y) { +#if USE_OVERLAY + XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_; + if (fl_overlay) { + if (!draw_) + draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window, + fl_overlay_visual->visual, fl_overlay_colormap); + else //if (draw_overlay_window != fl_window) + XftDrawChange(draw_, draw_overlay_window = fl_window); + } else +#endif + if (!draw_) + draw_ = XftDrawCreate(fl_display, draw_window = fl_window, + fl_visual->visual, fl_colormap); + else //if (draw_window != fl_window) + XftDrawChange(draw_, draw_window = fl_window); + + Region region = fl_clip_region(); + if (region && XEmptyRegion(region)) return; + XftDrawSetClip(draw_, region); + + // Use fltk's color allocator, copy the results to match what + // XftCollorAllocValue returns: + XftColor color; + color.pixel = fl_xpixel(driver->color()); + uchar r,g,b; Fl::get_color(driver->color(), r,g,b); + color.color.red = ((int)r)*0x101; + color.color.green = ((int)g)*0x101; + color.color.blue = ((int)b)*0x101; + color.color.alpha = 0xffff; + + XftDrawString32(draw_, &color, driver->font_descriptor()->font, x, y, (FcChar32 *)str, n); +} + + +void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { + +#if defined(__GNUC__) +// FIXME: warning Need to improve this XFT right to left draw function +#endif /*__GNUC__*/ + +// This actually draws LtoR, but aligned to R edge with the glyph order reversed... +// but you can't just byte-rev a UTF-8 string, that isn't valid. +// You can reverse a UCS4 string though... + int num_chars, wid, utf_len = strlen(c); + FcChar8 *u8 = (FcChar8 *)c; + FcBool valid = FcUtf8Len(u8, utf_len, &num_chars, &wid); + if (!valid) + { + // badly formed Utf-8 input string + return; + } + if (num_chars < n) n = num_chars; // limit drawing to usable characters in input array + FcChar32 *ucs_txt = new FcChar32[n+1]; + FcChar32* pu; + int out, sz; + ucs_txt[n] = 0; + out = n-1; + while ((out >= 0) && (utf_len > 0)) + { + pu = &ucs_txt[out]; + sz = FcUtf8ToUcs4(u8, pu, utf_len); + utf_len = utf_len - sz; + u8 = u8 + sz; + out = out - 1; + } + // Now we have a UCS4 version of the input text, reversed, in ucs_txt + int offs = (int)fl_xft_width(font_descriptor(), ucs_txt, n); + fl_drawUCS4(this, ucs_txt, n, (x-offs), y); + + delete[] ucs_txt; +} +#endif + +// +// End of "$Id$" +// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx new file mode 100644 index 000000000..a20ace778 --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx @@ -0,0 +1,71 @@ +// +// "$Id$" +// +// Line style code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2016 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#ifndef FL_CFG_GFX_XLIB_LINE_STYLE_CXX +#define FL_CFG_GFX_XLIB_LINE_STYLE_CXX + +/** + \file xlib_line_style.cxx + \brief Line style drawing utility hiding different platforms. +*/ + +#include "Fl_Xlib_Graphics_Driver.h" + +void Fl_Xlib_Graphics_Driver::line_style(int style, int width, char* dashes) { + + // save line width in global variable for X11 clipping + if (width == 0) fl_line_width_ = 1; + else fl_line_width_ = width>0 ? width : -width; + + int ndashes = dashes ? strlen(dashes) : 0; + // emulate the WIN32 dash patterns on X + char buf[7]; + if (!ndashes && (style&0xff)) { + int w = width ? width : 1; + char dash, dot, gap; + // adjust lengths to account for cap: + if (style & 0x200) { + dash = char(2*w); + dot = 1; // unfortunately 0 does not work + gap = char(2*w-1); + } else { + dash = char(3*w); + dot = gap = char(w); + } + char* p = dashes = buf; + switch (style & 0xff) { + case FL_DASH: *p++ = dash; *p++ = gap; break; + case FL_DOT: *p++ = dot; *p++ = gap; break; + case FL_DASHDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; break; + case FL_DASHDOTDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; *p++ = dot; *p++ = gap; break; + } + ndashes = p-buf; + } + static int Cap[4] = {CapButt, CapButt, CapRound, CapProjecting}; + static int Join[4] = {JoinMiter, JoinMiter, JoinRound, JoinBevel}; + XSetLineAttributes(fl_display, fl_gc, width, + ndashes ? LineOnOffDash : LineSolid, + Cap[(style>>8)&3], Join[(style>>12)&3]); + if (ndashes) XSetDashes(fl_display, fl_gc, 0, dashes, ndashes); +} + +#endif // FL_CFG_GFX_XLIB_LINE_STYLE_CXX + +// +// End of "$Id$". +// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx new file mode 100644 index 000000000..225b578d1 --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx @@ -0,0 +1,339 @@ +// +// "$Id$" +// +// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2012 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + + +#ifndef FL_CFG_GFX_XLIB_RECT_CXX +#define FL_CFG_GFX_XLIB_RECT_CXX + + +/** + \file xlib_rect.cxx + \brief X11 Xlib specific line and polygon drawing with integer coordinates. + */ + + +#include "Fl_Xlib_Graphics_Driver.h" + + +#ifndef SHRT_MAX +#define SHRT_MAX (32767) +#endif + +/* + We need to check some coordinates for areas for clipping before we + use X functions, because X can't handle coordinates outside the 16-bit + range. Since all windows use relative coordinates > 0, we do also + check for negative values. X11 only, see also STR #2304. + + Note that this is only necessary for large objects, where only a + part of the object is visible. The draw() functions (e.g. box + drawing) must be clipped correctly. This is usually only a matter + for large container widgets. The individual child widgets will be + clipped completely. + + We define the usable X coordinate space as [ -LW : SHRT_MAX - LW ] + where LW = current line width for drawing. This is done so that + horizontal and vertical line drawing works correctly, even in real + border cases, e.g. drawing a rectangle slightly outside the top left + window corner, but with a line width so that a part of the line should + be visible (in this case 2 of 5 pixels): + + fl_line_style (FL_SOLID,5); // line width = 5 + fl_rect (-1,-1,100,100); // top/left: 2 pixels visible + + In this example case, no clipping would be done, because X can + handle it and clip unneeded pixels. + + Note that we must also take care of the case where fl_line_width_ + is zero (maybe unitialized). If this is the case, we assume a line + width of 1. + + Todo: Arbitrary line drawings (e.g. polygons) and clip regions + are not yet done. + + Note: + + We could use max. screen coordinates instead of SHRT_MAX, but that + would need more work and would probably be slower. We assume that + all window coordinates are >= 0 and that no window extends up to + 32767 - LW (where LW = current line width). Thus it is safe to clip + all coordinates to this range before calling X functions. If this + is not true, then clip_to_short() and clip_x() must be redefined. + + It would be somewhat easier if we had fl_clip_w and fl_clip_h, as + defined in FLTK 2.0 (for the upper clipping bounds)... + */ + +/* + clip_to_short() returns 1, if the area is invisible (clipped), + because ... + + (a) w or h are <= 0 i.e. nothing is visible + (b) x+w or y+h are < kmin i.e. left of or above visible area + (c) x or y are > kmax i.e. right of or below visible area + + kmin and kmax are the minimal and maximal X coordinate values, + as defined above. In this case x, y, w, and h are not changed. + + It returns 0, if the area is potentially visible and X can handle + clipping. x, y, w, and h may have been adjusted to fit into the + X coordinate space. + + Use this for clipping rectangles, as used in fl_rect() and + fl_rectf(). + */ +static int clip_to_short(int &x, int &y, int &w, int &h) { + + int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; + int kmin = -lw; + int kmax = SHRT_MAX - lw; + + if (w <= 0 || h <= 0) return 1; // (a) + if (x+w < kmin || y+h < kmin) return 1; // (b) + if (x > kmax || y > kmax) return 1; // (c) + + if (x < kmin) { w -= (kmin-x); x = kmin; } + if (y < kmin) { h -= (kmin-y); y = kmin; } + if (x+w > kmax) w = kmax - x; + if (y+h > kmax) h = kmax - y; + + return 0; +} + +/* + clip_x() returns a coordinate value clipped to the 16-bit coordinate + space (see above). This can be used to draw horizontal and vertical + lines that can be handled by X11. Each single coordinate value can + be clipped individually, and the result can be used directly, e.g. + in fl_xyline() and fl_yxline(). Note that this can't be used for + arbitrary lines (not horizontal or vertical). + */ +static int clip_x (int x) { + + int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1; + int kmin = -lw; + int kmax = SHRT_MAX - lw; + + if (x < kmin) + x = kmin; + else if (x > kmax) + x = kmax; + return x; +} + +// Missing X call: (is this the fastest way to init a 1-rectangle region?) +// MSWindows equivalent exists, implemented inline in win32.H +Fl_Region XRectangleRegion(int x, int y, int w, int h) { + XRectangle R; + clip_to_short(x, y, w, h); + R.x = x; R.y = y; R.width = w; R.height = h; + Fl_Region r = XCreateRegion(); + XUnionRectWithRegion(&R, r, r); + return r; +} + +// --- line and polygon drawing with integer coordinates + +void Fl_Xlib_Graphics_Driver::point(int x, int y) { + XDrawPoint(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y)); +} + +void Fl_Xlib_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + if (!clip_to_short(x, y, w, h)) + XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1); +} + +void Fl_Xlib_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + if (!clip_to_short(x, y, w, h)) + XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h); +} + +void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1) { + XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1); +} + +void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[3]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1) { + XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x1), clip_x(y)); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + XPoint p[3]; + p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); + p[1].x = p[2].x = clip_x(x1); p[2].y = clip_x(y2); + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + XPoint p[4]; + p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y); + p[1].x = p[2].x = clip_x(x1); p[2].y = p[3].y = clip_x(y2); + p[3].x = clip_x(x3); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1) { + XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x), clip_x(y1)); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + XPoint p[3]; + p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); + p[1].y = p[2].y = clip_x(y1); p[2].x = clip_x(x2); + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +} + +void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + XPoint p[4]; + p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y); + p[1].y = p[2].y = clip_x(y1); p[2].x = p[3].x = clip_x(x2); + p[3].y = clip_x(y3); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x; p[3].y = y; + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[5]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + p[4].x = x; p[4].y = y; + XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); +} + +void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + XPoint p[4]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x; p[3].y = y; + XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0); + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +} + +void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + XPoint p[5]; + p[0].x = x; p[0].y = y; + p[1].x = x1; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x3; p[3].y = y3; + p[4].x = x; p[4].y = y; + XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0); + XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0); +} + +// --- clipping + +void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) { + Fl_Region r; + if (w > 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { + Fl_Region temp = XCreateRegion(); + XIntersectRegion(current, r, temp); + XDestroyRegion(r); + r = temp; + } + } else { // make empty clip region: + r = XCreateRegion(); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_Xlib_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; + switch (XRectInRegion(r, x, y, w, h)) { + case 0: // completely outside + W = H = 0; + return 2; + case 1: // completely inside: + return 0; + default: // partial: + break; + } + Fl_Region rr = XRectangleRegion(x,y,w,h); + Fl_Region temp = XCreateRegion(); + XIntersectRegion(r, rr, temp); + XRectangle rect; + XClipBox(temp, &rect); + X = rect.x; Y = rect.y; W = rect.width; H = rect.height; + XDestroyRegion(temp); + XDestroyRegion(rr); + return 1; +} + +int Fl_Xlib_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; + if (!r) return 1; + // get rid of coordinates outside the 16-bit range the X calls take. + if (clip_to_short(x,y,w,h)) return 0; // clipped + return XRectInRegion(r, x, y, w, h); +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_Xlib_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("fl_push_no_cFl_Xlib_Graphics_Driver::push_no_cliplip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_Xlib_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_Xlib_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_Xlib_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + if (r) XSetRegion(fl_display, fl_gc, r); + else XSetClipMask(fl_display, fl_gc, 0); +} + +#endif // FL_CFG_GFX_XLIB_RECT_CXX + +// +// End of "$Id$". +// diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx new file mode 100644 index 000000000..4c559ad8c --- /dev/null +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx @@ -0,0 +1,116 @@ +// +// "$Id$" +// +// Portable drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2016 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: +// +// http://www.fltk.org/COPYING.php +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#ifndef FL_CFG_GFX_XLIB_VERTEX_CXX +#define FL_CFG_GFX_XLIB_VERTEX_CXX + +/** + \file xlib_vertex.cxx + \brief Portable drawing code for drawing arbitrary shapes with + simple 2D transformations, implemented for X11 Xlib. + */ + +#include "Fl_Xlib_Graphics_Driver.h" + +#include +#include +#include + + +void Fl_Xlib_Graphics_Driver::transformed_vertex(double xf, double yf) { + transformed_vertex0(COORD_T(rint(xf)), COORD_T(rint(yf))); +} + +void Fl_Xlib_Graphics_Driver::vertex(double x,double y) { + transformed_vertex0(COORD_T(x*m.a + y*m.c + m.x), COORD_T(x*m.b + y*m.d + m.y)); +} + +void Fl_Xlib_Graphics_Driver::end_points() { + if (n>1) XDrawPoints(fl_display, fl_window, fl_gc, p, n, 0); +} + +void Fl_Xlib_Graphics_Driver::end_line() { + if (n < 2) { + end_points(); + return; + } + if (n>1) XDrawLines(fl_display, fl_window, fl_gc, p, n, 0); +} + +void Fl_Xlib_Graphics_Driver::end_loop() { + fixloop(); + if (n>2) transformed_vertex((COORD_T)p[0].x, (COORD_T)p[0].y); + end_line(); +} + +void Fl_Xlib_Graphics_Driver::end_polygon() { + fixloop(); + if (n < 3) { + end_line(); + return; + } + if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, Convex, 0); +} + +void Fl_Xlib_Graphics_Driver::begin_complex_polygon() { + begin_polygon(); + gap_ = 0; +} + +void Fl_Xlib_Graphics_Driver::gap() { + while (n>gap_+2 && p[n-1].x == p[gap_].x && p[n-1].y == p[gap_].y) n--; + if (n > gap_+2) { + transformed_vertex((COORD_T)p[gap_].x, (COORD_T)p[gap_].y); + gap_ = n; + } else { + n = gap_; + } +} + +void Fl_Xlib_Graphics_Driver::end_complex_polygon() { + gap(); + if (n < 3) { + end_line(); + return; + } + if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, 0, 0); +} + +// shortcut the closed circles so they use XDrawArc: +// warning: these do not draw rotated ellipses correctly! +// See fl_arc.c for portable version. + +void Fl_Xlib_Graphics_Driver::circle(double x, double y,double r) { + double xt = transform_x(x,y); + double yt = transform_y(x,y); + double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); + double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); + int llx = (int)rint(xt-rx); + int w = (int)rint(xt+rx)-llx; + int lly = (int)rint(yt-ry); + int h = (int)rint(yt+ry)-lly; + + (what == POLYGON ? XFillArc : XDrawArc) + (fl_display, fl_window, fl_gc, llx, lly, w, h, 0, 360*64); +} + +#endif // FL_CFG_GFX_XLIB_VERTEX_CXX + +// +// End of "$Id$". +// diff --git a/src/fl_arci.cxx b/src/fl_arci.cxx index 7cc3c0690..11f6d4273 100644 --- a/src/fl_arci.cxx +++ b/src/fl_arci.cxx @@ -60,7 +60,7 @@ #ifdef FL_CFG_GFX_XLIB -# include "cfg_gfx/xlib_arci.cxx" +# include "drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx" #endif diff --git a/src/fl_color.cxx b/src/fl_color.cxx index ddcb8a3ca..1bf3a19f6 100644 --- a/src/fl_color.cxx +++ b/src/fl_color.cxx @@ -52,7 +52,7 @@ #ifdef FL_CFG_GFX_XLIB -# include "cfg_gfx/xlib_color.cxx" +# include "drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx" #endif diff --git a/src/fl_font.cxx b/src/fl_font.cxx index ca7e87560..02a6b8932 100644 --- a/src/fl_font.cxx +++ b/src/fl_font.cxx @@ -54,7 +54,8 @@ #elif defined(FL_PORTING) # pragma message "FL_PORTING: implement font handling specifics in its own file" #else -# include "fl_font_x.cxx" +# include "drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx" +# include "drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx" #endif // WIN32 #if defined(WIN32) || defined(__APPLE__) diff --git a/src/fl_font_x.cxx b/src/fl_font_x.cxx deleted file mode 100644 index cd2ac4e6a..000000000 --- a/src/fl_font_x.cxx +++ /dev/null @@ -1,335 +0,0 @@ -// -// "$Id$" -// -// Standard X11 font selection code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2011 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// -#ifndef FL_DOXYGEN - -Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name) { - font = XCreateUtf8FontStruct(fl_display, name); - if (!font) { - Fl::warning("bad font: %s", name); - font = XCreateUtf8FontStruct(fl_display, "fixed"); - } -# if HAVE_GL - listbase = 0; - for (int u = 0; u < 64; u++) glok[u] = 0; -# endif -} - -Fl_XFont_On_Demand fl_xfont; - -Fl_Font_Descriptor::~Fl_Font_Descriptor() { -# if HAVE_GL -// Delete list created by gl_draw(). This is not done by this code -// as it will link in GL unnecessarily. There should be some kind -// of "free" routine pointer, or a subclass? -// if (listbase) { -// int base = font->min_char_or_byte2; -// int size = font->max_char_or_byte2-base+1; -// int base = 0; int size = 256; -// glDeleteLists(listbase+base,size); -// } -# endif - if (this == fl_graphics_driver->font_descriptor()) { - fl_graphics_driver->font_descriptor(NULL); - fl_xfont = 0; - } - XFreeUtf8FontStruct(fl_display, font); -} - -//////////////////////////////////////////////////////////////// - -// WARNING: if you add to this table, you must redefine FL_FREE_FONT -// in Enumerations.H & recompile!! -static Fl_Fontdesc built_in_table[] = { -{"-*-helvetica-medium-r-normal--*"}, -{"-*-helvetica-bold-r-normal--*"}, -{"-*-helvetica-medium-o-normal--*"}, -{"-*-helvetica-bold-o-normal--*"}, -{"-*-courier-medium-r-normal--*"}, -{"-*-courier-bold-r-normal--*"}, -{"-*-courier-medium-o-normal--*"}, -{"-*-courier-bold-o-normal--*"}, -{"-*-times-medium-r-normal--*"}, -{"-*-times-bold-r-normal--*"}, -{"-*-times-medium-i-normal--*"}, -{"-*-times-bold-i-normal--*"}, -{"-*-symbol-*"}, -{"-*-lucidatypewriter-medium-r-normal-sans-*"}, -{"-*-lucidatypewriter-bold-r-normal-sans-*"}, -{"-*-*zapf dingbats-*"} -}; - -Fl_Fontdesc* fl_fonts = built_in_table; - -#define MAXSIZE 32767 - -// return dash number N, or pointer to ending null if none: -const char* fl_font_word(const char* p, int n) { - while (*p) {if (*p=='-') {if (!--n) break;} p++;} - return p; -} - -// return a pointer to a number we think is "point size": -char* fl_find_fontsize(char* name) { - char* c = name; - // for standard x font names, try after 7th dash: - if (*c == '-') { - c = (char*)fl_font_word(c,7); - if (*c++ && isdigit(*c)) return c; - return 0; // malformed x font name? - } - char* r = 0; - // find last set of digits: - for (c++;* c; c++) - if (isdigit(*c) && !isdigit(*(c-1))) r = c; - return r; -} - -//const char* fl_encoding = "iso8859-1"; -const char* fl_encoding = "iso10646-1"; - -// return true if this matches fl_encoding: -int fl_correct_encoding(const char* name) { - if (*name != '-') return 0; - const char* c = fl_font_word(name,13); - return (*c++ && !strcmp(c,fl_encoding)); -} - -static const char *find_best_font(const char *fname, int size) { - int cnt; - static char **list = NULL; -// locate or create an Fl_Font_Descriptor for a given Fl_Fontdesc and size: - if (list) XFreeFontNames(list); - list = XListFonts(fl_display, fname, 100, &cnt); - if (!list) return "fixed"; - - // search for largest <= font size: - char* name = list[0]; int ptsize = 0; // best one found so far - int matchedlength = 32767; - char namebuffer[1024]; // holds scalable font name - int found_encoding = 0; - int m = cnt; if (m<0) m = -m; - for (int n=0; n < m; n++) { - char* thisname = list[n]; - if (fl_correct_encoding(thisname)) { - if (!found_encoding) ptsize = 0; // force it to choose this - found_encoding = 1; - } else { - if (found_encoding) continue; - } - char* c = (char*)fl_find_fontsize(thisname); - int thissize = c ? atoi(c) : MAXSIZE; - int thislength = strlen(thisname); - if (thissize == size && thislength < matchedlength) { - // exact match, use it: - name = thisname; - ptsize = size; - matchedlength = thislength; - } else if (!thissize && ptsize!=size) { - // whoa! A scalable font! Use unless exact match found: - int l = c-thisname; - memcpy(namebuffer,thisname,l); - l += sprintf(namebuffer+l,"%d",size); - while (*c == '0') c++; - strcpy(namebuffer+l,c); - name = namebuffer; - ptsize = size; - } else if (!ptsize || // no fonts yet - (thissize < ptsize && ptsize > size) || // current font too big - (thissize > ptsize && thissize <= size) // current too small - ) { - name = thisname; - ptsize = thissize; - matchedlength = thislength; - } - } - -// if (ptsize != size) { // see if we already found this unscalable font: -// for (f = s->first; f; f = f->next) { -// if (f->minsize <= ptsize && f->maxsize >= ptsize) { -// if (f->minsize > size) f->minsize = size; -// if (f->maxsize < size) f->maxsize = size; -// return f; -// } -// } -// } -// -// // okay, we definately have some name, make the font: -// f = new Fl_Font_Descriptor(name); -// if (ptsize < size) {f->minsize = ptsize; f->maxsize = size;} -// else {f->minsize = size; f->maxsize = ptsize;} -// f->next = s->first; -// s->first = f; -// return f; - - return name; -} - -static char *put_font_size(const char *n, int size) -{ - int i = 0; - char *buf; - const char *ptr; - const char *f; - char *name; - int nbf = 1; - name = strdup(n); - while (name[i]) { - if (name[i] == ',') {nbf++; name[i] = '\0';} - i++; - } - - buf = (char*) malloc(nbf * 256); - buf[0] = '\0'; - ptr = name; - i = 0; - while (ptr && nbf > 0) { - f = find_best_font(ptr, size); - while (*f) { - buf[i] = *f; - f++; i++; - } - nbf--; - while (*ptr) ptr++; - if (nbf) { - ptr++; - buf[i] = ','; - i++; - } - while(isspace(*ptr)) ptr++; - } - buf[i] = '\0'; - free(name); - return buf; -} - - -char *fl_get_font_xfld(int fnum, int size) { - Fl_Fontdesc* s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use font 0 if still undefined - fl_open_display(); - return put_font_size(s->name, size); -} - -// locate or create an Fl_Font_Descriptor for a given Fl_Fontdesc and size: -static Fl_Font_Descriptor* find(int fnum, int size) { - char *name; - Fl_Fontdesc* s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use font 0 if still undefined - Fl_Font_Descriptor* f; - for (f = s->first; f; f = f->next) - if (f->size == size) return f; - fl_open_display(); - - name = put_font_size(s->name, size); - f = new Fl_Font_Descriptor(name); - f->size = size; - f->next = s->first; - s->first = f; - free(name); - return f; -} - - -//////////////////////////////////////////////////////////////// -// Public interface: - -void *fl_xftfont = 0; -static GC font_gc; - -XFontStruct* Fl_XFont_On_Demand::value() { - return ptr; -} - -void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { - if (fnum==-1) { - Fl_Graphics_Driver::font(0, 0); - return; - } - if (fnum == Fl_Graphics_Driver::font() && size == Fl_Graphics_Driver::size()) return; - Fl_Graphics_Driver::font(fnum, size); - Fl_Font_Descriptor* f = find(fnum, size); - if (f != this->font_descriptor()) { - this->font_descriptor(f); - fl_xfont = f->font->fonts[0]; - font_gc = 0; - } -} - -int Fl_Xlib_Graphics_Driver::height() { - if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent; - else return -1; -} - -int Fl_Xlib_Graphics_Driver::descent() { - if (font_descriptor()) return font_descriptor()->font->descent; - else return -1; -} - -double Fl_Xlib_Graphics_Driver::width(const char* c, int n) { - if (font_descriptor()) return (double) XUtf8TextWidth(font_descriptor()->font, c, n); - else return -1; -} - -double Fl_Xlib_Graphics_Driver::width(unsigned int c) { - if (font_descriptor()) return (double) XUtf8UcsWidth(font_descriptor()->font, c); - else return -1; -} - -void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &W, int &H) { - if (font_gc != fl_gc) { - if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); - font_gc = fl_gc; - XSetFont(fl_display, fl_gc, font_descriptor()->font->fid); - } - int xx, yy, ww, hh; - xx = yy = ww = hh = 0; - if (fl_gc) XUtf8_measure_extents(fl_display, fl_window, font_descriptor()->font, fl_gc, &xx, &yy, &ww, &hh, c, n); - - W = ww; H = hh; dx = xx; dy = yy; -// This is the safe but mostly wrong thing we used to do... -// W = 0; H = 0; -// fl_measure(c, W, H, 0); -// dx = 0; -// dy = fl_descent() - H; -} - -void Fl_Xlib_Graphics_Driver::draw(const char* c, int n, int x, int y) { - if (font_gc != fl_gc) { - if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); - font_gc = fl_gc; - XSetFont(fl_display, fl_gc, font_descriptor()->font->fid); - } - if (fl_gc) XUtf8DrawString(fl_display, fl_window, font_descriptor()->font, fl_gc, x, y, c, n); -} - -void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { - fprintf(stderr,"ROTATING TEXT NOT IMPLEMENTED\n"); - this->draw(str, n, (int)x, (int)y); -} - -void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { - if (font_gc != fl_gc) { - if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); - font_gc = fl_gc; - } - if (fl_gc) XUtf8DrawRtlString(fl_display, fl_window, font_descriptor()->font, fl_gc, x, y, c, n); -} -#endif // FL_DOXYGEN -// -// End of "$Id$". -// diff --git a/src/fl_font_xft.cxx b/src/fl_font_xft.cxx deleted file mode 100644 index 67921699a..000000000 --- a/src/fl_font_xft.cxx +++ /dev/null @@ -1,697 +0,0 @@ -// -// "$Id$" -// -// Xft font code for the Fast Light Tool Kit (FLTK). -// -// Copyright 2001-2011 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -// -// Draw fonts using Keith Packard's Xft library to provide anti- -// aliased text. Yow! -// -// Many thanks to Carl for making the original version of this. -// -// This font code only requires libXft to work. Contrary to popular -// belief there is no need to have FreeType, or the Xrender extension -// available to use this code. You will just get normal Xlib fonts -// (Xft calls them "core" fonts) The Xft algorithms for choosing -// these is about as good as the FLTK ones (I hope to fix it so it is -// exactly as good...), plus it can cache its results and share them -// between programs, so using this should be a win in all cases. Also -// it should be obvious by comparing this file and fl_font_x.cxx that -// it is a lot easier to program with Xft than with Xlib. -// -// Also, Xft supports UTF-8 text rendering directly, which will allow -// us to support UTF-8 on all platforms more easily. -// -// To actually get antialiasing you need the following: -// -// 1. You have XFree86 4 -// 2. You have the XRender extension -// 3. Your X device driver supports the render extension -// 4. You have libXft -// 5. Your libXft has FreeType2 support compiled in -// 6. You have the FreeType2 library -// -// Distributions that have XFree86 4.0.3 or later should have all of this... -// -// Unlike some other Xft packages, I tried to keep this simple and not -// to work around the current problems in Xft by making the "patterns" -// complicated. I believe doing this defeats our ability to improve Xft -// itself. You should edit the ~/.xftconfig file to "fix" things, there -// are several web pages of information on how to do this. -// -#ifndef FL_DOXYGEN - -#include - -#include - -// The predefined fonts that FLTK has: -static Fl_Fontdesc built_in_table[] = { -#if 1 -{" sans"}, -{"Bsans"}, -{"Isans"}, -{"Psans"}, -{" mono"}, -{"Bmono"}, -{"Imono"}, -{"Pmono"}, -{" serif"}, -{"Bserif"}, -{"Iserif"}, -{"Pserif"}, -{" symbol"}, -{" screen"}, -{"Bscreen"}, -{" zapf dingbats"}, -#else -{" helvetica"}, -{"Bhelvetica"}, -{"Ihelvetica"}, -{"Phelvetica"}, -{" courier"}, -{"Bcourier"}, -{"Icourier"}, -{"Pcourier"}, -{" times"}, -{"Btimes"}, -{"Itimes"}, -{"Ptimes"}, -{" symbol"}, -{" lucidatypewriter"}, -{"Blucidatypewriter"}, -{" zapf dingbats"}, -#endif -}; - -Fl_Fontdesc* fl_fonts = built_in_table; - -Fl_XFont_On_Demand fl_xfont; -void *fl_xftfont = 0; -//static const char* fl_encoding_ = "iso8859-1"; -static const char* fl_encoding_ = "iso10646-1"; - -static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, int angle) { - if (fnum==-1) { // special case to stop font caching - driver->Fl_Graphics_Driver::font(0, 0); - return; - } - Fl_Font_Descriptor* f = driver->font_descriptor(); - if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size() && f && f->angle == angle) - return; - driver->Fl_Graphics_Driver::font(fnum, size); - Fl_Fontdesc *font = fl_fonts + fnum; - // search the fontsizes we have generated already - for (f = font->first; f; f = f->next) { - if (f->size == size && f->angle == angle)// && !strcasecmp(f->encoding, fl_encoding_)) - break; - } - if (!f) { - f = new Fl_Font_Descriptor(font->name, size, angle); - f->next = font->first; - font->first = f; - } - driver->font_descriptor(f); -#if XFT_MAJOR < 2 - fl_xfont = f->font->u.core.font; -#else - fl_xfont = NULL; // invalidate -#endif // XFT_MAJOR < 2 - fl_xftfont = (void*)f->font; -} - -void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { - fl_xft_font(this,fnum,size,0); -} - -static XftFont* fontopen(const char* name, Fl_Fontsize size, bool core, int angle) { - // Check: does it look like we have been passed an old-school XLFD fontname? - bool is_xlfd = false; - int hyphen_count = 0; - int comma_count = 0; - unsigned len = strlen(name); - if (len > 512) len = 512; // ensure we are not passed an unbounded font name - for(unsigned idx = 0; idx < len; idx++) { - if(name[idx] == '-') hyphen_count++; // check for XLFD hyphens - if(name[idx] == ',') comma_count++; // are there multiple names? - } - if(hyphen_count >= 14) is_xlfd = true; // Not a robust check, but good enough? - - fl_open_display(); - - if(!is_xlfd) { // Not an XLFD - open as a XFT style name - XftFont *the_font = NULL; // the font we will return; - XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for matching - int slant = XFT_SLANT_ROMAN; - int weight = XFT_WEIGHT_MEDIUM; - - /* This "converts" FLTK-style font names back into "regular" names, extracting - * the BOLD and ITALIC codes as it does so - all FLTK font names are prefixed - * by 'I' (italic) 'B' (bold) 'P' (bold italic) or ' ' (regular) modifiers. - * This gives a fairly limited font selection ability, but is retained for - * compatibility reasons. If you really need a more complex choice, you are best - * calling Fl::set_fonts(*) then selecting the font by font-index rather than by - * name anyway. Probably. - * If you want to load a font who's name does actually begin with I, B or P, you - * MUST use a leading space OR simply use lowercase for the name... - */ - /* This may be efficient, but it is non-obvious. */ - switch (*name++) { - case 'I': slant = XFT_SLANT_ITALIC; break; // italic - case 'P': slant = XFT_SLANT_ITALIC; // bold-italic (falls-through) - case 'B': weight = XFT_WEIGHT_BOLD; break; // bold - case ' ': break; // regular - default: name--; // no prefix, restore name - } - - if(comma_count) { // multiple comma-separated names were passed - char *local_name = strdup(name); // duplicate the full name so we can edit the copy - char *curr = local_name; // points to first name in string - char *nxt; // next name in string - do { - nxt = strchr(curr, ','); // find comma separator - if (nxt) { - *nxt = 0; // terminate first name - nxt++; // first char of next name - } - - // Add the current name to the match pattern - XftPatternAddString(fnt_pat, XFT_FAMILY, curr); - - if(nxt) curr = nxt; // move onto next name (if it exists) - // Now do a cut-down version of the FLTK name conversion. - // NOTE: we only use the slant and weight of the first name, - // subsequent names we ignore this for... But we still need to do the check. - switch (*curr++) { - case 'I': break; // italic - case 'P': // bold-italic (falls-through) - case 'B': break; // bold - case ' ': break; // regular - default: curr--; // no prefix, restore name - } - - comma_count--; // decrement name sections count - } while (comma_count >= 0); - free(local_name); // release our local copy of font names - } - else { // single name was passed - add it directly - XftPatternAddString(fnt_pat, XFT_FAMILY, name); - } - - // Construct a match pattern for the font we want... - XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight); - XftPatternAddInteger(fnt_pat, XFT_SLANT, slant); - XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)size); - XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_); - - // rotate font if angle!=0 - if (angle !=0) { - XftMatrix m; - XftMatrixInit(&m); - XftMatrixRotate(&m,cos(M_PI*angle/180.),sin(M_PI*angle/180.)); - XftPatternAddMatrix (fnt_pat, XFT_MATRIX,&m); - } - - if (core) { - XftPatternAddBool(fnt_pat, XFT_CORE, FcTrue); - XftPatternAddBool(fnt_pat, XFT_RENDER, FcFalse); - } - - XftPattern *match_pat; // the best available match on the system - XftResult match_result; // the result of our matching attempt - - // query the system to find a match for this font - match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result); - -#if 0 // the XftResult never seems to get set to anything... abandon this code? - switch(match_result) { // how good a match is this font for our request? - case XftResultMatch: - puts("Object exists with the specified ID"); - break; - - case XftResultTypeMismatch: - puts("Object exists, but the type does not match"); - break; - - case XftResultNoId: - puts("Object exists, but has fewer values than specified"); - break; - - case FcResultOutOfMemory: - puts("FcResult: Malloc failed"); - break; - - case XftResultNoMatch: - puts("Object does not exist at all"); - break; - - default: - printf("Invalid XftResult status %d \n", match_result); - break; - } -#endif - -#if 0 // diagnostic to print the "full name" of the font we matched. This works. - FcChar8 *picked_name = FcNameUnparse(match_pat); - printf("Match: %s\n", picked_name); - free(picked_name); -#endif - - // open the matched font - if (match_pat) the_font = XftFontOpenPattern(fl_display, match_pat); - - if (!match_pat || !the_font) { - // last chance, just open any font in the right size - the_font = XftFontOpen (fl_display, fl_screen, - XFT_FAMILY, XftTypeString, "sans", - XFT_SIZE, XftTypeDouble, (double)size, - NULL); - XftPatternDestroy(fnt_pat); - if (!the_font) { - Fl::error("Unable to find fonts. Check your FontConfig configuration.\n"); - exit(1); - } - return the_font; - } - -#if 0 // diagnostic to print the "full name" of the font we actually opened. This works. - FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern); - printf("Open : %s\n", picked_name2); - free(picked_name2); -#endif - - XftPatternDestroy(fnt_pat); -// XftPatternDestroy(match_pat); // FontConfig will destroy this resource for us. We must not! - - return the_font; - } - else { // We were passed a font name in XLFD format - /* OksiD's X font code could handle being passed a comma separated list - * of XLFD's. It then attempted to find which font was "best" from this list. - * But XftFontOpenXlfd can not do this, so if a list is passed, we just - * terminate it at the first comma. - * A "better" solution might be to use XftXlfdParse() on each of the passed - * XLFD's to construct a "super-pattern" that incorporates attributes from all - * XLFD's and use that to perform a XftFontMatch(). Maybe... - */ - char *local_name = strdup(name); - if(comma_count) { // This means we were passed multiple XLFD's - char *pc = strchr(local_name, ','); - *pc = 0; // terminate the XLFD at the first comma - } - XftFont *the_font = XftFontOpenXlfd(fl_display, fl_screen, local_name); - free(local_name); -#if 0 // diagnostic to print the "full name" of the font we actually opened. This works. -puts("Font Opened"); fflush(stdout); - FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern); - printf("Open : %s\n", picked_name2); fflush(stdout); - free(picked_name2); -#endif - return the_font; - } -} // end of fontopen - -Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize fsize, int fangle) { -// encoding = fl_encoding_; - size = fsize; - angle = fangle; -#if HAVE_GL - listbase = 0; -#endif // HAVE_GL - font = fontopen(name, fsize, false, angle); -} - -Fl_Font_Descriptor::~Fl_Font_Descriptor() { - if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL); -// XftFontClose(fl_display, font); -} - -/* decodes the input UTF-8 string into a series of wchar_t characters. - n is set upon return to the number of characters. - Don't deallocate the returned memory. - */ -static const wchar_t *utf8reformat(const char *str, int& n) -{ - static const wchar_t empty[] = {0}; - static wchar_t *buffer; - static int lbuf = 0; - int newn; - if (n == 0) return empty; - newn = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf); - if (newn >= lbuf) { - lbuf = newn + 100; - if (buffer) free(buffer); - buffer = (wchar_t*)malloc(lbuf * sizeof(wchar_t)); - n = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf); - } else { - n = newn; - } - return buffer; -} - -static void utf8extents(Fl_Font_Descriptor *desc, const char *str, int n, XGlyphInfo *extents) -{ - memset(extents, 0, sizeof(XGlyphInfo)); - const wchar_t *buffer = utf8reformat(str, n); -#ifdef __CYGWIN__ - XftTextExtents16(fl_display, desc->font, (XftChar16 *)buffer, n, extents); -#else - XftTextExtents32(fl_display, desc->font, (XftChar32 *)buffer, n, extents); -#endif -} - -int Fl_Xlib_Graphics_Driver::height() { - if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent; - else return -1; -} - -int Fl_Xlib_Graphics_Driver::descent() { - if (font_descriptor()) return font_descriptor()->font->descent; - else return -1; -} - -double Fl_Xlib_Graphics_Driver::width(const char* str, int n) { - if (!font_descriptor()) return -1.0; - XGlyphInfo i; - utf8extents(font_descriptor(), str, n, &i); - return i.xOff; -} - -/*double fl_width(uchar c) { - return fl_graphics_driver->width((const char *)(&c), 1); -}*/ - -static double fl_xft_width(Fl_Font_Descriptor *desc, FcChar32 *str, int n) { - if (!desc) return -1.0; - XGlyphInfo i; - XftTextExtents32(fl_display, desc->font, str, n, &i); - return i.xOff; -} - -double Fl_Xlib_Graphics_Driver::width(unsigned int c) { - return fl_xft_width(font_descriptor(), (FcChar32 *)(&c), 1); -} - -void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { - if (!font_descriptor()) { - w = h = 0; - dx = dy = 0; - return; - } - XGlyphInfo gi; - utf8extents(font_descriptor(), c, n, &gi); - - w = gi.width; - h = gi.height; - dx = -gi.x; - dy = -gi.y; -} // fl_text_extents - - -/* This code is used (mainly by opengl) to get a bitmapped font. The - * original XFT-1 code used XFT's "core" fonts methods to load an XFT - * font that was actually a X-bitmap font, that could then be readily - * used with GL. But XFT-2 does not provide that ability, and there - * is no easy method to use an XFT font directly with GL. So... -*/ - -# if XFT_MAJOR > 1 -// This function attempts, on XFT2 systems, to find a suitable "core" Xfont -// for GL or other bitmap font needs (we dont have an XglUseXftFont(...) function.) -// There's probably a better way to do this. I can't believe it is this hard... -// Anyway... This code attempts to make an XLFD out of the fltk-style font -// name it is passed, then tries to load that font. Surprisingly, this quite -// often works - boxes that have XFT generally also have a fontserver that -// can serve TTF and other fonts to X, and so the font name that fltk makes -// from the XFT name often also "exists" as an "core" X font... -// If this code fails to load the requested font, it falls back through a -// series of tried 'n tested alternatives, ultimately resorting to what the -// original fltk code did. -// NOTE: On my test boxes (FC6, FC7, FC8, ubuntu8.04, 9.04, 9.10) this works -// well for the fltk "built-in" font names. -static XFontStruct* load_xfont_for_xft2(Fl_Graphics_Driver *driver) { - XFontStruct* xgl_font = 0; - int size = driver->size(); - int fnum = driver->font(); - const char *wt_med = "medium"; - const char *wt_bold = "bold"; - const char *weight = wt_med; // no specifc weight requested - accept any - char slant = 'r'; // regular non-italic by default - char xlfd[128]; // we will put our synthetic XLFD in here - char *pc = strdup(fl_fonts[fnum].name); // what font were we asked for? - const char *name = pc; // keep a handle to the original name for freeing later - // Parse the "fltk-name" of the font - switch (*name++) { - case 'I': slant = 'i'; break; // italic - case 'P': slant = 'i'; // bold-italic (falls-through) - case 'B': weight = wt_bold; break; // bold - case ' ': break; // regular - default: name--; // no prefix, restore name - } - - // first, we do a query with no prefered size, to see if the font exists at all - snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-*-*-*-*-*-*-*", name, weight, slant); // make up xlfd style name - xgl_font = XLoadQueryFont(fl_display, xlfd); - if(xgl_font) { // the face exists, but can we get it in a suitable size? - XFreeFont(fl_display, xgl_font); // release the non-sized version - snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10)); - xgl_font = XLoadQueryFont(fl_display, xlfd); // attempt to load the font at the right size - } -//puts(xlfd); - - // try alternative names - if (!xgl_font) { - if (!strcmp(name, "sans")) { - name = "helvetica"; - } else if (!strcmp(name, "mono")) { - name = "courier"; - } else if (!strcmp(name, "serif")) { - name = "times"; - } else if (!strcmp(name, "screen")) { - name = "lucidatypewriter"; - } else if (!strcmp(name, "dingbats")) { - name = "zapf dingbats"; - } - snprintf(xlfd, 128, "-*-*%s*-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10)); - xgl_font = XLoadQueryFont(fl_display, xlfd); - } - free(pc); // release our copy of the font name - - // if we have nothing loaded, try a generic proportional font - if(!xgl_font) { - snprintf(xlfd, 128, "-*-helvetica-*-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10)); - xgl_font = XLoadQueryFont(fl_display, xlfd); - } - // If that still didn't work, try this instead - if(!xgl_font) { - snprintf(xlfd, 128, "-*-courier-medium-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10)); - xgl_font = XLoadQueryFont(fl_display, xlfd); - } -//printf("glf: %d\n%s\n%s\n", size, xlfd, fl_fonts[fl_font_].name); -//if(xgl_font) puts("ok"); - - // Last chance fallback - this usually loads something... - if (!xgl_font) xgl_font = XLoadQueryFont(fl_display, "fixed"); - - return xgl_font; -} // end of load_xfont_for_xft2 -# endif - -static XFontStruct* fl_xxfont(Fl_Graphics_Driver *driver) { -# if XFT_MAJOR > 1 - // kludge! XFT 2 and later does not provide core fonts for us to use with GL - // try to load a bitmap X font instead - static XFontStruct* xgl_font = 0; - static int glsize = 0; - static int glfont = -1; - // Do we need to load a new font? - if ((!xgl_font) || (glsize != driver->size()) || (glfont != driver->font())) { - // create a dummy XLFD for some font of the appropriate size... - if (xgl_font) XFreeFont(fl_display, xgl_font); // font already loaded, free it - this *might* be a Bad Idea - glsize = driver->size(); // record current font size - glfont = driver->font(); // and face - xgl_font = load_xfont_for_xft2(driver); - } - return xgl_font; -# else // XFT-1 provides a means to load a "core" font directly - if (driver->font_descriptor()->font->core) { - return driver->font_descriptor()->font->u.core.font; // is the current font a "core" font? If so, use it. - } - static XftFont* xftfont; - if (xftfont) XftFontClose (fl_display, xftfont); - xftfont = fontopen(fl_fonts[driver->font()].name, driver->size(), true, 0); // else request XFT to load a suitable "core" font instead. - return xftfont->u.core.font; -# endif // XFT_MAJOR > 1 -} - -XFontStruct* Fl_XFont_On_Demand::value() { - if (!ptr) ptr = fl_xxfont(fl_graphics_driver); - return ptr; -} - -#if USE_OVERLAY -// Currently Xft does not work with colormapped visuals, so this probably -// does not work unless you have a true-color overlay. -extern bool fl_overlay; -extern Colormap fl_overlay_colormap; -extern XVisualInfo* fl_overlay_visual; -#endif - -// For some reason Xft produces errors if you destroy a window whose id -// still exists in an XftDraw structure. It would be nice if this is not -// true, a lot of junk is needed to try to stop this: - -static XftDraw* draw_; -static Window draw_window; -#if USE_OVERLAY -static XftDraw* draw_overlay; -static Window draw_overlay_window; -#endif - -void fl_destroy_xft_draw(Window id) { - if (id == draw_window) - XftDrawChange(draw_, draw_window = fl_message_window); -#if USE_OVERLAY - if (id == draw_overlay_window) - XftDrawChange(draw_overlay, draw_overlay_window = fl_message_window); -#endif -} - -void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) { - if ( !this->font_descriptor() ) { - this->font(FL_HELVETICA, FL_NORMAL_SIZE); - } -#if USE_OVERLAY - XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_; - if (fl_overlay) { - if (!draw_) - draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window, - fl_overlay_visual->visual, fl_overlay_colormap); - else //if (draw_overlay_window != fl_window) - XftDrawChange(draw_, draw_overlay_window = fl_window); - } else -#endif - if (!draw_) - draw_ = XftDrawCreate(fl_display, draw_window = fl_window, - fl_visual->visual, fl_colormap); - else //if (draw_window != fl_window) - XftDrawChange(draw_, draw_window = fl_window); - - Region region = fl_clip_region(); - if (region && XEmptyRegion(region)) return; - XftDrawSetClip(draw_, region); - - // Use fltk's color allocator, copy the results to match what - // XftCollorAllocValue returns: - XftColor color; - color.pixel = fl_xpixel(Fl_Graphics_Driver::color()); - uchar r,g,b; Fl::get_color(Fl_Graphics_Driver::color(), r,g,b); - color.color.red = ((int)r)*0x101; - color.color.green = ((int)g)*0x101; - color.color.blue = ((int)b)*0x101; - color.color.alpha = 0xffff; - - const wchar_t *buffer = utf8reformat(str, n); -#ifdef __CYGWIN__ - XftDrawString16(draw_, &color, font_descriptor()->font, x, y, (XftChar16 *)buffer, n); -#else - XftDrawString32(draw_, &color, font_descriptor()->font, x, y, (XftChar32 *)buffer, n); -#endif -} - -void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { - fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), angle); - this->draw(str, n, (int)x, (int)y); - fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), 0); -} - -static void fl_drawUCS4(Fl_Graphics_Driver *driver, const FcChar32 *str, int n, int x, int y) { -#if USE_OVERLAY - XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_; - if (fl_overlay) { - if (!draw_) - draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window, - fl_overlay_visual->visual, fl_overlay_colormap); - else //if (draw_overlay_window != fl_window) - XftDrawChange(draw_, draw_overlay_window = fl_window); - } else -#endif - if (!draw_) - draw_ = XftDrawCreate(fl_display, draw_window = fl_window, - fl_visual->visual, fl_colormap); - else //if (draw_window != fl_window) - XftDrawChange(draw_, draw_window = fl_window); - - Region region = fl_clip_region(); - if (region && XEmptyRegion(region)) return; - XftDrawSetClip(draw_, region); - - // Use fltk's color allocator, copy the results to match what - // XftCollorAllocValue returns: - XftColor color; - color.pixel = fl_xpixel(driver->color()); - uchar r,g,b; Fl::get_color(driver->color(), r,g,b); - color.color.red = ((int)r)*0x101; - color.color.green = ((int)g)*0x101; - color.color.blue = ((int)b)*0x101; - color.color.alpha = 0xffff; - - XftDrawString32(draw_, &color, driver->font_descriptor()->font, x, y, (FcChar32 *)str, n); -} - - -void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { - -#if defined(__GNUC__) -// FIXME: warning Need to improve this XFT right to left draw function -#endif /*__GNUC__*/ - -// This actually draws LtoR, but aligned to R edge with the glyph order reversed... -// but you can't just byte-rev a UTF-8 string, that isn't valid. -// You can reverse a UCS4 string though... - int num_chars, wid, utf_len = strlen(c); - FcChar8 *u8 = (FcChar8 *)c; - FcBool valid = FcUtf8Len(u8, utf_len, &num_chars, &wid); - if (!valid) - { - // badly formed Utf-8 input string - return; - } - if (num_chars < n) n = num_chars; // limit drawing to usable characters in input array - FcChar32 *ucs_txt = new FcChar32[n+1]; - FcChar32* pu; - int out, sz; - ucs_txt[n] = 0; - out = n-1; - while ((out >= 0) && (utf_len > 0)) - { - pu = &ucs_txt[out]; - sz = FcUtf8ToUcs4(u8, pu, utf_len); - utf_len = utf_len - sz; - u8 = u8 + sz; - out = out - 1; - } - // Now we have a UCS4 version of the input text, reversed, in ucs_txt - int offs = (int)fl_xft_width(font_descriptor(), ucs_txt, n); - fl_drawUCS4(this, ucs_txt, n, (x-offs), y); - - delete[] ucs_txt; -} -#endif - -// -// End of "$Id$" -// diff --git a/src/fl_line_style.cxx b/src/fl_line_style.cxx index e07add50b..83a373394 100644 --- a/src/fl_line_style.cxx +++ b/src/fl_line_style.cxx @@ -60,7 +60,7 @@ int fl_line_width_ = 0; #ifdef FL_CFG_GFX_XLIB -# include "cfg_gfx/xlib_line_style.cxx" +# include "drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx" #endif diff --git a/src/fl_rect.cxx b/src/fl_rect.cxx index 0676bb8f6..39af2e20c 100644 --- a/src/fl_rect.cxx +++ b/src/fl_rect.cxx @@ -65,31 +65,6 @@ Fl_Region Fl_Graphics_Driver::clip_region() { -//////////////////////////////////////////////////////////////// - -/* - Matt: I wrote individual methods for every class. They are virtual, so the - correct function is called, depending on the active driver. - - By having individual methods, multiple drivers can co-exist, for example - Quartz, OpenGL, and a printer driver. - - The individual implementations should eventually go into files that are - included into this file, based on the configuration, for example: - - src/cfg_gfx/quartz_rect.cxx - src/cfg_gfx/gdi_rect.cxx - src/cfg_gfx/xlib_rect.cxx - - Porting the graphics system to a new platform then requires to copy one of - these files and implement the virtual functions. point() is the only function - that *must* be implemented when deriving from 'Fl_Minimal_Graphics_Driver" - (which is still to be written) - */ - -//////////////////////////////////////////////////////////////// - - #ifdef FL_CFG_GFX_QUARTZ # include "cfg_gfx/quartz_rect.cxx" @@ -112,7 +87,7 @@ Fl_Region Fl_Graphics_Driver::clip_region() { #ifdef FL_CFG_GFX_XLIB -# include "cfg_gfx/xlib_rect.cxx" +# include "drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx" #endif diff --git a/src/fl_set_fonts.cxx b/src/fl_set_fonts.cxx index 2673a78fd..ab92dc664 100644 --- a/src/fl_set_fonts.cxx +++ b/src/fl_set_fonts.cxx @@ -31,7 +31,7 @@ #elif defined(FL_PORTING) # pragma message "FL_PORTING: implement changes in font in its own file" #else -# include "fl_set_fonts_x.cxx" +// now included for fl_font.cxx, but will be its own source code module in drivers/Xlib/Fl_Xlib_Graphics_Driver_font..." #endif // WIN32 // diff --git a/src/fl_set_fonts_x.cxx b/src/fl_set_fonts_x.cxx deleted file mode 100644 index 845f15a87..000000000 --- a/src/fl_set_fonts_x.cxx +++ /dev/null @@ -1,341 +0,0 @@ -// -// "$Id$" -// -// X11 font utilities for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2010 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -// This function fills in the fltk font table with all the fonts that -// are found on the X server. It tries to place the fonts into families -// and to sort them so the first 4 in a family are normal, bold, italic, -// and bold italic. - -// Standard X fonts are matched by a pattern that is always of -// this form, and this pattern is put in the table: -// "-*-family-weight-slant-width1-style-*-registry-encoding" - -// Non-standard font names (those not starting with '-') are matched -// by a pattern of the form "prefix*suffix", where the '*' is where -// fltk thinks the point size is, or by the actual font name if no -// point size is found. - -// Fltk knows how to pull an "attribute" out of a font name, such as -// bold or italic, by matching known x font field values. All words -// that don't match a known attribute are combined into the "name" -// of the font. Names are compared before attributes for sorting, this -// makes the bold and plain version of a font come out next to each -// other despite the poor X font naming scheme. - -// By default fl_set_fonts() only does iso8859-1 encoded fonts. You can -// do all normal X fonts by passing "-*" or every possible font with "*". - -// Fl::set_font will take strings other than the ones this stores -// and can identify any font on X that way. You may want to write your -// own system of font management and not use this code. - -// turn word N of a X font name into either some attribute bits -// (right now 0, FL_BOLD, or FL_ITALIC), or into -1 indicating that -// the word should be put into the name: - -static int attribute(int n, const char *p) { - // don't put blank things into name: - if (!*p || *p=='-' || *p=='*') return 0; - if (n == 3) { // weight - if (!strncmp(p,"normal",6) || - !strncmp(p,"light",5) || - !strncmp(p,"medium",6) || - !strncmp(p,"book",4)) return 0; - if (!strncmp(p,"bold",4) || !strncmp(p,"demi",4)) return FL_BOLD; - } else if (n == 4) { // slant - if (*p == 'r') return 0; - if (*p == 'i' || *p == 'o') return FL_ITALIC; - } else if (n == 5) { // sWidth - if (!strncmp(p,"normal",6)) return 0; - } - return -1; -} - -// return non-zero if the registry-encoding should be used: -extern const char* fl_encoding; -static int use_registry(const char *p) { - return *p && *p!='*' && strcmp(p,fl_encoding); -} - -// Bug: older versions calculated the value for *ap as a side effect of -// making the name, and then forgot about it. To avoid having to change -// the header files I decided to store this value in the last character -// of the font name array. -#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 - -// turn a stored (with *'s) X font name into a pretty name: -const char* Fl::get_font_name(Fl_Font fnum, int* ap) { - Fl_Fontdesc *f = fl_fonts + fnum; - if (!f->fontname[0]) { - int type = 0; - const char* p = f->name; - if (!p) { - if (ap) *ap = 0; - return ""; - } - char *o = f->fontname; - - if (*p != '-') { // non-standard font, just replace * with spaces: - if (strstr(p,"bold")) type = FL_BOLD; - if (strstr(p,"ital")) type |= FL_ITALIC; - for (;*p; p++) { - if (*p == '*' || *p == ' ' || *p == '-') { - do p++; while (*p == '*' || *p == ' ' || *p == '-'); - if (!*p) break; - if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' '; - } - if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = *p; - } - *o = 0; - - } else { // standard dash-separated font: - - // get the family: - const char *x = fl_font_word(p,2); if (*x) x++; if (*x=='*') x++; - if (!*x) { - if (ap) *ap = 0; - return p; - } - const char *e = fl_font_word(x,1); - if ((e - x) < (int)(ENDOFBUFFER - 1)) { - // MRS: we want strncpy here, not strlcpy... - strncpy(o,x,e-x); - o += e-x; - } else { - strlcpy(f->fontname, x, ENDOFBUFFER); - o = f->fontname+ENDOFBUFFER-1; - } - - // collect all the attribute words: - for (int n = 3; n <= 6; n++) { - // get the next word: - if (*e) e++; x = e; e = fl_font_word(x,1); - int t = attribute(n,x); - if (t < 0) { - if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' '; - if ((e - x) < (int)(ENDOFBUFFER - (o - f->fontname) - 1)) { - // MRS: we want strncpy here, not strlcpy... - strncpy(o,x,e-x); - o += e-x; - } else { - strlcpy(o,x, ENDOFBUFFER - (o - f->fontname) - 1); - o = f->fontname+ENDOFBUFFER-1; - } - } else type |= t; - } - - // skip over the '*' for the size and get the registry-encoding: - x = fl_font_word(e,2); - if (*x) {x++; *o++ = '('; while (*x) *o++ = *x++; *o++ = ')';} - - *o = 0; - if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); - if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); - } - f->fontname[ENDOFBUFFER] = (char)type; - } - if (ap) *ap = f->fontname[ENDOFBUFFER]; - return f->fontname; -} - -extern "C" { -// sort raw (non-'*') X font names into perfect order: - -static int ultrasort(const void *aa, const void *bb) { - const char *a = *(char **)aa; - const char *b = *(char **)bb; - - // sort all non x-fonts at the end: - if (*a != '-') { - if (*b == '-') return 1; - // 2 non-x fonts are matched by "numeric sort" - int ret = 0; - for (;;) { - if (isdigit(*a) && isdigit(*b)) { - int na = strtol(a, (char **)&a, 10); - int nb = strtol(b, (char **)&b, 10); - if (!ret) ret = na-nb; - } else if (*a != *b) { - return (*a-*b); - } else if (!*a) { - return ret; - } else { - a++; b++; - } - } - } else { - if (*b != '-') return -1; - } - - // skip the foundry (assume equal): - for (a++; *a && *a++!='-';); - for (b++; *b && *b++!='-';); - - // compare the family and all the attribute words: - int atype = 0; - int btype = 0; - for (int n = 2; n <= 6; n++) { - int at = attribute(n,a); - int bt = attribute(n,b); - if (at < 0) { - if (bt >= 0) return 1; - for (;;) {if (*a!=*b) return *a-*b; b++; if (!*a || *a++=='-') break;} - } else { - if (bt < 0) return -1; - a = fl_font_word(a,1); if (*a) a++; - b = fl_font_word(b,1); if (*b) b++; - atype |= at; btype |= bt; - } - } - - // remember the pixel size: - int asize = atoi(a); - int bsize = atoi(b); - - // compare the registry/encoding: - a = fl_font_word(a,6); if (*a) a++; - b = fl_font_word(b,6); if (*b) b++; - if (use_registry(a)) { - if (!use_registry(b)) return 1; - int r = strcmp(a,b); if (r) return r; - } else { - if (use_registry(b)) return -1; - } - - if (atype != btype) return atype-btype; - if (asize != bsize) return asize-bsize; - - // something wrong, just do a string compare... - return strcmp(*(char**)aa, *(char**)bb); -} -} - -// converts a X font name to a standard starname, returns point size: -static int to_canonical(char *to, const char *from, size_t tolen) { - char* c = fl_find_fontsize((char*)from); - if (!c) return -1; // no point size found... - const char* endptr; - int size = strtol(c,(char**)&endptr,10); - if (from[0] == '-') { - // replace the "foundry" with -*-: - *to++ = '-'; *to++ = '*'; - for (from++; *from && *from != '-'; from++); - // skip to the registry-encoding: - endptr = (char*)fl_font_word(endptr,6); - if (*endptr && !use_registry(endptr+1)) endptr = ""; - } - int n = c-from; - // MRS: we want strncpy here, not strlcpy... - if (n > (int)(tolen - 1)) return -1; - strncpy(to,from,n); - to[n++] = '*'; - strlcpy(to+n,endptr, tolen - n); - return size; -} - -static unsigned int fl_free_font = FL_FREE_FONT; - -Fl_Font Fl::set_fonts(const char* xstarname) { - if (fl_free_font > (unsigned)FL_FREE_FONT) // already been here - return (Fl_Font)fl_free_font; - fl_open_display(); - int xlistsize; - char buf[20]; - if (!xstarname) { - strcpy(buf,"-*-"); strcpy(buf+3,fl_encoding); - xstarname = buf; - } - char **xlist = XListFonts(fl_display, xstarname, 10000, &xlistsize); - if (!xlist) return (Fl_Font)fl_free_font; - qsort(xlist, xlistsize, sizeof(*xlist), ultrasort); - int used_xlist = 0; - for (int i=0; i= 0) { - for (;;) { // find all matching fonts: - if (i >= xlistsize) break; - const char *q = xlist[i]; - char this_canon[1024]; - if (to_canonical(this_canon, q, sizeof(this_canon)) < 0) break; - if (strcmp(canon, this_canon)) break; - i++; - } - /*if (*p=='-' || i > first_xlist+1)*/ p = canon; - } - unsigned int j; - for (j = 0;; j++) { - /*if (j < FL_FREE_FONT) { - // see if it is one of our built-in fonts: - // if so, set the list of x fonts, since we have it anyway - if (fl_fonts[j].name && !strcmp(fl_fonts[j].name, p)) break; - } else */{ - j = fl_free_font++; - if (p == canon) p = strdup(p); else used_xlist = 1; - Fl::set_font((Fl_Font)j, p); - break; - } - } - if (!fl_fonts[j].xlist) { - fl_fonts[j].xlist = xlist+first_xlist; - fl_fonts[j].n = -(i-first_xlist); - used_xlist = 1; - } - } - if (!used_xlist) XFreeFontNames(xlist); - return (Fl_Font)fl_free_font; -} - -int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { - Fl_Fontdesc *s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 - if (!s->xlist) { - fl_open_display(); - s->xlist = XListFonts(fl_display, s->name, 100, &(s->n)); - if (!s->xlist) return 0; - } - int listsize = s->n; if (listsize<0) listsize = -listsize; - static int sizes[128]; - int numsizes = 0; - for (int i = 0; i < listsize; i++) { - char *q = s->xlist[i]; - char *d = fl_find_fontsize(q); - if (!d) continue; - int s = strtol(d,0,10); - if (!numsizes || sizes[numsizes-1] < s) { - sizes[numsizes++] = s; - } else { - // insert-sort the new size into list: - int n; - for (n = numsizes-1; n > 0; n--) if (sizes[n-1] < s) break; - if (sizes[n] != s) { - for (int m = numsizes; m > n; m--) sizes[m] = sizes[m-1]; - sizes[n] = s; - numsizes++; - } - } - } - sizep = sizes; - return numsizes; -} - -// -// End of "$Id$". -// diff --git a/src/fl_set_fonts_xft.cxx b/src/fl_set_fonts_xft.cxx deleted file mode 100644 index 13374ee7f..000000000 --- a/src/fl_set_fonts_xft.cxx +++ /dev/null @@ -1,384 +0,0 @@ -// -// "$Id$" -// -// More font utilities for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2011 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: -// -// http://www.fltk.org/COPYING.php -// -// Please report all bugs and problems on the following page: -// -// http://www.fltk.org/str.php -// - -#include - -// This function fills in the fltk font table with all the fonts that -// are found on the X server. It tries to place the fonts into families -// and to sort them so the first 4 in a family are normal, bold, italic, -// and bold italic. - -// Bug: older versions calculated the value for *ap as a side effect of -// making the name, and then forgot about it. To avoid having to change -// the header files I decided to store this value in the last character -// of the font name array. -#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 - -// turn a stored font name in "fltk format" into a pretty name: -const char* Fl::get_font_name(Fl_Font fnum, int* ap) { - Fl_Fontdesc *f = fl_fonts + fnum; - if (!f->fontname[0]) { - const char* p = f->name; - int type; - switch (p[0]) { - case 'B': type = FL_BOLD; break; - case 'I': type = FL_ITALIC; break; - case 'P': type = FL_BOLD | FL_ITALIC; break; - default: type = 0; break; - } - - // NOTE: This can cause duplications in fonts that already have Bold or Italic in - // their "name". Maybe we need to find a cleverer way? - strlcpy(f->fontname, p+1, ENDOFBUFFER); - if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); - if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); - f->fontname[ENDOFBUFFER] = (char)type; - } - if (ap) *ap = f->fontname[ENDOFBUFFER]; - return f->fontname; -} - -/////////////////////////////////////////////////////////// -#define LOCAL_RAW_NAME_MAX 256 - -extern "C" { -// sort returned fontconfig font names -static int name_sort(const void *aa, const void *bb) { - // What should we do here? Just do a string compare for now... - // NOTE: This yeilds some oddities - in particular a Blah Bold font will be - // listed before Blah... - // Also - the fontconfig listing returns some faces that are effectively duplicates - // as far as fltk is concerned, e.g. where there are ko or ja variants that we - // can't distinguish (since we are not yet fully UTF-*) - should we strip them here? - return fl_ascii_strcasecmp(*(char**)aa, *(char**)bb); -} // end of name_sort -} // end of extern C section - - -// Read the "pretty" name we have derived from fontconfig then convert -// it into the format fltk uses internally for Xft names... -// This is just a mess - I should have tokenised the strings and gone from there, -// but I really thought this would be easier! -static void make_raw_name(char *raw, char *pretty) -{ - // Input name will be "Some Name:style = Bold Italic" or whatever - // The plan is this: - // - the first char in the "raw" name becomes either I, B, P or " " for - // italic, bold, bold italic or normal - this seems to be the fltk way... - - char *style = strchr(pretty, ':'); - - if (style) - { - *style = 0; // Terminate "name" string - style ++; // point to start of style section - } - - // It is still possible that the "pretty" name has multiple comma separated entries - // I've seen this often in CJK fonts, for example... Keep only the first one... This - // is not ideal, the CJK fonts often have the name in utf8 in several languages. What - // we ought to do is use fontconfig to query the available languages and pick one... But which? -#if 0 // loop to keep the LAST name entry... - char *nm1 = pretty; - char *nm2 = strchr(nm1, ','); - while(nm2) { - nm1 = nm2 + 1; - nm2 = strchr(nm1, ','); - } - raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text - strncat(raw, nm1, LOCAL_RAW_NAME_MAX-1); // only copy MAX-1 chars, we have already set cell 0 - // Ensure raw is terminated, just in case the given name is infeasibly long... - raw[LOCAL_RAW_NAME_MAX-1] = 0; -#else // keep the first remaining name entry - char *nm2 = strchr(pretty, ','); - if(nm2) *nm2 = 0; // terminate name after first entry - raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text - strncat(raw, pretty, LOCAL_RAW_NAME_MAX-1); // only copy MAX-1 chars, we have already set cell 0 - // Ensure raw is terminated, just in case the given name is infeasibly long... - raw[LOCAL_RAW_NAME_MAX-1] = 0; -#endif - // At this point, the name is "marked" as regular... - if (style) - { -#define PLAIN 0 -#define BOLD 1 -#define ITALIC 2 -#define BITALIC (BOLD | ITALIC) - - int mods = PLAIN; - char *last = style + strlen(style) - 2; - - // Now try and parse the style string - look for the "=" sign - style = strchr(style, '='); - while ((style) && (style < last)) - { - int type; - while ((*style == '=') || (*style == ' ') || (*style == '\t') || (*style == ',')) - { - style++; // Start of Style string - if ((style >= last) || (*style == 0)) continue; - } - type = toupper(style[0]); - switch (type) - { - // Things we might see: Regular Normal Bold Italic Oblique (??what??) Medium - // Roman Light Demi Sans SemiCondensed SuperBold Book... etc... - // Things we actually care about: Bold Italic Oblique SuperBold - Others??? - case 'I': - if (strncasecmp(style, "Italic", 6) == 0) - { - mods |= ITALIC; - } - goto NEXT_STYLE; - - case 'B': - if (strncasecmp(style, "Bold", 4) == 0) - { - mods |= BOLD; - } - goto NEXT_STYLE; - - case 'O': - if (strncasecmp(style, "Oblique", 7) == 0) - { - mods |= ITALIC; - } - goto NEXT_STYLE; - - case 'S': - if (strncasecmp(style, "SuperBold", 9) == 0) - { - mods |= BOLD; - } - goto NEXT_STYLE; - - default: // find the next gap - goto NEXT_STYLE; - } // switch end -NEXT_STYLE: - while ((*style != ' ') && (*style != '\t') && (*style != ',')) - { - style++; - if ((style >= last) || (*style == 0)) goto STYLE_DONE; - } - } -STYLE_DONE: - // Set the "modifier" character in the raw string - switch(mods) - { - case BOLD: raw[0] = 'B'; - break; - case ITALIC: raw[0] = 'I'; - break; - case BITALIC: raw[0] = 'P'; - break; - default: raw[0] = ' '; - break; - } - } -} // make_raw_name - -/////////////////////////////////////////////////////////// - -static int fl_free_font = FL_FREE_FONT; - -// Uses the fontconfig lib to construct a list of all installed fonts. -// I tried using XftListFonts for this, but the API is tricky - and when -// I looked at the XftList* code, it calls the Fc* functions anyway, so... -// -// Also, for now I'm ignoring the "pattern_name" and just getting everything... -// AND I don't try and skip the fonts we've already loaded in the defaults. -// Blimey! What a hack! -Fl_Font Fl::set_fonts(const char* pattern_name) -{ - FcFontSet *fnt_set; // Will hold the list of fonts we find - FcPattern *fnt_pattern; // Holds the generic "match all names" pattern - FcObjectSet *fnt_obj_set = 0; // Holds the generic "match all objects" - - int j; // loop iterator variable - int font_count; // Total number of fonts found to process - char **full_list; // The list of font names we build - - if (fl_free_font > FL_FREE_FONT) // already been here - return (Fl_Font)fl_free_font; - - fl_open_display(); // Just in case... - - // Make sure fontconfig is ready... is this necessary? The docs say it is - // safe to call it multiple times, so just go for it anyway! - if (!FcInit()) - { - // What to do? Just return defaults... - return FL_FREE_FONT; - } - - // Create a search pattern that will match every font name - I think this - // does the Right Thing, but am not certain... - // - // This could possibly be "enhanced" to pay attention to the requested - // "pattern_name"? - fnt_pattern = FcPatternCreate(); - fnt_obj_set = FcObjectSetBuild(FC_FAMILY, FC_STYLE, (void *)0); - - // Hopefully, this is a set of all the fonts... - fnt_set = FcFontList(0, fnt_pattern, fnt_obj_set); - - // We don't need the fnt_pattern and fnt_obj_set any more, release them - FcPatternDestroy(fnt_pattern); - FcObjectSetDestroy(fnt_obj_set); - - // Now, if we got any fonts, iterate through them... - if (fnt_set) - { - char *stop; - char *start; - char *first; - - font_count = fnt_set->nfont; // How many fonts? - - // Allocate array of char*'s to hold the name strings - full_list = (char **)malloc(sizeof(char *) * font_count); - - // iterate through all the font patterns and get the names out... - for (j = 0; j < font_count; j++) - { - // NOTE: FcChar8 is a typedef of "unsigned char"... - FcChar8 *font; // String to hold the font's name - - // Convert from fontconfig internal pattern to human readable name - // NOTE: This WILL malloc storage, so we need to free it later... - font = FcNameUnparse(fnt_set->fonts[j]); - - // The returned strings look like this... - // Century Schoolbook:style=Bold Italic,fed kursiv,Fett Kursiv,... - // So the bit we want is up to the first comma - BUT some strings have - // more than one name, separated by, guess what?, a comma... - stop = start = first = 0; - stop = strchr((char *)font, ','); - start = strchr((char *)font, ':'); - if ((stop) && (start) && (stop < start)) - { - first = stop + 1; // discard first version of name - // find first comma *after* the end of the name - stop = strchr((char *)start, ','); - } - else - { - first = (char *)font; // name is just what was returned - } - // Truncate the name after the (english) modifiers description - // Matt: Actually, there is no guarantee that the *first* description is the English one. - // Matt: So we keep the entire description, just in case. - //if (stop) - //{ - // *stop = 0; // Terminate the string at the first comma, if there is one - //} - - // Copy the font description into our list - if (first == (char *)font) - { // The listed name is still OK - full_list[j] = (char *)font; - } - else - { // The listed name has been modified - full_list[j] = strdup(first); - // Free the font name storage - free (font); - } - // replace "style=Regular" so strcmp sorts it first - if (start) { - char *reg = strstr(full_list[j], "=Regular"); - if (reg) reg[1]='.'; - } - } - - // Release the fnt_set - we don't need it any more - FcFontSetDestroy(fnt_set); - - // Sort the list into alphabetic order - qsort(full_list, font_count, sizeof(*full_list), name_sort); - - // Now let us add the names we got to fltk's font list... - for (j = 0; j < font_count; j++) - { - if (full_list[j]) - { - char xft_name[LOCAL_RAW_NAME_MAX]; - char *stored_name; - // Parse the strings into FLTK-XFT style.. - make_raw_name(xft_name, full_list[j]); - // NOTE: This just adds on AFTER the default fonts - no attempt is made - // to identify already loaded fonts. Is this bad? - stored_name = strdup(xft_name); - Fl::set_font((Fl_Font)(j + FL_FREE_FONT), stored_name); - fl_free_font ++; - - free(full_list[j]); // release that name from our internal array - } - } - // Now we are done with the list, release it fully - free(full_list); - } - return (Fl_Font)fl_free_font; -} // ::set_fonts -//////////////////////////////////////////////////////////////// - - -extern "C" { -static int int_sort(const void *aa, const void *bb) { - return (*(int*)aa)-(*(int*)bb); -} -} - -//////////////////////////////////////////////////////////////// - -// Return all the point sizes supported by this font: -// Suprisingly enough Xft works exactly like fltk does and returns -// the same list. Except there is no way to tell if the font is scalable. -int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { - Fl_Fontdesc *s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 - - fl_open_display(); - XftFontSet* fs = XftListFonts(fl_display, fl_screen, - XFT_FAMILY, XftTypeString, s->name+1, - (void *)0, - XFT_PIXEL_SIZE, - (void *)0); - static int* array = 0; - static int array_size = 0; - if (fs->nfont >= array_size) { - delete[] array; - array = new int[array_size = fs->nfont+1]; - } - array[0] = 0; int j = 1; // claim all fonts are scalable - for (int i = 0; i < fs->nfont; i++) { - double v; - if (XftPatternGetDouble(fs->fonts[i], XFT_PIXEL_SIZE, 0, &v) == XftResultMatch) { - array[j++] = int(v); - } - } - qsort(array+1, j-1, sizeof(int), int_sort); - XftFontSetDestroy(fs); - sizep = array; - return j; -} - -// -// End of "$Id$". -// diff --git a/src/fl_vertex.cxx b/src/fl_vertex.cxx index 16f0a501f..d891794c0 100644 --- a/src/fl_vertex.cxx +++ b/src/fl_vertex.cxx @@ -170,7 +170,7 @@ void Fl_Graphics_Driver::fixloop() { // remove equal points from closed path #ifdef FL_CFG_GFX_XLIB -# include "cfg_gfx/xlib_vertex.cxx" +# include "drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx" #endif -- cgit v1.2.3