X11+XRender platform: more accurate drawing of RGB images when GUI is scaled.

RGB images are now drawn to a size that exactly fit discretised rectangles when non
integral GUI scaling values are used.
This commit is contained in:
ManoloFLTK 2021-11-25 11:19:10 +01:00
parent bf470919f7
commit 2f50640732
2 changed files with 19 additions and 9 deletions

View File

@ -774,8 +774,10 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int
Window xid = (win && !allow_outside ? fl_xid(win) : fl_window);
float s = allow_outside ? Fl::screen_driver()->scale(win->screen_num()) : Fl_Surface_Device::surface()->driver()->scale();
int Xs = Fl_Scalable_Graphics_Driver::floor(X, s), Ys = Fl_Scalable_Graphics_Driver::floor(Y, s),
ws = Fl_Scalable_Graphics_Driver::floor(X+w, s) - Xs, hs = Fl_Scalable_Graphics_Driver::floor(Y+h, s) - Ys;
int Xs = Fl_Scalable_Graphics_Driver::floor(X, s);
int Ys = Fl_Scalable_Graphics_Driver::floor(Y, s);
int ws = Fl_Scalable_Graphics_Driver::floor(X+w, s) - Xs;
int hs = Fl_Scalable_Graphics_Driver::floor(Y+h, s) - Ys;
# ifdef __sgi
if (XReadDisplayQueryExtension(fl_display, &i, &i)) {
@ -800,12 +802,14 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int
sw = screens[ns].width;
sh = screens[ns].height;
}
#if ! HAVE_XRENDER
if (win && !allow_outside && int(s) != s) {
ws = (w+1) * s; // approximates what Fl_Graphics_Driver::cache_size() does
hs = (h+1) * s;
if (Xs + ws >= int(win->w()*s)) ws = win->w()*s - Xs -1;
if (Ys + hs >= int(win->h()*s)) hs = win->h()*s - Ys -1;
}
#endif
if (win && Xs + ws >= int(win->w()*s)) ws = win->w()*s - Xs -1;
if (win && Ys + hs >= int(win->h()*s)) hs = win->h()*s - Ys -1;
if (ws < 1) ws = 1;
if (hs < 1) hs = 1;
if (!win || (dx >= sx && dy >= sy && dx + ws <= sx+sw && dy + hs <= sy+sh) ) {

View File

@ -772,9 +772,15 @@ void Fl_Xlib_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP
if (!*Fl_Graphics_Driver::id(rgb)) {
cache(rgb);
}
push_clip(XP, YP, WP, HP);
int Wfull = rgb->w(), Hfull = rgb->h(), offset = 0;
cache_size(rgb, Wfull, Hfull);
float s = scale();
int Xs = Fl_Scalable_Graphics_Driver::floor(XP - cx, s);
int Wfull = Fl_Scalable_Graphics_Driver::floor(XP - cx + rgb->w(), s) - Xs ;
int Ys = Fl_Scalable_Graphics_Driver::floor(YP - cy, s);
int Hfull = Fl_Scalable_Graphics_Driver::floor(YP - cy + rgb->h(), s) - Ys;
if (Wfull == 0 || Hfull == 0) return;
bool need_clip = (cx || cy || WP < rgb->w() || HP < rgb->h());
if (need_clip) push_clip(XP, YP, WP, HP);
int offset = 0;
if (Wfull > rgb->data_w() || Hfull > rgb->data_h()) {
// When enlarging while drawing with XRender, 1 pixel around target area seems unpainted,
// so we increase a bit the target area and move it 1 pixel to left and top.
@ -783,9 +789,9 @@ void Fl_Xlib_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP
}
scale_and_render_pixmap( *Fl_Graphics_Driver::id(rgb), rgb->d(),
rgb->data_w() / double(Wfull), rgb->data_h() / double(Hfull),
floor(XP-cx) + floor(offset_x_) - offset, floor(YP-cy) + floor(offset_y_) - offset,
Xs + this->floor(offset_x_) - offset, Ys + this->floor(offset_y_) - offset,
Wfull, Hfull);
pop_clip();
if (need_clip) pop_clip();
}
/* Draws with Xrender an Fl_Offscreen with optional scaling and accounting for transparency if necessary.