X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/03647350fc7cd141953c72e0284e928847d30f44..9c4672b0f849f87d83dd7a694b2c5d73f070ee2a:/src/osx/carbon/region.cpp diff --git a/src/osx/carbon/region.cpp b/src/osx/carbon/region.cpp index 1df36935a3..c1fb9d9518 100644 --- a/src/osx/carbon/region.cpp +++ b/src/osx/carbon/region.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// File: src/mac/carbon/region.cpp +// File: src/osx/carbon/region.cpp // Purpose: Region class // Author: Stefan Csomor // Created: Fri Oct 24 10:46:34 MET 1997 @@ -10,10 +10,13 @@ #include "wx/wxprec.h" +#if wxOSX_USE_COCOA_OR_CARBON + #include "wx/region.h" #ifndef WX_PRECOMP #include "wx/gdicmn.h" + #include "wx/dcmemory.h" #endif #include "wx/osx/private.h" @@ -21,6 +24,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject) IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject) +#define OSX_USE_SCANLINES 1 + //----------------------------------------------------------------------------- // wxRegionRefData implementation //----------------------------------------------------------------------------- @@ -65,14 +70,6 @@ public: // wxRegion //----------------------------------------------------------------------------- -/*! - * Create an empty region. - */ -wxRegion::wxRegion() -{ - m_refData = new wxRegionRefData(); -} - wxRegion::wxRegion(WXHRGN hRegion ) { wxCFRef< HIShapeRef > shape( (HIShapeRef) hRegion ); @@ -87,8 +84,8 @@ wxRegion::wxRegion(long x, long y, long w, long h) wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight) { m_refData = new wxRegionRefData(topLeft.x , topLeft.y , - topLeft.x - bottomRight.x , - topLeft.y - bottomRight.y); + bottomRight.x - topLeft.x, + bottomRight.y - topLeft.y); } wxRegion::wxRegion(const wxRect& rect) @@ -96,62 +93,896 @@ wxRegion::wxRegion(const wxRect& rect) m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height); } -wxRegion::wxRegion(size_t n, const wxPoint *points, wxPolygonFillMode WXUNUSED(fillStyle)) +#if OSX_USE_SCANLINES + +/* + + Copyright 1987, 1998 The Open Group + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of The Open Group shall + not be used in advertising or otherwise to promote the sale, use or + other dealings in this Software without prior written authorization + from The Open Group. + + */ + +/* miscanfill.h */ + +/* + * scanfill.h + * + * Written by Brian Kelleher; Jan 1985 + * + * This file contains a few macros to help track + * the edge of a filled object. The object is assumed + * to be filled in scanline order, and thus the + * algorithm used is an extension of Bresenham's line + * drawing algorithm which assumes that y is always the + * major axis. + * Since these pieces of code are the same for any filled shape, + * it is more convenient to gather the library in one + * place, but since these pieces of code are also in + * the inner loops of output primitives, procedure call + * overhead is out of the question. + * See the author for a derivation if needed. + */ + + +/* + * In scan converting polygons, we want to choose those pixels + * which are inside the polygon. Thus, we add .5 to the starting + * x coordinate for both left and right edges. Now we choose the + * first pixel which is inside the pgon for the left edge and the + * first pixel which is outside the pgon for the right edge. + * Draw the left pixel, but not the right. + * + * How to add .5 to the starting x coordinate: + * If the edge is moving to the right, then subtract dy from the + * error term from the general form of the algorithm. + * If the edge is moving to the left, then add dy to the error term. + * + * The reason for the difference between edges moving to the left + * and edges moving to the right is simple: If an edge is moving + * to the right, then we want the algorithm to flip immediately. + * If it is moving to the left, then we don't want it to flip until + * we traverse an entire pixel. + */ +#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \ +int dx; /* local storage */ \ +\ +/* \ +* if the edge is horizontal, then it is ignored \ +* and assumed not to be processed. Otherwise, do this stuff. \ +*/ \ +if ((dy) != 0) { \ +xStart = (x1); \ +dx = (x2) - xStart; \ +if (dx < 0) { \ +m = dx / (dy); \ +m1 = m - 1; \ +incr1 = -2 * dx + 2 * (dy) * m1; \ +incr2 = -2 * dx + 2 * (dy) * m; \ +d = 2 * m * (dy) - 2 * dx - 2 * (dy); \ +} else { \ +m = dx / (dy); \ +m1 = m + 1; \ +incr1 = 2 * dx - 2 * (dy) * m1; \ +incr2 = 2 * dx - 2 * (dy) * m; \ +d = -2 * m * (dy) + 2 * dx; \ +} \ +} \ +} + +#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \ +if (m1 > 0) { \ +if (d > 0) { \ +minval += m1; \ +d += incr1; \ +} \ +else { \ +minval += m; \ +d += incr2; \ +} \ +} else {\ +if (d >= 0) { \ +minval += m1; \ +d += incr1; \ +} \ +else { \ +minval += m; \ +d += incr2; \ +} \ +} \ +} + + +/* + * This structure contains all of the information needed + * to run the bresenham algorithm. + * The variables may be hardcoded into the declarations + * instead of using this structure to make use of + * register declarations. + */ +typedef struct { + int minor; /* minor axis */ + int d; /* decision variable */ + int m, m1; /* slope and slope+1 */ + int incr1, incr2; /* error increments */ +} BRESINFO; + + +#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \ +BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \ +bres.m, bres.m1, bres.incr1, bres.incr2) + +#define BRESINCRPGONSTRUCT(bres) \ +BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2) + + +/* mipoly.h */ + +/* + * fill.h + * + * Created by Brian Kelleher; Oct 1985 + * + * Include file for filled polygon routines. + * + * These are the data structures needed to scan + * convert regions. Two different scan conversion + * methods are available -- the even-odd method, and + * the winding number method. + * The even-odd rule states that a point is inside + * the polygon if a ray drawn from that point in any + * direction will pass through an odd number of + * path segments. + * By the winding number rule, a point is decided + * to be inside the polygon if a ray drawn from that + * point in any direction passes through a different + * number of clockwise and counter-clockwise path + * segments. + * + * These data structures are adapted somewhat from + * the algorithm in (Foley/Van Dam) for scan converting + * polygons. + * The basic algorithm is to start at the top (smallest y) + * of the polygon, stepping down to the bottom of + * the polygon by incrementing the y coordinate. We + * keep a list of edges which the current scanline crosses, + * sorted by x. This list is called the Active Edge Table (AET) + * As we change the y-coordinate, we update each entry in + * in the active edge table to reflect the edges new xcoord. + * This list must be sorted at each scanline in case + * two edges intersect. + * We also keep a data structure known as the Edge Table (ET), + * which keeps track of all the edges which the current + * scanline has not yet reached. The ET is basically a + * list of ScanLineList structures containing a list of + * edges which are entered at a given scanline. There is one + * ScanLineList per scanline at which an edge is entered. + * When we enter a new edge, we move it from the ET to the AET. + * + * From the AET, we can implement the even-odd rule as in + * (Foley/Van Dam). + * The winding number rule is a little trickier. We also + * keep the EdgeTableEntries in the AET linked by the + * nextWETE (winding EdgeTableEntry) link. This allows + * the edges to be linked just as before for updating + * purposes, but only uses the edges linked by the nextWETE + * link as edges representing spans of the polygon to + * drawn (as with the even-odd rule). + */ + +/* + * for the winding number rule + */ +#define CLOCKWISE 1 +#define COUNTERCLOCKWISE -1 + +typedef struct _EdgeTableEntry { + int ymax; /* ycoord at which we exit this edge. */ + BRESINFO bres; /* Bresenham info to run the edge */ + struct _EdgeTableEntry *next; /* next in the list */ + struct _EdgeTableEntry *back; /* for insertion sort */ + struct _EdgeTableEntry *nextWETE; /* for winding num rule */ + int ClockWise; /* flag for winding number rule */ +} EdgeTableEntry; + + +typedef struct _ScanLineList{ + int scanline; /* the scanline represented */ + EdgeTableEntry *edgelist; /* header node */ + struct _ScanLineList *next; /* next in the list */ +} ScanLineList; + + +typedef struct { + int ymax; /* ymax for the polygon */ + int ymin; /* ymin for the polygon */ + ScanLineList scanlines; /* header node */ +} EdgeTable; + + +/* + * Here is a struct to help with storage allocation + * so we can allocate a big chunk at a time, and then take + * pieces from this heap when we need to. + */ +#define SLLSPERBLOCK 25 + +typedef struct _ScanLineListBlock { + ScanLineList SLLs[SLLSPERBLOCK]; + struct _ScanLineListBlock *next; +} ScanLineListBlock; + +/* + * number of points to buffer before sending them off + * to scanlines() : Must be an even number + */ +#define NUMPTSTOBUFFER 200 + + +/* + * + * a few macros for the inner loops of the fill code where + * performance considerations don't allow a procedure call. + * + * Evaluate the given edge at the given scanline. + * If the edge has expired, then we leave it and fix up + * the active edge table; otherwise, we increment the + * x value to be ready for the next scanline. + * The winding number rule is in effect, so we must notify + * the caller when the edge has been removed so he + * can reorder the Winding Active Edge Table. + */ +#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \ +if (pAET->ymax == y) { /* leaving this edge */ \ +pPrevAET->next = pAET->next; \ +pAET = pPrevAET->next; \ +fixWAET = 1; \ +if (pAET) \ +pAET->back = pPrevAET; \ +} \ +else { \ +BRESINCRPGONSTRUCT(pAET->bres); \ +pPrevAET = pAET; \ +pAET = pAET->next; \ +} \ +} + + +/* + * Evaluate the given edge at the given scanline. + * If the edge has expired, then we leave it and fix up + * the active edge table; otherwise, we increment the + * x value to be ready for the next scanline. + * The even-odd rule is in effect. + */ +#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \ +if (pAET->ymax == y) { /* leaving this edge */ \ +pPrevAET->next = pAET->next; \ +pAET = pPrevAET->next; \ +if (pAET) \ +pAET->back = pPrevAET; \ +} \ +else { \ +BRESINCRPGONSTRUCT(pAET->bres); \ +pPrevAET = pAET; \ +pAET = pAET->next; \ +} \ +} + +/* mipolyutil.c */ + +static bool miCreateETandAET( + int /*count*/, + const wxPoint * /*pts*/, + EdgeTable * /*ET*/, + EdgeTableEntry * /*AET*/, + EdgeTableEntry * /*pETEs*/, + ScanLineListBlock * /*pSLLBlock*/ + ); + +static void miloadAET( + EdgeTableEntry * /*AET*/, + EdgeTableEntry * /*ETEs*/ + ); + +static void micomputeWAET( + EdgeTableEntry * /*AET*/ + ); + +static int miInsertionSort( + EdgeTableEntry * /*AET*/ + ); + +static void miFreeStorage( + ScanLineListBlock * /*pSLLBlock*/ + ); + +/* + * fillUtils.c + * + * Written by Brian Kelleher; Oct. 1985 + * + * This module contains all of the utility functions + * needed to scan convert a polygon. + * + */ + +/* + * InsertEdgeInET + * + * Insert the given edge into the edge table. + * First we must find the correct bucket in the + * Edge table, then find the right slot in the + * bucket. Finally, we can insert it. + * + */ +static bool +miInsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, + ScanLineListBlock **SLLBlock, int *iSLLBlock) { - wxUnusedVar(n); - wxUnusedVar(points); + EdgeTableEntry *start, *prev; + ScanLineList *pSLL, *pPrevSLL; + ScanLineListBlock *tmpSLLBlock; + + /* + * find the right bucket to put the edge into + */ + pPrevSLL = &ET->scanlines; + pSLL = pPrevSLL->next; + while (pSLL && (pSLL->scanline < scanline)) + { + pPrevSLL = pSLL; + pSLL = pSLL->next; + } + + /* + * reassign pSLL (pointer to ScanLineList) if necessary + */ + if ((!pSLL) || (pSLL->scanline > scanline)) + { + if (*iSLLBlock > SLLSPERBLOCK-1) + { + tmpSLLBlock = + (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock)); + if (!tmpSLLBlock) + return FALSE; + (*SLLBlock)->next = tmpSLLBlock; + tmpSLLBlock->next = (ScanLineListBlock *)NULL; + *SLLBlock = tmpSLLBlock; + *iSLLBlock = 0; + } + pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); + + pSLL->next = pPrevSLL->next; + pSLL->edgelist = (EdgeTableEntry *)NULL; + pPrevSLL->next = pSLL; + } + pSLL->scanline = scanline; + + /* + * now insert the edge in the right bucket + */ + prev = (EdgeTableEntry *)NULL; + start = pSLL->edgelist; + while (start && (start->bres.minor < ETE->bres.minor)) + { + prev = start; + start = start->next; + } + ETE->next = start; + + if (prev) + prev->next = ETE; + else + pSLL->edgelist = ETE; + return TRUE; +} -#if 0 - // no non-QD APIs available - // TODO : remove ? - // OS X somehow does not collect the region invisibly as before, so sometimes things - // get drawn on screen instead of just being combined into a region, therefore we allocate a temp gworld now - - GWorldPtr gWorld = NULL; - GWorldPtr oldWorld; - GDHandle oldGDHandle; - OSStatus err; - Rect destRect = { 0, 0, 1, 1 }; - - ::GetGWorld( &oldWorld, &oldGDHandle ); - err = ::NewGWorld( &gWorld, 32, &destRect, NULL, NULL, 0 ); - if ( err == noErr ) +/* + * CreateEdgeTable + * + * This routine creates the edge table for + * scan converting polygons. + * The Edge Table (ET) looks like: + * + * EdgeTable + * -------- + * | ymax | ScanLineLists + * |scanline|-->------------>-------------->... + * -------- |scanline| |scanline| + * |edgelist| |edgelist| + * --------- --------- + * | | + * | | + * V V + * list of ETEs list of ETEs + * + * where ETE is an EdgeTableEntry data structure, + * and there is one ScanLineList per scanline at + * which an edge is initially entered. + * + */ + +static bool +miCreateETandAET(int count, const wxPoint * pts, EdgeTable *ET, EdgeTableEntry *AET, + EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) +{ + const wxPoint* top, *bottom; + const wxPoint* PrevPt, *CurrPt; + int iSLLBlock = 0; + + int dy; + + if (count < 2) return TRUE; + + /* + * initialize the Active Edge Table + */ + AET->next = (EdgeTableEntry *)NULL; + AET->back = (EdgeTableEntry *)NULL; + AET->nextWETE = (EdgeTableEntry *)NULL; + AET->bres.minor = INT_MIN; + + /* + * initialize the Edge Table. + */ + ET->scanlines.next = (ScanLineList *)NULL; + ET->ymax = INT_MIN; + ET->ymin = INT_MAX; + pSLLBlock->next = (ScanLineListBlock *)NULL; + + PrevPt = &pts[count-1]; + + /* + * for each vertex in the array of points. + * In this loop we are dealing with two vertices at + * a time -- these make up one edge of the polygon. + */ + while (count--) { - ::SetGWorld( gWorld, GetGDevice() ); + CurrPt = pts++; + + /* + * find out which point is above and which is below. + */ + if (PrevPt->y > CurrPt->y) + { + bottom = PrevPt, top = CurrPt; + pETEs->ClockWise = 0; + } + else + { + bottom = CurrPt, top = PrevPt; + pETEs->ClockWise = 1; + } + + /* + * don't add horizontal edges to the Edge table. + */ + if (bottom->y != top->y) + { + pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ + + /* + * initialize integer edge algorithm + */ + dy = bottom->y - top->y; + BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres); + + if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) + { + miFreeStorage(pSLLBlock->next); + return FALSE; + } + + ET->ymax = wxMax(ET->ymax, PrevPt->y); + ET->ymin = wxMin(ET->ymin, PrevPt->y); + pETEs++; + } + + PrevPt = CurrPt; + } + return TRUE; +} - OpenRgn(); +/* + * loadAET + * + * This routine moves EdgeTableEntries from the + * EdgeTable into the Active Edge Table, + * leaving them sorted by smaller x coordinate. + * + */ - wxCoord x1, x2 , y1 , y2 ; - x2 = x1 = points[0].x ; - y2 = y1 = points[0].y ; +static void +miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs) +{ + EdgeTableEntry *pPrevAET; + EdgeTableEntry *tmp; + + pPrevAET = AET; + AET = AET->next; + while (ETEs) + { + while (AET && (AET->bres.minor < ETEs->bres.minor)) + { + pPrevAET = AET; + AET = AET->next; + } + tmp = ETEs->next; + ETEs->next = AET; + if (AET) + AET->back = ETEs; + ETEs->back = pPrevAET; + pPrevAET->next = ETEs; + pPrevAET = ETEs; + + ETEs = tmp; + } +} - ::MoveTo( x1, y1 ); - for (size_t i = 1; i < n; i++) +/* + * computeWAET + * + * This routine links the AET by the + * nextWETE (winding EdgeTableEntry) link for + * use by the winding number rule. The final + * Active Edge Table (AET) might look something + * like: + * + * AET + * ---------- --------- --------- + * |ymax | |ymax | |ymax | + * | ... | |... | |... | + * |next |->|next |->|next |->... + * |nextWETE| |nextWETE| |nextWETE| + * --------- --------- ^-------- + * | | | + * V-------------------> V---> ... + * + */ +static void +micomputeWAET(EdgeTableEntry *AET) +{ + EdgeTableEntry *pWETE; + int inside = 1; + int isInside = 0; + + AET->nextWETE = (EdgeTableEntry *)NULL; + pWETE = AET; + AET = AET->next; + while (AET) + { + if (AET->ClockWise) + isInside++; + else + isInside--; + + if ((!inside && !isInside) || + ( inside && isInside)) { - x2 = points[i].x ; - y2 = points[i].y ; - ::LineTo( x2, y2 ); + pWETE->nextWETE = AET; + pWETE = AET; + inside = !inside; } + AET = AET->next; + } + pWETE->nextWETE = (EdgeTableEntry *)NULL; +} - // close the polyline if necessary - if ( x1 != x2 || y1 != y2 ) - ::LineTo( x1, y1 ) ; +/* + * InsertionSort + * + * Just a simple insertion sort using + * pointers and back pointers to sort the Active + * Edge Table. + * + */ - RgnHandle tempRgn = NewRgn(); - CloseRgn( tempRgn ) ; +static int +miInsertionSort(EdgeTableEntry *AET) +{ + EdgeTableEntry *pETEchase; + EdgeTableEntry *pETEinsert; + EdgeTableEntry *pETEchaseBackTMP; + int changed = 0; + + AET = AET->next; + while (AET) + { + pETEinsert = AET; + pETEchase = AET; + while (pETEchase->back->bres.minor > AET->bres.minor) + pETEchase = pETEchase->back; + + AET = AET->next; + if (pETEchase != pETEinsert) + { + pETEchaseBackTMP = pETEchase->back; + pETEinsert->back->next = AET; + if (AET) + AET->back = pETEinsert->back; + pETEinsert->next = pETEchase; + pETEchase->back->next = pETEinsert; + pETEchase->back = pETEinsert; + pETEinsert->back = pETEchaseBackTMP; + changed = 1; + } + } + return(changed); +} - ::SetGWorld( oldWorld, oldGDHandle ); - wxCFRef tempShape( HIShapeCreateWithQDRgn(tempRgn ) ); - m_refData = new wxRegionRefData(tempShape); - DisposeRgn( tempRgn ); +/* + * Clean up our act. + */ +static void +miFreeStorage(ScanLineListBlock *pSLLBlock) +{ + ScanLineListBlock *tmpSLLBlock; + + while (pSLLBlock) + { + tmpSLLBlock = pSLLBlock->next; + free(pSLLBlock); + pSLLBlock = tmpSLLBlock; } - else +} + +/* mipolygen.c */ + +static bool +scanFillGeneralPoly( wxRegion* rgn, + int count, /* number of points */ + const wxPoint *ptsIn, /* the points */ + wxPolygonFillMode fillStyle + ) +{ + EdgeTableEntry *pAET; /* the Active Edge Table */ + int y; /* the current scanline */ + int nPts = 0; /* number of pts in buffer */ + EdgeTableEntry *pWETE; /* Winding Edge Table */ + ScanLineList *pSLL; /* Current ScanLineList */ + wxPoint * ptsOut; /* ptr to output buffers */ + int *width; + wxPoint FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ + int FirstWidth[NUMPTSTOBUFFER]; + EdgeTableEntry *pPrevAET; /* previous AET entry */ + EdgeTable ET; /* Edge Table header node */ + EdgeTableEntry AET; /* Active ET header node */ + EdgeTableEntry *pETEs; /* Edge Table Entries buff */ + ScanLineListBlock SLLBlock; /* header for ScanLineList */ + int fixWAET = 0; + + if (count < 3) + return(TRUE); + + if(!(pETEs = (EdgeTableEntry *) + malloc(sizeof(EdgeTableEntry) * count))) + return(FALSE); + ptsOut = FirstPoint; + width = FirstWidth; + if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) + { + free(pETEs); + return(FALSE); + } + pSLL = ET.scanlines.next; + + if (fillStyle == wxODDEVEN_RULE) + { + /* + * for each scanline + */ + for (y = ET.ymin; y < ET.ymax; y++) + { + /* + * Add a new edge to the active edge table when we + * get to the next edge. + */ + if (pSLL && y == pSLL->scanline) + { + miloadAET(&AET, pSLL->edgelist); + pSLL = pSLL->next; + } + pPrevAET = &AET; + pAET = AET.next; + + /* + * for each active edge + */ + while (pAET) + { + ptsOut->x = pAET->bres.minor; + ptsOut++->y = y; + *width++ = pAET->next->bres.minor - pAET->bres.minor; + nPts++; + + /* + * send out the buffer when its full + */ + if (nPts == NUMPTSTOBUFFER) + { + // (*pgc->ops->FillSpans)(dst, pgc, + // nPts, FirstPoint, FirstWidth,1); + + for ( int i = 0 ; i < nPts; ++i) + { + wxRect rect; + rect.y = FirstPoint[i].y; + rect.x = FirstPoint[i].x; + rect.height = 1; + rect.width = FirstWidth[i]; + rgn->Union(rect); + } + ptsOut = FirstPoint; + width = FirstWidth; + nPts = 0; + } + EVALUATEEDGEEVENODD(pAET, pPrevAET, y) + EVALUATEEDGEEVENODD(pAET, pPrevAET, y); + } + miInsertionSort(&AET); + } + } + else /* default to WindingNumber */ + { + /* + * for each scanline + */ + for (y = ET.ymin; y < ET.ymax; y++) + { + /* + * Add a new edge to the active edge table when we + * get to the next edge. + */ + if (pSLL && y == pSLL->scanline) + { + miloadAET(&AET, pSLL->edgelist); + micomputeWAET(&AET); + pSLL = pSLL->next; + } + pPrevAET = &AET; + pAET = AET.next; + pWETE = pAET; + + /* + * for each active edge + */ + while (pAET) + { + /* + * if the next edge in the active edge table is + * also the next edge in the winding active edge + * table. + */ + if (pWETE == pAET) + { + ptsOut->x = pAET->bres.minor; + ptsOut++->y = y; + *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor; + nPts++; + + /* + * send out the buffer + */ + if (nPts == NUMPTSTOBUFFER) + { + // (*pgc->ops->FillSpans)(dst, pgc, + // nPts, FirstPoint, FirstWidth,1); + for ( int i = 0 ; i < nPts ; ++i) + { + wxRect rect; + rect.y = FirstPoint[i].y; + rect.x = FirstPoint[i].x; + rect.height = 1; + rect.width = FirstWidth[i]; + rgn->Union(rect); + } + ptsOut = FirstPoint; + width = FirstWidth; + nPts = 0; + } + + pWETE = pWETE->nextWETE; + while (pWETE != pAET) + EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); + pWETE = pWETE->nextWETE; + } + EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); + } + + /* + * reevaluate the Winding active edge table if we + * just had to resort it or if we just exited an edge. + */ + if (miInsertionSort(&AET) || fixWAET) + { + micomputeWAET(&AET); + fixWAET = 0; + } + } + } + + /* + * Get any spans that we missed by buffering + */ + // (*pgc->ops->FillSpans)(dst, pgc, + // nPts, FirstPoint, FirstWidth,1); + for ( int i = 0 ; i < nPts; ++i) { - m_refData = new wxRegionRefData; + wxRect rect; + rect.y = FirstPoint[i].y; + rect.x = FirstPoint[i].x; + rect.height = 1; + rect.width = FirstWidth[i]; + rgn->Union(rect); } + + free(pETEs); + miFreeStorage(SLLBlock.next); + return(TRUE); +} + +#endif + +wxRegion::wxRegion(size_t n, const wxPoint *points, wxPolygonFillMode fillStyle) +{ + // Set the region to a polygon shape generically using a bitmap with the + // polygon drawn on it. + + m_refData = new wxRegionRefData(); + +#if OSX_USE_SCANLINES + scanFillGeneralPoly(this,n,points,fillStyle); #else - wxFAIL_MSG( "not implemented" ); - m_refData = NULL; + wxCoord mx = 0; + wxCoord my = 0; + wxPoint p; + size_t idx; + + // Find the max size needed to draw the polygon + for (idx=0; idx mx) + mx = pt.x; + if (pt.y > my) + my = pt.y; + } + + // Make the bitmap + wxBitmap bmp(mx, my); + wxMemoryDC dc(bmp); + dc.SetBackground(*wxBLACK_BRUSH); + dc.Clear(); + dc.SetPen(*wxWHITE_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawPolygon(n, (wxPoint*)points, 0, 0, fillStyle); + dc.SelectObject(wxNullBitmap); + bmp.SetMask(new wxMask(bmp, *wxBLACK)); + + // Use it to set this region + Union(bmp); #endif } @@ -183,35 +1014,66 @@ void wxRegion::Clear() // Move the region bool wxRegion::DoOffset(wxCoord x, wxCoord y) { - wxCHECK_MSG( M_REGION, false, wxT("invalid wxRegion") ); + wxCHECK_MSG( m_refData, false, wxT("invalid wxRegion") ); if ( !x && !y ) // nothing to do return true; + AllocExclusive(); + verify_noerr( HIShapeOffset( M_REGION , x , y ) ) ; return true ; } +bool wxRegion::DoUnionWithRect(const wxRect& rect) +{ + if ( !m_refData ) + { + m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height); + return true; + } + + AllocExclusive(); + + CGRect r = CGRectMake(rect.x , rect.y , rect.width , rect.height); + HIShapeUnionWithRect(M_REGION , &r); + + return true; +} //! Union /e region with this. bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op) { - wxCHECK_MSG( region.Ok(), false, wxT("invalid wxRegion") ); + wxCHECK_MSG( region.IsOk(), false, wxT("invalid wxRegion") ); - // Don't change shared data - if (!m_refData) - { - m_refData = new wxRegionRefData(); - } - else if (m_refData->GetRefCount() > 1) + // Handle the special case of not initialized (e.g. default constructed) + // region as we can't use HIShape functions if we don't have any shape. + if ( !m_refData ) { - wxRegionRefData* ref = (wxRegionRefData*)m_refData; - UnRef(); - m_refData = new wxRegionRefData(*ref); + switch ( op ) + { + case wxRGN_COPY: + case wxRGN_OR: + case wxRGN_XOR: + // These operations make sense with a null region. + *this = region; + return true; + + case wxRGN_AND: + case wxRGN_DIFF: + // Those ones don't really make sense so just leave this region + // empty/invalid. + return false; + } + + wxFAIL_MSG( wxT("Unknown region operation") ); + return false; } + AllocExclusive(); + switch (op) { case wxRGN_AND: @@ -248,11 +1110,21 @@ bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op) //# Information on region //----------------------------------------------------------------------------- -bool wxRegion::DoIsEqual(const wxRegion& WXUNUSED(region)) const +bool wxRegion::DoIsEqual(const wxRegion& region) const { - wxFAIL_MSG( wxT("not implemented") ); + // There doesn't seem to be any native function for checking the equality + // of HIShapes so we compute their differences to determine if they are + // equal. + wxRegion r(*this); + r.Subtract(region); + + if ( !r.IsEmpty() ) + return false; + + wxRegion r2(region); + r2.Subtract(*this); - return false; + return r2.IsEmpty(); } // Outer bounds of region @@ -286,8 +1158,11 @@ bool wxRegion::IsEmpty() const return true ; } -const WXHRGN wxRegion::GetWXHRGN() const +WXHRGN wxRegion::GetWXHRGN() const { + if ( !m_refData ) + return NULL; + return M_REGION ; } @@ -301,7 +1176,7 @@ wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const if (!m_refData) return wxOutRegion; - CGPoint p = { y , x } ; + CGPoint p = CGPointMake( x, y ) ; if (HIShapeContainsPoint( M_REGION , &p ) ) return wxInRegion; @@ -344,11 +1219,7 @@ wxRegionIterator::wxRegionIterator() wxRegionIterator::~wxRegionIterator() { - if (m_rects) - { - delete [] m_rects; - m_rects = NULL; - } + wxDELETEA(m_rects); } wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator) @@ -373,11 +1244,7 @@ wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator) */ void wxRegionIterator::SetRects(long numRects, wxRect *rects) { - if (m_rects) - { - delete [] m_rects; - m_rects = NULL; - } + wxDELETEA(m_rects); if (rects && (numRects > 0)) { @@ -412,40 +1279,6 @@ public : long m_current ; }; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - -OSStatus wxMacRegionToRectsCounterCallback( - UInt16 message, RgnHandle WXUNUSED(region), const Rect *WXUNUSED(rect), void *data ) -{ - long *m_numRects = (long*) data ; - if ( message == kQDRegionToRectsMsgInit ) - { - (*m_numRects) = 0 ; - } - else if (message == kQDRegionToRectsMsgParse) - { - (*m_numRects) += 1 ; - } - - return noErr; -} - -OSStatus wxMacRegionToRectsSetterCallback( - UInt16 message, RgnHandle WXUNUSED(region), const Rect *rect, void *data ) -{ - if (message == kQDRegionToRectsMsgParse) - { - RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ; - cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ; - } - - return noErr; -} - -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - OSStatus wxOSXRegionToRectsCounterCallback( int message, HIShapeRef WXUNUSED(region), const CGRect *WXUNUSED(rect), void *data ) { @@ -474,18 +1307,12 @@ OSStatus wxOSXRegionToRectsSetterCallback( return noErr; } -#endif - void wxRegionIterator::Reset(const wxRegion& region) { m_current = 0; m_region = region; - if (m_rects) - { - delete [] m_rects; - m_rects = NULL; - } + wxDELETEA(m_rects); if (m_region.IsEmpty()) { @@ -500,51 +1327,20 @@ void wxRegionIterator::Reset(const wxRegion& region) m_rects = new wxRect[m_numRects]; m_rects[0] = m_region.GetBox(); #endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - if ( HIShapeEnumerate != NULL ) + OSStatus err = HIShapeEnumerate (OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsCounterCallback, + (void*)&m_numRects); + if (err == noErr) { - OSStatus err = HIShapeEnumerate (OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsCounterCallback, - (void*)&m_numRects); - if (err == noErr) - { - m_rects = new wxRect[m_numRects]; - RegionToRectsCallbackData data ; - data.m_rects = m_rects ; - data.m_current = 0 ; - HIShapeEnumerate( OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsSetterCallback, - (void*)&data ); - } - else - { - m_numRects = 0; - } + m_rects = new wxRect[m_numRects]; + RegionToRectsCallbackData data ; + data.m_rects = m_rects ; + data.m_current = 0 ; + HIShapeEnumerate( OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsSetterCallback, + (void*)&data ); } else -#endif { -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - OSStatus err = noErr; - RgnHandle rgn = NewRgn(); - HIShapeGetAsQDRgn(OTHER_M_REGION(region), rgn); - - err = QDRegionToRects (rgn, kQDParseRegionFromTopLeft, wxMacRegionToRectsCounterCallback - , (void*)&m_numRects); - if (err == noErr) - { - m_rects = new wxRect[m_numRects]; - RegionToRectsCallbackData data ; - data.m_rects = m_rects ; - data.m_current = 0 ; - QDRegionToRects( rgn , kQDParseRegionFromTopLeft, wxMacRegionToRectsSetterCallback, - (void*)&data ); - } - else - { - m_numRects = 0; - } - DisposeRgn( rgn ); -#endif + m_numRects = 0; } } } @@ -606,3 +1402,5 @@ long wxRegionIterator::GetH() const return 0; } + +#endif