Browse Source

Revert "Replace X clipping with custom code based on FLTK2's Rectangle class to interact better with Cairo."

Use cairo_region_t for clipping instead of Fl_Rectangle.
tags/v1.3.1000
Jonathan Moore Liles 13 years ago
parent
commit
b447ad1d3b
8 changed files with 204 additions and 290 deletions
  1. +0
    -128
      FL/Fl_Rectangle.H
  2. +5
    -2
      FL/x.H
  3. +62
    -7
      src/Fl.cxx
  4. +0
    -108
      src/Fl_Rectangle.cxx
  5. +3
    -1
      src/Fl_x.cxx
  6. +0
    -1
      src/Makefile
  7. +1
    -1
      src/fl_font_xft.cxx
  8. +133
    -42
      src/fl_rect.cxx

+ 0
- 128
FL/Fl_Rectangle.H View File

@@ -1,128 +0,0 @@
// "$Id: Fl_Rectangle.h 8500 2011-03-03 09:20:46Z bgbnbigben $"
//
// Copyright 1998-2006 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php

#ifndef fltk_Fl_Rectangle_h
#define fltk_Fl_Rectangle_h

// rectangle macros that help keeping rectangle predicates as strict as possible
// even when not using rectangles in some situations (as when only using w h scalars)
// so that there is only one strict defintion for common predicates,
// if one change the following, it will be repercuted in all the core lib
#define FLTK_RECT_EMPTY(w,h) (w <= 0 || h <= 0)
// we should always use the same evaluation for center_x, center_y in all corelib code:
//#define FLTK_CENTER_X(coord, length) (coord + (length>>1))
//#define FLTK_CENTER_Y(coord, length) (coord + (length>>1))

class Fl_Rectangle {
int x_, y_, w_, h_;

public:

/*! Left edge */
int x() const {return x_;}
/*! Top edge */
int y() const {return y_;}
/*! Distance between left and right edges */
int w() const {return w_;}
/*! Distance between top and bottom edges */
int h() const {return h_;}
/*! Return x()+w(), the right edge of the rectangle. */
int r() const {return x_+w_;}
/*! Return y()+h(), the bottom edge of the rectangle. */
int b() const {return y_+h_;}
/*! Move the rectangle so the left edge is at \a v. */
void x(int v) {x_ = v;}
/*! Move the rectangle so the top edge is at \a v. */
void y(int v) {y_ = v;}
/*! Change w() by moving the right edge. x() does not change. */
void w(int v) {w_ = v;}
/*! Change h() by moving the bottom edge. y() does not change. */
void h(int v) {h_ = v;}
/*! Change x() without changing r(), by changing the width. */
void set_x(int v) {w_ -= v-x_; x_ = v;}
/*! Change y() without changing b(), by changing the height. */
void set_y(int v) {h_ -= v-y_; y_ = v;}
/*! Change r() without changing x(), by changine the width. */
void set_r(int v) {w_ = v-x_;}
/*! Change b() without changing y(), by changine the height. */
void set_b(int v) {h_ = v-y_;}
/*! Set x(), y(), w(), and h() all at once. */
void set(int x, int y, int w, int h) {x_=x; y_=y; w_=w; h_=h;}
/*! Sets x, y, w, h so that's it's centered or aligned (if flags!=0) inside the source r */
void set (const Fl_Rectangle& r, int w, int h, int flags = 0);
/*! Add \a d to x() without changing r() (it reduces w() by \a d). */
void move_x(int d) {x_ += d; w_ -= d;}
/*! Add \a d to y() without changing b() (it reduces h() by \a d). */
void move_y(int d) {y_ += d; h_ -= d;}
/*! Add \a d to r() and w(). */
void move_r(int d) {w_ += d;}
/*! Add \a d to b() and h(). */
void move_b(int d) {h_ += d;}
/*! Move all edges in by \a d. See also Symbol::inset() */
void inset(int d) {x_ += d; y_ += d; w_ -= 2*d; h_ -= 2*d;}
/*! Move entire rectangle by given distance in x and y. */
void move(int dx, int dy) {x_ += dx; y_ += dy;}
/*! True if w() or h() are less or equal to zero. */
bool empty() const {return FLTK_RECT_EMPTY(w_, h_);}
/*! Same as !empty(), true if w() and h() are both greater than zero. */
bool not_empty() const {return !FLTK_RECT_EMPTY(w_, h_);}
/*! Integer center position. Rounded to the left if w() is odd. */
int center_x() const {return x_+(w_>>1);}
/*! Integer center position. Rounded to lower y if h() is odd. */
int center_y() const {return y_+(h_>>1);}
/*! Where to put baseline to center current font nicely */
int baseline_y() const;

Fl_Rectangle() {}

/*! Constructor that sets x(), y(), w(), and h(). */
Fl_Rectangle(int x, int y, int w, int h) : x_(x), y_(y), w_(w), h_(h) {}

/*! Constructor that sets x() and y() to zero, and sets w() and h(). */
Fl_Rectangle(int w, int h) : x_(0), y_(0), w_(w), h_(h) {}

/*! Copy constructor. */
Fl_Rectangle(const Fl_Rectangle& r) : x_(r.x_),y_(r.y_),w_(r.w_),h_(r.h_) {}

/*! Constructor that calls set(). */
Fl_Rectangle(const Fl_Rectangle& r, int w, int h, int flags = 0) {set(r,w,h,flags);}

/*! True if rectangle contains the pixel who's upper-left corner is at x,y */
bool contains(int x, int y) const {return x>=x_ && y>=y_ && x<x_+w_ && y<y_+h_;}

/* returns true if the rectangles intersect at all */
bool intersects ( const Fl_Rectangle &r ) const
{
Fl_Rectangle r2( r );

r2.intersect( *this );

return ! r2.empty();
}

void merge(const Fl_Rectangle& r);
void intersect(const Fl_Rectangle& r);

};

