diff options
Diffstat (limited to 'vcl/source/gdi/outdev.cxx')
-rwxr-xr-x[-rw-r--r--] | vcl/source/gdi/outdev.cxx | 847 |
1 files changed, 32 insertions, 815 deletions
diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx index ad89fda760b9..b5ecb0761949 100644..100755 --- a/vcl/source/gdi/outdev.cxx +++ b/vcl/source/gdi/outdev.cxx @@ -202,10 +202,6 @@ bool OutputDevice::ImplSelectClipRegion( const Region& rRegion, SalGraphics* pGr { DBG_TESTSOLARMUTEX(); - // TODO(Q3): Change from static to plain method - everybody's - // calling it with pOutDev=this! - // => done, but only with minimal changes for now => TODO - OutputDevice* const pOutDev = this; if( !pGraphics ) { if( !mpGraphics ) @@ -214,91 +210,8 @@ bool OutputDevice::ImplSelectClipRegion( const Region& rRegion, SalGraphics* pGr pGraphics = mpGraphics; } - if( rRegion.HasPolyPolygon() - && pGraphics->supportsOperation( OutDevSupport_B2DClip ) ) - { - const ::basegfx::B2DPolyPolygon& rB2DPolyPolygon = rRegion.GetB2DPolyPolygon(); - pGraphics->BeginSetClipRegion( 0 ); - pGraphics->UnionClipRegion( rB2DPolyPolygon, pOutDev ); - pGraphics->EndSetClipRegion(); - return true; - } - - long nX; - long nY; - long nWidth; - long nHeight; - sal_uLong nRectCount; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; - sal_Bool bClipRegion = sal_True; - const sal_Bool bClipDeviceBounds( !pOutDev->GetPDFWriter() - && pOutDev->GetOutDevType() != OUTDEV_PRINTER ); - - nRectCount = rRegion.GetRectCount(); - pGraphics->BeginSetClipRegion( nRectCount ); - bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - if( bClipDeviceBounds ) - { - // #b6520266# Perform actual rect clip against outdev - // dimensions, to generate empty clips whenever one of the - // values is completely off the device. - const long nOffX( pOutDev->mnOutOffX ); - const long nOffY( pOutDev->mnOutOffY ); - const long nDeviceWidth( pOutDev->GetOutputWidthPixel() ); - const long nDeviceHeight( pOutDev->GetOutputHeightPixel() ); - Rectangle aDeviceBounds( nOffX, nOffY, - nOffX+nDeviceWidth-1, - nOffY+nDeviceHeight-1 ); - while ( bRegionRect ) - { - // #i59315# Limit coordinates passed to sal layer to actual - // outdev dimensions - everything else bears the risk of - // overflowing internal coordinates (e.g. the 16 bit wire - // format of X11). - Rectangle aTmpRect(nX,nY,nX+nWidth-1,nY+nHeight-1); - aTmpRect.Intersection(aDeviceBounds); - - if( !aTmpRect.IsEmpty() ) - { - if ( !pGraphics->UnionClipRegion( aTmpRect.Left(), - aTmpRect.Top(), - aTmpRect.GetWidth(), - aTmpRect.GetHeight(), - pOutDev ) ) - { - bClipRegion = sal_False; - } - } - else - { - // #i79850# Fake off-screen clip - if ( !pGraphics->UnionClipRegion( nDeviceWidth+1, - nDeviceHeight+1, - 1, 1, - pOutDev ) ) - { - bClipRegion = sal_False; - } - } - DBG_ASSERT( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't create region" ); - bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); - } - } - else - { - // #i65720# Actually, _don't_ clip anything on printer or PDF - // export, since output might be visible outside the specified - // device boundaries. - while ( bRegionRect ) - { - if ( !pGraphics->UnionClipRegion( nX, nY, nWidth, nHeight, pOutDev ) ) - bClipRegion = sal_False; - DBG_ASSERT( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't cerate region" ); - bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); - } - } - pGraphics->EndSetClipRegion(); + bool bClipRegion = pGraphics->SetClipRegion( rRegion, this ); + OSL_ENSURE( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't cerate region" ); return bClipRegion; } @@ -1075,9 +988,22 @@ void OutputDevice::ImplInitClipRegion() else { mbOutputClipped = sal_False; - ImplSelectClipRegion( - // #102532# Respect output offset also for clip region - ImplPixelToDevicePixel( maRegion ) ); + + // #102532# Respect output offset also for clip region + Region aRegion( ImplPixelToDevicePixel( maRegion ) ); + const bool bClipDeviceBounds( ! GetPDFWriter() + && GetOutDevType() != OUTDEV_PRINTER ); + if( bClipDeviceBounds ) + { + // #b6520266# Perform actual rect clip against outdev + // dimensions, to generate empty clips whenever one of the + // values is completely off the device. + Rectangle aDeviceBounds( mnOutOffX, mnOutOffY, + mnOutOffX+GetOutputWidthPixel()-1, + mnOutOffY+GetOutputHeightPixel()-1 ); + aRegion.Intersect( aDeviceBounds ); + } + ImplSelectClipRegion( aRegion ); } mbClipRegionSet = sal_True; @@ -1122,693 +1048,6 @@ void OutputDevice::ImplSetClipRegion( const Region* pRegion ) // ----------------------------------------------------------------------- -namespace -{ - inline int iround( float x ) - { - union - { - float f; - sal_Int32 i; - }; - f = x; - sal_Int32 exponent = (127 + 31) - ((i >> 23) & 0xFF); - sal_Int32 r = ((sal_Int32(i) << 8) | (1U << 31)) >> exponent; - r &= ((exponent - 32) >> 31); - sal_Int32 sign = i >> 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),maRemainingScanlines(dwNumScanlines),maPitch(dwPitch) - { - 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) - { - // #128002# add one scanline buffer at the end, as - // SpanIterator::Skip reads two bytes past the end. - ++dwNumScanlines; - - // 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; - - if( mpGraphics->supportsOperation( OutDevSupport_B2DClip ) ) - { -#if 0 - ::basegfx::B2DPolyPolygon aB2DPolyPolygon = rPolyPolygon.getB2DPolyPolygon(); -#else - // getB2DPolyPolygon() "optimizes away" some points - // which prevents reliable undoing of the "triangle thingy" parameter - // so the toolspoly -> b2dpoly conversion has to be done manually - ::basegfx::B2DPolyPolygon aB2DPolyPolygon; - for( sal_uInt16 nPolyIdx = 0; nPolyIdx < rPolyPolygon.Count(); ++nPolyIdx ) - { - const Polygon& rPolygon = rPolyPolygon[ nPolyIdx ]; - ::basegfx::B2DPolygon aB2DPoly; - for( sal_uInt16 nPointIdx = 0; nPointIdx < rPolygon.GetSize(); ++nPointIdx ) - { - const Point& rPoint = rPolygon[ nPointIdx ]; - const ::basegfx::B2DPoint aB2DPoint( rPoint.X(), rPoint.Y() ); - aB2DPoly.append( aB2DPoint ); - } - aB2DPolyPolygon.append( aB2DPoly ); - } -#endif - - const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation(); - aB2DPolyPolygon.transform( aTransform ); - - // the rPolyPolygon argument is a "triangle thingy" - // so convert it to a normal polypolyon first - ::basegfx::B2DPolyPolygon aPolyTriangle; - const int nPolyCount = aB2DPolyPolygon.count(); - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolygon rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx ); - const int nPointCount = rPolygon.count(); - for( int nPointIdx = 0; nPointIdx+2 < nPointCount; nPointIdx +=3 ) - { - ::basegfx::B2DPolygon aTriangle; - aTriangle.append( rPolygon.getB2DPoint( nPointIdx+0 ) ); - aTriangle.append( rPolygon.getB2DPoint( nPointIdx+1 ) ); - aTriangle.append( rPolygon.getB2DPoint( nPointIdx+2 ) ); - aPolyTriangle.append( aTriangle ); - } - } - - // now set the clip region with the real polypolygon - mpGraphics->BeginSetClipRegion( 0 ); - mpGraphics->UnionClipRegion( aPolyTriangle, this ); - mpGraphics->EndSetClipRegion(); - - // and mark the clip status as ready - mbOutputClipped = sal_False; - mbClipRegion = sal_True; - mbClipRegionSet = sal_True; - mbInitClipRegion = sal_False; - return; - } - - sal_Int32 offset_x = 0; - sal_Int32 offset_y = 0; - if ( GetOutDevType() == OUTDEV_WINDOW ) - { - offset_x = mnOutOffX+mnOutOffOrigX; - offset_y = mnOutOffY+mnOutOffOrigY; - } - - // 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(sal_uInt16 i=0; i<rPolyPolygon.Count(); ++i) - { - const Polygon &rPoly = rPolyPolygon.GetObject(i); - const sal_Int32 dwNumVertices = rPoly.GetSize(); - if(!(dwNumVertices % 3)) - { - for(sal_uInt16 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 = sal_True; - - // indicates that a clip region has been - // presented to the output device. - mbClipRegion = sal_True; - - // indicates that the set clipping region - // has been processed. - mbClipRegionSet = sal_True; - - // under 'normal' circumstances a new clipping region - // needs to be processed by ImplInitClipRegion(), - // which we need to circumvent. - mbInitClipRegion = sal_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(sal_uInt16 i=0; i<rPolyPolygon.Count(); ++i) - { - const Polygon &rPoly = rPolyPolygon.GetObject(i); - const sal_uInt16 dwNumVertices = rPoly.GetSize(); - if(!(dwNumVertices % 3)) - { - for(sal_uInt16 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); - - // 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; - - // 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(); - - // 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 = sal_True; - - // indicates that the set clipping region - // has been processed. - mbClipRegionSet = sal_True; - - // under 'normal' circumstances a new clipping region - // needs to be processed by ImplInitClipRegion(), - // which we need to circumvent. - mbInitClipRegion = sal_False; -} - -// ----------------------------------------------------------------------- - void OutputDevice::SetClipRegion() { DBG_TRACE( "OutputDevice::SetClipRegion()" ); @@ -1848,42 +1087,6 @@ 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, sal_True ) ); - - ImplSetTriangleClipRegion( rPolyPolygon ); - - if( mpAlphaVDev ) - mpAlphaVDev->SetTriangleClipRegion( rPolyPolygon ); -} - -// ----------------------------------------------------------------------- - Region OutputDevice::GetClipRegion() const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); @@ -3159,6 +2362,20 @@ void OutputDevice::DrawPolyLine( // ----------------------------------------------------------------------- +sal_uInt32 OutputDevice::GetGCStackDepth() const +{ + const ImplObjStack* pData = mpObjStack; + sal_uInt32 nDepth = 0; + while( pData ) + { + nDepth++; + pData = pData->mpPrev; + } + return nDepth; +} + +// ----------------------------------------------------------------------- + void OutputDevice::Push( sal_uInt16 nFlags ) { DBG_TRACE( "OutputDevice::Push()" ); |