diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2016-02-09 18:25:02 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2016-02-09 18:25:02 +0000 |
| commit | 41e22f2f39f6b9a53d5248669e531e6c8e36a421 (patch) | |
| tree | 48dd8a971667ae53be38524e3d4d27fa92ded326 /src | |
| parent | dee0f5a82452da4334f269ceaee01f2d3df01bc0 (diff) | |
Move ifdef's in RGB_Image into driver system.
- change image caching variable types to uintptr_t
- added driver function to uncache image data
- cleaning up (Xlib and GDI will likely throw syntax errors. Trying to fix ASAP)
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11138 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | src/Fl_Bitmap.cxx | 53 | ||||
| -rw-r--r-- | src/Fl_Device.cxx | 63 | ||||
| -rw-r--r-- | src/Fl_Graphics_Device.cxx | 106 | ||||
| -rw-r--r-- | src/Fl_Graphics_Driver.cxx | 69 | ||||
| -rw-r--r-- | src/Fl_Image.cxx | 236 | ||||
| -rw-r--r-- | src/Fl_Pixmap.cxx | 152 | ||||
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver.h | 6 | ||||
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx | 188 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.h | 2 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h | 13 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx | 41 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h | 6 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx | 207 |
14 files changed, 666 insertions, 489 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ad0572e3c..6157a3a62 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ set(CPPFILES Fl_File_Chooser2.cxx Fl_File_Icon.cxx Fl_File_Input.cxx + Fl_Graphics_Driver.cxx Fl_Group.cxx Fl_Help_View.cxx Fl_Image.cxx @@ -211,6 +212,8 @@ else () endif (USE_X11) +source_group("Driver Source Files" FILES ${DRIVER_FILES}) + set(CPPFILES ${CPPFILES} ${DRIVER_FILES} @@ -238,6 +241,9 @@ set(GLCPPFILES gl_start.cxx glut_compatability.cxx glut_font.cxx +) + +set (GL_DRIVER_FILES drivers/OpenGL/Fl_OpenGL_Display_Device.cxx drivers/OpenGL/Fl_OpenGL_Graphics_Driver.cxx drivers/OpenGL/Fl_OpenGL_Graphics_Driver_arci.cxx @@ -249,6 +255,13 @@ set(GLCPPFILES drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx ) +source_group("Driver Source Files" FILES ${GL_DRIVER_FILES}) + +set(GLCPPFILES + ${GLCPPFILES} + ${GL_DRIVER_FILES} +) + set(IMGCPPFILES fl_images_core.cxx Fl_BMP_Image.cxx diff --git a/src/Fl_Bitmap.cxx b/src/Fl_Bitmap.cxx index 4d3627515..b5fa32c2c 100644 --- a/src/Fl_Bitmap.cxx +++ b/src/Fl_Bitmap.cxx @@ -23,14 +23,11 @@ The constructors create a new bitmap from the specified bitmap data.*/ #include <FL/Fl.H> -#include <FL/x.H> -#include "config_lib.h" #include <FL/fl_draw.H> #include <FL/Fl_Widget.H> #include <FL/Fl_Menu_Item.H> #include <FL/Fl_Bitmap.H> #include <FL/Fl_Printer.H> -#include "flstring.h" Fl_Bitmask fl_create_bitmask(int w, int h, const uchar *array) { return fl_graphics_driver->create_bitmask(w, h, array); @@ -117,38 +114,7 @@ void Fl_Bitmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) { fl_graphics_driver->draw(this, XP, YP, WP, HP, cx, cy); } -#if defined(WIN32) -// TODO: move this code into the GDI driver in a sensible way -// 'fl_create_bitmap()' - Create a 1-bit bitmap for drawing... -static Fl_Bitmask fl_create_bitmap(int w, int h, const uchar *data) { - // we need to pad the lines out to words & swap the bits - // in each byte. - int w1 = (w + 7) / 8; - int w2 = ((w + 15) / 16) * 2; - uchar* newarray = new uchar[w2*h]; - const uchar* src = data; - uchar* dest = newarray; - Fl_Bitmask bm; - static uchar reverse[16] = /* Bit reversal lookup table */ - { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, - 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; - - for (int y = 0; y < h; y++) { - for (int n = 0; n < w1; n++, src++) - *dest++ = (uchar)((reverse[*src & 0x0f] & 0xf0) | - (reverse[(*src >> 4) & 0x0f] & 0x0f)); - dest += w2 - w1; - } - - bm = CreateBitmap(w, h, 1, 1, newarray); - - delete[] newarray; - - return bm; -} -#endif - -int Fl_Bitmap::start(int XP, int YP, int WP, int HP, int &cx, int &cy, +int Fl_Bitmap::start(int XP, int YP, int WP, int HP, int &cx, int &cy, int &X, int &Y, int &W, int &H) { if (!array) { @@ -165,13 +131,8 @@ int Fl_Bitmap::start(int XP, int YP, int WP, int HP, int &cx, int &cy, if (cy < 0) {H += cy; Y -= cy; cy = 0;} if (cy+H > h()) H = h()-cy; if (H <= 0) return 1; -#if defined(WIN32) - if (!id_) id_ = fl_create_bitmap(w(), h(), array); -#elif defined(__APPLE__) || defined(USE_X11) - if (!id_) id_ = fl_create_bitmask(w(), h(), array); -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: call the right function to create a bitmap" -#endif + if (!id_) + id_ = fl_graphics_driver->cache(this, w(), h(), array); return 0; } @@ -186,13 +147,7 @@ Fl_Bitmap::~Fl_Bitmap() { void Fl_Bitmap::uncache() { if (id_) { -#ifdef __APPLE_QUARTZ__ - fl_delete_bitmask((Fl_Bitmask)id_); -#elif defined(WIN32) || defined(USE_X11) - fl_delete_bitmask((Fl_Offscreen)id_); -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: call the right function to create a bitmask" -#endif + fl_graphics_driver->uncache(this, id_); id_ = 0; } } diff --git a/src/Fl_Device.cxx b/src/Fl_Device.cxx index efbd0712d..bfb60d789 100644 --- a/src/Fl_Device.cxx +++ b/src/Fl_Device.cxx @@ -19,13 +19,39 @@ #include <FL/Fl.H> #include "config_lib.h" #include <FL/Fl_Device.H> -#include <FL/Fl_Image.H> -#include <FL/fl_draw.H> +#include <FL/Fl_Graphics_Driver.H> + +/* Attempt at an inheritance diagram. + + Fl_Device: base class for the core device systems + | + +- Fl_Surface_Device: any kind of surface that we can draw onto -> uses an Fl_Graphics_Driver + | + +- Fl_Display_Device: some kind of video device + +- Fl_Copy_Surface: create an image for dnd or copy/paste + +- Fl_Image_Surface: create an RGB Image + +- Fl_Paged_Device: output to a printer or similar + | + +- Fl_..._Surface_: platform specific driver + +- Fl_Printer: user can instantiate this to gain access to a printer + +- Fl_System_Printer: + +- Fl_PostScript_File_Device + | + +- Fl_PostScript_Printer + | + +- Fl_Graphics_Driver + | + +- Fl_..._Graphics_Driver: platform specific graphics driver + +TODO: + Window Device to handle creation of surfaces and manage events + System Device to handle file system acces, standard dialogs, etc. + +*/ const char *Fl_Device::class_id = "Fl_Device"; const char *Fl_Surface_Device::class_id = "Fl_Surface_Device"; const char *Fl_Display_Device::class_id = "Fl_Display_Device"; -const char *Fl_Graphics_Driver::class_id = "Fl_Graphics_Driver"; bool Fl_Display_Device::high_res_window_ = false; @@ -38,38 +64,8 @@ void Fl_Surface_Device::set_current(void) _surface = this; } -FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver; // the current target device of graphics operations Fl_Surface_Device* Fl_Surface_Device::_surface; // the current target surface of graphics operations -const Fl_Graphics_Driver::matrix Fl_Graphics_Driver::m0 = {1, 0, 0, 1, 0, 0}; - -Fl_Graphics_Driver::Fl_Graphics_Driver() { - font_ = 0; - size_ = 0; - sptr=0; rstackptr=0; - rstack[0] = NULL; - fl_clip_state_number=0; - m = m0; - fl_matrix = &m; - p = (XPOINT *)0; - font_descriptor_ = NULL; - p_size = 0; -}; - -void Fl_Graphics_Driver::text_extents(const char*t, int n, int& dx, int& dy, int& w, int& h) -{ - w = (int)width(t, n); - h = - height(); - dx = 0; - dy = descent(); -} - -void Fl_Graphics_Driver::focus_rect(int x, int y, int w, int h) -{ - line_style(FL_DOT); - rect(x, y, w, h); - line_style(FL_SOLID); -} /** A constructor that sets the graphics driver used by the display */ Fl_Display_Device::Fl_Display_Device(Fl_Graphics_Driver *graphics_driver) : Fl_Surface_Device(graphics_driver) { @@ -92,6 +88,7 @@ Fl_Surface_Device *Fl_Surface_Device::default_surface() Fl_Display_Device *Fl_Display_Device::_display = Fl_Display_Device::display_device(); + // // End of "$Id$". // diff --git a/src/Fl_Graphics_Device.cxx b/src/Fl_Graphics_Device.cxx new file mode 100644 index 000000000..22e17fa3a --- /dev/null +++ b/src/Fl_Graphics_Device.cxx @@ -0,0 +1,106 @@ +// +// "$Id$" +// +// implementation of Fl_Device class for the Fast Light Tool Kit (FLTK). +// +// Copyright 2010-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 to: +// +// http://www.fltk.org/str.php +// + +#include <FL/Fl.H> +#include "config_lib.h" +#include <FL/Fl_Device.H> +#include <FL/Fl_Image.H> +#include <FL/fl_draw.H> + +const char *Fl_Device::class_id = "Fl_Device"; +const char *Fl_Surface_Device::class_id = "Fl_Surface_Device"; +const char *Fl_Display_Device::class_id = "Fl_Display_Device"; +const char *Fl_Graphics_Driver::class_id = "Fl_Graphics_Driver"; + +bool Fl_Display_Device::high_res_window_ = false; + + +/** \brief Make this surface the current drawing surface. + This surface will receive all future graphics requests. */ +void Fl_Surface_Device::set_current(void) +{ + fl_graphics_driver = _driver; + _surface = this; +} + +FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver; // the current target device of graphics operations +Fl_Surface_Device* Fl_Surface_Device::_surface; // the current target surface of graphics operations + +const Fl_Graphics_Driver::matrix Fl_Graphics_Driver::m0 = {1, 0, 0, 1, 0, 0}; + +Fl_Graphics_Driver::Fl_Graphics_Driver() { + font_ = 0; + size_ = 0; + sptr=0; rstackptr=0; + rstack[0] = NULL; + fl_clip_state_number=0; + m = m0; + fl_matrix = &m; + p = (XPOINT *)0; + font_descriptor_ = NULL; + p_size = 0; +}; + +void Fl_Graphics_Driver::text_extents(const char*t, int n, int& dx, int& dy, int& w, int& h) +{ + w = (int)width(t, n); + h = - height(); + dx = 0; + dy = descent(); +} + +void Fl_Graphics_Driver::focus_rect(int x, int y, int w, int h) +{ + line_style(FL_DOT); + rect(x, y, w, h); + line_style(FL_SOLID); +} + +/** A constructor that sets the graphics driver used by the display */ +Fl_Display_Device::Fl_Display_Device(Fl_Graphics_Driver *graphics_driver) : Fl_Surface_Device(graphics_driver) { + this->set_current(); +}; + + +/** Returns the platform display device. */ +Fl_Display_Device *Fl_Display_Device::display_device() { + static Fl_Display_Device *display = new Fl_Display_Device(Fl_Graphics_Driver::newMainGraphicsDriver()); + return display; +}; + + +Fl_Surface_Device *Fl_Surface_Device::default_surface() +{ + return Fl_Display_Device::display_device(); +} + + +Fl_Display_Device *Fl_Display_Device::_display = Fl_Display_Device::display_device(); + + +/** Draws an Fl_Image scaled to width \p W & height \p H with top-left corner at \em X,Y + \return zero when the graphics driver doesn't implement scaled drawing, non-zero if it does implement it. + */ +int Fl_Graphics_Driver::draw_scaled(Fl_Image *img, int X, int Y, int W, int H) { + return 0; +} + + +// +// End of "$Id$". +// diff --git a/src/Fl_Graphics_Driver.cxx b/src/Fl_Graphics_Driver.cxx new file mode 100644 index 000000000..365f1df5e --- /dev/null +++ b/src/Fl_Graphics_Driver.cxx @@ -0,0 +1,69 @@ +// +// "$Id$" +// +// implementation of Fl_Device class for the Fast Light Tool Kit (FLTK). +// +// Copyright 2010-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 to: +// +// http://www.fltk.org/str.php +// + +#include <FL/Fl.H> +#include "config_lib.h" +#include <FL/Fl_Graphics_Driver.H> +#include <FL/Fl_Image.H> +#include <FL/fl_draw.H> + +const char *Fl_Graphics_Driver::class_id = "Fl_Graphics_Driver"; + +FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver; // the current target device of graphics operations + +const Fl_Graphics_Driver::matrix Fl_Graphics_Driver::m0 = {1, 0, 0, 1, 0, 0}; + +Fl_Graphics_Driver::Fl_Graphics_Driver() { + font_ = 0; + size_ = 0; + sptr=0; rstackptr=0; + rstack[0] = NULL; + fl_clip_state_number=0; + m = m0; + fl_matrix = &m; + p = (XPOINT *)0; + font_descriptor_ = NULL; + p_size = 0; +}; + +void Fl_Graphics_Driver::text_extents(const char*t, int n, int& dx, int& dy, int& w, int& h) +{ + w = (int)width(t, n); + h = - height(); + dx = 0; + dy = descent(); +} + +void Fl_Graphics_Driver::focus_rect(int x, int y, int w, int h) +{ + line_style(FL_DOT); + rect(x, y, w, h); + line_style(FL_SOLID); +} + +/** Draws an Fl_Image scaled to width \p W & height \p H with top-left corner at \em X,Y + \return zero when the graphics driver doesn't implement scaled drawing, non-zero if it does implement it. + */ +int Fl_Graphics_Driver::draw_scaled(Fl_Image *img, int X, int Y, int W, int H) { + return 0; +} + + +// +// End of "$Id$". +// diff --git a/src/Fl_Image.cxx b/src/Fl_Image.cxx index 907035893..35871765c 100644 --- a/src/Fl_Image.cxx +++ b/src/Fl_Image.cxx @@ -32,10 +32,6 @@ #else #endif -#ifdef WIN32 -void fl_release_dc(HWND, HDC); // from Fl_win32.cxx -#endif - void fl_restore_clip(); // from fl_rect.cxx // @@ -75,25 +71,6 @@ void Fl_Image::draw(int XP, int YP, int, int, int, int) { } -#if defined(WIN32) || defined (USE_X11) -static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, - int &X, int &Y, int &W, int &H) -{ - // account for current clip region (faster on Irix): - fl_clip_box(XP,YP,WP,HP,X,Y,W,H); - cx += X-XP; cy += Y-YP; - // clip the box down to the size of image, quit if empty: - if (cx < 0) {W += cx; X -= cx; cx = 0;} - if (cx+W > w) W = w-cx; - if (W <= 0) return 1; - if (cy < 0) {H += cy; Y -= cy; cy = 0;} - if (cy+H > h) H = h-cy; - if (H <= 0) return 1; - return 0; -} -#endif // defined(WIN32) || defined (USE_X11) - - /** The protected method draw_empty() draws a box with an X in it. It can be used to draw any image that lacks image @@ -313,34 +290,12 @@ Fl_RGB_Image::Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg): the image. */ Fl_RGB_Image::~Fl_RGB_Image() { -#ifdef __APPLE__ - if (id_) CGImageRelease((CGImageRef)id_); - else if (alloc_array) delete[] (uchar *)array; -#else uncache(); if (alloc_array) delete[] (uchar *)array; -#endif } void Fl_RGB_Image::uncache() { -#ifdef __APPLE__ - if (id_) { - if (mask_) *(bool*)mask_ = false; - CGImageRelease((CGImageRef)id_); - id_ = 0; - mask_ = NULL; - } -#else - if (id_) { - fl_delete_offscreen((Fl_Offscreen)id_); - id_ = 0; - } - - if (mask_) { - fl_delete_bitmask((Fl_Bitmask)mask_); - mask_ = 0; - } -#endif + fl_graphics_driver->uncache(this, id_, mask_); } Fl_Image *Fl_RGB_Image::copy(int W, int H) { @@ -587,199 +542,10 @@ void Fl_RGB_Image::desaturate() { d(new_d); } -#if !defined(WIN32) && !defined(__APPLE__) -// Composite an image with alpha on systems that don't have accelerated -// alpha compositing... -static void alpha_blend(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { - int ld = img->ld(); - if (ld == 0) ld = img->w() * img->d(); - uchar *srcptr = (uchar*)img->array + cy * ld + cx * img->d(); - int srcskip = ld - img->d() * W; - - uchar *dst = new uchar[W * H * 3]; - uchar *dstptr = dst; - - fl_read_image(dst, X, Y, W, H, 0); - - uchar srcr, srcg, srcb, srca; - uchar dstr, dstg, dstb, dsta; - - if (img->d() == 2) { - // Composite grayscale + alpha over RGB... - for (int y = H; y > 0; y--, srcptr+=srcskip) - for (int x = W; x > 0; x--) { - srcg = *srcptr++; - srca = *srcptr++; - - dstr = dstptr[0]; - dstg = dstptr[1]; - dstb = dstptr[2]; - dsta = 255 - srca; - - *dstptr++ = (srcg * srca + dstr * dsta) >> 8; - *dstptr++ = (srcg * srca + dstg * dsta) >> 8; - *dstptr++ = (srcg * srca + dstb * dsta) >> 8; - } - } else { - // Composite RGBA over RGB... - for (int y = H; y > 0; y--, srcptr+=srcskip) - for (int x = W; x > 0; x--) { - srcr = *srcptr++; - srcg = *srcptr++; - srcb = *srcptr++; - srca = *srcptr++; - - dstr = dstptr[0]; - dstg = dstptr[1]; - dstb = dstptr[2]; - dsta = 255 - srca; - - *dstptr++ = (srcr * srca + dstr * dsta) >> 8; - *dstptr++ = (srcg * srca + dstg * dsta) >> 8; - *dstptr++ = (srcb * srca + dstb * dsta) >> 8; - } - } - - fl_draw_image(dst, X, Y, W, H, 3, 0); - - delete[] dst; -} -#endif // !WIN32 && !__APPLE__ - void Fl_RGB_Image::draw(int XP, int YP, int WP, int HP, int cx, int cy) { fl_graphics_driver->draw(this, XP, YP, WP, HP, cx, cy); } -/** Draws an Fl_Image scaled to width \p W & height \p H with top-left corner at \em X,Y - \return zero when the graphics driver doesn't implement scaled drawing, non-zero if it does implement it. - */ -int Fl_Graphics_Driver::draw_scaled(Fl_Image *img, int X, int Y, int W, int H) { - return 0; -} - -#ifdef __APPLE__ - -#elif defined(WIN32) -static Fl_Offscreen build_id(Fl_RGB_Image *img, void **pmask) -{ - Fl_Offscreen offs = fl_create_offscreen(img->w(), img->h()); - if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) { - fl_begin_offscreen(offs); - fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); - fl_end_offscreen(); - } else { - fl_begin_offscreen(offs); - fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); - fl_end_offscreen(); - if (img->d() == 2 || img->d() == 4) { - *pmask = fl_create_alphamask(img->w(), img->h(), img->d(), img->ld(), img->array); - } - } - return offs; -} - -void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - // Don't draw an empty image... - if (!img->d() || !img->array) { - img->draw_empty(XP, YP); - return; - } - if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { - return; - } - if (!img->id_) img->id_ = build_id(img, &(img->mask_)); - if (img->mask_) { - HDC new_gc = CreateCompatibleDC(fl_gc); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)img->mask_); - BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); - SelectObject(new_gc, (void*)img->id_); - BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - } else if (img->d()==2 || img->d()==4) { - copy_offscreen_with_alpha(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); - } else { - copy_offscreen(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); - } -} - -int Fl_GDI_Printer_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) { - XFORM old_tr, tr; - GetWorldTransform(fl_gc, &old_tr); // storing old transform - tr.eM11 = float(WP)/float(img->w()); - tr.eM22 = float(HP)/float(img->h()); - tr.eM12 = tr.eM21 = 0; - tr.eDx = XP; - tr.eDy = YP; - ModifyWorldTransform(fl_gc, &tr, MWT_LEFTMULTIPLY); - img->draw(0, 0, img->w(), img->h(), 0, 0); - SetWorldTransform(fl_gc, &old_tr); - return 1; -} - -#elif defined(FL_PORTING) - -# pragma message "FL_PORTING: implement RGB image handling here" - -#else -void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - // Don't draw an empty image... - if (!img->d() || !img->array) { - img->draw_empty(XP, YP); - return; - } - if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { - return; - } - if (!img->id_) { - if (img->d() == 1 || img->d() == 3) { - img->id_ = fl_create_offscreen(img->w(), img->h()); - fl_begin_offscreen((Fl_Offscreen)img->id_); - fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); - fl_end_offscreen(); - } else if (img->d() == 4 && fl_can_do_alpha_blending()) { - img->id_ = fl_create_offscreen_with_alpha(img->w(), img->h()); - fl_begin_offscreen((Fl_Offscreen)img->id_); - fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d() | FL_IMAGE_WITH_ALPHA, - img->ld()); - fl_end_offscreen(); - } - } - if (img->id_) { - if (img->mask_) { - // I can't figure out how to combine a mask with existing region, - // so cut the image down to a clipped rectangle: - int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H); - cx += nx-X; X = nx; - cy += ny-Y; Y = ny; - // make X use the bitmap as a mask: - XSetClipMask(fl_display, fl_gc, img->mask_); - int ox = X-cx; if (ox < 0) ox += img->w(); - int oy = Y-cy; if (oy < 0) oy += img->h(); - XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); - } - - if (img->d() == 4 && fl_can_do_alpha_blending()) - copy_offscreen_with_alpha(X, Y, W, H, img->id_, cx, cy); - else - copy_offscreen(X, Y, W, H, img->id_, cx, cy); - - if (img->mask_) { - // put the old clip region back - XSetClipOrigin(fl_display, fl_gc, 0, 0); - fl_restore_clip(); - } - } else { - // Composite image with alpha manually each time... - alpha_blend(img, X, Y, W, H, cx, cy); - } -} - -#endif - void Fl_RGB_Image::label(Fl_Widget* widget) { widget->image(this); } diff --git a/src/Fl_Pixmap.cxx b/src/Fl_Pixmap.cxx index 01a3afa6e..56512994e 100644 --- a/src/Fl_Pixmap.cxx +++ b/src/Fl_Pixmap.cxx @@ -23,7 +23,6 @@ // Implemented without using the xpm library (which I can't use because // it interferes with the color cube used by fl_draw_image). -#include "config_lib.h" #include <FL/Fl.H> #include <FL/fl_draw.H> #include <FL/x.H> @@ -32,38 +31,10 @@ #include <FL/Fl_Pixmap.H> #include <FL/Fl_Printer.H> -#if defined(WIN32) -#elif defined(__APPLE__) -#include "src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h" -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: this file needs a lot of custom code to draw Pixmaps correctly" -#else -#endif - -#if defined(USE_X11) -# if HAVE_X11_XREGION_H -# include <X11/Xregion.h> -# else // if the X11/Xregion.h header is not available, we assume this is the layout of an X11 Region: -typedef struct { - short x1, x2, y1, y2; -} BOX; -struct _XRegion { - long size; - long numRects; - BOX *rects; - BOX extents; -}; -# endif // HAVE_X11_XREGION_H -#endif // USE_X11 - #include <stdio.h> #include "flstring.h" #include <ctype.h> -#ifdef WIN32 -extern void fl_release_dc(HWND, HDC); // located in Fl_win32.cxx -#endif - extern uchar **fl_mask_bitmap; // used by fl_draw_pixmap.cxx to store mask void fl_restore_clip(); // in fl_rect.cxx @@ -117,132 +88,11 @@ int Fl_Pixmap::prepare(int XP, int YP, int WP, int HP, int &cx, int &cy, return 1; } if (!id_) { -#ifdef __APPLE__ - id_ = Fl_Quartz_Graphics_Driver::create_offscreen_with_alpha(w(), h()); -#else - id_ = fl_create_offscreen(w(), h()); -#endif - fl_begin_offscreen((Fl_Offscreen)id_); -#ifndef __APPLE__ - uchar *bitmap = 0; - fl_mask_bitmap = &bitmap; -#endif - fl_draw_pixmap(data(), 0, 0, FL_BLACK); -#ifndef __APPLE__ -#if defined(WIN32) - extern UINT win_pixmap_bg_color; // computed by fl_draw_pixmap() - this->pixmap_bg_color = win_pixmap_bg_color; -#endif - fl_mask_bitmap = 0; - if (bitmap) { - mask_ = fl_create_bitmask(w(), h(), bitmap); - delete[] bitmap; - } -#endif - fl_end_offscreen(); + id_ = fl_graphics_driver->cache(this, w(), h(), data()); } return 0; } -//------------------------------------------------------------------------------ -#ifdef __APPLE__ // Apple, Mac OS X -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -#elif defined(WIN32) // Windows GDI -//------------------------------------------------------------------------------ - -void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (pxm->prepare(XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; - if (pxm->mask_) { - HDC new_gc = CreateCompatibleDC(fl_gc); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)pxm->mask_); - BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); - SelectObject(new_gc, (void*)pxm->id_); - BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - } else { - copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy); - } -} - - -void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (pxm->prepare(XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; - typedef BOOL (WINAPI* fl_transp_func) (HDC,int,int,int,int,HDC,int,int,int,int,UINT); - static HMODULE hMod = NULL; - static fl_transp_func fl_TransparentBlt = NULL; - if (!hMod) { - hMod = LoadLibrary("MSIMG32.DLL"); - if(hMod) fl_TransparentBlt = (fl_transp_func)GetProcAddress(hMod, "TransparentBlt"); - } - if (fl_TransparentBlt) { - HDC new_gc = CreateCompatibleDC(fl_gc); - int save = SaveDC(new_gc); - SelectObject(new_gc, (void*)pxm->id_); - // print all of offscreen but its parts in background color - fl_TransparentBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, W, H, pxm->pixmap_bg_color ); - RestoreDC(new_gc,save); - DeleteDC(new_gc); - } - else { - copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy); - } -} - -//------------------------------------------------------------------------------ -#elif defined(FL_PORTING) -#pragma message "Implement Fl_XXX_Graphics_Driver methods here" -//------------------------------------------------------------------------------ -#else // X11, Xlib -//------------------------------------------------------------------------------ - -void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (pxm->prepare(XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; - if (pxm->mask_) { - // make X use the bitmap as a mask: - XSetClipMask(fl_display, fl_gc, pxm->mask_); - XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); - if (clip_region()) { - // At this point, XYWH is the bounding box of the intersection between - // the current clip region and the (portion of the) pixmap we have to draw. - // The current clip region is often a rectangle. But, when a window with rounded - // corners is moved above another window, expose events may create a complex clip - // region made of several (e.g., 10) rectangles. We have to draw only in the clip - // region, and also to mask out the transparent pixels of the image. This can't - // be done in a single Xlib call for a multi-rectangle clip region. Thus, we - // process each rectangle of the intersection between the clip region and XYWH. - // See also STR #3206. - Region r = XRectangleRegion(X,Y,W,H); - XIntersectRegion(r, clip_region(), r); - int X1, Y1, W1, H1; - for (int i = 0; i < r->numRects; i++) { - X1 = r->rects[i].x1; - Y1 = r->rects[i].y1; - W1 = r->rects[i].x2 - r->rects[i].x1; - H1 = r->rects[i].y2 - r->rects[i].y1; - copy_offscreen(X1, Y1, W1, H1, pxm->id_, cx + (X1 - X), cy + (Y1 - Y)); - } - XDestroyRegion(r); - } else { - copy_offscreen(X, Y, W, H, pxm->id_, cx, cy); - } - // put the old clip region back - XSetClipOrigin(fl_display, fl_gc, 0, 0); - restore_clip(); - } - else copy_offscreen(X, Y, W, H, pxm->id_, cx, cy); -} - -//------------------------------------------------------------------------------ -#endif // (platform-specific) -//------------------------------------------------------------------------------ - /** The destructor frees all memory and server resources that are used by the pixmap. diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.h b/src/drivers/GDI/Fl_GDI_Graphics_Driver.h index 06e040f1a..1dd62a4e6 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.h +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver.h @@ -25,7 +25,7 @@ #ifndef FL_GDI_GRAPHICS_DRIVER_H #define FL_GDI_GRAPHICS_DRIVER_H -#include <FL/Fl_Device.H> +#include <FL/Fl_Graphics_Driver.H> /** @@ -56,6 +56,10 @@ public: 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); + fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array); + fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array); + void uncache(Fl_Bitmap *img, fl_uintptr_t &id_); + void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_); 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); diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx index a6d32d6e4..f12de853b 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx @@ -43,6 +43,8 @@ #define MAXBUFFER 0x40000 // 256k +void fl_release_dc(HWND, HDC); // from Fl_win32.cxx + #if USE_COLORMAP // error-diffusion dither into the FLTK colormap @@ -459,6 +461,192 @@ void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, } +static Fl_Offscreen build_id(Fl_RGB_Image *img, void **pmask) +{ + Fl_Offscreen offs = fl_create_offscreen(img->w(), img->h()); + if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) { + fl_begin_offscreen(offs); + fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld()); + fl_end_offscreen(); + } else { + fl_begin_offscreen(offs); + fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); + fl_end_offscreen(); + if (img->d() == 2 || img->d() == 4) { + *pmask = fl_create_alphamask(img->w(), img->h(), img->d(), img->ld(), img->array); + } + } + return offs; +} + + +static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, + int &X, int &Y, int &W, int &H) +{ + // account for current clip region (faster on Irix): + fl_clip_box(XP,YP,WP,HP,X,Y,W,H); + cx += X-XP; cy += Y-YP; + // clip the box down to the size of image, quit if empty: + if (cx < 0) {W += cx; X -= cx; cx = 0;} + if (cx+W > w) W = w-cx; + if (W <= 0) return 1; + if (cy < 0) {H += cy; Y -= cy; cy = 0;} + if (cy+H > h) H = h-cy; + if (H <= 0) return 1; + return 0; +} + + +void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + // Don't draw an empty image... + if (!img->d() || !img->array) { + img->draw_empty(XP, YP); + return; + } + if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { + return; + } + if (!img->id_) img->id_ = build_id(img, &(img->mask_)); + if (img->mask_) { + HDC new_gc = CreateCompatibleDC(fl_gc); + int save = SaveDC(new_gc); + SelectObject(new_gc, (void*)img->mask_); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); + SelectObject(new_gc, (void*)img->id_); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); + RestoreDC(new_gc,save); + DeleteDC(new_gc); + } else if (img->d()==2 || img->d()==4) { + copy_offscreen_with_alpha(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); + } else { + copy_offscreen(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy); + } +} + +int Fl_GDI_Printer_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) { + XFORM old_tr, tr; + GetWorldTransform(fl_gc, &old_tr); // storing old transform + tr.eM11 = float(WP)/float(img->w()); + tr.eM22 = float(HP)/float(img->h()); + tr.eM12 = tr.eM21 = 0; + tr.eDx = XP; + tr.eDy = YP; + ModifyWorldTransform(fl_gc, &tr, MWT_LEFTMULTIPLY); + img->draw(0, 0, img->w(), img->h(), 0, 0); + SetWorldTransform(fl_gc, &old_tr); + return 1; +} + +void Fl_GDI_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) +{ + if (id_) { + fl_delete_offscreen((Fl_Offscreen)id_); + id_ = 0; + } + + if (mask_) { + fl_delete_bitmask((Fl_Bitmask)mask_); + mask_ = 0; + } +} + +// 'fl_create_bitmap()' - Create a 1-bit bitmap for drawing... +static Fl_Bitmask fl_create_bitmap(int w, int h, const uchar *data) { + // we need to pad the lines out to words & swap the bits + // in each byte. + int w1 = (w + 7) / 8; + int w2 = ((w + 15) / 16) * 2; + uchar* newarray = new uchar[w2*h]; + const uchar* src = data; + uchar* dest = newarray; + Fl_Bitmask bm; + static uchar reverse[16] = /* Bit reversal lookup table */ + { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, + 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; + + for (int y = 0; y < h; y++) { + for (int n = 0; n < w1; n++, src++) + *dest++ = (uchar)((reverse[*src & 0x0f] & 0xf0) | + (reverse[(*src >> 4) & 0x0f] & 0x0f)); + dest += w2 - w1; + } + + bm = CreateBitmap(w, h, 1, 1, newarray); + + delete[] newarray; + + return bm; +} + +fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) { + return (fl_uintptr_t)create_bitmap(w, h, array); +} + +void Fl_GDI_Graphics_Driver::uncache(Fl_Bitmap *img, fl_uintptr_t &id_) { + delete_bitmask((Fl_Offscreen)id_); +} + +void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + if (pxm->prepare(XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; + if (pxm->mask_) { + HDC new_gc = CreateCompatibleDC(fl_gc); + int save = SaveDC(new_gc); + SelectObject(new_gc, (void*)pxm->mask_); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); + SelectObject(new_gc, (void*)pxm->id_); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); + RestoreDC(new_gc,save); + DeleteDC(new_gc); + } else { + copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy); + } +} + + +void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + if (pxm->prepare(XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; + typedef BOOL (WINAPI* fl_transp_func) (HDC,int,int,int,int,HDC,int,int,int,int,UINT); + static HMODULE hMod = NULL; + static fl_transp_func fl_TransparentBlt = NULL; + if (!hMod) { + hMod = LoadLibrary("MSIMG32.DLL"); + if(hMod) fl_TransparentBlt = (fl_transp_func)GetProcAddress(hMod, "TransparentBlt"); + } + if (fl_TransparentBlt) { + HDC new_gc = CreateCompatibleDC(fl_gc); + int save = SaveDC(new_gc); + SelectObject(new_gc, (void*)pxm->id_); + // print all of offscreen but its parts in background color + fl_TransparentBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, W, H, pxm->pixmap_bg_color ); + RestoreDC(new_gc,save); + DeleteDC(new_gc); + } + else { + copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy); + } +} + +fl_uintptr_t Fl_GDI_Printer_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const char *const*data) { + Fl_Offscreen id; + id = fl_create_offscreen(w(), h()); + fl_begin_offscreen(id); + uchar *bitmap = 0; + fl_mask_bitmap = &bitmap; + fl_draw_pixmap(data, 0, 0, FL_BLACK); + extern UINT win_pixmap_bg_color; // computed by fl_draw_pixmap() + this->pixmap_bg_color = win_pixmap_bg_color; + fl_mask_bitmap = 0; + if (bitmap) { + img->mask_ = (fl_uintptr_t)fl_create_bitmask(w(), h(), bitmap); + delete[] bitmap; + } + fl_end_offscreen(); + return (fl_uintptr_t)id; +} + // // End of "$Id$". // diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.h b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.h index 206b90029..d4e7074fe 100644 --- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.h +++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver.h @@ -25,7 +25,7 @@ #ifndef FL_CFG_GFX_OPENGL_H #define FL_CFG_GFX_OPENGL_H -#include <FL/Fl_Device.H> +#include <FL/Fl_Graphics_Driver.H> /** diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h index f72e8be8d..04d214504 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.h @@ -22,14 +22,10 @@ \brief Definition of Apple Quartz graphics driver. */ -#include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ - #ifndef FL_QUARTZ_GRAPHICS_DRIVER_H #define FL_QUARTZ_GRAPHICS_DRIVER_H -#include <FL/Fl_Device.H> - +#include <FL/Fl_Graphics_Driver.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 @@ -59,6 +55,10 @@ public: 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); + fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array); + fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array); + void uncache(Fl_Bitmap *img, fl_uintptr_t &id_); + void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_); #if ! defined(FL_DOXYGEN) static Fl_Offscreen create_offscreen_with_alpha(int w, int h); #endif @@ -122,11 +122,8 @@ protected: int descent(); }; - #endif // FL_QUARTZ_GRAPHICS_DRIVER_H -#endif // FL_CFG_GFX_QUARTZ - // // End of "$Id: quartz.H 11017 2016-01-20 21:40:12Z matt $". // diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx index 442b8b29a..9a2180910 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx @@ -17,7 +17,6 @@ // #include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ #include "Fl_Quartz_Graphics_Driver.h" @@ -221,12 +220,12 @@ void Fl_Quartz_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, // If the CGImage is printed, it is not deallocated until after the end of the page, // therefore, with img->alloc_array != 0, the RGB image can be safely deleted any time after return from this function. // The previously unused mask_ member allows to make sure the RGB image data is not deleted by Fl_RGB_Image::uncache(). - if (img->alloc_array) img->mask_ = new bool(true); - CGDataProviderRef src = CGDataProviderCreateWithData(img->mask_, img->array, ld * img->h(), + if (img->alloc_array) img->mask_ = (fl_uintptr_t)new bool(true); + CGDataProviderRef src = CGDataProviderCreateWithData((void*)img->mask_, img->array, ld * img->h(), img->alloc_array?imgProviderReleaseData:NULL); - img->id_ = CGImageCreate(img->w(), img->h(), 8, img->d()*8, ld, - lut, (img->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, - src, 0L, false, kCGRenderingIntentDefault); + img->id_ = (fl_uintptr_t)CGImageCreate(img->w(), img->h(), 8, img->d()*8, ld, + lut, (img->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, + src, 0L, false, kCGRenderingIntentDefault); CGColorSpaceRelease(lut); CGDataProviderRelease(src); } @@ -244,9 +243,9 @@ void Fl_Quartz_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, img->uncache(); CGColorSpaceRef lut = img->d()<=2 ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); CGDataProviderRef src = CGDataProviderCreateWithData( NULL, img_bytes, ld * img->h(), imgProviderReleaseData); - img->id_ = CGImageCreate(img->w(), img->h(), 8, img->d()*8, ld, - lut, (img->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, - src, 0L, true, kCGRenderingIntentDefault); + img->id_ = (fl_uintptr_t)CGImageCreate(img->w(), img->h(), 8, img->d()*8, ld, + lut, (img->d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, + src, 0L, true, kCGRenderingIntentDefault); CGColorSpaceRelease(lut); CGDataProviderRelease(src); } @@ -298,9 +297,31 @@ void Fl_Quartz_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) { if (bm) CGImageRelease((CGImageRef)bm); } +void Fl_Quartz_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) { + if (id_) { + if (mask_) *(bool*)mask_ = false; + CGImageRelease((CGImageRef)id_); + id_ = 0; + mask_ = NULL; + } +} + +fl_uintptr_t Fl_Quartz_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) { + return (fl_uintptr_t)create_bitmask(w, h, array); +} +void Fl_Quartz_Graphics_Driver::uncache(Fl_Bitmap*, fl_uintptr_t &id_) { + delete_bitmask((Fl_Bitmask)id_); +} -#endif // FL_CFG_GFX_QUARTZ +fl_uintptr_t Fl_Quartz_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const char *const*data) { + Fl_Offscreen id; + id = create_offscreen_with_alpha(w, h); + fl_begin_offscreen(id); + fl_draw_pixmap(data, 0, 0, FL_BLACK); + fl_end_offscreen(); + return (fl_uintptr_t)id; +} // // End of "$Id$". diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h index bb55c1f53..577f5f573 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h @@ -25,7 +25,7 @@ #ifndef FL_CFG_GFX_XLIB_H #define FL_CFG_GFX_XLIB_H -#include <FL/Fl_Device.H> +#include <FL/Fl_Graphics_Driver.H> /** \brief The Xlib-specific graphics class. @@ -52,6 +52,10 @@ public: 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); + fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array); + fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array); + void uncache(Fl_Bitmap *img, fl_uintptr_t &id_); + void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_); 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); diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx index cf91cb3a7..479696b77 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx @@ -624,6 +624,213 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP XSetFillStyle(fl_display, fl_gc, FillSolid); } + +static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, + int &X, int &Y, int &W, int &H) +{ + // account for current clip region (faster on Irix): + fl_clip_box(XP,YP,WP,HP,X,Y,W,H); + cx += X-XP; cy += Y-YP; + // clip the box down to the size of image, quit if empty: + if (cx < 0) {W += cx; X -= cx; cx = 0;} + if (cx+W > w) W = w-cx; + if (W <= 0) return 1; + if (cy < 0) {H += cy; Y -= cy; cy = 0;} + if (cy+H > h) H = h-cy; + if (H <= 0) return 1; + return 0; +} + + +// Composite an image with alpha on systems that don't have accelerated +// alpha compositing... +static void alpha_blend(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { + int ld = img->ld(); + if (ld == 0) ld = img->w() * img->d(); + uchar *srcptr = (uchar*)img->array + cy * ld + cx * img->d(); + int srcskip = ld - img->d() * W; + + uchar *dst = new uchar[W * H * 3]; + uchar *dstptr = dst; + + fl_read_image(dst, X, Y, W, H, 0); + + uchar srcr, srcg, srcb, srca; + uchar dstr, dstg, dstb, dsta; + + if (img->d() == 2) { + // Composite grayscale + alpha over RGB... + for (int y = H; y > 0; y--, srcptr+=srcskip) + for (int x = W; x > 0; x--) { + srcg = *srcptr++; + srca = *srcptr++; + + dstr = dstptr[0]; + dstg = dstptr[1]; + dstb = dstptr[2]; + dsta = 255 - srca; + + *dstptr++ = (srcg * srca + dstr * dsta) >> 8; + *dstptr++ = (srcg * srca + dstg * dsta) >> 8; + *dstptr++ = (srcg * srca + dstb * dsta) >> 8; + } + } else { + // Composite RGBA over RGB... + for (int y = H; y > 0; y--, srcptr+=srcskip) + for (int x = W; x > 0; x--) { + srcr = *srcptr++; + srcg = *srcptr++; + srcb = *srcptr++; + srca = *srcptr++; + + dstr = dstptr[0]; + dstg = dstptr[1]; + dstb = dstptr[2]; + dsta = 255 - srca; + + *dstptr++ = (srcr * srca + dstr * dsta) >> 8; + *dstptr++ = (srcg * srca + dstg * dsta) >> 8; + *dstptr++ = (srcb * srca + dstb * dsta) >> 8; + } + } + + fl_draw_image(dst, X, Y, W, H, 3, 0); + + delete[] dst; +} + + +void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + // Don't draw an empty image... + if (!img->d() || !img->array) { + img->draw_empty(XP, YP); + return; + } + if (start(img, XP, YP, WP, HP, img->w(), img->h(), cx, cy, X, Y, W, H)) { + return; + } + if (!img->id_) { + if (img->d() == 1 || img->d() == 3) { + img->id_ = fl_create_offscreen(img->w(), img->h()); + fl_begin_offscreen((Fl_Offscreen)img->id_); + fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld()); + fl_end_offscreen(); + } else if (img->d() == 4 && fl_can_do_alpha_blending()) { + img->id_ = (fl_uintptr_t)fl_create_offscreen_with_alpha(img->w(), img->h()); + fl_begin_offscreen((Fl_Offscreen)img->id_); + fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d() | FL_IMAGE_WITH_ALPHA, + img->ld()); + fl_end_offscreen(); + } + } + if (img->id_) { + if (img->mask_) { + // I can't figure out how to combine a mask with existing region, + // so cut the image down to a clipped rectangle: + int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H); + cx += nx-X; X = nx; + cy += ny-Y; Y = ny; + // make X use the bitmap as a mask: + XSetClipMask(fl_display, fl_gc, img->mask_); + int ox = X-cx; if (ox < 0) ox += img->w(); + int oy = Y-cy; if (oy < 0) oy += img->h(); + XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); + } + + if (img->d() == 4 && fl_can_do_alpha_blending()) + copy_offscreen_with_alpha(X, Y, W, H, img->id_, cx, cy); + else + copy_offscreen(X, Y, W, H, img->id_, cx, cy); + + if (img->mask_) { + // put the old clip region back + XSetClipOrigin(fl_display, fl_gc, 0, 0); + fl_restore_clip(); + } + } else { + // Composite image with alpha manually each time... + alpha_blend(img, X, Y, W, H, cx, cy); + } +} + +void Fl_Xlib_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) +{ + if (id_) { + fl_delete_offscreen((Fl_Offscreen)id_); + id_ = 0; + } + + if (mask_) { + fl_delete_bitmask((Fl_Bitmask)mask_); + mask_ = 0; + } +} + +fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) { + return (fl_uintptr_t)create_bitmask(w, h, array); +} + +void Fl_Xlib_Graphics_Driver::uncache(Fl_Bitmap*, fl_uintptr_t &id_) { + delete_bitmask((Fl_Offscreen)id_); +} + + +void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + if (pxm->prepare(XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; + if (pxm->mask_) { + // make X use the bitmap as a mask: + XSetClipMask(fl_display, fl_gc, pxm->mask_); + XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); + if (clip_region()) { + // At this point, XYWH is the bounding box of the intersection between + // the current clip region and the (portion of the) pixmap we have to draw. + // The current clip region is often a rectangle. But, when a window with rounded + // corners is moved above another window, expose events may create a complex clip + // region made of several (e.g., 10) rectangles. We have to draw only in the clip + // region, and also to mask out the transparent pixels of the image. This can't + // be done in a single Xlib call for a multi-rectangle clip region. Thus, we + // process each rectangle of the intersection between the clip region and XYWH. + // See also STR #3206. + Region r = XRectangleRegion(X,Y,W,H); + XIntersectRegion(r, clip_region(), r); + int X1, Y1, W1, H1; + for (int i = 0; i < r->numRects; i++) { + X1 = r->rects[i].x1; + Y1 = r->rects[i].y1; + W1 = r->rects[i].x2 - r->rects[i].x1; + H1 = r->rects[i].y2 - r->rects[i].y1; + copy_offscreen(X1, Y1, W1, H1, pxm->id_, cx + (X1 - X), cy + (Y1 - Y)); + } + XDestroyRegion(r); + } else { + copy_offscreen(X, Y, W, H, pxm->id_, cx, cy); + } + // put the old clip region back + XSetClipOrigin(fl_display, fl_gc, 0, 0); + restore_clip(); + } + else copy_offscreen(X, Y, W, H, pxm->id_, cx, cy); +} + +fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const char *const*data) { + Fl_Offscreen id; + id = fl_create_offscreen(w(), h()); + fl_begin_offscreen(id); + uchar *bitmap = 0; + fl_mask_bitmap = &bitmap; + fl_draw_pixmap(data(), 0, 0, FL_BLACK); + fl_mask_bitmap = 0; + if (bitmap) { + img->mask_ = (fl_uintptr_t)fl_create_bitmask(w(), h(), bitmap); + delete[] bitmap; + } + fl_end_offscreen(); + return (fl_uintptr_t)id; +} + + // // End of "$Id$". // |