#endif

+ 5
- 2
FL/x.H View File

@@ -46,7 +46,6 @@

# include "Enumerations.H"
#include <FL/Fl_Cairo.H>
#include <FL/Fl_Rectangle.H>

# ifdef WIN32
# include "win32.H"
@@ -65,7 +64,11 @@
# include "Fl_Window.H"
# include "Xutf8.h"
// Mirror X definition of Region to Fl_Region, for portability...
typedef Fl_Rectangle * Fl_Region;
#if FLTK_USE_CAIRO
typedef cairo_region_t * Fl_Region;
#else
typedef Region Fl_Region;
#endif

FL_EXPORT void fl_open_display();
FL_EXPORT void fl_open_display(Display*);


+ 62
- 7
src/Fl.cxx View File

@@ -753,7 +753,15 @@ void Fl::flush() {
if (!wi->visible_r()) continue;
if (wi->damage()) {wi->make_current(); i->flush(); wi->clear_damage();}
// destroy damage regions for windows that don't use them:
if (i->region) {delete i->region; i->region = 0;}
#if FLTK_USE_CAIRO
if ( i->region )
{
cairo_region_destroy( i->region );
i->region = 0;
}
#else
if (i->region) {XDestroyRegion(i->region); i->region = 0;}
#endif
}
}
#if defined(USE_X11)
@@ -1433,8 +1441,15 @@ void Fl_Window::hide() {
if ( ip->xid == fl_window && !parent() )
fl_window = 0;
#endif

if (ip->region) delete ip->region; ip->region = 0;
#if FLTK_USE_CAIRO
if (ip->region)
{
cairo_region_destroy( ip->region );
ip->region = 0;
}
#else
if (ip->region) XDestroyRegion(ip->region);
#endif

#if defined(USE_X11)
#if FLTK_HAVE_CAIRO
@@ -1639,7 +1654,15 @@ void Fl_Widget::damage(uchar fl) {
// damage entire window by deleting the region:
Fl_X* i = Fl_X::i((Fl_Window*)this);
if (!i) return; // window not mapped, so ignore it
if (i->region) {delete i->region; i->region = 0;}
#if FLTK_USE_CAIRO
if ( i->region )
{
cairo_region_destroy( i->region );
i->region = 0;
}
#else
if (i->region) {XDestroyRegion(i->region); i->region = 0;}
#endif
damage_ |= fl;
Fl::damage(FL_DAMAGE_CHILD);
}
@@ -1674,7 +1697,21 @@ void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
// if we already have damage we must merge with existing region:
if (i->region) {
#if defined(USE_X11)
i->region->merge( Fl_Rectangle( X, Y, W, H ) );

#if FLTK_USE_CAIRO
cairo_rectangle_int_t rect;
rect.x = X;
rect.y = Y;
rect.width = W;
rect.height = H;

cairo_region_union_rectangle( i->region, &rect );
#else
XRectangle R;
R.x = X; R.y = Y; R.width = W; R.height = H;
XUnionRectWithRegion(&R, i->region, i->region);
#endif
#elif defined(WIN32)
Fl_Region R = XRectangleRegion(X, Y, W, H);
CombineRgn(i->region, i->region, R, RGN_OR);
@@ -1695,9 +1732,27 @@ void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
}
wi->damage_ |= fl;
} else {


#if FLTK_USE_CAIRO
if ( i->region )
cairo_region_destroy( i->region );

i->region = cairo_region_create();
cairo_rectangle_int_t rect;
rect.x = X;
rect.y = Y;
rect.width = W;
rect.height = H;

cairo_region_union_rectangle( i->region, &rect );
#else

// create a new region:
if (i->region) delete i->region;
i->region = new Fl_Rectangle(X,Y,W,H);
if (i->region) XDestroyRegion(i->region);
i->region = XRectangleRegion(X,Y,W,H);
#endif
wi->damage_ = fl;
}
Fl::damage(FL_DAMAGE_CHILD);


