Browse Source

Fix for issue #155 - continued

The issue lies in details how floating point scaled coordinates are converted
to integer values and its impact on the drawing of large SVG images.
This commit fixes the X11 platform.
The macOS platform is immune because drawing uses floating point
coordinates.
The Windows platform still needs fixing.
pull/166/head
ManoloFLTK 5 years ago
parent
commit
231159e16c
  1. 2
      FL/Fl_Graphics_Driver.H
  2. 2
      FL/Fl_SVG_Image.H
  3. 13
      src/Fl_Graphics_Driver.cxx
  4. 17
      src/Fl_SVG_Image.cxx
  5. 8
      src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx
  6. 2
      src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H
  7. 2
      src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx
  8. 2
      src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx
  9. 10
      src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx

2
FL/Fl_Graphics_Driver.H

@ -236,7 +236,7 @@ protected:
static void draw_empty(Fl_Image* img, int X, int Y) {img->draw_empty(X, Y);} static void draw_empty(Fl_Image* img, int X, int Y) {img->draw_empty(X, Y);}
Fl_Graphics_Driver(); Fl_Graphics_Driver();
virtual void cache_size(int &width, int &height); virtual void cache_size(Fl_Image *img, int &width, int &height);
static unsigned need_pixmap_bg_color; static unsigned need_pixmap_bg_color;
public: public:
virtual ~Fl_Graphics_Driver() {} ///< Destructor virtual ~Fl_Graphics_Driver() {} ///< Destructor

2
FL/Fl_SVG_Image.H

