diff options
Diffstat (limited to 'vcl/source/gdi')
-rw-r--r-- | vcl/source/gdi/bitmap.cxx | 10 | ||||
-rw-r--r-- | vcl/source/gdi/lineinfo.cxx | 22 | ||||
-rwxr-xr-x[-rw-r--r--] | vcl/source/gdi/outdev.cxx | 847 | ||||
-rw-r--r-- | vcl/source/gdi/outdev3.cxx | 8 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 307 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.hxx | 11 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl2.cxx | 511 | ||||
-rw-r--r-- | vcl/source/gdi/print.cxx | 44 | ||||
-rw-r--r-- | vcl/source/gdi/print2.cxx | 35 | ||||
-rwxr-xr-x[-rw-r--r--] | vcl/source/gdi/region.cxx | 193 | ||||
-rwxr-xr-x | vcl/source/gdi/salgdilayout.cxx | 60 |
11 files changed, 1029 insertions, 1019 deletions
diff --git a/vcl/source/gdi/bitmap.cxx b/vcl/source/gdi/bitmap.cxx index 5f434f9ba48a..8d831961f8af 100644 --- a/vcl/source/gdi/bitmap.cxx +++ b/vcl/source/gdi/bitmap.cxx @@ -236,9 +236,13 @@ bool BitmapPalette::IsGreyPalette() const const int nEntryCount = GetEntryCount(); if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping return true; - const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount ); - if( rGreyPalette == *this ) - return true; + // see above: only certain entry values will result in a valid call to GetGreyPalette + if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 ) + { + const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount ); + if( rGreyPalette == *this ) + return true; + } // TODO: is it worth to compare the entries? return false; } diff --git a/vcl/source/gdi/lineinfo.cxx b/vcl/source/gdi/lineinfo.cxx index b7020874ca9c..ebd55a48f593 100644 --- a/vcl/source/gdi/lineinfo.cxx +++ b/vcl/source/gdi/lineinfo.cxx @@ -70,6 +70,20 @@ ImplLineInfo::ImplLineInfo( const ImplLineInfo& rImplLineInfo ) : { } +// ----------------------------------------------------------------------- + +inline bool ImplLineInfo::operator==( const ImplLineInfo& rB ) const +{ + return(meStyle == rB.meStyle + && mnWidth == rB.mnWidth + && mnDashCount == rB.mnDashCount + && mnDashLen == rB.mnDashLen + && mnDotCount == rB.mnDotCount + && mnDotLen == rB.mnDotLen + && mnDistance == rB.mnDistance + && meLineJoin == rB.meLineJoin); +} + // ------------ // - LineInfo - // ------------ @@ -125,13 +139,7 @@ sal_Bool LineInfo::operator==( const LineInfo& rLineInfo ) const DBG_CHKOBJ( &rLineInfo, LineInfo, NULL ); return( mpImplLineInfo == rLineInfo.mpImplLineInfo || - ( mpImplLineInfo->meStyle == rLineInfo.mpImplLineInfo->meStyle && - mpImplLineInfo->mnWidth == rLineInfo.mpImplLineInfo->mnWidth && - mpImplLineInfo->mnDashCount == rLineInfo.mpImplLineInfo->mnDashCount && - mpImplLineInfo->mnDashLen == rLineInfo.mpImplLineInfo->mnDashLen && - mpImplLineInfo->mnDotCount == rLineInfo.mpImplLineInfo->mnDotCount && - mpImplLineInfo->mnDotLen == rLineInfo.mpImplLineInfo->mnDotLen && - mpImplLineInfo->mnDistance == rLineInfo.mpImplLineInfo->mnDistance ) ); + *mpImplLineInfo == *rLineInfo.mpImplLineInfo ); } // ----------------------------------------------------------------------- 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()" ); diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx index 25e589e70c95..10f618d6e7c1 100644 --- a/vcl/source/gdi/outdev3.cxx +++ b/vcl/source/gdi/outdev3.cxx @@ -7414,7 +7414,6 @@ SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, c // setup glyphs Point aPos; sal_GlyphId aGlyphId; - int nFallbacklevel = 0; for( int nStart = 0; rLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); ) { // NOTE: Windows backend is producing unicode chars (ucs4), so on windows, @@ -7424,15 +7423,12 @@ SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, c aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK); aGlyph.x = aPos.X(); aGlyph.y = aPos.Y(); - aSysLayoutData.rGlyphData.push_back(aGlyph); - int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT; - if (nLevel > nFallbacklevel && nLevel < MAX_FALLBACK) - nFallbacklevel = nLevel; + aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0; + aSysLayoutData.rGlyphData.push_back(aGlyph); } // Get font data - aSysLayoutData.aSysFontData = GetSysFontData(nFallbacklevel); aSysLayoutData.orientation = rLayout->GetOrientation(); rLayout->Release(); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 32f534129e07..4a37d3a5d601 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -54,6 +54,7 @@ #include <vcl/metric.hxx> #include <vcl/fontsubset.hxx> #include <vcl/textlayout.hxx> +#include <vcl/cvtgrf.hxx> #include <svsys.h> #include <vcl/salgdi.hxx> #include <vcl/svapp.hxx> @@ -887,34 +888,44 @@ static void appendDouble( double fValue, OStringBuffer& rBuffer, sal_Int32 nPrec } -static void appendColor( const Color& rColor, OStringBuffer& rBuffer ) +static void appendColor( const Color& rColor, OStringBuffer& rBuffer, bool bConvertToGrey = false ) { if( rColor != Color( COL_TRANSPARENT ) ) { - appendDouble( (double)rColor.GetRed() / 255.0, rBuffer ); - rBuffer.append( ' ' ); - appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer ); - rBuffer.append( ' ' ); - appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer ); + if( bConvertToGrey ) + { + sal_uInt8 cByte = rColor.GetLuminance(); + appendDouble( (double)cByte / 255.0, rBuffer ); + } + else + { + appendDouble( (double)rColor.GetRed() / 255.0, rBuffer ); + rBuffer.append( ' ' ); + appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer ); + rBuffer.append( ' ' ); + appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer ); + } } } -static void appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer ) +void PDFWriterImpl::appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer ) { if( rColor != Color( COL_TRANSPARENT ) ) { - appendColor( rColor, rBuffer ); - rBuffer.append( " RG" ); + bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale; + appendColor( rColor, rBuffer, bGrey ); + rBuffer.append( bGrey ? " G" : " RG" ); } } -static void appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer ) +void PDFWriterImpl::appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer ) { if( rColor != Color( COL_TRANSPARENT ) ) { - appendColor( rColor, rBuffer ); - rBuffer.append( " rg" ); + bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale; + appendColor( rColor, rBuffer, bGrey ); + rBuffer.append( bGrey ? " g" : " rg" ); } } @@ -2037,9 +2048,25 @@ inline void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OString& rInSt appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer); } -inline void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ) +void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc ) { - rtl::OString aBufferString( rtl::OUStringToOString( rInString, RTL_TEXTENCODING_ASCII_US ) ); + rtl::OString aBufferString( rtl::OUStringToOString( rInString, nEnc ) ); + sal_Int32 nLen = aBufferString.getLength(); + rtl::OStringBuffer aBuf( nLen ); + const sal_Char* pT = aBufferString.getStr(); + + for( sal_Int32 i = 0; i < nLen; i++, pT++ ) + { + if( (*pT & 0x80) == 0 ) + aBuf.append( *pT ); + else + { + aBuf.append( '<' ); + appendHex( *pT, aBuf ); + aBuf.append( '>' ); + } + } + aBufferString = aBuf.makeStringAndClear(); appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer); } @@ -2946,12 +2973,9 @@ bool PDFWriterImpl::emitTilings() aTilingObj.setLength( 0 ); -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( "PDFWriterImpl::emitTilings" ); - emitComment( aLine.getStr() ); - } -#endif + #if OSL_DEBUG_LEVEL > 1 + emitComment( "PDFWriterImpl::emitTilings" ); + #endif sal_Int32 nX = (sal_Int32)it->m_aRectangle.Left(); sal_Int32 nY = (sal_Int32)it->m_aRectangle.Top(); @@ -3439,10 +3463,7 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFont // now we can actually write the font stream ! #if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::emitEmbeddedFont" ); - emitComment( aLine.getStr() ); - } + emitComment( " PDFWriterImpl::emitEmbeddedFont" ); #endif OStringBuffer aLine( 512 ); nStreamObject = createObject(); @@ -3868,12 +3889,9 @@ sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding, delete pCodec; #endif -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::createToUnicodeCMap" ); - emitComment( aLine.getStr() ); - } -#endif + #if OSL_DEBUG_LEVEL > 1 + emitComment( "PDFWriterImpl::createToUnicodeCMap" ); + #endif OStringBuffer aLine( 40 ); aLine.append( nStream ); @@ -4060,10 +4078,7 @@ bool PDFWriterImpl::emitFonts() CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) ); #if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine1( " PDFWriterImpl::emitFonts" ); - emitComment( aLine1.getStr() ); - } + emitComment( "PDFWriterImpl::emitFonts" ); #endif sal_Int32 nFontStream = createObject(); sal_Int32 nStreamLengthObject = createObject(); @@ -4634,18 +4649,20 @@ we check in the following sequence: { aLine.append( "/Launch/Win<</F" ); // INetURLObject is not good with UNC paths, use original path - appendLiteralStringEncrypt( rLink.m_aURL, rLink.m_nObject, aLine ); + appendLiteralStringEncrypt( rLink.m_aURL, rLink.m_nObject, aLine, osl_getThreadTextEncoding() ); aLine.append( ">>" ); } else { - sal_Int32 nSetRelative = 0; + bool bSetRelative = false; + bool bFileSpec = false; //check if relative file link is requested and if the protocol is 'file://' if( m_aContext.RelFsys && eBaseProtocol == eTargetProtocol && eTargetProtocol == INET_PROT_FILE ) - nSetRelative++; + bSetRelative = true; rtl::OUString aFragment = aTargetURL.GetMark( INetURLObject::NO_DECODE /*DECODE_WITH_CHARSET*/ ); //fragment as is, if( nSetGoToRMode == 0 ) + { switch( m_aContext.DefaultLinkAction ) { default: @@ -4665,19 +4682,24 @@ we check in the following sequence: eTargetProtocol != INET_PROT_FILE ) aLine.append( "/URI/URI" ); else + { aLine.append( "/Launch/F" ); + bFileSpec = true; + } break; } + } //fragment are encoded in the same way as in the named destination processing - rtl::OUString aURLNoMark = aTargetURL.GetURLNoMark( INetURLObject::DECODE_WITH_CHARSET ); if( nSetGoToRMode ) {//add the fragment + rtl::OUString aURLNoMark = aTargetURL.GetURLNoMark( INetURLObject::DECODE_WITH_CHARSET ); aLine.append("/GoToR"); aLine.append("/F"); - appendLiteralStringEncrypt( nSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURLNoMark, + bFileSpec = true; + appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURLNoMark, INetURLObject::WAS_ENCODED, INetURLObject::DECODE_WITH_CHARSET ) : - aURLNoMark, rLink.m_nObject, aLine ); + aURLNoMark, rLink.m_nObject, aLine, osl_getThreadTextEncoding() ); if( aFragment.getLength() > 0 ) { aLine.append("/D/"); @@ -4696,13 +4718,16 @@ we check in the following sequence: //substitute the fragment aTargetURL.SetMark( aLineLoc.getStr() ); } - rtl::OUString aURL = aTargetURL.GetMainURL( (nSetRelative || eTargetProtocol == INET_PROT_FILE) ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE ); + rtl::OUString aURL = aTargetURL.GetMainURL( bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE ); // check if we have a URL available, if the string is empty, set it as the original one // if( aURL.getLength() == 0 ) // appendLiteralStringEncrypt( rLink.m_aURL , rLink.m_nObject, aLine ); // else - appendLiteralStringEncrypt( nSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURL ) : - aURL , rLink.m_nObject, aLine ); + appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURL, + INetURLObject::WAS_ENCODED, + bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE + ) : + aURL , rLink.m_nObject, aLine, osl_getThreadTextEncoding() ); } //<--- i56629 } @@ -5358,12 +5383,9 @@ bool PDFWriterImpl::emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDi pApppearanceStream->Seek( STREAM_SEEK_TO_BEGIN ); sal_Int32 nObject = createObject(); CHECK_RETURN( updateObject( nObject ) ); -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::emitAppearances" ); - emitComment( aLine.getStr() ); - } -#endif + #if OSL_DEBUG_LEVEL > 1 + emitComment( "PDFWriterImpl::emitAppearances" ); + #endif OStringBuffer aLine; aLine.append( nObject ); @@ -5606,7 +5628,7 @@ bool PDFWriterImpl::emitWidgetAnnotations() { // create a submit form action aLine.append( "/AA<</D<</Type/Action/S/SubmitForm/F" ); - appendLiteralStringEncrypt( rWidget.m_aListEntries.front(), rWidget.m_nObject, aLine ); + appendLiteralStringEncrypt( rWidget.m_aListEntries.front(), rWidget.m_nObject, aLine, osl_getThreadTextEncoding() ); aLine.append( "/Flags " ); sal_Int32 nFlags = 0; @@ -9251,12 +9273,9 @@ bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject ) rObject.m_pContentStream->Seek( STREAM_SEEK_TO_END ); sal_uLong nSize = rObject.m_pContentStream->Tell(); rObject.m_pContentStream->Seek( STREAM_SEEK_TO_BEGIN ); -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::writeTransparentObject" ); - emitComment( aLine.getStr() ); - } -#endif + #if OSL_DEBUG_LEVEL > 1 + emitComment( "PDFWriterImpl::writeTransparentObject" ); + #endif OStringBuffer aLine( 512 ); CHECK_RETURN( updateObject( rObject.m_nObject ) ); aLine.append( rObject.m_nObject ); @@ -9400,28 +9419,25 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject ) sal_Int32 nFunctionObject = createObject(); CHECK_RETURN( updateObject( nFunctionObject ) ); - OutputDevice* pRefDevice = getReferenceDevice(); - pRefDevice->Push( PUSH_ALL ); - if( rObject.m_aSize.Width() > pRefDevice->GetOutputSizePixel().Width() ) - rObject.m_aSize.Width() = pRefDevice->GetOutputSizePixel().Width(); - if( rObject.m_aSize.Height() > pRefDevice->GetOutputSizePixel().Height() ) - rObject.m_aSize.Height() = pRefDevice->GetOutputSizePixel().Height(); - pRefDevice->SetMapMode( MapMode( MAP_PIXEL ) ); - pRefDevice->DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient ); + VirtualDevice aDev; + aDev.SetOutputSizePixel( rObject.m_aSize ); + aDev.SetMapMode( MapMode( MAP_PIXEL ) ); + if( m_aContext.ColorMode == PDFWriter::DrawGreyscale ) + aDev.SetDrawMode( aDev.GetDrawMode() | + ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | + DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); + aDev.DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient ); - Bitmap aSample = pRefDevice->GetBitmap( Point( 0, 0 ), rObject.m_aSize ); + Bitmap aSample = aDev.GetBitmap( Point( 0, 0 ), rObject.m_aSize ); BitmapReadAccess* pAccess = aSample.AcquireReadAccess(); AccessReleaser aReleaser( pAccess ); Size aSize = aSample.GetSizePixel(); sal_Int32 nStreamLengthObject = createObject(); -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::writeGradientFunction" ); - emitComment( aLine.getStr() ); - } -#endif + #if OSL_DEBUG_LEVEL > 1 + emitComment( "PDFWriterImpl::writeGradientFunction" ); + #endif OStringBuffer aLine( 120 ); aLine.append( nFunctionObject ); aLine.append( " 0 obj\n" @@ -9434,6 +9450,7 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject ) aLine.append( " ]\n" "/BitsPerSample 8\n" "/Range[ 0 1 0 1 0 1 ]\n" + "/Order 3\n" "/Length " ); aLine.append( nStreamLengthObject ); aLine.append( " 0 R\n" @@ -9449,7 +9466,7 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject ) checkAndEnableStreamEncryption( nFunctionObject ); beginCompression(); - for( int y = 0; y < aSize.Height(); y++ ) + for( int y = aSize.Height()-1; y >= 0; y-- ) { for( int x = 0; x < aSize.Width(); x++ ) { @@ -9500,8 +9517,6 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject ) "endobj\n\n" ); CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); - pRefDevice->Pop(); - return true; } @@ -9530,12 +9545,9 @@ bool PDFWriterImpl::writeJPG( JPGEmit& rObject ) m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDF13 ); } -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::writeJPG" ); - emitComment( aLine.getStr() ); - } -#endif + #if OSL_DEBUG_LEVEL > 1 + emitComment( "PDFWriterImpl::writeJPG" ); + #endif OStringBuffer aLine(200); aLine.append( rObject.m_nObject ); @@ -9655,26 +9667,32 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) sal_Int32 nStreamLengthObject = createObject(); sal_Int32 nMaskObject = 0; -#if OSL_DEBUG_LEVEL > 1 - { - OStringBuffer aLine( " PDFWriterImpl::writeBitmapObject" ); - emitComment( aLine.getStr() ); - } -#endif + #if OSL_DEBUG_LEVEL > 1 + emitComment( "PDFWriterImpl::writeBitmapObject" ); + #endif OStringBuffer aLine(1024); aLine.append( rObject.m_nObject ); aLine.append( " 0 obj\n" "<</Type/XObject/Subtype/Image/Width " ); aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() ); - aLine.append( " /Height " ); + aLine.append( "/Height " ); aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() ); - aLine.append( " /BitsPerComponent " ); + aLine.append( "/BitsPerComponent " ); aLine.append( nBitsPerComponent ); - aLine.append( " /Length " ); + aLine.append( "/Length " ); aLine.append( nStreamLengthObject ); aLine.append( " 0 R\n" ); #ifndef DEBUG_DISABLE_PDFCOMPRESSION - aLine.append( "/Filter/FlateDecode" ); + if( nBitsPerComponent != 1 ) + { + aLine.append( "/Filter/FlateDecode" ); + } + else + { + aLine.append( "/Filter/CCITTFaxDecode/DecodeParms<</K -1/BlackIs1 true/Columns " ); + aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() ); + aLine.append( ">>\n" ); + } #endif if( ! bMask ) { @@ -9742,7 +9760,7 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) { if( aBitmap.GetBitCount() == 1 ) { - aLine.append( " /ImageMask true\n" ); + aLine.append( "/ImageMask true\n" ); sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) ); DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" ); if( nBlackIndex ) @@ -9804,33 +9822,42 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos )) ); checkAndEnableStreamEncryption( rObject.m_nObject ); - beginCompression(); - if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) +#ifndef DEBUG_DISABLE_PDFCOMPRESSION + if( nBitsPerComponent == 1 ) { - const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U ); - - for( int i = 0; i < pAccess->Height(); i++ ) - { - CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) ); - } + writeG4Stream( pAccess ); } else +#endif { - const int nScanLineBytes = pAccess->Width()*3; - boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] ); - for( int y = 0; y < pAccess->Height(); y++ ) + beginCompression(); + if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) { - for( int x = 0; x < pAccess->Width(); x++ ) + const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U ); + + for( int i = 0; i < pAccess->Height(); i++ ) { - BitmapColor aColor = pAccess->GetColor( y, x ); - pCol[3*x+0] = aColor.GetRed(); - pCol[3*x+1] = aColor.GetGreen(); - pCol[3*x+2] = aColor.GetBlue(); + CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) ); } - CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) ); } + else + { + const int nScanLineBytes = pAccess->Width()*3; + boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] ); + for( int y = 0; y < pAccess->Height(); y++ ) + { + for( int x = 0; x < pAccess->Width(); x++ ) + { + BitmapColor aColor = pAccess->GetColor( y, x ); + pCol[3*x+0] = aColor.GetRed(); + pCol[3*x+1] = aColor.GetGreen(); + pCol[3*x+2] = aColor.GetBlue(); + } + CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) ); + } + } + endCompression(); } - endCompression(); disableStreamEncryption(); sal_uInt64 nEndPos = 0; @@ -9870,8 +9897,25 @@ void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const if( ! (rSizePixel.Width() && rSizePixel.Height()) ) return; - SvMemoryStream* pStream = new SvMemoryStream; rDCTData.Seek( 0 ); + if( bIsTrueColor && m_aContext.ColorMode == PDFWriter::DrawGreyscale ) + { + // need to convert to grayscale; + // load stream to bitmap and draw the bitmap instead + Graphic aGraphic; + GraphicConverter::Import( rDCTData, aGraphic, CVT_JPG ); + Bitmap aBmp( aGraphic.GetBitmap() ); + if( !!rMask && rMask.GetSizePixel() == aBmp.GetSizePixel() ) + { + BitmapEx aBmpEx( aBmp, rMask ); + drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmpEx ); + } + else + drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmp ); + return; + } + + SvMemoryStream* pStream = new SvMemoryStream; *pStream << rDCTData; pStream->Seek( STREAM_SEEK_TO_END ); @@ -9962,18 +10006,28 @@ void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, writeBuffer( aLine.getStr(), aLine.getLength() ); } -const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& rBitmap, bool bDrawMask ) +const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& i_rBitmap, bool bDrawMask ) { + BitmapEx aBitmap( i_rBitmap ); + if( m_aContext.ColorMode == PDFWriter::DrawGreyscale ) + { + BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS; + int nDepth = aBitmap.GetBitmap().GetBitCount(); + if( nDepth <= 4 ) + eConv = BMP_CONVERSION_4BIT_GREYS; + if( nDepth > 1 ) + aBitmap.Convert( eConv ); + } BitmapID aID; - aID.m_aPixelSize = rBitmap.GetSizePixel(); - aID.m_nSize = rBitmap.GetBitCount(); - aID.m_nChecksum = rBitmap.GetBitmap().GetChecksum(); + aID.m_aPixelSize = aBitmap.GetSizePixel(); + aID.m_nSize = aBitmap.GetBitCount(); + aID.m_nChecksum = aBitmap.GetBitmap().GetChecksum(); aID.m_nMaskChecksum = 0; - if( rBitmap.IsAlpha() ) - aID.m_nMaskChecksum = rBitmap.GetAlpha().GetChecksum(); + if( aBitmap.IsAlpha() ) + aID.m_nMaskChecksum = aBitmap.GetAlpha().GetChecksum(); else { - Bitmap aMask = rBitmap.GetMask(); + Bitmap aMask = aBitmap.GetMask(); if( ! aMask.IsEmpty() ) aID.m_nMaskChecksum = aMask.GetChecksum(); } @@ -9987,7 +10041,7 @@ const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx { m_aBitmaps.push_front( BitmapEmit() ); m_aBitmaps.front().m_aID = aID; - m_aBitmaps.front().m_aBitmap = rBitmap; + m_aBitmaps.front().m_aBitmap = aBitmap; m_aBitmaps.front().m_nObject = createObject(); m_aBitmaps.front().m_bDrawMask = bDrawMask; it = m_aBitmaps.begin(); @@ -10050,15 +10104,16 @@ sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize ) ); // check if we already have this gradient std::list<GradientEmit>::iterator it; + // rounding to point will generally lose some pixels + // round up to point boundary + aPtSize.Width()++; + aPtSize.Height()++; for( it = m_aGradients.begin(); it != m_aGradients.end(); ++it ) { if( it->m_aGradient == rGradient ) { - if( it->m_aSize.Width() < aPtSize.Width() ) - it->m_aSize.Width() = aPtSize.Width(); - if( it->m_aSize.Height() <= aPtSize.Height() ) - it->m_aSize.Height() = aPtSize.Height(); - break; + if( it->m_aSize == aPtSize ) + break; } } if( it == m_aGradients.end() ) @@ -10133,12 +10188,12 @@ void PDFWriterImpl::drawGradient( const PolyPolygon& rPolyPoly, const Gradient& return; } - sal_Int32 nGradient = createGradient( rGradient, rPolyPoly.GetBoundRect().GetSize() ); + Rectangle aBoundRect = rPolyPoly.GetBoundRect(); + sal_Int32 nGradient = createGradient( rGradient, aBoundRect.GetSize() ); updateGraphicsState(); - Rectangle aBoundRect = rPolyPoly.GetBoundRect(); - Point aTranslate = aBoundRect.BottomLeft() + Point( 0, 1 ); + Point aTranslate = aBoundRect.BottomLeft(); int nPolygons = rPolyPoly.Count(); OStringBuffer aLine( 80*nPolygons ); diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index b6612d835ca2..c73be7c037e5 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -59,6 +59,7 @@ class ImplFontMetricData; class FontSubsetInfo; class ZCodec; class EncHashTransporter; +struct BitStreamState; // the maximum password length #define ENCRYPTED_PWD_SIZE 32 @@ -831,7 +832,7 @@ i12626 // test if the encryption is active, if yes than encrypt the unicode string and add to the OStringBuffer parameter void appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ); - void appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ); + void appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc = RTL_TEXTENCODING_ASCII_US ); void appendLiteralStringEncrypt( const rtl::OString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ); void appendLiteralStringEncrypt( rtl::OStringBuffer& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ); @@ -1057,6 +1058,14 @@ i12626 void implWriteBitmapEx( const Point& rPoint, const Size& rSize, const BitmapEx& rBitmapEx, VirtualDevice* pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& ); + // helpers for CCITT 1bit bitmap stream + void putG4Bits( sal_uInt32 i_nLength, sal_uInt32 i_nCode, BitStreamState& io_rState ); + void putG4Span( long i_nSpan, bool i_bWhitePixel, BitStreamState& io_rState ); + void writeG4Stream( BitmapReadAccess* i_pBitmap ); + + // color helper functions + void appendStrokingColor( const Color& rColor, rtl::OStringBuffer& rBuffer ); + void appendNonStrokingColor( const Color& rColor, rtl::OStringBuffer& rBuffer ); public: PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >&, PDFWriter& ); ~PDFWriterImpl(); diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index 8546df1be705..143c55a83ab1 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -33,6 +33,7 @@ #include "vcl/virdev.hxx" #include "vcl/gdimtf.hxx" #include "vcl/metaact.hxx" +#include "vcl/bmpacc.hxx" #include "vcl/graph.hxx" #include "vcl/svdata.hxx" #include "unotools/streamwrap.hxx" @@ -47,6 +48,8 @@ #include <rtl/digest.h> +#undef USE_PDFGRADIENTS + using namespace vcl; using namespace rtl; using namespace com::sun::star; @@ -58,7 +61,7 @@ using namespace com::sun::star::beans; void PDFWriterImpl::implWriteGradient( const PolyPolygon& i_rPolyPoly, const Gradient& i_rGradient, VirtualDevice* i_pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& i_rContext ) { - GDIMetaFile aTmpMtf; + GDIMetaFile aTmpMtf; i_pDummyVDev->AddGradientActions( i_rPolyPoly.GetBoundRect(), i_rGradient, aTmpMtf ); @@ -140,6 +143,15 @@ void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSiz const Size aSizePixel( aBitmapEx.GetSizePixel() ); if ( aSizePixel.Width() && aSizePixel.Height() ) { + if( m_aContext.ColorMode == PDFWriter::DrawGreyscale ) + { + BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS; + int nDepth = aBitmapEx.GetBitmap().GetBitCount(); + if( nDepth <= 4 ) + eConv = BMP_CONVERSION_4BIT_GREYS; + if( nDepth > 1 ) + aBitmapEx.Convert( eConv ); + } sal_Bool bUseJPGCompression = !i_rContext.m_bOnlyLosslessCompression; if ( ( aSizePixel.Width() < 32 ) || ( aSizePixel.Height() < 32 ) ) bUseJPGCompression = sal_False; @@ -178,13 +190,13 @@ void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSiz try { uno::Reference < io::XStream > xStream = new utl::OStreamWrapper( aStrm ); - Reference< io::XSeekable > xSeekable( xStream, UNO_QUERY_THROW ); - Reference< graphic::XGraphicProvider > xGraphicProvider( ImplGetSVData()->maAppData.mxMSF->createInstance( + uno::Reference< io::XSeekable > xSeekable( xStream, UNO_QUERY_THROW ); + uno::Reference< graphic::XGraphicProvider > xGraphicProvider( ImplGetSVData()->maAppData.mxMSF->createInstance( OUString::createFromAscii( "com.sun.star.graphic.GraphicProvider" ) ), UNO_QUERY ); if ( xGraphicProvider.is() ) { - Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() ); - Reference < io::XOutputStream > xOut( xStream->getOutputStream() ); + uno::Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() ); + uno::Reference < io::XOutputStream > xOut( xStream->getOutputStream() ); rtl::OUString aMimeType( ::rtl::OUString::createFromAscii( "image/jpeg" ) ); uno::Sequence< beans::PropertyValue > aOutMediaProperties( 3 ); aOutMediaProperties[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" ); @@ -207,7 +219,7 @@ void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSiz Sequence< PropertyValue > aArgs( 1 ); aArgs[ 0 ].Name = ::rtl::OUString::createFromAscii( "InputStream" ); aArgs[ 0 ].Value <<= xStream; - Reference< XPropertySet > xPropSet( xGraphicProvider->queryGraphicDescriptor( aArgs ) ); + uno::Reference< XPropertySet > xPropSet( xGraphicProvider->queryGraphicDescriptor( aArgs ) ); if ( xPropSet.is() ) { sal_Int16 nBitsPerPixel = 24; @@ -354,16 +366,23 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa case( META_GRADIENT_ACTION ): { const MetaGradientAction* pA = (const MetaGradientAction*) pAction; + #ifdef USE_PDFGRADIENTS + m_rOuterFace.DrawGradient( pA->GetRect(), pA->GetGradient() ); + #else const PolyPolygon aPolyPoly( pA->GetRect() ); - implWriteGradient( aPolyPoly, pA->GetGradient(), pDummyVDev, i_rContext ); + #endif } break; case( META_GRADIENTEX_ACTION ): { const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction; + #ifdef USE_PDFGRADIENTS + m_rOuterFace.DrawGradient( pA->GetPolyPolygon(), pA->GetGradient() ); + #else implWriteGradient( pA->GetPolyPolygon(), pA->GetGradient(), pDummyVDev, i_rContext ); + #endif } break; @@ -518,7 +537,13 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa } if( pGradAction ) + { + #if USE_PDFGRADIENTS + m_rOuterFace.DrawGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient() ); + #else implWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), pDummyVDev, i_rContext ); + #endif + } } else { @@ -1538,3 +1563,475 @@ bool PDFWriterImpl::computeUDictionaryValue( EncHashTransporter* i_pTransporter, /* end i12626 methods */ +static const long unsetRun[256] = +{ + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */ +}; + +static const long setRun[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */ +}; + +inline bool isSet( const Scanline i_pLine, long i_nIndex ) +{ + return (i_pLine[ i_nIndex/8 ] & (0x80 >> (i_nIndex&7))) != 0; +} + +long findBitRun( const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet ) +{ + if( i_nStartIndex < 0 ) + return i_nW; + + long nIndex = i_nStartIndex; + if( nIndex < i_nW ) + { + const sal_uInt8 * pByte = static_cast<sal_uInt8*>(i_pLine) + (nIndex/8); + sal_uInt8 nByte = *pByte; + + // run up to byte boundary + long nBitInByte = (nIndex & 7); + if( nBitInByte ) + { + sal_uInt8 nMask = 0x80 >> nBitInByte; + while( nBitInByte != 8 ) + { + if( (nByte & nMask) != (i_bSet ? nMask : 0) ) + return nIndex < i_nW ? nIndex : i_nW; + nMask = nMask >> 1; + nBitInByte++; + nIndex++; + } + if( nIndex < i_nW ) + { + pByte++; + nByte = *pByte; + } + } + + sal_uInt8 nRunByte; + const long* pRunTable; + if( i_bSet ) + { + nRunByte = 0xff; + pRunTable = setRun; + } + else + { + nRunByte = 0; + pRunTable = unsetRun; + } + + while( nByte == nRunByte && nIndex < i_nW ) + { + nIndex += 8; + pByte++; + nByte = *pByte; + } + if( nIndex < i_nW ) + { + nIndex += pRunTable[nByte]; + } + } + return nIndex < i_nW ? nIndex : i_nW; +} + +struct BitStreamState +{ + sal_uInt8 mnBuffer; + sal_uInt32 mnNextBitPos; + + BitStreamState() + : mnBuffer( 0 ) + , mnNextBitPos( 8 ) + { + } + + const sal_uInt8* getByte() const { return &mnBuffer; } + void flush() { mnNextBitPos = 8; mnBuffer = 0; } +}; + +void PDFWriterImpl::putG4Bits( sal_uInt32 i_nLength, sal_uInt32 i_nCode, BitStreamState& io_rState ) +{ + while( i_nLength > io_rState.mnNextBitPos ) + { + io_rState.mnBuffer |= static_cast<sal_uInt8>( i_nCode >> (i_nLength - io_rState.mnNextBitPos) ); + i_nLength -= io_rState.mnNextBitPos; + writeBuffer( io_rState.getByte(), 1 ); + io_rState.flush(); + } + OSL_ASSERT( i_nLength < 9 ); + static const unsigned int msbmask[9] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + io_rState.mnBuffer |= static_cast<sal_uInt8>( (i_nCode & msbmask[i_nLength]) << (io_rState.mnNextBitPos - i_nLength) ); + io_rState.mnNextBitPos -= i_nLength; + if( io_rState.mnNextBitPos == 0 ) + { + writeBuffer( io_rState.getByte(), 1 ); + io_rState.flush(); + } +} + +struct PixelCode +{ + sal_uInt32 mnEncodedPixels; + sal_uInt32 mnCodeBits; + sal_uInt32 mnCode; +}; + +static const PixelCode WhitePixelCodes[] = +{ + { 0, 8, 0x35 }, // 0011 0101 + { 1, 6, 0x7 }, // 0001 11 + { 2, 4, 0x7 }, // 0111 + { 3, 4, 0x8 }, // 1000 + { 4, 4, 0xB }, // 1011 + { 5, 4, 0xC }, // 1100 + { 6, 4, 0xE }, // 1110 + { 7, 4, 0xF }, // 1111 + { 8, 5, 0x13 }, // 1001 1 + { 9, 5, 0x14 }, // 1010 0 + { 10, 5, 0x7 }, // 0011 1 + { 11, 5, 0x8 }, // 0100 0 + { 12, 6, 0x8 }, // 0010 00 + { 13, 6, 0x3 }, // 0000 11 + { 14, 6, 0x34 }, // 1101 00 + { 15, 6, 0x35 }, // 1101 01 + { 16, 6, 0x2A }, // 1010 10 + { 17, 6, 0x2B }, // 1010 11 + { 18, 7, 0x27 }, // 0100 111 + { 19, 7, 0xC }, // 0001 100 + { 20, 7, 0x8 }, // 0001 000 + { 21, 7, 0x17 }, // 0010 111 + { 22, 7, 0x3 }, // 0000 011 + { 23, 7, 0x4 }, // 0000 100 + { 24, 7, 0x28 }, // 0101 000 + { 25, 7, 0x2B }, // 0101 011 + { 26, 7, 0x13 }, // 0010 011 + { 27, 7, 0x24 }, // 0100 100 + { 28, 7, 0x18 }, // 0011 000 + { 29, 8, 0x2 }, // 0000 0010 + { 30, 8, 0x3 }, // 0000 0011 + { 31, 8, 0x1A }, // 0001 1010 + { 32, 8, 0x1B }, // 0001 1011 + { 33, 8, 0x12 }, // 0001 0010 + { 34, 8, 0x13 }, // 0001 0011 + { 35, 8, 0x14 }, // 0001 0100 + { 36, 8, 0x15 }, // 0001 0101 + { 37, 8, 0x16 }, // 0001 0110 + { 38, 8, 0x17 }, // 0001 0111 + { 39, 8, 0x28 }, // 0010 1000 + { 40, 8, 0x29 }, // 0010 1001 + { 41, 8, 0x2A }, // 0010 1010 + { 42, 8, 0x2B }, // 0010 1011 + { 43, 8, 0x2C }, // 0010 1100 + { 44, 8, 0x2D }, // 0010 1101 + { 45, 8, 0x4 }, // 0000 0100 + { 46, 8, 0x5 }, // 0000 0101 + { 47, 8, 0xA }, // 0000 1010 + { 48, 8, 0xB }, // 0000 1011 + { 49, 8, 0x52 }, // 0101 0010 + { 50, 8, 0x53 }, // 0101 0011 + { 51, 8, 0x54 }, // 0101 0100 + { 52, 8, 0x55 }, // 0101 0101 + { 53, 8, 0x24 }, // 0010 0100 + { 54, 8, 0x25 }, // 0010 0101 + { 55, 8, 0x58 }, // 0101 1000 + { 56, 8, 0x59 }, // 0101 1001 + { 57, 8, 0x5A }, // 0101 1010 + { 58, 8, 0x5B }, // 0101 1011 + { 59, 8, 0x4A }, // 0100 1010 + { 60, 8, 0x4B }, // 0100 1011 + { 61, 8, 0x32 }, // 0011 0010 + { 62, 8, 0x33 }, // 0011 0011 + { 63, 8, 0x34 }, // 0011 0100 + { 64, 5, 0x1B }, // 1101 1 + { 128, 5, 0x12 }, // 1001 0 + { 192, 6, 0x17 }, // 0101 11 + { 256, 7, 0x37 }, // 0110 111 + { 320, 8, 0x36 }, // 0011 0110 + { 384, 8, 0x37 }, // 0011 0111 + { 448, 8, 0x64 }, // 0110 0100 + { 512, 8, 0x65 }, // 0110 0101 + { 576, 8, 0x68 }, // 0110 1000 + { 640, 8, 0x67 }, // 0110 0111 + { 704, 9, 0xCC }, // 0110 0110 0 + { 768, 9, 0xCD }, // 0110 0110 1 + { 832, 9, 0xD2 }, // 0110 1001 0 + { 896, 9, 0xD3 }, // 0110 1001 1 + { 960, 9, 0xD4 }, // 0110 1010 0 + { 1024, 9, 0xD5 }, // 0110 1010 1 + { 1088, 9, 0xD6 }, // 0110 1011 0 + { 1152, 9, 0xD7 }, // 0110 1011 1 + { 1216, 9, 0xD8 }, // 0110 1100 0 + { 1280, 9, 0xD9 }, // 0110 1100 1 + { 1344, 9, 0xDA }, // 0110 1101 0 + { 1408, 9, 0xDB }, // 0110 1101 1 + { 1472, 9, 0x98 }, // 0100 1100 0 + { 1536, 9, 0x99 }, // 0100 1100 1 + { 1600, 9, 0x9A }, // 0100 1101 0 + { 1664, 6, 0x18 }, // 0110 00 + { 1728, 9, 0x9B }, // 0100 1101 1 + { 1792, 11, 0x8 }, // 0000 0001 000 + { 1856, 11, 0xC }, // 0000 0001 100 + { 1920, 11, 0xD }, // 0000 0001 101 + { 1984, 12, 0x12 }, // 0000 0001 0010 + { 2048, 12, 0x13 }, // 0000 0001 0011 + { 2112, 12, 0x14 }, // 0000 0001 0100 + { 2176, 12, 0x15 }, // 0000 0001 0101 + { 2240, 12, 0x16 }, // 0000 0001 0110 + { 2304, 12, 0x17 }, // 0000 0001 0111 + { 2368, 12, 0x1C }, // 0000 0001 1100 + { 2432, 12, 0x1D }, // 0000 0001 1101 + { 2496, 12, 0x1E }, // 0000 0001 1110 + { 2560, 12, 0x1F } // 0000 0001 1111 +}; + +static const PixelCode BlackPixelCodes[] = +{ + { 0, 10, 0x37 }, // 0000 1101 11 + { 1, 3, 0x2 }, // 010 + { 2, 2, 0x3 }, // 11 + { 3, 2, 0x2 }, // 10 + { 4, 3, 0x3 }, // 011 + { 5, 4, 0x3 }, // 0011 + { 6, 4, 0x2 }, // 0010 + { 7, 5, 0x3 }, // 0001 1 + { 8, 6, 0x5 }, // 0001 01 + { 9, 6, 0x4 }, // 0001 00 + { 10, 7, 0x4 }, // 0000 100 + { 11, 7, 0x5 }, // 0000 101 + { 12, 7, 0x7 }, // 0000 111 + { 13, 8, 0x4 }, // 0000 0100 + { 14, 8, 0x7 }, // 0000 0111 + { 15, 9, 0x18 }, // 0000 1100 0 + { 16, 10, 0x17 }, // 0000 0101 11 + { 17, 10, 0x18 }, // 0000 0110 00 + { 18, 10, 0x8 }, // 0000 0010 00 + { 19, 11, 0x67 }, // 0000 1100 111 + { 20, 11, 0x68 }, // 0000 1101 000 + { 21, 11, 0x6C }, // 0000 1101 100 + { 22, 11, 0x37 }, // 0000 0110 111 + { 23, 11, 0x28 }, // 0000 0101 000 + { 24, 11, 0x17 }, // 0000 0010 111 + { 25, 11, 0x18 }, // 0000 0011 000 + { 26, 12, 0xCA }, // 0000 1100 1010 + { 27, 12, 0xCB }, // 0000 1100 1011 + { 28, 12, 0xCC }, // 0000 1100 1100 + { 29, 12, 0xCD }, // 0000 1100 1101 + { 30, 12, 0x68 }, // 0000 0110 1000 + { 31, 12, 0x69 }, // 0000 0110 1001 + { 32, 12, 0x6A }, // 0000 0110 1010 + { 33, 12, 0x6B }, // 0000 0110 1011 + { 34, 12, 0xD2 }, // 0000 1101 0010 + { 35, 12, 0xD3 }, // 0000 1101 0011 + { 36, 12, 0xD4 }, // 0000 1101 0100 + { 37, 12, 0xD5 }, // 0000 1101 0101 + { 38, 12, 0xD6 }, // 0000 1101 0110 + { 39, 12, 0xD7 }, // 0000 1101 0111 + { 40, 12, 0x6C }, // 0000 0110 1100 + { 41, 12, 0x6D }, // 0000 0110 1101 + { 42, 12, 0xDA }, // 0000 1101 1010 + { 43, 12, 0xDB }, // 0000 1101 1011 + { 44, 12, 0x54 }, // 0000 0101 0100 + { 45, 12, 0x55 }, // 0000 0101 0101 + { 46, 12, 0x56 }, // 0000 0101 0110 + { 47, 12, 0x57 }, // 0000 0101 0111 + { 48, 12, 0x64 }, // 0000 0110 0100 + { 49, 12, 0x65 }, // 0000 0110 0101 + { 50, 12, 0x52 }, // 0000 0101 0010 + { 51, 12, 0x53 }, // 0000 0101 0011 + { 52, 12, 0x24 }, // 0000 0010 0100 + { 53, 12, 0x37 }, // 0000 0011 0111 + { 54, 12, 0x38 }, // 0000 0011 1000 + { 55, 12, 0x27 }, // 0000 0010 0111 + { 56, 12, 0x28 }, // 0000 0010 1000 + { 57, 12, 0x58 }, // 0000 0101 1000 + { 58, 12, 0x59 }, // 0000 0101 1001 + { 59, 12, 0x2B }, // 0000 0010 1011 + { 60, 12, 0x2C }, // 0000 0010 1100 + { 61, 12, 0x5A }, // 0000 0101 1010 + { 62, 12, 0x66 }, // 0000 0110 0110 + { 63, 12, 0x67 }, // 0000 0110 0111 + { 64, 10, 0xF }, // 0000 0011 11 + { 128, 12, 0xC8 }, // 0000 1100 1000 + { 192, 12, 0xC9 }, // 0000 1100 1001 + { 256, 12, 0x5B }, // 0000 0101 1011 + { 320, 12, 0x33 }, // 0000 0011 0011 + { 384, 12, 0x34 }, // 0000 0011 0100 + { 448, 12, 0x35 }, // 0000 0011 0101 + { 512, 13, 0x6C }, // 0000 0011 0110 0 + { 576, 13, 0x6D }, // 0000 0011 0110 1 + { 640, 13, 0x4A }, // 0000 0010 0101 0 + { 704, 13, 0x4B }, // 0000 0010 0101 1 + { 768, 13, 0x4C }, // 0000 0010 0110 0 + { 832, 13, 0x4D }, // 0000 0010 0110 1 + { 896, 13, 0x72 }, // 0000 0011 1001 0 + { 960, 13, 0x73 }, // 0000 0011 1001 1 + { 1024, 13, 0x74 }, // 0000 0011 1010 0 + { 1088, 13, 0x75 }, // 0000 0011 1010 1 + { 1152, 13, 0x76 }, // 0000 0011 1011 0 + { 1216, 13, 0x77 }, // 0000 0011 1011 1 + { 1280, 13, 0x52 }, // 0000 0010 1001 0 + { 1344, 13, 0x53 }, // 0000 0010 1001 1 + { 1408, 13, 0x54 }, // 0000 0010 1010 0 + { 1472, 13, 0x55 }, // 0000 0010 1010 1 + { 1536, 13, 0x5A }, // 0000 0010 1101 0 + { 1600, 13, 0x5B }, // 0000 0010 1101 1 + { 1664, 13, 0x64 }, // 0000 0011 0010 0 + { 1728, 13, 0x65 }, // 0000 0011 0010 1 + { 1792, 11, 0x8 }, // 0000 0001 000 + { 1856, 11, 0xC }, // 0000 0001 100 + { 1920, 11, 0xD }, // 0000 0001 101 + { 1984, 12, 0x12 }, // 0000 0001 0010 + { 2048, 12, 0x13 }, // 0000 0001 0011 + { 2112, 12, 0x14 }, // 0000 0001 0100 + { 2176, 12, 0x15 }, // 0000 0001 0101 + { 2240, 12, 0x16 }, // 0000 0001 0110 + { 2304, 12, 0x17 }, // 0000 0001 0111 + { 2368, 12, 0x1C }, // 0000 0001 1100 + { 2432, 12, 0x1D }, // 0000 0001 1101 + { 2496, 12, 0x1E }, // 0000 0001 1110 + { 2560, 12, 0x1F } // 0000 0001 1111 +}; + + +void PDFWriterImpl::putG4Span( long i_nSpan, bool i_bWhitePixel, BitStreamState& io_rState ) +{ + const PixelCode* pTable = i_bWhitePixel ? WhitePixelCodes : BlackPixelCodes; + // maximum encoded span is 2560 consecutive pixels + while( i_nSpan > 2623 ) + { + // write 2560 bits, that is entry (63 + (2560 >> 6)) == 103 in the appropriate table + putG4Bits( pTable[103].mnCodeBits, pTable[103].mnCode, io_rState ); + i_nSpan -= pTable[103].mnEncodedPixels; + } + // write multiples of 64 pixels up to 2560 + if( i_nSpan > 63 ) + { + sal_uInt32 nTabIndex = 63 + (i_nSpan >> 6); + OSL_ASSERT( pTable[nTabIndex].mnEncodedPixels == static_cast<sal_uInt32>(64*(i_nSpan >> 6)) ); + putG4Bits( pTable[nTabIndex].mnCodeBits, pTable[nTabIndex].mnCode, io_rState ); + i_nSpan -= pTable[nTabIndex].mnEncodedPixels; + } + putG4Bits( pTable[i_nSpan].mnCodeBits, pTable[i_nSpan].mnCode, io_rState ); +} + +void PDFWriterImpl::writeG4Stream( BitmapReadAccess* i_pBitmap ) +{ + long nW = i_pBitmap->Width(); + long nH = i_pBitmap->Height(); + if( nW <= 0 || nH <= 0 ) + return; + if( i_pBitmap->GetBitCount() != 1 ) + return; + + BitStreamState aBitState; + + // the first reference line is virtual and completely empty + const Scanline pFirstRefLine = (Scanline)rtl_allocateZeroMemory( nW/8 + 1 ); + Scanline pRefLine = pFirstRefLine; + for( long nY = 0; nY < nH; nY++ ) + { + const Scanline pCurLine = i_pBitmap->GetScanline( nY ); + long nLineIndex = 0; + bool bRunSet = (*pCurLine & 0x80) ? true : false; + bool bRefSet = (*pRefLine & 0x80) ? true : false; + long nRunIndex1 = bRunSet ? 0 : findBitRun( pCurLine, 0, nW, bRunSet ); + long nRefIndex1 = bRefSet ? 0 : findBitRun( pRefLine, 0, nW, bRefSet ); + for( ; nLineIndex < nW; ) + { + long nRefIndex2 = findBitRun( pRefLine, nRefIndex1, nW, isSet( pRefLine, nRefIndex1 ) ); + if( nRefIndex2 >= nRunIndex1 ) + { + long nDiff = nRefIndex1 - nRunIndex1; + if( -3 <= nDiff && nDiff <= 3 ) + { // vertical coding + static const struct + { + sal_uInt32 mnCodeBits; + sal_uInt32 mnCode; + } VerticalCodes[7] = { + { 7, 0x03 }, // 0000 011 + { 6, 0x03 }, // 0000 11 + { 3, 0x03 }, // 011 + { 1, 0x1 }, // 1 + { 3, 0x2 }, // 010 + { 6, 0x02 }, // 0000 10 + { 7, 0x02 } // 0000 010 + }; + // convert to index + nDiff += 3; + + // emit diff code + putG4Bits( VerticalCodes[nDiff].mnCodeBits, VerticalCodes[nDiff].mnCode, aBitState ); + nLineIndex = nRunIndex1; + } + else + { // difference too large, horizontal coding + // emit horz code 001 + putG4Bits( 3, 0x1, aBitState ); + long nRunIndex2 = findBitRun( pCurLine, nRunIndex1, nW, isSet( pCurLine, nRunIndex1 ) ); + bool bWhiteFirst = ( nLineIndex + nRunIndex1 == 0 || ! isSet( pCurLine, nLineIndex ) ); + putG4Span( nRunIndex1 - nLineIndex, bWhiteFirst, aBitState ); + putG4Span( nRunIndex2 - nRunIndex1, ! bWhiteFirst, aBitState ); + nLineIndex = nRunIndex2; + } + } + else + { // emit pass code 0001 + putG4Bits( 4, 0x1, aBitState ); + nLineIndex = nRefIndex2; + } + if( nLineIndex < nW ) + { + bool bSet = isSet( pCurLine, nLineIndex ); + nRunIndex1 = findBitRun( pCurLine, nLineIndex, nW, bSet ); + nRefIndex1 = findBitRun( pRefLine, nLineIndex, nW, ! bSet ); + nRefIndex1 = findBitRun( pRefLine, nRefIndex1, nW, bSet ); + } + } + + // the current line is the reference for the next line + pRefLine = pCurLine; + } + // terminate strip with EOFB + putG4Bits( 12, 1, aBitState ); + putG4Bits( 12, 1, aBitState ); + if( aBitState.mnNextBitPos != 8 ) + { + writeBuffer( aBitState.getByte(), 1 ); + aBitState.flush(); + } + + rtl_freeMemory( pFirstRefLine ); +} diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index c00dfd7635ae..e5e19dff3771 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -41,6 +41,7 @@ #include <vcl/unohelp.hxx> #include <tools/debug.hxx> +#include <tools/resary.hxx> #include <tools/stream.hxx> #include <tools/vcompat.hxx> #include <vcl/svdata.hxx> @@ -54,6 +55,7 @@ #include <vcl/gdimtf.hxx> #include <vcl/metaact.hxx> #include <vcl/print.hxx> +#include <vcl/svids.hrc> #include <comphelper/processfactory.hxx> @@ -1280,6 +1282,48 @@ int Printer::GetPaperInfoCount() const // ----------------------------------------------------------------------- +rtl::OUString Printer::GetPaperName( Paper ePaper ) +{ + ImplSVData* pSVData = ImplGetSVData(); + if( ! pSVData->mpPaperNames ) + { + pSVData->mpPaperNames = new std::hash_map< int, rtl::OUString >(); + if( ImplGetResMgr() ) + { + ResStringArray aPaperStrings( VclResId( RID_STR_PAPERNAMES ) ); + static const int PaperIndex[] = + { + PAPER_A0, PAPER_A1, PAPER_A2, PAPER_A3, PAPER_A4, PAPER_A5, + PAPER_B4_ISO, PAPER_B5_ISO, PAPER_LETTER, PAPER_LEGAL, PAPER_TABLOID, + PAPER_USER, PAPER_B6_ISO, PAPER_ENV_C4, PAPER_ENV_C5, PAPER_ENV_C6, PAPER_ENV_C65, + PAPER_ENV_DL, PAPER_SLIDE_DIA, PAPER_SCREEN, PAPER_C, PAPER_D, PAPER_E, + PAPER_EXECUTIVE, PAPER_FANFOLD_LEGAL_DE, PAPER_ENV_MONARCH, PAPER_ENV_PERSONAL, + PAPER_ENV_9, PAPER_ENV_10, PAPER_ENV_11, PAPER_ENV_12, PAPER_KAI16, + PAPER_KAI32, PAPER_KAI32BIG, PAPER_B4_JIS, PAPER_B5_JIS, PAPER_B6_JIS + }; + OSL_ENSURE( sal_uInt32(sizeof(PaperIndex)/sizeof(PaperIndex[0])) == aPaperStrings.Count(), "localized paper name count wrong" ); + for( int i = 0; i < int(sizeof(PaperIndex)/sizeof(PaperIndex[0])); i++ ) + (*pSVData->mpPaperNames)[PaperIndex[i]] = aPaperStrings.GetString(i); + } + } + + std::hash_map<int,rtl::OUString>::const_iterator it = pSVData->mpPaperNames->find( (int)ePaper ); + return (it != pSVData->mpPaperNames->end()) ? it->second : rtl::OUString(); +} + +// ----------------------------------------------------------------------- + +rtl::OUString Printer::GetPaperName( bool i_bPaperUser ) const +{ + Size aPageSize = PixelToLogic( GetPaperSizePixel(), MAP_100TH_MM ); + Paper ePaper = ImplGetPaperFormat( aPageSize.Width(), aPageSize.Height() ); + if( ePaper == PAPER_USER ) + ePaper = ImplGetPaperFormat( aPageSize.Height(), aPageSize.Width() ); + return (ePaper != PAPER_USER || i_bPaperUser ) ? GetPaperName( ePaper ) : rtl::OUString(); +} + +// ----------------------------------------------------------------------- + const PaperInfo& Printer::GetPaperInfo( int nPaper ) const { if( ! mpInfoPrinter ) diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx index 01bf4ca90d65..d86df6e2816b 100644 --- a/vcl/source/gdi/print2.cxx +++ b/vcl/source/gdi/print2.cxx @@ -855,13 +855,12 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, ++nActionNum; } - ConnectedComponentsList aCCList; // list containing distinct sets of connected components as elements. + // clean up aMapModeVDev + sal_uInt32 nCount = aMapModeVDev.GetGCStackDepth(); + while( nCount-- ) + aMapModeVDev.Pop(); - // create an OutputDevice to record mapmode changes and the like - VirtualDevice aMapModeVDev2; - aMapModeVDev2.mnDPIX = mnDPIX; - aMapModeVDev2.mnDPIY = mnDPIY; - aMapModeVDev2.EnableOutput(sal_False); + ConnectedComponentsList aCCList; // list containing distinct sets of connected components as elements. // fast-forward until one after the last background action // (need to reconstruct map mode vdev state) @@ -876,7 +875,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, pCurrAct, nActionNum) ); // execute action to get correct MapModes etc. - pCurrAct->Execute( &aMapModeVDev2 ); + pCurrAct->Execute( &aMapModeVDev ); pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(); ++nActionNum; } @@ -893,10 +892,10 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum ) { // execute action to get correct MapModes etc. - pCurrAct->Execute( &aMapModeVDev2 ); + pCurrAct->Execute( &aMapModeVDev ); // cache bounds of current action - const Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, aMapModeVDev2) ); + const Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, aMapModeVDev) ); // accumulate collected bounds here, initialize with current action Rectangle aTotalBounds( aBBCurrAct ); // thus, @@ -925,7 +924,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // not be considered for connected components, // too. Just put each of them into a separate // component. - aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, aMapModeVDev2); + aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, aMapModeVDev); if( !aBBCurrAct.IsEmpty() && !aTotalComponents.bIsFullyTransparent ) @@ -1311,18 +1310,16 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, } } + // clean up aMapModeVDev + nCount = aMapModeVDev.GetGCStackDepth(); + while( nCount-- ) + aMapModeVDev.Pop(); + // // STAGE 4: Copy actions to output metafile // ======================================== // - // create an OutputDevice to record color settings, mapmode - // changes and the like - VirtualDevice aMapModeVDev3; - aMapModeVDev3.mnDPIX = mnDPIX; - aMapModeVDev3.mnDPIY = mnDPIY; - aMapModeVDev3.EnableOutput(sal_False); - // iterate over all actions and duplicate the ones not in a // special aCCList member into rOutMtf for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0; @@ -1350,7 +1347,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, // given background color ImplConvertTransparentAction(rOutMtf, *pCurrAct, - aMapModeVDev3, + aMapModeVDev, aBackgroundComponent.aBgColor); } else @@ -1359,7 +1356,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, rOutMtf.AddAction( ( pCurrAct->Duplicate(), pCurrAct ) ); } - pCurrAct->Execute(&aMapModeVDev3); + pCurrAct->Execute(&aMapModeVDev); } } diff --git a/vcl/source/gdi/region.cxx b/vcl/source/gdi/region.cxx index cab1b6610d26..96e67aaabffa 100644..100755 --- a/vcl/source/gdi/region.cxx +++ b/vcl/source/gdi/region.cxx @@ -46,6 +46,8 @@ #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> #include <basegfx/range/b2drange.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> @@ -1376,6 +1378,28 @@ sal_Bool Region::Union( const Rectangle& rRect ) if ( rRect.IsEmpty() ) return sal_True; + if( HasPolyPolygon() ) + { + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + + if( aThisPolyPoly.count() == 0 ) + { + *this = rRect; + return true; + } + + // get the other B2DPolyPolygon + basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) ); + basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly ); + + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly ); + *this = Region( aClip ); + + return sal_True; + } + ImplPolyPolyRegionToBandRegion(); // no instance data? -> create! @@ -1446,6 +1470,22 @@ sal_Bool Region::Intersect( const Rectangle& rRect ) return sal_True; } + else if( mpImplRegion->mpB2DPolyPoly ) + { + // #127431# make ImplRegion unique, if not already. + if( mpImplRegion->mnRefCount > 1 ) + { + mpImplRegion->mnRefCount--; + mpImplRegion = new ImplRegion( *mpImplRegion->mpB2DPolyPoly ); + } + + *mpImplRegion->mpB2DPolyPoly = + basegfx::tools::clipPolyPolygonOnRange( *mpImplRegion->mpB2DPolyPoly, + basegfx::B2DRange( rRect.Left(), rRect.Top(), + rRect.Right(), rRect.Bottom() ), + true, false ); + return sal_True; + } else ImplPolyPolyRegionToBandRegion(); @@ -1529,6 +1569,25 @@ sal_Bool Region::Exclude( const Rectangle& rRect ) if ( rRect.IsEmpty() ) return sal_True; + if( HasPolyPolygon() ) + { + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + + if( aThisPolyPoly.count() == 0 ) + return sal_True; + + // get the other B2DPolyPolygon + basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) ); + basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly ); + + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly ); + *this = Region( aClip ); + + return sal_True; + } + ImplPolyPolyRegionToBandRegion(); // no instance data? -> create! @@ -1571,6 +1630,28 @@ sal_Bool Region::XOr( const Rectangle& rRect ) if ( rRect.IsEmpty() ) return sal_True; + if( HasPolyPolygon() ) + { + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + + if( aThisPolyPoly.count() == 0 ) + { + *this = rRect; + return sal_True; + } + + // get the other B2DPolyPolygon + basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) ); + basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly ); + + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly ); + *this = Region( aClip ); + + return sal_True; + } + ImplPolyPolyRegionToBandRegion(); // no instance data? -> create! @@ -1604,11 +1685,38 @@ sal_Bool Region::XOr( const Rectangle& rRect ) } // ----------------------------------------------------------------------- +void Region::ImplUnionPolyPolygon( const Region& i_rRegion ) +{ + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + + if( aThisPolyPoly.count() == 0 ) + { + *this = i_rRegion; + return; + } + + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); + aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); + + + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly ); + + *this = Region( aClip ); +} sal_Bool Region::Union( const Region& rRegion ) { DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) + { + ImplUnionPolyPolygon( rRegion ); + return sal_True; + } + ImplPolyPolyRegionToBandRegion(); ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); @@ -1654,6 +1762,22 @@ sal_Bool Region::Union( const Region& rRegion ) } // ----------------------------------------------------------------------- +void Region::ImplIntersectWithPolyPolygon( const Region& i_rRegion ) +{ + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + if( aThisPolyPoly.count() == 0 ) + { + *this = i_rRegion; + return; + } + + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); + + basegfx::B2DPolyPolygon aClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aOtherPolyPoly, aThisPolyPoly, true, false ); + *this = Region( aClip ); +} sal_Bool Region::Intersect( const Region& rRegion ) { @@ -1663,6 +1787,12 @@ sal_Bool Region::Intersect( const Region& rRegion ) if ( mpImplRegion == rRegion.mpImplRegion ) return sal_True; + if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) + { + ImplIntersectWithPolyPolygon( rRegion ); + return sal_True; + } + ImplPolyPolyRegionToBandRegion(); ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); @@ -1793,11 +1923,32 @@ sal_Bool Region::Intersect( const Region& rRegion ) } // ----------------------------------------------------------------------- +void Region::ImplExcludePolyPolygon( const Region& i_rRegion ) +{ + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + if( aThisPolyPoly.count() == 0 ) + return; + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); + aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); + + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly ); + *this = Region( aClip ); +} sal_Bool Region::Exclude( const Region& rRegion ) { DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) + { + ImplExcludePolyPolygon( rRegion ); + return sal_True; + } + ImplPolyPolyRegionToBandRegion(); ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); @@ -1846,11 +1997,35 @@ sal_Bool Region::Exclude( const Region& rRegion ) } // ----------------------------------------------------------------------- +void Region::ImplXOrPolyPolygon( const Region& i_rRegion ) +{ + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + if( aThisPolyPoly.count() == 0 ) + { + *this = i_rRegion; + return; + } + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); + aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); + + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly ); + *this = Region( aClip ); +} sal_Bool Region::XOr( const Region& rRegion ) { DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) + { + ImplXOrPolyPolygon( rRegion ); + return sal_True; + } + ImplPolyPolyRegionToBandRegion(); ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); @@ -2031,7 +2206,7 @@ basegfx::B2DPolyPolygon Region::ConvertToB2DPolyPolygon() // ----------------------------------------------------------------------- -sal_Bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, +bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, long& rX, long& rY, long& rWidth, long& rHeight ) const { @@ -2041,11 +2216,11 @@ sal_Bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, // no internal data? -> region is empty! if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_False; + return false; // no band in the list? -> region is empty! if ( mpImplRegion->mpFirstBand == NULL ) - return sal_False; + return false; // initialise pointer for first access ImplRegionBand* pCurrRectBand = mpImplRegion->mpFirstBand; @@ -2053,7 +2228,7 @@ sal_Bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, DBG_ASSERT( pCurrRectBandSep != NULL, "Erstes Band wurde nicht optimiert." ); if ( !pCurrRectBandSep ) - return sal_False; + return false; // get boundaries of current rectangle rX = pCurrRectBandSep->mnXLeft; @@ -2065,12 +2240,12 @@ sal_Bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand; rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep; - return sal_True; + return true; } // ----------------------------------------------------------------------- -sal_Bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, +bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, long& rX, long& rY, long& rWidth, long& rHeight ) const { @@ -2078,7 +2253,7 @@ sal_Bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, // no internal data? -> region is empty! if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_False; + return false; // get last pointers ImplRegionBand* pCurrRectBand = (ImplRegionBand*)rImplRegionInfo.mpVoidCurrRectBand; @@ -2095,7 +2270,7 @@ sal_Bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, // no band found? -> not further rectangles! if( !pCurrRectBand ) - return sal_False; + return false; // get first separation in current band pCurrRectBandSep = pCurrRectBand->mpFirstSep; @@ -2111,7 +2286,7 @@ sal_Bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand; rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep; - return sal_True; + return true; } // ----------------------------------------------------------------------- diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index f3c381147054..9f2ee0924555 100755 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -253,14 +253,29 @@ sal_Bool SalGraphics::mirror( sal_uInt32 nPoints, const SalPoint *pPtAry, SalPoi void SalGraphics::mirror( Region& rRgn, const OutputDevice *pOutDev, bool bBack ) const { - // mirror the bounding rect and move Region by resulting offset - Rectangle aRect( rRgn.GetBoundRect() ); - long nWidth = aRect.GetWidth(); - long x = aRect.Left(); - long x_org = x; + if( rRgn.HasPolyPolygon() ) + { + basegfx::B2DPolyPolygon aPolyPoly( rRgn.ConvertToB2DPolyPolygon() ); + aPolyPoly = mirror( aPolyPoly, pOutDev, bBack ); + rRgn = Region( aPolyPoly ); + } + else + { + ImplRegionInfo aInfo; + bool bRegionRect; + Region aMirroredRegion; + long nX, nY, nWidth, nHeight; - mirror( x, nWidth, pOutDev, bBack ); - rRgn.Move( x - x_org, 0 ); + bRegionRect = rRgn.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) ); + mirror( aRect, pOutDev, bBack ); + aMirroredRegion.Union( aRect ); + bRegionRect = rRgn.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + rRgn = aMirroredRegion; + } } void SalGraphics::mirror( Rectangle& rRect, const OutputDevice *pOutDev, bool bBack ) const @@ -358,22 +373,15 @@ basegfx::B2DPolyPolygon SalGraphics::mirror( const basegfx::B2DPolyPolygon& i_rP // ---------------------------------------------------------------------------- -sal_Bool SalGraphics::UnionClipRegion( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev ) +bool SalGraphics::SetClipRegion( const Region& i_rClip, const OutputDevice *pOutDev ) { if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) ) - mirror( nX, nWidth, pOutDev ); - return unionClipRegion( nX, nY, nWidth, nHeight ); -} - -bool SalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& ) -{ - return false; -} - -sal_Bool SalGraphics::UnionClipRegion( const ::basegfx::B2DPolyPolygon& rPoly, const OutputDevice* pOutDev ) -{ - (void)pOutDev;// TODO: SAL_LAYOUT_BIDI_RTL - return unionClipRegion( rPoly ); + { + Region aMirror( i_rClip ); + mirror( aMirror, pOutDev ); + return setClipRegion( aMirror ); + } + return setClipRegion( i_rClip ); } void SalGraphics::DrawPixel( long nX, long nY, const OutputDevice *pOutDev ) @@ -465,7 +473,7 @@ void SalGraphics::DrawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, bool SalGraphics::DrawPolyPolygon( const ::basegfx::B2DPolyPolygon& i_rPolyPolygon, double i_fTransparency, const OutputDevice* i_pOutDev ) { bool bRet = false; - if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) ) + if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) { basegfx::B2DPolyPolygon aMirror( mirror( i_rPolyPolygon, i_pOutDev ) ); bRet = drawPolyPolygon( aMirror, i_fTransparency ); @@ -483,7 +491,7 @@ bool SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fT sal_Bool SalGraphics::DrawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry, const OutputDevice* pOutDev ) { sal_Bool bResult = sal_False; - if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) ) + if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) ) { SalPoint* pPtAry2 = new SalPoint[nPoints]; sal_Bool bCopied = mirror( nPoints, pPtAry, pPtAry2, pOutDev ); @@ -498,7 +506,7 @@ sal_Bool SalGraphics::DrawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPt sal_Bool SalGraphics::DrawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry, const OutputDevice* pOutDev ) { sal_Bool bResult = sal_False; - if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) ) + if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) ) { SalPoint* pPtAry2 = new SalPoint[nPoints]; sal_Bool bCopied = mirror( nPoints, pPtAry, pPtAry2, pOutDev ); @@ -514,7 +522,7 @@ sal_Bool SalGraphics::DrawPolyPolygonBezier( sal_uInt32 i_nPoly, const sal_uInt3 const SalPoint* const* i_pPtAry, const sal_uInt8* const* i_pFlgAry, const OutputDevice* i_pOutDev ) { sal_Bool bRet = sal_False; - if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) ) + if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) { // TODO: optimize, reduce new/delete calls SalPoint **pPtAry2 = new SalPoint*[i_nPoly]; @@ -542,7 +550,7 @@ bool SalGraphics::DrawPolyLine( const ::basegfx::B2DPolygon& i_rPolygon, double const OutputDevice* i_pOutDev ) { bool bRet = false; - if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) ) + if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) ) { basegfx::B2DPolygon aMirror( mirror( i_rPolygon, i_pOutDev ) ); bRet = drawPolyLine( aMirror, fTransparency, i_rLineWidth, i_eLineJoin ); |