+ 0
- 108
src/Fl_Rectangle.cxx View File

@@ -1,108 +0,0 @@
// "$Id: Fl_Rectangle.h 8500 2011-03-03 09:20:46Z bgbnbigben $"
//
// Copyright 1998-2006 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php

#include <FL/Fl_Rectangle.H>
#include <FL/fl_draw.H>

/*! \class Fl_Rectangle
Describes an integer-sized rectangle. This is the base class of
Widget, and also used a lot to pass rectangular areas to drawing
functions. Almost all the functions are inline.

Negative w() or h() is supposed to mean an empty and thus
invisible rectangle, but some code will treat the rectangle as
reflected about x or y. Set the size to zero to make sure you
have an empty one.
*/

/*! \fn Rectangle::Rectangle()
The default constructor does not put anything into the fields!
You can either call set() or just modify the x_, y_, w_, and h_
variables directly.
*/

/** Initialize to the size w,h. The rectangle is placed inside the
source rectangle \a r either centered or against an edge depending
on the FL_ALIGN values in \a flags. For centered alignment if the
difference in sizes is odd, it always rounds up and left.
Default value for \a flags is to center in both directions.
*/
void Fl_Rectangle::set(const Fl_Rectangle& r, int w, int h, int flags) {
if (flags & FL_ALIGN_LEFT) {
if (flags & FL_ALIGN_RIGHT && w > r.w()) x_ = r.r()-w;
else x_ = r.x();
} else if (flags & FL_ALIGN_RIGHT) {
x_ = r.r()-w;
} else {
x_ = r.x()+((r.w()-w)>>1);
// fabien: shouldn't it consider the case r is smaller to avoid negative values ?
// WAS: no, it is supposed to center at all times. The right-shift
// instead of divide-by-2 is to avoid shifting as it goes negative.
// fabien : well while debugging i observed the shift doesn't avoid
// to get negative value at least on Win32
// WAS: no, it is *supposed* to return a negative value! I want the
// rectangle "centered" even if it is *bigger*.
// if (x_<0) x_=0;
}
if (flags & FL_ALIGN_TOP) {
if (flags & FL_ALIGN_BOTTOM && h > r.h()) y_ = r.b()-h;
else y_ = r.y();
} else if (flags & FL_ALIGN_BOTTOM) {
y_ = r.b()-h;
} else {
y_ = r.y()+((r.h()-h)>>1);
// see above
// if (y_<0) y_=0;
}
w_ = w;
h_ = h;
}

