summaryrefslogtreecommitdiff
path: root/vcl/source/gdi/outdev.cxx
diff options
context:
space:
mode:
authorKurt Zenker <kz@openoffice.org>2005-11-02 12:29:39 +0000
committerKurt Zenker <kz@openoffice.org>2005-11-02 12:29:39 +0000
commit7fb7a608a10b515a822aefca7c94b9295fe46156 (patch)
treee7033aa74b54e636e59494ae80475b60594f285e /vcl/source/gdi/outdev.cxx
parent628820c311a9e36f3d77dc9dcc9da11d4b1fccb2 (diff)
INTEGRATION: CWS canvas02 (1.33.84); FILE MERGED
2005/10/09 07:06:58 thb 1.33.84.7: RESYNC: (1.33-1.35); FILE MERGED 2005/09/07 14:58:23 mbu 1.33.84.6: SetTriangleClipRegion() now plays well with the rest of the clipping code 2005/08/19 15:15:26 mbu 1.33.84.5: platform independent float to integer truncation 2005/08/19 14:50:06 mbu 1.33.84.4: consolidating spans in triangle clipper 2005/08/19 13:57:03 thb 1.33.84.3: #i10000# Using non-asm version for non-Windows 2005/08/18 15:31:02 mbu 1.33.84.2: latest changes in ImplSetTriangleClipRegion() 2005/08/17 15:28:36 mbu 1.33.84.1: SetTriangleClipRegion()
Diffstat (limited to 'vcl/source/gdi/outdev.cxx')
-rw-r--r--vcl/source/gdi/outdev.cxx668
1 files changed, 666 insertions, 2 deletions
diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx
index 0e05587bebae..3447d359f71d 100644
--- a/vcl/source/gdi/outdev.cxx
+++ b/vcl/source/gdi/outdev.cxx
@@ -4,9 +4,9 @@
*
* $RCSfile: outdev.cxx,v $
*
- * $Revision: 1.36 $
+ * $Revision: 1.37 $
*
- * last change: $Author: rt $ $Date: 2005-10-17 14:01:55 $
+ * last change: $Author: kz $ $Date: 2005-11-02 13:29:39 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
@@ -983,6 +983,634 @@ void OutputDevice::ImplSetClipRegion( const Region* pRegion )
// -----------------------------------------------------------------------
+namespace
+{
+ inline int iround( float x )
+ {
+ sal_Int32 a = *reinterpret_cast<const sal_Int32 *>(&x);
+ sal_Int32 exponent = (127 + 31) - ((a >> 23) & 0xFF);
+ sal_Int32 r = ((sal_Int32(a) << 8) | (1U << 31)) >> exponent;
+ r &= ((exponent - 32) >> 31);
+ sal_Int32 sign = a >> 31;
+ return r = (r ^ sign) - sign;
+ }
+
+ inline int floorDiv(int a, int b)
+ {
+ if(b == 0)
+ return 0x80000000;
+ if(a >= 0)
+ return a / b;
+ int q = -(-a / b); // quotient
+ int r = -a % b; // remainder
+ if(r)
+ q--;
+ return q;
+ }
+
+ inline int floorMod( int a, int b )
+ {
+ if(b == 0)
+ return 0x80000000;
+ if(a >= 0)
+ return a % b;
+ int r = -a % b; // remainder
+ if(r)
+ r = b - r;
+ return r;
+ }
+
+ inline int ceilDiv( int a, int b )
+ {
+ if(b == 0)
+ return 0x80000000;
+ a += - 1 + b;
+ if(a >= 0)
+ return a / b;
+ int q = -(-a / b); // quotient
+ int r = -a % b; // remainder
+ if(r)
+ q--;
+ return q;
+ }
+
+ inline int ceilMod( int a, int b )
+ {
+ if(b == 0)
+ return 0x80000000;
+ a += - 1 + b;
+ if(a >= 0)
+ return (a % b) + 1 - b;
+ int r = -a % b;
+ if(r)
+ r = b - r;
+ return r + 1 - b;
+ }
+
+ inline int ceilFix4(int x) { return (x + 0xF) & 0xFFFFFFF0; }
+
+ struct vertex
+ {
+ float x,y;
+ inline vertex( const Point &p )
+ : x((float)p.getX()),y((float)p.getY()) {}
+ };
+
+ template<class T> inline void swap(T &a, T &b) { T t=a; a=b; b=t; }
+
+ class SpanIterator
+ {
+ public:
+
+ SpanIterator( sal_Int32 *pTable, size_t dwPitch, sal_Int32 dwNumScanlines );
+ std::pair<sal_Int32,sal_Int32> GetNextSpan( void );
+ sal_Int32 GetNumRemainingScanlines( void );
+ sal_Int32 GetNumEqualScanlines( void );
+ SpanIterator &operator++ ();
+ SpanIterator &Skip( sal_Int32 dwNumScanlines );
+ sal_Int32 GetRemainingSpans( void ) const { return maNumSpans; }
+
+ private:
+
+ sal_Int32 *mpTable;
+ sal_Int32 *mpSpanArray;
+ sal_Int32 maNumSpans;
+ sal_Int32 maRemainingScanlines;
+ size_t maPitch;
+ };
+
+ inline SpanIterator::SpanIterator( sal_Int32 *pTable, size_t dwPitch, sal_Int32 dwNumScanlines )
+ : mpTable(pTable),maPitch(dwPitch),maRemainingScanlines(dwNumScanlines)
+ {
+ sal_Int32 *pNumSpans = mpTable;
+ mpSpanArray = reinterpret_cast<sal_Int32 *>(pNumSpans+2);
+ maNumSpans = *pNumSpans;
+ }
+
+ inline SpanIterator &SpanIterator::operator++ ()
+ {
+ --maRemainingScanlines;
+ mpTable += maPitch;
+ sal_Int32 *pNumSpans = mpTable;
+ mpSpanArray = reinterpret_cast<sal_Int32 *>(pNumSpans+2);
+ maNumSpans = *pNumSpans;
+ return (*this);
+ }
+
+ inline SpanIterator &SpanIterator::Skip( sal_Int32 dwNumScanlines )
+ {
+ // don't skip more scanlines than there are...
+ if(dwNumScanlines > maRemainingScanlines)
+ dwNumScanlines = maRemainingScanlines;
+
+ // skip in one fellow swoop...
+ maRemainingScanlines -= dwNumScanlines;
+ mpTable += maPitch * dwNumScanlines;
+
+ // initialize necessary query fields...
+ sal_Int32 *pNumSpans = mpTable;
+ mpSpanArray = reinterpret_cast<sal_Int32 *>(pNumSpans+2);
+ maNumSpans = *pNumSpans;
+ return (*this);
+ }
+
+ inline std::pair<sal_Int32,sal_Int32> SpanIterator::GetNextSpan( void )
+ {
+ sal_Int32 x(0);
+ sal_Int32 w(0);
+ if(maNumSpans)
+ {
+ x = *mpSpanArray++;
+ w = *mpSpanArray++;
+ --maNumSpans;
+ }
+ return std::pair<sal_Int32,sal_Int32>(x,w);
+ }
+
+ inline sal_Int32 SpanIterator::GetNumEqualScanlines( void )
+ {
+ return mpTable[1];
+ }
+
+ inline sal_Int32 SpanIterator::GetNumRemainingScanlines( void )
+ {
+ return maRemainingScanlines;
+ }
+
+ class ScanlineContainer
+ {
+
+ public:
+
+ ScanlineContainer( sal_uInt32 dwNumScanlines,
+ sal_uInt32 dwNumSpansPerScanline );
+
+ ~ScanlineContainer( void );
+
+ void InsertSpan( sal_Int32 y, sal_Int32 lx, sal_Int32 rx );
+
+ SpanIterator Iterate( void ) const { return SpanIterator(mpTable,maPitch,maNumScanlines); }
+
+ inline sal_uInt32 GetNumSpans( void ) const { return maNumberOfSpans; }
+
+ void Consolidate( void );
+
+ private:
+
+ // the span table will assist in determinate exactly how many clipping
+ // regions [that is *spans*] we will end up with.
+ // the counter for this purpose is right ahead.
+ sal_uInt32 maNumberOfSpans;
+
+ struct span
+ {
+ sal_Int32 x;
+ sal_Int32 w;
+ };
+
+ sal_uInt32 maNumScanlines;
+ sal_uInt32 maNumSpansPerScanline;
+ sal_Int32 *mpTable;
+ size_t maPitch;
+ };
+
+ ScanlineContainer::ScanlineContainer( sal_uInt32 dwNumScanlines,
+ sal_uInt32 dwNumSpansPerScanline ) : maNumScanlines(dwNumScanlines),
+ maNumSpansPerScanline(dwNumSpansPerScanline)
+ {
+ // since each triangle could possibly add another span
+ // we can calculate the upper limit by [num scanlines * num triangles].
+ const sal_uInt32 dwNumPossibleRegions = dwNumScanlines*dwNumSpansPerScanline;
+
+ // calculate the number of bytes the span table will consume
+ const size_t dwTableSize = dwNumPossibleRegions*sizeof(span)+dwNumScanlines*(sizeof(sal_Int32)<<1);
+
+ // allocate the span table [on the stack]
+ mpTable = static_cast<sal_Int32 *>(rtl_allocateMemory(dwTableSize));
+
+ // calculate the table pitch, that is how many int's do i need to get from a scanline to the next.
+ maPitch = (dwNumSpansPerScanline*sizeof(span)/sizeof(sal_Int32))+2;
+
+ // we need to initialize the table here.
+ // the first *int* on each scanline tells us how many spans are on it.
+ sal_Int32 *pNumSpans = mpTable;
+ for(unsigned int i=0; i<dwNumScanlines; ++i)
+ {
+ pNumSpans[0] = 0;
+ pNumSpans[1] = 0;
+ pNumSpans += maPitch;
+ }
+
+ maNumberOfSpans = 0;
+ }
+
+ ScanlineContainer::~ScanlineContainer( void )
+ {
+ rtl_freeMemory(mpTable);
+ }
+
+ void ScanlineContainer::InsertSpan( sal_Int32 y, sal_Int32 lx, sal_Int32 rx )
+ {
+ // there's new incoming span which we need to store in the table.
+ // first see if its width contributes a valid span.
+ if(sal_Int32 dwSpanWidth = rx-lx)
+ {
+ // first select the appropriate scanline the new span.
+ sal_Int32 *pNumSpans = mpTable+(y*maPitch);
+ span *pSpanArray = reinterpret_cast<span *>(pNumSpans+2);
+
+ // retrieve the number of already contained spans.
+ sal_Int32 dwNumSpan = *pNumSpans;
+
+ // since we need to sort the spans from top to bottom
+ // and left to right, we need to find the correct location
+ // in the table.
+ sal_Int32 dwIndex = 0;
+ while(dwIndex<dwNumSpan)
+ {
+ // since we would like to avoid unnecessary spans
+ // we try to consolidate them if possible.
+ // consolidate with right neighbour
+ if(pSpanArray[dwIndex].x == rx)
+ {
+ pSpanArray[dwIndex].x = lx;
+ pSpanArray[dwIndex].w += dwSpanWidth;
+ return;
+ }
+
+ // consolidate with left neighbour
+ if((pSpanArray[dwIndex].x+pSpanArray[dwIndex].w) == lx)
+ {
+ pSpanArray[dwIndex].w += rx-lx;
+ return;
+ }
+
+ // no consolidation possible, either this is a completely
+ // seperate span or it is the first in the list.
+ if(pSpanArray[dwIndex].x > lx)
+ break;
+
+ // forward to next element in the list.
+ ++dwIndex;
+ }
+
+ // if we reach here, the new span needs to be stored
+ // in the table, increase the number of spans in the
+ // current scanline.
+ *pNumSpans = dwNumSpan+1;
+
+ // keep the list of spans in sorted order. 'dwIndex'
+ // is where we want to store the new span. 'dwNumSpan'
+ // is the number of spans already there. now we need
+ // to move the offending spans out of the way.
+ while(dwIndex != dwNumSpan)
+ {
+ pSpanArray[dwNumSpan].x = pSpanArray[dwNumSpan-1].x;
+ pSpanArray[dwNumSpan].w = pSpanArray[dwNumSpan-1].w;
+ --dwNumSpan;
+ }
+
+ // insert the new span
+ pSpanArray[dwIndex].x = lx;
+ pSpanArray[dwIndex].w = rx-lx;
+
+ // remember the total number of spans in the table.
+ ++maNumberOfSpans;
+ }
+ }
+
+ void ScanlineContainer::Consolidate( void )
+ {
+ sal_Int32 *pScanline = mpTable;
+
+ sal_Int32 dwRemaining = maNumScanlines;
+ while(dwRemaining)
+ {
+ sal_Int32 dwNumSpans = pScanline[0];
+ sal_Int32 *pSpanArray = pScanline+2;
+
+ sal_Int32 dwRest = dwRemaining-1;
+ sal_Int32 *pNext = pScanline;
+ while(dwRest)
+ {
+ pNext += maPitch;
+ sal_Int32 dwNumNextSpans = pNext[0];
+ sal_Int32 *pSpanArrayNext = pNext+2;
+ if(dwNumSpans != dwNumNextSpans)
+ break;
+
+ sal_Int32 dwCompare = dwNumSpans<<1;
+ while(dwCompare)
+ {
+ if(pSpanArray[dwCompare-1] != pSpanArrayNext[dwCompare-1])
+ break;
+ --dwCompare;
+ }
+ if(dwCompare)
+ break;
+
+ --dwRest;
+ }
+
+ const sal_Int32 dwNumEqualScanlines(dwRemaining-dwRest);
+ pScanline[1] = dwNumEqualScanlines;
+ pScanline += maPitch*dwNumEqualScanlines;
+ dwRemaining -= dwNumEqualScanlines;
+
+ // since we track the total number of spans to generate,
+ // we need to account for consolidated scanlines here.
+ if(dwNumEqualScanlines > 1)
+ maNumberOfSpans -= dwNumSpans * (dwNumEqualScanlines-1);
+ }
+ }
+}
+
+// TODO: we should consider passing a basegfx b2dpolypolygon here to
+// ensure that the signature isn't misleading.
+// if we could pass a b2dpolypolygon here, we could easily triangulate it.
+void OutputDevice::ImplSetTriangleClipRegion( const PolyPolygon &rPolyPolygon )
+{
+ DBG_TESTSOLARMUTEX();
+
+ if(!(IsDeviceOutputNecessary()))
+ return;
+ if(!(mpGraphics))
+ if(!(ImplGetGraphics()))
+ return;
+
+ // first of all we need to know the upper limit
+ // of the amount of possible clipping regions.
+ sal_Int32 maxy = SAL_MIN_INT32;
+ sal_Int32 miny = SAL_MAX_INT32;
+ sal_uInt32 dwNumTriangles = 0;
+ for(unsigned int i=0; i<rPolyPolygon.Count(); ++i)
+ {
+ const Polygon &rPoly = rPolyPolygon.GetObject(i);
+ const sal_Int32 dwNumVertices = rPoly.GetSize();
+ if(!(dwNumVertices % 3))
+ {
+ for(unsigned int j=0; j<rPoly.GetSize(); ++j)
+ {
+ const Point &p = rPoly.GetPoint(j);
+ if(p.Y() < miny)
+ miny = p.Y();
+ if(p.Y() > maxy)
+ maxy = p.Y();
+ }
+ dwNumTriangles += dwNumVertices / 3;
+ }
+ }
+
+ const sal_uInt32 dwNumScanlines = (maxy-miny);
+ if(!(dwNumScanlines))
+ {
+ // indicates that no output needs to be produced
+ // since the clipping region did not provide any
+ // visible areas.
+ mbOutputClipped = TRUE;
+
+ // indicates that a clip region has been
+ // presented to the output device.
+ mbClipRegion = TRUE;
+
+ // indicates that the set clipping region
+ // has been processed.
+ mbClipRegionSet = TRUE;
+
+ // under 'normal' circumstances a new clipping region
+ // needs to be processed by ImplInitClipRegion(),
+ // which we need to circumvent.
+ mbInitClipRegion = FALSE;
+ return;
+ }
+
+ // this container provides all services we need to
+ // efficiently store/retrieve spans from the table.
+ const sal_uInt32 dwNumSpansPerScanline = dwNumTriangles;
+ ScanlineContainer container(dwNumScanlines,dwNumSpansPerScanline);
+
+ // convert the incoming polypolygon to spans, we assume that
+ // the polypolygon has already been triangulated since we don't
+ // want to use the basegfx-types here. this could be leveraged
+ // after the tools-types had been removed.
+ for(unsigned int i=0; i<rPolyPolygon.Count(); ++i)
+ {
+ const Polygon &rPoly = rPolyPolygon.GetObject(i);
+ const sal_uInt32 dwNumVertices = rPoly.GetSize();
+ if(!(dwNumVertices % 3))
+ {
+ for(unsigned int j=0; j<dwNumVertices; j+=3)
+ {
+ const Point &p0 = rPoly.GetPoint(j+0);
+ const Point &p1 = rPoly.GetPoint(j+1);
+ const Point &p2 = rPoly.GetPoint(j+2);
+
+ // what now follows is an extremely fast triangle
+ // rasterizer from which all tricky and interesting
+ // parts were forcibly amputated.
+ // note: top.left fill-convention
+ vertex v0(p0);
+ vertex v1(p1);
+ vertex v2(p2);
+
+ //sprintf(string,"[%f,%f] [%f,%f] [%f,%f]\n",v0.x,v0.y,v1.x,v1.y,v2.x,v2.y);
+ //OSL_TRACE(string);
+
+ if(v0.y > v2.y) swap(v0, v2);
+ if(v1.y > v2.y) swap(v1, v2);
+ if(v0.y > v1.y) swap(v0, v1);
+
+ const float float2fixed(16.0f);
+ const float fixed2float(1.0f/float2fixed);
+
+ // vertex coordinates of the triangle [28.4 fixed-point]
+ const int i4x0 = iround(float2fixed * (v0.x - 0.5f));
+ const int i4y0 = iround(float2fixed * (v0.y - 0.5f));
+ const int i4x1 = iround(float2fixed * (v1.x - 0.5f));
+ const int i4y1 = iround(float2fixed * (v1.y - 0.5f));
+ const int i4x2 = iround(float2fixed * (v2.x - 0.5f));
+ const int i4y2 = iround(float2fixed * (v2.y - 0.5f));
+
+ // vertex coordinate deltas [28.4 fixed-point]
+ const int i4dx12 = i4x1-i4x0;
+ const int i4dy12 = i4y1-i4y0;
+ const int i4dx13 = i4x2-i4x0;
+ const int i4dy13 = i4y2-i4y0;
+ const int i4dx23 = i4x2-i4x1;
+ const int i4dy23 = i4y2-i4y1;
+
+ // vertex coordinate deltas [32-bit floating-point]
+ const float fdx12 = i4dx12 * fixed2float;
+ const float fdy12 = i4dy12 * fixed2float;
+ const float fdx13 = i4dx13 * fixed2float;
+ const float fdy13 = i4dy13 * fixed2float;
+
+ // slope of edges [quotient,remainder]
+ const int mq12 = floorDiv(i4dx12 << 4, i4dy12 << 4);
+ const int mq13 = floorDiv(i4dx13 << 4, i4dy13 << 4);
+ const int mq23 = floorDiv(i4dx23 << 4, i4dy23 << 4);
+ const int mr12 = floorMod(i4dx12 << 4, i4dy12 << 4);
+ const int mr13 = floorMod(i4dx13 << 4, i4dy13 << 4);
+ const int mr23 = floorMod(i4dx23 << 4, i4dy23 << 4);
+
+ // convert the vertical coordinates back to integers.
+ // according to the top-left fillrule we need to step
+ // the coordinates to the ceiling.
+ const int y0 = (i4y0+15)>>4;
+ const int y1 = (i4y1+15)>>4;
+ const int y2 = (i4y2+15)>>4;
+
+ // calculate the value of the horizontal coordinate
+ // from the edge that 'spans' the triangle.
+ const int x = ceilDiv(i4dx13*i4dy12 + i4x0*i4dy13, i4dy13);
+
+ // this will hold the horizontal coordinates
+ // of the seperate spans during the rasterization process.
+ int lx,rx;
+
+ // this pair will serve as the error accumulator while
+ // we step along the edges.
+ int ld,rd,lD,rD;
+
+ // these are the edge and error stepping values that
+ // will be used while stepping.
+ int lQ,rQ,lR,rR;
+
+ if(i4x1 < x)
+ {
+ lx = ceilDiv(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ ld = ceilMod(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ rx = ceilDiv(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ rd = ceilMod(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ lQ = mq12;
+ rQ = mq13;
+ lR = mr12;
+ rR = mr13;
+ lD = i4dy12 << 4;
+ rD = i4dy13 << 4;
+ }
+ else
+ {
+ lx = ceilDiv(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ ld = ceilMod(i4dx13 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ rx = ceilDiv(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ rd = ceilMod(i4dx12 * (ceilFix4(i4y0) - i4y0) + i4x0 * i4dy12, i4dy12 << 4);
+ lQ = mq13;
+ rQ = mq12;
+ lR = mr13;
+ rR = mr12;
+ lD = i4dy13 << 4;
+ rD = i4dy12 << 4;
+ }
+
+ for(signed int y=y0; y<y1; y++)
+ {
+ container.InsertSpan(y-miny,lx,rx);
+
+ lx += lQ; ld += lR;
+ if(ld > 0) { ld -= lD; lx += 1; }
+ rx += rQ; rd += rR;
+ if(rd > 0) { rd -= rD; rx += 1; }
+ }
+
+ if(i4x1 < x)
+ {
+ lx = ceilDiv(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ ld = ceilMod(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ rx = ceilDiv(i4dx13 * (ceilFix4(i4y1) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ rd = ceilMod(i4dx13 * (ceilFix4(i4y1) - i4y0) + i4x0 * i4dy13, i4dy13 << 4);
+ lQ = mq23;
+ lR = mr23;
+ lD = i4dy23 << 4;
+ }
+ else
+ {
+ rx = ceilDiv(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ rd = ceilMod(i4dx23 * (ceilFix4(i4y1) - i4y1) + i4x1 * i4dy23, i4dy23 << 4);
+ rQ = mq23;
+ rR = mr23;
+ rD = i4dy23 << 4;
+ }
+
+ for(signed int y=y1; y<y2; y++)
+ {
+ container.InsertSpan(y-miny,lx,rx);
+
+ lx += lQ; ld += lR;
+ if(ld > 0) { ld -= lD; lx += 1; }
+ rx += rQ; rd += rR;
+ if(rd > 0) { rd -= rD; rx += 1; }
+ }
+ }
+ }
+ }
+
+ // now try to consolidate as many scanlines as possible.
+ // please note that this will probably change the number
+ // of spans [at least this is why we do all this hassle].
+ // so, if you use 'consolidate' you should *use* this
+ // information during iteration, because the 'graphics'
+ // object we tell all those regions about is a bit,
+ // hm, how to say, *picky* if you supply not correctly
+ // the amount of regions.
+ container.Consolidate();
+
+ sal_Int32 offset_x = 0;
+ sal_Int32 offset_y = 0;
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ offset_x = mnOutOffX+mnOutOffOrigX;
+ offset_y = mnOutOffY+mnOutOffOrigY;
+ }
+
+ // now forward the spantable to the graphics handler.
+ SpanIterator it(container.Iterate());
+ mpGraphics->BeginSetClipRegion( container.GetNumSpans() );
+ while(miny < maxy)
+ {
+ const sal_Int32 dwNumEqual(it.GetNumEqualScanlines());
+ while(it.GetRemainingSpans())
+ {
+ // retrieve the next span [x-coordinate, width] from the current scanline.
+ std::pair<sal_Int32,sal_Int32> span(it.GetNextSpan());
+
+ // now forward this to the graphics object.
+ // the only part that is worth noting is that we use
+ // the number of equal spanlines [the current is always the
+ // first one of the equal bunch] as the height of the region.
+ mpGraphics->UnionClipRegion( offset_x+span.first,
+ offset_y+miny,
+ span.second,
+ dwNumEqual,
+ this );
+ }
+ it.Skip(dwNumEqual);
+ miny += dwNumEqual;
+ }
+ mpGraphics->EndSetClipRegion();
+
+ // indicates that no output needs to be produced
+ // since the clipping region did not provide any
+ // visible areas. the clip covers the whole area
+ // if there's not a single region.
+ mbOutputClipped = (container.GetNumSpans() == 0);
+
+ // indicates that a clip region has been
+ // presented to the output device.
+ mbClipRegion = TRUE;
+
+ // indicates that the set clipping region
+ // has been processed.
+ mbClipRegionSet = TRUE;
+
+ // under 'normal' circumstances a new clipping region
+ // needs to be processed by ImplInitClipRegion(),
+ // which we need to circumvent.
+ mbInitClipRegion = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
void OutputDevice::SetClipRegion()
{
DBG_TRACE( "OutputDevice::SetClipRegion()" );
@@ -1022,6 +1650,42 @@ void OutputDevice::SetClipRegion( const Region& rRegion )
// -----------------------------------------------------------------------
+void OutputDevice::SetTriangleClipRegion( const PolyPolygon &rPolyPolygon )
+{
+ DBG_TRACE( "OutputDevice::SetTriangleClipRegion( rPolyPolygon )" );
+ DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
+
+ // in case the passed polypolygon is empty, use the
+ // existing SetClipRegion() method which gracefully
+ // unsets any previously set clipping region.
+ if(!(rPolyPolygon.Count()))
+ SetClipRegion();
+
+ sal_Int32 offset_x = 0;
+ sal_Int32 offset_y = 0;
+ if ( GetOutDevType() == OUTDEV_WINDOW )
+ {
+ offset_x = mnOutOffX+mnOutOffOrigX;
+ offset_y = mnOutOffY+mnOutOffOrigY;
+ }
+
+ // play nice with the rest of the system and provide an old-style region.
+ // the rest of this method does not rely on this.
+ maRegion = Region::GetRegionFromPolyPolygon( LogicToPixel(rPolyPolygon) );
+ maRegion.Move(offset_x,offset_x);
+
+ // feed region to metafile
+ if ( mpMetaFile )
+ mpMetaFile->AddAction( new MetaClipRegionAction( maRegion, TRUE ) );
+
+ ImplSetTriangleClipRegion( rPolyPolygon );
+
+ if( mpAlphaVDev )
+ mpAlphaVDev->SetTriangleClipRegion( rPolyPolygon );
+}
+
+// -----------------------------------------------------------------------
+
Region OutputDevice::GetClipRegion() const
{
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );