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
This commit is contained in:
Manolo Gouy
2018-02-09 13:48:22 +00:00
parent b78b2f7f5f
commit c472d5d8b7
21 changed files with 214 additions and 173 deletions
+6
View File
@@ -395,6 +395,12 @@ public:
virtual void font_name(int num, const char *name) {} virtual void font_name(int num, const char *name) {}
/** Support function for Fl_Shared_Image drawing */ /** Support function for Fl_Shared_Image drawing */
virtual int draw_scaled(Fl_Image *img, int X, int Y, int W, int H); 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 #ifndef FL_DOXYGEN
+9 -11
View File
@@ -3,7 +3,7 @@
// //
// All screen related calls in a driver style class. // 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 // 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 // the file "COPYING" which should have been included with this file. If this
@@ -126,25 +126,23 @@ public:
#if defined(FL_PORTING) #if defined(FL_PORTING)
# pragma message "FL_PORTING: implement code to read RGB data from screen" # pragma message "FL_PORTING: implement code to read RGB data from screen"
#endif #endif
/* Both member functions read_image() and read_win_rectangle() support /* Member function read_win_rectangle() supports the public function
the public function fl_read_image() which captures pixel data either from fl_read_image() which captures pixel data either from
the current window or from an offscreen buffer. the current window or from an offscreen buffer.
A platform re-implements either read_image() or read_win_rectangle(). With fl_read_image() and for capture from a window, the returned pixel array
In the 1st case and for capture from a window, the returned pixel array
also contains data from any embedded sub-window. 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 In the case of read_win_rectangle() and for capture from a window, only data
pixels from any subwindow. from the current window is collected.
A platform may also use its read_win_rectangle() implementation to capture 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 window decorations (e.g., title bar). In that case, it is called by
Fl_XXX_Window_Driver::capture_titlebar_and_borders(). 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(int X, int Y, int w, int h) {return NULL;}
virtual Fl_RGB_Image *read_win_rectangle(uchar *p, int X, int Y, int w, int h, int alpha) {return NULL;}
static void write_image_inside(Fl_RGB_Image *to, Fl_RGB_Image *from, int to_x, int to_y); 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); Fl_RGB_Image *full_img);
// optional platform-specific key handling for Fl_Input widget // optional platform-specific key handling for Fl_Input widget
// the default implementation may be enough // the default implementation may be enough
+5
View File
@@ -221,6 +221,11 @@ unsigned Fl_Graphics_Driver::font_desc_size() {
return (unsigned)sizeof(Fl_Fontdesc); return (unsigned)sizeof(Fl_Fontdesc);
} }
bool Fl_Graphics_Driver::overlay_rect_unscaled()
{
return (scale() == int(scale()));
}
#ifndef FL_DOXYGEN #ifndef FL_DOXYGEN
Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) { Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) {
next = 0; next = 0;
+10 -47
View File
@@ -141,45 +141,22 @@ void Fl_Screen_Driver::compose_reset() {
Fl::compose_state = 0; 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) 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. /* 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 to_ld = (to->ld() == 0? to->w() * to->d() : to->ld());
int from_ld = (from->ld() == 0? from->w() * from->d() : from->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(); uchar *tobytes = (uchar*)to->array + to_y * to_ld + to_x * to->d();
const uchar *frombytes = from->array; const uchar *frombytes = from->array;
int need_alpha = (from->d() == 3 && to->d() == 4);
for (int i = 0; i < from->h(); i++) { for (int i = 0; i < from->h(); i++) {
if (from->d() == to->d()) memcpy(tobytes, frombytes, from->w() * from->d()); if (from->d() == to->d()) memcpy(tobytes, frombytes, from->w() * from->d());
else { else {
for (int j = 0; j < from->w(); j++) { for (int j = 0; j < from->w(); j++) {
memcpy(tobytes + j * to->d(), frombytes + j * from->d(), from->d()); memcpy(tobytes + j * to->d(), frombytes + j * from->d(), from->d());
if (need_alpha) *(tobytes + j * to->d() + 3) = 0xff;
} }
} }
tobytes += to_ld; tobytes += to_ld;
@@ -193,45 +170,31 @@ Image depth can differ between "to" and "from".
Arguments when this function is initially called: Arguments when this function is initially called:
g: a window or GL window g: a window or GL window
p: as in fl_read_image()
x,y,w,h: a rectangle in window g's coordinates x,y,w,h: a rectangle in window g's coordinates
alpha: as in fl_read_image()
full_img: NULL full_img: NULL
Arguments when this function recursively calls itself: Arguments when this function recursively calls itself:
g: an Fl_Group 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 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 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 will be partially overwritten with the new capture
Return value: 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) Fl_RGB_Image *full_img)
{ {
if ( g->as_gl_window() ) { if ( g->as_gl_window() ) {
Fl_Plugin_Manager pm("fltk:device"); Fl_Plugin_Manager pm("fltk:device");
Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org"); Fl_Device_Plugin *pi = (Fl_Device_Plugin*)pm.plugin("opengl.device.fltk.org");
if (!pi) return full_img; if (!pi) return full_img;
Fl_RGB_Image *img = pi->rectangle_capture(g, x, y, w, h); full_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;
}
} }
else if ( g->as_window() && (!full_img || (g->window() && g->window()->as_gl_window())) ) { else if ( g->as_window() && (!full_img || (g->window() && g->window()->as_gl_window())) ) {
// the starting window or one inside a GL window // the starting window or one inside a GL window
if (full_img) g->as_window()->make_current(); 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(x, y, w, h);
full_img = Fl::screen_driver()->read_win_rectangle( (alloc_img ? NULL : p), x, y, w, h, alpha);
} }
int n = g->children(); int n = g->children();
for (int i = 0; i < n; i++) { 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 > c->y() + c->h()) height = c->y() + c->h() - origin_y;
if (origin_y + height > y + h) height = y + h - origin_y; if (origin_y + height > y + h) height = y + h - origin_y;
if (width > 0 && height > 0) { if (width > 0 && height > 0) {
Fl_RGB_Image *img = traverse_to_gl_subwindows(c->as_window(), p, origin_x - c->x(), Fl_RGB_Image *img = traverse_to_gl_subwindows(c->as_window(), origin_x - c->x(),
origin_y - c->y(), width, height, alpha, full_img); origin_y - c->y(), width, height, full_img);
if (img == full_img) continue; if (img == full_img) continue;
int top; int top;
if (c->as_gl_window()) { 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; 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; return full_img;
} }
+1 -1
View File
@@ -157,7 +157,7 @@ void Fl_Widget_Surface::print_window_part(Fl_Window *win, int x, int y, int w, i
win->show(); win->show();
Fl::check(); Fl::check();
win->driver()->flush(); // makes the window current 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); Fl_Shared_Image *shared = Fl_Shared_Image::get(img);
shared->scale(w, h, 1, 1); shared->scale(w, h, 1, 1);
if (save_front != win) save_front->show(); if (save_front != win) save_front->show();
+4 -4
View File
@@ -2710,17 +2710,17 @@ void Fl_WinAPI_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image *&top
// capture the 4 window sides from screen // capture the 4 window sides from screen
Fl_WinAPI_Screen_Driver *dr = (Fl_WinAPI_Screen_Driver *)Fl::screen_driver(); Fl_WinAPI_Screen_Driver *dr = (Fl_WinAPI_Screen_Driver *)Fl::screen_driver();
if (htop) { 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); top = Fl_Shared_Image::get(r_top);
if (DWMscaling != 1) if (DWMscaling != 1)
top->scale(ww, htop / DWMscaling, 0, 1); top->scale(ww, htop / DWMscaling, 0, 1);
} }
if (wsides) { 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); 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); 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); bottom = Fl_Shared_Image::get(r_bottom);
if (scaling != 1) { if (scaling != 1) {
left->scale(wsides, h(), 0, 1); left->scale(wsides, h(), 0, 1);
+3 -2
View File
@@ -4,7 +4,7 @@
// Definition of Apple Cocoa Screen interface // Definition of Apple Cocoa Screen interface
// for the Fast Light Tool Kit (FLTK). // 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 // 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 // the file "COPYING" which should have been included with this file. If this
@@ -40,6 +40,7 @@
class Fl_Window; class Fl_Window;
class Fl_Input; class Fl_Input;
class Fl_RGB_Image;
class FL_EXPORT Fl_Cocoa_Screen_Driver : public Fl_Screen_Driver 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); int insertion_point_location(int *px, int *py, int *pheight);
virtual int dnd(int use_selection); virtual int dnd(int use_selection);
virtual int compose(int &del); 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 input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input);
virtual int get_mouse(int &x, int &y); virtual int get_mouse(int &x, int &y);
virtual void enable_im(); virtual void enable_im();
@@ -100,6 +100,7 @@ public:
virtual APP_SCALING_CAPABILITY rescalable() { return SYSTEMWIDE_APP_SCALING; } virtual APP_SCALING_CAPABILITY rescalable() { return SYSTEMWIDE_APP_SCALING; }
virtual float scale(int n) {return scale_;} virtual float scale(int n) {return scale_;}
virtual void scale(int n, float f) { scale_ = f;} 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 run_also_windowless();
virtual int wait_also_windowless(double delay); virtual int wait_also_windowless(double delay);
private: private:
+61 -64
View File
@@ -256,70 +256,6 @@ int Fl_Cocoa_Screen_Driver::compose(int &del) {
return 1; 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) 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); 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$". // End of "$Id$".
// //
@@ -88,7 +88,6 @@ public:
CGRect* subRect() { return subRect_; } // getter CGRect* subRect() { return subRect_; } // getter
void subRect(CGRect *r) { subRect_ = r; } // setter void subRect(CGRect *r) { subRect_ = r; } // setter
static void destroy(FLWindow*); 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); CGImageRef CGImage_from_window_rect(int x, int y, int w, int h);
// --- window data // --- window data
@@ -92,7 +92,7 @@ void Fl_GDI_Image_Surface_Driver::untranslate() {
Fl_RGB_Image* Fl_GDI_Image_Surface_Driver::image() 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; return image;
} }
@@ -184,6 +184,8 @@ protected:
#else #else
void descriptor_init(const char* name, Fl_Fontsize Size, Fl_Quartz_Font_Descriptor *d); void descriptor_init(const char* name, Fl_Fontsize Size, Fl_Quartz_Font_Descriptor *d);
#endif #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 { class Fl_Quartz_Printer_Graphics_Driver : public Fl_Quartz_Graphics_Driver {
@@ -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); 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) { void Fl_Quartz_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) {
CGContextSetShouldAntialias(gc_, true); CGContextSetShouldAntialias(gc_, true);
CGContextMoveToPoint(gc_, x, y); CGContextMoveToPoint(gc_, x, y);
+3 -3
View File
@@ -4,7 +4,7 @@
// Definition of MSWindows Win32/64 Screen interface // Definition of MSWindows Win32/64 Screen interface
// for the Fast Light Tool Kit (FLTK). // 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 // 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 // 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 void remove_timeout(Fl_Timeout_Handler cb, void *argp);
virtual int dnd(int unused); virtual int dnd(int unused);
virtual int compose(int &del); virtual int compose(int &del);
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);
Fl_RGB_Image *read_win_rectangle_unscaled(uchar *p, int X, int Y, int w, int h, int alpha); Fl_RGB_Image *read_win_rectangle_unscaled(int X, int Y, int w, int h);
virtual int get_mouse(int &x, int &y); virtual int get_mouse(int &x, int &y);
virtual void enable_im(); virtual void enable_im();
virtual void disable_im(); virtual void disable_im();
+7 -10
View File
@@ -496,24 +496,21 @@ int Fl_WinAPI_Screen_Driver::compose(int &del) {
Fl_RGB_Image * // O - image or NULL if failed 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 X, // I - Left position
int Y, // I - Top position int Y, // I - Top position
int w, // I - Width of area to read int w, // I - Width of area to read
int h, // I - Height of area to read int h) // I - Height of area to read
int alpha) // I - Alpha value for image (0 for none)
{ {
float s = Fl_Surface_Device::surface()->driver()->scale(); 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 int d = 3; // Depth of image
int alpha = 0; uchar *p = NULL;
// Allocate the image data array as needed... // Allocate the image data array as needed...
d = alpha ? 4 : 3;
const uchar *oldp = p; const uchar *oldp = p;
if (!p) p = new uchar[w * h * d]; if (!p) p = new uchar[w * h * d];
+2 -2
View File
@@ -4,7 +4,7 @@
// Definition of X11 Screen interface // Definition of X11 Screen interface
// for the Fast Light Tool Kit (FLTK). // 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 // 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 // the file "COPYING" which should have been included with this file. If this
@@ -93,7 +93,7 @@ public:
virtual int compose(int &del); virtual int compose(int &del);
virtual void compose_reset(); virtual void compose_reset();
virtual int text_display_can_leak(); 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 int get_mouse(int &x, int &y);
virtual void enable_im(); virtual void enable_im();
virtual void disable_im(); virtual void disable_im();
+4 -4
View File
@@ -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 XImage *image; // Captured image
int i, maxindex; // Looping vars 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); printf("map_entries = %d\n", fl_visual->visual->map_entries);
#endif // DEBUG #endif // DEBUG
d = alpha ? 4 : 3; d = 3;
uchar *p = NULL;
// Allocate the image data array as needed... // Allocate the image data array as needed...
const uchar *oldp = p; const uchar *oldp = p;
if (!p) p = new uchar[w * h * d]; if (!p) p = new uchar[w * h * d];
// Initialize the default colors/alpha in the whole image... // 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... // Check that we have valid mask/shift values...
if (!image->red_mask && image->bits_per_pixel > 12) { if (!image->red_mask && image->bits_per_pixel > 12) {
+4 -4
View File
@@ -413,22 +413,22 @@ void Fl_X11_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image*& top, F
htop /= s; wsides /= s; htop /= s; wsides /= s;
fl_window = parent; fl_window = parent;
if (htop) { 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 = Fl_Shared_Image::get(r_top);
top->scale(w() + 2 * wsides, htop, 0, 1); top->scale(w() + 2 * wsides, htop, 0, 1);
} }
if (wsides) { 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) { if (r_left) {
left = Fl_Shared_Image::get(r_left); left = Fl_Shared_Image::get(r_left);
left->scale(wsides, h(), 0, 1); 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) { if (r_right) {
right = Fl_Shared_Image::get(r_right); right = Fl_Shared_Image::get(r_right);
right->scale(wsides, h(), 0, 1); 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) { if (r_bottom) {
bottom = Fl_Shared_Image::get(r_bottom); bottom = Fl_Shared_Image::get(r_bottom);
bottom->scale(w() + 2*wsides, wsides, 0, 1); bottom->scale(w() + 2*wsides, wsides, 0, 1);
@@ -67,7 +67,7 @@ Fl_Xlib_Copy_Surface_Driver::~Fl_Xlib_Copy_Surface_Driver() {
driver()->pop_clip(); driver()->pop_clip();
bool need_push = (Fl_Surface_Device::surface() != this); bool need_push = (Fl_Surface_Device::surface() != this);
if (need_push) Fl_Surface_Device::push_current(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(); if (need_push) Fl_Surface_Device::pop_current();
Fl_X11_Screen_Driver::copy_image(rgb->array, rgb->w(), rgb->h(), 1); Fl_X11_Screen_Driver::copy_image(rgb->array, rgb->w(), rgb->h(), 1);
delete rgb; delete rgb;
@@ -80,7 +80,7 @@ void Fl_Xlib_Image_Surface_Driver::untranslate() {
Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image() 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; return image;
} }
+15 -14
View File
@@ -57,7 +57,7 @@ static void draw_current_rect() {
int old = SetROP2(fl_graphics_driver->gc(), R2_NOT); int old = SetROP2(fl_graphics_driver->gc(), R2_NOT);
fl_rect(px, py, pw, ph); fl_rect(px, py, pw, ph);
SetROP2(fl_graphics_driver->gc(), old); 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 // warning: Quartz does not support xor drawing
// Use the Fl_Overlay_Window instead. // Use the Fl_Overlay_Window instead.
fl_color(FL_WHITE); fl_color(FL_WHITE);
@@ -66,8 +66,8 @@ static void draw_current_rect() {
# error unsupported platform # error unsupported platform
# endif # endif
#else #else
float s = fl_graphics_driver->scale(); bool unscaled = fl_graphics_driver->overlay_rect_unscaled();
if (s == int(s)) { if (unscaled) {
if (bgN) { free(bgN); bgN = 0L; } if (bgN) { free(bgN); bgN = 0L; }
if (bgS) { free(bgS); bgS = 0L; } if (bgS) { free(bgS); bgS = 0L; }
if (bgE) { free(bgE); bgE = 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 (s_bgW) { s_bgW->release(); s_bgW = 0; }
} }
if (pw>0 && ph>0) { if (pw>0 && ph>0) {
if (s == int(s)) { if (unscaled) {
bgE = fl_read_image(0L, px+pw-1, py, 1, ph); bgE = fl_read_image(0L, px+pw-1, py, 1, ph);
bgW = fl_read_image(0L, px, py, 1, ph); bgW = fl_read_image(0L, px, py, 1, ph);
bgS = fl_read_image(0L, px, py+ph-1, pw, 1); bgS = fl_read_image(0L, px, py+ph-1, pw, 1);
bgN = fl_read_image(0L, px, py, pw, 1); bgN = fl_read_image(0L, px, py, pw, 1);
} else { } else {
Fl_RGB_Image *tmp; 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()) { if(tmp && tmp->w() && tmp->h()) {
s_bgE = Fl_Shared_Image::get(tmp); s_bgE = Fl_Shared_Image::get(tmp);
s_bgE->scale(1, ph,0,1); 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()) { if(tmp && tmp->w() && tmp->h()) {
s_bgW = Fl_Shared_Image::get(tmp); s_bgW = Fl_Shared_Image::get(tmp);
s_bgW->scale(1, ph,0,1); 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()) { if(tmp && tmp->w() && tmp->h()) {
s_bgS = Fl_Shared_Image::get(tmp); s_bgS = Fl_Shared_Image::get(tmp);
s_bgS->scale(pw, 1,0,1); 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()) { if(tmp && tmp->w() && tmp->h()) {
s_bgN = Fl_Shared_Image::get(tmp); s_bgN = Fl_Shared_Image::get(tmp);
s_bgN->scale(pw, 1,0,1); s_bgN->scale(pw, 1,0,1);
@@ -112,12 +112,13 @@ static void draw_current_rect() {
} }
fl_color(FL_WHITE); fl_color(FL_WHITE);
fl_line_style(FL_SOLID); fl_line_style(FL_SOLID);
if (s == int(s)) fl_rect(px, py, pw, ph); if (unscaled) 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); else fl_graphics_driver->overlay_rect(px, py, pw, ph);
fl_color(FL_BLACK); fl_color(FL_BLACK);
fl_line_style(FL_DOT); fl_line_style(FL_DOT);
if (s == int(s)) fl_rect(px, py, pw, ph); if (unscaled) 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); else fl_graphics_driver->overlay_rect(px, py, pw, ph);
fl_line_style(FL_SOLID); fl_line_style(FL_SOLID);
#endif // USE_XOR #endif // USE_XOR
} }
@@ -130,8 +131,8 @@ static void erase_current_rect() {
draw_current_rect(); draw_current_rect();
# endif # endif
#else #else
float s = fl_graphics_driver->scale(); bool unscaled = fl_graphics_driver->overlay_rect_unscaled();
if (s == int(s)) { if (unscaled) {
if (bgN) fl_draw_image(bgN, bgx, bgy, bgw, 1); if (bgN) fl_draw_image(bgN, bgx, bgy, bgw, 1);
if (bgS) fl_draw_image(bgS, bgx, bgy+bgh-1, bgw, 1); if (bgS) fl_draw_image(bgS, bgx, bgy+bgh-1, bgw, 1);
if (bgW) fl_draw_image(bgW, bgx, bgy, 1, bgh); if (bgW) fl_draw_image(bgW, bgx, bgy, 1, bgh);
+51 -3
View File
@@ -3,7 +3,7 @@
// //
// X11 image reading routines for the Fast Light Tool Kit (FLTK). // 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 // 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 // the file "COPYING" which should have been included with this file. If this
@@ -17,6 +17,7 @@
// //
#include <FL/Fl.H> #include <FL/Fl.H>
#include <FL/platform.H>
#include <FL/Fl_Screen_Driver.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 and the value that is placed in the alpha channel. If 0, no alpha
channel is generated. channel is generated.
*/ */
uchar *fl_read_image(uchar *p, int X, int Y, int W, int H, int alpha) { 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 *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;
} }
// //