@ -133,6 +133,7 @@ struct NSVGimage;
*/ */
class FL_EXPORT Fl_SVG_Image : public Fl_RGB_Image { class FL_EXPORT Fl_SVG_Image : public Fl_RGB_Image {
friend class Fl_Graphics_Driver;
private: private:
typedef struct { typedef struct {
NSVGimage* svg_image; NSVGimage* svg_image;
@ -146,6 +147,7 @@ private:
float average_weight_; float average_weight_;
float svg_scaling_(int W, int H); float svg_scaling_(int W, int H);
void rasterize_(int W, int H); void rasterize_(int W, int H);
void cache_size(int &width, int &height);
void init_(const char *filename, const char *filedata, Fl_SVG_Image *copy_source); void init_(const char *filename, const char *filedata, Fl_SVG_Image *copy_source);
Fl_SVG_Image(Fl_SVG_Image *source); Fl_SVG_Image(Fl_SVG_Image *source);
public: public:

13
src/Fl_Graphics_Driver.cxx

@ -29,6 +29,7 @@
#include <FL/Fl_Image_Surface.H> #include <FL/Fl_Image_Surface.H>
#include <FL/math.h> #include <FL/math.h>
#include <FL/platform.H> #include <FL/platform.H>
#include <FL/Fl_SVG_Image.H>
FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver; // the current driver of graphics operations FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver; // the current driver of graphics operations
@ -201,7 +202,7 @@ unsigned Fl_Graphics_Driver::font_desc_size() {
/** Converts \p width and \p height from FLTK units to drawing units. /** Converts \p width and \p height from FLTK units to drawing units.
The conversion performed consists in multiplying \p width and \p height by The conversion performed consists in multiplying \p width and \p height by
scale() and in slightly modifying that to help support tiled images. */ scale() and in slightly modifying that to help support tiled images. */
void Fl_Graphics_Driver::cache_size(int &width, int &height) void Fl_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height)
{ {
if ( int(scale()) == scale() ) { if ( int(scale()) == scale() ) {
width = width * scale(); width = width * scale();
@ -210,6 +211,10 @@ void Fl_Graphics_Driver::cache_size(int &width, int &height)
width = (width+1) * scale(); width = (width+1) * scale();
height = (height+1) * scale(); height = (height+1) * scale();
} }
if (img->d() == 4 && ((Fl_RGB_Image*)img)->as_svg_image()) { // check for SVG image
Fl_SVG_Image *svg = (Fl_SVG_Image*)img;
svg->cache_size(width, height);
}
} }
/** Draws an Fl_Pixmap object using this graphics driver. /** Draws an Fl_Pixmap object using this graphics driver.
@ -223,7 +228,7 @@ void Fl_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm, int XP, int YP, int WP, int
} }
// to allow rescale at runtime // to allow rescale at runtime
int w2=pxm->w(), h2=pxm->h(); int w2=pxm->w(), h2=pxm->h();
cache_size(w2, h2); // after this, w2 x h2 is size of desired cached image cache_size(pxm, w2, h2); // after this, w2 x h2 is size of desired cached image
int *pw, *ph; int *pw, *ph;
cache_w_h(pxm, pw, ph); // after this, *pw x *ph is current size of cached form of bitmap cache_w_h(pxm, pw, ph); // after this, *pw x *ph is current size of cached form of bitmap
if (*id(pxm) && (*pw != w2 || *ph != h2)) { if (*id(pxm) && (*pw != w2 || *ph != h2)) {
@ -256,7 +261,7 @@ void Fl_Graphics_Driver::draw_bitmap(Fl_Bitmap *bm, int XP, int YP, int WP, int
return; return;
} }
int w2 = bm->w(), h2 = bm->h(); int w2 = bm->w(), h2 = bm->h();
cache_size(w2, h2); // after this, w2 x h2 is size of desired cached image cache_size(bm, w2, h2); // after this, w2 x h2 is size of desired cached image
int *pw, *ph; int *pw, *ph;
cache_w_h(bm, pw, ph); // after this, *pw x *ph is current size of cached form of bitmap cache_w_h(bm, pw, ph); // after this, *pw x *ph is current size of cached form of bitmap
if (*id(bm) && (*pw != w2 || *ph != h2)) { if (*id(bm) && (*pw != w2 || *ph != h2)) {
@ -296,7 +301,7 @@ void Fl_Graphics_Driver::draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int
int w2, h2, *pw, *ph; int w2, h2, *pw, *ph;
if (need_scaled_drawing) { if (need_scaled_drawing) {
w2 = img->w(); h2 = img->h(); w2 = img->w(); h2 = img->h();
cache_size(w2, h2); cache_size(img, w2, h2);
} else { } else {
w2 = img->data_w(); h2 = img->data_h(); w2 = img->data_w(); h2 = img->data_h();
} // after this, w2 x h2 is desired cached image size } // after this, w2 x h2 is desired cached image size

17
src/Fl_SVG_Image.cxx

@ -221,8 +221,8 @@ void Fl_SVG_Image::resize(int width, int height) {
int w1 = width, h1 = height; int w1 = width, h1 = height;
if (proportional) { if (proportional) {
float f = svg_scaling_(width, height); float f = svg_scaling_(width, height);
w1 = int( int(counted_svg_image_->svg_image->width+0.5)*f + 0.5 ); w1 = int( counted_svg_image_->svg_image->width*f + 0.5 );
h1 = int( int(counted_svg_image_->svg_image->height+0.5)*f + 0.5 ); h1 = int( counted_svg_image_->svg_image->height*f + 0.5 );
} }
w(w1); h(h1); w(w1); h(h1);
if (rasterized_ && w1 == raster_w_ && h1 == raster_h_) return; if (rasterized_ && w1 == raster_w_ && h1 == raster_h_) return;
@ -235,6 +235,17 @@ void Fl_SVG_Image::resize(int width, int height) {
} }
void Fl_SVG_Image::cache_size(int &width, int &height) {
if (proportional) {
// Keep the rasterized image proportional to its source-level width and height
// while maintaining it large enough to allow image tiling.
float f = counted_svg_image_->svg_image->width / counted_svg_image_->svg_image->height;
if (height * f >= width) width = height * f + 0.5;
else height = width/f + 0.5;
}
}
void Fl_SVG_Image::draw(int X, int Y, int W, int H, int cx, int cy) { void Fl_SVG_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
/* There may be several pixels per FLTK unit in an area /* There may be several pixels per FLTK unit in an area
of size w() x h() of the display. This occurs, e.g., with Apple retina displays of size w() x h() of the display. This occurs, e.g., with Apple retina displays
@ -246,7 +257,7 @@ void Fl_SVG_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
int w1 = w(), h1 = h(); int w1 = w(), h1 = h();
int f = fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER) ? 2 : 1; int f = fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER) ? 2 : 1;
int w2 = f*w(), h2 = f*h(); int w2 = f*w(), h2 = f*h();
fl_graphics_driver->cache_size(w2, h2); fl_graphics_driver->cache_size(this, w2, h2);
resize(w2, h2); resize(w2, h2);
scale(w1, h1, 0, 1); scale(w1, h1, 0, 1);
Fl_RGB_Image::draw(X, Y, W, H, cx, cy); Fl_RGB_Image::draw(X, Y, W, H, cx, cy);

8
src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx

@ -400,7 +400,7 @@ 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) { void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Bitmap *bm, int X, int Y, int W, int H, int cx, int cy) {
X = X*scale(); X = X*scale();
Y = Y*scale(); Y = Y*scale();
cache_size(W, H); cache_size(bm, W, H);
cx *= scale(); cy *= scale(); cx *= scale(); cy *= scale();
HDC tempdc = CreateCompatibleDC(gc_); HDC tempdc = CreateCompatibleDC(gc_);
@ -500,7 +500,7 @@ 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) { void Fl_GDI_Graphics_Driver::draw_fixed(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) {
X = X*scale(); X = X*scale();
Y = Y*scale(); Y = Y*scale();
cache_size(W, H); cache_size(img, W, H);
cx *= scale(); cy *= scale(); cx *= scale(); cy *= scale();
if (W + cx > img->data_w()) W = img->data_w() - cx; if (W + cx > img->data_w()) W = img->data_w() - cx;
if (H + cy > img->data_h()) H = img->data_h() - cy; if (H + cy > img->data_h()) H = img->data_h() - cy;
@ -538,7 +538,7 @@ void Fl_GDI_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP,
float scaleW = float(rgb->data_w())/rgb->w(); float scaleW = float(rgb->data_w())/rgb->w();
float scaleH = float(rgb->data_h())/rgb->h(); float scaleH = float(rgb->data_h())/rgb->h();
int W = WP, H = HP; int W = WP, H = HP;
cache_size(W, H); cache_size(rgb, W, H);
HDC new_gc = CreateCompatibleDC(gc_); HDC new_gc = CreateCompatibleDC(gc_);
int save = SaveDC(new_gc); int save = SaveDC(new_gc);
SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb)); SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb));
@ -628,7 +628,7 @@ 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) { void Fl_GDI_Graphics_Driver::draw_fixed(Fl_Pixmap *pxm, int X, int Y, int W, int H, int cx, int cy) {
X = X*scale(); X = X*scale();
Y = Y*scale(); Y = Y*scale();
cache_size(W, H); cache_size(pxm, W, H);
cx *= scale(); cy *= scale(); cx *= scale(); cy *= scale();
Fl_Region r2 = scale_clip(scale()); Fl_Region r2 = scale_clip(scale());
if (*Fl_Graphics_Driver::mask(pxm)) { if (*Fl_Graphics_Driver::mask(pxm)) {

2
src/drivers/Quartz/Fl_Quartz_Graphics_Driver.H

@ -59,7 +59,7 @@ protected:
CGLineJoin quartz_line_join_; CGLineJoin quartz_line_join_;
CGFloat *quartz_line_pattern; CGFloat *quartz_line_pattern;
int quartz_line_pattern_size; int quartz_line_pattern_size;
virtual void cache_size(int &width, int &height); virtual void cache_size(Fl_Image* img, int &width, int &height);
public: public:
Fl_Quartz_Graphics_Driver(); Fl_Quartz_Graphics_Driver();
virtual ~Fl_Quartz_Graphics_Driver() { if (p) free(p); } virtual ~Fl_Quartz_Graphics_Driver() { if (p) free(p); }

2
src/drivers/Quartz/Fl_Quartz_Graphics_Driver.cxx

@ -154,7 +154,7 @@ void Fl_Quartz_Graphics_Driver::XDestroyRegion(Fl_Region r) {
} }
} }
void Fl_Quartz_Graphics_Driver::cache_size(int &width, int &height) { void Fl_Quartz_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) {
width *= 2 * scale(); width *= 2 * scale();
height *= 2 * scale(); height *= 2 * scale();
} }

2
src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx

@ -86,7 +86,7 @@ void Fl_Xlib_Graphics_Driver::scale(float f) {
Setting line_delta_ to 1 and offsetting all line, rectangle, text and clip 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. coordinates by line_delta_ achieves what is wanted until scale_ <= 3.5.
*/ */
line_delta_ = (scale() > 1.75 ? 1 : 0); line_delta_ = (scale() > 1.9/*1.75*/ ? 1 : 0);
} }
#endif #endif
} }

