summaryrefslogtreecommitdiff
path: root/src/drivers/Cairo
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2022-03-06 19:47:06 +0100
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2022-03-06 19:47:06 +0100
commitf8db18597a545c245b885ad18dbfb8862161966a (patch)
treee093eea6a0fcb62f9a110e85b80b40ba64a17930 /src/drivers/Cairo
parent272bc2560cad49bc5d504e2cede7c55d4518791a (diff)
Complete class Fl_Cairo_Graphics_Driver using Fl_Wayland_Graphics_Driver
Diffstat (limited to 'src/drivers/Cairo')
-rw-r--r--src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H65
-rw-r--r--src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx596
2 files changed, 540 insertions, 121 deletions
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 <FL/Fl_Graphics_Driver.H>
+#include <cairo/cairo.h>
-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 <stdlib.h> // abs(int)
#include <string.h> // 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) {
- delete[] (uchar*)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;
}
-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;
+
+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) {
- draw_rgb_bitmap_(rgb, XP, YP, WP, HP, cx, 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);
}
-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);
+
+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_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;
+
+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 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 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;
+ }
+ 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);
+ *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);
- cairo_restore(cairo_);
- check_status();
}
}
+
+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