From f8db18597a545c245b885ad18dbfb8862161966a Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Sun, 6 Mar 2022 19:47:06 +0100 Subject: [PATCH] Complete class Fl_Cairo_Graphics_Driver using Fl_Wayland_Graphics_Driver --- src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H | 65 +- .../Cairo/Fl_Cairo_Graphics_Driver.cxx | 614 ++++++++++++---- src/drivers/PostScript/Fl_PostScript.cxx | 22 +- .../Fl_PostScript_Graphics_Driver.H | 16 +- .../PostScript/Fl_PostScript_image.cxx | 122 +++- src/drivers/Wayland/Fl_Font.H | 33 - .../Wayland/Fl_Wayland_Graphics_Driver.H | 60 +- .../Wayland/Fl_Wayland_Graphics_Driver.cxx | 667 +----------------- .../Wayland/Fl_Wayland_Window_Driver.cxx | 4 + 9 files changed, 736 insertions(+), 867 deletions(-) delete mode 100644 src/drivers/Wayland/Fl_Font.H diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H index d2b24cb30..98253ffbc 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H @@ -1,7 +1,7 @@ // // Support for Cairo graphics for the Fast Light Tool Kit (FLTK). // -// Copyright 2021 by Bill Spitzak and others. +// Copyright 2021-2022 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 @@ -22,16 +22,28 @@ # define FL_CAIRO_GRAPHICS_DRIVER_H #include +#include -typedef struct _cairo cairo_t; typedef struct _PangoLayout PangoLayout; typedef struct _PangoFontDescription PangoFontDescription; + +class Fl_Cairo_Font_Descriptor : public Fl_Font_Descriptor { +public: + Fl_Cairo_Font_Descriptor(const char* fontname, Fl_Fontsize size); + FL_EXPORT ~Fl_Cairo_Font_Descriptor(); + PangoFontDescription *fontref; + int **width; // array of arrays of character widths +}; + + class FL_EXPORT Fl_Cairo_Graphics_Driver : public Fl_Graphics_Driver { +private: + bool *needs_commit_tag_; // NULL or points to whether cairo surface was drawn to protected: cairo_t *cairo_; PangoLayout *pango_layout_; - void draw_rgb_bitmap_(Fl_Image *img,int XP, int YP, int WP, int HP, int cx, int cy); + int linestyle_; public: Fl_Cairo_Graphics_Driver(); virtual ~Fl_Cairo_Graphics_Driver(); @@ -63,8 +75,12 @@ public: float angle; int left_margin; int top_margin; + static const cairo_format_t cairo_format; - void transformed_draw(const char* s, int n, double x, double y); //precise text placing + void surface_needs_commit() { + if (needs_commit_tag_) *needs_commit_tag_ = true; + } + void needs_commit_tag(bool *tag) { needs_commit_tag_ = tag; } // implementation of drawing methods void color(Fl_Color c); @@ -95,6 +111,11 @@ public: 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 point(int x, int y); + void overlay_rect(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); + void restore_clip(); + int not_clipped(int x, int y, int w, int h); void begin_points(); void begin_line(); @@ -118,20 +139,40 @@ public: void draw_image_mono(const uchar* d, int x,int y,int w,int h, int delta=1, int ld=0); void draw_image(Fl_Draw_Image_Cb call, void* data, int x,int y, int w, int h, int delta=3); void draw_image_mono(Fl_Draw_Image_Cb call, void* data, int x,int y, int w, int h, int delta=1); - - void draw(const char* s, int nBytes, int x, int y) { transformed_draw(s,nBytes,x,y); } - void draw(const char* s, int nBytes, float x, float y) { transformed_draw(s,nBytes,x,y); } - void draw(int angle, const char *str, int n, int x, int y); - void rtl_draw(const char* s, int n, int x, int y); - void draw_pixmap(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy); - void draw_bitmap(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy); - void draw_rgb(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy); // --- Fl_Bitmask create_bitmask(int /*w*/, int /*h*/, const uchar */*array*/) { return 0L; } void ps_origin(int x, int y); void ps_translate(int, int); void ps_untranslate(); + + void draw_cached_pattern_(Fl_Image *img, cairo_pattern_t *pat, int X, int Y, int W, int H, int cx, int cy); + void draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD); + void draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy); + void cache(Fl_RGB_Image *rgb); + void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_); + void draw_bitmap(Fl_Bitmap *bm,int XP, int YP, int WP, int HP, int cx, int cy); + void cache(Fl_Bitmap *img); + void delete_bitmask(Fl_Bitmask bm); + void cache(Fl_Pixmap *pxm); + void draw_pixmap(Fl_Pixmap *rgb,int XP, int YP, int WP, int HP, int cx, int cy); + void uncache_pixmap(fl_uintptr_t p); + + void font(Fl_Font fnum, Fl_Fontsize s); + Fl_Font font() { return Fl_Graphics_Driver::font(); } + void draw(const char* s, int nBytes, int x, int y) { draw(s, nBytes, float(x), float(y)); } + void draw(const char* s, int nBytes, float x, float 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); + int height(); + int descent(); + double width(const char *str, int n); + double width(unsigned c); + void text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h); + virtual PangoFontDescription* pango_font_description(Fl_Font /*fnum*/) { + return ((Fl_Cairo_Font_Descriptor*)font_descriptor())->fontref; + } + }; #endif // FL_CAIRO_GRAPHICS_DRIVER_H diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx index df7ea100c..131cdd511 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx @@ -1,7 +1,7 @@ // // Support for Cairo graphics for the Fast Light Tool Kit (FLTK). // -// Copyright 2021 by Bill Spitzak and others. +// Copyright 2021-2022 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 @@ -29,6 +29,7 @@ #include // abs(int) #include // memcpy() + // duplicated from Fl_PostScript.cxx struct callback_data { const uchar *data; @@ -71,21 +72,26 @@ Fl_Cairo_Graphics_Driver::Fl_Cairo_Graphics_Driver() : Fl_Graphics_Driver() { scale_x = scale_y = 1; angle = 0; left_margin = top_margin = 0; + needs_commit_tag_ = NULL; } Fl_Cairo_Graphics_Driver::~Fl_Cairo_Graphics_Driver() {} +const cairo_format_t Fl_Cairo_Graphics_Driver::cairo_format = CAIRO_FORMAT_ARGB32; + void Fl_Cairo_Graphics_Driver::rectf(int x, int y, int w, int h) { cairo_rectangle(cairo_, x-0.5, y-0.5, w, h); cairo_fill(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::rect(int x, int y, int w, int h) { cairo_rectangle(cairo_, x, y, w-1, h-1); cairo_stroke(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::line(int x1, int y1, int x2, int y2) { @@ -93,6 +99,7 @@ void Fl_Cairo_Graphics_Driver::line(int x1, int y1, int x2, int y2) { cairo_move_to(cairo_, x1, y1); cairo_line_to(cairo_, x2, y2); cairo_stroke(cairo_); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::line(int x0, int y0, int x1, int y1, int x2, int y2) { @@ -101,6 +108,7 @@ void Fl_Cairo_Graphics_Driver::line(int x0, int y0, int x1, int y1, int x2, int cairo_line_to(cairo_, x1, y1); cairo_line_to(cairo_, x2, y2); cairo_stroke(cairo_); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::xyline(int x, int y, int x1) { @@ -108,6 +116,7 @@ void Fl_Cairo_Graphics_Driver::xyline(int x, int y, int x1) { cairo_line_to(cairo_, x1, y); cairo_stroke(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::xyline(int x, int y, int x1, int y2) { @@ -116,6 +125,7 @@ void Fl_Cairo_Graphics_Driver::xyline(int x, int y, int x1, int y2) { cairo_line_to(cairo_, x1, y2); cairo_stroke(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { @@ -125,6 +135,7 @@ void Fl_Cairo_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { cairo_line_to(cairo_, x3, y2); cairo_stroke(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::yxline(int x, int y, int y1) { @@ -132,6 +143,7 @@ void Fl_Cairo_Graphics_Driver::yxline(int x, int y, int y1) { cairo_line_to(cairo_, x, y1); cairo_stroke(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::yxline(int x, int y, int y1, int x2) { @@ -140,6 +152,7 @@ void Fl_Cairo_Graphics_Driver::yxline(int x, int y, int y1, int x2) { cairo_line_to(cairo_, x2, y1); cairo_stroke(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { @@ -149,6 +162,7 @@ void Fl_Cairo_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { cairo_line_to(cairo_, x2, y3); cairo_stroke(cairo_); check_status(); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) { @@ -160,6 +174,7 @@ void Fl_Cairo_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int cairo_close_path(cairo_); cairo_stroke(cairo_); cairo_restore(cairo_); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { @@ -172,7 +187,7 @@ void Fl_Cairo_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int cairo_close_path(cairo_); cairo_stroke(cairo_); cairo_restore(cairo_); - + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) { @@ -184,6 +199,7 @@ void Fl_Cairo_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, i cairo_close_path(cairo_); cairo_fill(cairo_); cairo_restore(cairo_); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { @@ -196,9 +212,11 @@ void Fl_Cairo_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, i cairo_close_path(cairo_); cairo_fill(cairo_); cairo_restore(cairo_); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::line_style(int style, int width, char* dashes) { + linestyle_ = style; if(dashes){ if(dashes != linedash_) strcpy(linedash_,dashes); @@ -275,37 +293,6 @@ void Fl_Cairo_Graphics_Driver::color(Fl_Color c) { Fl_Color Fl_Cairo_Graphics_Driver::color() { return Fl_Graphics_Driver::color(); } -void Fl_Cairo_Graphics_Driver::draw(int rotation, const char *str, int n, int x, int y) -{ - cairo_save(cairo_); - cairo_translate(cairo_, x, y); - cairo_rotate(cairo_, -rotation * M_PI / 180); - this->transformed_draw(str, n, 0, 0); - cairo_restore(cairo_); -} - -void Fl_Cairo_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) { - if (!n) return; - pango_layout_set_font_description(pango_layout_, pango_font_description(Fl_Graphics_Driver::font())); - int pwidth, pheight; - cairo_save(cairo_); - pango_layout_set_text(pango_layout_, str, n); - pango_layout_get_size(pango_layout_, &pwidth, &pheight); - if (pwidth > 0) { - double s = width(str, n); - cairo_translate(cairo_, x, y - height() + descent()); - s = (s/pwidth) * PANGO_SCALE; - cairo_scale(cairo_, s, s); - pango_cairo_show_layout(cairo_, pango_layout_); - } - cairo_restore(cairo_); - check_status(); -} - -void Fl_Cairo_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) { - int w = (int)width(str, n); - transformed_draw(str, n, x - w, y); -} void Fl_Cairo_Graphics_Driver::concat(){ cairo_matrix_t mat = {fl_matrix->a , fl_matrix->b , fl_matrix->c , fl_matrix->d , fl_matrix->x , fl_matrix->y}; @@ -354,31 +341,37 @@ void Fl_Cairo_Graphics_Driver::begin_polygon() { } void Fl_Cairo_Graphics_Driver::vertex(double x, double y) { - if(shape_==POINTS){ + if (shape_==POINTS){ cairo_move_to(cairo_, x, y); gap_=1; return; } - if(gap_){ + if (gap_){ cairo_move_to(cairo_, x, y); gap_=0; - }else + } else { cairo_line_to(cairo_, x, y); + surface_needs_commit(); + } } void Fl_Cairo_Graphics_Driver::curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3) { if(shape_==NONE) return; + if (shape_ == POINTS) Fl_Graphics_Driver::curve(x, y, x1, y1, x2, y2, x3, y3); + else { if(gap_) cairo_move_to(cairo_, x, y); else cairo_line_to(cairo_, x, y); gap_=0; cairo_curve_to(cairo_, x1 , y1 , x2 , y2 , x3 , y3); + } + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::circle(double x, double y, double r){ - if (shape_==NONE){ + if (shape_ == NONE){ cairo_save(cairo_); concat(); cairo_arc(cairo_, x, y, r, 0, 2*M_PI); @@ -386,6 +379,7 @@ void Fl_Cairo_Graphics_Driver::circle(double x, double y, double r){ cairo_restore(cairo_); } else cairo_arc(cairo_, x, y, r, 0, 2*M_PI); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::arc(double x, double y, double r, double start, double a){ @@ -395,6 +389,7 @@ void Fl_Cairo_Graphics_Driver::arc(double x, double y, double r, double start, d cairo_arc(cairo_, x, y, r, -start*M_PI/180, -a*M_PI/180); else cairo_arc_negative(cairo_, x, y, r, -start*M_PI/180, -a*M_PI/180); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::arc(int x, int y, int w, int h, double a1, double a2) { @@ -408,6 +403,7 @@ void Fl_Cairo_Graphics_Driver::arc(int x, int y, int w, int h, double a1, double cairo_translate(cairo_, -x - w/2.0 +0.5 , -y - h/2.0 +0.5); end_line(); cairo_restore(cairo_); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::pie(int x, int y, int w, int h, double a1, double a2) { @@ -419,6 +415,7 @@ void Fl_Cairo_Graphics_Driver::pie(int x, int y, int w, int h, double a1, double arc(0.0,0.0, 1, a2, a1); end_polygon(); cairo_restore(cairo_); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::end_points() { @@ -431,6 +428,7 @@ void Fl_Cairo_Graphics_Driver::end_line() { cairo_stroke(cairo_); cairo_restore(cairo_); shape_=NONE; + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::end_loop(){ @@ -440,6 +438,7 @@ void Fl_Cairo_Graphics_Driver::end_loop(){ cairo_stroke(cairo_); cairo_restore(cairo_); shape_=NONE; + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::end_polygon() { @@ -449,16 +448,24 @@ void Fl_Cairo_Graphics_Driver::end_polygon() { cairo_fill(cairo_); cairo_restore(cairo_); shape_=NONE; + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::transformed_vertex(double x, double y) { - reconcat(); + if (shape_ == POINTS){ + cairo_move_to(cairo_, x, y); + point(x, y); + gap_ = 1; + } else { + reconcat(); if(gap_){ cairo_move_to(cairo_, x, y); gap_=0; }else cairo_line_to(cairo_, x, y); + surface_needs_commit(); concat(); + } } void Fl_Cairo_Graphics_Driver::push_clip(int x, int y, int w, int h) { @@ -538,6 +545,7 @@ void Fl_Cairo_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int rgb->alloc_array = 1; draw_rgb(rgb, ix, iy, iw, ih, 0, 0); delete rgb; + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) @@ -550,6 +558,7 @@ void Fl_Cairo_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy cb_data.D = D; cb_data.LD = LD; draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, abs(D)); + surface_needs_commit(); } void Fl_Cairo_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) @@ -557,76 +566,260 @@ void Fl_Cairo_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb call, void *data draw_image(call, data, ix, iy, iw, ih, D); } -static void destroy_BGRA(void *data) { + +int Fl_Cairo_Graphics_Driver::not_clipped(int x, int y, int w, int h) { + if (!clip_) return 1; + if (clip_->w < 0) return 1; + int X = 0, Y = 0, W = 0, H = 0; + clip_box(x, y, w, h, X, Y, W, H); + if (W) return 1; + return 0; +} + + +int Fl_Cairo_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) { + if (!clip_) { + X = x; Y = y; W = w; H = h; + return 0; + } + if (clip_->w < 0) { + X = x; Y = y; W = w; H = h; + return 1; + } + int ret = 0; + if (x > (X=clip_->x)) {X=x; ret=1;} + if (y > (Y=clip_->y)) {Y=y; ret=1;} + if ((x+w) < (clip_->x+clip_->w)) { + W=x+w-X; + + ret=1; + + }else + W = clip_->x + clip_->w - X; + if(W<0){ + W=0; + return 1; + } + if ((y+h) < (clip_->y+clip_->h)) { + H=y+h-Y; + ret=1; + }else + H = clip_->y + clip_->h - Y; + if(H<0){ + W=0; + H=0; + return 1; + } + return ret; +} + + +void Fl_Cairo_Graphics_Driver::restore_clip() { + if (cairo_) cairo_reset_clip(cairo_); +} + + +void Fl_Cairo_Graphics_Driver::point(int x, int y) { + rectf(x, y, 1, 1); +} + + +void Fl_Cairo_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) { + if (abs(D)<3){ //mono + draw_image_mono(data, ix, iy, iw, ih, D, LD); + return; + } + struct callback_data cb_data; + if (!LD) LD = iw*abs(D); + if (D<0) data += iw*abs(D); + cb_data.data = data; + cb_data.D = D; + cb_data.LD = LD; + Fl_Cairo_Graphics_Driver::draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, abs(D)); +} + + +void Fl_Cairo_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { + cairo_save(cairo_); + cairo_matrix_t mat; + cairo_get_matrix(cairo_, &mat); + float s = (float)mat.xx; + cairo_matrix_init_identity(&mat); + cairo_set_matrix(cairo_, &mat); // use drawing units + int lwidth = s < 1 ? 1 : int(s); + cairo_set_line_width(cairo_, lwidth); + cairo_translate(cairo_, lwidth/2., lwidth/2.); // translate by half of line width + double ddash = (lwidth > 2 ? lwidth : 2); + if (linestyle_ == FL_DOT){ + cairo_set_dash(cairo_, &ddash, 1, 0); // dash size = line width + } + // rectangle in drawing units + int Xs = Fl_Scalable_Graphics_Driver::floor(x, s); + int Ws = Fl_Scalable_Graphics_Driver::floor(x+w-1, s) - Xs; + int Ys = Fl_Scalable_Graphics_Driver::floor(y, s); + int Hs = Fl_Scalable_Graphics_Driver::floor(y+h-1, s) - Ys; + cairo_move_to(cairo_, Xs, Ys); + cairo_line_to(cairo_, Xs+Ws, Ys); + cairo_line_to(cairo_, Xs+Ws, Ys+Hs); + cairo_line_to(cairo_, Xs, Ys+Hs); + cairo_close_path(cairo_); + cairo_stroke(cairo_); + cairo_restore(cairo_); + surface_needs_commit(); +} + + +void Fl_Cairo_Graphics_Driver::draw_cached_pattern_(Fl_Image *img, cairo_pattern_t *pat, int X, int Y, int W, int H, int cx, int cy) { + // compute size of output image in drawing units + cairo_matrix_t matrix; + cairo_get_matrix(cairo_, &matrix); + float s = (float)matrix.xx; + int Xs = Fl_Scalable_Graphics_Driver::floor(X - cx, s); + int Ws = Fl_Scalable_Graphics_Driver::floor(X - cx + img->w(), s) - Xs ; + int Ys = Fl_Scalable_Graphics_Driver::floor(Y - cy, s); + int Hs = Fl_Scalable_Graphics_Driver::floor(Y - cy + img->h(), s) - Ys; + if (Ws == 0 || Hs == 0) return; + cairo_save(cairo_); + if (cx || cy || W < img->w() || H < img->h()) { // clip when necessary + cairo_rectangle(cairo_, X-0.5, Y-0.5, W+1, H+1); + cairo_clip(cairo_); + } + // remove any scaling and the current "0.5" translation useful for lines but bad for images + matrix.xx = matrix.yy = 1; + matrix.x0 -= 0.5 * s; matrix.y0 -= 0.5 * s; + cairo_set_matrix(cairo_, &matrix); + if (img->d() >= 1) cairo_set_source(cairo_, pat); + int offset = 0; + if (Ws >= img->data_w()*1.09 || Hs >= img->data_h()*1.09) { + // When enlarging while drawing, 1 pixel around target area seems unpainted, + // so we increase a bit the target area and move it int(s) pixels to left and top. + Ws = (img->w()+2)*s, Hs = (img->h()+2)*s; + offset = int(s); + } + +//fprintf(stderr,"WHs=%dx%d dataWH=%dx%d s=%.1f offset=%d\n",Ws,Hs,img->data_w(),img->data_h(),s,offset); + cairo_matrix_init_scale(&matrix, double(img->data_w())/Ws, double(img->data_h())/Hs); + cairo_matrix_translate(&matrix, -Xs + offset, -Ys + offset); + cairo_pattern_set_matrix(pat, &matrix); + cairo_mask(cairo_, pat); + cairo_restore(cairo_); + surface_needs_commit(); +} + + +void Fl_Cairo_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + // Don't draw an empty image... + if (!rgb->d() || !rgb->array) { + Fl_Graphics_Driver::draw_empty(rgb, XP, YP); + return; + } + if (start_image(rgb, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { + return; + } + cairo_pattern_t *pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(rgb); + if (!pat) { + cache(rgb); + pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(rgb); + } + draw_cached_pattern_(rgb, pat, X, Y, W, H, cx, cy); +} + + +static cairo_user_data_key_t data_key_for_surface = {}; + +static void dealloc_surface_data(void *data) { delete[] (uchar*)data; } -void Fl_Cairo_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm,int XP, int YP, int WP, int HP, int cx, int cy) { - Fl_RGB_Image *rgb = new Fl_RGB_Image(pxm); - draw_rgb_bitmap_(rgb, XP, YP, WP, HP, cx, cy); - delete rgb; -} -void Fl_Cairo_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy) { - draw_rgb_bitmap_(rgb, XP, YP, WP, HP, cx, cy); -} - -void Fl_Cairo_Graphics_Driver::draw_bitmap(Fl_Bitmap *bitmap,int XP, int YP, int WP, int HP, int cx, int cy) { - draw_rgb_bitmap_(bitmap, XP, YP, WP, HP, cx, cy); -} - -void Fl_Cairo_Graphics_Driver::draw_rgb_bitmap_(Fl_Image *img,int XP, int YP, int WP, int HP, int cx, int cy) -{ - cairo_surface_t *surf; - cairo_format_t format = (img->d() >= 1 ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A1); - int stride = cairo_format_stride_for_width(format, img->data_w()); - uchar *BGRA = new uchar[stride * img->data_h()]; - memset(BGRA, 0, stride * img->data_h()); - if (img->d() >= 1) { // process Fl_RGB_Image of all depths - Fl_RGB_Image *rgb = (Fl_RGB_Image*)img; - int lrgb = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d(); - uchar A = 0xff, R,G,B, *q; - const uchar *r; - float f = 1; - if (rgb->d() >= 3) { // color images - for (int j = 0; j < rgb->data_h(); j++) { - r = rgb->array + j * lrgb; - q = BGRA + j * stride; - for (int i = 0; i < rgb->data_w(); i++) { - R = *r; - G = *(r+1); - B = *(r+2); - if (rgb->d() == 4) { - A = *(r+3); - f = float(A)/0xff; - } - *q = B * f; - *(q+1) = G * f; - *(q+2) = R * f; - *(q+3) = A; - r += rgb->d(); q += 4; - } - } - } else if (rgb->d() == 1 || rgb->d() == 2) { // B&W - for (int j = 0; j < rgb->data_h(); j++) { - r = rgb->array + j * lrgb; - q = BGRA + j * stride; - for (int i = 0; i < rgb->data_w(); i++) { - G = *r; - if (rgb->d() == 2) { - A = *(r+1); - f = float(A)/0xff; - } - *(q) = G * f; - *(q+1) = G * f; - *(q+2) = G * f; - *(q+3) = A; - r += rgb->d(); q += 4; +void Fl_Cairo_Graphics_Driver::cache(Fl_RGB_Image *rgb) { + int stride = cairo_format_stride_for_width(Fl_Cairo_Graphics_Driver::cairo_format, rgb->data_w()); + uchar *BGRA = new uchar[stride * rgb->data_h()]; + memset(BGRA, 0, stride * rgb->data_h()); + int lrgb = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d(); + uchar A = 0xff, R,G,B, *q; + const uchar *r; + float f = 1; + if (rgb->d() >= 3) { // color images + for (int j = 0; j < rgb->data_h(); j++) { + r = rgb->array + j * lrgb; + q = BGRA + j * stride; + for (int i = 0; i < rgb->data_w(); i++) { + R = *r; + G = *(r+1); + B = *(r+2); + if (rgb->d() == 4) { + A = *(r+3); + f = float(A)/0xff; } + *q = B * f; + *(q+1) = G * f; + *(q+2) = R * f; + *(q+3) = A; + r += rgb->d(); q += 4; } } - } else { - Fl_Bitmap *bm = (Fl_Bitmap*)img; + } else if (rgb->d() == 1 || rgb->d() == 2) { // B&W + for (int j = 0; j < rgb->data_h(); j++) { + r = rgb->array + j * lrgb; + q = BGRA + j * stride; + for (int i = 0; i < rgb->data_w(); i++) { + G = *r; + if (rgb->d() == 2) { + A = *(r+1); + f = float(A)/0xff; + } + *(q) = G * f; + *(q+1) = G * f; + *(q+2) = G * f; + *(q+3) = A; + r += rgb->d(); q += 4; + } + } + } + cairo_surface_t *surf = cairo_image_surface_create_for_data(BGRA, Fl_Cairo_Graphics_Driver::cairo_format, rgb->data_w(), rgb->data_h(), stride); + if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) return; + (void)cairo_surface_set_user_data(surf, &data_key_for_surface, BGRA, dealloc_surface_data); + cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); + *Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)pat; +} + + +void Fl_Cairo_Graphics_Driver::uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_) { + cairo_pattern_t *pat = (cairo_pattern_t*)id_; + if (pat) { + cairo_surface_t *surf; + cairo_pattern_get_surface(pat, &surf); + cairo_pattern_destroy(pat); + cairo_surface_destroy(surf); + id_ = 0; + } +} + + +void Fl_Cairo_Graphics_Driver::draw_bitmap(Fl_Bitmap *bm,int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + if (!bm->array) { + draw_empty(bm, XP, YP); + return; + } + if (start_image(bm, XP,YP,WP,HP,cx,cy,X,Y,W,H)) return; + cairo_pattern_t *pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(bm); + if (!pat) { + cache(bm); + pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(bm); + } + if (pat) { + draw_cached_pattern_(bm, pat, X, Y, W, H, cx, cy); + } +} + + +void Fl_Cairo_Graphics_Driver::cache(Fl_Bitmap *bm) { + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_A1, bm->data_w()); + uchar *BGRA = new uchar[stride * bm->data_h()]; + memset(BGRA, 0, stride * bm->data_h()); uchar *r, p; unsigned *q; for (int j = 0; j < bm->data_h(); j++) { @@ -641,26 +834,211 @@ void Fl_Cairo_Graphics_Driver::draw_rgb_bitmap_(Fl_Image *img,int XP, int YP, in if (k % 32 != 0) mask32 <<= 1; else {q++; mask32 = 1;} } } - } - surf = cairo_image_surface_create_for_data(BGRA, format, img->data_w(), img->data_h(), stride); + cairo_surface_t *surf = cairo_image_surface_create_for_data(BGRA, CAIRO_FORMAT_A1, bm->data_w(), bm->data_h(), stride); if (cairo_surface_status(surf) == CAIRO_STATUS_SUCCESS) { - static cairo_user_data_key_t key = {}; - (void)cairo_surface_set_user_data(surf, &key, BGRA, destroy_BGRA); + (void)cairo_surface_set_user_data(surf, &data_key_for_surface, BGRA, dealloc_surface_data); cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); - cairo_save(cairo_); - cairo_rectangle(cairo_, XP-0.5, YP-0.5, WP+1, HP+1); - cairo_clip(cairo_); - if (img->d() >= 1) cairo_set_source(cairo_, pat); - cairo_matrix_t matrix; - cairo_matrix_init_scale(&matrix, double(img->data_w())/(img->w()+1), double(img->data_h())/(img->h()+1)); - cairo_matrix_translate(&matrix, -XP+0.5+cx, -YP+0.5+cy); - cairo_pattern_set_matrix(pat, &matrix); - cairo_mask(cairo_, pat); - cairo_pattern_destroy(pat); - cairo_surface_destroy(surf); - cairo_restore(cairo_); - check_status(); + *Fl_Graphics_Driver::id(bm) = (fl_uintptr_t)pat; } } + +void Fl_Cairo_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm,int XP, int YP, int WP, int HP, int cx, int cy) { + int X, Y, W, H; + // Don't draw an empty image... + if (!pxm->data() || !pxm->w()) { + Fl_Graphics_Driver::draw_empty(pxm, XP, YP); + return; + } + if (start_image(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { + return; + } + cairo_pattern_t *pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(pxm); + if (!pat) { + cache(pxm); + pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(pxm); + } + draw_cached_pattern_(pxm, pat, X, Y, W, H, cx, cy); +} + + +void Fl_Cairo_Graphics_Driver::cache(Fl_Pixmap *pxm) { + Fl_RGB_Image *rgb = new Fl_RGB_Image(pxm); + cache(rgb); + *Fl_Graphics_Driver::id(pxm) = *Fl_Graphics_Driver::id(rgb); + *Fl_Graphics_Driver::id(rgb) = 0; + delete rgb; +} + + +void Fl_Cairo_Graphics_Driver::uncache_pixmap(fl_uintptr_t p) { + cairo_pattern_t *pat = (cairo_pattern_t*)p; + if (pat) { + cairo_surface_t *surf; + cairo_pattern_get_surface(pat, &surf); + cairo_pattern_destroy(pat); + cairo_surface_destroy(surf); + } +} + + +void Fl_Cairo_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) { + cairo_pattern_t *pat = (cairo_pattern_t*)bm; + if (pat) { + cairo_surface_t *surf; + cairo_pattern_get_surface(pat, &surf); + cairo_pattern_destroy(pat); + cairo_surface_destroy(surf); + } +} + + +int Fl_Cairo_Graphics_Driver::height() { + if (!font_descriptor()) font(0, 12); + return (font_descriptor()->ascent + font_descriptor()->descent)*1.1 /*1.15 scale=1*/; +} + + +int Fl_Cairo_Graphics_Driver::descent() { + return font_descriptor()->descent; +} + +extern Fl_Fontdesc *fl_fonts; + + +Fl_Cairo_Font_Descriptor::Fl_Cairo_Font_Descriptor(const char* name, Fl_Fontsize size) : Fl_Font_Descriptor(name, size) { + char string[70]; + strcpy(string, name); + sprintf(string + strlen(string), " %d", int(size * 0.7 + 0.5) ); // why reduce size? + fontref = pango_font_description_from_string(string); + width = NULL; + static PangoFontMap *def_font_map = pango_cairo_font_map_get_default(); // 1.10 + static PangoContext *pango_context = pango_font_map_create_context(def_font_map); // 1.22 + static PangoLanguage *language = pango_language_get_default(); // 1.16 + PangoFontset *fontset = pango_font_map_load_fontset(def_font_map, pango_context, fontref, language); + PangoFontMetrics *metrics = pango_fontset_get_metrics(fontset); + ascent = pango_font_metrics_get_ascent(metrics)/PANGO_SCALE; + descent = pango_font_metrics_get_descent(metrics)/PANGO_SCALE; + q_width = pango_font_metrics_get_approximate_char_width(metrics)/PANGO_SCALE; + pango_font_metrics_unref(metrics); + g_object_unref(fontset); +//fprintf(stderr, "[%s](%d) ascent=%d descent=%d q_width=%d\n", name, size, ascent, descent, q_width); +} + + +Fl_Cairo_Font_Descriptor::~Fl_Cairo_Font_Descriptor() { + pango_font_description_free(fontref); + if (width) { + for (int i = 0; i < 64; i++) delete[] width[i]; + } + delete[] width; +} + + +static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) { + Fl_Fontdesc* s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // use 0 if fnum undefined + Fl_Font_Descriptor* f; + for (f = s->first; f; f = f->next) + if (f->size == size) return f; + f = new Fl_Cairo_Font_Descriptor(s->name, size); + f->next = s->first; + s->first = f; + return f; +} + + +void Fl_Cairo_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize s) { + if (font() == fnum && size() == s) return; + if (fnum == -1) { + Fl_Graphics_Driver::font(0, 0); + return; + } + Fl_Graphics_Driver::font(fnum, s); + font_descriptor( find(fnum, s) ); + pango_layout_set_font_description(pango_layout_, ((Fl_Cairo_Font_Descriptor*)font_descriptor())->fontref); +} + + +void Fl_Cairo_Graphics_Driver::draw(const char* str, int n, float x, float y) { + if (!n) return; + cairo_save(cairo_); + cairo_translate(cairo_, x, y - height() + descent() -1); + pango_layout_set_text(pango_layout_, str, n); + pango_cairo_show_layout(cairo_, pango_layout_); + cairo_restore(cairo_); + surface_needs_commit(); +} + + +void Fl_Cairo_Graphics_Driver::draw(int rotation, const char *str, int n, int x, int y) +{ + cairo_save(cairo_); + cairo_translate(cairo_, x, y); + cairo_rotate(cairo_, -rotation * M_PI / 180); + this->draw(str, n, 0, 0); + cairo_restore(cairo_); +} + + +void Fl_Cairo_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) { + int w = (int)width(str, n); + draw(str, n, x - w, y); +} + + +double Fl_Cairo_Graphics_Driver::width(const char* c, int n) { + if (!font_descriptor()) return -1.0; + int i = 0, w = 0, l; + const char *end = c + n; + unsigned int ucs; + while (i < n) { + ucs = fl_utf8decode(c + i, end, &l); + i += l; + w += width(ucs); + } + return (double)w; +} + + +double Fl_Cairo_Graphics_Driver::width(unsigned int c) { + unsigned int r = 0; + Fl_Cairo_Font_Descriptor *desc = NULL; + if (c <= 0xFFFF) { // when inside basic multilingual plane + desc = (Fl_Cairo_Font_Descriptor*)font_descriptor(); + r = (c & 0xFC00) >> 10; + if (!desc->width) { + desc->width = (int**)new int*[64]; + memset(desc->width, 0, 64*sizeof(int*)); + } + if (!desc->width[r]) { + desc->width[r] = (int*)new int[0x0400]; + for (int i = 0; i < 0x0400; i++) desc->width[r][i] = -1; + } else { + if ( desc->width[r][c & 0x03FF] >= 0 ) { // already cached + return (double) desc->width[r][c & 0x03FF]; + } + } + } + char buf[4]; + int n = fl_utf8encode(c, buf); + pango_layout_set_text(pango_layout_, buf, n); + int W = 0, H; + pango_layout_get_pixel_size(pango_layout_, &W, &H); + if (c <= 0xFFFF) desc->width[r][c & 0x03FF] = W; + return (double)W; +} + + +void Fl_Cairo_Graphics_Driver::text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h) { + pango_layout_set_text(pango_layout_, txt, n); + PangoRectangle ink_rect; + pango_layout_get_pixel_extents(pango_layout_, &ink_rect, NULL); + dx = ink_rect.x; + dy = ink_rect.y - height() + descent(); + w = ink_rect.width; + h = ink_rect.height; +} + + #endif // USE_PANGO diff --git a/src/drivers/PostScript/Fl_PostScript.cxx b/src/drivers/PostScript/Fl_PostScript.cxx index 38407d5c4..e930bbee7 100644 --- a/src/drivers/PostScript/Fl_PostScript.cxx +++ b/src/drivers/PostScript/Fl_PostScript.cxx @@ -1,7 +1,7 @@ // // Classes Fl_PostScript_File_Device and Fl_PostScript_Graphics_Driver for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2020 by Bill Spitzak and others. +// Copyright 2010-2022 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 @@ -1499,8 +1499,24 @@ int Fl_PostScript_Graphics_Driver::start_eps(int width, int height) { return 0; } -PangoFontDescription* Fl_PostScript_Graphics_Driver::pango_font_description(Fl_Font fnum) { - return Fl_Graphics_Driver::default_driver().pango_font_description(fnum); + +void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, double x, double y) { + if (!n) return; + PangoFontDescription *pfd = Fl_Graphics_Driver::default_driver().pango_font_description(font()); + pango_layout_set_font_description(pango_layout_, pfd); + int pwidth, pheight; + cairo_save(cairo_); + pango_layout_set_text(pango_layout_, str, n); + pango_layout_get_size(pango_layout_, &pwidth, &pheight); + if (pwidth > 0) { + double s = width(str, n); + cairo_translate(cairo_, x, y - height() + descent()); + s = (s/pwidth) * PANGO_SCALE; + cairo_scale(cairo_, s, s); + pango_cairo_show_layout(cairo_, pango_layout_); + } + cairo_restore(cairo_); + check_status(); } #endif // USE_PANGO diff --git a/src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H b/src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H index eb2060cc9..9ff238738 100644 --- a/src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H +++ b/src/drivers/PostScript/Fl_PostScript_Graphics_Driver.H @@ -1,7 +1,7 @@ // // Support for graphics output to PostScript file for the Fast Light Tool Kit (FLTK). // -// Copyright 2010-2020 by Bill Spitzak and others. +// Copyright 2010-2022 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 @@ -70,17 +70,27 @@ public: int height(); int descent(); void text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h); + // draw text at width measured on display + void transformed_draw(const char* s, int n, double x, double y); + void draw(const char* s, int nBytes, int x, int y) {transformed_draw(s,nBytes,x,y); } + void draw(const char* s, int nBytes, float x, float y) {transformed_draw(s,nBytes,x,y); } + void draw(int angle, const char *str, int n, int x, int y) {Fl_Cairo_Graphics_Driver::draw(angle, str, n, x, y);} + void color(Fl_Color c); void color(uchar r, uchar g, uchar b) {Fl_Cairo_Graphics_Driver::color(r,g,b);} Fl_Color color(); void point(int x, int y); int not_clipped(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); - virtual PangoFontDescription* pango_font_description(Fl_Font fnum); virtual int has_feature(driver_feature feature_mask) { return feature_mask & PRINTER; } + // draw image classes without caching them + void draw_rgb_bitmap_(Fl_Image *img,int XP, int YP, int WP, int HP, int cx, int cy); + void draw_pixmap(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy); + void draw_bitmap(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy); + void draw_rgb(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy); }; -#else // USE_PANGO +#else // ! USE_PANGO class FL_EXPORT Fl_PostScript_Graphics_Driver : public Fl_Graphics_Driver { private: diff --git a/src/drivers/PostScript/Fl_PostScript_image.cxx b/src/drivers/PostScript/Fl_PostScript_image.cxx index 38b129e44..f2a41a2d4 100644 --- a/src/drivers/PostScript/Fl_PostScript_image.cxx +++ b/src/drivers/PostScript/Fl_PostScript_image.cxx @@ -1,7 +1,7 @@ // // Postscript image drawing implementation for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2021 by Bill Spitzak and others. +// Copyright 1998-2022 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 @@ -25,8 +25,10 @@ #include // abs(int) #include // memcpy() -#if ! USE_PANGO -#include // fprintf() +#if USE_PANGO +# include +#else +# include // fprintf() #endif struct callback_data { @@ -66,7 +68,119 @@ void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, abs(D)); } -#if ! USE_PANGO +#if USE_PANGO + +static void destroy_BGRA(void *data) { + delete[] (uchar*)data; +} + + +void Fl_PostScript_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm,int XP, int YP, int WP, int HP, int cx, int cy) { + Fl_RGB_Image *rgb = new Fl_RGB_Image(pxm); + draw_rgb_bitmap_(rgb, XP, YP, WP, HP, cx, cy); + delete rgb; +} + + +void Fl_PostScript_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy) { + draw_rgb_bitmap_(rgb, XP, YP, WP, HP, cx, cy); +} + + +void Fl_PostScript_Graphics_Driver::draw_bitmap(Fl_Bitmap *bitmap,int XP, int YP, int WP, int HP, int cx, int cy) { + draw_rgb_bitmap_(bitmap, XP, YP, WP, HP, cx, cy); +} + + +void Fl_PostScript_Graphics_Driver::draw_rgb_bitmap_(Fl_Image *img,int XP, int YP, int WP, int HP, int cx, int cy) +{ + cairo_surface_t *surf; + cairo_format_t format = (img->d() >= 1 ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A1); + int stride = cairo_format_stride_for_width(format, img->data_w()); + uchar *BGRA = new uchar[stride * img->data_h()]; + memset(BGRA, 0, stride * img->data_h()); + if (img->d() >= 1) { // process Fl_RGB_Image of all depths + Fl_RGB_Image *rgb = (Fl_RGB_Image*)img; + int lrgb = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d(); + uchar A = 0xff, R,G,B, *q; + const uchar *r; + float f = 1; + if (rgb->d() >= 3) { // color images + for (int j = 0; j < rgb->data_h(); j++) { + r = rgb->array + j * lrgb; + q = BGRA + j * stride; + for (int i = 0; i < rgb->data_w(); i++) { + R = *r; + G = *(r+1); + B = *(r+2); + if (rgb->d() == 4) { + A = *(r+3); + f = float(A)/0xff; + } + *q = B * f; + *(q+1) = G * f; + *(q+2) = R * f; + *(q+3) = A; + r += rgb->d(); q += 4; + } + } + } else if (rgb->d() == 1 || rgb->d() == 2) { // B&W + for (int j = 0; j < rgb->data_h(); j++) { + r = rgb->array + j * lrgb; + q = BGRA + j * stride; + for (int i = 0; i < rgb->data_w(); i++) { + G = *r; + if (rgb->d() == 2) { + A = *(r+1); + f = float(A)/0xff; + } + *(q) = G * f; + *(q+1) = G * f; + *(q+2) = G * f; + *(q+3) = A; + r += rgb->d(); q += 4; + } + } + } + } else { + Fl_Bitmap *bm = (Fl_Bitmap*)img; + uchar *r, p; + unsigned *q; + for (int j = 0; j < bm->data_h(); j++) { + r = (uchar*)bm->array + j * ((bm->data_w() + 7)/8); + q = (unsigned*)(BGRA + j * stride); + unsigned k = 0, mask32 = 1; + p = *r; + for (int i = 0; i < bm->data_w(); i++) { + if (p&1) (*q) |= mask32; + k++; + if (k % 8 != 0) p >>= 1; else p = *(++r); + if (k % 32 != 0) mask32 <<= 1; else {q++; mask32 = 1;} + } + } + } + surf = cairo_image_surface_create_for_data(BGRA, format, img->data_w(), img->data_h(), stride); + if (cairo_surface_status(surf) == CAIRO_STATUS_SUCCESS) { + static cairo_user_data_key_t key = {}; + (void)cairo_surface_set_user_data(surf, &key, BGRA, destroy_BGRA); + cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); + cairo_save(cairo_); + cairo_rectangle(cairo_, XP-0.5, YP-0.5, WP+1, HP+1); + cairo_clip(cairo_); + if (img->d() >= 1) cairo_set_source(cairo_, pat); + cairo_matrix_t matrix; + cairo_matrix_init_scale(&matrix, double(img->data_w())/(img->w()+1), double(img->data_h())/(img->h()+1)); + cairo_matrix_translate(&matrix, -XP+0.5+cx, -YP+0.5+cy); + cairo_pattern_set_matrix(pat, &matrix); + cairo_mask(cairo_, pat); + cairo_pattern_destroy(pat); + cairo_surface_destroy(surf); + cairo_restore(cairo_); + check_status(); + } +} + +#else // USE_PANGO // // Implementation of the /ASCII85Encode PostScript filter diff --git a/src/drivers/Wayland/Fl_Font.H b/src/drivers/Wayland/Fl_Font.H deleted file mode 100644 index eca2f32ca..000000000 --- a/src/drivers/Wayland/Fl_Font.H +++ /dev/null @@ -1,33 +0,0 @@ -// -// Font definitions for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021 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 -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#ifndef FL_FONT_ -#define FL_FONT_ - -#include -#include "Fl_Wayland_Graphics_Driver.H" - -class Fl_Wayland_Font_Descriptor : public Fl_Font_Descriptor { -public: - Fl_Wayland_Font_Descriptor(const char* fontname, Fl_Fontsize size); - FL_EXPORT ~Fl_Wayland_Font_Descriptor(); - PangoFontDescription *fontref; - int **width; // array of arrays of character widths -}; - -extern FL_EXPORT Fl_Fontdesc *fl_fonts; // the table - -#endif // FL_FONT_ diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H index 19991c531..8023c6c94 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H @@ -42,22 +42,16 @@ gives the stride of this buffer; - size_t data_size gives the total buffer size in bytes (thus, data_size / stride gives the buffer height); - - bool draw_buffer_needs_commit - is TRUE when draw_buffer has been modified and needs being committed for display, and - FALSE after having been committed but before having been modified; - struct wl_callback *cb is used to synchronize drawing with the compositor during progressive drawing. When a graphics scene is to be committed, the data_size bytes of draw_buffer are copied by memcpy() starting at data, and wl_buffer is attached to the wl_surface which is committed for display - by wl_surface_commit(). Finally, draw_buffer_needs_commit is set to FALSE. - - All drawing functions have Cairo write to draw_buffer and turn draw_buffer_needs_commit to TRUE. -*/ + by wl_surface_commit(). + */ #include "../Cairo/Fl_Cairo_Graphics_Driver.H" -#include #include // for uint32_t typedef struct _PangoLayout PangoLayout; @@ -75,34 +69,19 @@ struct fl_wld_buffer { }; struct wld_window; + class FL_EXPORT Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver { private: struct fl_wld_buffer *buffer_; PangoLayout *dummy_pango_layout_; // used to measure text width before showing a window - int linestyle_; - void draw_cached_pattern_(Fl_Image *img, cairo_pattern_t *pat, int X, int Y, int W, int H, int cx, int cy); public: Fl_Wayland_Graphics_Driver(); ~Fl_Wayland_Graphics_Driver(); static const uint32_t wld_format; - static const cairo_format_t cairo_format; void activate(struct fl_wld_buffer *buffer, float scale); void font(Fl_Font fnum, Fl_Fontsize s); Fl_Font font() { return Fl_Graphics_Driver::font(); } - void draw(const char* s, int nBytes, int x, int y) { draw(s, nBytes, float(x), float(y)); } - void draw(const char* s, int nBytes, float x, float 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); - int height(); - int descent(); - double width(const char *str, int n); - double width(unsigned c); - void text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h); - int not_clipped(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); - void restore_clip(); void clip_region(Fl_Region r); - void line_style(int style, int width=0, char* dashes=0); Fl_Region XRectangleRegion(int x, int y, int w, int h); void add_rectangle_to_region(Fl_Region r, int X, int Y, int W, int H); void XDestroyRegion(Fl_Region r); @@ -112,45 +91,12 @@ public: void font_name(int num, const char *name); const char* get_font_name(Fl_Font fnum, int* ap); int get_font_sizes(Fl_Font fnum, int*& sizep); - void point(int x, int y); void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy); - void draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD); - void curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3); - void begin_points(); - void end_points(); - void transformed_vertex(double x, double y); - void draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy); - void cache(Fl_RGB_Image *rgb); - void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_); - void draw_bitmap(Fl_Bitmap *bm,int XP, int YP, int WP, int HP, int cx, int cy); - void cache(Fl_Bitmap *img); - void delete_bitmask(Fl_Bitmask bm); - void cache(Fl_Pixmap *pxm); - void draw_pixmap(Fl_Pixmap *rgb,int XP, int YP, int WP, int HP, int cx, int cy); - void uncache_pixmap(fl_uintptr_t p); - void overlay_rect(int x, int y, int w , int h); static void init_built_in_fonts(); static struct fl_wld_buffer *create_shm_buffer(int width, int height); static void buffer_release(struct wld_window *window); static void buffer_commit(struct wld_window *window); static void cairo_init(struct fl_wld_buffer *buffer, int width, int height, int stride, cairo_format_t format); - void line(int x1, int y1, int x2, int y2); - void line(int x1, int y1, int x2, int y2, int x3, int y3); - 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 rect(int x, int y, int w, int h); - void rectf(int x, int y, int w, int h); - 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 end_loop(); - void end_line(); - void end_polygon(); void set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win); void reset_spot(); }; diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx index 55f6de8d9..6f57c6cec 100644 --- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx @@ -19,7 +19,6 @@ #include "Fl_Wayland_Graphics_Driver.H" #include "Fl_Wayland_Screen_Driver.H" #include "Fl_Wayland_Window_Driver.H" -#include "Fl_Font.H" #include "text-input-client-protocol.h" #include #if ! PANGO_VERSION_CHECK(1,22,0) @@ -63,7 +62,7 @@ static int create_anonymous_file(int size, char **pshared) struct fl_wld_buffer *Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, int height) { struct fl_wld_buffer *buffer; - int stride = cairo_format_stride_for_width(Fl_Wayland_Graphics_Driver::cairo_format, width); + int stride = cairo_format_stride_for_width(Fl_Cairo_Graphics_Driver::cairo_format, width); int size = stride * height; static char *pool_memory = NULL; static int pool_size = 10000000; // gets increased if necessary @@ -91,7 +90,7 @@ struct fl_wld_buffer *Fl_Wayland_Graphics_Driver::create_shm_buffer(int width, i buffer->draw_buffer = new uchar[buffer->data_size]; buffer->draw_buffer_needs_commit = false; //fprintf(stderr, "create_shm_buffer: %dx%d = %d\n", width, height, size); - cairo_init(buffer, width, height, stride, Fl_Wayland_Graphics_Driver::cairo_format); + cairo_init(buffer, width, height, stride, Fl_Cairo_Graphics_Driver::cairo_format); return buffer; } @@ -146,7 +145,6 @@ void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window) // these 2 refer to the same memory layout for pixel data const uint32_t Fl_Wayland_Graphics_Driver::wld_format = WL_SHM_FORMAT_ARGB8888; -const cairo_format_t Fl_Wayland_Graphics_Driver::cairo_format = CAIRO_FORMAT_ARGB32; Fl_Wayland_Graphics_Driver::Fl_Wayland_Graphics_Driver () : Fl_Cairo_Graphics_Driver() { @@ -213,75 +211,26 @@ static Fl_Fontdesc built_in_table[] = { // Pango font names FL_EXPORT Fl_Fontdesc *fl_fonts = built_in_table; - -static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) { - Fl_Fontdesc* s = fl_fonts+fnum; - if (!s->name) s = fl_fonts; // use 0 if fnum undefined - Fl_Font_Descriptor* f; - for (f = s->first; f; f = f->next) - if (f->size == size) return f; - f = new Fl_Wayland_Font_Descriptor(s->name, size); - f->next = s->first; - s->first = f; - return f; -} - - -Fl_Wayland_Font_Descriptor::Fl_Wayland_Font_Descriptor(const char* name, Fl_Fontsize size) : Fl_Font_Descriptor(name, size) { - char string[70]; - strcpy(string, name); - sprintf(string + strlen(string), " %d", int(size * 0.7 + 0.5) ); // why reduce size? - fontref = pango_font_description_from_string(string); - width = NULL; - static PangoFontMap *def_font_map = pango_cairo_font_map_get_default(); // 1.10 - static PangoContext *pango_context = pango_font_map_create_context(def_font_map); // 1.22 - static PangoLanguage *language = pango_language_get_default(); // 1.16 - PangoFontset *fontset = pango_font_map_load_fontset(def_font_map, pango_context, fontref, language); - PangoFontMetrics *metrics = pango_fontset_get_metrics(fontset); - ascent = pango_font_metrics_get_ascent(metrics)/PANGO_SCALE; - descent = pango_font_metrics_get_descent(metrics)/PANGO_SCALE; - q_width = pango_font_metrics_get_approximate_char_width(metrics)/PANGO_SCALE; - pango_font_metrics_unref(metrics); - g_object_unref(fontset); -//fprintf(stderr, "[%s](%d) ascent=%d descent=%d q_width=%d\n", name, size, ascent, descent, q_width); -} - - -Fl_Wayland_Font_Descriptor::~Fl_Wayland_Font_Descriptor() { - pango_font_description_free(fontref); - if (width) { - for (int i = 0; i < 64; i++) delete[] width[i]; +void Fl_Wayland_Graphics_Driver::init_built_in_fonts() { + static int i = 0; + if (!i) { + while (i < FL_FREE_FONT) { + i++; + Fl::set_font((Fl_Font)i-1, built_in_table[i-1].name); + } } - delete[] width; -} - - -int Fl_Wayland_Graphics_Driver::height() { - return (font_descriptor()->ascent + font_descriptor()->descent)*1.1 /*1.15 scale=1*/; -} - - -int Fl_Wayland_Graphics_Driver::descent() { - return font_descriptor()->descent; } void Fl_Wayland_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize s) { - if (font() == fnum && size() == s) return; if (!font_descriptor()) fl_open_display(); if (!pango_layout_) { - cairo_surface_t *surf = cairo_image_surface_create(Fl_Wayland_Graphics_Driver::cairo_format, 100, 100); + cairo_surface_t *surf = cairo_image_surface_create(Fl_Cairo_Graphics_Driver::cairo_format, 100, 100); cairo_ = cairo_create(surf); dummy_pango_layout_ = pango_cairo_create_layout(cairo_); pango_layout_ = dummy_pango_layout_; } - if (fnum == -1) { - Fl_Graphics_Driver::font(0, 0); - return; - } - Fl_Graphics_Driver::font(fnum, s); - font_descriptor( find(fnum, s) ); - pango_layout_set_font_description(pango_layout_, ((Fl_Wayland_Font_Descriptor*)font_descriptor())->fontref); + Fl_Cairo_Graphics_Driver::font(fnum, s); } @@ -339,17 +288,6 @@ Fl_Font Fl_Wayland_Graphics_Driver::set_fonts(const char* pattern_name) } -void Fl_Wayland_Graphics_Driver::init_built_in_fonts() { - static int i = 0; - if (!i) { - while (i < FL_FREE_FONT) { - i++; - Fl::set_font((Fl_Font)i-1, built_in_table[i-1].name); - } - } -} - - const char *Fl_Wayland_Graphics_Driver::font_name(int num) { return fl_fonts[num].name; } @@ -403,136 +341,6 @@ int Fl_Wayland_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) { } -void Fl_Wayland_Graphics_Driver::draw(const char* str, int n, float x, float y) { - if (!n) return; - cairo_save(cairo_); - cairo_translate(cairo_, x, y - height() + descent() -1); - pango_layout_set_text(pango_layout_, str, n); - pango_cairo_show_layout(cairo_, pango_layout_); - cairo_restore(cairo_); - buffer_->draw_buffer_needs_commit = true; -} - - -void Fl_Wayland_Graphics_Driver::draw(int rotation, const char *str, int n, int x, int y) -{ - cairo_save(cairo_); - cairo_translate(cairo_, x, y); - cairo_rotate(cairo_, -rotation * M_PI / 180); - this->draw(str, n, 0, 0); - cairo_restore(cairo_); -} - - -void Fl_Wayland_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) { - int w = (int)width(str, n); - draw(str, n, x - w, y); -} - - -double Fl_Wayland_Graphics_Driver::width(const char* c, int n) { - if (!font_descriptor()) return -1.0; - int i = 0, w = 0, l; - const char *end = c + n; - unsigned int ucs; - while (i < n) { - ucs = fl_utf8decode(c + i, end, &l); - i += l; - w += width(ucs); - } - return (double)w; -} - - -double Fl_Wayland_Graphics_Driver::width(unsigned int c) { - unsigned int r = 0; - Fl_Wayland_Font_Descriptor *desc = NULL; - if (c <= 0xFFFF) { // when inside basic multilingual plane - desc = (Fl_Wayland_Font_Descriptor*)font_descriptor(); - r = (c & 0xFC00) >> 10; - if (!desc->width) { - desc->width = (int**)new int*[64]; - memset(desc->width, 0, 64*sizeof(int*)); - } - if (!desc->width[r]) { - desc->width[r] = (int*)new int[0x0400]; - for (int i = 0; i < 0x0400; i++) desc->width[r][i] = -1; - } else { - if ( desc->width[r][c & 0x03FF] >= 0 ) { // already cached - return (double) desc->width[r][c & 0x03FF]; - } - } - } - char buf[4]; - int n = fl_utf8encode(c, buf); - pango_layout_set_text(pango_layout_, buf, n); - int W = 0, H; - pango_layout_get_pixel_size(pango_layout_, &W, &H); - if (c <= 0xFFFF) desc->width[r][c & 0x03FF] = W; - return (double)W; -} - - -void Fl_Wayland_Graphics_Driver::text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h) { - pango_layout_set_text(pango_layout_, txt, n); - PangoRectangle ink_rect; - pango_layout_get_pixel_extents(pango_layout_, &ink_rect, NULL); - dx = ink_rect.x; - dy = ink_rect.y - height() + descent(); - w = ink_rect.width; - h = ink_rect.height; -} - - -int Fl_Wayland_Graphics_Driver::not_clipped(int x, int y, int w, int h) { - if (!clip_) return 1; - if (clip_->w < 0) return 1; - int X = 0, Y = 0, W = 0, H = 0; - clip_box(x, y, w, h, X, Y, W, H); - if (W) return 1; - return 0; -} - -int Fl_Wayland_Graphics_Driver::clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) { - if (!clip_) { - X = x; Y = y; W = w; H = h; - return 0; - } - if (clip_->w < 0) { - X = x; Y = y; W = w; H = h; - return 1; - } - int ret = 0; - if (x > (X=clip_->x)) {X=x; ret=1;} - if (y > (Y=clip_->y)) {Y=y; ret=1;} - if ((x+w) < (clip_->x+clip_->w)) { - W=x+w-X; - - ret=1; - - }else - W = clip_->x + clip_->w - X; - if(W<0){ - W=0; - return 1; - } - if ((y+h) < (clip_->y+clip_->h)) { - H=y+h-Y; - ret=1; - }else - H = clip_->y + clip_->h - Y; - if(H<0){ - W=0; - H=0; - return 1; - } - return ret; -} - -void Fl_Wayland_Graphics_Driver::restore_clip() { - if (cairo_) cairo_reset_clip(cairo_); -} - void Fl_Wayland_Graphics_Driver::clip_region(Fl_Region r) { if (cairo_) { cairo_reset_clip(cairo_); @@ -590,357 +398,6 @@ void Fl_Wayland_Graphics_Driver::set_color(Fl_Color i, unsigned c) { } -void Fl_Wayland_Graphics_Driver::point(int x, int y) { - rectf(x, y, 1, 1); -} - - -void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy) { - // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of the graphics driver's surface - int height = osrc->data_size / osrc->stride; - cairo_matrix_t matrix; - cairo_get_matrix(cairo_, &matrix); - double s = matrix.xx; - cairo_save(cairo_); - cairo_rectangle(cairo_, x, y, w, h); - cairo_clip(cairo_); - cairo_surface_t *surf = cairo_image_surface_create_for_data(osrc->draw_buffer, Fl_Wayland_Graphics_Driver::cairo_format, osrc->width, height, osrc->stride); - cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); - cairo_set_source(cairo_, pat); - cairo_matrix_init_scale(&matrix, s, s); - cairo_matrix_translate(&matrix, -(x - srcx), -(y - srcy)); - cairo_pattern_set_matrix(pat, &matrix); - cairo_mask(cairo_, pat); - cairo_pattern_destroy(pat); - cairo_surface_destroy(surf); - cairo_restore(cairo_); -} - - -struct callback_data { - const uchar *data; - int D, LD; -}; - - -static void draw_image_cb(void *data, int x, int y, int w, uchar *buf) { - struct callback_data *cb_data; - const uchar *curdata; - - cb_data = (struct callback_data*)data; - int last = x+w; - const size_t aD = abs(cb_data->D); - curdata = cb_data->data + x*cb_data->D + y*cb_data->LD; - for (; xD; - } -} - - -void Fl_Wayland_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) { - if (abs(D)<3){ //mono - draw_image_mono(data, ix, iy, iw, ih, D, LD); - return; - } - struct callback_data cb_data; - if (!LD) LD = iw*abs(D); - if (D<0) data += iw*abs(D); - cb_data.data = data; - cb_data.D = D; - cb_data.LD = LD; - Fl_Cairo_Graphics_Driver::draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, abs(D)); -} - - -void Fl_Wayland_Graphics_Driver::curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3) { - if (shape_ == POINTS) Fl_Graphics_Driver::curve(x, y, x1, y1, x2, y2, x3, y3); - else Fl_Cairo_Graphics_Driver::curve(x, y, x1, y1, x2, y2, x3, y3); -} - - -void Fl_Wayland_Graphics_Driver::begin_points() { - cairo_save(cairo_); - gap_=1; - shape_=POINTS; -} - - -void Fl_Wayland_Graphics_Driver::end_points() { - cairo_restore(cairo_); -} - - -void Fl_Wayland_Graphics_Driver::transformed_vertex(double x, double y) { - if (shape_ == POINTS){ - cairo_move_to(cairo_, x, y); - point(x, y); - gap_ = 1; - } else { - Fl_Cairo_Graphics_Driver::transformed_vertex(x, y); - } -} - -void Fl_Wayland_Graphics_Driver::line_style(int style, int width, char* dashes) { - linestyle_ = style; - Fl_Cairo_Graphics_Driver::line_style(style, width, dashes); -} - -void Fl_Wayland_Graphics_Driver::overlay_rect(int x, int y, int w , int h) { - cairo_save(cairo_); - cairo_matrix_t mat; - cairo_get_matrix(cairo_, &mat); - float s = (float)mat.xx; - cairo_matrix_init_identity(&mat); - cairo_set_matrix(cairo_, &mat); // use drawing units - int lwidth = s < 1 ? 1 : int(s); - cairo_set_line_width(cairo_, lwidth); - cairo_translate(cairo_, lwidth/2., lwidth/2.); // translate by half of line width - double ddash = (lwidth > 2 ? lwidth : 2); - if (linestyle_ == FL_DOT){ - cairo_set_dash(cairo_, &ddash, 1, 0); // dash size = line width - } - // rectangle in drawing units - int Xs = Fl_Scalable_Graphics_Driver::floor(x, s); - int Ws = Fl_Scalable_Graphics_Driver::floor(x+w-1, s) - Xs; - int Ys = Fl_Scalable_Graphics_Driver::floor(y, s); - int Hs = Fl_Scalable_Graphics_Driver::floor(y+h-1, s) - Ys; - cairo_move_to(cairo_, Xs, Ys); - cairo_line_to(cairo_, Xs+Ws, Ys); - cairo_line_to(cairo_, Xs+Ws, Ys+Hs); - cairo_line_to(cairo_, Xs, Ys+Hs); - cairo_close_path(cairo_); - cairo_stroke(cairo_); - cairo_restore(cairo_); - buffer_->draw_buffer_needs_commit = true; -} - - -void Fl_Wayland_Graphics_Driver::draw_cached_pattern_(Fl_Image *img, cairo_pattern_t *pat, int X, int Y, int W, int H, int cx, int cy) { - // compute size of output image in drawing units - cairo_matrix_t matrix; - cairo_get_matrix(cairo_, &matrix); - float s = (float)matrix.xx; - int Xs = Fl_Scalable_Graphics_Driver::floor(X - cx, s); - int Ws = Fl_Scalable_Graphics_Driver::floor(X - cx + img->w(), s) - Xs ; - int Ys = Fl_Scalable_Graphics_Driver::floor(Y - cy, s); - int Hs = Fl_Scalable_Graphics_Driver::floor(Y - cy + img->h(), s) - Ys; - if (Ws == 0 || Hs == 0) return; - cairo_save(cairo_); - if (cx || cy || W < img->w() || H < img->h()) { // clip when necessary - cairo_rectangle(cairo_, X-0.5, Y-0.5, W+1, H+1); - cairo_clip(cairo_); - } - // remove any scaling and the current "0.5" translation useful for lines but bad for images - matrix.xx = matrix.yy = 1; - matrix.x0 -= 0.5 * s; matrix.y0 -= 0.5 * s; - cairo_set_matrix(cairo_, &matrix); - if (img->d() >= 1) cairo_set_source(cairo_, pat); - int offset = 0; - if (Ws >= img->data_w()*1.09 || Hs >= img->data_h()*1.09) { - // When enlarging while drawing, 1 pixel around target area seems unpainted, - // so we increase a bit the target area and move it int(s) pixels to left and top. - Ws = (img->w()+2)*s, Hs = (img->h()+2)*s; - offset = int(s); - } - -//fprintf(stderr,"WHs=%dx%d dataWH=%dx%d s=%.1f offset=%d\n",Ws,Hs,img->data_w(),img->data_h(),s,offset); - cairo_matrix_init_scale(&matrix, double(img->data_w())/Ws, double(img->data_h())/Hs); - cairo_matrix_translate(&matrix, -Xs + offset, -Ys + offset); - cairo_pattern_set_matrix(pat, &matrix); - cairo_mask(cairo_, pat); - cairo_restore(cairo_); - buffer_->draw_buffer_needs_commit = true; -} - - -void Fl_Wayland_Graphics_Driver::draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - // Don't draw an empty image... - if (!rgb->d() || !rgb->array) { - Fl_Graphics_Driver::draw_empty(rgb, XP, YP); - return; - } - if (start_image(rgb, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; - } - cairo_pattern_t *pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(rgb); - if (!pat) { - cache(rgb); - pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(rgb); - } - draw_cached_pattern_(rgb, pat, X, Y, W, H, cx, cy); -} - - -static cairo_user_data_key_t data_key_for_surface = {}; - -static void dealloc_surface_data(void *data) { - delete[] (uchar*)data; -} - - -void Fl_Wayland_Graphics_Driver::cache(Fl_RGB_Image *rgb) { - int stride = cairo_format_stride_for_width(Fl_Wayland_Graphics_Driver::cairo_format, rgb->data_w()); - uchar *BGRA = new uchar[stride * rgb->data_h()]; - memset(BGRA, 0, stride * rgb->data_h()); - int lrgb = rgb->ld() ? rgb->ld() : rgb->data_w() * rgb->d(); - uchar A = 0xff, R,G,B, *q; - const uchar *r; - float f = 1; - if (rgb->d() >= 3) { // color images - for (int j = 0; j < rgb->data_h(); j++) { - r = rgb->array + j * lrgb; - q = BGRA + j * stride; - for (int i = 0; i < rgb->data_w(); i++) { - R = *r; - G = *(r+1); - B = *(r+2); - if (rgb->d() == 4) { - A = *(r+3); - f = float(A)/0xff; - } - *q = B * f; - *(q+1) = G * f; - *(q+2) = R * f; - *(q+3) = A; - r += rgb->d(); q += 4; - } - } - } else if (rgb->d() == 1 || rgb->d() == 2) { // B&W - for (int j = 0; j < rgb->data_h(); j++) { - r = rgb->array + j * lrgb; - q = BGRA + j * stride; - for (int i = 0; i < rgb->data_w(); i++) { - G = *r; - if (rgb->d() == 2) { - A = *(r+1); - f = float(A)/0xff; - } - *(q) = G * f; - *(q+1) = G * f; - *(q+2) = G * f; - *(q+3) = A; - r += rgb->d(); q += 4; - } - } - } - cairo_surface_t *surf = cairo_image_surface_create_for_data(BGRA, Fl_Wayland_Graphics_Driver::cairo_format, rgb->data_w(), rgb->data_h(), stride); - if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) return; - (void)cairo_surface_set_user_data(surf, &data_key_for_surface, BGRA, dealloc_surface_data); - cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); - *Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)pat; -} - - -void Fl_Wayland_Graphics_Driver::uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_) { - cairo_pattern_t *pat = (cairo_pattern_t*)id_; - if (pat) { - cairo_surface_t *surf; - cairo_pattern_get_surface(pat, &surf); - cairo_pattern_destroy(pat); - cairo_surface_destroy(surf); - id_ = 0; - } -} - - -void Fl_Wayland_Graphics_Driver::draw_bitmap(Fl_Bitmap *bm,int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - if (!bm->array) { - draw_empty(bm, XP, YP); - return; - } - if (start_image(bm, XP,YP,WP,HP,cx,cy,X,Y,W,H)) return; - cairo_pattern_t *pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(bm); - if (!pat) { - cache(bm); - pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(bm); - } - if (pat) { - draw_cached_pattern_(bm, pat, X, Y, W, H, cx, cy); - } -} - - -void Fl_Wayland_Graphics_Driver::cache(Fl_Bitmap *bm) { - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_A1, bm->data_w()); - uchar *BGRA = new uchar[stride * bm->data_h()]; - memset(BGRA, 0, stride * bm->data_h()); - uchar *r, p; - unsigned *q; - for (int j = 0; j < bm->data_h(); j++) { - r = (uchar*)bm->array + j * ((bm->data_w() + 7)/8); - q = (unsigned*)(BGRA + j * stride); - unsigned k = 0, mask32 = 1; - p = *r; - for (int i = 0; i < bm->data_w(); i++) { - if (p&1) (*q) |= mask32; - k++; - if (k % 8 != 0) p >>= 1; else p = *(++r); - if (k % 32 != 0) mask32 <<= 1; else {q++; mask32 = 1;} - } - } - cairo_surface_t *surf = cairo_image_surface_create_for_data(BGRA, CAIRO_FORMAT_A1, bm->data_w(), bm->data_h(), stride); - if (cairo_surface_status(surf) == CAIRO_STATUS_SUCCESS) { - (void)cairo_surface_set_user_data(surf, &data_key_for_surface, BGRA, dealloc_surface_data); - cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); - *Fl_Graphics_Driver::id(bm) = (fl_uintptr_t)pat; - } -} - - -void Fl_Wayland_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) { - cairo_pattern_t *pat = (cairo_pattern_t*)bm; - if (pat) { - cairo_surface_t *surf; - cairo_pattern_get_surface(pat, &surf); - cairo_pattern_destroy(pat); - cairo_surface_destroy(surf); - } -} - - -void Fl_Wayland_Graphics_Driver::draw_pixmap(Fl_Pixmap *pxm,int XP, int YP, int WP, int HP, int cx, int cy) { - int X, Y, W, H; - // Don't draw an empty image... - if (!pxm->data() || !pxm->w()) { - Fl_Graphics_Driver::draw_empty(pxm, XP, YP); - return; - } - if (start_image(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) { - return; - } - cairo_pattern_t *pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(pxm); - if (!pat) { - cache(pxm); - pat = (cairo_pattern_t*)*Fl_Graphics_Driver::id(pxm); - } - draw_cached_pattern_(pxm, pat, X, Y, W, H, cx, cy); -} - - -void Fl_Wayland_Graphics_Driver::cache(Fl_Pixmap *pxm) { - Fl_RGB_Image *rgb = new Fl_RGB_Image(pxm); - cache(rgb); - *Fl_Graphics_Driver::id(pxm) = *Fl_Graphics_Driver::id(rgb); - *Fl_Graphics_Driver::id(rgb) = 0; - delete rgb; -} - - -void Fl_Wayland_Graphics_Driver::uncache_pixmap(fl_uintptr_t p) { - cairo_pattern_t *pat = (cairo_pattern_t*)p; - if (pat) { - cairo_surface_t *surf; - cairo_pattern_get_surface(pat, &surf); - cairo_pattern_destroy(pat); - cairo_surface_destroy(surf); - } -} - - void Fl_Wayland_Graphics_Driver::set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) { Fl_Wayland_Screen_Driver::insertion_point_location(x, y, height); } @@ -953,87 +410,23 @@ void Fl_Wayland_Graphics_Driver::reset_spot() { } -void Fl_Wayland_Graphics_Driver::line(int x1, int y1, int x2, int y2) { - Fl_Cairo_Graphics_Driver::line(x1, y1, x2, y2); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::line(int x1, int y1, int x2, int y2, int x3, int y3) { - Fl_Cairo_Graphics_Driver::line(x1, y1, x2, y2, x3, y3); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::xyline(int x, int y, int x1) { - Fl_Cairo_Graphics_Driver::xyline(x, y, x1); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::xyline(int x, int y, int x1, int y2) { - Fl_Cairo_Graphics_Driver::xyline(x, y, x1, y2); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) { - Fl_Cairo_Graphics_Driver::xyline(x, y, x1, y2, x3); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::yxline(int x, int y, int y1) { - Fl_Cairo_Graphics_Driver::yxline(x, y, y1); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::yxline(int x, int y, int y1, int x2) { - Fl_Cairo_Graphics_Driver::yxline(x, y, y1, x2); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) { - Fl_Cairo_Graphics_Driver::yxline(x, y, y1, x2, y3); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) { - Fl_Cairo_Graphics_Driver::loop(x0, y0, x1, y1, x2, y2); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { - Fl_Cairo_Graphics_Driver::loop(x0, y0, x1, y1, x2, y2, x3, y3); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::rectf(int x, int y, int w, int h) { - Fl_Cairo_Graphics_Driver::rectf(x, y, w, h); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::rect(int x, int y, int w, int h) { - Fl_Cairo_Graphics_Driver::rect(x, y, w, h); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) { - Fl_Cairo_Graphics_Driver::polygon(x0, y0, x1, y1, x2, y2); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { - Fl_Cairo_Graphics_Driver::polygon(x0, y0, x1, y1, x2, y2, x3, y3); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::end_line() { - Fl_Cairo_Graphics_Driver::end_line(); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::end_loop(){ - Fl_Cairo_Graphics_Driver::end_loop(); - buffer_->draw_buffer_needs_commit = true; -} - -void Fl_Wayland_Graphics_Driver::end_polygon() { - Fl_Cairo_Graphics_Driver::end_polygon(); - buffer_->draw_buffer_needs_commit = true; +void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy) { + // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of the graphics driver's surface + int height = osrc->data_size / osrc->stride; + cairo_matrix_t matrix; + cairo_get_matrix(cairo_, &matrix); + double s = matrix.xx; + cairo_save(cairo_); + cairo_rectangle(cairo_, x, y, w, h); + cairo_clip(cairo_); + cairo_surface_t *surf = cairo_image_surface_create_for_data(osrc->draw_buffer, Fl_Cairo_Graphics_Driver::cairo_format, osrc->width, height, osrc->stride); + cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); + cairo_set_source(cairo_, pat); + cairo_matrix_init_scale(&matrix, s, s); + cairo_matrix_translate(&matrix, -(x - srcx), -(y - srcy)); + cairo_pattern_set_matrix(pat, &matrix); + cairo_mask(cairo_, pat); + cairo_pattern_destroy(pat); + cairo_surface_destroy(surf); + cairo_restore(cairo_); } diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index 9738ab861..e852bc6a6 100644 --- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -396,6 +396,10 @@ void Fl_Wayland_Window_Driver::make_current() { struct wld_window *window = fl_xid(pWindow); float scale = Fl::screen_scale(pWindow->screen_num()) * window->scale; + if (window && window->buffer) { + ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->needs_commit_tag( + &window->buffer->draw_buffer_needs_commit); + } // to support progressive drawing if ( (!Fl_Wayland_Window_Driver::in_flush) && window && window->buffer && (!window->buffer->cb)) {