diff options
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx | 2 | ||||
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver.H | 18 | ||||
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx | 21 | ||||
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx | 22 | ||||
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx | 134 | ||||
| -rw-r--r-- | src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx | 10 |
6 files changed, 132 insertions, 75 deletions
diff --git a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx index 7117c6c49..b73c72e8d 100644 --- a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx +++ b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx @@ -75,7 +75,7 @@ Fl_GDI_Copy_Surface_Driver::~Fl_GDI_Copy_Surface_Driver() { SetClipboardData (CF_ENHMETAFILE, hmf); // then put a BITMAP version of the graphics in the clipboard float scaling = driver()->scale(); - int W = int(width * scaling), H = int(height * scaling); + int W = Fl_GDI_Graphics_Driver::floor(width, scaling), H = Fl_GDI_Graphics_Driver::floor(height, scaling); RECT rect = {0, 0, W, H}; Fl_Image_Surface *surf = new Fl_Image_Surface(W, H); Fl_Surface_Device::push_current(surf); diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H index e2a29da4c..d322bc8af 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.H +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver.H @@ -58,6 +58,11 @@ public: char can_do_alpha_blending(); virtual void gc(void *ctxt) { gc_ = (HDC)ctxt; global_gc(); } virtual void *gc() {return gc_;} + // This function aims to compute accurately int(x * s) in + // presence of rounding errors existing with floating point numbers + // and that sometimes differ between 32 and 64 bits. + static inline int floor(int x, float s) { return int(x * s + 0.001f); } + inline int floor(int x) { return Fl_GDI_Graphics_Driver::floor(x, scale()); } // --- bitmap stuff Fl_Bitmask create_bitmask(int w, int h, const uchar *array); @@ -96,14 +101,18 @@ public: protected: void transformed_vertex0(float x, float y); void fixloop(); - virtual void point_unscaled(float x, float y); + virtual void point(int x, int y); virtual void rect(int x, int y, int w, int h); void focus_rect(int x, int y, int w, int h); - void rectf_unscaled(float x, float y, float w, float h); + virtual void rectf(int x, int y, int w, int 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 yxline_unscaled(float x, float y, float y1); + virtual void xyline(int x, int y, int x1); + virtual void xyline(int x, int y, int x1, int y2); + virtual void xyline(int x, int y, int x1, int y2, int x3); + virtual void yxline(int x, int y, int y1); + virtual void yxline(int x, int y, int y1, int x2); + virtual void yxline(int x, int y, int y1, int x2, int 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); @@ -144,6 +153,7 @@ protected: virtual void font_name(int num, const char *name); void global_gc(); virtual void overlay_rect(int x, int y, int w , int h); + virtual void cache_size(Fl_Image *img, int &width, int &height); }; diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx index dd9ed5dbc..09dd6fa45 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx @@ -260,15 +260,14 @@ HRGN Fl_GDI_Graphics_Driver::scale_region(HRGN r, float f, Fl_GDI_Graphics_Drive pt.y = int(pt.y * (f - 1)); } RECT *rects = (RECT*)&(pdata->Buffer); - int delta = (f > 1.75 ? 1 : 0) - int(f/2); for (DWORD i = 0; i < pdata->rdh.nCount; i++) { - int x = int(rects[i].left * f) + pt.x; - int y = int(rects[i].top * f) + pt.y; + int x = Fl_GDI_Graphics_Driver::floor(rects[i].left, f) + pt.x; + int y = Fl_GDI_Graphics_Driver::floor(rects[i].top, f) + pt.y; RECT R2; - R2.left = x + delta; - R2.top = y + delta; - R2.right = int(rects[i].right * f) + pt.x - x + R2.left; - R2.bottom = int(rects[i].bottom * f) + pt.y - y + R2.top; + R2.left = x; + R2.top = y; + R2.right = Fl_GDI_Graphics_Driver::floor(rects[i].right, f) + pt.x - x + R2.left; + R2.bottom = Fl_GDI_Graphics_Driver::floor(rects[i].bottom, f) + pt.y - y + R2.top; rects[i] = R2; } r = ExtCreateRegion(NULL, size, pdata); @@ -287,3 +286,11 @@ Fl_Region Fl_GDI_Graphics_Driver::scale_clip(float f) { void Fl_GDI_Graphics_Driver::set_current_() { restore_clip(); } + +void Fl_GDI_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) +{ + float s = scale(); + width = (s == int(s) ? width * int(s) : floor(width+1)); + height = (s == int(s) ? height * int(s) : floor(height+1)); + cache_size_finalize(img, width, height); +} diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx index 0135eb638..29fd653b5 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx @@ -398,10 +398,10 @@ void Fl_GDI_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) { } void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Bitmap *bm, int X, int Y, int W, int H, int cx, int cy) { - X = int(X * scale()); - Y = int(Y * scale()); + X = this->floor(X); + Y = this->floor(Y); cache_size(bm, W, H); - cx = int(cx * scale()); cy = int(cy * scale()); + cx = this->floor(cx); cy = this->floor(cy); HDC tempdc = CreateCompatibleDC(gc_); int save = SaveDC(tempdc); @@ -499,10 +499,10 @@ void Fl_GDI_Graphics_Driver::cache(Fl_RGB_Image *img) void Fl_GDI_Graphics_Driver::draw_fixed(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { - X = int(X * scale()); - Y = int(Y * scale()); + X = this->floor(X); + Y = this->floor(Y); cache_size(img, W, H); - cx = int(cx * scale()); cy = int(cy * scale()); + cx = this->floor(cx); cy = this->floor(cy); if (W + cx > img->data_w()) W = img->data_w() - cx; if (H + cy > img->data_h()) H = img->data_h() - cy; if (!*Fl_Graphics_Driver::id(img)) { @@ -547,10 +547,10 @@ void Fl_GDI_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP, int save = SaveDC(new_gc); SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb)); if ( (rgb->d() % 2) == 0 ) { - alpha_blend_(int(XP*scale()), int(YP*scale()), W, H, new_gc, 0, 0, rgb->data_w(), rgb->data_h()); + alpha_blend_(this->floor(XP), this->floor(YP), W, H, new_gc, 0, 0, rgb->data_w(), rgb->data_h()); } else { SetStretchBltMode(gc_, HALFTONE); - StretchBlt(gc_, int(XP*scale()), int(YP*scale()), W, H, new_gc, 0, 0, rgb->data_w(), rgb->data_h(), SRCCOPY); + StretchBlt(gc_, this->floor(XP), this->floor(YP), W, H, new_gc, 0, 0, rgb->data_w(), rgb->data_h(), SRCCOPY); } RestoreDC(new_gc, save); DeleteDC(new_gc); @@ -631,10 +631,10 @@ void Fl_GDI_Graphics_Driver::cache(Fl_Bitmap *bm) { } void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Pixmap *pxm, int X, int Y, int W, int H, int cx, int cy) { - X = int(X * scale()); - Y = int(Y * scale()); + X = this->floor(X); + Y = this->floor(Y); cache_size(pxm, W, H); - cx = int(cx * scale()); cy = int(cy * scale()); + cx = this->floor(cx); cy = this->floor(cy); Fl_Region r2 = scale_clip(scale()); if (*Fl_Graphics_Driver::mask(pxm)) { HDC new_gc = CreateCompatibleDC(gc_); diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx index 8e45c6eb9..4a8daebb1 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx @@ -31,47 +31,51 @@ // --- line and polygon drawing with integer coordinates -void Fl_GDI_Graphics_Driver::point_unscaled(float fx, float fy) { - int width = (scale() >= 1 ? int(scale()) : 1); - RECT rect; - rect.left = int(fx); rect.top = int(fy); - rect.right = int(fx) + width; rect.bottom = int(fy) + width; - FillRect(gc_, &rect, fl_brush()); +void Fl_GDI_Graphics_Driver::point(int x, int y) { + rectf(x, y, 1, 1); } void Fl_GDI_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { // make pen have a one-pixel width line_style_unscaled( (color()==FL_WHITE?FL_SOLID:FL_DOT), 1, NULL); - loop(x, y, x+w-1, y, x+w-1, y+h-1, x, y+h-1); + int right = this->floor(x+w-1), bottom = this->floor(y+h-1); + x = this->floor(x); y = this->floor(y); + MoveToEx(gc_, x, y, 0L); + LineTo(gc_, right, y); + LineTo(gc_, right, bottom); + LineTo(gc_, x, bottom); + LineTo(gc_, x, y); } void Fl_GDI_Graphics_Driver::rect(int x, int y, int w, int h) { if (w > 0 && h > 0) { - float s = scale(); - xyline_unscaled(x*s, y*s, (x+w-1)*s); - yxline_unscaled(x*s, y*s, (y+h-1)*s); - yxline_unscaled((x+w-1)*s, y*s, (y+h-1)*s); - xyline_unscaled(x*s, (y+h-1)*s, (x+w-1)*s); + xyline(x, y, (x+w-1)); + yxline(x, y, (y+h-1)); + yxline((x+w-1), y, (y+h-1)); + xyline(x, (y+h-1), (x+w-1)); } } void Fl_GDI_Graphics_Driver::focus_rect(int x, int y, int w, int h) { // Windows 95/98/ME do not implement the dotted line style, so draw // every other pixel around the focus area... - w--; h--; + w = floor(x+w-1) - floor(x) + 1; + h = floor(y+h-1) - floor(y) + 1; + x = floor(x); y = floor(y); int i=1, xx, yy; - for (xx = 0; xx < w; xx++, i++) if (i & 1) point(x + xx, y); - for (yy = 0; yy < h; yy++, i++) if (i & 1) point(x + w, y + yy); - for (xx = w; xx > 0; xx--, i++) if (i & 1) point(x + xx, y + h); - for (yy = h; yy > 0; yy--, i++) if (i & 1) point(x, y + yy); + COLORREF c = fl_RGB(); + for (xx = 0; xx < w; xx++, i++) if (i & 1) SetPixel(gc_, x+xx, y, c); + for (yy = 0; yy < h; yy++, i++) if (i & 1) SetPixel(gc_, x+w, y+yy, c); + for (xx = w; xx > 0; xx--, i++) if (i & 1) SetPixel(gc_, x+xx, y+h, c); + for (yy = h; yy > 0; yy--, i++) if (i & 1) SetPixel(gc_, x, y+yy, c); } -void Fl_GDI_Graphics_Driver::rectf_unscaled(float x, float y, float w, float h) { +void Fl_GDI_Graphics_Driver::rectf(int x, int y, int w, int h) { if (w<=0 || h<=0) return; RECT rect; - rect.left = int(x); rect.top = int(y); - rect.right = int(x + w); rect.bottom = int(y + h); + rect.left = this->floor(x); rect.top = this->floor(y); + rect.right = this->floor(x + w); rect.bottom = this->floor(y + h); FillRect(gc_, &rect, fl_brush()); } @@ -88,38 +92,74 @@ void Fl_GDI_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1, SetPixel(gc_, int(x2), int(y2), fl_RGB()); } -void Fl_GDI_Graphics_Driver::xyline_unscaled(float x, float y, float x1) { - int line_delta_ = (scale() > 1.75 ? 1 : 0); - int tw = line_width_ ? line_width_ : 1; // true line width - if (x > x1) { float exch = x; x = x1; x1 = exch; } - int ix = int(x) + line_delta_; if (scale() >= 2.f) ix -= int(scale()/2); - int iy = int(y) + line_delta_; - if (scale() > 1.9 && line_width_/scale() >= 2) iy--; - int ix1 = int( int(x1/scale()+1.5f) * scale() ) - 1; // extend line to pixel before line beginning at x1/scale_ + 1 - ix1 += line_delta_; if (scale() >= 2) ix1 -= 1;; if (scale() >= 4) ix1 -= 1; - MoveToEx(gc_, ix, iy, 0L); LineTo(gc_, ix1+1, iy); - // try and make sure no unfilled area lies between xyline(x,y,x1) and xyline(x,y+1,x1) - if (int(scale()) != scale() && y+line_delta_ + scale() >= iy + tw+1 - 0.001 ) { - MoveToEx(gc_, ix, iy+1, 0L); LineTo(gc_, ix1+1, iy+1); +static HPEN change_pen_width(int width, HDC gc) { // set the width of the pen, return previous pen + LOGBRUSH penbrush = {BS_SOLID, fl_RGB(), 0}; + HPEN newpen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_FLAT | PS_JOIN_ROUND, width, &penbrush, 0, 0); + return (HPEN)SelectObject(gc, newpen); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1) { + if (y < 0) return; + float s = scale(); + int xx = (x < x1 ? x : x1); + int xx1 = (x < x1 ? x1 : x); + if (s != int(s) && line_width_ <= int(s)) { + int lwidth = this->floor((y+1)) - this->floor(y); + bool need_pen = (lwidth != int(s)); + HPEN oldpen = (need_pen ? change_pen_width(lwidth, gc_) : NULL); + MoveToEx(gc_, this->floor(xx), this->floor(y) + int(lwidth/2.f) , 0L); + LineTo(gc_, this->floor((xx1+1)), this->floor(y) + int(lwidth/2.f)); + if (need_pen) { + DeleteObject(SelectObject(gc_, oldpen)); + } + } else { + y = int((y + 0.5f) * s); + MoveToEx(gc_, this->floor(xx), y, 0L); + LineTo(gc_, this->floor(xx1) + int(s) , y); } } -void Fl_GDI_Graphics_Driver::yxline_unscaled(float x, float y, float y1) { - if (y1 < y) { float exch = y; y = y1; y1 = exch;} - int line_delta_ = (scale() > 1.75 ? 1 : 0); - int tw = line_width_ ? line_width_ : 1; // true line width - - int ix = int(x) + line_delta_; - if (scale() > 1.9 && line_width_/scale() >= 2) ix--; - int iy = int(y) + line_delta_; if (scale() >= 2) iy -= int(scale()/2); - int iy1 = int( int(y1/scale()+1.5) * scale() ) - 1; - iy1 += line_delta_; if (scale() >= 2) iy1 -= 1;; if (scale() >= 4) iy1 -= 1; // extend line to pixel before line beginning at y1/scale_ + 1 - MoveToEx(gc_, ix, iy, 0L); LineTo(gc_, ix, iy1+1); - // try and make sure no unfilled area lies between yxline(x,y,y1) and yxline(x+1,y,y1) - if (int(scale()) != scale() && x+line_delta_+scale() >= ix + tw+1 -0.001) { - MoveToEx(gc_, ix+1, iy, 0L); LineTo(gc_, ix+1, iy1+1); +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2) { + xyline(x, y, x1); + yxline(x1, y, y2); +} + +void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { + xyline(x, y, x1); + yxline(x1, y, y2); + xyline(x1, y2, x3); +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1) { + if (x < 0) return; + double s = scale(); + int yy = (y < y1 ? y : y1); + int yy1 = (y < y1 ? y1 : y); + if (s != int(s) && line_width_ <= int(s)) { + int lwidth = (this->floor((x+1)) - this->floor(x)); + bool need_pen = (lwidth != int(s)); + HPEN oldpen = (need_pen ? change_pen_width(lwidth, gc_) : NULL); + MoveToEx(gc_, this->floor(x) + int(lwidth/2.f), this->floor(yy), 0L); + LineTo(gc_, this->floor(x) + int(lwidth/2.f), this->floor((yy1+1)) ); + if (need_pen) { + DeleteObject(SelectObject(gc_, oldpen)); + } + } else { + x = int((x + 0.5f) * s); + MoveToEx(gc_, x, this->floor(yy), 0L); + LineTo(gc_, x, this->floor(yy1) + int(s)); } +} + +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2) { + yxline(x, y, y1); + xyline(x, y1, x2); +} +void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { + yxline(x, y, y1); + xyline(x, y1, x2); + yxline(x2, y1, y3); } void Fl_GDI_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2) { diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 7c57d08f2..eb437b965 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -20,7 +20,7 @@ #include "../GDI/Fl_Font.H" #include <FL/Fl.H> #include <FL/platform.H> -#include <FL/Fl_Graphics_Driver.H> +#include "../GDI/Fl_GDI_Graphics_Driver.H" #include <FL/Fl_RGB_Image.H> #include <FL/fl_ask.H> #include <stdio.h> @@ -499,14 +499,14 @@ Fl_WinAPI_Screen_Driver::read_win_rectangle( { float s = Fl_Surface_Device::surface()->driver()->scale(); int ws, hs; - if (int(s) == s) { ws = int(w * s); hs = int(h * s);} + if (int(s) == s) { ws = w * int(s); hs = h * int(s);} else { - ws = int((w+1) * s); // approximates what Fl_Graphics_Driver::cache_size() does - hs = int((h+1) * s); + ws = Fl_GDI_Graphics_Driver::floor(w+1, s); // approximates what Fl_Graphics_Driver::cache_size() does + hs = Fl_GDI_Graphics_Driver::floor(h+1, s); if (ws < 1) ws = 1; if (hs < 1) hs = 1; } - return read_win_rectangle_unscaled(int(X*s), int(Y*s), ws, hs, win); + return read_win_rectangle_unscaled(Fl_GDI_Graphics_Driver::floor(X, s), Fl_GDI_Graphics_Driver::floor(Y, s), ws, hs, win); } Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y, int w, int h, Fl_Window *win) |
