diff options
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h | 112 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx | 42 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx | 351 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx | 676 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx | 1081 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx | 71 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx | 339 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx | 116 |
8 files changed, 2788 insertions, 0 deletions
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 <FL/Fl_Device.H> + +/** + \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 <FL/Fl.H> +# include <FL/x.H> +# include <FL/fl_draw.H> + +//////////////////////////////////////////////////////////////// +// 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_greenshift)+ + ((b&fl_bluemask)<< fl_blueshift) + ) >> 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_greenshift)+ + ((b&fl_bluemask)<< fl_blueshift) + ) >> 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<xlistsize;) { + int first_xlist = i; + const char *p = xlist[i++]; + char canon[1024]; + int size = to_canonical(canon, p, sizeof(canon)); + if (size >= 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 <X11/Xft/Xft.h> + +// 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 <X11/Xft/Xft.h> + +#include <math.h> + +// 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 <FL/fl_draw.H> +#include <FL/x.H> +#include <FL/math.h> + + +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$". +// |