10
src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx

@ -625,7 +625,7 @@ void Fl_Xlib_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) {
void Fl_Xlib_Graphics_Driver::draw_fixed(Fl_Bitmap *bm, int X, int Y, int W, int H, int cx, int cy) { void Fl_Xlib_Graphics_Driver::draw_fixed(Fl_Bitmap *bm, int X, int Y, int W, int H, int cx, int cy) {
X = (X+offset_x_)*scale(); X = (X+offset_x_)*scale();
Y = (Y+offset_y_)*scale(); Y = (Y+offset_y_)*scale();
cache_size(W, H); cache_size(bm, W, H);
cx *= scale(); cy *= scale(); cx *= scale(); cy *= scale();
XSetStipple(fl_display, gc_, *Fl_Graphics_Driver::id(bm)); XSetStipple(fl_display, gc_, *Fl_Graphics_Driver::id(bm));
int ox = X-cx; if (ox < 0) ox += bm->w()*scale(); int ox = X-cx; if (ox < 0) ox += bm->w()*scale();
@ -727,7 +727,7 @@ void Fl_Xlib_Graphics_Driver::cache(Fl_RGB_Image *img) {
void Fl_Xlib_Graphics_Driver::draw_fixed(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { void Fl_Xlib_Graphics_Driver::draw_fixed(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) {
X = (X+offset_x_)*scale(); X = (X+offset_x_)*scale();
Y = (Y+offset_y_)*scale(); Y = (Y+offset_y_)*scale();
cache_size(W, H); cache_size(img, W, H);
cx *= scale(); cy *= scale(); cx *= scale(); cy *= scale();
if (img->d() == 1 || img->d() == 3) { if (img->d() == 1 || img->d() == 3) {
XCopyArea(fl_display, *Fl_Graphics_Driver::id(img), fl_window, gc_, cx, cy, W, H, X, Y); XCopyArea(fl_display, *Fl_Graphics_Driver::id(img), fl_window, gc_, cx, cy, W, H, X, Y);
@ -764,9 +764,9 @@ void Fl_Xlib_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb, int XP, int YP, int WP
if (!*Fl_Graphics_Driver::id(rgb)) { if (!*Fl_Graphics_Driver::id(rgb)) {
cache(rgb); cache(rgb);
} }
cache_size(W, H); cache_size(rgb, W, H);
int Wfull = rgb->w(), Hfull = rgb->h(); int Wfull = rgb->w(), Hfull = rgb->h();
cache_size(Wfull, Hfull); cache_size(rgb, Wfull, Hfull);
scale_and_render_pixmap( *Fl_Graphics_Driver::id(rgb), rgb->d(), scale_and_render_pixmap( *Fl_Graphics_Driver::id(rgb), rgb->d(),
rgb->data_w() / double(Wfull), rgb->data_h() / double(Hfull), rgb->data_w() / double(Wfull), rgb->data_h() / double(Hfull),
cx*scale(), cy*scale(), (X + offset_x_)*scale(), (Y + offset_y_)*scale(), W, H); cx*scale(), cy*scale(), (X + offset_x_)*scale(), (Y + offset_y_)*scale(), W, H);
@ -829,7 +829,7 @@ void Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap *bm) {
void Fl_Xlib_Graphics_Driver::draw_fixed(Fl_Pixmap *pxm, int X, int Y, int W, int H, int cx, int cy) { void Fl_Xlib_Graphics_Driver::draw_fixed(Fl_Pixmap *pxm, int X, int Y, int W, int H, int cx, int cy) {
X = (X+offset_x_)*scale(); X = (X+offset_x_)*scale();
Y = (Y+offset_y_)*scale(); Y = (Y+offset_y_)*scale();
cache_size(W, H); cache_size(pxm, W, H);
cx *= scale(); cy *= scale(); cx *= scale(); cy *= scale();
Fl_Region r2 = scale_clip(scale()); Fl_Region r2 = scale_clip(scale());
if (*Fl_Graphics_Driver::mask(pxm)) { if (*Fl_Graphics_Driver::mask(pxm)) {

Loading…
Cancel
Save