diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2016-01-26 21:01:09 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2016-01-26 21:01:09 +0000 |
| commit | ac275b89bcd8333dd1b05bfc9f6fc0accd8e065d (patch) | |
| tree | e4fcd53eee80ae26f2e4500b99bbee9f211a2bd2 /src/drivers | |
| parent | f1a2730855e544fbc0973aba7e76f18d377a893c (diff) | |
Moved Quartz graphics driver to the new naming scheme
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11057 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h | 123 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx | 75 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx | 82 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx | 588 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx | 98 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx | 289 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx | 142 |
7 files changed, 1397 insertions, 0 deletions
diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h new file mode 100644 index 000000000..ae597fe13 --- /dev/null +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h @@ -0,0 +1,123 @@ +// +// "$Id: quartz.H 11017 2016-01-20 21:40:12Z matt $" +// +// Definition of Apple Quartz graphics driver +// for the Fast Light Tool Kit (FLTK). +// +// Copyright 2010-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 +// + +/** + \file quartz.h + \brief Definition of Apple Quartz graphics driver. + */ + +#ifndef FL_CFG_GFX_QUARTZ_H +#define FL_CFG_GFX_QUARTZ_H + +#include <FL/Fl_Device.H> + + +// typedef what the x,y fields in a point are: +// FIXME: this is still defined in Fl_Device.H, but should be invisible to the user +//typedef float COORD_T; +//typedef struct { float x; float y; } QPoint; + + +/** + \brief The Mac OS X-specific graphics class. + * + This class is implemented only on the Mac OS X platform. + */ +class FL_EXPORT Fl_Quartz_Graphics_Driver : public Fl_Graphics_Driver { +public: + static const char *class_id; + const char *class_name() {return class_id;}; + + 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); + int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); + 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); +#if ! defined(FL_DOXYGEN) + static Fl_Offscreen create_offscreen_with_alpha(int w, int h); +#endif + void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +protected: + // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/quartz_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); + // --- implementation is in src/fl_font.cxx which includes src/cfg_gfx/xxx_font.cxx + void draw(const char *str, int n, int x, int y); + void draw(const char *str, int n, float x, float 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 fsize); + 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(); +}; + + +#endif // FL_CFG_GFX_QUARTZ_H + +// +// End of "$Id: quartz.H 11017 2016-01-20 21:40:12Z matt $". +// diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx new file mode 100644 index 000000000..c6288d7fe --- /dev/null +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx @@ -0,0 +1,75 @@ +// +// "$Id$" +// +// Arc (integer) drawing functions 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_QUARTZ_ARCI_CXX +#define FL_CFG_GFX_QUARTZ_ARCI_CXX + +#include "Fl_Quartz_Graphics_Driver.h" + +/** + \file quartz_arci.cxx + \brief Utility functions for drawing circles using integers +*/ + +void Fl_Quartz_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { + if (w <= 0 || h <= 0) return; + a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; + float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; + CGContextSetShouldAntialias(fl_gc, true); + if (w!=h) { + CGContextSaveGState(fl_gc); + CGContextTranslateCTM(fl_gc, cx, cy); + CGContextScaleCTM(fl_gc, w-1.0f, h-1.0f); + CGContextAddArc(fl_gc, 0, 0, 0.5, a1, a2, 1); + CGContextRestoreGState(fl_gc); + } else { + float r = (w+h)*0.25f-0.5f; + CGContextAddArc(fl_gc, cx, cy, r, a1, a2, 1); + } + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { + if (w <= 0 || h <= 0) return; + a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; + float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; + CGContextSetShouldAntialias(fl_gc, true); + if (w!=h) { + CGContextSaveGState(fl_gc); + CGContextTranslateCTM(fl_gc, cx, cy); + CGContextScaleCTM(fl_gc, w, h); + CGContextAddArc(fl_gc, 0, 0, 0.5, a1, a2, 1); + CGContextAddLineToPoint(fl_gc, 0, 0); + CGContextClosePath(fl_gc); + CGContextRestoreGState(fl_gc); + } else { + float r = (w+h)*0.25f; + CGContextAddArc(fl_gc, cx, cy, r, a1, a2, 1); + CGContextAddLineToPoint(fl_gc, cx, cy); + CGContextClosePath(fl_gc); + } + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +#endif // FL_CFG_GFX_QUARTZ_ARCI_CXX + +// +// End of "$Id$". +// diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx new file mode 100644 index 000000000..178fb6604 --- /dev/null +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx @@ -0,0 +1,82 @@ +// +// "$Id$" +// +// MacOS color functions 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 +// + +// The fltk "colormap". This allows ui colors to be stored in 8-bit +// locations, and provides a level of indirection so that global color +// changes can be made. Not to be confused with the X colormap, which +// I try to hide completely. + +// matt: Neither Quartz nor Quickdraw support colormaps in this implementation +// matt: Quartz support done + +#include "Fl_Quartz_Graphics_Driver.h" + +#include <config.h> +#include <FL/Fl.H> +#include <FL/x.H> +#include <FL/fl_draw.H> + +static unsigned fl_cmap[256] = { +#include "../../fl_cmap.h" // this is a file produced by "cmap.cxx": +}; + +void Fl_Quartz_Graphics_Driver::color(Fl_Color i) { + Fl_Graphics_Driver::color(i); + int index; + uchar r, g, b; + if (i & 0xFFFFFF00) { + // translate rgb colors into color index + r = i>>24; + g = i>>16; + b = i>> 8; + } else { + // translate index into rgb: + index = i; + unsigned c = fl_cmap[i]; + r = c>>24; + g = c>>16; + b = c>> 8; + } + if (!fl_gc) return; // no context yet? We will assign the color later. + float fr = r/255.0f; + float fg = g/255.0f; + float fb = b/255.0f; + CGContextSetRGBFillColor(fl_gc, fr, fg, fb, 1.0f); + CGContextSetRGBStrokeColor(fl_gc, fr, fg, fb, 1.0f); +} + +void Fl_Quartz_Graphics_Driver::color(uchar r, uchar g, uchar b) { + Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) ); + float fr = r/255.0f; + float fg = g/255.0f; + float fb = b/255.0f; + if (!fl_gc) return; // no context yet? We will assign the color later. + CGContextSetRGBFillColor(fl_gc, fr, fg, fb, 1.0f); + CGContextSetRGBStrokeColor(fl_gc, fr, fg, fb, 1.0f); +} + +// FIXME: this function should not be here! It's not part of the driver. +void Fl::set_color(Fl_Color i, unsigned c) { + if (fl_cmap[i] != c) { + fl_cmap[i] = c; + } +} + +// +// End of "$Id$". +// diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx new file mode 100644 index 000000000..b48a14f4a --- /dev/null +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx @@ -0,0 +1,588 @@ +// +// "$Id$" +// +// MacOS font selection 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 +// + +#include "Fl_Quartz_Graphics_Driver.h" + +#include <config.h> +#include <math.h> + +Fl_Fontdesc* fl_fonts = NULL; + +/* from fl_utf.c */ +extern unsigned fl_utf8toUtf16(const char* src, unsigned srclen, unsigned short* dst, unsigned dstlen); + +static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 }; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +static CFMutableDictionaryRef attributes = NULL; +#endif + +const int Fl_X::CoreText_threshold = 100500; // this represents Mac OS 10.5 +// condition when the ATSU API is available at compile time +#define HAS_ATSU (!__LP64__) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11 + +Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) { + next = 0; +# if HAVE_GL + listbase = 0; +# endif + +// knowWidths = 0; + // OpenGL needs those for its font handling + size = Size; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +if (fl_mac_os_version >= Fl_X::CoreText_threshold) { + CFStringRef str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); + fontref = CTFontCreateWithName(str, size, NULL); + CGGlyph glyph[2]; + const UniChar A[2]={'W','.'}; + CTFontGetGlyphsForCharacters(fontref, A, glyph, 2); + CGSize advances[2]; + double w; + CTFontGetAdvancesForGlyphs(fontref, kCTFontHorizontalOrientation, glyph, advances, 2); + w = advances[0].width; + if ( fabs(advances[0].width - advances[1].width) < 1E-2 ) {//this is a fixed-width font + // slightly rescale fixed-width fonts so the character width has an integral value + CFRelease(fontref); + CGFloat fsize = size / ( w/floor(w + 0.5) ); + fontref = CTFontCreateWithName(str, fsize, NULL); + w = CTFontGetAdvancesForGlyphs(fontref, kCTFontHorizontalOrientation, glyph, NULL, 1); + } + CFRelease(str); + ascent = (short)(CTFontGetAscent(fontref) + 0.5); + descent = (short)(CTFontGetDescent(fontref) + 0.5); + q_width = w + 0.5; + for (unsigned i = 0; i < sizeof(width)/sizeof(float*); i++) width[i] = NULL; + if (!attributes) { + static CFNumberRef zero_ref; + float zero = 0.; + zero_ref = CFNumberCreate(NULL, kCFNumberFloat32Type, &zero); + // deactivate kerning for all fonts, so that string width = sum of character widths + // which allows fast fl_width() implementation. + attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, + 3, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue (attributes, kCTKernAttributeName, zero_ref); + } + if (ascent == 0) { // this may happen with some third party fonts + CFDictionarySetValue (attributes, kCTFontAttributeName, fontref); + CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, CFSTR("Wj"), attributes); + CTLineRef ctline = CTLineCreateWithAttributedString(mastr); + CFRelease(mastr); + CGFloat fascent, fdescent; + CTLineGetTypographicBounds(ctline, &fascent, &fdescent, NULL); + CFRelease(ctline); + ascent = (short)(fascent + 0.5); + descent = (short)(fdescent + 0.5); + } +} +else { +#endif +#if HAS_ATSU + OSStatus err; + // fill our structure with a few default values + ascent = Size*3/4.; + descent = Size-ascent; + q_width = Size*2/3.; + // now we allocate everything needed to render text in this font later + // get us the default layout and style + err = ATSUCreateTextLayout(&layout); + UniChar mTxt[2] = { 65, 0 }; + err = ATSUSetTextPointerLocation(layout, mTxt, kATSUFromTextBeginning, 1, 1); + err = ATSUCreateStyle(&style); + err = ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd); + // now set the actual font, size and attributes. We also set the font matrix to + // render our font up-side-down, so when rendered through our inverted CGContext, + // text will appear normal again. + Fixed fsize = IntToFixed(Size); + ATSUFontID fontID; + ATSUFindFontFromName(name, strlen(name), kFontFullName, kFontMacintoshPlatform, kFontNoScriptCode, kFontEnglishLanguage, &fontID); + + // draw the font upside-down... Compensate for fltk/OSX origin differences + ATSUAttributeTag sTag[] = { kATSUFontTag, kATSUSizeTag, kATSUFontMatrixTag }; + ByteCount sBytes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(CGAffineTransform) }; + ATSUAttributeValuePtr sAttr[] = { &fontID, &fsize, &font_mx }; + if (fontID != kATSUInvalidFontID) err = ATSUSetAttributes(style, 1, sTag, sBytes, sAttr); // set the font attribute + err = ATSUSetAttributes(style, 2, sTag + 1, sBytes + 1, sAttr + 1); // then the size and matrix attributes + // next, make sure that Quartz will only render at integer coordinates + ATSLineLayoutOptions llo = kATSLineUseDeviceMetrics | kATSLineDisableAllLayoutOperations; + ATSUAttributeTag aTag[] = { kATSULineLayoutOptionsTag }; + ByteCount aBytes[] = { sizeof(ATSLineLayoutOptions) }; + ATSUAttributeValuePtr aAttr[] = { &llo }; + err = ATSUSetLineControls (layout, kATSUFromTextBeginning, 1, aTag, aBytes, aAttr); + // now we are finally ready to measure some letter to get the bounding box + Fixed bBefore, bAfter, bAscent, bDescent; + err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, 1, &bBefore, &bAfter, &bAscent, &bDescent); + // Requesting a certain height font on Mac does not guarantee that ascent+descent + // equal the requested height. fl_height will reflect the actual height that we got. + // The font "Apple Chancery" is a pretty extreme example of overlapping letters. + float fa = -FixedToFloat(bAscent), fd = -FixedToFloat(bDescent); + if (fa>0.0f && fd>0.0f) { + //float f = Size/(fa+fd); + ascent = int(fa); //int(fa*f+0.5f); + descent = int(fd); //Size - ascent; + } + int w = FixedToInt(bAfter); + if (w) + q_width = FixedToInt(bAfter); + +# define ENABLE_TRANSIENT_FONTS 1 + +# ifdef ENABLE_TRANSIENT_FONTS + // Now, by way of experiment, try enabling Transient Font Matching, this will + // cause ATSU to find a suitable font to render any chars the current font can't do... + ATSUSetTransientFontMatching (layout, true); +# endif +#endif//HAS_ATSU +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + } +#endif +} + +Fl_Font_Descriptor::~Fl_Font_Descriptor() { +/* +#if HAVE_GL + // ++ todo: remove OpenGL font alocations +// 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); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + if (fl_mac_os_version >= Fl_X::CoreText_threshold) { + CFRelease(fontref); + for (unsigned i = 0; i < sizeof(width)/sizeof(float*); i++) { + if (width[i]) free(width[i]); + } + } +#endif +} + +//////////////////////////////////////////////////////////////// + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +static Fl_Fontdesc built_in_table_PS[] = { // PostScript font names preferred when Mac OS ≥ 10.5 +{"ArialMT"}, +{"Arial-BoldMT"}, +{"Arial-ItalicMT"}, +{"Arial-BoldItalicMT"}, +{"Courier"}, +{"Courier-Bold"}, +{"Courier-Oblique"}, +{"Courier-BoldOblique"}, +{"TimesNewRomanPSMT"}, +{"TimesNewRomanPS-BoldMT"}, +{"TimesNewRomanPS-ItalicMT"}, +{"TimesNewRomanPS-BoldItalicMT"}, +{"Symbol"}, +{"Monaco"}, +{"AndaleMono"}, // there is no bold Monaco font on standard Mac +{"ZapfDingbatsITC"} +}; +#endif + +static Fl_Fontdesc built_in_table_full[] = { // full font names used before 10.5 + {"Arial"}, + {"Arial Bold"}, + {"Arial Italic"}, + {"Arial Bold Italic"}, + {"Courier"}, + {"Courier Bold"}, + {"Courier New Italic"}, + {"Courier New Bold Italic"}, + {"Times New Roman"}, + {"Times New Roman Bold"}, + {"Times New Roman Italic"}, + {"Times New Roman Bold Italic"}, + {"Symbol"}, + {"Monaco"}, + {"Andale Mono"}, // there is no bold Monaco font on standard Mac + {"Webdings"} +}; + +static UniChar *utfWbuf = 0; +static unsigned utfWlen = 0; + +static UniChar *mac_Utf8_to_Utf16(const char *txt, int len, int *new_len) +{ + unsigned wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); + if (wlen >= utfWlen) + { + utfWlen = wlen + 100; + if (utfWbuf) free(utfWbuf); + utfWbuf = (UniChar*)malloc((utfWlen)*sizeof(UniChar)); + wlen = fl_utf8toUtf16(txt, len, (unsigned short*)utfWbuf, utfWlen); + } + *new_len = wlen; + return utfWbuf; +} // mac_Utf8_to_Utf16 + +Fl_Fontdesc* Fl_X::calc_fl_fonts(void) +{ + if (!fl_mac_os_version) fl_mac_os_version = calc_mac_os_version(); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + return (fl_mac_os_version >= Fl_X::CoreText_threshold ? built_in_table_PS : built_in_table_full); +#else + return built_in_table_full; +#endif +} + +static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) { + if (!fl_fonts) fl_fonts = Fl_X::calc_fl_fonts(); + Fl_Fontdesc* s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // use 0 if fnum undefined + Fl_Font_Descriptor* f; + for (f = s->first; f; f = f->next) + if (f->size == size) return f; + f = new Fl_Font_Descriptor(s->name, size); + f->next = s->first; + s->first = f; + return f; +} + +//////////////////////////////////////////////////////////////// +// Public interface: + +void Fl_Quartz_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { + if (fnum==-1) { + Fl_Graphics_Driver::font(0, 0); + return; + } + Fl_Graphics_Driver::font(fnum, size); + this->font_descriptor( find(fnum, size) ); +} + +int Fl_Quartz_Graphics_Driver::height() { + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + Fl_Font_Descriptor *fl_fontsize = font_descriptor(); + return fl_fontsize->ascent + fl_fontsize->descent; +} + +int Fl_Quartz_Graphics_Driver::descent() { + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + Fl_Font_Descriptor *fl_fontsize = font_descriptor(); + return fl_fontsize->descent+1; +} + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +// returns width of a pair of UniChar's in the surrogate range +static CGFloat surrogate_width(const UniChar *txt, Fl_Font_Descriptor *fl_fontsize) +{ + CTFontRef font2 = fl_fontsize->fontref; + bool must_release = false; + CGGlyph glyphs[2]; + bool b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2); + CGSize a; + if(!b) { // the current font doesn't contain this char + CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, txt, 2, kCFAllocatorNull); + // find a font that contains it + font2 = CTFontCreateForString(font2, str, CFRangeMake(0,2)); + must_release = true; + CFRelease(str); + b = CTFontGetGlyphsForCharacters(font2, txt, glyphs, 2); + } + if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontHorizontalOrientation, glyphs, &a, 1); + else a.width = fl_fontsize->q_width; + if(must_release) CFRelease(font2); + return a.width; +} + +static CGFloat variation_selector_width(CFStringRef str16, Fl_Font_Descriptor *fl_fontsize) +{ + CGFloat retval; + CFDictionarySetValue(attributes, kCTFontAttributeName, fl_fontsize->fontref); + CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); + CTLineRef ctline = CTLineCreateWithAttributedString(mastr); + CFRelease(mastr); + retval = CTLineGetOffsetForStringIndex(ctline, 2, NULL); + CFRelease(ctline); + return retval; +} +#endif + +static double fl_mac_width(const UniChar* txt, int n, Fl_Font_Descriptor *fl_fontsize) { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +if (fl_mac_os_version >= Fl_X::CoreText_threshold) { + double retval = 0; + UniChar uni; + int i; + for (i = 0; i < n; i++) { // loop over txt + uni = txt[i]; + if (uni >= 0xD800 && uni <= 0xDBFF) { // handles the surrogate range + retval += surrogate_width(&txt[i], fl_fontsize); + i++; // because a pair of UniChar's represent a single character + continue; + } + if (i+1 < n && txt[i+1] >= 0xFE00 && txt[i+1] <= 0xFE0F) { // handles variation selectors + CFStringRef substr = CFStringCreateWithCharacters(NULL, txt + i, 2); + retval += variation_selector_width(substr, fl_fontsize); + CFRelease(substr); + i++; + continue; + } + const int block = 0x10000 / (sizeof(fl_fontsize->width)/sizeof(float*)); // block size + // r: index of the character block containing uni + unsigned int r = uni >> 7; // change 7 if sizeof(width) is changed + if (!fl_fontsize->width[r]) { // this character block has not been hit yet + //fprintf(stderr,"r=%d size=%d name=%s\n",r,fl_fontsize->size,fl_fonts[fl_font()].name); + // allocate memory to hold width of each character in the block + fl_fontsize->width[r] = (float*) malloc(sizeof(float) * block); + UniChar ii = r * block; + CGSize advance_size; + CGGlyph glyph; + for (int j = 0; j < block; j++) { // loop over the block + // ii spans all characters of this block + bool b = CTFontGetGlyphsForCharacters(fl_fontsize->fontref, &ii, &glyph, 1); + if (b) + CTFontGetAdvancesForGlyphs(fl_fontsize->fontref, kCTFontHorizontalOrientation, &glyph, &advance_size, 1); + else + advance_size.width = -1e9; // calculate this later + // the width of one character of this block of characters + fl_fontsize->width[r][j] = advance_size.width; + ii++; + } + } + // sum the widths of all characters of txt + double wdt = fl_fontsize->width[r][uni & (block-1)]; + if (wdt == -1e9) { + CGSize advance_size; + CGGlyph glyph; + CTFontRef font2 = fl_fontsize->fontref; + bool must_release = false; + bool b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1); + if (!b) { // the current font doesn't contain this char + CFStringRef str = CFStringCreateWithCharactersNoCopy(NULL, &uni, 1, kCFAllocatorNull); + // find a font that contains it + font2 = CTFontCreateForString(font2, str, CFRangeMake(0,1)); + must_release = true; + CFRelease(str); + b = CTFontGetGlyphsForCharacters(font2, &uni, &glyph, 1); + } + if (b) CTFontGetAdvancesForGlyphs(font2, kCTFontHorizontalOrientation, &glyph, &advance_size, 1); + else advance_size.width = 0.; + // the width of the 'uni' character + wdt = fl_fontsize->width[r][uni & (block-1)] = advance_size.width; + if (must_release) CFRelease(font2); + } + retval += wdt; + } + return retval; +} else { +#endif +#if HAS_ATSU + OSStatus err; + Fixed bBefore, bAfter, bAscent, bDescent; + ATSUTextLayout layout; + ByteCount iSize; + ATSUAttributeTag iTag; + ATSUAttributeValuePtr iValuePtr; + + // Here's my ATSU text measuring attempt... This seems to do the Right Thing + // now collect our ATSU resources and measure our text string + layout = fl_fontsize->layout; + // activate the current GC + iSize = sizeof(CGContextRef); + iTag = kATSUCGContextTag; + iValuePtr = &fl_gc; + ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); + // now measure the bounding box + err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n); + err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, n, &bBefore, &bAfter, &bAscent, &bDescent); + // If err is OK then return length, else return 0. Or something... + int len = FixedToInt(bAfter); + return len; +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + } +#endif + return 0; +} + +double Fl_Quartz_Graphics_Driver::width(const char* txt, int n) { + int wc_len = n; + UniChar *uniStr = mac_Utf8_to_Utf16(txt, n, &wc_len); + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + return fl_mac_width(uniStr, wc_len, font_descriptor()); +} + +double Fl_Quartz_Graphics_Driver::width(unsigned int wc) { + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + + UniChar utf16[3]; + int l = 1; + if (wc <= 0xFFFF) { + *utf16 = wc; + } + else { +// char buf[4]; +// l = fl_utf8encode(wc, buf); +// l = (int)fl_utf8toUtf16(buf, l, utf16, 3); + l = (int)fl_ucs_to_Utf16(wc, utf16, 3); + } + return fl_mac_width(utf16, l, font_descriptor()); +} + +// text extent calculation +void Fl_Quartz_Graphics_Driver::text_extents(const char *str8, int n, int &dx, int &dy, int &w, int &h) { + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + Fl_Font_Descriptor *fl_fontsize = font_descriptor(); + UniChar *txt = mac_Utf8_to_Utf16(str8, n, &n); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +if (fl_mac_os_version >= Fl_X::CoreText_threshold) { + CFStringRef str16 = CFStringCreateWithCharactersNoCopy(NULL, txt, n, kCFAllocatorNull); + CFDictionarySetValue (attributes, kCTFontAttributeName, fl_fontsize->fontref); + CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); + CFRelease(str16); + CTLineRef ctline = CTLineCreateWithAttributedString(mastr); + CFRelease(mastr); + CGContextSetTextPosition(fl_gc, 0, 0); + CGContextSetShouldAntialias(fl_gc, true); + CGRect rect = CTLineGetImageBounds(ctline, fl_gc); + CGContextSetShouldAntialias(fl_gc, false); + CFRelease(ctline); + dx = floor(rect.origin.x + 0.5); + dy = floor(- rect.origin.y - rect.size.height + 0.5); + w = rect.size.width + 0.5; + h = rect.size.height + 0.5; + } +else { +#endif +#if HAS_ATSU + OSStatus err; + ATSUTextLayout layout; + ByteCount iSize; + ATSUAttributeTag iTag; + ATSUAttributeValuePtr iValuePtr; + +// Here's my ATSU text measuring attempt... This seems to do the Right Thing + // now collect our ATSU resources and measure our text string + layout = fl_fontsize->layout; + // activate the current GC + iSize = sizeof(CGContextRef); + iTag = kATSUCGContextTag; + iValuePtr = &fl_gc; + ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); + // now measure the bounding box + err = ATSUSetTextPointerLocation(layout, txt, kATSUFromTextBeginning, n, n); + Rect bbox; + err = ATSUMeasureTextImage(layout, kATSUFromTextBeginning, n, 0, 0, &bbox); + w = bbox.right - bbox.left; + h = bbox.bottom - bbox.top; + dx = bbox.left; + dy = -bbox.bottom; +//printf("r: %d l: %d t: %d b: %d w: %d h: %d\n", bbox.right, bbox.left, bbox.top, bbox.bottom, w, h); +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + } +#endif + return; +} // fl_text_extents + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +static CGColorRef flcolortocgcolor(Fl_Color i) +{ + uchar r, g, b; + Fl::get_color(i, r, g, b); + CGFloat components[4] = {r/255.0f, g/255.0f, b/255.0f, 1.}; + static CGColorSpaceRef cspace = NULL; + if (cspace == NULL) { + cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + } + return CGColorCreate(cspace, components); +} +#endif + +static void fl_mac_draw(const char *str, int n, float x, float y, Fl_Graphics_Driver *driver) { + // convert to UTF-16 first + UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + if (fl_mac_os_version >= Fl_X::CoreText_threshold) { + CFMutableStringRef str16 = CFStringCreateMutableWithExternalCharactersNoCopy(NULL, uniStr, n, n, kCFAllocatorNull); + if (str16 == NULL) return; // shd not happen + CGColorRef color = flcolortocgcolor(driver->color()); + CFDictionarySetValue (attributes, kCTFontAttributeName, driver->font_descriptor()->fontref); + CFDictionarySetValue (attributes, kCTForegroundColorAttributeName, color); + CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes); + CFRelease(str16); + CFRelease(color); + CTLineRef ctline = CTLineCreateWithAttributedString(mastr); + CFRelease(mastr); + CGContextSetTextMatrix(fl_gc, font_mx); + CGContextSetTextPosition(fl_gc, x, y); + CGContextSetShouldAntialias(fl_gc, true); + CTLineDraw(ctline, fl_gc); + CGContextSetShouldAntialias(fl_gc, false); + CFRelease(ctline); + } else { +#endif +#if HAS_ATSU + OSStatus err; + // now collect our ATSU resources + ATSUTextLayout layout = driver->font_descriptor()->layout; + + ByteCount iSize = sizeof(CGContextRef); + ATSUAttributeTag iTag = kATSUCGContextTag; + ATSUAttributeValuePtr iValuePtr=&fl_gc; + ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); + + err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n); + CGContextSetShouldAntialias(fl_gc, true); + err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y)); + CGContextSetShouldAntialias(fl_gc, false); +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + } +#endif +} + +void Fl_Quartz_Graphics_Driver::draw(const char *str, int n, float x, float y) { + // avoid a crash if no font has been selected by user yet ! + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + fl_mac_draw(str, n, x, y, this); +} + +void Fl_Quartz_Graphics_Driver::draw(const char* str, int n, int x, int y) { + // avoid a crash if no font has been selected by user yet ! + if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); + fl_mac_draw(str, n, (float)x-0.0f, (float)y+0.5f, this); +} + +void Fl_Quartz_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { + CGContextSaveGState(fl_gc); + CGContextTranslateCTM(fl_gc, x, y); + CGContextRotateCTM(fl_gc, - angle*(M_PI/180) ); + draw(str, n, 0, 0); + CGContextRestoreGState(fl_gc); +} + +void Fl_Quartz_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { + int dx, dy, w, h; + text_extents(c, n, dx, dy, w, h); + draw(c, n, x - w - dx, y); +} + +// +// End of "$Id$". +// diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx new file mode 100644 index 000000000..a70a067b6 --- /dev/null +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx @@ -0,0 +1,98 @@ +// +// "$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_QUARTZ_LINE_STYLE_CXX +#define FL_CFG_GFX_QUARTZ_LINE_STYLE_CXX + +/** + \file quartz_line_style.cxx + \brief Line style drawing utility hiding different platforms. +*/ + +#include "Fl_Quartz_Graphics_Driver.h" + +float fl_quartz_line_width_ = 1.0f; +static /*enum*/ CGLineCap fl_quartz_line_cap_ = kCGLineCapButt; +static /*enum*/ CGLineJoin fl_quartz_line_join_ = kCGLineJoinMiter; +static CGFloat *fl_quartz_line_pattern = 0; +static int fl_quartz_line_pattern_size = 0; + +void fl_quartz_restore_line_style_() { + CGContextSetLineWidth(fl_gc, fl_quartz_line_width_); + CGContextSetLineCap(fl_gc, fl_quartz_line_cap_); + CGContextSetLineJoin(fl_gc, fl_quartz_line_join_); + CGContextSetLineDash(fl_gc, 0, fl_quartz_line_pattern, fl_quartz_line_pattern_size); +} + +void Fl_Quartz_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; + + static /*enum*/ CGLineCap Cap[4] = { kCGLineCapButt, kCGLineCapButt, + kCGLineCapRound, kCGLineCapSquare }; + static /*enum*/ CGLineJoin Join[4] = { kCGLineJoinMiter, kCGLineJoinMiter, + kCGLineJoinRound, kCGLineJoinBevel }; + if (width<1) width = 1; + fl_quartz_line_width_ = (float)width; + fl_quartz_line_cap_ = Cap[(style>>8)&3]; + // when printing kCGLineCapSquare seems better for solid lines + if ( Fl_Surface_Device::surface() != Fl_Display_Device::display_device() && style == FL_SOLID && dashes == NULL ) { + fl_quartz_line_cap_ = kCGLineCapSquare; + } + fl_quartz_line_join_ = Join[(style>>12)&3]; + char *d = dashes; + static CGFloat pattern[16]; + if (d && *d) { + CGFloat *p = pattern; + while (*d) { *p++ = (float)*d++; } + fl_quartz_line_pattern = pattern; + fl_quartz_line_pattern_size = d-dashes; + } else if (style & 0xff) { + char dash, dot, gap; + // adjust lengths to account for cap: + if (style & 0x200) { + dash = char(2*width); + dot = 1; + gap = char(2*width-1); + } else { + dash = char(3*width); + dot = gap = char(width); + } + CGFloat *p = pattern; + 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; + } + fl_quartz_line_pattern_size = p-pattern; + fl_quartz_line_pattern = pattern; + } else { + fl_quartz_line_pattern = 0; + fl_quartz_line_pattern_size = 0; + } + fl_quartz_restore_line_style_(); +} + +#endif // FL_CFG_GFX_QUARTZ_LINE_STYLE_CXX + +// +// End of "$Id$". +// diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx new file mode 100644 index 000000000..63dcd07a8 --- /dev/null +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx @@ -0,0 +1,289 @@ +// +// "$Id$" +// +// Rectangle 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_QUARTZ_RECT_CXX +#define FL_CFG_GFX_QUARTZ_RECT_CXX + + +/** + \file quartz_rect.cxx + \brief Apple Quartz specific line and polygon drawing with integer coordinates. +*/ + + +#include "Fl_Quartz_Graphics_Driver.h" + + +extern float fl_quartz_line_width_; + +// FIXME: the use of the macro below can be avoided by adding a specific class +// for drawing to the prinitng context +#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) + + +// --- line and polygon drawing with integer coordinates + +void Fl_Quartz_Graphics_Driver::point(int x, int y) { + CGContextFillRect(fl_gc, CGRectMake(x - 0.5, y - 0.5, 1, 1) ); +} + +void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + // FIXME: there should be a quartz graphics driver for the printer device that makes the USINGQUARTZPRINTER obsolete + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGRect rect = CGRectMake(x, y, w-1, h-1); + CGContextStrokeRect(fl_gc, rect); + if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; + CGRect rect = CGRectMake(x - 0.5, y - 0.5, w , h); + CGContextFillRect(fl_gc, rect); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit + (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles + of size one unit by line-width. + */ + CGContextFillRect(fl_gc, CGRectMake(x-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1-0.5 , y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x1 - fl_quartz_line_width_/2, y2-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextAddLineToPoint(fl_gc, x3, y2); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x-0.5, y - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + CGContextFillRect(fl_gc, CGRectMake(x3-0.5, y2 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y1-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2-0.5, y1 - fl_quartz_line_width_/2, 1 , fl_quartz_line_width_)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextAddLineToPoint(fl_gc, x2, y3); + CGContextStrokePath(fl_gc); + if (Fl_Display_Device::high_resolution()) { + CGContextFillRect(fl_gc, CGRectMake(x - fl_quartz_line_width_/2, y-0.5, fl_quartz_line_width_, 1)); + CGContextFillRect(fl_gc, CGRectMake(x2 - fl_quartz_line_width_/2, y3-0.5, fl_quartz_line_width_, 1)); + } + if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y1); + CGContextAddLineToPoint(fl_gc, x2, y2); + CGContextAddLineToPoint(fl_gc, x3, y3); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +// --- clipping + +void Fl_Quartz_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) { + XDestroyRegion(r); + r = Fl_X::intersect_region_and_rect(current, x,y,w,h); + } + } else { // make empty clip region: + r = XRectangleRegion(0,0,0,0); + } + if (rstackptr < region_stack_max) rstack[++rstackptr] = r; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +int Fl_Quartz_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; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + CGRect u = CGRectMake(0,0,0,0); + CGRect test; + for (int i = 0; i < r->count; i++) { + test = CGRectIntersection(r->rects[i], arg); + if ( !CGRectIsEmpty(test) ) { + if(CGRectIsEmpty(u)) u = test; + else u = CGRectUnion(u, test); + } + } + X = int(u.origin.x + 0.5); // reverse offset introduced by fl_cgrectmake_cocoa() + Y = int(u.origin.y + 0.5); + W = int(u.size.width + 0.5); // round to nearest integer + H = int(u.size.height + 0.5); + if (CGRectIsEmpty(u)) W = H = 0; + return !CGRectEqualToRect(arg, u); +} + +int Fl_Quartz_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; + CGRect arg = fl_cgrectmake_cocoa(x, y, w, h); + for (int i = 0; i < r->count; i++) { + CGRect test = CGRectIntersection(r->rects[i], arg); + if (!CGRectIsEmpty(test)) return 1; + } + return 0; +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void Fl_Quartz_Graphics_Driver::push_no_clip() { + if (rstackptr < region_stack_max) rstack[++rstackptr] = 0; + else Fl::warning("Fl_Quartz_Graphics_Driver::push_no_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void Fl_Quartz_Graphics_Driver::pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("Fl_Quartz_Graphics_Driver::pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +void Fl_Quartz_Graphics_Driver::restore_clip() { + fl_clip_state_number++; + Fl_Region r = rstack[rstackptr]; + if ( fl_window || fl_gc ) { // clipping for a true window or an offscreen buffer + Fl_X::q_clear_clipping(); + Fl_X::q_fill_context();//flip coords if bitmap context + //apply program clip + if (r) { + CGContextClipToRects(fl_gc, r->rects, r->count); + } + } +} + + +#endif // FL_CFG_GFX_QUARTZ_RECT_CXX + +// +// End of "$Id$". +// diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx new file mode 100644 index 000000000..b7404e299 --- /dev/null +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx @@ -0,0 +1,142 @@ +// +// "$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_QUARTZ_VERTEX_CXX +#define FL_CFG_GFX_QUARTZ_VERTEX_CXX + +/** + \file quartz_vertex.cxx + \brief Portable drawing code for drawing arbitrary shapes with + simple 2D transformations, implemented for OS X Quartz. +*/ + +#include "Fl_Quartz_Graphics_Driver.h" + +#include <FL/fl_draw.H> +#include <FL/x.H> +#include <FL/math.h> + + +void Fl_Quartz_Graphics_Driver::transformed_vertex(double xf, double yf) { + transformed_vertex0(COORD_T(xf), COORD_T(yf)); +} + +void Fl_Quartz_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_Quartz_Graphics_Driver::end_points() { + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true); + for (int i=0; i<n; i++) { + CGContextMoveToPoint(fl_gc, p[i].x, p[i].y); + CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y); + CGContextStrokePath(fl_gc); + } + if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::end_line() { + if (n < 2) { + end_points(); + return; + } + if (n<=1) return; + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, p[0].x, p[0].y); + for (int i=1; i<n; i++) + CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y); + CGContextStrokePath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::end_loop() { + fixloop(); + if (n>2) transformed_vertex((COORD_T)p[0].x, (COORD_T)p[0].y); + end_line(); +} + +void Fl_Quartz_Graphics_Driver::end_polygon() { + fixloop(); + if (n < 3) { + end_line(); + return; + } + if (n<=1) return; + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, p[0].x, p[0].y); + for (int i=1; i<n; i++) + CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_Graphics_Driver::begin_complex_polygon() { + begin_polygon(); + gap_ = 0; +} + +void Fl_Quartz_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_Quartz_Graphics_Driver::end_complex_polygon() { + gap(); + if (n < 3) { + end_line(); + return; + } + if (n<=1) return; + CGContextSetShouldAntialias(fl_gc, true); + CGContextMoveToPoint(fl_gc, p[0].x, p[0].y); + for (int i=1; i<n; i++) + CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y); + CGContextClosePath(fl_gc); + CGContextFillPath(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +void Fl_Quartz_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; + + // Quartz warning: circle won't scale to current matrix! + // Last argument must be 0 (counter-clockwise) or it draws nothing under __LP64__ !!!! + CGContextSetShouldAntialias(fl_gc, true); + CGContextAddArc(fl_gc, xt, yt, (w+h)*0.25f, 0, 2.0f*M_PI, 0); + (what == POLYGON ? CGContextFillPath : CGContextStrokePath)(fl_gc); + CGContextSetShouldAntialias(fl_gc, false); +} + +#endif // FL_CFG_GFX_QUARTZ_VERTEX_CXX + +// +// End of "$Id$". +// |
