summaryrefslogtreecommitdiff
path: root/src/drivers/Xlib
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2023-11-20 17:13:09 +0100
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2023-12-04 12:34:44 +0100
commit3e61ec7044942ebaeda948c64df762a0250f8954 (patch)
tree642c08a6f7b120c2237f5e457074670d0ccf3e86 /src/drivers/Xlib
parentb9ac6bd728659a7780d7cde024f34607601e8a7f (diff)
New member function Fl_Image_Surface::mask(Fl_RGB_Image*)
Diffstat (limited to 'src/drivers/Xlib')
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H13
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx122
2 files changed, 134 insertions, 1 deletions
diff --git a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H
index ab702840d..382daf886 100644
--- a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H
+++ b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.H
@@ -1,7 +1,7 @@
//
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2022 by Bill Spitzak and others.
+// Copyright 2022-2023 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
@@ -32,8 +32,19 @@ public:
void translate(int x, int y) FL_OVERRIDE;
void untranslate() FL_OVERRIDE;
Fl_RGB_Image *image() FL_OVERRIDE;
+ void mask(const Fl_RGB_Image *) FL_OVERRIDE;
#if FLTK_USE_CAIRO
cairo_t *cairo_;
+ struct shape_data_type {
+ double scale;
+ cairo_pattern_t *mask_pattern_;
+ cairo_t *bg_cr;
+ } *shape_data_;
+#else
+ struct shape_data_type {
+ Pixmap background;
+ Fl_RGB_Image* mask;
+ } *shape_data_;
#endif
};
diff --git a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx
index bcaf7d46a..87e55b417 100644
--- a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx
+++ b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx
@@ -17,6 +17,7 @@
#include <FL/platform.H>
#include "Fl_Xlib_Image_Surface_Driver.H"
#include "../../Fl_Screen_Driver.H"
+#include <stdlib.h>
#if FLTK_USE_CAIRO
# include <cairo-xlib.h>
# include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H"
@@ -37,6 +38,7 @@ Fl_Xlib_Image_Surface_Driver::Fl_Xlib_Image_Surface_Driver(int w, int h, int hig
}
offscreen = (Fl_Offscreen)XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth);
}
+ shape_data_ = NULL;
#if FLTK_USE_CAIRO
driver(new Fl_X11_Cairo_Graphics_Driver());
cairo_surface_t *s = cairo_xlib_surface_create(fl_display, offscreen, fl_visual->visual, w, h);
@@ -52,7 +54,24 @@ Fl_Xlib_Image_Surface_Driver::Fl_Xlib_Image_Surface_Driver(int w, int h, int hig
Fl_Xlib_Image_Surface_Driver::~Fl_Xlib_Image_Surface_Driver() {
#if FLTK_USE_CAIRO
+ if (shape_data_) {
+ cairo_surface_t *surf;
+ cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
+ unsigned char *bits = cairo_image_surface_get_data(surf);
+ cairo_pattern_destroy(shape_data_->mask_pattern_);
+ delete[] bits;
+ Pixmap p = cairo_xlib_surface_get_drawable(cairo_get_target(shape_data_->bg_cr));
+ XFreePixmap(fl_display, p);
+ cairo_destroy(shape_data_->bg_cr);
+ free(shape_data_);
+ }
cairo_destroy(cairo_);
+#else
+ if (shape_data_) {
+ XFreePixmap(fl_display, shape_data_->background);
+ delete shape_data_->mask;
+ free(shape_data_);
+ }
#endif
if (offscreen && !external_offscreen) XFreePixmap(fl_display, (Pixmap)offscreen);
delete driver();
@@ -84,14 +103,117 @@ void Fl_Xlib_Image_Surface_Driver::untranslate() {
#endif
}
+
Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image()
{
+ if (shape_data_) {
+#if FLTK_USE_CAIRO
+ // draw above the secondary offscreen the main offscreen masked by mask_pattern_
+ cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr();
+ cairo_pattern_t *paint_pattern = cairo_pattern_create_for_surface(cairo_get_target(c));
+ cairo_set_source(shape_data_->bg_cr, paint_pattern);
+ cairo_mask(shape_data_->bg_cr, shape_data_->mask_pattern_);
+ cairo_pattern_destroy(paint_pattern);
+ // copy secondary offscreen to the main offscreen
+ cairo_pattern_t *pat = cairo_pattern_create_for_surface(cairo_get_target(shape_data_->bg_cr));
+ cairo_scale(c, shape_data_->scale, shape_data_->scale);
+ cairo_set_source(c, pat),
+ cairo_paint(c);
+ cairo_pattern_destroy(pat);
+ // delete secondary offscreen
+ cairo_surface_t *surf;
+ cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
+ unsigned char *bits = cairo_image_surface_get_data(surf);
+ cairo_pattern_destroy(shape_data_->mask_pattern_);
+ delete[] bits;
+ Pixmap p = cairo_xlib_surface_get_drawable(cairo_get_target(shape_data_->bg_cr));
+ XFreePixmap(fl_display, p);
+ cairo_destroy(shape_data_->bg_cr);
+#else // !FLTK_USE_CAIRO
+ // draw the main offscreen masked by shape_data_->mask above the background offscreen
+ int w, h;
+ printable_rect(&w, &h);
+ Fl_RGB_Image *img_main = Fl::screen_driver()->read_win_rectangle(0, 0, w, h, 0);
+ fl_window = shape_data_->background; // temporary change
+ Fl_RGB_Image *img_background = Fl::screen_driver()->read_win_rectangle(0, 0, w, h, 0);
+ fl_window = offscreen;
+ Fl_Image_Surface_Driver::copy_with_mask(shape_data_->mask,
+ (uchar*)img_background->array,
+ (uchar*)img_main->array,
+ 3 * shape_data_->mask->w(), false);
+ delete img_main;
+ // copy background offscreen to main offscreen
+ float s = driver()->scale();
+ driver()->scale(1);
+ fl_draw_image(img_background->array, 0, 0,
+ img_background->data_w(), img_background->data_h());
+ driver()->scale(s);
+ delete img_background;
+ // delete background offscreen
+ XFreePixmap(fl_display, shape_data_->background);
+ delete shape_data_->mask;
+#endif // FLTK_USE_CAIRO
+ free(shape_data_);
+ shape_data_ = NULL;
+}
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(0, 0, width, height, 0);
return image;
}
+
void Fl_Xlib_Image_Surface_Driver::end_current()
{
fl_window = pre_window;
Fl_Surface_Device::end_current();
}
+
+
+#if FLTK_USE_CAIRO
+
+void Fl_Xlib_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) {
+ bool using_copy = false;
+ shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type));
+ int W, H;
+ cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr();
+ cairo_surface_t *c_surface = cairo_get_target(c);
+ W = cairo_xlib_surface_get_width(c_surface);
+ H = cairo_xlib_surface_get_height(c_surface);
+ if (W != mask->data_w() || H != mask->data_h()) {
+ Fl_RGB_Image *copy = (Fl_RGB_Image*)mask->copy(W, H);
+ mask = copy;
+ using_copy = true;
+ }
+ shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::calc_cairo_mask(mask);
+ //duplicate current offscreen content to new cairo_t* shape_data_->bg_cr
+ int width, height;
+ printable_rect(&width, &height);
+ Pixmap pxm = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), W, H, fl_visual->depth);
+ cairo_surface_t *background = cairo_xlib_surface_create(fl_display, pxm, fl_visual->visual, W, H);
+ shape_data_->bg_cr = cairo_create(background);
+ cairo_surface_destroy(background);
+ cairo_surface_flush(c_surface);
+ cairo_pattern_t *pat = cairo_pattern_create_for_surface(c_surface);
+ cairo_set_source(shape_data_->bg_cr, pat),
+ cairo_paint(shape_data_->bg_cr);
+ cairo_pattern_destroy(pat);
+ shape_data_->scale = double(width) / W;
+ if (using_copy) delete mask;
+}
+
+#else
+
+void Fl_Xlib_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) {
+ shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type));
+ // get dimensions
+ int W, H;
+ Fl::screen_driver()->offscreen_size(offscreen, W, H);
+ // compute depth-1 mask
+ shape_data_->mask = Fl_Image_Surface_Driver::RGB3_to_RGB1(mask, W, H);
+
+ // duplicate current offscreen content to new, background offscreen
+ shape_data_->background = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), W, H, fl_visual->depth);
+ driver()->restore_clip();
+ XCopyArea(fl_display, (Pixmap)offscreen, shape_data_->background, (GC)driver()->gc(), 0, 0, W, H, 0, 0);
+}
+
+#endif // FLTK_USE_CAIRO