diff options
Diffstat (limited to 'src/drivers')
28 files changed, 1031 insertions, 446 deletions
diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H index 71a99b9b0..140e6acea 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H @@ -34,7 +34,7 @@ * This class is implemented only on the MSWindows platform. */ -class FL_EXPORT Fl_GDI_Graphics_Driver : public Fl_Graphics_Driver { +class FL_EXPORT Fl_GDI_Graphics_Driver : public Fl_Scalable_Graphics_Driver { private: BOOL alpha_blend_(int x, int y, int w, int h, HDC src_gc, int srcx, int srcy, int srcw, int srch); int depth; // to support translation @@ -59,55 +59,58 @@ public: // --- bitmap stuff Fl_Bitmask create_bitmask(int w, int h, const uchar *array); void delete_bitmask(Fl_Bitmask bm); - void draw(const char* str, int n, int x, int y); - void draw(int angle, const char *str, int n, int x, int y); - void rtl_draw(const char* str, int n, int x, int y); - void font(Fl_Font face, Fl_Fontsize size); - void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); - void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); - void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); + virtual void draw_unscaled(const char* str, int n, int x, int y); + virtual void draw_unscaled(int angle, const char *str, int n, int x, int y); + virtual void rtl_draw_unscaled(const char* str, int n, int x, int y); + virtual void font_unscaled(Fl_Font face, Fl_Fontsize size); + void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_unscaled(Fl_Bitmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_unscaled(Fl_RGB_Image *img, float s, int XP, int YP, int WP, int HP, int cx, int cy); int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); - void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); - void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); - void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); - void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); + virtual void draw_image_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + virtual void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + virtual void draw_image_mono_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + virtual void draw_image_mono_unscaled(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_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); - int height(); - int descent(); + virtual double width_unscaled(const char *str, int n); + virtual double width_unscaled(unsigned int c); + void text_extents_unscaled(const char*, int n, int& dx, int& dy, int& w, int& h); + int height_unscaled(); + int descent_unscaled(); + Fl_Fontsize size_unscaled(); #if ! defined(FL_DOXYGEN) void copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy); #endif - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); + virtual void copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen pixmap, float srcx, float srcy); void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h); Fl_Region XRectangleRegion(int x, int y, int w, int h); void XDestroyRegion(Fl_Region r); void translate_all(int x, int y); void untranslate_all(void); + static HRGN scale_region(HRGN r, float f, bool keep, bool inflate=false); + virtual void scale(float f); protected: - void transformed_vertex0(int x, int y); + void transformed_vertex0(float x, float y); void fixloop(); // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/gdi_rect.cxx - void point(int x, int y); - void rect(int x, int y, int w, int h); + virtual void point_unscaled(float x, float y); + void rect_unscaled(float x, float y, float w, float h); void focus_rect(int x, int y, int w, int h); - void rectf(int x, int y, int w, int h); - void line(int x, int y, int x1, int y1); - void line(int x, int y, int x1, int y1, int x2, int y2); - void xyline(int x, int y, int x1); - void xyline(int x, int y, int x1, int y2); - void xyline(int x, int y, int x1, int y2, int x3); - void yxline(int x, int y, int y1); - void yxline(int x, int y, int y1, int x2); - void yxline(int x, int y, int y1, int x2, int y3); - void loop(int x0, int y0, int x1, int y1, int x2, int y2); - void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); - void polygon(int x0, int y0, int x1, int y1, int x2, int y2); - void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + void rectf_unscaled(float x, float y, float w, float h); + virtual void line_unscaled(float x, float y, float x1, float y1); + virtual void line_unscaled(float x, float y, float x1, float y1, float x2, float y2); + virtual void xyline_unscaled(float x, float y, float x1); + virtual void xyline_unscaled(float x, float y, float x1, float y2); + virtual void xyline_unscaled(float x, float y, float x1, float y2, float x3); + virtual void yxline_unscaled(float x, float y, float y1); + virtual void yxline_unscaled(float x, float y, float y1, float x2); + virtual void yxline_unscaled(float x, float y, float y1, float x2, float y3); + virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2); + virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); + virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2); + virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); // --- clipping void push_clip(int x, int y, int w, int h); int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); @@ -115,24 +118,23 @@ protected: void push_no_clip(); void pop_clip(); void restore_clip(); + virtual Fl_Region scale_clip(float f); // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx void begin_complex_polygon(); - void transformed_vertex(double xf, double yf); - void vertex(double x, double y); void end_points(); void end_line(); void end_loop(); void end_polygon(); void end_complex_polygon(); void gap(); - void circle(double x, double y, double r); + virtual void ellipse_unscaled(double xt, double yt, double rx, double ry); // --- implementation is in src/fl_arc.cxx which includes src/cfg_gfx/xxx_arc.cxx if needed // using void Fl_Graphics_Driver::arc(double x, double y, double r, double start, double end); // --- implementation is in src/fl_arci.cxx which includes src/cfg_gfx/xxx_arci.cxx - void arc(int x, int y, int w, int h, double a1, double a2); - void pie(int x, int y, int w, int h, double a1, double a2); + virtual void arc_unscaled(float x, float y, float w, float h, double a1, double a2); + virtual void pie_unscaled(float x, float y, float w, float h, double a1, double a2); // --- implementation is in src/fl_line_style.cxx which includes src/cfg_gfx/xxx_line_style.cxx - void line_style(int style, int width=0, char* dashes=0); + virtual void line_style_unscaled(int style, float width, char* dashes); // --- implementation is in src/fl_color.cxx which includes src/cfg_gfx/xxx_color.cxx void color(Fl_Color c); Fl_Color color() { return color_; } @@ -162,8 +164,8 @@ private: transparent_f_type TransparentBlt(); public: virtual int has_feature(driver_feature mask) { return mask & (NATIVE | PRINTER); } - void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); - void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy); + void draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy); int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); }; diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx index 6649e3f3d..e211f1e3a 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx @@ -104,7 +104,7 @@ HDC fl_makeDC(HBITMAP bitmap) { return new_gc; } -void Fl_GDI_Graphics_Driver::copy_offscreen(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { +void Fl_GDI_Graphics_Driver::copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen bitmap, float srcx, float srcy) { HDC new_gc = CreateCompatibleDC(gc_); int save = SaveDC(new_gc); SelectObject(new_gc, bitmap); @@ -162,7 +162,7 @@ void Fl_GDI_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y, XDestroyRegion(R); } -void Fl_GDI_Graphics_Driver::transformed_vertex0(int x, int y) { +void Fl_GDI_Graphics_Driver::transformed_vertex0(float x, float y) { if (!n || x != p[n-1].x || y != p[n-1].y) { if (n >= p_size) { p_size = p ? 2*p_size : 16; @@ -228,6 +228,45 @@ void Fl_GDI_Graphics_Driver::set_spot(int font, int size, int X, int Y, int W, i } +void Fl_GDI_Graphics_Driver::scale(float f) { + if (f != scale_) { + size_ = 0; + scale_ = f; + //line_style(FL_SOLID); // scale also default line width + } +} + + +/* Rescale region r with factor f and returns the scaled region. + The input region is deleted if keep is false. + The input region is inflated by 1 unit before rescaling if inflate is true. + Region r is returned unchanged if r is null or f is 1. + */ +HRGN Fl_GDI_Graphics_Driver::scale_region(HRGN r, float f, bool keep, bool inflate) { + if (r && f != 1) { + DWORD size = GetRegionData(r, 0, NULL); + RGNDATA *pdata = (RGNDATA*)malloc(size); + GetRegionData(r, size, pdata); + if (!keep) DeleteObject(r); + if (inflate) { + RECT *rects = (RECT*)&(pdata->Buffer); + for (DWORD i = 0; i < pdata->rdh.nCount; i++) { + InflateRect(rects+i, 1, 1); + } + } + XFORM xform = {f, 0, 0, f, 0, 0}; + r = ExtCreateRegion(&xform, size, pdata); + free(pdata); + } + return r; +} + + +Fl_Region Fl_GDI_Graphics_Driver::scale_clip(float f) { + HRGN r = rstack[rstackptr]; + HRGN r2 = scale_region(r, f, true); + return (r == r2 ? NULL : (rstack[rstackptr] = r2, r)); +} // // End of "$Id$". diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx index 77753139f..53ea13dcd 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_arci.cxx @@ -35,7 +35,7 @@ #include <FL/math.h> #include <FL/x.H> -void Fl_GDI_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { +void Fl_GDI_Graphics_Driver::arc_unscaled(float x, float y, float w, float h, double a1, double a2) { if (w <= 0 || h <= 0) return; int xa = x+w/2+int(w*cos(a1/180.0*M_PI)); int ya = y+h/2-int(h*sin(a1/180.0*M_PI)); @@ -47,7 +47,7 @@ void Fl_GDI_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { } else Arc(gc_, x, y, x+w, y+h, xa, ya, xb, yb); } -void Fl_GDI_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { +void Fl_GDI_Graphics_Driver::pie_unscaled(float x, float y, float w, float h, double a1, double a2) { if (w <= 0 || h <= 0) return; if (a1 == a2) return; int xa = x+w/2+int(w*cos(a1/180.0*M_PI)); diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx index 6204929bd..5aea512f7 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx @@ -323,34 +323,40 @@ static void fl_font(Fl_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, driver->Fl_Graphics_Driver::font(0, 0); return; } - if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size() && angle == fl_angle_) return; + if (fnum == driver->Fl_Graphics_Driver::font() && size == ((Fl_GDI_Graphics_Driver*)driver)->size_unscaled() && angle == fl_angle_) return; fl_angle_ = angle; driver->Fl_Graphics_Driver::font(fnum, size); driver->font_descriptor( find(fnum, size, angle) ); } -void Fl_GDI_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { +void Fl_GDI_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) { fl_font(this, fnum, size, 0); } -int Fl_GDI_Graphics_Driver::height() { +int Fl_GDI_Graphics_Driver::height_unscaled() { Fl_Font_Descriptor *fl_fontsize = font_descriptor(); if (fl_fontsize) return (fl_fontsize->metr.tmAscent + fl_fontsize->metr.tmDescent); else return -1; } -int Fl_GDI_Graphics_Driver::descent() { +int Fl_GDI_Graphics_Driver::descent_unscaled() { Fl_Font_Descriptor *fl_fontsize = font_descriptor(); if (fl_fontsize) return fl_fontsize->metr.tmDescent; else return -1; } +Fl_Fontsize Fl_GDI_Graphics_Driver::size_unscaled() { + if (font_descriptor()) return size_; + return -1; +} + + // Unicode string buffer static unsigned short *wstr = NULL; static int wstr_len = 0; -double Fl_GDI_Graphics_Driver::width(const char* c, int n) { +double Fl_GDI_Graphics_Driver::width_unscaled(const char* c, int n) { int i = 0; if (!font_descriptor()) return -1.0; double w = 0.0; @@ -362,13 +368,13 @@ double Fl_GDI_Graphics_Driver::width(const char* c, int n) { // if (l < 1) l = 1; i += l; if (!fl_nonspacing(ucs)) { - w += width(ucs); + w += width_unscaled(ucs); } } return w; } -double Fl_GDI_Graphics_Driver::width(unsigned int c) { +double Fl_GDI_Graphics_Driver::width_unscaled(unsigned int c) { Fl_Font_Descriptor *fl_fontsize = font_descriptor(); unsigned int r; SIZE s; @@ -466,7 +472,7 @@ static void on_printer_extents_update(int &dx, int &dy, int &w, int &h, HDC gc) } // Function to determine the extent of the "inked" area of the glyphs in a string -void Fl_GDI_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { +void Fl_GDI_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &w, int &h) { Fl_Font_Descriptor *fl_fontsize = font_descriptor(); if (!fl_fontsize) { // no valid font, nothing to measure @@ -571,14 +577,14 @@ void Fl_GDI_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy exit_error: // some error here - just return fl_measure values w = (int)width(c, n); - h = height(); + h = height_unscaled(); dx = 0; - dy = descent() - h; + dy = descent_unscaled() - h; EXTENTS_UPDATE(dx, dy, w, h, gc_); return; } // fl_text_extents -void Fl_GDI_Graphics_Driver::draw(const char* str, int n, int x, int y) { +void Fl_GDI_Graphics_Driver::draw_unscaled(const char* str, int n, int x, int y) { COLORREF oldColor = SetTextColor(gc_, fl_RGB()); // avoid crash if no font has been set yet if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); @@ -593,8 +599,8 @@ void Fl_GDI_Graphics_Driver::draw(const char* str, int n, int x, int y) { SetTextColor(gc_, oldColor); // restore initial state } -void Fl_GDI_Graphics_Driver::draw(int angle, const char* str, int n, int x, int y) { - fl_font(this, Fl_Graphics_Driver::font(), size(), angle); +void Fl_GDI_Graphics_Driver::draw_unscaled(int angle, const char* str, int n, int x, int y) { + fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), angle); int wn = 0; // count of UTF16 cells to render full string COLORREF oldColor = SetTextColor(gc_, fl_RGB()); SelectObject(gc_, font_descriptor()->fid); @@ -606,10 +612,10 @@ void Fl_GDI_Graphics_Driver::draw(int angle, const char* str, int n, int x, int } TextOutW(gc_, x, y, (WCHAR*)wstr, wn); SetTextColor(gc_, oldColor); - fl_font(this, Fl_Graphics_Driver::font(), size(), 0); + fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), 0); } -void Fl_GDI_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { +void Fl_GDI_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) { int wn; wn = fl_utf8toUtf16(c, n, wstr, wstr_len); if(wn >= wstr_len) { @@ -634,7 +640,7 @@ void Fl_GDI_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { } #else UINT old_align = SetTextAlign(gc_, TA_RIGHT | TA_RTLREADING); - TextOutW(gc_, x, y - height() + descent(), (WCHAR*)wstr, wn); + TextOutW(gc_, x, y - height_unscaled() + descent_unscaled(), (WCHAR*)wstr, wn); SetTextAlign(gc_, old_align); #endif SetTextColor(gc_, oldColor); diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx index 7006bc429..4749ad14a 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx @@ -42,6 +42,7 @@ #include <FL/Fl_Printer.H> #include <FL/fl_draw.H> #include <FL/x.H> +#include <FL/Fl_Image_Surface.H> #define MAXBUFFER 0x40000 // 256k @@ -284,7 +285,7 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, } } -void Fl_GDI_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){ +void Fl_GDI_Graphics_Driver::draw_image_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { d ^= FL_IMAGE_WITH_ALPHA; innards(buf,x,y,w,h,d,l,fl_abs(d),0,0, gc_); @@ -293,7 +294,7 @@ void Fl_GDI_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, i } } -void Fl_GDI_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, +void Fl_GDI_Graphics_Driver::draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int x, int y, int w, int h,int d) { if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { d ^= FL_IMAGE_WITH_ALPHA; @@ -303,7 +304,7 @@ void Fl_GDI_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, } } -void Fl_GDI_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ +void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { d ^= FL_IMAGE_WITH_ALPHA; innards(buf,x,y,w,h,d,l,1,0,0, gc_); @@ -312,7 +313,7 @@ void Fl_GDI_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int } } -void Fl_GDI_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, +void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int x, int y, int w, int h,int d) { if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { d ^= FL_IMAGE_WITH_ALPHA; @@ -399,11 +400,15 @@ void Fl_GDI_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) { DeleteObject((HGDIOBJ)bm); } -void Fl_GDI_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { +void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy) { int X, Y, W, H; if (Fl_Graphics_Driver::prepare(bm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { return; } + X = X*s; + Y = Y*s; + cache_size(bm, W, H); + cx *= s; cy *= s; HDC tempdc = CreateCompatibleDC(gc_); int save = SaveDC(tempdc); @@ -423,7 +428,7 @@ Fl_GDI_Printer_Graphics_Driver::transparent_f_type Fl_GDI_Printer_Graphics_Drive return fpter; } -void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { +void Fl_GDI_Printer_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy) { int X, Y, W, H; transparent_f_type fl_TransparentBlt = TransparentBlt(); if (!fl_TransparentBlt) { @@ -467,34 +472,33 @@ 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()); + Fl_Image_Surface *surface = new Fl_Image_Surface(img->w(), img->h()); + Fl_Surface_Device::push_current(surface); 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); } } + Fl_Surface_Device::pop_current(); + Fl_Offscreen offs = surface->get_offscreen_before_delete(); + delete surface; 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) { - Fl_Graphics_Driver::draw_empty(img, XP, YP); - return; - } - if (start_image(img, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; +void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, int Y, int W, int H, int cx, int cy) { + X = X*s; + Y = Y*s; + cache_size(img, W, H); + cx *= s; cy *= s; + if (!*Fl_Graphics_Driver::id(img)) { + *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)build_id(img, (void**)(Fl_Graphics_Driver::mask(img))); + *cache_scale(img) = 1; } - if (!*Fl_Graphics_Driver::id(img)) *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)build_id(img, (void**)(Fl_Graphics_Driver::mask(img))); + Fl_Region r2 = scale_clip(s); if (*Fl_Graphics_Driver::mask(img)) { HDC new_gc = CreateCompatibleDC(gc_); int save = SaveDC(new_gc); @@ -509,6 +513,7 @@ void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int } else { copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(img), cx, cy); } + unscale_clip(r2); } int Fl_GDI_Printer_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) { @@ -525,21 +530,26 @@ int Fl_GDI_Printer_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, i return 1; } + int Fl_GDI_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) { Fl_RGB_Image *rgb = img->as_rgb_image(); if (!rgb || !rgb->array) return 0; // for bitmaps and pixmaps if ((rgb->d() % 2) == 0 && !can_do_alpha_blending()) return 0; - if (!*Fl_Graphics_Driver::id(rgb)) *Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)build_id(rgb, + if (!*Fl_Graphics_Driver::id(rgb)) { + *Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)build_id(rgb, (void**)(Fl_Graphics_Driver::mask(rgb))); + *cache_scale(rgb) = 1; + } + cache_size(img, WP, HP); HDC new_gc = CreateCompatibleDC(gc_); int save = SaveDC(new_gc); SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb)); if ( (rgb->d() % 2) == 0 ) { - alpha_blend_(XP, YP, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h()); + alpha_blend_(XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h()); } else { SetStretchBltMode(gc_, HALFTONE); - StretchBlt(gc_, XP, YP, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h(), SRCCOPY); + StretchBlt(gc_, XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h(), SRCCOPY); } RestoreDC(new_gc, save); DeleteDC(new_gc); @@ -587,13 +597,17 @@ static Fl_Bitmask fl_create_bitmap(int w, int h, const uchar *data) { return bm; } -fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) { +fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Bitmap *bm, int w, int h, const uchar *array) { + *cache_scale(bm) = Fl_Scalable_Graphics_Driver::scale(); return (fl_uintptr_t)fl_create_bitmap(w, h, array); } -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 (Fl_Graphics_Driver::prepare(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; +void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int X, int Y, int W, int H, int cx, int cy) { + X = X*s; + Y = Y*s; + cache_size(pxm, W, H); + cx *= s; cy *= s; + Fl_Region r2 = scale_clip(s); if (*Fl_Graphics_Driver::mask(pxm)) { HDC new_gc = CreateCompatibleDC(gc_); int save = SaveDC(new_gc); @@ -606,10 +620,11 @@ void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP } else { copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(pxm), cx, cy); } + unscale_clip(r2); } -void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) { +void Fl_GDI_Printer_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy) { int X, Y, W, H; if (Fl_Graphics_Driver::prepare(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) return; transparent_f_type fl_TransparentBlt = TransparentBlt(); @@ -642,6 +657,7 @@ fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const c delete[] bitmap; } fl_end_offscreen(); + *cache_scale(img) = Fl_Scalable_Graphics_Driver::scale(); return (fl_uintptr_t)id; } diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx index 26dd842d9..35281265c 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx @@ -35,7 +35,7 @@ #include "Fl_GDI_Graphics_Driver.H" -void Fl_GDI_Graphics_Driver::line_style(int style, int width, char* dashes) { +void Fl_GDI_Graphics_Driver::line_style_unscaled(int style, float width, char* dashes) { // According to Bill, the "default" cap and join should be the // "fastest" mode supported for the platform. I don't know why diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx index 3ef206488..86698e386 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx @@ -35,11 +35,11 @@ // --- line and polygon drawing with integer coordinates -void Fl_GDI_Graphics_Driver::point(int x, int y) { +void Fl_GDI_Graphics_Driver::point_unscaled(float x, float y) { SetPixel(gc_, x, y, fl_RGB()); } -void Fl_GDI_Graphics_Driver::rect(int x, int y, int w, int h) { +void Fl_GDI_Graphics_Driver::rect_unscaled(float x, float y, float w, float h) { if (w<=0 || h<=0) return; MoveToEx(gc_, x, y, 0L); LineTo(gc_, x+w-1, y); @@ -59,7 +59,7 @@ void Fl_GDI_Graphics_Driver::focus_rect(int x, int y, int w, int h) { for (yy = h; yy > 0; yy--, i++) if (i & 1) point(x, y + yy); } -void Fl_GDI_Graphics_Driver::rectf(int x, int y, int w, int h) { +void Fl_GDI_Graphics_Driver::rectf_unscaled(float x, float y, float w, float h) { if (w<=0 || h<=0) return; RECT rect; rect.left = x; rect.top = y; @@ -67,24 +67,24 @@ void Fl_GDI_Graphics_Driver::rectf(int x, int y, int w, int h) { FillRect(gc_, &rect, fl_brush()); } -void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1) { +void Fl_GDI_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1) { MoveToEx(gc_, x, y, 0L); LineTo(gc_, x1, y1); SetPixel(gc_, x1, y1, fl_RGB()); } -void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { +void Fl_GDI_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1, float x2, float y2) { MoveToEx(gc_, x, y, 0L); LineTo(gc_, x1, y1); LineTo(gc_, x2, y2); SetPixel(gc_, x2, y2, fl_RGB()); } -void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1) { +void Fl_GDI_Graphics_Driver::xyline_unscaled(float x, float y, float x1) { MoveToEx(gc_, x, y, 0L); LineTo(gc_, x1+1, y); } -void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2) { +void Fl_GDI_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2) { if (y2 < y) y2--; else y2++; MoveToEx(gc_, x, y, 0L); @@ -92,7 +92,7 @@ void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2) { LineTo(gc_, x1, y2); } -void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { +void Fl_GDI_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2, float x3) { if(x3 < x1) x3--; else x3++; MoveToEx(gc_, x, y, 0L); @@ -101,13 +101,13 @@ void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { LineTo(gc_, x3, y2); } -void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1) { +void Fl_GDI_Graphics_Driver::yxline_unscaled(float x, float y, float y1) { if (y1 < y) y1--; else y1++; MoveToEx(gc_, x, y, 0L); LineTo(gc_, x, y1); } -void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2) { +void Fl_GDI_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2) { if (x2 > x) x2++; else x2--; MoveToEx(gc_, x, y, 0L); @@ -115,7 +115,7 @@ void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2) { LineTo(gc_, x2, y1); } -void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { +void Fl_GDI_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2, float y3) { if(y3<y1) y3--; else y3++; MoveToEx(gc_, x, y, 0L); @@ -124,14 +124,14 @@ void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { LineTo(gc_, x2, y3); } -void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { +void Fl_GDI_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2) { MoveToEx(gc_, x, y, 0L); LineTo(gc_, x1, y1); LineTo(gc_, x2, y2); LineTo(gc_, x, y); } -void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { +void Fl_GDI_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) { MoveToEx(gc_, x, y, 0L); LineTo(gc_, x1, y1); LineTo(gc_, x2, y2); @@ -139,7 +139,7 @@ void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, LineTo(gc_, x, y); } -void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { +void Fl_GDI_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2) { POINT p[3]; p[0].x = x; p[0].y = y; p[1].x = x1; p[1].y = y1; @@ -148,7 +148,7 @@ void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y Polygon(gc_, p, 3); } -void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { +void Fl_GDI_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) { POINT p[4]; p[0].x = x; p[0].y = y; p[1].x = x1; p[1].y = y1; @@ -244,8 +244,10 @@ void Fl_GDI_Graphics_Driver::pop_clip() { void Fl_GDI_Graphics_Driver::restore_clip() { fl_clip_state_number++; if (gc_) { - Fl_Region r = rstack[rstackptr]; - SelectClipRgn(gc_, r); // if r is NULL, clip is automatically cleared + HRGN r = NULL; + if (rstack[rstackptr]) r = scale_clip(scale_); + SelectClipRgn(gc_, rstack[rstackptr]); // if region is NULL, clip is automatically cleared + if (r) unscale_clip(r); } } diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx index e4ce856b1..ee817bf4f 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx @@ -32,14 +32,6 @@ #include <FL/math.h> -void Fl_GDI_Graphics_Driver::transformed_vertex(double xf, double yf) { - transformed_vertex0(int(rint(xf)), int(rint(yf))); -} - -void Fl_GDI_Graphics_Driver::vertex(double x,double y) { - transformed_vertex0(int(x*m.a + y*m.c + m.x), int(x*m.b + y*m.d + m.y)); -} - void Fl_GDI_Graphics_Driver::end_points() { for (int i=0; i<n; i++) SetPixel(gc_, p[i].x, p[i].y, fl_RGB()); } @@ -54,7 +46,7 @@ void Fl_GDI_Graphics_Driver::end_line() { void Fl_GDI_Graphics_Driver::end_loop() { fixloop(); - if (n>2) transformed_vertex((int)p[0].x, (int)p[0].y); + if (n>2) transformed_vertex0(p[0].x, p[0].y); end_line(); } @@ -79,7 +71,7 @@ void Fl_GDI_Graphics_Driver::begin_complex_polygon() { void Fl_GDI_Graphics_Driver::gap() { while (n>gap_+2 && p[n-1].x == p[gap_].x && p[n-1].y == p[gap_].y) n--; if (n > gap_+2) { - transformed_vertex((int)p[gap_].x, (int)p[gap_].y); + transformed_vertex0(p[gap_].x, p[gap_].y); counts[numcount++] = n-gap_; gap_ = n; } else { @@ -99,15 +91,7 @@ void Fl_GDI_Graphics_Driver::end_complex_polygon() { } } -// shortcut the closed circles so they use XDrawArc: -// warning: these do not draw rotated ellipses correctly! -// See fl_arc.c for portable version. - -void Fl_GDI_Graphics_Driver::circle(double x, double y,double r) { - double xt = transform_x(x,y); - double yt = transform_y(x,y); - double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); - double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); +void Fl_GDI_Graphics_Driver::ellipse_unscaled(double xt, double yt, double rx, double ry) { int llx = (int)rint(xt-rx); int w = (int)rint(xt+rx)-llx; int lly = (int)rint(yt-ry); diff --git a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx index 5e0b636f5..e55e69583 100644 --- a/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx +++ b/src/drivers/GDI/Fl_GDI_Image_Surface_Driver.cxx @@ -27,7 +27,6 @@ #include <windows.h> class Fl_GDI_Image_Surface_Driver : public Fl_Image_Surface_Driver { - friend class Fl_Image_Surface; virtual void end_current_(Fl_Surface_Device*); public: Fl_Surface_Device *previous; @@ -51,8 +50,14 @@ Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, i Fl_GDI_Image_Surface_Driver::Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, 0) { previous = 0; + float d = fl_graphics_driver->scale(); + if (!off && d != 1 && high_res) { + w = int(w*d); + h = int(h*d); + } offscreen = off ? off : CreateCompatibleBitmap( (fl_graphics_driver->gc() ? (HDC)fl_graphics_driver->gc() : fl_GetDC(0) ) , w, h); driver(new Fl_GDI_Graphics_Driver); + if (d != 1 && high_res) driver()->scale(d); _sgc = NULL; } diff --git a/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx b/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx index 21bcf65df..c65c6a3a1 100644 --- a/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx +++ b/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx @@ -3,7 +3,7 @@ // // implementation of class Fl_Gl_Device_Plugin for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2014 by Bill Spitzak and others. +// Copyright 2010-2017 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 @@ -94,6 +94,8 @@ Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window* glw, # pragma message "FL_PORTING: check whether the default Fl_OpenGL_Display_Device::capture_gl_rectangle() works for your platform" #endif +#include <FL/Fl_Screen_Driver.H> +#include <FL/Fl_Window_Driver.H> Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window *glw, int x, int y, int w, int h) /* captures a rectangle of a Fl_Gl_Window window, and returns it as a RGB image */ @@ -106,6 +108,12 @@ Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window *glw, glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + // + int ns = glw->driver()->screen_num(); + float s = Fl::screen_driver()->scale(ns); + if (s != 1) { + x *= s; y *= s; w *= s; h *= s; + } // Read a block of pixels from the frame buffer int mByteWidth = w * 3; mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H index 5c016ce73..ff2688bcf 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H @@ -78,6 +78,13 @@ public: virtual void disable_im(); virtual void open_display(); virtual void offscreen_size(Fl_Offscreen off, int &width, int &height); + + 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 float desktop_scale_factor(); +private: + float scale_; }; diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 219c1d1d6..e9ca9d2fb 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -617,6 +617,9 @@ Fl_WinAPI_Screen_Driver::read_win_rectangle(uchar *p, // I - Pixel buffer or NU /** Returns the current desktop scaling factor (1.75 for example) */ float Fl_WinAPI_Screen_Driver::desktop_scaling_factor() { +#ifdef FLTK_HIDPI_SUPPORT + return 1;// this becomes useless if FLTK app are made DPI-aware by calling SetProcessDpiAwareness() +#else // Compute the global desktop scaling factor: 1, 1.25, 1.5, 1.75, etc... // This factor can be set in Windows 10 by // "Change the size of text, apps and other items" in display settings. @@ -636,6 +639,7 @@ float Fl_WinAPI_Screen_Driver::desktop_scaling_factor() { float scaling = dhr/float(hr); scaling = int(scaling * 100 + 0.5)/100.; // round to 2 digits after decimal point return scaling; +#endif // FLTK_HIDPI_SUPPORT } void Fl_WinAPI_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height) diff --git a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx index eb8e13b33..1d496edff 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx @@ -261,10 +261,11 @@ static HRGN bitmap2region(Fl_Image* image) { void Fl_WinAPI_Window_Driver::draw_begin() { if (shape_data_) { - if ((shape_data_->lw_ != w() || shape_data_->lh_ != h()) && shape_data_->shape_) { + float s = Fl::screen_driver()->scale(screen_num()); + if ((shape_data_->lw_ != s*w() || shape_data_->lh_ != s*h()) && shape_data_->shape_) { // size of window has changed since last time - shape_data_->lw_ = w(); - shape_data_->lh_ = h(); + shape_data_->lw_ = s*w(); + shape_data_->lh_ = s*h(); Fl_Image* temp = shape_data_->shape_->copy(shape_data_->lw_, shape_data_->lh_); HRGN region = bitmap2region(temp); SetWindowRgn(fl_xid(pWindow), region, TRUE); // the system deletes the region when it's no longer needed @@ -385,6 +386,7 @@ void Fl_WinAPI_Window_Driver::make_current() { #endif // USE_COLORMAP fl_graphics_driver->clip_region(0); +fl_graphics_driver->scale(Fl::screen_driver()->scale(0)); } void Fl_WinAPI_Window_Driver::label(const char *name,const char *iname) { diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.H b/src/drivers/X11/Fl_X11_Screen_Driver.H index 2be26a1ee..8ccf056da 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-2016 by Bill Spitzak and others. +// Copyright 2010-2017 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 @@ -39,13 +39,27 @@ protected: short y_org; short width; short height; +#if USE_XFT + float scale; +#endif } FLScreenInfo; FLScreenInfo screens[MAX_SCREENS]; float dpi[MAX_SCREENS][2]; int poll_or_select(); int poll_or_select_with_delay(double time_to_wait); + int get_mouse_unscaled(int &xx, int &yy); public: +#if USE_XFT // scaling does not work without Xft + virtual APP_SCALING_CAPABILITY rescalable() { return PER_SCREEN_APP_SCALING; } + virtual float scale(int n) {return screens[n].scale;} + virtual void scale(int n, float f) { screens[n].scale = f;} + virtual float desktop_scale_factor(); + int screen_num_unscaled(int x, int y); + int screen_num_unscaled(int x, int y, int w, int h); + virtual void screen_xywh(int &X, int &Y, int &W, int &H); +#endif + static int ewmh_supported(); static void copy_image(const unsigned char* data, int W, int H, int destination); // --- display management diff --git a/src/drivers/X11/Fl_X11_Screen_Driver.cxx b/src/drivers/X11/Fl_X11_Screen_Driver.cxx index 7095ea948..490189673 100644 --- a/src/drivers/X11/Fl_X11_Screen_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Screen_Driver.cxx @@ -3,7 +3,7 @@ // // Definition of X11 Screen interface // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -20,9 +20,14 @@ #include "../../config_lib.h" #include "Fl_X11_Screen_Driver.H" #include "../Xlib/Fl_Font.H" +#include "Fl_X11_Window_Driver.H" +#include "../Xlib/Fl_Xlib_Graphics_Driver.H" #include <FL/Fl.H> #include <FL/x.H> #include <FL/fl_ask.H> +#include <FL/Fl_Box.H> +#include <FL/Fl_Image_Surface.H> +#include <FL/Fl_Tooltip.H> #include <sys/time.h> @@ -229,10 +234,15 @@ void Fl_X11_Screen_Driver::init_workarea() } else { - fl_workarea_xywh[0] = (int)xywh[0]; - fl_workarea_xywh[1] = (int)xywh[1]; - fl_workarea_xywh[2] = (int)xywh[2]; - fl_workarea_xywh[3] = (int)xywh[3]; +#if USE_XFT + float s = screens[0].scale; +#else + float s = 1; +#endif + fl_workarea_xywh[0] = xywh[0] / s; + fl_workarea_xywh[1] = xywh[1] / s; + fl_workarea_xywh[2] = xywh[2] / s; + fl_workarea_xywh[3] = xywh[3] / s; } if ( xywh ) { XFree(xywh); xywh = 0; } } @@ -316,7 +326,9 @@ void Fl_X11_Screen_Driver::init() { screens[i].y_org = xsi[i].y_org; screens[i].width = xsi[i].width; screens[i].height = xsi[i].height; - +#if USE_XFT + screens[i].scale = 1; +#endif if (dpi_by_randr) { dpi[i][0] = dpih; dpi[i][1] = dpiv; @@ -341,7 +353,9 @@ void Fl_X11_Screen_Driver::init() { screens[i].y_org = 0; screens[i].width = DisplayWidth(fl_display, i); screens[i].height = DisplayHeight(fl_display, i); - +#if USE_XFT + screens[i].scale = 1; +#endif if (dpi_by_randr) { dpi[i][0] = dpih; dpi[i][1] = dpiv; @@ -353,6 +367,17 @@ void Fl_X11_Screen_Driver::init() { } } } +/*#if __APPLE_CC__ && USE_XFT // TMP simulate 2 screens under XQuartz + if (strstr(getenv("DISPLAY"), "xquartz")) { + num_screens = 2; + screens[1].x_org = screens[0].width/2;; + screens[1].y_org = screens[0].y_org; + screens[1].width = screens[0].width = screens[0].width/2; + screens[1].height = screens[0].height; + screens[1].scale = screens[0].scale = 1; + } +#endif*/ + init_workarea(); } @@ -379,10 +404,15 @@ void Fl_X11_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) n = 0; if (num_screens > 0) { - X = screens[n].x_org; - Y = screens[n].y_org; - W = screens[n].width; - H = screens[n].height; +#if USE_XFT + float s = screens[n].scale; +#else + float s = 1; +#endif + X = screens[n].x_org / s; + Y = screens[n].y_org / s; + W = screens[n].width / s; + H = screens[n].height / s; } } @@ -765,26 +795,29 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, i image = 0; # endif // __sgi + float s = Fl_Surface_Device::surface()->driver()->scale(); + if (!image) { // fetch absolute coordinates int dx, dy, sx, sy, sw, sh; Window child_win; Fl_Window *win; - if (allow_outside) win = (Fl_Window*)1; + if (allow_outside) win = Fl_Window::current(); else win = fl_find(fl_window); if (win) { XTranslateCoordinates(fl_display, fl_window, - RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win); + RootWindow(fl_display, fl_screen), X*s, Y*s, &dx, &dy, &child_win); + dx /= s; dy /= s; // screen dimensions - Fl::screen_xywh(sx, sy, sw, sh, fl_screen); + Fl::screen_xywh(sx, sy, sw, sh, win->driver()->screen_num()); } if (!win || (dx >= sx && dy >= sy && dx + w <= sx+sw && dy + h <= sy+sh)) { // the image is fully contained, we can use the traditional method // however, if the window is obscured etc. the function will still fail. Make sure we // catch the error and continue, otherwise an exception will be thrown. XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); - image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap); + image = XGetImage(fl_display, fl_window, int(X*s), int(Y*s), w*s < 1 ? 1 : int(w*s), h*s < 1 ? 1 : int(h*s), AllPlanes, ZPixmap); XSetErrorHandler(old_handler); } else { // image is crossing borders, determine visible region @@ -795,17 +828,17 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, i // allocate the image int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8; - char* buf = (char*)malloc(bpp / 8 * w * h); + char* buf = (char*)malloc(bpp / 8 * int(w*s) * int(h*s)); image = XCreateImage(fl_display, fl_visual->visual, - fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0); + fl_visual->depth, ZPixmap, 0, buf, w*s, h*s, bpp, 0); if (!image) { if (buf) free(buf); return 0; } XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); - XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy, - nw, nh, AllPlanes, ZPixmap, image, noffx, noffy); + XImage *subimg = XGetSubImage(fl_display, fl_window, (X + noffx)*s, (Y + noffy)*s, + nw*s, nh*s, AllPlanes, ZPixmap, image, noffx*s, noffy*s); XSetErrorHandler(old_handler); if (!subimg) { XDestroyImage(image); @@ -815,6 +848,10 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, i } if (!image) return 0; + if (s != 1) { + w = w*s < 1 ? 1 : int(w*s); + h = h*s < 1 ? 1 : int(h*s); + } #ifdef DEBUG printf("width = %d\n", image->width); @@ -1154,6 +1191,244 @@ void Fl_X11_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &hei height = (int)h; } +#if USE_XFT +int Fl_X11_Screen_Driver::screen_num_unscaled(int x, int y) +{ + int screen = 0; + if (num_screens < 0) init(); + + for (int i = 0; i < num_screens; i ++) { + int sx = screens[i].x_org, sy = screens[i].y_org, sw = screens[i].width, sh = screens[i].height; + if ((x >= sx) && (x < (sx+sw)) && (y >= sy) && (y < (sy+sh))) { + screen = i; + break; + } + } + return screen; +} + +int Fl_X11_Screen_Driver::screen_num_unscaled(int x, int y, int w, int h) +{ + int best_screen = 0; + float best_intersection = 0.; + if (num_screens < 0) init(); + for (int i = 0; i < num_screens; i++) { + float sintersection = fl_intersection(x, y, w, h, screens[i].x_org, screens[i].y_org, + screens[i].width, screens[i].height); + if (sintersection > best_intersection) { + best_screen = i; + best_intersection = sintersection; + } + } + return best_screen; +} +#endif + +#if USE_XFT +void Fl_X11_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H) +{ + int xx, yy; + int ns = get_mouse_unscaled(xx,yy); + float s = screens[ns].scale; + X = screens[ns].x_org / s; + Y = screens[ns].y_org / s; + W = screens[ns].width / s; + H = screens[ns].height / s; +} + + +#if HAVE_DLSYM && HAVE_DLFCN_H + +// returns true when schema is among the list of available schemas +static bool is_schema_valid(const char *schema, const char **known) { + int i = 0; + while (known[i]) { + if (strcmp(known[i++], schema) == 0) return true; + } + return false; +} + + +/* + returns true under Ubuntu or Debian or FreeBSD and when the gnome scaling value has been found + + Ubuntu: + Change the gnome scaling factor with: + System Settings ==> Displays ==> Scale for menu and title bars + Read the current gnome scaling factor with: + gsettings get com.ubuntu.user-interface scale-factor + Example value: {'VGA-0': 10} + Its type is "a{si}". This value should be divided by 8 to get the correct scaling factor. + + Debian or FreeBSD : + Change the gnome scaling factor with: + Tweak tools ==> Windows ==> Window scaling + Read the current gnome scaling factor with: + gsettings get org.gnome.settings-daemon.plugins.xsettings overrides + Example value: {'Gdk/WindowScalingFactor': <2>} + Its type is "a{sv}" and v itself is of type i + + It's also possible to use 'Tweak tools' under Ubuntu. With the standard Ubuntu desktop, + the modified value goes to "org.gnome.settings-daemon.plugins.xsettings" as above. + + With Gnome session flashback under Ubuntu 'Tweak tools' puts the scaling value (1 or 2) + in "org.gnome.desktop.interface scaling-factor". + Read the current gnome scaling factor with: + gsettings get org.gnome.desktop.interface scaling-factor + Its type is "u" + + Thus, under Ubuntu, we read the 3 possible factor values and + return the first value different from 1 to get the scaling factor. + + ================================================================================================= + Ubuntu | default ubuntu desktop | System Settings => Displays => Scale for menu and title bars + com.ubuntu.user-interface scale-factor + ----------------------- + Tweak tools => Windows => Window scaling + org.gnome.settings-daemon.plugins.xsettings overrides + ----------------------- + Gnome session flashback | System Settings => Displays => Scale for menu and title bars + no effect + ----------------------- + Tweak tools => Windows => Window scaling + org.gnome.desktop.interface scaling-factor + ================================================================================================= + Debian or FreeBSD | gnome | Tweak tools => Windows => Window scaling + org.gnome.settings-daemon.plugins.xsettings overrides + ================================================================================================= + */ +static bool gnome_scale_factor(float& factor) { + // define types needed for dynamic lib functions + typedef const char** (*g_settings_list_schemas_ftype)(void); + typedef void* (*g_settings_new_ftype)(const char *); + typedef void* (*g_settings_get_value_ftype)(void *settings, const char *key); + typedef void (*g_variant_get_ftype)(void *value, const char *format_string, ...); + typedef bool (*g_variant_iter_loop_ftype)(void *iter, const char *format_string, ...); + typedef void (*pter_ftype)(void*); + //typedef void* (*g_variant_get_type_ftype)(void *variant); + + // open dynamic libs + void *glib = dlopen("libglib-2.0.so", RTLD_LAZY); + void *gio = dlopen("libgio-2.0.so", RTLD_LAZY); + void *gobj = dlopen("libgobject-2.0.so", RTLD_LAZY); + //fprintf(stderr,"glib=%p gio=%p gobj=%p\n",glib,gio,gobj); + if (!glib || !gio || !gobj) return false; + + bool ubuntu = false; + // determine whether we run Ubuntu + char line[400] = ""; + FILE *in = fopen("/proc/version", "r"); + if (in) { + fgets(line, sizeof(line), in); + fclose(in); + if (strstr(line, "Ubuntu")) ubuntu = true; + } + + // define pters to used functions + g_settings_list_schemas_ftype g_settings_list_schemas_f = (g_settings_list_schemas_ftype)dlsym(gio, "g_settings_list_schemas"); // 2.26 + g_settings_new_ftype g_settings_new_f = (g_settings_new_ftype)dlsym(gio, "g_settings_new"); // 2.26 + g_settings_get_value_ftype g_settings_get_value_f = + (g_settings_get_value_ftype)dlsym(gio, "g_settings_get_value"); // 2.26 + if (!g_settings_list_schemas_f || !g_settings_new_f || !g_settings_get_value_f) return false; + g_variant_get_ftype g_variant_get_f = (g_variant_get_ftype)dlsym(glib, "g_variant_get"); //2.24 + g_variant_iter_loop_ftype g_variant_iter_loop_f = (g_variant_iter_loop_ftype)dlsym(glib, "g_variant_iter_loop"); // 2.24 + pter_ftype g_variant_iter_free_f = (pter_ftype)dlsym(glib, "g_variant_iter_free"); // 2.24 + pter_ftype g_object_unref_f = (pter_ftype)dlsym(gobj, "g_object_unref"); + pter_ftype g_variant_unref_f = (pter_ftype)dlsym(glib, "g_variant_unref"); // 2.24 + //g_variant_get_type_ftype g_variant_get_type_f = (g_variant_get_type_ftype)dlsym(glib, "g_variant_get_type"); // 2.24 + + // call dynamic lib functions + const char **known = g_settings_list_schemas_f(); // list of available GSettings schemas + const char *schema; + float ubuntu_f = 1, ubuntu_desktop_f = 1, gnome_f = 1; + bool found = false; + + if (ubuntu) { + schema = "com.ubuntu.user-interface"; + if (is_schema_valid(schema, known)) { + found = true; + void *gset = g_settings_new_f(schema); + void *gvar = g_settings_get_value_f(gset, "scale-factor"); + void *iter; + char str[10], *str2; int v=8, v2; + g_variant_get_f(gvar, "a{si}", &iter); + while (g_variant_iter_loop_f(iter, "{si}", &str2, &v2)) { // read the last couple of values + strcpy(str, str2); v = v2; + } + ubuntu_f = v/8.; + printf("com.ubuntu.user-interface scale-factor name=%s value=%d factor=%g\n", str, v, ubuntu_f); + g_variant_iter_free_f(iter); + g_variant_unref_f(gvar); + g_object_unref_f(gset); + if (ubuntu_f != 1) { + factor = ubuntu_f; + return true; + } + } + schema = "org.gnome.desktop.interface"; + if (is_schema_valid(schema, known)) { + found = true; + void *gset = g_settings_new_f(schema); + void *gvar = g_settings_get_value_f(gset, "scaling-factor"); + unsigned v; + g_variant_get_f(gvar, "u", &v); + ubuntu_desktop_f = v; + printf("org.gnome.desktop.interface scaling-factor value=%u factor=%g\n", v, ubuntu_desktop_f); + g_variant_unref_f(gvar); + g_object_unref_f(gset); + if (ubuntu_desktop_f != 1) { + factor = ubuntu_desktop_f; + return true; + } + } + } + schema = "org.gnome.settings-daemon.plugins.xsettings"; + if (is_schema_valid(schema, known)) { + void *gset = g_settings_new_f(schema); + void *gvar = g_settings_get_value_f(gset, "overrides"); + void *iter; + char *str; int v; + //str = (char*)g_variant_get_type_f(gvar); // -> "a{sv}" + g_variant_get_f(gvar, "a{sv}", &iter); + g_variant_unref_f(gvar); + gvar = NULL; + while (g_variant_iter_loop_f(iter, "{sv}", &str, &gvar)) { + if (strstr(str, "WindowScalingFactor") == NULL) continue; + found = true; + //str = (char*)g_variant_get_type_f(gvar); // -> "i" + g_variant_get_f(gvar, "i", &v); + gnome_f = v; + printf("org.gnome.settings-daemon.plugins.xsettings overrides name=%s value=%d factor=%g\n", str, v, gnome_f); + free(str); + break; + } + g_variant_iter_free_f(iter); + if (gvar) g_variant_unref_f(gvar); + g_object_unref_f(gset); + } + if (!found) return false; + //factor = ubuntu_f * ubuntu_desktop_f * gnome_f; + factor = gnome_f; + return true; +} +#endif // HAVE_DLSYM && HAVE_DLFCN_H + + +// return the desktop's default scaling value +float Fl_X11_Screen_Driver::desktop_scale_factor() +{ + float factor = 1; +#if HAVE_DLSYM && HAVE_DLFCN_H + gnome_scale_factor(factor); +#endif + return factor; +} + + + + +#endif // USE_XFT + // // End of "$Id$". // diff --git a/src/drivers/X11/Fl_X11_Window_Driver.H b/src/drivers/X11/Fl_X11_Window_Driver.H index 4de4e3680..0893d28c0 100644 --- a/src/drivers/X11/Fl_X11_Window_Driver.H +++ b/src/drivers/X11/Fl_X11_Window_Driver.H @@ -4,7 +4,7 @@ // Definition of X11 window driver // for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2016 by Bill Spitzak and others. +// Copyright 2010-2017 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 @@ -27,6 +27,7 @@ #include <FL/Fl_Window_Driver.H> #include <config.h> // for USE_XDBE +#include <FL/x.H> // for Cursor class Fl_Bitmap; /* @@ -56,6 +57,8 @@ struct Fl_Window_Driver::shape_data_type { class FL_EXPORT Fl_X11_Window_Driver : public Fl_Window_Driver { friend class Fl_X; + friend class Fl_X11_Screen_Driver; + friend int fl_handle(const XEvent&); private: struct icon_data { @@ -63,6 +66,17 @@ private: Fl_RGB_Image **icons; int count; } *icon_; + Cursor current_cursor_; +#if USE_XFT + // --- support for screen-specific scaling factors + struct type_for_resize_window_between_screens { + int screen; + bool busy; + }; + static type_for_resize_window_between_screens data_for_resize_window_between_screens_; + int screen_num_; + void screen_num(int n) { screen_num_ = n; } +#endif // USE_XFT void decorated_win_size(int &w, int &h); void combine_mask(); void shape_bitmap_(Fl_Image* b); @@ -79,7 +93,11 @@ public: Fl_X11_Window_Driver(Fl_Window*); virtual ~Fl_X11_Window_Driver(); static inline Fl_X11_Window_Driver* driver(Fl_Window *w) {return (Fl_X11_Window_Driver*)w->driver();} - +#if USE_XFT + virtual int screen_num(); + static void resize_after_screen_change(void *data); +#endif // USE_XFT + // --- window data virtual int decorated_w(); virtual int decorated_h(); diff --git a/src/drivers/X11/Fl_X11_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Window_Driver.cxx index f10ed307a..a8952eed3 100644 --- a/src/drivers/X11/Fl_X11_Window_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Window_Driver.cxx @@ -3,7 +3,7 @@ // // Definition of X11 window driver. // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -112,11 +112,11 @@ void Fl_X11_Window_Driver::destroy_double_buffer() { #if USE_XDBE if (can_xdbe()) { XdbeDeallocateBackBufferName(fl_display, other_xid); - other_xid = 0; } else #endif // USE_XDBE - Fl_Window_Driver::destroy_double_buffer(); + fl_delete_offscreen(other_xid); + other_xid = 0; } Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) @@ -130,6 +130,10 @@ Fl_X11_Window_Driver::Fl_X11_Window_Driver(Fl_Window *win) { icon_ = new icon_data; memset(icon_, 0, sizeof(icon_data)); + current_cursor_ = None; +#if USE_XFT + screen_num_ = -1; +#endif } @@ -160,8 +164,10 @@ void Fl_X11_Window_Driver::decorated_win_size(int &w, int &h) if (status == 0 || root == parent) return; XWindowAttributes attributes; XGetWindowAttributes(fl_display, parent, &attributes); - w = attributes.width; - h = attributes.height; + int nscreen = screen_num(); + float s = Fl::screen_driver()->scale(nscreen); + w = attributes.width / s; + h = attributes.height / s; } @@ -196,7 +202,9 @@ void Fl_X11_Window_Driver::take_focus() void Fl_X11_Window_Driver::draw_begin() { if (shape_data_) { - if (( shape_data_->lw_ != w() || shape_data_->lh_ != h() ) && shape_data_->shape_) { + int nscreen = screen_num(); + float s = Fl::screen_driver()->scale(nscreen); + if (( shape_data_->lw_ != int(s*w()) || shape_data_->lh_ != int(s*h()) ) && shape_data_->shape_) { // size of window has changed since last time combine_mask(); } @@ -324,8 +332,9 @@ void Fl_X11_Window_Driver::combine_mask() #endif } if (!XShapeCombineMask_f) return; - shape_data_->lw_ = w(); - shape_data_->lh_ = h(); + float s = Fl::screen_driver()->scale(screen_num()); + shape_data_->lw_ = w()*s; + shape_data_->lh_ = h()*s; Fl_Image* temp = shape_data_->shape_->copy(shape_data_->lw_, shape_data_->lh_); Pixmap pbitmap = XCreateBitmapFromData(fl_display, fl_xid(pWindow), (const char*)*temp->data(), @@ -400,25 +409,30 @@ void Fl_X11_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image*& top, F if (n) XFree(children); if (!do_it) wsides = htop = 0; int hbottom = wsides; + float s = Fl::screen_driver()->scale(screen_num()); + 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); 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); 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); 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); if (r_bottom) { bottom = Fl_Shared_Image::get(r_bottom); - } - } + bottom->scale(w() + 2*wsides, wsides, 0, 1); + } } fl_window = from; Fl_Surface_Device::pop_current(); } @@ -432,6 +446,9 @@ void Fl_X11_Window_Driver::make_current() { } fl_window = fl_xid(pWindow); fl_graphics_driver->clip_region(0); +#if USE_XFT + ((Fl_Xlib_Graphics_Driver*)fl_graphics_driver)->scale(Fl::screen_driver()->scale(screen_num())); +#endif #ifdef FLTK_USE_CAIRO // update the cairo_t context @@ -460,6 +477,7 @@ void Fl_X11_Window_Driver::hide() { if (ip->region) Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region); # if USE_XFT Fl_Xlib_Graphics_Driver::destroy_xft_draw(ip->xid); + screen_num_ = -1; # endif // this test makes sure ip->xid has not been destroyed already if (ip->xid) XDestroyWindow(fl_display, ip->xid); @@ -650,8 +668,9 @@ void Fl_X11_Window_Driver::erase_menu() { int Fl_X11_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data) { + float s = Fl::screen_driver()->scale(screen_num()); XCopyArea(fl_display, fl_window, fl_window, (GC)fl_graphics_driver->gc(), - src_x, src_y, src_w, src_h, dest_x, dest_y); + int(src_x*s), int(src_y*s), int(src_w*s), int(src_h*s), int(dest_x*s), int(dest_y*s)); // we have to sync the display and get the GraphicsExpose events! (sigh) for (;;) { XEvent e; XWindowEvent(fl_display, fl_window, ExposureMask, &e); @@ -670,6 +689,40 @@ Fl_X *Fl_X11_Window_Driver::makeWindow() return Fl_X::i(pWindow); } + +#if USE_XFT + +Fl_X11_Window_Driver::type_for_resize_window_between_screens Fl_X11_Window_Driver::data_for_resize_window_between_screens_ = {0, false}; + +void Fl_X11_Window_Driver::resize_after_screen_change(void *data) { + Fl_Window *win = (Fl_Window*)data; + int oldx, oldy; + XWindowAttributes actual; + XGetWindowAttributes(fl_display, fl_xid(win), &actual); + Window cr; + XTranslateCoordinates(fl_display, fl_xid(win), actual.root, 0, 0, &oldx, &oldy, &cr); + win->hide(); + float f = Fl::screen_driver()->scale(data_for_resize_window_between_screens_.screen); + Fl_X11_Window_Driver::driver(win)->screen_num(data_for_resize_window_between_screens_.screen); + win->position(oldx/f, oldy/f); + win->driver()->force_position(1); + Fl_Xlib_Graphics_Driver *d = (Fl_Xlib_Graphics_Driver*)Fl_Display_Device::display_device()->driver(); + d->scale(f); + win->show(); + win->wait_for_expose(); + data_for_resize_window_between_screens_.busy = false; +} + + +int Fl_X11_Window_Driver::screen_num() { + if (pWindow->parent()) { + screen_num_ = pWindow->top_window()->driver()->screen_num(); + } + return screen_num_ >= 0 ? screen_num_ : 0; +} +#endif // USE_XFT + + // // End of "$Id$". // diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx index 138564600..b96a4f410 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx @@ -51,6 +51,8 @@ Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int Fl_Xlib_Copy_Surface_Driver::Fl_Xlib_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { driver(new Fl_Xlib_Graphics_Driver()); + float s = Fl_Graphics_Driver::default_driver().scale(); + ((Fl_Xlib_Graphics_Driver*)driver())->scale(s); oldwindow = fl_window; xid = fl_create_offscreen(w,h); driver()->push_no_clip(); @@ -65,10 +67,10 @@ 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); - unsigned char *data = fl_read_image(NULL,0,0,width,height,0); + Fl_RGB_Image *rgb = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, width, height, 0); if (need_push) Fl_Surface_Device::pop_current(); - Fl_X11_Screen_Driver::copy_image(data, width, height, 1); - delete[] data; + Fl_X11_Screen_Driver::copy_image(rgb->array, rgb->w(), rgb->h(), 1); + delete rgb; fl_delete_offscreen(xid); delete driver(); } diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H index e71eab3cf..d1f6f3fc9 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H @@ -43,7 +43,7 @@ struct _XRegion { #endif // HAVE_X11_XREGION_H #if USE_PANGO -#include <pango/pangoxft.h> +#include <pango/pango.h> #endif @@ -52,11 +52,27 @@ struct _XRegion { * This class is implemented only on the Xlib platform. */ -class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Graphics_Driver { +class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Scalable_Graphics_Driver { private: int offset_x_, offset_y_; // translation between user and graphical coordinates: graphical = user + offset unsigned depth_; // depth of translation stack int stack_x_[20], stack_y_[20]; // translation stack allowing cumulative translations + int line_delta_; +protected: + virtual void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy); + virtual void draw_unscaled(Fl_Bitmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy); + virtual void draw_unscaled(Fl_RGB_Image *img, float s, int XP, int YP, int WP, int HP, int cx, int cy); + virtual void draw_image_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); + virtual void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); + virtual void draw_image_mono_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); + virtual void draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); +#if HAVE_XRENDER + virtual int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); + int scale_and_render_pixmap(Fl_Offscreen pixmap, int depth, double scale_x, double scale_y, int srcx, int srcy, int XP, int YP, int WP, int HP); +#endif + virtual int height_unscaled(); + virtual int descent_unscaled(); + virtual Region scale_clip(float f); #if USE_XFT void drawUCS4(const void *str, int n, int x, int y); #endif @@ -65,16 +81,11 @@ private: static PangoContext *pctxt_; static PangoFontMap *pfmap_; static PangoLayout *playout_; -protected: PangoFontDescription *pfd_; void do_draw(int from_right, const char *str, int n, int x, int y); static PangoContext *context(); static void init_built_in_fonts(); #endif -#if HAVE_XRENDER - int scale_and_render_pixmap(Fl_Offscreen pixmap, int depth, double scale_x, double scale_y, int srcx, int srcy, int XP, int YP, int WP, int HP); -#endif -protected: static GC gc_; uchar **mask_bitmap_; uchar **mask_bitmap() {return mask_bitmap_;} @@ -93,6 +104,7 @@ public: virtual ~Fl_Xlib_Graphics_Driver(); void translate_all(int dx, int dy); void untranslate_all(); + virtual void scale(float f); virtual int has_feature(driver_feature mask) { return mask & NATIVE; } virtual void *gc() { return gc_; } virtual void gc(void *value); @@ -104,51 +116,43 @@ public: // --- bitmap stuff Fl_Bitmask create_bitmask(int w, int h, const uchar *array); void delete_bitmask(Fl_Bitmask bm); - void draw(const char* str, int n, int x, int y); - void draw(int angle, const char *str, int n, int x, int y); - void rtl_draw(const char* str, int n, int x, int y); - void font(Fl_Font face, Fl_Fontsize size); - void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); - void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy); - void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy); - void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0); - void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3); - void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0); - void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1); -#if HAVE_XRENDER - int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP); -#endif + virtual void draw_unscaled(const char* str, int n, int x, int y); + virtual void draw_unscaled(int angle, const char *str, int n, int x, int y); + virtual void rtl_draw_unscaled(const char* str, int n, int x, int y); + virtual void font_unscaled(Fl_Font face, Fl_Fontsize size); 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_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); - int height(); - int descent(); - void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); + virtual double width_unscaled(const char *str, int n); + virtual double width_unscaled(unsigned int c); + virtual void text_extents_unscaled(const char*, int n, int& dx, int& dy, int& w, int& h); + virtual Fl_Fontsize size_unscaled(); + virtual void copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen pixmap, float srcx, float srcy); +#if ! defined(FL_DOXYGEN) + void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); +#endif void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h); Fl_Region XRectangleRegion(int x, int y, int w, int h); void XDestroyRegion(Fl_Region r); protected: - virtual void transformed_vertex0(short x, short y); + virtual void transformed_vertex0(float x, float y); void fixloop(); // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx - void point(int x, int y); - void rect(int x, int y, int w, int h); - void rectf(int x, int y, int w, int h); - void line(int x, int y, int x1, int y1); - void line(int x, int y, int x1, int y1, int x2, int y2); - void xyline(int x, int y, int x1); - void xyline(int x, int y, int x1, int y2); - void xyline(int x, int y, int x1, int y2, int x3); - void yxline(int x, int y, int y1); - void yxline(int x, int y, int y1, int x2); - void yxline(int x, int y, int y1, int x2, int y3); - void loop(int x0, int y0, int x1, int y1, int x2, int y2); - void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); - void polygon(int x0, int y0, int x1, int y1, int x2, int y2); - void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3); + virtual void point_unscaled(float x, float y); + virtual void rect_unscaled(float x, float y, float w, float h); + virtual void rectf_unscaled(float x, float y, float w, float h); + virtual void line_unscaled(float x, float y, float x1, float y1); + virtual void line_unscaled(float x, float y, float x1, float y1, float x2, float y2); + virtual void xyline_unscaled(float x, float y, float x1); + virtual void xyline_unscaled(float x, float y, float x1, float y2); + virtual void xyline_unscaled(float x, float y, float x1, float y2, float x3); + virtual void yxline_unscaled(float x, float y, float y1); + virtual void yxline_unscaled(float x, float y, float y1, float x2); + virtual void yxline_unscaled(float x, float y, float y1, float x2, float y3); + virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2); + virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); + virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2); + virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3); // --- clipping void push_clip(int x, int y, int w, int h); int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H); @@ -156,25 +160,18 @@ protected: void push_no_clip(); void pop_clip(); void restore_clip(); - // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx void begin_complex_polygon(); - void transformed_vertex(double xf, double yf); - void vertex(double x, double y); void end_points(); void end_line(); void end_loop(); void end_polygon(); void end_complex_polygon(); void gap(); - void circle(double x, double y, double r); - // --- implementation is in src/fl_arc.cxx which includes src/cfg_gfx/xxx_arc.cxx if needed - // using void Fl_Graphics_Driver::arc(double x, double y, double r, double start, double end); + virtual void ellipse_unscaled(double xt, double yt, double rx, double ry); // --- implementation is in src/fl_arci.cxx which includes src/cfg_gfx/xxx_arci.cxx - void arc(int x, int y, int w, int h, double a1, double a2); - void pie(int x, int y, int w, int h, double a1, double a2); - // --- implementation is in src/fl_line_style.cxx which includes src/cfg_gfx/xxx_line_style.cxx - void line_style(int style, int width=0, char* dashes=0); - // --- implementation is in src/fl_color.cxx which includes src/cfg_gfx/xxx_color.cxx + virtual void arc_unscaled(float x, float y, float w, float h, double a1, double a2); + virtual void pie_unscaled(float x, float y, float w, float h, double a1, double a2); + virtual void line_style_unscaled(int style, float width, char* dashes); void color(Fl_Color c); void set_color(Fl_Color i, unsigned int c); void free_color(Fl_Color i, int overlay); diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx index 6d6cff681..741ceb89a 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx @@ -3,7 +3,7 @@ // // Rectangle drawing routines for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -57,6 +57,7 @@ Fl_Xlib_Graphics_Driver::Fl_Xlib_Graphics_Driver(void) { p_size = 0; p = NULL; line_width_ = 0; + line_delta_ = 0; #if USE_PANGO pfd_ = pango_font_description_new(); Fl_Graphics_Driver::font(0, 0); @@ -78,8 +79,30 @@ void Fl_Xlib_Graphics_Driver::gc(void *value) { fl_gc = gc_; } -void Fl_Xlib_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) { - XCopyArea(fl_display, pixmap, fl_window, gc_, srcx, srcy, w, h, x+offset_x_, y+offset_y_); +void Fl_Xlib_Graphics_Driver::scale(float f) { +#if USE_XFT + if (f != scale_) { + size_ = 0; + scale_ = f; + //fprintf(stderr, "scale=%.2f\n", scale_); + line_style(FL_SOLID); // scale also default line width + /* Scaling >= 2 transforms 1-pixel wide lines into wider lines. + X11 draws 2-pixel wide lines so that half of the line width is above or at left + of a 1-pixel wide line that would be drawn with the same coordinates. + Thus, if the line starts at coordinates (0,0) half of the line width is invisible. + Similarly, if the line ends at w()-1 the last pixel of the window is not drawn. + What is wanted when scale_ == 2 is a visible 2-pixel wide line in the first case, + and a line at the window's edge in the 2nd case. + Setting line_delta_ to 1 and offsetting all line, rectangle, text and clip + coordinates by line_delta_ achieves what is wanted until scale_ <= 3.5. + */ + line_delta_ = (scale_ > 1.75 ? 1 : 0); + } +#endif +} + +void Fl_Xlib_Graphics_Driver::copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen pixmap, float srcx, float srcy) { + XCopyArea(fl_display, pixmap, fl_window, gc_, srcx, srcy, w, h, x+offset_x_*scale_, y+offset_y_*scale_); } void Fl_Xlib_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y, int W, int H) { @@ -88,7 +111,8 @@ void Fl_Xlib_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y, XUnionRectWithRegion(&R, r, r); } -void Fl_Xlib_Graphics_Driver::transformed_vertex0(short x, short y) { +void Fl_Xlib_Graphics_Driver::transformed_vertex0(float fx, float fy) { + short x = short(fx), y = short(fy); if (!n || x != p[n-1].x || y != p[n-1].y) { if (n >= p_size) { p_size = p ? 2*p_size : 16; @@ -205,6 +229,25 @@ void Fl_Xlib_Graphics_Driver::font_name(int num, const char *name) { s->first = 0; } + +Region Fl_Xlib_Graphics_Driver::scale_clip(float f) { + Region r = rstack[rstackptr]; + if (r == 0 || (f == 1 && offset_x_ == 0 && offset_y_ == 0) ) return 0; + float delta = (f >= 2 ? f/3 : 0); + Region r2 = XCreateRegion(); + XRectangle R; + for (int i = 0; i < r->numRects; i++) { + R.x = short((r->rects[i].x1 + offset_x_)*f-delta + line_delta_); + R.y = short((r->rects[i].y1 + offset_y_)*f-delta + line_delta_); + R.width = short(r->rects[i].x2*f) - short(r->rects[i].x1*f); + R.height = short(r->rects[i].y2*f) - short(r->rects[i].y1*f); + XUnionRectWithRegion(&R, r2, r2); + } + rstack[rstackptr] = r2; + return r; +} + + void Fl_Xlib_Graphics_Driver::translate_all(int dx, int dy) { // reversibly adds dx,dy to the offset between user and graphical coordinates stack_x_[depth_] = offset_x_; stack_y_[depth_] = offset_y_; diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx index b1a8cd10d..cd0b7915f 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx @@ -3,7 +3,7 @@ // // Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -26,15 +26,15 @@ \brief Utility functions for drawing circles using integers */ -void Fl_Xlib_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) { +void Fl_Xlib_Graphics_Driver::arc_unscaled(float x,float y,float w,float h,double a1,double a2) { if (w <= 0 || h <= 0) return; - XDrawArc(fl_display, fl_window, gc_, x+offset_x_,y+offset_y_,w-1,h-1, int(a1*64),int((a2-a1)*64)); + XDrawArc(fl_display, fl_window, gc_, int(x+offset_x_*scale_), int(y+offset_y_*scale_), int(w-1), int(h-1), int(a1*64),int((a2-a1)*64)); } -void Fl_Xlib_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) { +void Fl_Xlib_Graphics_Driver::pie_unscaled(float x,float y,float w,float h,double a1,double a2) { if (w <= 0 || h <= 0) return; - x += offset_x_; - y += offset_y_; + x += offset_x_*scale_; + y += offset_y_*scale_; XDrawArc(fl_display, fl_window, gc_, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); XFillArc(fl_display, fl_window, gc_, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); } diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx index a1da5a585..5123f6e02 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx @@ -3,7 +3,7 @@ // // X11 font utilities for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -596,7 +596,7 @@ XFontStruct* Fl_XFont_On_Demand::value() { return ptr; } -void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { +void Fl_Xlib_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) { if (fnum==-1) { Fl_Graphics_Driver::font(0, 0); return; @@ -611,27 +611,32 @@ void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { } } -int Fl_Xlib_Graphics_Driver::height() { +int Fl_Xlib_Graphics_Driver::height_unscaled() { if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent; else return -1; } -int Fl_Xlib_Graphics_Driver::descent() { +int Fl_Xlib_Graphics_Driver::descent_unscaled() { if (font_descriptor()) return font_descriptor()->font->descent; else return -1; } -double Fl_Xlib_Graphics_Driver::width(const char* c, int n) { +Fl_Fontsize Fl_Xlib_Graphics_Driver::size_unscaled() { + if (font_descriptor()) return size_; + return -1; +} + +double Fl_Xlib_Graphics_Driver::width_unscaled(const char* c, int n) { if (font_descriptor()) return (double) XUtf8TextWidth(font_descriptor()->font, c, n); else return -1; } -double Fl_Xlib_Graphics_Driver::width(unsigned int c) { +double Fl_Xlib_Graphics_Driver::width_unscaled(unsigned int c) { if (font_descriptor()) return (double) XUtf8UcsWidth(font_descriptor()->font, c); else return -1; } -void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &W, int &H) { +void Fl_Xlib_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &W, int &H) { if (font_gc != gc_) { if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE); font_gc = gc_; @@ -649,7 +654,7 @@ void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &d // dy = fl_descent() - H; } -void Fl_Xlib_Graphics_Driver::draw(const char* c, int n, int x, int y) { +void Fl_Xlib_Graphics_Driver::draw_unscaled(const char* c, int n, int x, int y) { if (font_gc != gc_) { if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); font_gc = gc_; @@ -658,7 +663,7 @@ void Fl_Xlib_Graphics_Driver::draw(const char* c, int n, int x, int y) { if (gc_) XUtf8DrawString(fl_display, fl_window, font_descriptor()->font, gc_, x+offset_x_, y+offset_y_, c, n); } -void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { +void Fl_Xlib_Graphics_Driver::draw_unscaled(int angle, const char *str, int n, int x, int y) { static char warning = 0; // issue warning only once if (!warning && angle != 0) { warning = 1; @@ -669,7 +674,7 @@ void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int this->draw(str, n, (int)x, (int)y); } -void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { +void Fl_Xlib_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) { if (font_gc != gc_) { if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE); font_gc = gc_; diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx index 48771d0a2..a2c655455 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx @@ -3,7 +3,7 @@ // // More font utilities for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -125,6 +125,30 @@ static Fl_Fontdesc built_in_table[] = { Fl_Fontdesc* fl_fonts = built_in_table; +Fl_Fontsize Fl_Xlib_Graphics_Driver::size_unscaled() { + return (Fl_Fontsize)(size_); +} + +static void correct_extents (float scale_, int &dx, int &dy, int &w, int &h) { + if (int(scale_) == scale_) { // correct for extents non divisible by integral scale_ + int delta = dx - int(dx/scale_)*scale_; + if (delta) { + dx -= delta; w += delta; + } + delta = -dy - int((-dy)/scale_)*scale_; + if (delta) { + dy -= delta; h += delta; + } + delta = h - int(h/scale_)*scale_; + if (delta) { + h += delta; + } + delta = w - int(w/scale_)*scale_; + if (delta) { + w += delta; + } + } +} #if ! USE_PANGO @@ -455,8 +479,8 @@ Fl_Font Fl_Xlib_Graphics_Driver::set_fonts(const char* pattern_name) static const char* fl_encoding_ = "iso10646-1"; -void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { - fl_xft_font(this,fnum,size,0); +void Fl_Xlib_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) { + fl_xft_font(this, fnum, size, 0); } static XftFont* fontopen(const char* name, /*Fl_Fontsize*/double size, bool core, int angle) { @@ -691,17 +715,17 @@ static void utf8extents(Fl_Font_Descriptor *desc, const char *str, int n, XGlyph #endif } -int Fl_Xlib_Graphics_Driver::height() { +int Fl_Xlib_Graphics_Driver::height_unscaled() { if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent; else return -1; } -int Fl_Xlib_Graphics_Driver::descent() { +int Fl_Xlib_Graphics_Driver::descent_unscaled() { if (font_descriptor()) return font_descriptor()->font->descent; else return -1; } -double Fl_Xlib_Graphics_Driver::width(const char* str, int n) { +double Fl_Xlib_Graphics_Driver::width_unscaled(const char* str, int n) { if (!font_descriptor()) return -1.0; XGlyphInfo i; utf8extents(font_descriptor(), str, n, &i); @@ -715,11 +739,12 @@ static double fl_xft_width(Fl_Font_Descriptor *desc, FcChar32 *str, int n) { return i.xOff; } -double Fl_Xlib_Graphics_Driver::width(unsigned int c) { +double Fl_Xlib_Graphics_Driver::width_unscaled(unsigned int c) { + if (!font_descriptor()) return -1.0; return fl_xft_width(font_descriptor(), (FcChar32 *)(&c), 1); } -void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { +void Fl_Xlib_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &w, int &h) { if (!font_descriptor()) { w = h = 0; dx = dy = 0; @@ -730,15 +755,12 @@ void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &d w = gi.width; h = gi.height; - dx = -gi.x; - dy = -gi.y; -} // fl_text_extents - + dx = -gi.x + line_delta_; + dy = -gi.y + line_delta_; + correct_extents(scale_, dx, dy, w, h); +} -void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) { - if ( !this->font_descriptor() ) { - this->font(FL_HELVETICA, FL_NORMAL_SIZE); - } +void Fl_Xlib_Graphics_Driver::draw_unscaled(const char *str, int n, int x, int y) { #if USE_OVERLAY XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_; if (fl_overlay) { @@ -756,31 +778,32 @@ void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) { XftDrawChange(draw_, draw_window = fl_window); Region region = fl_clip_region(); - if (region && XEmptyRegion(region)) return; - XftDrawSetClip(draw_, region); - - // Use fltk's color allocator, copy the results to match what - // XftCollorAllocValue returns: - XftColor color; - color.pixel = fl_xpixel(Fl_Graphics_Driver::color()); - uchar r,g,b; Fl::get_color(Fl_Graphics_Driver::color(), r,g,b); - color.color.red = ((int)r)*0x101; - color.color.green = ((int)g)*0x101; - color.color.blue = ((int)b)*0x101; - color.color.alpha = 0xffff; - - const wchar_t *buffer = utf8reformat(str, n); + if (!(region && XEmptyRegion(region))) { + XftDrawSetClip(draw_, region); + + // Use fltk's color allocator, copy the results to match what + // XftCollorAllocValue returns: + XftColor color; + color.pixel = fl_xpixel(Fl_Graphics_Driver::color()); + uchar r,g,b; Fl::get_color(Fl_Graphics_Driver::color(), r,g,b); + color.color.red = ((int)r)*0x101; + color.color.green = ((int)g)*0x101; + color.color.blue = ((int)b)*0x101; + color.color.alpha = 0xffff; + + const wchar_t *buffer = utf8reformat(str, n); #ifdef __CYGWIN__ - XftDrawString16(draw_, &color, font_descriptor()->font, x+offset_x_, y+offset_y_, (XftChar16 *)buffer, n); + XftDrawString16(draw_, &color, font_descriptor()->font, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, (XftChar16 *)buffer, n); #else - XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_, y+offset_y_, (XftChar32 *)buffer, n); + XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, (XftChar32 *)buffer, n); #endif + } } -void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { - fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), angle); - this->draw(str, n, (int)x, (int)y); - fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), 0); +void Fl_Xlib_Graphics_Driver::draw_unscaled(int angle, const char *str, int n, int x, int y) { + fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size_unscaled(), angle); + this->draw_unscaled(str, n, x, y); + fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size_unscaled(), 0); } void Fl_Xlib_Graphics_Driver::drawUCS4(const void *str, int n, int x, int y) { @@ -814,11 +837,11 @@ void Fl_Xlib_Graphics_Driver::drawUCS4(const void *str, int n, int x, int y) { color.color.blue = ((int)b)*0x101; color.color.alpha = 0xffff; - XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_, y+offset_x_, (FcChar32 *)str, n); + XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, (FcChar32 *)str, n); } -void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { +void Fl_Xlib_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) { #if defined(__GNUC__) // FIXME: warning Need to improve this XFT right to left draw function @@ -902,7 +925,7 @@ int Fl_Xlib_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) { float Fl_Xlib_Graphics_Driver::scale_font_for_PostScript(Fl_Font_Descriptor *desc, int s) { // Xft font height is sometimes larger than the required size (see STR 2566). // Increase the PostScript font size by 15% without exceeding the display font height - int max = height(); + int max = height_unscaled(); float ps_size = s * 1.15; if (ps_size > max) ps_size = max; return ps_size; @@ -972,7 +995,7 @@ static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsi return; } Fl_Font_Descriptor* f = driver->font_descriptor(); - if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size() && f && f->angle == angle) + if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size_unscaled() && f && f->angle == angle) return; driver->Fl_Graphics_Driver::font(fnum, size); Fl_Fontdesc *font = fl_fonts + fnum; @@ -1021,7 +1044,7 @@ static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsi // well for the fltk "built-in" font names. static XFontStruct* load_xfont_for_xft2(Fl_Graphics_Driver *driver) { XFontStruct* xgl_font = 0; - int size = driver->size(); + int size = ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled(); int fnum = driver->font(); const char *wt_med = "medium"; const char *wt_bold = "bold"; @@ -1112,10 +1135,10 @@ static XFontStruct* fl_xxfont(Fl_Graphics_Driver *driver) { static int glsize = 0; static int glfont = -1; // Do we need to load a new font? - if ((!xgl_font) || (glsize != driver->size()) || (glfont != driver->font())) { + if ((!xgl_font) || (glsize != ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled()) || (glfont != driver->font())) { // create a dummy XLFD for some font of the appropriate size... if (xgl_font) XFreeFont(fl_display, xgl_font); // font already loaded, free it - this *might* be a Bad Idea - glsize = driver->size(); // record current font size + glsize = ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled(); // record current font size glfont = driver->font(); // and face xgl_font = load_xfont_for_xft2(driver); } @@ -1126,7 +1149,7 @@ static XFontStruct* fl_xxfont(Fl_Graphics_Driver *driver) { } static XftFont* xftfont; if (xftfont) XftFontClose (fl_display, xftfont); - xftfont = fontopen(fl_fonts[driver->font()].name, driver->size(), true, 0); // else request XFT to load a suitable "core" font instead. + xftfont = fontopen(fl_fonts[driver->font()].name, ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled(), true, 0); // else request XFT to load a suitable "core" font instead. return xftfont->u.core.font; # endif // XFT_MAJOR > 1 } @@ -1161,9 +1184,13 @@ PangoContext *Fl_Xlib_Graphics_Driver::context() { return pctxt_; } -void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { +void Fl_Xlib_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) { if (!size) return; - if (this->Fl_Graphics_Driver::font() == fnum && this->size() == size) return; + if (size < 0) { + Fl_Graphics_Driver::font(0, 0); + return; + } + if (this->Fl_Graphics_Driver::font() == fnum && this->size_unscaled() == size) return; fl_xft_font(this, fnum, size, 0); init_built_in_fonts(); if (pfd_) pango_font_description_free(pfd_); @@ -1180,21 +1207,21 @@ void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { } } -void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) { - do_draw(0, str, n, x+offset_x_, y+offset_y_); +void Fl_Xlib_Graphics_Driver::draw_unscaled(const char *str, int n, int x, int y) { + do_draw(0, str, n, x+offset_x_*scale_, y+offset_y_*scale_); } -void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) { +void Fl_Xlib_Graphics_Driver::draw_unscaled(int angle, const char *str, int n, int x, int y) { PangoMatrix mat = PANGO_MATRIX_INIT; // 1.6 - pango_matrix_translate(&mat, x+offset_x_, y+offset_y_); // 1.6 + pango_matrix_translate(&mat, x+offset_x_*scale_, y+offset_y_*scale_); // 1.6 pango_matrix_rotate(&mat, angle); // 1.6 pango_context_set_matrix(pctxt_, &mat); // 1.6 do_draw(0, str, n, 0, 0); pango_context_set_matrix(pctxt_, NULL); // 1.6 } -void Fl_Xlib_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) { - do_draw(1, str, n, x+offset_x_, y+offset_y_); +void Fl_Xlib_Graphics_Driver::rtl_draw_unscaled(const char* str, int n, int x, int y) { + do_draw(1, str, n, x+offset_x_*scale_, y+offset_y_*scale_); } void Fl_Xlib_Graphics_Driver::do_draw(int from_right, const char *str, int n, int x, int y) { @@ -1245,12 +1272,13 @@ void Fl_Xlib_Graphics_Driver::do_draw(int from_right, const char *str, int n, in else XftDrawChange(draw_, draw_window = fl_window); XftDrawSetClip(draw_, region); - pango_xft_render_layout(draw_, &color, playout_, x*PANGO_SCALE, (y-height()+descent())*PANGO_SCALE ); // 1.8 -} + pango_xft_render_layout(draw_, &color, playout_, (x + line_delta_)*PANGO_SCALE, + (y+line_delta_-height_unscaled()+descent_unscaled())*PANGO_SCALE ); // 1.8 + } -double Fl_Xlib_Graphics_Driver::width(const char* str, int n) { +double Fl_Xlib_Graphics_Driver::width_unscaled(const char* str, int n) { if (!n) return 0; - if (!fl_display || fl_size() == 0) return -1; + if (!fl_display || size_ == 0) return -1; if (!playout_) context(); int width, height; pango_layout_set_font_description(playout_, pfd_); @@ -1259,30 +1287,31 @@ double Fl_Xlib_Graphics_Driver::width(const char* str, int n) { return (double)width; } -void Fl_Xlib_Graphics_Driver::text_extents(const char *str, int n, int &dx, int &dy, int &w, int &h) { +void Fl_Xlib_Graphics_Driver::text_extents_unscaled(const char *str, int n, int &dx, int &dy, int &w, int &h) { if (!playout_) context(); pango_layout_set_font_description(playout_, pfd_); pango_layout_set_text(playout_, str, n); PangoRectangle ink_rect, logical_rect; pango_layout_get_pixel_extents(playout_, &ink_rect, &logical_rect); - dx = ink_rect.x; - dy = ink_rect.y - height() + descent(); + dx = ink_rect.x + line_delta_; + dy = ink_rect.y + line_delta_ - height_unscaled() + descent_unscaled(); w = ink_rect.width; h = ink_rect.height; + correct_extents(scale_, dx, dy, w, h); } -int Fl_Xlib_Graphics_Driver::height() { +int Fl_Xlib_Graphics_Driver::height_unscaled() { if (font_descriptor()) return font_descriptor()->height_; else return -1; } -double Fl_Xlib_Graphics_Driver::width(unsigned int c) { +double Fl_Xlib_Graphics_Driver::width_unscaled(unsigned int c) { char buf4[4]; int n = fl_utf8encode(c, buf4); - return width(buf4, n); + return width_unscaled(buf4, n); } -int Fl_Xlib_Graphics_Driver::descent() { +int Fl_Xlib_Graphics_Driver::descent_unscaled() { if (font_descriptor()) return font_descriptor()->descent_; else return -1; } diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx index 44bd17a42..c7b298493 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx @@ -47,10 +47,13 @@ #include <config.h> #include "Fl_Xlib_Graphics_Driver.H" +#include "../X11/Fl_X11_Screen_Driver.H" +#include "../X11/Fl_X11_Window_Driver.H" # include <FL/Fl.H> # include <FL/fl_draw.H> # include <FL/x.H> # include <FL/Fl_Image_Surface.H> +# include <FL/Fl_Screen_Driver.H> # include "../../Fl_XColor.H" # include "../../flstring.h" #if HAVE_XRENDER @@ -476,7 +479,6 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, if (w<=0 || h<=0) return; dx -= X; dy -= Y; - if (!bytes_per_pixel) figure_out_visual(); const unsigned oldbpp = bytes_per_pixel; static GC gc32 = None; @@ -574,32 +576,32 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, } } -void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){ +void Fl_Xlib_Graphics_Driver::draw_image_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ const bool alpha = !!(abs(d) & FL_IMAGE_WITH_ALPHA); if (alpha) d ^= FL_IMAGE_WITH_ALPHA; const int mono = (d>-3 && d<3); - innards(buf,x+offset_x_,y+offset_y_,w,h,d,l,mono,0,0,alpha,gc_); + innards(buf,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,l,mono,0,0,alpha,gc_); } -void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, +void Fl_Xlib_Graphics_Driver::draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int x, int y, int w, int h,int d) { const bool alpha = !!(abs(d) & FL_IMAGE_WITH_ALPHA); if (alpha) d ^= FL_IMAGE_WITH_ALPHA; const int mono = (d>-3 && d<3); - innards(0,x+offset_x_,y+offset_y_,w,h,d,0,mono,cb,data,alpha,gc_); + innards(0,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,0,mono,cb,data,alpha,gc_); } -void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ - innards(buf,x+offset_x_,y+offset_y_,w,h,d,l,1,0,0,0,gc_); +void Fl_Xlib_Graphics_Driver::draw_image_mono_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){ + innards(buf,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,l,1,0,0,0,gc_); } -void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, +void Fl_Xlib_Graphics_Driver::draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int x, int y, int w, int h,int d) { - innards(0,x+offset_x_,y+offset_y_,w,h,d,0,1,cb,data,0,gc_); + innards(0,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,0,1,cb,data,0,gc_); } void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { @@ -622,15 +624,14 @@ void Fl_Xlib_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) { XFreePixmap(fl_display, bm); } -void Fl_Xlib_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (Fl_Graphics_Driver::prepare(bm, XP+offset_x_, YP+offset_y_, WP, HP, cx, cy, X, Y, W, H)) { - return; - } - +void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int X, int Y, int W, int H, int cx, int cy) { + X = (X+offset_x_)*s; + Y = (Y+offset_y_)*s; + cache_size(bm, W, H); + cx *= s; cy *= s; XSetStipple(fl_display, gc_, *Fl_Graphics_Driver::id(bm)); - int ox = X-cx; if (ox < 0) ox += bm->w(); - int oy = Y-cy; if (oy < 0) oy += bm->h(); + int ox = X-cx; if (ox < 0) ox += bm->w()*s; + int oy = Y-cy; if (oy < 0) oy += bm->h()*s; XSetTSOrigin(fl_display, gc_, ox, oy); XSetFillStyle(fl_display, gc_, FillStippled); XFillRectangle(fl_display, fl_window, gc_, X, Y, W, H); @@ -715,33 +716,42 @@ static Fl_Offscreen cache_rgb(Fl_RGB_Image *img) { return off; } -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; - XP += offset_x_; - YP += offset_y_; - // Don't draw an empty image... - if (!img->d() || !img->array) { - Fl_Graphics_Driver::draw_empty(img, XP, YP); - return; - } - if (start_image(img, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; - } +// X,Y,W,H,cx,cy are in FLTK units +// if s != 1 and id(img) != 0, the offscreen has been previously scaled by s +// if s != 1 and id(img) == 0, img has been previously scaled by s +void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, int Y, int W, int H, int cx, int cy) { + X = (X+offset_x_)*s; + Y = (Y+offset_y_)*s; + cache_size(img, W, H); + cx *= s; cy *= s; if (!*Fl_Graphics_Driver::id(img)) { *Fl_Graphics_Driver::id(img) = cache_rgb(img); + *cache_scale(img) = 1; } + Fl_Region r2 = scale_clip(s); if (*Fl_Graphics_Driver::id(img)) { if (img->d() == 4 || img->d() == 2) { #if HAVE_XRENDER - scale_and_render_pixmap(*Fl_Graphics_Driver::id(img), 4, 1, 1, cx, cy, X - offset_x_, Y - offset_y_, W, H); + scale_and_render_pixmap(*Fl_Graphics_Driver::id(img), img->d(), 1, 1, cx, cy, X, Y, W, H); #endif } else { - copy_offscreen(X - offset_x_, Y - offset_y_, W, H, *Fl_Graphics_Driver::id(img), cx, cy); + XCopyArea(fl_display, *Fl_Graphics_Driver::id(img), fl_window, gc_, cx, cy, W, H, X, Y); } } else { // Composite image with alpha manually each time... + scale_ = 1; + int ox = offset_x_, oy = offset_y_; + offset_x_ = offset_y_ = 0; + Fl_X11_Screen_Driver *d = (Fl_X11_Screen_Driver*)Fl::screen_driver(); + int nscreen = Fl_Window::current()->driver()->screen_num(); + float keep = d->scale(nscreen); + d->scale(nscreen, 1); alpha_blend(img, X, Y, W, H, cx, cy); + d->scale(nscreen, keep); + scale_ = s; + offset_x_ = ox; offset_y_ = oy; } + unscale_clip(r2); } void Fl_Xlib_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_) @@ -752,13 +762,17 @@ void Fl_Xlib_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintp } } -fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) { +fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap *bm, int w, int h, const uchar *array) { + *cache_scale(bm) = Fl_Scalable_Graphics_Driver::scale(); return (fl_uintptr_t)create_bitmask(w, h, array); } -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 (Fl_Graphics_Driver::prepare(pxm, XP+offset_x_, YP+offset_y_, WP, HP, cx, cy, X, Y, W, H)) return; +void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int X, int Y, int W, int H, int cx, int cy) { + X = (X+offset_x_)*s; + Y = (Y+offset_y_)*s; + cache_size(pxm, W, H); + cx *= s; cy *= s; + Fl_Region r2 = scale_clip(s); if (*Fl_Graphics_Driver::mask(pxm)) { // make X use the bitmap as a mask: XSetClipMask(fl_display, gc_, *Fl_Graphics_Driver::mask(pxm)); @@ -781,21 +795,24 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int H 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-offset_x_, Y1-offset_y_, W1, H1, *Fl_Graphics_Driver::id(pxm), cx + (X1 - X), cy + (Y1 - Y)); + XCopyArea(fl_display, *Fl_Graphics_Driver::id(pxm), fl_window, gc_, cx + (X1 - X), cy + (Y1 - Y), W1, H1, X1, Y1); } XDestroyRegion(r); } else { - copy_offscreen(X-offset_x_, Y-offset_y_, W, H, *Fl_Graphics_Driver::id(pxm), cx, cy); + XCopyArea(fl_display, *Fl_Graphics_Driver::id(pxm), fl_window, gc_, cx, cy, W, H, X, Y); } // put the old clip region back XSetClipOrigin(fl_display, gc_, 0, 0); + s = scale_; scale_ = 1; restore_clip(); + scale_ = s; } - else copy_offscreen(X-offset_x_, Y-offset_y_, W, H, *Fl_Graphics_Driver::id(pxm), cx, cy); + else XCopyArea(fl_display, *Fl_Graphics_Driver::id(pxm), fl_window, gc_, cx, cy, W, H, X, Y); + unscale_clip(r2); } -fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const char *const*data) { +fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *pxm, int w, int h, const char *const*data) { Fl_Offscreen id; id = fl_create_offscreen(w, h); fl_begin_offscreen(id); @@ -804,22 +821,26 @@ fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const fl_draw_pixmap(data, 0, 0, FL_BLACK); Fl_Surface_Device::surface()->driver()->mask_bitmap(0); if (bitmap) { - *Fl_Graphics_Driver::mask(img) = (fl_uintptr_t)fl_create_bitmask(w, h, bitmap); + *Fl_Graphics_Driver::mask(pxm) = (fl_uintptr_t)create_bitmask(w * scale_, h * scale_, bitmap); delete[] bitmap; } fl_end_offscreen(); + *cache_scale(pxm) = Fl_Scalable_Graphics_Driver::scale(); return (fl_uintptr_t)id; } #if HAVE_XRENDER +/* Draws with Xrender an Fl_Offscreen with optional scaling and accounting for transparency if necessary. + XP,YP,WP,HP are in drawing units + */ int Fl_Xlib_Graphics_Driver::scale_and_render_pixmap(Fl_Offscreen pixmap, int depth, double scale_x, double scale_y, int srcx, int srcy, int XP, int YP, int WP, int HP) { + bool has_alpha = (depth == 2 || depth == 4); XRenderPictureAttributes srcattr; memset(&srcattr, 0, sizeof(XRenderPictureAttributes)); static XRenderPictFormat *fmt32 = XRenderFindStandardFormat(fl_display, PictStandardARGB32); static XRenderPictFormat *fmt24 = XRenderFindStandardFormat(fl_display, PictStandardRGB24); - Picture src = XRenderCreatePicture(fl_display, pixmap, - depth%2 == 0 ?fmt32:fmt24, 0, &srcattr); + Picture src = XRenderCreatePicture(fl_display, pixmap, has_alpha ?fmt32:fmt24, 0, &srcattr); Picture dst = XRenderCreatePicture(fl_display, fl_window, fmt24, 0, &srcattr); if (!src || !dst) { fprintf(stderr, "Failed to create Render pictures (%lu %lu)\n", src, dst); @@ -836,22 +857,24 @@ int Fl_Xlib_Graphics_Driver::scale_and_render_pixmap(Fl_Offscreen pixmap, int de }}; XRenderSetPictureTransform(fl_display, src, &mat); } - XRenderComposite(fl_display, (depth%2 == 0 ? PictOpOver : PictOpSrc), src, None, dst, srcx, srcy, 0, 0, - XP + offset_x_, YP + offset_y_, WP, HP); + XRenderComposite(fl_display, (has_alpha ? PictOpOver : PictOpSrc), src, None, dst, srcx, srcy, 0, 0, + XP, YP, WP, HP); XRenderFreePicture(fl_display, src); XRenderFreePicture(fl_display, dst); return 1; } - +// XP,YP,WP,HP are in FLTK units int Fl_Xlib_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) { Fl_RGB_Image *rgb = img->as_rgb_image(); if (!rgb || !can_do_alpha_blending()) return 0; if (!*Fl_Graphics_Driver::id(rgb)) { *Fl_Graphics_Driver::id(rgb) = cache_rgb(rgb); + *cache_scale(rgb) = 1; } - return scale_and_render_pixmap(*Fl_Graphics_Driver::id(rgb), rgb->d(), rgb->w()/double(WP), rgb->h()/double(HP), - 0, 0, XP, YP, WP, HP); + cache_size(img, WP, HP); + return scale_and_render_pixmap( *Fl_Graphics_Driver::id(rgb), rgb->d(), + rgb->w() / double(WP), rgb->h() / double(HP), 0, 0, (XP + offset_x_)*scale_, (YP + offset_y_)*scale_, WP, HP); } #endif // HAVE_XRENDER diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx index a10ce7972..6629d7bfa 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx @@ -3,7 +3,7 @@ // // Line style code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -34,10 +34,9 @@ #include "Fl_Xlib_Graphics_Driver.H" -void Fl_Xlib_Graphics_Driver::line_style(int style, int width, char* dashes) { - +void Fl_Xlib_Graphics_Driver::line_style_unscaled(int style, float width, char* dashes) { // save line width for X11 clipping - if (width == 0) line_width_ = 1; + if (width == 0) line_width_ = scale_ < 2 ? 0 : scale_; else line_width_ = width>0 ? width : -width; int ndashes = dashes ? strlen(dashes) : 0; @@ -63,10 +62,12 @@ void Fl_Xlib_Graphics_Driver::line_style(int style, int width, char* dashes) { case FL_DASHDOTDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; *p++ = dot; *p++ = gap; break; } ndashes = p-buf; +if (*dashes == 0) ndashes = 0;//against error with very small scaling } static int Cap[4] = {CapButt, CapButt, CapRound, CapProjecting}; static int Join[4] = {JoinMiter, JoinMiter, JoinRound, JoinBevel}; - XSetLineAttributes(fl_display, gc_, width, + XSetLineAttributes(fl_display, gc_, + line_width_, ndashes ? LineOnOffDash : LineSolid, Cap[(style>>8)&3], Join[(style>>12)&3]); if (ndashes) XSetDashes(fl_display, gc_, 0, dashes, ndashes); diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx index 71395afdf..bc318a7e9 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx @@ -3,7 +3,7 @@ // // Rectangle drawing routines for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -161,112 +161,167 @@ void Fl_Xlib_Graphics_Driver::XDestroyRegion(Fl_Region r) { ::XDestroyRegion(r); } -// --- line and polygon drawing with integer coordinates +// --- line and polygon drawing -void Fl_Xlib_Graphics_Driver::point(int x, int y) { - XDrawPoint(fl_display, fl_window, gc_, clip_x(x+offset_x_), clip_x(y+offset_y_)); -} -void Fl_Xlib_Graphics_Driver::rect(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - x+=offset_x_; y+=offset_y_; +void Fl_Xlib_Graphics_Driver::rect_unscaled(float fx, float fy, float fw, float fh) { + if (fw<=0 || fh<=0) return; + int deltaf = scale_ >= 2 ? scale_-1 : 0; + fx += offset_x_*scale_; fy += offset_y_*scale_; + int x = fx; int y = fy; + int w = int(int(fx/scale_+fw/scale_+0.5)*scale_) - x - 1 - deltaf; + int h = int(int(fy/scale_+fh/scale_+0.5)*scale_) - y - 1 - deltaf; if (!clip_to_short(x, y, w, h, line_width_)) - XDrawRectangle(fl_display, fl_window, gc_, x, y, w-1, h-1); + XDrawRectangle(fl_display, fl_window, gc_, x+line_delta_, y+line_delta_, w, h); } -void Fl_Xlib_Graphics_Driver::rectf(int x, int y, int w, int h) { - if (w<=0 || h<=0) return; - x+=offset_x_; y+=offset_y_; +void Fl_Xlib_Graphics_Driver::rectf_unscaled(float fx, float fy, float fw, float fh) { + if (fw<=0 || fh<=0) return; + int deltaf = scale_ >= 2 ? scale_/2 : 0; + fx += offset_x_*scale_; fy += offset_y_*scale_; + int x = fx-deltaf; int y = fy-deltaf; + // make sure no unfilled area lies between rectf(x,y,w,h) and rectf(x+w,y,1,h) or rectf(x,y+w,w,1) + int w = int(int(fx/scale_+fw/scale_+0.5)*scale_) - int(fx); + int h = int(int(fy/scale_+fh/scale_+0.5)*scale_) - int(fy); if (!clip_to_short(x, y, w, h, line_width_)) - XFillRectangle(fl_display, fl_window, gc_, x, y, w, h); + XFillRectangle(fl_display, fl_window, gc_, x+line_delta_, y+line_delta_, w, h); +} + +void Fl_Xlib_Graphics_Driver::point_unscaled(float fx, float fy) { + int deltaf = scale_ >= 2 ? scale_/2 : 0; + int x = fx+offset_x_*scale_-deltaf; int y = fy+offset_y_*scale_-deltaf; + int width = scale_ >= 1 ? scale_ : 1; + XFillRectangle(fl_display, fl_window, gc_, x+line_delta_, y+line_delta_, width, width); } -void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1) { - XDrawLine(fl_display, fl_window, gc_, x+offset_x_, y+offset_y_, x1+offset_x_, y1+offset_y_); +void Fl_Xlib_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1) { + if (x == x1) yxline_unscaled(x, y, y1); + else if (y == y1) xyline_unscaled(x, y, x1); + else XDrawLine(fl_display, fl_window, gc_, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, x1+offset_x_*scale_+line_delta_, y1+offset_y_*scale_+line_delta_); } -void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) { +void Fl_Xlib_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1, float x2, float y2) { XPoint p[3]; - p[0].x = x+offset_x_; p[0].y = y+offset_y_; - p[1].x = x1+offset_x_; p[1].y = y1+offset_y_; - p[2].x = x2+offset_x_; p[2].y = y2+offset_y_; + p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_; + p[1].x = x1+offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_; + p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_; XDrawLines(fl_display, fl_window, gc_, p, 3, 0); } -void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1) { - XDrawLine(fl_display, fl_window, gc_, clip_x(x+offset_x_), clip_x(y+offset_y_), clip_x(x1+offset_x_), clip_x(y+offset_y_)); +void Fl_Xlib_Graphics_Driver::xyline_unscaled(float x, float y, float x1) {//OK + x+=offset_x_*scale_; y+=offset_y_*scale_; x1 += offset_x_*scale_; + int tw = line_width_ ? line_width_ : 1; // true line width + if (x > x1) { float exch = x; x = x1; x1 = exch; } + int ix = clip_x(x+line_delta_); if (scale_ >= 2) ix -= int(scale_/2); + int iy = clip_x(y+line_delta_); + int ix1 = int(x1/scale_+1.5)*scale_-1; if (scale_ >= 2) ix1 += int(scale_/2); if (scale_ >= 4) ix1 -= scale_/2; + XDrawLine(fl_display, fl_window, gc_, ix, iy, ix1, iy); + // try and make sure no unfilled area lies between xyline(x,y,x1) and xyline(x,y+1,x1) + if (y+line_delta_ + scale_ >= iy + tw+1 - 0.001 ) XDrawLine(fl_display, fl_window, gc_, ix, iy+1, ix1, iy+1); } -void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2) { +void Fl_Xlib_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2) {//OK + x+=offset_x_*scale_; y+=offset_y_*scale_; x1 += offset_x_*scale_; y2+=offset_y_*scale_; + if (scale_ >= 2) { + int delta = int(scale_/2 + 0.5); + if (x > x1) x += delta; else x -= delta; + if (y2 > y) y2 += delta; else y2 -= delta; + } XPoint p[3]; - p[0].x = clip_x(x+offset_x_); p[0].y = p[1].y = clip_x(y+offset_y_); - p[1].x = p[2].x = clip_x(x1+offset_x_); p[2].y = clip_x(y2+offset_y_); + p[0].x = clip_x(x+line_delta_); p[0].y = p[1].y = clip_x(y+line_delta_); + p[1].x = p[2].x = clip_x(x1+line_delta_); p[2].y = clip_x(y2+line_delta_); XDrawLines(fl_display, fl_window, gc_, p, 3, 0); } -void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { +void Fl_Xlib_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2, float x3) { + x+=offset_x_*scale_; y+=offset_y_*scale_; x1 += offset_x_*scale_; y2+=offset_y_*scale_; x3 += offset_x_*scale_; + if (scale_ >= 2) { + int delta = int(scale_/2 + 0.5); + if (x > x1) x += delta; else x -= delta; + if (x3 > x1) x3 += delta; else x3 -= delta; + } XPoint p[4]; - p[0].x = clip_x(x+offset_x_); p[0].y = p[1].y = clip_x(y+offset_y_); - p[1].x = p[2].x = clip_x(x1+offset_x_); p[2].y = p[3].y = clip_x(y2+offset_y_); - p[3].x = clip_x(x3+offset_x_); + p[0].x = clip_x(x+line_delta_); p[0].y = p[1].y = clip_x(y+line_delta_); + p[1].x = p[2].x = clip_x(x1+line_delta_); p[2].y = p[3].y = clip_x(y2+line_delta_); + p[3].x = clip_x(x3+line_delta_); XDrawLines(fl_display, fl_window, gc_, p, 4, 0); } -void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1) { - XDrawLine(fl_display, fl_window, gc_, clip_x(x+offset_x_), clip_x(y+offset_y_), clip_x(x+offset_x_), clip_x(y1+offset_y_)); +void Fl_Xlib_Graphics_Driver::yxline_unscaled(float x, float y, float y1) {//OK + x+=offset_x_*scale_; y+=offset_y_*scale_; y1 += offset_y_*scale_; + int tw = line_width_ ? line_width_ : 1; // true line width + if (y > y1) { float exch = y; y = y1; y1 = exch; } + int ix = clip_x(x+line_delta_); + int iy = clip_x(y+line_delta_); if (scale_ >= 2) iy -= int(scale_/2); + int iy1 = int(y1/scale_+1.5)*scale_-1; if (scale_ >= 2) iy1 += int(scale_/2); if (scale_ >= 4) iy1 -= scale_/2; + XDrawLine(fl_display, fl_window, gc_, ix, iy, ix, iy1); + // try and make sure no unfilled area lies between yxline(x,y,y1) and yxline(x+1,y,y1) + if (x+line_delta_+scale_ >= ix + tw+1 -0.001) XDrawLine(fl_display, fl_window, gc_, ix+1, iy, ix+1, iy1); } -void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2) { +void Fl_Xlib_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2) { + x+=offset_x_*scale_; y+=offset_y_*scale_; y1 += offset_y_*scale_; x2+=offset_x_*scale_; + if (scale_ >= 2) { + int delta = int(scale_/2 + 0.5); + if (y > y1) y += delta; else y -= delta; + if (x2 > x) x2 += delta; else x2 -= delta; + } XPoint p[3]; - p[0].x = p[1].x = clip_x(x+offset_x_); p[0].y = clip_x(y+offset_y_); - p[1].y = p[2].y = clip_x(y1+offset_y_); p[2].x = clip_x(x2+offset_x_); + p[0].x = p[1].x = clip_x(x+line_delta_); p[0].y = clip_x(y+line_delta_); + p[1].y = p[2].y = clip_x(y1+line_delta_); p[2].x = clip_x(x2+line_delta_); XDrawLines(fl_display, fl_window, gc_, p, 3, 0); } -void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { +void Fl_Xlib_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2, float y3) { + x+=offset_x_*scale_; y+=offset_y_*scale_; y1 += offset_y_*scale_; x2+=offset_x_*scale_; y3 += offset_y_*scale_; + if (scale_ >= 2) { + int delta = int(scale_/2 + 0.5); + if (y > y1) y += delta; else y -= delta; + if (y3 > y1) y3 += delta; else y3 -= delta; + } XPoint p[4]; - p[0].x = p[1].x = clip_x(x+offset_x_); p[0].y = clip_x(y+offset_y_); - p[1].y = p[2].y = clip_x(y1+offset_y_); p[2].x = p[3].x = clip_x(x2+offset_x_); - p[3].y = clip_x(y3+offset_y_); + p[0].x = p[1].x = clip_x(x+line_delta_); p[0].y = clip_x(y+line_delta_); + p[1].y = p[2].y = clip_x(y1+line_delta_); p[2].x = p[3].x = clip_x(x2+line_delta_); + p[3].y = clip_x(y3+line_delta_); XDrawLines(fl_display, fl_window, gc_, p, 4, 0); } -void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) { +void Fl_Xlib_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2) { XPoint p[4]; - p[0].x = x+offset_x_; p[0].y = y+offset_y_; - p[1].x = x1+offset_x_; p[1].y = y1+offset_y_; - p[2].x = x2+offset_x_; p[2].y = y2+offset_y_; - p[3].x = x+offset_x_; p[3].y = y+offset_y_; + p[0].x = x +offset_x_*scale_+line_delta_; p[0].y = y +offset_y_*scale_+line_delta_; + p[1].x = x1 +offset_x_*scale_+line_delta_; p[1].y = y1 +offset_y_*scale_+line_delta_; + p[2].x = x2 +offset_x_*scale_+line_delta_; p[2].y = y2 +offset_y_*scale_+line_delta_; + p[3].x = x +offset_x_*scale_+line_delta_; p[3].y = y +offset_y_*scale_+line_delta_; XDrawLines(fl_display, fl_window, gc_, p, 4, 0); } -void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { +void Fl_Xlib_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) { XPoint p[5]; - p[0].x = x+offset_x_; p[0].y = y+offset_y_; - p[1].x = x1+offset_x_; p[1].y = y1+offset_y_; - p[2].x = x2+offset_x_; p[2].y = y2+offset_y_; - p[3].x = x3+offset_x_; p[3].y = y3+offset_y_; - p[4].x = x+offset_x_; p[4].y = y+offset_y_; + p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_; + p[1].x = x1 +offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_; + p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_; + p[3].x = x3+offset_x_*scale_+line_delta_; p[3].y = y3+offset_y_*scale_+line_delta_; + p[4].x = x+offset_x_*scale_+line_delta_; p[4].y = y+offset_y_*scale_+line_delta_; XDrawLines(fl_display, fl_window, gc_, p, 5, 0); } -void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) { +void Fl_Xlib_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2) { XPoint p[4]; - p[0].x = x+offset_x_; p[0].y = y+offset_y_; - p[1].x = x1+offset_x_; p[1].y = y1+offset_y_; - p[2].x = x2+offset_x_; p[2].y = y2+offset_y_; - p[3].x = x+offset_x_; p[3].y = y+offset_y_; + p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_; + p[1].x = x1+offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_; + p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_; + p[3].x = x+offset_x_*scale_+line_delta_; p[3].y = y+offset_y_*scale_+line_delta_; XFillPolygon(fl_display, fl_window, gc_, p, 3, Convex, 0); XDrawLines(fl_display, fl_window, gc_, p, 4, 0); } -void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { +void Fl_Xlib_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) { XPoint p[5]; - p[0].x = x+offset_x_; p[0].y = y+offset_y_; - p[1].x = x1+offset_x_; p[1].y = y1+offset_y_; - p[2].x = x2+offset_x_; p[2].y = y2+offset_y_; - p[3].x = x3+offset_x_; p[3].y = y3+offset_y_; - p[4].x = x+offset_x_; p[4].y = y+offset_y_; + p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_; + p[1].x = x1+offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_; + p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_; + p[3].x = x3+offset_x_*scale_+line_delta_; p[3].y = y3+offset_y_*scale_+line_delta_; + p[4].x = x+offset_x_*scale_+line_delta_; p[4].y = y+offset_y_*scale_+line_delta_; XFillPolygon(fl_display, fl_window, gc_, p, 4, Convex, 0); XDrawLines(fl_display, fl_window, gc_, p, 5, 0); } @@ -276,7 +331,7 @@ void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) { Fl_Region r; if (w > 0 && h > 0) { - r = XRectangleRegion(x+offset_x_,y+offset_y_,w,h); + r = XRectangleRegion(x,y,w,h); Fl_Region current = rstack[rstackptr]; if (current) { Fl_Region temp = XCreateRegion(); @@ -294,8 +349,6 @@ void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) { int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ X = x; Y = y; W = w; H = h; - x += offset_x_; - y += offset_y_; Fl_Region r = rstack[rstackptr]; if (!r) return 0; switch (XRectInRegion(r, x, y, w, h)) { @@ -312,15 +365,13 @@ int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y XIntersectRegion(r, rr, temp); XRectangle rect; XClipBox(temp, &rect); - X = rect.x - offset_x_; Y = rect.y - offset_y_; W = rect.width; H = rect.height; + X = rect.x; Y = rect.y; W = rect.width; H = rect.height; XDestroyRegion(temp); XDestroyRegion(rr); return 1; } int Fl_Xlib_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - x += offset_x_; - y += offset_y_; if (x+w <= 0 || y+h <= 0) return 0; Fl_Region r = rstack[rstackptr]; if (!r) return 1; @@ -348,8 +399,12 @@ void Fl_Xlib_Graphics_Driver::pop_clip() { void Fl_Xlib_Graphics_Driver::restore_clip() { fl_clip_state_number++; if (gc_) { - Fl_Region r = rstack[rstackptr]; - if (r) XSetRegion(fl_display, gc_, r); + Region r = rstack[rstackptr]; + if (r) { + Region r2 = scale_clip(scale_); + XSetRegion(fl_display, gc_, rstack[rstackptr]); + unscale_clip(r2); + } else XSetClipMask(fl_display, gc_, 0); } } diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx index 05c58eb8d..d36b540e7 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx @@ -3,7 +3,7 @@ // // Portable drawing routines for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 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 @@ -30,14 +30,6 @@ #include <FL/math.h> -void Fl_Xlib_Graphics_Driver::transformed_vertex(double xf, double yf) { - transformed_vertex0(short(rint(xf)), short(rint(yf))); -} - -void Fl_Xlib_Graphics_Driver::vertex(double x,double y) { - transformed_vertex0(short(x*m.a + y*m.c + m.x), short(x*m.b + y*m.d + m.y)); -} - void Fl_Xlib_Graphics_Driver::end_points() { if (n>1) XDrawPoints(fl_display, fl_window, gc_, (XPoint*)p, n, 0); } @@ -52,7 +44,9 @@ void Fl_Xlib_Graphics_Driver::end_line() { void Fl_Xlib_Graphics_Driver::end_loop() { fixloop(); - if (n>2) transformed_vertex((short)p[0].x, (short)p[0].y); + if (n>2) { + transformed_vertex0(p[0].x, p[0].y); + } end_line(); } @@ -73,7 +67,7 @@ void Fl_Xlib_Graphics_Driver::begin_complex_polygon() { void Fl_Xlib_Graphics_Driver::gap() { while (n>gap_+2 && p[n-1].x == p[gap_].x && p[n-1].y == p[gap_].y) n--; if (n > gap_+2) { - transformed_vertex((short)p[gap_].x, (short)p[gap_].y); + transformed_vertex0(p[gap_].x, p[gap_].y); gap_ = n; } else { n = gap_; @@ -92,12 +86,7 @@ void Fl_Xlib_Graphics_Driver::end_complex_polygon() { // shortcut the closed circles so they use XDrawArc: // warning: these do not draw rotated ellipses correctly! // See fl_arc.c for portable version. - -void Fl_Xlib_Graphics_Driver::circle(double x, double y,double r) { - double xt = transform_x(x,y); - double yt = transform_y(x,y); - double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); - double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); +void Fl_Xlib_Graphics_Driver::ellipse_unscaled(double xt, double yt, double rx, double ry) { int llx = (int)rint(xt-rx); int w = (int)rint(xt+rx)-llx; int lly = (int)rint(yt-ry); diff --git a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx index 49a84e7d8..fa2aaeb5d 100644 --- a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx @@ -24,12 +24,13 @@ #include "Fl_Xlib_Graphics_Driver.H" #include <FL/Fl_Image_Surface.H> #include "Fl_Xlib_Graphics_Driver.H" +#include <FL/Fl_Screen_Driver.H> class Fl_Xlib_Image_Surface_Driver : public Fl_Image_Surface_Driver { - friend class Fl_Image_Surface; virtual void end_current_(Fl_Surface_Device *next_current); public: Window pre_window; + int was_high; Fl_Xlib_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off); ~Fl_Xlib_Image_Surface_Driver(); void set_current(); @@ -44,11 +45,18 @@ Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, i } Fl_Xlib_Image_Surface_Driver::Fl_Xlib_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) { + float d = 1; if (!off) { fl_open_display(); + d = fl_graphics_driver->scale(); + if (d != 1 && high_res) { + w = int(w*d); + h = int(h*d); + } offscreen = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth); } driver(new Fl_Xlib_Graphics_Driver()); + if (d != 1 && high_res) ((Fl_Xlib_Graphics_Driver*)driver())->scale(d); } Fl_Xlib_Image_Surface_Driver::~Fl_Xlib_Image_Surface_Driver() { @@ -73,9 +81,7 @@ void Fl_Xlib_Image_Surface_Driver::untranslate() { Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image() { - unsigned char *data = fl_read_image(NULL, 0, 0, width, height, 0); - Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height); - image->alloc_array = 1; + Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, width, height, 0); return image; } |