/**
Replace the value with the union of this rectangle and \a R
(ie the rectangle that surrounds both of these rectangles).
If one rectangle is empty(), the other is returned unchanged
(ie it does not union in the degenerate point of that rectangle).
*/
void Fl_Rectangle::merge(const Fl_Rectangle& R) {
if (R.empty()) return;
if (empty()) {*this = R; return;}
if (R.x() < x()) set_x(R.x());
if (R.r() > r()) set_r(R.r());
if (R.y() < y()) set_y(R.y());
if (R.b() > b()) set_b(R.b());
}

/**
Replace the value with the intersection of this rectangle and \a R.
If the rectangles do not intersect, the result may have negative
width and/or height, this means empty() will return true, but some
code may still draw this rectangle.
*/
void Fl_Rectangle::intersect(const Fl_Rectangle& R) {
if (R.x() > x()) set_x(R.x());
if (R.r() < r()) set_r(R.r());
if (R.y() > y()) set_y(R.y());
if (R.b() < b()) set_b(R.b());
}


+ 3
- 1
src/Fl_x.cxx View File

@@ -1691,7 +1691,7 @@ Fl_X* Fl_X::set_xid(Fl_Window* win, Window winxid) {
xp->setwindow(win);
xp->next = Fl_X::first;
xp->region = 0;
xp->wait_for_expose = 0;
xp->wait_for_expose = 1;
// xp->backbuffer_bad = 1;
Fl_X::first = xp;
if (win->modal()) {Fl::modal_ = win; fl_fix_focus();}
@@ -2014,6 +2014,8 @@ void Fl_Window::show() {
labeltype(FL_NO_LABEL);
}



Fl_Tooltip::exit(this);
if (!shown()) {
fl_open_display();


+ 0
- 1
src/Makefile View File

@@ -170,7 +170,6 @@ CPPFILES = \
Clean_Theme.cxx \
Crystal_Theme.cxx \
themes.cxx \
Fl_Rectangle.cxx \
ps_image.cxx
OBJCPPFILES = \


+ 1
- 1
src/fl_font_xft.cxx View File

@@ -113,7 +113,7 @@ void *fl_xftfont = 0;
//const char* fl_encoding_ = "iso8859-1";
const char* fl_encoding_ = "iso10646-1";

extern Region XRegionFromRectangle ( Fl_Rectangle *rg );
extern Region XRegionFromRectangle ( Fl_Region rg );

static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, int angle) {
if (fnum==-1) { // special case to stop font caching


+ 133
- 42
src/fl_rect.cxx View File

@@ -511,10 +511,28 @@ void Fl_Graphics_Driver::point(int x, int y) {
#endif
}

Region XRegionFromRectangle ( Fl_Rectangle *rg )
Region XRegionFromRectangle ( Fl_Region rg )
{
if ( rg )
{
#if FLTK_USE_CAIRO
Region region = XCreateRegion();

XRectangle rr;
cairo_rectangle_int_t rect;

cairo_region_get_extents( rg, &rect );

rr.x = rect.x;
rr.y = rect.y;
rr.width = rect.width;
rr.height = rect.height;
XUnionRectWithRegion( &rr, region, region );

return region;
#else
Region region = XCreateRegion();

XRectangle rr;
@@ -526,6 +544,7 @@ Region XRegionFromRectangle ( Fl_Rectangle *rg )
XUnionRectWithRegion( &rr, region, region );

return region;
#endif
}

return 0;
@@ -537,7 +556,27 @@ Region XRegionFromRectangle ( Fl_Rectangle *rg )
// Missing X call: (is this the fastest way to init a 1-rectangle region?)
// MSWindows equivalent exists, implemented inline in win32.H
Fl_Region XRectangleRegion(int x, int y, int w, int h) {
return new Fl_Rectangle( x, y, w, h );

#if FLTK_USE_CAIRO
cairo_rectangle_int_t rect;
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;

return cairo_region_create_rectangle( &rect );

#else

XRectangle R;
clip_to_short(x, y, w, h);
R.x = x; R.y = y; R.width = w; R.height = h;
Fl_Region r = XCreateRegion();
XUnionRectWithRegion(&R, r, r);
return r;
#endif
}
#endif

@@ -545,14 +584,10 @@ void Fl_Graphics_Driver::restore_clip() {
fl_clip_state_number++;
Fl_Region r = rstack[rstackptr];
#if defined(USE_X11)
if (r)
{
Region xr = XRegionFromRectangle( r );
XSetRegion(fl_display, fl_gc, xr );
XDestroyRegion( xr );
}
else
XSetClipMask(fl_display, fl_gc, 0);
#if ! FLTK_USE_CAIRO
if (r) XSetRegion(fl_display, fl_gc, r);
else XSetClipMask(fl_display, fl_gc, 0);
#endif
#elif defined(WIN32)
SelectClipRgn(fl_gc, r); //if r is NULL, clip is automatically cleared
#elif defined(__APPLE_QUARTZ__)
@@ -583,8 +618,16 @@ void Fl_Graphics_Driver::restore_clip() {

if ( r )
{
cairo_rectangle_int_t rect;

for ( int i = cairo_region_num_rectangles( r ); --i >= 0; )
{
cairo_region_get_rectangle( r, i, &rect );
cairo_rectangle( cr, rect.x, rect.y, rect.width, rect.height );
}
// cairo_set_source_rgb( cr, 0, 1, 0 );
cairo_rectangle( cr, r->x(), r->y(), r->w(), r->h() );
// cairo_rectangle( cr, r->x(), r->y(), r->w(), r->h() );
// cairo_stroke_preserve( cr );

cairo_clip( cr );
@@ -596,9 +639,17 @@ void Fl_Graphics_Driver::restore_clip() {

void Fl_Graphics_Driver::clip_region(Fl_Region r) {
Fl_Region oldr = rstack[rstackptr];
if (oldr && r != oldr ) delete oldr;
#if FLTK_USE_CAIRO
if (oldr && r != oldr )
{
cairo_region_destroy( oldr );
}
rstack[rstackptr] = r ? new Fl_Rectangle( *r ) : 0;
rstack[rstackptr] = r ? cairo_region_reference( r ) : 0;
#else
if (oldr && r != oldr ) XDestroyRegion(oldr);
rstack[rstackptr] = r;
#endif
fl_restore_clip();
}

@@ -609,16 +660,18 @@ Fl_Region Fl_Graphics_Driver::clip_region() {
void Fl_Graphics_Driver::push_clip(int x, int y, int w, int h) {
Fl_Region r;
if (w > 0 && h > 0) {
r = new Fl_Rectangle( x, y, w, h );
r = XRectangleRegion(x,y,w,h);
Fl_Region current = rstack[rstackptr];
if (current) {
#if defined(USE_X11)
r->intersect( *current );
if ( r->empty() )
{
delete r;
r = new Fl_Rectangle( 0, 0, 0, 0 );
}
#if FLTK_USE_CAIRO
cairo_region_intersect( r, current );
#else
Fl_Region temp = XCreateRegion();
XIntersectRegion(current, r, temp);
XDestroyRegion(r);
r = temp;
#endif
#elif defined(WIN32)
CombineRgn(r,r,current,RGN_AND);
#elif defined(__APPLE_QUARTZ__)
@@ -630,7 +683,7 @@ void Fl_Graphics_Driver::push_clip(int x, int y, int w, int h) {
}
} else { // make empty clip region:
#if defined(USE_X11)
r = new Fl_Rectangle( 0, 0, 0, 0 );
r = XRectangleRegion( 0, 0, 0, 0 );
#elif defined(WIN32)
r = CreateRectRgn(0,0,0,0);
#elif defined(__APPLE_QUARTZ__)
@@ -655,7 +708,14 @@ void Fl_Graphics_Driver::push_no_clip() {
void Fl_Graphics_Driver::pop_clip() {
if (rstackptr > 0) {
Fl_Region oldr = rstack[rstackptr--];
if (oldr) delete oldr;
#if FLTK_USE_CAIRO
if (oldr)
{
cairo_region_destroy( oldr );
}
#else
if (oldr) XDestroyRegion(oldr);
#endif
} else Fl::warning("fl_pop_clip: clip stack underflow!\n");
fl_restore_clip();
}
@@ -666,8 +726,18 @@ int Fl_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
if (!r) return 1;
#if defined (USE_X11)
// get rid of coordinates outside the 16-bit range the X calls take.
// if (clip_to_short(x,y,w,h)) return 0; // clipped
return r->intersects( Fl_Rectangle( x, y, w, h ) );
if (clip_to_short(x,y,w,h)) return 0; // clipped

#if FLTK_USE_CAIRO
cairo_rectangle_int_t rect;
rect.x = x; rect.y = y; rect.width = w; rect.height = h;

cairo_region_overlap_t o = cairo_region_contains_rectangle( r, &rect );

return o != CAIRO_REGION_OVERLAP_OUT;
#else
return XRectInRegion(r, x, y, w, h);
#endif
#elif defined(WIN32)
RECT rect;
if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { // in case of print context, convert coords from logical to device
@@ -695,31 +765,52 @@ int Fl_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int
X = x; Y = y; W = w; H = h;
Fl_Region r = rstack[rstackptr];
if (!r) return 0;
#if defined(USE_X11)
#if FLTK_USE_CAIRO
cairo_rectangle_int_t rect;
rect.x = x; rect.y = y; rect.width = w; rect.height = h;

Fl_Rectangle rec( x, y, w, h );
rec.intersect( *r );
cairo_region_t *t = cairo_region_copy( r );

X = rec.x(); Y = rec.y(); W = rec.w(); H = rec.h();
cairo_region_intersect_rectangle( t, &rect );

if ( r->contains( x, y ) && r->contains( x + w - 1, y + h - 1 ) )
{
/* completely inside */
return 0;
}
cairo_region_get_extents( t, &rect );

if ( rec.empty() )
X = rect.x; Y = rect.y; W = rect.width; H = rect.height;

cairo_region_overlap_t o = cairo_region_contains_rectangle( r, &rect );
switch ( o )
{
H = W = 0;
/* completely outside */
return 2;
case CAIRO_REGION_OVERLAP_IN:
return 0;
case CAIRO_REGION_OVERLAP_OUT:
return 2;
case CAIRO_REGION_OVERLAP_PART:
return 1;
default:
return 2;
}

/* partial */

#else
switch (XRectInRegion(r, x, y, w, h)) {
case RectangleOut: // completely outside
W = H = 0;
return 2;
case RectangleIn: // completely inside:
return 0;
default: // partial:
break;
}
Fl_Region rr = XRectangleRegion(x,y,w,h);
Fl_Region temp = XCreateRegion();
XIntersectRegion(r, rr, temp);
XRectangle rect;
XClipBox(temp, &rect);
X = rect.x; Y = rect.y; W = rect.width; H = rect.height;
XDestroyRegion(temp);
XDestroyRegion(rr);
return 1;

#if defined(USE_X11)
#endif

#elif defined(WIN32)
// The win32 API makes no distinction between partial and complete


Loading…
Cancel
Save