diff options
| author | Manolo Gouy <Manolo> | 2018-02-09 13:48:22 +0000 |
|---|---|---|
| committer | Manolo Gouy <Manolo> | 2018-02-09 13:48:22 +0000 |
| commit | c472d5d8b76e17e4dd537ca20c9bfb144b06189c (patch) | |
| tree | fbe64110002b5d36127631c37cc5d1bb44f86318 | |
| parent | b78b2f7f5f24b98640d31bb8ee7b573703e8cc19 (diff) | |
Fix fl_read_image() under MacOS platform when GUI is rescaled.
This commit also simplifies the platform-dependent support of fl_read_image():
only Fl_XXX_Screen_Driver::read_win_rectangle() contains platform-specific
code to capture pixels from the current window or from an offscreen buffer.
Platform-independent function Fl_Screen_Driver::traverse_to_gl_subwindows()
captures subwindows that intersect with the area fl_read_image() targets.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12653 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
21 files changed, 214 insertions, 173 deletions
diff --git a/FL/Fl_Graphics_Driver.H b/FL/Fl_Graphics_Driver.H index bd4a82326..27778da2f 100644 --- a/FL/Fl_Graphics_Driver.H +++ b/FL/Fl_Graphics_Driver.H @@ -395,6 +395,12 @@ public: virtual void font_name(int num, const char *name) {} /** Support function for Fl_Shared_Image drawing */ virtual int draw_scaled(Fl_Image *img, int X, int Y, int W, int H); + /** Support function for fl_overlay_rect() and scaled GUI. + Defaut implementation may be enough */ + virtual bool overlay_rect_unscaled(); + /** Support function for fl_overlay_rect() and scaled GUI. + Defaut implementation may be enough */ + virtual void overlay_rect(int x, int y, int w , int h) { loop(x, y, x+w-1, y, x+w-1, y+h-1, x, y+h-1); } }; #ifndef FL_DOXYGEN diff --git a/FL/Fl_Screen_Driver.H b/FL/Fl_Screen_Driver.H index 00d3d763d..564b77754 100644 --- a/FL/Fl_Screen_Driver.H +++ b/FL/Fl_Screen_Driver.H @@ -3,7 +3,7 @@ // // All screen related calls in a driver style class. // -// Copyright 1998-2017 by Bill Spitzak and others. +// Copyright 1998-2018 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 @@ -126,25 +126,23 @@ public: #if defined(FL_PORTING) # pragma message "FL_PORTING: implement code to read RGB data from screen" #endif - /* Both member functions read_image() and read_win_rectangle() support - the public function fl_read_image() which captures pixel data either from + /* Member function read_win_rectangle() supports the public function + fl_read_image() which captures pixel data either from the current window or from an offscreen buffer. - A platform re-implements either read_image() or read_win_rectangle(). - In the 1st case and for capture from a window, the returned pixel array + With fl_read_image() and for capture from a window, the returned pixel array also contains data from any embedded sub-window. - In the 2nd case and for capture from a window, only data from the current - window is collected, and read_image()'s default implementation captures - pixels from any subwindow. + + In the case of read_win_rectangle() and for capture from a window, only data + from the current window is collected. A platform may also use its read_win_rectangle() implementation to capture window decorations (e.g., title bar). In that case, it is called by Fl_XXX_Window_Driver::capture_titlebar_and_borders(). */ - virtual uchar *read_image(uchar *p, int x, int y, int w, int h, int alpha); - virtual Fl_RGB_Image *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha) {return NULL;} + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h) {return NULL;} static void write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y); - static Fl_RGB_Image *traverse_to_gl_subwindows(Fl_Group *g, uchar *p, int x, int y, int w, int h, int alpha, + static Fl_RGB_Image *traverse_to_gl_subwindows(Fl_Group *g, int x, int y, int w, int h, Fl_RGB_Image *full_img); // optional platform-specific key handling for Fl_Input widget // the default implementation may be enough diff --git a/src/Fl_Graphics_Driver.cxx b/src/Fl_Graphics_Driver.cxx index d7cb15031..05d609f14 100644 --- a/src/Fl_Graphics_Driver.cxx +++ b/src/Fl_Graphics_Driver.cxx @@ -221,6 +221,11 @@ unsigned Fl_Graphics_Driver::font_desc_size() { return (unsigned)sizeof(Fl_Fontdesc); } +bool Fl_Graphics_Driver::overlay_rect_unscaled() +{ + return (scale() == int(scale())); +} + #ifndef FL_DOXYGEN Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) { next = 0; diff --git a/src/Fl_Screen_Driver.cxx b/src/Fl_Screen_Driver.cxx index b10aa13ac..2dffcd7a5 100644 --- a/src/Fl_Screen_Driver.cxx +++ b/src/Fl_Screen_Driver.cxx @@ -141,45 +141,22 @@ void Fl_Screen_Driver::compose_reset() { Fl::compose_state = 0; } -uchar *Fl_Screen_Driver::read_image(uchar *p, int X, int Y, int w, int h, int alpha) { - uchar *image_data = NULL; - Fl_RGB_Image *img; - if (fl_find(fl_window) == 0) { // read from off_screen buffer - img = read_win_rectangle(p, X, Y, w, h, alpha); - if (!img) { - return NULL; - } - img->alloc_array = 1; - } else { - img = traverse_to_gl_subwindows(Fl_Window::current(), p, X, Y, w, h, alpha, NULL); - } - if (img) { - if (img->w() != w) { - Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w, h); - delete img; - img = img2; - } - img->alloc_array = 0; - image_data = (uchar*)img->array; - delete img; - } - return image_data; -} - void Fl_Screen_Driver::write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y) /* Copy the image "from" inside image "to" with its top-left angle at coordinates to_x, to_y. -Image depth can differ between "to" and "from". +Image depths can differ between "to" and "from". */ { int to_ld = (to->ld() == 0? to->w() * to->d() : to->ld()); int from_ld = (from->ld() == 0? from->w() * from->d() : from->ld()); uchar *tobytes = (uchar*)to->array + to_y * to_ld + to_x * to->d(); const uchar *frombytes = from->array; + int need_alpha = (from->d() == 3 && to->d() == 4); for (int i = 0; i < from->h(); i++) { if (from->d() == to->d()) memcpy(tobytes, frombytes, from->w() * from->d()); else { for (int j = 0; j < from->w(); j++) { memcpy(tobytes + j * to->d(), frombytes + j * from->d(), from->d()); + if (need_alpha) *(tobytes + j * to->d() + 3) = 0xff; } } tobytes += to_ld; @@ -193,45 +170,31 @@ Image depth can differ between "to" and "from". Arguments when this function is initially called: g: a window or GL window - p: as in fl_read_image() x,y,w,h: a rectangle in window g's coordinates - alpha: as in fl_read_image() full_img: NULL Arguments when this function recursively calls itself: g: an Fl_Group - p: as above x,y,w,h: a rectangle in g's coordinates if g is a window, or in g's parent window coords if g is a group - alpha: as above full_img: NULL, or a previously captured image that encompasses the x,y,w,h rectangle and that will be partially overwritten with the new capture Return value: - An Fl_RGB_Image* of depth 4 if alpha>0 or 3 if alpha = 0 containing the captured pixels. + An Fl_RGB_Image*, the depth of which is platform-dependent, containing the captured pixels. */ -Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, uchar *p, int x, int y, int w, int h, int alpha, +Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, int x, int y, int w, int h, Fl_RGB_Image *full_img) { if ( g->as_gl_window() ) { Fl_Plugin_Manager pm("fltk:device"); Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org"); if (!pi) return full_img; - Fl_RGB_Image *img = pi->rectangle_capture(g, x, y, w, h); - if (full_img) full_img = img; - else { - uchar *data = ( p ? p : new uchar[img->w() * img->h() * (alpha?4:3)] ); - full_img = new Fl_RGB_Image(data, img->w(), img->h(), alpha?4:3); - if (!p) full_img->alloc_array = 1; - if (alpha) memset(data, alpha, img->w() * img->h() * 4); - write_image_inside(full_img, img, 0, 0); - delete img; - } + full_img = pi->rectangle_capture(g, x, y, w, h); } else if ( g->as_window() && (!full_img || (g->window() && g->window()->as_gl_window())) ) { // the starting window or one inside a GL window if (full_img) g->as_window()->make_current(); - int alloc_img = (full_img != NULL || p == NULL); // false means use p, don't alloc new memory for image - full_img = Fl::screen_driver()->read_win_rectangle( (alloc_img ? NULL : p), x, y, w, h, alpha); + full_img = Fl::screen_driver()->read_win_rectangle(x, y, w, h); } int n = g->children(); for (int i = 0; i < n; i++) { @@ -249,8 +212,8 @@ Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, uchar *p, if (origin_y + height > c->y() + c->h()) height = c->y() + c->h() - origin_y; if (origin_y + height > y + h) height = y + h - origin_y; if (width > 0 && height > 0) { - Fl_RGB_Image *img = traverse_to_gl_subwindows(c->as_window(), p, origin_x - c->x(), - origin_y - c->y(), width, height, alpha, full_img); + Fl_RGB_Image *img = traverse_to_gl_subwindows(c->as_window(), origin_x - c->x(), + origin_y - c->y(), width, height, full_img); if (img == full_img) continue; int top; if (c->as_gl_window()) { @@ -264,7 +227,7 @@ Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, uchar *p, delete img; } } - else traverse_to_gl_subwindows(c->as_group(), p, x, y, w, h, alpha, full_img); + else traverse_to_gl_subwindows(c->as_group(), x, y, w, h, full_img); } return full_img; } diff --git a/src/Fl_Widget_Surface.cxx b/src/Fl_Widget_Surface.cxx index 7adc4361e..64f86d9ed 100644 --- a/src/Fl_Widget_Surface.cxx +++ b/src/Fl_Widget_Surface.cxx @@ -157,7 +157,7 @@ void Fl_Widget_Surface::print_window_part(Fl_Window *win, int x, int y, int w, i win->show(); Fl::check(); win->driver()->flush(); // makes the window current - Fl_RGB_Image *img = Fl_Screen_Driver::traverse_to_gl_subwindows(win, NULL, x, y, w, h, 0, NULL); + Fl_RGB_Image *img = Fl_Screen_Driver::traverse_to_gl_subwindows(win, x, y, w, h, NULL); Fl_Shared_Image *shared = Fl_Shared_Image::get(img); shared->scale(w, h, 1, 1); if (save_front != win) save_front->show(); diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 74b2f317b..0a8e399b9 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -2710,17 +2710,17 @@ void Fl_WinAPI_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image *&top // capture the 4 window sides from screen Fl_WinAPI_Screen_Driver *dr = (Fl_WinAPI_Screen_Driver *)Fl::screen_driver(); if (htop) { - r_top = dr->read_win_rectangle_unscaled(NULL, r.left, r.top, r.right - r.left, htop, 0); + r_top = dr->read_win_rectangle_unscaled(r.left, r.top, r.right - r.left, htop); top = Fl_Shared_Image::get(r_top); if (DWMscaling != 1) top->scale(ww, htop / DWMscaling, 0, 1); } if (wsides) { - r_left = dr->read_win_rectangle_unscaled(NULL, r.left, r.top + htop, wsides, h() * scaling, 0); + r_left = dr->read_win_rectangle_unscaled(r.left, r.top + htop, wsides, h() * scaling); left = Fl_Shared_Image::get(r_left); - r_right = dr->read_win_rectangle_unscaled(NULL, r.right - wsides, r.top + htop, wsides, h() * scaling, 0); + r_right = dr->read_win_rectangle_unscaled(r.right - wsides, r.top + htop, wsides, h() * scaling); right = Fl_Shared_Image::get(r_right); - r_bottom = dr->read_win_rectangle_unscaled(NULL, r.left, r.bottom - hbottom, ww, hbottom, 0); + r_bottom = dr->read_win_rectangle_unscaled(r.left, r.bottom - hbottom, ww, hbottom); bottom = Fl_Shared_Image::get(r_bottom); if (scaling != 1) { left->scale(wsides, h(), 0, 1); diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H index 12d93b9e8..077416823 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H @@ -4,7 +4,7 @@ // Definition of Apple Cocoa Screen interface // for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2017 by Bill Spitzak and others. +// Copyright 2010-2018 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 @@ -40,6 +40,7 @@ class Fl_Window; class Fl_Input; +class Fl_RGB_Image; class FL_EXPORT Fl_Cocoa_Screen_Driver : public Fl_Screen_Driver { @@ -87,7 +88,6 @@ public: int insertion_point_location(int *px, int *py, int *pheight); virtual int dnd(int use_selection); virtual int compose(int &del); - virtual uchar *read_image(uchar *p, int x, int y, int w, int h, int alpha); virtual int input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input); virtual int get_mouse(int &x, int &y); virtual void enable_im(); @@ -100,6 +100,7 @@ public: virtual APP_SCALING_CAPABILITY rescalable() { return SYSTEMWIDE_APP_SCALING; } virtual float scale(int n) {return scale_;} virtual void scale(int n, float f) { scale_ = f;} + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h); virtual int run_also_windowless(); virtual int wait_also_windowless(double delay); private: diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx index 213995126..d46879932 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx @@ -256,70 +256,6 @@ int Fl_Cocoa_Screen_Driver::compose(int &del) { return 1; } -uchar * // O - Pixel buffer or NULL if failed -Fl_Cocoa_Screen_Driver::read_image(uchar *p, // I - Pixel buffer or NULL to allocate - int x, // I - Left position - int y, // I - Top position - int w, // I - Width of area to read - int h, // I - Height of area to read - int alpha)// I - Alpha value for image (0 for none) -{ - uchar *base; - int rowBytes, delta; - float s = 1; - int ori_w = w, ori_h = h; - if (fl_window == NULL) { // reading from an offscreen buffer - CGContextRef src = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); // get bitmap context - base = (uchar *)CGBitmapContextGetData(src); // get data - if(!base) return NULL; - int sw = CGBitmapContextGetWidth(src); - int sh = CGBitmapContextGetHeight(src); - if( (sw - x < w) || (sh - y < h) ) return NULL; - rowBytes = CGBitmapContextGetBytesPerRow(src); - delta = CGBitmapContextGetBitsPerPixel(src)/8; - Fl_Image_Surface *imgs = (Fl_Image_Surface*)Fl_Surface_Device::surface(); - int fltk_w, fltk_h; - imgs->printable_rect(&fltk_w, &fltk_h); - s = sw / float(fltk_w); - x *= s; y *= s; w *= s; h *= s; - if (x + w > sw) w = sw - x; - if (y + h > sh) h = sh - y; - } - else { // reading from current window - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(Fl_Window::current()); - base = d->bitmap_from_window_rect(x,y,w,h,&delta); - if (!base) return NULL; - rowBytes = delta*w; - x = y = 0; - } - // Allocate the image data array as needed... - int d = alpha ? 4 : 3; - if (!p) p = new uchar[w * h * d]; - // Initialize the default colors/alpha in the whole image... - memset(p, alpha, w * h * d); - // Copy the image from the off-screen buffer to the memory buffer. - int idx, idy; // Current X & Y in image - uchar *pdst, *psrc; - for (idy = y, pdst = p; idy < h + y; idy ++) { - for (idx = 0, psrc = base + idy * rowBytes + x * delta; idx < w; idx ++, psrc += delta, pdst += d) { - pdst[0] = psrc[0]; // R - pdst[1] = psrc[1]; // G - pdst[2] = psrc[2]; // B - } - } - if (fl_window != NULL) delete[] base; - if (s != 1) { - Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, alpha ? 4 : 3); - rgb->alloc_array = 1; - Fl_RGB_Image *rgb2 = (Fl_RGB_Image*)rgb->copy(ori_w, ori_h); - rgb2->alloc_array = 0; - delete rgb; - p = (uchar*)rgb2->array; - delete rgb2; - } - return p; -} - int Fl_Cocoa_Screen_Driver::input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input) { @@ -401,6 +337,67 @@ void Fl_Cocoa_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &h height = CGBitmapContextGetHeight(off); } +Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h) +{ + int bpp, bpr, depth = 4; + uchar *base, *p; + if (!fl_window) { // read from offscreen buffer + float s = 1; + CGContextRef src = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); // get bitmap context + base = (uchar *)CGBitmapContextGetData(src); // get data + if(!base) return NULL; + int sw = CGBitmapContextGetWidth(src); + int sh = CGBitmapContextGetHeight(src); + if( (sw - X < w) || (sh - Y < h) ) return NULL; + bpr = CGBitmapContextGetBytesPerRow(src); + bpp = CGBitmapContextGetBitsPerPixel(src)/8; + Fl_Image_Surface *imgs = (Fl_Image_Surface*)Fl_Surface_Device::surface(); + int fltk_w, fltk_h; + imgs->printable_rect(&fltk_w, &fltk_h); + s = sw / float(fltk_w); + X *= s; Y *= s; w *= s; h *= s; + if (X + w > sw) w = sw - X; + if (Y + h > sh) h = sh - Y; + // Copy the image from the off-screen buffer to the memory buffer. + int idx, idy; // Current X & Y in image + uchar *pdst, *psrc; + p = new uchar[w * h * depth]; + for (idy = Y, pdst = p; idy < h + Y; idy ++) { + for (idx = 0, psrc = base + idy * bpr + X * bpp; idx < w; idx ++, psrc += bpp, pdst += depth) { + pdst[0] = psrc[0]; // R + pdst[1] = psrc[1]; // G + pdst[2] = psrc[2]; // B + } + } + bpr = 0; + } else { // read from window + Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(Fl_Window::current()); + CGImageRef cgimg = d->CGImage_from_window_rect(X, Y, w, h); + if (!cgimg) { + return NULL; + } + w = CGImageGetWidth(cgimg); + h = CGImageGetHeight(cgimg); + Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); + Fl_Surface_Device::push_current(surf); + ((Fl_Quartz_Graphics_Driver*)fl_graphics_driver)->draw_CGImage(cgimg, 0, 0, w, h, 0, 0, w, h); + CGContextRef gc = (CGContextRef)fl_graphics_driver->gc(); + w = CGBitmapContextGetWidth(gc); + h = CGBitmapContextGetHeight(gc); + bpr = CGBitmapContextGetBytesPerRow(gc); + bpp = CGBitmapContextGetBitsPerPixel(gc)/8; + base = (uchar*)CGBitmapContextGetData(gc); + p = new uchar[bpr * h]; + memcpy(p, base, bpr * h); + Fl_Surface_Device::pop_current(); + delete surf; + CFRelease(cgimg); + } + Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, depth, bpr); + rgb->alloc_array = 1; + return rgb; +} + // // End of "$Id$". // diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H index 08a8ce42c..ef64799c9 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H @@ -88,7 +88,6 @@ public: CGRect* subRect() { return subRect_; } // getter void subRect(CGRect *r) { subRect_ = r; } // setter static void destroy(FLWindow*); - unsigned char *bitmap_from_window_rect(int x, int y, int w, int h, int *bytesPerPixel); CGImageRef CGImage_from_window_rect(int x, int y, int w, int h); // --- window data diff --git a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx index 573bca696..453a5f600 100644 --- a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx +++ b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx @@ -92,7 +92,7 @@ void Fl_GDI_Image_Surface_Driver::untranslate() { Fl_RGB_Image* Fl_GDI_Image_Surface_Driver::image() { - Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, width, height, 0); + Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle( 0, 0, width, height); return image; } diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H index 60a261e94..b23817d46 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H @@ -184,6 +184,8 @@ protected: #else void descriptor_init(const char* name, Fl_Fontsize Size, Fl_Quartz_Font_Descriptor *d); #endif + virtual bool overlay_rect_unscaled() {return false; } + virtual void overlay_rect(int x, int y, int w , int h); }; class Fl_Quartz_Printer_Graphics_Driver : public Fl_Quartz_Graphics_Driver { diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx index 3a83b94d6..8153f4e78 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx @@ -173,6 +173,30 @@ void Fl_Quartz_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y if (quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); } +// returns y of horizontal line corresponding to pixels of current window +// read by Fl_Cocoa_Screen_Driver::read_win_rectangle( -, y, -, 1) +// when GUI is scaled by s +static float overlay_y(int y, float s, int H) { + int a, b, c; + a = int(H*s) - (y+1)*s; // in Cocoa units from window bottom + c = (s > 1 ? s : 1); // height of pixels read in Cocoa units + b = H*s - (a+c); // top of read image from window top in Cocoa units + return b/s; // top of read image from window top in FLTK units +} + +void Fl_Quartz_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { + float s = scale(); + CGContextSetLineWidth(gc_, 0.01); + int H = Fl_Window::current()->h(); + CGContextMoveToPoint(gc_, x, overlay_y(y, s, H)); + CGContextAddLineToPoint(gc_, x+w-1, overlay_y(y, s, H)); + CGContextAddLineToPoint(gc_, x+w-1, overlay_y(y+h-1, s, H)); + CGContextAddLineToPoint(gc_, x, overlay_y(y+h-1, s, H)); + CGContextClosePath(gc_); + CGContextStrokePath(gc_); + CGContextSetLineWidth(gc_, quartz_line_width_); +} + void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { CGContextSetShouldAntialias(gc_, true); CGContextMoveToPoint(gc_, x, y); diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H index e28fb791a..b5d238ba9 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H @@ -4,7 +4,7 @@ // Definition of MSWindows Win32/64 Screen interface // for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2016 by Bill Spitzak and others. +// Copyright 2010-2018 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 @@ -79,8 +79,8 @@ public: virtual void remove_timeout(Fl_Timeout_Handler cb, void *argp); virtual int dnd(int unused); virtual int compose(int &del); - virtual Fl_RGB_Image *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha); - Fl_RGB_Image *read_win_rectangle_unscaled(uchar *p, int X, int Y, int w, int h, int alpha); + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h); + Fl_RGB_Image *read_win_rectangle_unscaled(int X, int Y, int w, int h); virtual int get_mouse(int &x, int &y); virtual void enable_im(); virtual void disable_im(); diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 9373d345d..f44fa7a3c 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -496,24 +496,21 @@ int Fl_WinAPI_Screen_Driver::compose(int &del) { Fl_RGB_Image * // O - image or NULL if failed -Fl_WinAPI_Screen_Driver::read_win_rectangle(uchar *p, // I - Pixel buffer or NULL to allocate +Fl_WinAPI_Screen_Driver::read_win_rectangle( int X, // I - Left position int Y, // I - Top position int w, // I - Width of area to read - int h, // I - Height of area to read - int alpha) // I - Alpha value for image (0 for none) + int h) // I - Height of area to read { float s = Fl_Surface_Device::surface()->driver()->scale(); - return read_win_rectangle_unscaled(p, X*s, Y*s, w*s, h*s, alpha); + return read_win_rectangle_unscaled(X*s, Y*s, w*s, h*s); } -Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(uchar *p, int X, int Y, int w, int h, int alpha) +Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y, int w, int h) { - int d; // Depth of image - - // Allocate the image data array as needed... - d = alpha ? 4 : 3; - + int d = 3; // Depth of image + int alpha = 0; uchar *p = NULL; + // Allocate the image data array as needed... const uchar *oldp = p; if (!p) p = new uchar[w * h * d]; diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.H b/src/drivers/X11/Fl_X11_Screen_Driver.H index 6ceca775c..78a0510a5 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.H +++ b/src/drivers/X11/Fl_X11_Screen_Driver.H @@ -4,7 +4,7 @@ // Definition of X11 Screen interface // for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2017 by Bill Spitzak and others. +// Copyright 2010-2018 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 @@ -93,7 +93,7 @@ public: virtual int compose(int &del); virtual void compose_reset(); virtual int text_display_can_leak(); - virtual Fl_RGB_Image *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha); + virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h); virtual int get_mouse(int &x, int &y); virtual void enable_im(); virtual void disable_im(); diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.cxx b/src/drivers/X11/Fl_X11_Screen_Driver.cxx index 6b253931d..7f6dc5528 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Screen_Driver.cxx @@ -750,7 +750,7 @@ extern "C" { } } -Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha) +Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h) { XImage *image; // Captured image int i, maxindex; // Looping vars @@ -862,14 +862,14 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, i printf("map_entries = %d\n", fl_visual->visual->map_entries); #endif // DEBUG - d = alpha ? 4 : 3; - + d = 3; + uchar *p = NULL; // Allocate the image data array as needed... const uchar *oldp = p; if (!p) p = new uchar[w * h * d]; // Initialize the default colors/alpha in the whole image... - memset(p, alpha, w * h * d); + memset(p, 0, w * h * d); // Check that we have valid mask/shift values... if (!image->red_mask && image->bits_per_pixel > 12) { diff --git a/src/drivers/X11/Fl_X11_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Window_Driver.cxx index 5612ce4df..b89688b47 100644 --- a/src/drivers/X11/Fl_X11_Window_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Window_Driver.cxx @@ -413,22 +413,22 @@ void Fl_X11_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image*& top, F htop /= s; wsides /= s; fl_window = parent; if (htop) { - r_top = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, - (w() + 2 * wsides), htop, 0); + r_top = Fl::screen_driver()->read_win_rectangle(0, 0, - (w() + 2 * wsides), htop); top = Fl_Shared_Image::get(r_top); top->scale(w() + 2 * wsides, htop, 0, 1); } if (wsides) { - r_left = Fl::screen_driver()->read_win_rectangle(NULL, 0, htop, -wsides, h(), 0); + r_left = Fl::screen_driver()->read_win_rectangle(0, htop, -wsides, h()); if (r_left) { left = Fl_Shared_Image::get(r_left); left->scale(wsides, h(), 0, 1); } - r_right = Fl::screen_driver()->read_win_rectangle(NULL, w() + wsides, htop, -wsides, h(), 0); + r_right = Fl::screen_driver()->read_win_rectangle(w() + wsides, htop, -wsides, h()); if (r_right) { right = Fl_Shared_Image::get(r_right); right->scale(wsides, h(), 0, 1); } - r_bottom = Fl::screen_driver()->read_win_rectangle(NULL, 0, htop + h(), -(w() + 2*wsides), hbottom, 0); + r_bottom = Fl::screen_driver()->read_win_rectangle(0, htop + h(), -(w() + 2*wsides), hbottom); if (r_bottom) { bottom = Fl_Shared_Image::get(r_bottom); bottom->scale(w() + 2*wsides, wsides, 0, 1); diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx index 73a69109b..74a5022f4 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx @@ -67,7 +67,7 @@ Fl_Xlib_Copy_Surface_Driver::~Fl_Xlib_Copy_Surface_Driver() { driver()->pop_clip(); bool need_push = (Fl_Surface_Device::surface() != this); if (need_push) Fl_Surface_Device::push_current(this); - Fl_RGB_Image *rgb = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, width, height, 0); + Fl_RGB_Image *rgb = Fl::screen_driver()->read_win_rectangle(0, 0, width, height); if (need_push) Fl_Surface_Device::pop_current(); Fl_X11_Screen_Driver::copy_image(rgb->array, rgb->w(), rgb->h(), 1); delete rgb; diff --git a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx index 0d3383cc5..c5bcce9af 100644 --- a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx @@ -80,7 +80,7 @@ void Fl_Xlib_Image_Surface_Driver::untranslate() { Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image() { - Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, width, height, 0); + Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(0, 0, width, height); return image; } diff --git a/src/fl_overlay.cxx b/src/fl_overlay.cxx index c1a8e2d32..8e095a962 100644 --- a/src/fl_overlay.cxx +++ b/src/fl_overlay.cxx @@ -57,7 +57,7 @@ static void draw_current_rect() { int old = SetROP2(fl_graphics_driver->gc(), R2_NOT); fl_rect(px, py, pw, ph); SetROP2(fl_graphics_driver->gc(), old); -# elif defined(__APPLE_) // PORTME: Fl_Window_Driver - platform overlay +# elif defined(__APPLE__) // warning: Quartz does not support xor drawing // Use the Fl_Overlay_Window instead. fl_color(FL_WHITE); @@ -66,8 +66,8 @@ static void draw_current_rect() { # error unsupported platform # endif #else - float s = fl_graphics_driver->scale(); - if (s == int(s)) { + bool unscaled = fl_graphics_driver->overlay_rect_unscaled(); + if (unscaled) { if (bgN) { free(bgN); bgN = 0L; } if (bgS) { free(bgS); bgS = 0L; } if (bgE) { free(bgE); bgE = 0L; } @@ -79,29 +79,29 @@ static void draw_current_rect() { if (s_bgW) { s_bgW->release(); s_bgW = 0; } } if (pw>0 && ph>0) { - if (s == int(s)) { + if (unscaled) { bgE = fl_read_image(0L, px+pw-1, py, 1, ph); bgW = fl_read_image(0L, px, py, 1, ph); bgS = fl_read_image(0L, px, py+ph-1, pw, 1); bgN = fl_read_image(0L, px, py, pw, 1); } else { Fl_RGB_Image *tmp; - tmp = Fl::screen_driver()->read_win_rectangle(NULL, px+pw-1, py, 1, ph, 0); + tmp = Fl::screen_driver()->read_win_rectangle( px+pw-1, py, 1, ph); if(tmp && tmp->w() && tmp->h()) { s_bgE = Fl_Shared_Image::get(tmp); s_bgE->scale(1, ph,0,1); } - tmp = Fl::screen_driver()->read_win_rectangle(NULL, px, py, 1, ph, 0); + tmp = Fl::screen_driver()->read_win_rectangle( px, py, 1, ph); if(tmp && tmp->w() && tmp->h()) { s_bgW = Fl_Shared_Image::get(tmp); s_bgW->scale(1, ph,0,1); } - tmp = Fl::screen_driver()->read_win_rectangle(NULL, px, py+ph-1, pw, 1, 0); + tmp = Fl::screen_driver()->read_win_rectangle( px, py+ph-1, pw, 1); if(tmp && tmp->w() && tmp->h()) { s_bgS = Fl_Shared_Image::get(tmp); s_bgS->scale(pw, 1,0,1); } - tmp = Fl::screen_driver()->read_win_rectangle(NULL, px, py, pw, 1, 0); + tmp = Fl::screen_driver()->read_win_rectangle( px, py, pw, 1); if(tmp && tmp->w() && tmp->h()) { s_bgN = Fl_Shared_Image::get(tmp); s_bgN->scale(pw, 1,0,1); @@ -112,12 +112,13 @@ static void draw_current_rect() { } fl_color(FL_WHITE); fl_line_style(FL_SOLID); - if (s == int(s)) fl_rect(px, py, pw, ph); - else fl_loop(px, py, px+pw-1, py, px+pw-1, py+ph-1, px, py+ph-1); + if (unscaled) fl_rect(px, py, pw, ph); + else fl_graphics_driver->overlay_rect(px, py, pw, ph); + fl_color(FL_BLACK); fl_line_style(FL_DOT); - if (s == int(s)) fl_rect(px, py, pw, ph); - else fl_loop(px, py, px+pw-1, py, px+pw-1, py+ph-1, px, py+ph-1); + if (unscaled) fl_rect(px, py, pw, ph); + else fl_graphics_driver->overlay_rect(px, py, pw, ph); fl_line_style(FL_SOLID); #endif // USE_XOR } @@ -130,8 +131,8 @@ static void erase_current_rect() { draw_current_rect(); # endif #else - float s = fl_graphics_driver->scale(); - if (s == int(s)) { + bool unscaled = fl_graphics_driver->overlay_rect_unscaled(); + if (unscaled) { if (bgN) fl_draw_image(bgN, bgx, bgy, bgw, 1); if (bgS) fl_draw_image(bgS, bgx, bgy+bgh-1, bgw, 1); if (bgW) fl_draw_image(bgW, bgx, bgy, 1, bgh); diff --git a/src/fl_read_image.cxx b/src/fl_read_image.cxx index e7d91b865..d3d32877f 100644 --- a/src/fl_read_image.cxx +++ b/src/fl_read_image.cxx @@ -3,7 +3,7 @@ // // X11 image reading routines for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2018 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 @@ -17,6 +17,7 @@ // #include <FL/Fl.H> +#include <FL/platform.H> #include <FL/Fl_Screen_Driver.H> /** @@ -36,8 +37,55 @@ and the value that is placed in the alpha channel. If 0, no alpha channel is generated. */ -uchar *fl_read_image(uchar *p, int X, int Y, int W, int H, int alpha) { - return Fl::screen_driver()->read_image(p, X, Y, W, H, alpha); +uchar *fl_read_image(uchar *p, int X, int Y, int w, int h, int alpha) { + uchar *image_data = NULL; + Fl_RGB_Image *img; + if (fl_find(fl_window) == 0) { // read from off_screen buffer + img = Fl::screen_driver()->read_win_rectangle(X, Y, w, h); + if (!img) { + return NULL; + } + img->alloc_array = 1; + } else { + img = Fl::screen_driver()->traverse_to_gl_subwindows(Fl_Window::current(), X, Y, w, h, NULL); + } + int depth = alpha ? 4 : 3; + if (img->d() != depth) { + uchar *data = new uchar[img->w() * img->h() * depth]; + if (depth == 4) memset(data, alpha, img->w() * img->h() * depth); + uchar *d = data; + const uchar *q; + int ld = img->ld() ? img->ld() : img->w() * img->d(); + for (int r = 0; r < img->h(); r++) { + q = img->array + r * ld; + for (int c = 0; c < img->w(); c++) { + d[0] = q[0]; + d[1] = q[1]; + d[2] = q[2]; + d += depth; q += img->d(); + } + } + Fl_RGB_Image *img2 = new Fl_RGB_Image(data, img->w(), img->h(), depth); + img2->alloc_array = 1; + delete img; + img = img2; + } + if (img) { + if (img->w() != w || img->h() != h) { + Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w, h); + delete img; + img = img2; + } + img->alloc_array = 0; + image_data = (uchar*)img->array; + delete img; + } + if (p && image_data) { + memcpy(p, image_data, w * h * depth); + delete[] image_data; + image_data = p; + } + return image_data; } // |
