diff options
| -rw-r--r-- | FL/Fl_Image_Surface.H | 34 | ||||
| -rw-r--r-- | src/Fl_Image_Surface.cxx | 429 |
2 files changed, 288 insertions, 175 deletions
diff --git a/FL/Fl_Image_Surface.H b/FL/Fl_Image_Surface.H index 20450be55..3236addd5 100644 --- a/FL/Fl_Image_Surface.H +++ b/FL/Fl_Image_Surface.H @@ -22,7 +22,7 @@ #include <FL/Fl_Widget_Surface.H> #include <FL/Fl_Image.H> #include <FL/Fl_Shared_Image.H> -#include <FL/x.H> +#include <FL/x.H> // for Fl_Offscreen /** Directs all graphics requests to an Fl_Image. @@ -46,33 +46,17 @@ \endcode */ class FL_EXPORT Fl_Image_Surface : public Fl_Widget_Surface { - friend Fl_Offscreen fl_create_offscreen(int, int); + friend Fl_Offscreen fl_create_offscreen(int w, int h); #ifndef FL_DOXYGEN friend Fl_Offscreen fl_create_offscreen_with_alpha(int, int);//X11 only #endif - friend void fl_begin_offscreen(Fl_Offscreen); + friend void fl_begin_offscreen(Fl_Offscreen ctx); friend void fl_end_offscreen(void); - friend void fl_delete_offscreen(Fl_Offscreen); + friend void fl_delete_offscreen(Fl_Offscreen ctx); private: - Fl_Offscreen offscreen; - int width; - int height; - Fl_Surface_Device *previous; - Window pre_window; -#if defined(__APPLE__) - int was_high; -#endif - Fl_Image_Surface(Fl_Offscreen pixmap, int w, int h); // for X11 only - void initialize_(Fl_Offscreen pixmap, int w, int h, int high_res); - void end_current(); -#ifdef __APPLE__ // PORTME: Fl_Surface_Driver - platform image surface driver -#elif defined(WIN32) - HDC _sgc; - int _savedc; -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: define variables to hold image data for Fl_Image_Surface" -#else -#endif + class Helper; + Helper *platform_surface; + Fl_Offscreen offscreen(); protected: void translate(int x, int y); void untranslate(); @@ -80,8 +64,12 @@ public: Fl_Image_Surface(int w, int h, int high_res = 0); ~Fl_Image_Surface(); void set_current(); + void end_current(); Fl_RGB_Image *image(); Fl_Shared_Image *highres_image(); + void origin(int *x, int *y); + void origin(int x, int y); + int printable_rect(int *w, int *h); }; #endif // Fl_Image_Surface_H diff --git a/src/Fl_Image_Surface.cxx b/src/Fl_Image_Surface.cxx index 4831ac197..b3e2392b7 100644 --- a/src/Fl_Image_Surface.cxx +++ b/src/Fl_Image_Surface.cxx @@ -17,45 +17,39 @@ // #include <FL/Fl_Image_Surface.H> -#include <FL/Fl_Printer.H> -#include <FL/Fl.H> -#include <FL/x.H> +#include <FL/fl_draw.H> #include "config_lib.h" + + +#if defined(__APPLE__) #ifdef FL_CFG_GFX_QUARTZ #include "drivers/Quartz/Fl_Quartz_Graphics_Driver.H" #endif -#ifdef FL_CFG_GFX_GDI -#include "drivers/GDI/Fl_GDI_Graphics_Driver.H" -#endif -#ifdef FL_CFG_GFX_XLIB -#include "drivers/Xlib/Fl_Translated_Xlib_Graphics_Driver.H" -#endif - -#if defined(WIN32) -#elif defined(__APPLE__) // PORTME: Fl_Surface_Driver - platform image surface -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement image surface handling here" -#else -#endif - -/** Constructor with optional high resolution. - \param w and \param h give the size in pixels of the resulting image. - \param high_res if non-zero, the surface pixel size is twice as high and wide as w and h, - which is useful to draw it later on a high resolution display (e.g., retina display). - This is implemented for the Mac OS platform only. - If \p highres is non-zero, use Fl_Image_Surface::highres_image() to get the image data. - \version 1.3.4 (1.3.3 without the highres parameter) - */ -Fl_Image_Surface::Fl_Image_Surface(int w, int h, int high_res) : Fl_Widget_Surface(NULL) { - initialize_((Fl_Offscreen)0, w, h, high_res); -} -void Fl_Image_Surface::initialize_(Fl_Offscreen pixmap, int w, int h, int high_res) { - width = w; - height = h; +#include <ApplicationServices/ApplicationServices.h> + +class Fl_Image_Surface::Helper : public Fl_Widget_Surface { + friend class Fl_Image_Surface; +public: + Fl_Offscreen offscreen; + Fl_Surface_Device *previous; + Window pre_window; + int was_high; + int width; + int height; + Helper(int w, int h, int high_res); + ~Helper(); + void set_current(); + void translate(int x, int y); + void untranslate(); + int printable_rect(int *w, int *h) {*w = width; *h = height; return 0;} + Fl_RGB_Image *image(); + void end_current(); +}; + +Fl_Image_Surface::Helper::Helper(int w, int h, int high_res) : Fl_Widget_Surface(NULL), width(w), height(h) { previous = 0; -#ifdef __APPLE__ // PORTME: platform image surface int W = high_res ? 2*w : w; int H = high_res ? 2*h : h; CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); @@ -72,95 +66,97 @@ void Fl_Image_Surface::initialize_(Fl_Offscreen pixmap, int w, int h, int high_r CGContextScaleCTM(offscreen, 1.0f, -1.0f); CGContextSetRGBFillColor(offscreen, 1, 1, 1, 0); CGContextFillRect(offscreen, CGRectMake(0,0,w,h)); -#elif defined(WIN32) - offscreen = CreateCompatibleBitmap( (fl_graphics_driver->gc() ? (HDC)fl_graphics_driver->gc() : fl_GetDC(0) ) , w, h); - driver(new Fl_Translated_GDI_Graphics_Driver); - _sgc = NULL; -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement Fl_Image_Surface" -#else - offscreen = pixmap ? pixmap : XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth); - driver(new Fl_Translated_Xlib_Graphics_Driver()); -#endif } -#if USE_X11 -// private constructor for X11 only -Fl_Image_Surface::Fl_Image_Surface(Fl_Offscreen pixmap, int w, int h) : Fl_Widget_Surface(NULL) { - initialize_(pixmap, w, h, 0); - } -#endif - -/** The destructor. - */ -Fl_Image_Surface::~Fl_Image_Surface() { -#ifdef __APPLE__ // PORTME: Fl_Surface_Driver - platform image surface +Fl_Image_Surface::Helper::~Helper() { void *data = CGBitmapContextGetData((CGContextRef)offscreen); free(data); CGContextRelease((CGContextRef)offscreen); -#elif defined(WIN32) - DeleteObject(offscreen); -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement Fl_Image_Surface" -#else - XFreePixmap(fl_display, offscreen); -#endif } -/** Returns an image made of all drawings sent to the Fl_Image_Surface object. - The returned object contains its own copy of the RGB data. - The caller is responsible for deleting the image. - */ -Fl_RGB_Image* Fl_Image_Surface::image() +void Fl_Image_Surface::Helper::set_current() { + pre_window = fl_window; + if (!previous) previous = Fl_Surface_Device::surface(); + driver()->gc(offscreen); + fl_window = 0; + Fl_Surface_Device::set_current(); + was_high = Fl_Display_Device::high_resolution(); + Fl_X::set_high_resolution( CGBitmapContextGetWidth(offscreen) > width ); +} + +void Fl_Image_Surface::Helper::translate(int x, int y) { + CGContextRef gc = (CGContextRef)driver()->gc(); + CGContextRestoreGState(gc); + CGContextSaveGState(gc); + CGContextTranslateCTM(gc, x, -y); + CGContextSaveGState(gc); + CGContextTranslateCTM(gc, 0, height); + CGContextScaleCTM(gc, 1.0f, -1.0f); +} + +void Fl_Image_Surface::Helper::untranslate() { + CGContextRestoreGState((CGContextRef)driver()->gc()); +} + +Fl_RGB_Image* Fl_Image_Surface::Helper::image() { unsigned char *data; int W = width, H = height; -#ifdef __APPLE__ // PORTME: platform image surface CGContextFlush(offscreen); W = CGBitmapContextGetWidth(offscreen); H = CGBitmapContextGetHeight(offscreen); data = fl_read_image(NULL, 0, 0, W, H, 0); -#elif defined(WIN32) - data = fl_read_image(NULL, 0, 0, width, height, 0); - end_current(); - previous->driver()->gc(_sgc); -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement Fl_Image_Surface" -#else - data = fl_read_image(NULL, 0, 0, width, height, 0); - end_current(); -#endif Fl_RGB_Image *image = new Fl_RGB_Image(data, W, H); image->alloc_array = 1; return image; } - -/** Returns a possibly high resolution image made of all drawings sent to the Fl_Image_Surface object. - The Fl_Image_Surface object should have been constructed with Fl_Image_Surface(W, H, 1). - The returned image is scaled to a size of WxH drawing units and may have a pixel size twice as wide and high. - The returned object should be deallocated with Fl_Shared_Image::release() after use. - \version 1.3.4 - */ -Fl_Shared_Image* Fl_Image_Surface::highres_image() +void Fl_Image_Surface::Helper::end_current() { - Fl_Shared_Image *s_img = Fl_Shared_Image::get(image()); - s_img->scale(width, height); - return s_img; + Fl_X::set_high_resolution(was_high); + previous->Fl_Surface_Device::set_current(); + fl_window = pre_window; } +#elif defined(WIN32) +#ifdef FL_CFG_GFX_GDI +#include "drivers/GDI/Fl_GDI_Graphics_Driver.H" +#endif -void Fl_Image_Surface::set_current() -{ +class Fl_Image_Surface::Helper : public Fl_Widget_Surface { + friend class Fl_Image_Surface; +public: + Fl_Offscreen offscreen; + int width; + int height; + Fl_Surface_Device *previous; + Window pre_window; + HDC _sgc; + int _savedc; + Helper(int w, int h, int high_res); + ~Helper(); + void set_current(); + void translate(int x, int y); + void untranslate(); + Fl_RGB_Image *image(); + void end_current(); + int printable_rect(int *w, int *h) {*w = width; *h = height; return 0;} +}; + +Fl_Image_Surface::Helper::Helper(int w, int h, int high_res) : Fl_Widget_Surface(NULL), width(w), height(h) { + previous = 0; + offscreen = CreateCompatibleBitmap( (fl_graphics_driver->gc() ? (HDC)fl_graphics_driver->gc() : fl_GetDC(0) ) , w, h); + driver(new Fl_Translated_GDI_Graphics_Driver); + _sgc = NULL; +} + +Fl_Image_Surface::Helper::~Helper() { + DeleteObject(offscreen); +} + +void Fl_Image_Surface::Helper::set_current() { pre_window = fl_window; if (!previous) previous = Fl_Surface_Device::surface(); -#if defined(__APPLE__) // PORTME: Fl_Surface_Driver - platform image surface - driver()->gc(offscreen); - fl_window = 0; - Fl_Surface_Device::set_current(); - was_high = Fl_Display_Device::high_resolution(); - Fl_X::set_high_resolution( CGBitmapContextGetWidth(offscreen) > width ); -#elif defined(WIN32) if (!_sgc) _sgc = (HDC)previous->driver()->gc(); HDC gc = fl_makeDC(offscreen); Fl_Surface_Device::set_current(); @@ -168,84 +164,215 @@ void Fl_Image_Surface::set_current() _savedc = SaveDC(gc); fl_window=(HWND)offscreen; fl_push_no_clip(); -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement Fl_Image_Surface" -#else - fl_window = offscreen; - Fl_Surface_Device::set_current(); - fl_push_no_clip(); -#endif } -void Fl_Image_Surface::end_current() +void Fl_Image_Surface::Helper::translate(int x, int y) { + ((Fl_Translated_GDI_Graphics_Driver*)driver())->translate_all(x, y); +} + +void Fl_Image_Surface::Helper::untranslate() { + ((Fl_Translated_GDI_Graphics_Driver*)driver())->untranslate_all(); +} + +Fl_RGB_Image* Fl_Image_Surface::Helper::image() +{ + unsigned char *data; + data = fl_read_image(NULL, 0, 0, width, height, 0); + end_current(); + previous->driver()->gc(_sgc); + Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height); + image->alloc_array = 1; + return image; +} + +void Fl_Image_Surface::Helper::end_current() { -#if defined(__APPLE__) - Fl_X::set_high_resolution(was_high); -#elif defined(WIN32) HDC gc = (HDC)driver()->gc(); RestoreDC(gc, _savedc); DeleteDC(gc); fl_pop_clip(); -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: implement Fl_Image_Surface" -#else - fl_pop_clip(); -#endif previous->Fl_Surface_Device::set_current(); fl_window = pre_window; } -#if defined(__APPLE__) // PORTME: Fl_Surface_Driver - platform image surface +#elif defined(USE_SDL) -void Fl_Image_Surface::translate(int x, int y) { - CGContextRef gc = (CGContextRef)driver()->gc(); - CGContextRestoreGState(gc); - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, x, -y); - CGContextSaveGState(gc); - CGContextTranslateCTM(gc, 0, height); - CGContextScaleCTM(gc, 1.0f, -1.0f); -} -void Fl_Image_Surface::untranslate() { - CGContextRestoreGState((CGContextRef)driver()->gc()); -} +#elif defined(FL_PORTING) +# pragma message "FL_PORTING: implement class Fl_Image_Surface::Helper for your platform" + +class Fl_Image_Surface::Helper : public Fl_Widget_Surface { // class model + friend class Fl_Image_Surface; +public: + int width; + int height; + Helper(int w, int h, int high_res) : Fl_Widget_Surface(NULL), width(w), height(h) {} // to implement + ~Helper() {} // to implement + void set_current(){} // to implement + void translate(int x, int y) {} // to implement + void untranslate() {} // to implement + Fl_RGB_Image *image() {} // to implement + void end_current() {} // to implement + int printable_rect(int *w, int *h) {*w = width; *h = height; return 0;} +}; -#elif defined(WIN32) -void Fl_Image_Surface::translate(int x, int y) { - ((Fl_Translated_GDI_Graphics_Driver*)driver())->translate_all(x, y); +#else + +#ifdef FL_CFG_GFX_XLIB +#include "drivers/Xlib/Fl_Translated_Xlib_Graphics_Driver.H" +#endif + +class Fl_Image_Surface::Helper : public Fl_Widget_Surface { +public: + Fl_Offscreen offscreen; + Fl_Surface_Device *previous; + Window pre_window; + int was_high; + int width; + int height; + Helper(int w, int h, int high_res); + Helper(Fl_Offscreen pixmap, int w, int h); + ~Helper(); + void set_current(); + void translate(int x, int y); + void untranslate(); + int printable_rect(int *w, int *h) {*w = width; *h = height; return 0;} + Fl_RGB_Image *image(); + void end_current(); + public: +}; + +Fl_Image_Surface::Helper::Helper(int w, int h, int high_res) : Fl_Widget_Surface(NULL) { + width = w; + height = h; + previous = 0; + offscreen = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth); + driver(new Fl_Translated_Xlib_Graphics_Driver()); } -void Fl_Image_Surface::untranslate() { - ((Fl_Translated_GDI_Graphics_Driver*)driver())->untranslate_all(); +Fl_Image_Surface::Helper::Helper(Fl_Offscreen pixmap, int w, int h) : Fl_Widget_Surface(NULL) { + width = w; + height = h; + previous = 0; + offscreen = pixmap; + driver(new Fl_Translated_Xlib_Graphics_Driver()); } -#elif defined(USE_SDL) +Fl_Image_Surface::Helper::~Helper() { + XFreePixmap(fl_display, offscreen); +} -#else +void Fl_Image_Surface::Helper::set_current() { + pre_window = fl_window; + if (!previous) previous = Fl_Surface_Device::surface(); + fl_window = offscreen; + Fl_Surface_Device::set_current(); + fl_push_no_clip(); +} -void Fl_Image_Surface::translate(int x, int y) { +void Fl_Image_Surface::Helper::translate(int x, int y) { ((Fl_Translated_Xlib_Graphics_Driver*)driver())->translate_all(x, y); } -void Fl_Image_Surface::untranslate() { +void Fl_Image_Surface::Helper::untranslate() { ((Fl_Translated_Xlib_Graphics_Driver*)driver())->untranslate_all(); } +Fl_RGB_Image* Fl_Image_Surface::Helper::image() +{ + unsigned char *data; + data = fl_read_image(NULL, 0, 0, width, height, 0); + end_current(); + Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height); + image->alloc_array = 1; + return image; +} + +void Fl_Image_Surface::Helper::end_current() +{ + fl_pop_clip(); + previous->Fl_Surface_Device::set_current(); + fl_window = pre_window; +} + + #endif -static Fl_Image_Surface *offscreen_api_surface[20]; +/** Constructor with optional high resolution. + \param w and \param h give the size in pixels of the resulting image. + \param high_res if non-zero, the surface pixel size is twice as high and wide as w and h, + which is useful to draw it later on a high resolution display (e.g., retina display). + This is implemented for the Mac OS platform only. + If \p highres is non-zero, use Fl_Image_Surface::highres_image() to get the image data. + \version 1.3.4 (1.3.3 without the highres parameter) + */ +Fl_Image_Surface::Fl_Image_Surface(int w, int h, int high_res) : Fl_Widget_Surface(NULL) { + platform_surface = new Helper(w, h, high_res); + driver(platform_surface->driver()); +} + +/** The destructor. + */ +Fl_Image_Surface::~Fl_Image_Surface() { delete platform_surface; } + +void Fl_Image_Surface::origin(int x, int y) {platform_surface->origin(x, y);} + +void Fl_Image_Surface::origin(int *x, int *y) {platform_surface->origin(x, y);} + +void Fl_Image_Surface::set_current() {platform_surface->set_current();} + +/** Stop sending graphics commands to the surface */ +void Fl_Image_Surface::end_current() {platform_surface->end_current();} + +void Fl_Image_Surface::translate(int x, int y) {platform_surface->translate(x, y);} + +void Fl_Image_Surface::untranslate() {platform_surface->untranslate();} + +Fl_Offscreen Fl_Image_Surface::offscreen() {return platform_surface->offscreen;} + +int Fl_Image_Surface::printable_rect(int *w, int *h) {return platform_surface->printable_rect(w, h);} + +/** Returns an image made of all drawings sent to the Fl_Image_Surface object. + The returned object contains its own copy of the RGB data. + The caller is responsible for deleting the image. + */ +Fl_RGB_Image *Fl_Image_Surface::image() {return platform_surface->image();} + +/** Returns a possibly high resolution image made of all drawings sent to the Fl_Image_Surface object. + The Fl_Image_Surface object should have been constructed with Fl_Image_Surface(W, H, 1). + The returned image is scaled to a size of WxH drawing units and may have a pixel size twice as wide and high. + The returned object should be deallocated with Fl_Shared_Image::release() after use. + \version 1.3.4 + */ +Fl_Shared_Image* Fl_Image_Surface::highres_image() +{ + Fl_Shared_Image *s_img = Fl_Shared_Image::get(platform_surface->image()); + int width, height; + printable_rect(&width, &height); + s_img->scale(width, height); + return s_img; +} + + + +static void **offscreen_api_surface = NULL; + static int count = 0; +static int max = 0; static int current; -static int find_slot() { // return an available slot to memorize an Fl_Image_Surface object - for (int num = 0; num < count; num++) { - if (!offscreen_api_surface[num]) return num; - } - if ((unsigned)count >= sizeof(offscreen_api_surface)/sizeof(Fl_Image_Surface*)) return -1; - return count++; +int find_slot(void) { // return an available slot to memorize an Fl_Image_Surface::Helper object + for (int num = 0; num < count; num++) { + if (!offscreen_api_surface[num]) return num; + } + if (count >= max) { + max += 20; + offscreen_api_surface = (void**)realloc(offscreen_api_surface, max * sizeof(void *)); + return find_slot(); } + return count++; +} /** \addtogroup fl_drawings @{ @@ -258,17 +385,15 @@ static int find_slot() { // return an available slot to memorize an Fl_Image_Sur */ Fl_Offscreen fl_create_offscreen(int w, int h) { int rank = find_slot(); - if (rank < 0) return (Fl_Offscreen)0; - offscreen_api_surface[rank] = new Fl_Image_Surface(w, h); - return offscreen_api_surface[rank]->offscreen; + offscreen_api_surface[rank] = new Fl_Image_Surface::Helper::Helper(w, h, 0); + return ((Fl_Image_Surface::Helper**)offscreen_api_surface)[rank]->offscreen; } -#if USE_X11 +#ifdef USE_X11 Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h) { int rank = find_slot(); - if (rank < 0) return (Fl_Offscreen)0; Fl_Offscreen pixmap = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, 32); - offscreen_api_surface[rank] = new Fl_Image_Surface(pixmap, w, h); + offscreen_api_surface[rank] = new Fl_Image_Surface::Helper::Helper(pixmap, w, h); return pixmap; } #endif @@ -279,8 +404,8 @@ Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h) { void fl_delete_offscreen(Fl_Offscreen ctx) { if (!ctx) return; for (int i = 0; i < count; i++) { - if (offscreen_api_surface[i] && offscreen_api_surface[i]->offscreen == ctx) { - delete offscreen_api_surface[i]; + if (offscreen_api_surface[i] && ((Fl_Image_Surface::Helper**)offscreen_api_surface)[i]->offscreen == ctx) { + delete ((Fl_Image_Surface::Helper**)offscreen_api_surface)[i]; offscreen_api_surface[i] = NULL; } } @@ -291,8 +416,8 @@ void fl_delete_offscreen(Fl_Offscreen ctx) { */ void fl_begin_offscreen(Fl_Offscreen ctx) { for (current = 0; current < count; current++) { - if (offscreen_api_surface[current] && offscreen_api_surface[current]->offscreen == ctx) { - offscreen_api_surface[current]->set_current(); + if (offscreen_api_surface[current] && ((Fl_Image_Surface::Helper**)offscreen_api_surface)[current]->offscreen == ctx) { + ((Fl_Image_Surface::Helper**)offscreen_api_surface)[current]->set_current(); return; } } @@ -301,7 +426,7 @@ void fl_begin_offscreen(Fl_Offscreen ctx) { /** Quit sending drawing commands to the current offscreen buffer. */ void fl_end_offscreen() { - offscreen_api_surface[current]->end_current(); + ((Fl_Image_Surface::Helper**)offscreen_api_surface)[current]->end_current(); } /** @} */ |
