diff options
Diffstat (limited to 'vcl/aqua/source/gdi/atsui/salgdi.cxx')
-rw-r--r-- | vcl/aqua/source/gdi/atsui/salgdi.cxx | 1570 |
1 files changed, 2 insertions, 1568 deletions
diff --git a/vcl/aqua/source/gdi/atsui/salgdi.cxx b/vcl/aqua/source/gdi/atsui/salgdi.cxx index fa0f1d8c96c1..1cdecd1ac2e5 100644 --- a/vcl/aqua/source/gdi/atsui/salgdi.cxx +++ b/vcl/aqua/source/gdi/atsui/salgdi.cxx @@ -53,7 +53,6 @@ #include "fontsubset.hxx" #include "impfont.hxx" -#include "region.h" #include "sallayout.hxx" #include "sft.hxx" @@ -378,1200 +377,8 @@ AquaSalGraphics::~AquaSalGraphics() } } -bool AquaSalGraphics::supportsOperation( OutDevSupportType eType ) const -{ - bool bRet = false; - switch( eType ) - { - case OutDevSupport_TransparentRect: - case OutDevSupport_B2DClip: - case OutDevSupport_B2DDraw: - bRet = true; - break; - default: break; - } - return bRet; -} - // ======================================================================= -void AquaSalGraphics::updateResolution() -{ - DBG_ASSERT( mbWindow, "updateResolution on inappropriate graphics" ); - - initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil ); -} - -void AquaSalGraphics::initResolution( NSWindow* ) -{ - // #i100617# read DPI only once; there is some kind of weird caching going on - // if the main screen changes - // FIXME: this is really unfortunate and needs to be investigated - - SalData* pSalData = GetSalData(); - if( pSalData->mnDPIX == 0 || pSalData->mnDPIY == 0 ) - { - NSScreen* pScreen = nil; - - /* #i91301# - many woes went into the try to have different resolutions - on different screens. The result of these trials is that OOo is not ready - for that yet, vcl and applications would need to be adapted. - - Unfortunately this is not possible in the 3.0 timeframe. - So let's stay with one resolution for all Windows and VirtualDevices - which is the resolution of the main screen - - This of course also means that measurements are exact only on the main screen. - For activating different resolutions again just comment out the two lines below. - - if( pWin ) - pScreen = [pWin screen]; - */ - if( pScreen == nil ) - { - NSArray* pScreens = [NSScreen screens]; - if( pScreens ) - pScreen = [pScreens objectAtIndex: 0]; - } - - mnRealDPIX = mnRealDPIY = 96; - if( pScreen ) - { - NSDictionary* pDev = [pScreen deviceDescription]; - if( pDev ) - { - NSNumber* pVal = [pDev objectForKey: @"NSScreenNumber"]; - if( pVal ) - { - // FIXME: casting a long to CGDirectDisplayID is evil, but - // Apple suggest to do it this way - const CGDirectDisplayID nDisplayID = (CGDirectDisplayID)[pVal longValue]; - const CGSize aSize = CGDisplayScreenSize( nDisplayID ); // => result is in millimeters - mnRealDPIX = static_cast<long>((CGDisplayPixelsWide( nDisplayID ) * 25.4) / aSize.width); - mnRealDPIY = static_cast<long>((CGDisplayPixelsHigh( nDisplayID ) * 25.4) / aSize.height); - } - else - { - OSL_FAIL( "no resolution found in device description" ); - } - } - else - { - OSL_FAIL( "no device description" ); - } - } - else - { - OSL_FAIL( "no screen found" ); - } - - // #i107076# maintaining size-WYSIWYG-ness causes many problems for - // low-DPI, high-DPI or for mis-reporting devices - // => it is better to limit the calculation result then - static const int nMinDPI = 72; - if( (mnRealDPIX < nMinDPI) || (mnRealDPIY < nMinDPI) ) - mnRealDPIX = mnRealDPIY = nMinDPI; - static const int nMaxDPI = 200; - if( (mnRealDPIX > nMaxDPI) || (mnRealDPIY > nMaxDPI) ) - mnRealDPIX = mnRealDPIY = nMaxDPI; - - // for OSX any anisotropy reported for the display resolution is best ignored (e.g. TripleHead2Go) - mnRealDPIX = mnRealDPIY = (mnRealDPIX + mnRealDPIY + 1) / 2; - - pSalData->mnDPIX = mnRealDPIX; - pSalData->mnDPIY = mnRealDPIY; - } - else - { - mnRealDPIX = pSalData->mnDPIX; - mnRealDPIY = pSalData->mnDPIY; - } - - mfFakeDPIScale = 1.0; -} - -void AquaSalGraphics::GetResolution( long& rDPIX, long& rDPIY ) -{ - if( !mnRealDPIY ) - initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil ); - - rDPIX = static_cast<long>(mfFakeDPIScale * mnRealDPIX); - rDPIY = static_cast<long>(mfFakeDPIScale * mnRealDPIY); -} - -void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics ) -{ - if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame ) - rGraphics.initResolution( rGraphics.mpFrame->mpWindow ); - - mnRealDPIX = rGraphics.mnRealDPIX; - mnRealDPIY = rGraphics.mnRealDPIY; - mfFakeDPIScale = rGraphics.mfFakeDPIScale; -} - -// ----------------------------------------------------------------------- - -sal_uInt16 AquaSalGraphics::GetBitCount() const -{ - sal_uInt16 nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24; - return nBits; -} - -// ----------------------------------------------------------------------- - -static const basegfx::B2DPoint aHalfPointOfs ( 0.5, 0.5 ); - -static void AddPolygonToPath( CGMutablePathRef xPath, - const ::basegfx::B2DPolygon& rPolygon, bool bClosePath, bool bPixelSnap, bool bLineDraw ) -{ - // short circuit if there is nothing to do - const int nPointCount = rPolygon.count(); - if( nPointCount <= 0 ) - return; - - (void)bPixelSnap; // TODO - const CGAffineTransform* pTransform = NULL; - - const bool bHasCurves = rPolygon.areControlPointsUsed(); - for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ ) - { - int nClosedIdx = nPointIdx; - if( nPointIdx >= nPointCount ) - { - // prepare to close last curve segment if needed - if( bClosePath && (nPointIdx == nPointCount) ) - nClosedIdx = 0; - else - break; - } - - ::basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx ); - - if( bPixelSnap) - { - // snap device coordinates to full pixels - aPoint.setX( basegfx::fround( aPoint.getX() ) ); - aPoint.setY( basegfx::fround( aPoint.getY() ) ); - } - - if( bLineDraw ) - aPoint += aHalfPointOfs; - - if( !nPointIdx ) { // first point => just move there - CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); - continue; - } - - bool bPendingCurve = false; - if( bHasCurves ) - { - bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx ); - bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx ); - } - - if( !bPendingCurve ) // line segment - CGPathAddLineToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); - else // cubic bezier segment - { - basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx ); - basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx ); - if( bLineDraw ) - { - aCP1 += aHalfPointOfs; - aCP2 += aHalfPointOfs; - } - CGPathAddCurveToPoint( xPath, pTransform, aCP1.getX(), aCP1.getY(), - aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() ); - } - } - - if( bClosePath ) - CGPathCloseSubpath( xPath ); -} - -static void AddPolyPolygonToPath( CGMutablePathRef xPath, - const ::basegfx::B2DPolyPolygon& rPolyPoly, bool bPixelSnap, bool bLineDraw ) -{ - // short circuit if there is nothing to do - const int nPolyCount = rPolyPoly.count(); - if( nPolyCount <= 0 ) - return; - - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx ); - AddPolygonToPath( xPath, rPolygon, true, bPixelSnap, bLineDraw ); - } -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::ResetClipRegion() -{ - // release old path and indicate no clipping - if( mxClipPath ) - { - CGPathRelease( mxClipPath ); - mxClipPath = NULL; - } - if( CheckContext() ) - SetState(); -} - -// ----------------------------------------------------------------------- - -bool AquaSalGraphics::setClipRegion( const Region& i_rClip ) -{ - // release old clip path - if( mxClipPath ) - { - CGPathRelease( mxClipPath ); - mxClipPath = NULL; - } - mxClipPath = CGPathCreateMutable(); - - // set current path, either as polypolgon or sequence of rectangles - if( i_rClip.HasPolyPolygon() ) - { - basegfx::B2DPolyPolygon aClip( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() ); - AddPolyPolygonToPath( mxClipPath, aClip, !getAntiAliasB2DDraw(), false ); - } - else - { - long nX, nY, nW, nH; - ImplRegionInfo aInfo; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) - { - if( nW && nH ) - { - CGRect aRect = {{nX,nY}, {nW,nH}}; - CGPathAddRect( mxClipPath, NULL, aRect ); - } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); - } - } - // set the current path as clip region - if( CheckContext() ) - SetState(); - return true; -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::SetLineColor() -{ - maLineColor.SetAlpha( 0.0 ); // transparent - if( CheckContext() ) - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::SetLineColor( SalColor nSalColor ) -{ - maLineColor = RGBAColor( nSalColor ); - if( CheckContext() ) - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::SetFillColor() -{ - maFillColor.SetAlpha( 0.0 ); // transparent - if( CheckContext() ) - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::SetFillColor( SalColor nSalColor ) -{ - maFillColor = RGBAColor( nSalColor ); - if( CheckContext() ) - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -static SalColor ImplGetROPSalColor( SalROPColor nROPColor ) -{ - SalColor nSalColor; - if ( nROPColor == SAL_ROP_0 ) - nSalColor = MAKE_SALCOLOR( 0, 0, 0 ); - else - nSalColor = MAKE_SALCOLOR( 255, 255, 255 ); - return nSalColor; -} - -void AquaSalGraphics::SetROPLineColor( SalROPColor nROPColor ) -{ - if( ! mbPrinter ) - SetLineColor( ImplGetROPSalColor( nROPColor ) ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::SetROPFillColor( SalROPColor nROPColor ) -{ - if( ! mbPrinter ) - SetFillColor( ImplGetROPSalColor( nROPColor ) ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::ImplDrawPixel( long nX, long nY, const RGBAColor& rColor ) -{ - if( !CheckContext() ) - return; - - // overwrite the fill color - CGContextSetFillColor( mrContext, rColor.AsArray() ); - // draw 1x1 rect, there is no pixel drawing in Quartz - CGRect aDstRect = {{nX,nY,},{1,1}}; - CGContextFillRect( mrContext, aDstRect ); - RefreshRect( aDstRect ); - // reset the fill color - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); -} - -void AquaSalGraphics::drawPixel( long nX, long nY ) -{ - // draw pixel with current line color - ImplDrawPixel( nX, nY, maLineColor ); -} - -void AquaSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) -{ - const RGBAColor aPixelColor( nSalColor ); - ImplDrawPixel( nX, nY, aPixelColor ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) -{ - if( nX1 == nX2 && nY1 == nY2 ) - { - // #i109453# platform independent code expects at least one pixel to be drawn - drawPixel( nX1, nY1 ); - return; - } - - if( !CheckContext() ) - return; - - CGContextBeginPath( mrContext ); - CGContextMoveToPoint( mrContext, static_cast<float>(nX1)+0.5, static_cast<float>(nY1)+0.5 ); - CGContextAddLineToPoint( mrContext, static_cast<float>(nX2)+0.5, static_cast<float>(nY2)+0.5 ); - CGContextDrawPath( mrContext, kCGPathStroke ); - - Rectangle aRefreshRect( nX1, nY1, nX2, nY2 ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) -{ - if( !CheckContext() ) - return; - - CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) ); - if( IsPenVisible() ) - { - aRect.origin.x += 0.5; - aRect.origin.y += 0.5; - aRect.size.width -= 1; - aRect.size.height -= 1; - } - - if( IsBrushVisible() ) - CGContextFillRect( mrContext, aRect ); - - if( IsPenVisible() ) - CGContextStrokeRect( mrContext, aRect ); - - RefreshRect( nX, nY, nWidth, nHeight ); -} - -// ----------------------------------------------------------------------- - -static void getBoundRect( sal_uLong nPoints, const SalPoint *pPtAry, long &rX, long& rY, long& rWidth, long& rHeight ) -{ - long nX1 = pPtAry->mnX; - long nX2 = nX1; - long nY1 = pPtAry->mnY; - long nY2 = nY1; - for( sal_uLong n = 1; n < nPoints; n++ ) - { - if( pPtAry[n].mnX < nX1 ) - nX1 = pPtAry[n].mnX; - else if( pPtAry[n].mnX > nX2 ) - nX2 = pPtAry[n].mnX; - - if( pPtAry[n].mnY < nY1 ) - nY1 = pPtAry[n].mnY; - else if( pPtAry[n].mnY > nY2 ) - nY2 = pPtAry[n].mnY; - } - rX = nX1; - rY = nY1; - rWidth = nX2 - nX1 + 1; - rHeight = nY2 - nY1 + 1; -} - -static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_fY ) -{ - o_fX = static_cast<float>(i_pIn->mnX ) + 0.5; - o_fY = static_cast<float>(i_pIn->mnY ) + 0.5; -} - -void AquaSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry ) -{ - if( nPoints < 1 ) - return; - if( !CheckContext() ) - return; - - long nX = 0, nY = 0, nWidth = 0, nHeight = 0; - getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight ); - - float fX, fY; - - CGContextBeginPath( mrContext ); - alignLinePoint( pPtAry, fX, fY ); - CGContextMoveToPoint( mrContext, fX, fY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - { - alignLinePoint( pPtAry, fX, fY ); - CGContextAddLineToPoint( mrContext, fX, fY ); - } - CGContextDrawPath( mrContext, kCGPathStroke ); - - RefreshRect( nX, nY, nWidth, nHeight ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint *pPtAry ) -{ - if( nPoints <= 1 ) - return; - if( !CheckContext() ) - return; - - long nX = 0, nY = 0, nWidth = 0, nHeight = 0; - getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight ); - - CGPathDrawingMode eMode; - if( IsBrushVisible() && IsPenVisible() ) - eMode = kCGPathEOFillStroke; - else if( IsPenVisible() ) - eMode = kCGPathStroke; - else if( IsBrushVisible() ) - eMode = kCGPathEOFill; - else - return; - - CGContextBeginPath( mrContext ); - - if( IsPenVisible() ) - { - float fX, fY; - alignLinePoint( pPtAry, fX, fY ); - CGContextMoveToPoint( mrContext, fX, fY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - { - alignLinePoint( pPtAry, fX, fY ); - CGContextAddLineToPoint( mrContext, fX, fY ); - } - } - else - { - CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - } - - CGContextDrawPath( mrContext, eMode ); - RefreshRect( nX, nY, nWidth, nHeight ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawPolyPolygon( sal_uLong nPolyCount, const sal_uLong *pPoints, PCONSTSALPOINT *ppPtAry ) -{ - if( nPolyCount <= 0 ) - return; - if( !CheckContext() ) - return; - - // find bound rect - long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0; - getBoundRect( pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight ); - for( sal_uLong n = 1; n < nPolyCount; n++ ) - { - long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight; - getBoundRect( pPoints[n], ppPtAry[n], nX, nY, nW, nH ); - if( nX < leftX ) - { - maxWidth += leftX - nX; - leftX = nX; - } - if( nY < topY ) - { - maxHeight += topY - nY; - topY = nY; - } - if( nX + nW > leftX + maxWidth ) - maxWidth = nX + nW - leftX; - if( nY + nH > topY + maxHeight ) - maxHeight = nY + nH - topY; - } - - // prepare drawing mode - CGPathDrawingMode eMode; - if( IsBrushVisible() && IsPenVisible() ) - eMode = kCGPathEOFillStroke; - else if( IsPenVisible() ) - eMode = kCGPathStroke; - else if( IsBrushVisible() ) - eMode = kCGPathEOFill; - else - return; - - // convert to CGPath - CGContextBeginPath( mrContext ); - if( IsPenVisible() ) - { - for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ ) - { - const sal_uLong nPoints = pPoints[nPoly]; - if( nPoints > 1 ) - { - const SalPoint *pPtAry = ppPtAry[nPoly]; - float fX, fY; - alignLinePoint( pPtAry, fX, fY ); - CGContextMoveToPoint( mrContext, fX, fY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - { - alignLinePoint( pPtAry, fX, fY ); - CGContextAddLineToPoint( mrContext, fX, fY ); - } - CGContextClosePath(mrContext); - } - } - } - else - { - for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ ) - { - const sal_uLong nPoints = pPoints[nPoly]; - if( nPoints > 1 ) - { - const SalPoint *pPtAry = ppPtAry[nPoly]; - CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - CGContextClosePath(mrContext); - } - } - } - - CGContextDrawPath( mrContext, eMode ); - - RefreshRect( leftX, topY, maxWidth, maxHeight ); -} - -// ----------------------------------------------------------------------- - -bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly, - double fTransparency ) -{ - // short circuit if there is nothing to do - const int nPolyCount = rPolyPoly.count(); - if( nPolyCount <= 0 ) - return true; - - // ignore invisible polygons - if( (fTransparency >= 1.0) || (fTransparency < 0) ) - return true; - - // setup poly-polygon path - CGMutablePathRef xPath = CGPathCreateMutable(); - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx ); - AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() ); - } - - const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); -#ifndef NO_I97317_WORKAROUND - // #i97317# workaround for Quartz having problems with drawing small polygons - if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) -#endif - { - // use the path to prepare the graphics context - CGContextSaveGState( mrContext ); - CGContextBeginPath( mrContext ); - CGContextAddPath( mrContext, xPath ); - - // draw path with antialiased polygon - CGContextSetShouldAntialias( mrContext, true ); - CGContextSetAlpha( mrContext, 1.0 - fTransparency ); - CGContextDrawPath( mrContext, kCGPathEOFillStroke ); - CGContextRestoreGState( mrContext ); - - // mark modified rectangle as updated - RefreshRect( aRefreshRect ); - } - - CGPathRelease( xPath ); - - return true; -} - -// ----------------------------------------------------------------------- - -bool AquaSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon& rPolyLine, - double fTransparency, - const ::basegfx::B2DVector& rLineWidths, - basegfx::B2DLineJoin eLineJoin ) -{ - // short circuit if there is nothing to do - const int nPointCount = rPolyLine.count(); - if( nPointCount <= 0 ) - return true; - - // reject requests that cannot be handled yet - if( rLineWidths.getX() != rLineWidths.getY() ) - return false; - - // #i101491# Aqua does not support B2DLINEJOIN_NONE; return false to use - // the fallback (own geometry preparation) - // #i104886# linejoin-mode and thus the above only applies to "fat" lines - if( (basegfx::B2DLINEJOIN_NONE == eLineJoin) - && (rLineWidths.getX() > 1.3) ) - return false; - - // setup line attributes - CGLineJoin aCGLineJoin = kCGLineJoinMiter; - switch( eLineJoin ) { - case ::basegfx::B2DLINEJOIN_NONE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break; - case ::basegfx::B2DLINEJOIN_MIDDLE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break; - case ::basegfx::B2DLINEJOIN_BEVEL: aCGLineJoin = kCGLineJoinBevel; break; - case ::basegfx::B2DLINEJOIN_MITER: aCGLineJoin = kCGLineJoinMiter; break; - case ::basegfx::B2DLINEJOIN_ROUND: aCGLineJoin = kCGLineJoinRound; break; - } - - // setup poly-polygon path - CGMutablePathRef xPath = CGPathCreateMutable(); - AddPolygonToPath( xPath, rPolyLine, rPolyLine.isClosed(), !getAntiAliasB2DDraw(), true ); - - const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); -#ifndef NO_I97317_WORKAROUND - // #i97317# workaround for Quartz having problems with drawing small polygons - if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) -#endif - { - // use the path to prepare the graphics context - CGContextSaveGState( mrContext ); - CGContextAddPath( mrContext, xPath ); - // draw path with antialiased line - CGContextSetShouldAntialias( mrContext, true ); - CGContextSetAlpha( mrContext, 1.0 - fTransparency ); - CGContextSetLineJoin( mrContext, aCGLineJoin ); - CGContextSetLineWidth( mrContext, rLineWidths.getX() ); - CGContextDrawPath( mrContext, kCGPathStroke ); - CGContextRestoreGState( mrContext ); - - // mark modified rectangle as updated - RefreshRect( aRefreshRect ); - } - - CGPathRelease( xPath ); - - return true; -} - -// ----------------------------------------------------------------------- - -sal_Bool AquaSalGraphics::drawPolyLineBezier( sal_uLong, const SalPoint*, const sal_uInt8* ) -{ - return sal_False; -} - -// ----------------------------------------------------------------------- - -sal_Bool AquaSalGraphics::drawPolygonBezier( sal_uLong, const SalPoint*, const sal_uInt8* ) -{ - return sal_False; -} - -// ----------------------------------------------------------------------- - -sal_Bool AquaSalGraphics::drawPolyPolygonBezier( sal_uLong, const sal_uLong*, - const SalPoint* const*, const sal_uInt8* const* ) -{ - return sal_False; -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::copyBits( const SalTwoRect *pPosAry, SalGraphics *pSrcGraphics ) -{ - if( !pSrcGraphics ) - pSrcGraphics = this; - - //from unix salgdi2.cxx - //[FIXME] find a better way to prevent calc from crashing when width and height are negative - if( pPosAry->mnSrcWidth <= 0 - || pPosAry->mnSrcHeight <= 0 - || pPosAry->mnDestWidth <= 0 - || pPosAry->mnDestHeight <= 0 ) - { - return; - } - - // accelerate trivial operations - /*const*/ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics); - const bool bSameGraphics = (this == pSrc) || (mbWindow && mpFrame && pSrc->mbWindow && (mpFrame == pSrc->mpFrame)); - if( bSameGraphics - && (pPosAry->mnSrcWidth == pPosAry->mnDestWidth) - && (pPosAry->mnSrcHeight == pPosAry->mnDestHeight)) - { - // short circuit if there is nothing to do - if( (pPosAry->mnSrcX == pPosAry->mnDestX) - && (pPosAry->mnSrcY == pPosAry->mnDestY)) - return; - // use copyArea() if source and destination context are identical - copyArea( pPosAry->mnDestX, pPosAry->mnDestY, pPosAry->mnSrcX, pPosAry->mnSrcY, - pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 0 ); - return; - } - - ApplyXorContext(); - pSrc->ApplyXorContext(); - - DBG_ASSERT( pSrc->mxLayer!=NULL, "AquaSalGraphics::copyBits() from non-layered graphics" ); - - const CGPoint aDstPoint = { +pPosAry->mnDestX - pPosAry->mnSrcX, pPosAry->mnDestY - pPosAry->mnSrcY }; - if( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth && pPosAry->mnSrcHeight == pPosAry->mnDestHeight) && - (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher - { - // in XOR mode the drawing context is redirected to the XOR mask - // if source and target are identical then copyBits() paints onto the target context though - CGContextRef xCopyContext = mrContext; - if( mpXorEmulation && mpXorEmulation->IsEnabled() ) - if( pSrcGraphics == this ) - xCopyContext = mpXorEmulation->GetTargetContext(); - - CGContextSaveGState( xCopyContext ); - const CGRect aDstRect = { {pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight} }; - CGContextClipToRect( xCopyContext, aDstRect ); - - // draw at new destination - // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down - if( pSrc->IsFlipped() ) - { CGContextTranslateCTM( xCopyContext, 0, +mnHeight ); CGContextScaleCTM( xCopyContext, +1, -1 ); } - // TODO: pSrc->size() != this->size() - ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, pSrc->mxLayer ); - CGContextRestoreGState( xCopyContext ); - // mark the destination rectangle as updated - RefreshRect( aDstRect ); - } - else - { - SalBitmap* pBitmap = pSrc->getBitmap( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ); - - if( pBitmap ) - { - SalTwoRect aPosAry( *pPosAry ); - aPosAry.mnSrcX = 0; - aPosAry.mnSrcY = 0; - drawBitmap( &aPosAry, *pBitmap ); - delete pBitmap; - } - } -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::copyArea( long nDstX, long nDstY,long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, sal_uInt16 /*nFlags*/ ) -{ - ApplyXorContext(); - - DBG_ASSERT( mxLayer!=NULL, "AquaSalGraphics::copyArea() for non-layered graphics" ); - - // in XOR mode the drawing context is redirected to the XOR mask - // copyArea() always works on the target context though - CGContextRef xCopyContext = mrContext; - if( mpXorEmulation && mpXorEmulation->IsEnabled() ) - xCopyContext = mpXorEmulation->GetTargetContext(); - - // drawing a layer onto its own context causes trouble on OSX => copy it first - // TODO: is it possible to get rid of this unneeded copy more often? - // e.g. on OSX>=10.5 only this situation causes problems: - // mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth - CGLayerRef xSrcLayer = mxLayer; - // TODO: if( mnBitmapDepth > 0 ) - { - const CGSize aSrcSize = { nSrcWidth, nSrcHeight }; - xSrcLayer = ::CGLayerCreateWithContext( xCopyContext, aSrcSize, NULL ); - const CGContextRef xSrcContext = CGLayerGetContext( xSrcLayer ); - CGPoint aSrcPoint = { -nSrcX, -nSrcY }; - if( IsFlipped() ) - { - ::CGContextTranslateCTM( xSrcContext, 0, +nSrcHeight ); - ::CGContextScaleCTM( xSrcContext, +1, -1 ); - aSrcPoint.y = (nSrcY + nSrcHeight) - mnHeight; - } - ::CGContextDrawLayerAtPoint( xSrcContext, aSrcPoint, mxLayer ); - } - - // draw at new destination - const CGPoint aDstPoint = { +nDstX, +nDstY }; - ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, xSrcLayer ); - - // cleanup - if( xSrcLayer != mxLayer ) - CGLayerRelease( xSrcLayer ); - - // mark the destination rectangle as updated - RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight ); - -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ) -{ - if( !CheckContext() ) - return; - - const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap); - CGImageRef xImage = rBitmap.CreateCroppedImage( (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY, (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight ); - if( !xImage ) - return; - - const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xImage ); - CGImageRelease( xImage ); - RefreshRect( aDstRect ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap,SalColor ) -{ - OSL_FAIL("not implemented for color masking!"); - drawBitmap( pPosAry, rSalBitmap ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, const SalBitmap& rTransparentBitmap ) -{ - if( !CheckContext() ) - return; - - const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap); - const AquaSalBitmap& rMask = static_cast<const AquaSalBitmap&>(rTransparentBitmap); - CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) ); - if( !xMaskedImage ) - return; - - const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xMaskedImage ); - CGImageRelease( xMaskedImage ); - RefreshRect( aDstRect ); -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::drawMask( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, SalColor nMaskColor ) -{ - if( !CheckContext() ) - return; - - const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap); - CGImageRef xImage = rBitmap.CreateColorMask( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, nMaskColor ); - if( !xImage ) - return; - - const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xImage ); - CGImageRelease( xImage ); - RefreshRect( aDstRect ); -} - -// ----------------------------------------------------------------------- - -SalBitmap* AquaSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) -{ - DBG_ASSERT( mxLayer, "AquaSalGraphics::getBitmap() with no layer" ); - - ApplyXorContext(); - - AquaSalBitmap* pBitmap = new AquaSalBitmap; - if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY, !mbWindow ) ) - { - delete pBitmap; - pBitmap = NULL; - } - - return pBitmap; -} - -// ----------------------------------------------------------------------- - -SalColor AquaSalGraphics::getPixel( long nX, long nY ) -{ - // return default value on printers or when out of bounds - if( !mxLayer - || (nX < 0) || (nX >= mnWidth) - || (nY < 0) || (nY >= mnHeight)) - return COL_BLACK; - - // prepare creation of matching a CGBitmapContext - CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; - CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; -#if __BIG_ENDIAN__ - struct{ unsigned char b, g, r, a; } aPixel; -#else - struct{ unsigned char a, r, g, b; } aPixel; -#endif - - // create a one-pixel bitmap context - // TODO: is it worth to cache it? - CGContextRef xOnePixelContext = ::CGBitmapContextCreate( &aPixel, - 1, 1, 8, sizeof(aPixel), aCGColorSpace, aCGBmpInfo ); - - // update this graphics layer - ApplyXorContext(); - - // copy the requested pixel into the bitmap context - if( IsFlipped() ) - nY = mnHeight - nY; - const CGPoint aCGPoint = {-nX, -nY}; - CGContextDrawLayerAtPoint( xOnePixelContext, aCGPoint, mxLayer ); - CGContextRelease( xOnePixelContext ); - - SalColor nSalColor = MAKE_SALCOLOR( aPixel.r, aPixel.g, aPixel.b ); - return nSalColor; -} - -// ----------------------------------------------------------------------- - - -static void DrawPattern50( void*, CGContextRef rContext ) -{ - static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } }; - CGContextAddRects( rContext, aRects, 2 ); - CGContextFillPath( rContext ); -} - -void AquaSalGraphics::Pattern50Fill() -{ - static const float aFillCol[4] = { 1,1,1,1 }; - static const CGPatternCallbacks aCallback = { 0, &DrawPattern50, NULL }; - if( ! GetSalData()->mxP50Space ) - GetSalData()->mxP50Space = CGColorSpaceCreatePattern( GetSalData()->mxRGBSpace ); - if( ! GetSalData()->mxP50Pattern ) - GetSalData()->mxP50Pattern = CGPatternCreate( NULL, CGRectMake( 0, 0, 4, 4 ), - CGAffineTransformIdentity, 4, 4, - kCGPatternTilingConstantSpacing, - false, &aCallback ); - - CGContextSetFillColorSpace( mrContext, GetSalData()->mxP50Space ); - CGContextSetFillPattern( mrContext, GetSalData()->mxP50Pattern, aFillCol ); - CGContextFillPath( mrContext ); -} - -void AquaSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) -{ - if ( CheckContext() ) - { - CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight); - CGContextSaveGState(mrContext); - - if ( nFlags & SAL_INVERT_TRACKFRAME ) - { - const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 ); - CGContextSetLineDash ( mrContext, 0, dashLengths, 2 ); - CGContextSetLineWidth( mrContext, 2.0); - CGContextStrokeRect ( mrContext, aCGRect ); - } - else if ( nFlags & SAL_INVERT_50 ) - { - //CGContextSetAllowsAntialiasing( mrContext, false ); - CGContextSetBlendMode(mrContext, kCGBlendModeDifference); - CGContextAddRect( mrContext, aCGRect ); - Pattern50Fill(); - } - else // just invert - { - CGContextSetBlendMode(mrContext, kCGBlendModeDifference); - CGContextSetRGBFillColor ( mrContext,1.0, 1.0, 1.0 , 1.0 ); - CGContextFillRect ( mrContext, aCGRect ); - } - CGContextRestoreGState( mrContext); - RefreshRect( aCGRect ); - } -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nSalFlags ) -{ - CGPoint* CGpoints ; - if ( CheckContext() ) - { - CGContextSaveGState(mrContext); - CGpoints = makeCGptArray(nPoints,pPtAry); - CGContextAddLines ( mrContext, CGpoints, nPoints ); - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - { - const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 ); - CGContextSetLineDash ( mrContext, 0, dashLengths, 2 ); - CGContextSetLineWidth( mrContext, 2.0); - CGContextStrokePath ( mrContext ); - } - else if ( nSalFlags & SAL_INVERT_50 ) - { - CGContextSetBlendMode(mrContext, kCGBlendModeDifference); - Pattern50Fill(); - } - else // just invert - { - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - CGContextSetRGBFillColor( mrContext, 1.0, 1.0, 1.0, 1.0 ); - CGContextFillPath( mrContext ); - } - const CGRect aRefreshRect = CGContextGetClipBoundingBox(mrContext); - CGContextRestoreGState( mrContext); - delete [] CGpoints; - RefreshRect( aRefreshRect ); - } -} - -// ----------------------------------------------------------------------- - -sal_Bool AquaSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, - void* pEpsData, sal_uLong nByteCount ) -{ - // convert the raw data to an NSImageRef - NSData* xNSData = [NSData dataWithBytes:(void*)pEpsData length:(int)nByteCount]; - NSImageRep* xEpsImage = [NSEPSImageRep imageRepWithData: xNSData]; - if( !xEpsImage ) - return false; - - // get the target context - if( !CheckContext() ) - return false; - - // NOTE: flip drawing, else the nsimage would be drawn upside down - CGContextSaveGState( mrContext ); -// CGContextTranslateCTM( mrContext, 0, +mnHeight ); - CGContextScaleCTM( mrContext, +1, -1 ); - nY = /*mnHeight*/ - (nY + nHeight); - - // prepare the target context - NSGraphicsContext* pOrigNSCtx = [NSGraphicsContext currentContext]; - [pOrigNSCtx retain]; - - // create new context - NSGraphicsContext* pDrawNSCtx = [NSGraphicsContext graphicsContextWithGraphicsPort: mrContext flipped: IsFlipped()]; - // set it, setCurrentContext also releases the prviously set one - [NSGraphicsContext setCurrentContext: pDrawNSCtx]; - - // draw the EPS - const NSRect aDstRect = {{nX,nY},{nWidth,nHeight}}; - const BOOL bOK = [xEpsImage drawInRect: aDstRect]; - - // restore the NSGraphicsContext - [NSGraphicsContext setCurrentContext: pOrigNSCtx]; - [pOrigNSCtx release]; // restore the original retain count - - CGContextRestoreGState( mrContext ); - // mark the destination rectangle as updated - RefreshRect( aDstRect ); - - return bOK; -} - -// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, - const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp ) -{ - // An image mask can't have a depth > 8 bits (should be 1 to 8 bits) - if( rAlphaBmp.GetBitCount() > 8 ) - return false; - - // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx) - // horizontal/vertical mirroring not implemented yet - if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 ) - return false; - - const AquaSalBitmap& rSrcSalBmp = static_cast<const AquaSalBitmap&>(rSrcBitmap); - const AquaSalBitmap& rMaskSalBmp = static_cast<const AquaSalBitmap&>(rAlphaBmp); - - CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask( rMaskSalBmp, rTR.mnSrcX, rTR.mnSrcY, rTR.mnSrcWidth, rTR.mnSrcHeight ); - if( !xMaskedImage ) - return false; - - if ( CheckContext() ) - { - const CGRect aDstRect = {{rTR.mnDestX, rTR.mnDestY}, {rTR.mnDestWidth, rTR.mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xMaskedImage ); - RefreshRect( aDstRect ); - } - - CGImageRelease(xMaskedImage); - return true; -} - -// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -bool AquaSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, - long nHeight, sal_uInt8 nTransparency ) -{ - if( !CheckContext() ) - return true; - - // save the current state - CGContextSaveGState( mrContext ); - CGContextSetAlpha( mrContext, (100-nTransparency) * (1.0/100) ); - - CGRect aRect = {{nX,nY},{nWidth-1,nHeight-1}}; - if( IsPenVisible() ) - { - aRect.origin.x += 0.5; - aRect.origin.y += 0.5; - } - - CGContextBeginPath( mrContext ); - CGContextAddRect( mrContext, aRect ); - CGContextDrawPath( mrContext, kCGPathFill ); - - // restore state - CGContextRestoreGState(mrContext); - RefreshRect( aRect ); - return true; -} - -// ----------------------------------------------------------------------- - void AquaSalGraphics::SetTextColor( SalColor nSalColor ) { RGBColor color; @@ -1831,25 +638,6 @@ sal_Bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPol // ----------------------------------------------------------------------- -long AquaSalGraphics::GetGraphicsWidth() const -{ - long w = 0; - if( mrContext && (mbWindow || mbVirDev) ) - { - w = mnWidth; - } - - if( w == 0 ) - { - if( mbWindow && mpFrame ) - w = mpFrame->maGeometry.nWidth; - } - - return w; -} - -// ----------------------------------------------------------------------- - sal_Bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect ) { ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback @@ -2062,8 +850,8 @@ static void FakeDirEntry( FourCharCode eFCC, ByteCount nOfs, ByteCount nLen, rpDest += 16; } -static bool GetRawFontData( const ImplFontData* pFontData, - ByteVector& rBuffer, bool* pJustCFF ) +bool AquaSalGraphics::GetRawFontData( const ImplFontData* pFontData, + ByteVector& rBuffer, bool* pJustCFF ) { const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData); const ATSUFontID nFontId = static_cast<ATSUFontID>(pMacFont->GetFontId()); @@ -2211,139 +999,6 @@ static bool GetRawFontData( const ImplFontData* pFontData, return sal_True; } -sal_Bool AquaSalGraphics::CreateFontSubset( const rtl::OUString& rToFile, - const ImplFontData* pFontData, long* pGlyphIDs, sal_uInt8* pEncoding, - sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo ) -{ - // TODO: move more of the functionality here into the generic subsetter code - - // prepare the requested file name for writing the font-subset file - rtl::OUString aSysPath; - if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) ) - return sal_False; - const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding(); - const rtl::OString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) ); - - // get the raw-bytes from the font to be subset - ByteVector aBuffer; - bool bCffOnly = false; - if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) ) - return sal_False; - - // handle CFF-subsetting - if( bCffOnly ) - { - // provide the raw-CFF data to the subsetter - ByteCount nCffLen = aBuffer.size(); - rInfo.LoadFont( FontSubsetInfo::CFF_FONT, &aBuffer[0], nCffLen ); - - // NOTE: assuming that all glyphids requested on Aqua are fully translated - - // make the subsetter provide the requested subset - FILE* pOutFile = fopen( aToFile.getStr(), "wb" ); - bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL, - pGlyphIDs, pEncoding, nGlyphCount, pGlyphWidths ); - fclose( pOutFile ); - return bRC; - } - - // TODO: modernize psprint's horrible fontsubset C-API - // this probably only makes sense after the switch to another SCM - // that can preserve change history after file renames - - // prepare data for psprint's font subsetter - TrueTypeFont* pSftFont = NULL; - int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont); - if( nRC != SF_OK ) - return sal_False; - - // get details about the subsetted font - TTGlobalFontInfo aTTInfo; - ::GetTTGlobalFontInfo( pSftFont, &aTTInfo ); - rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; - rInfo.m_aPSName = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 ); - rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ), - Point( aTTInfo.xMax, aTTInfo.yMax ) ); - rInfo.m_nCapHeight = aTTInfo.yMax; // Well ... - rInfo.m_nAscent = aTTInfo.winAscent; - rInfo.m_nDescent = aTTInfo.winDescent; - // mac fonts usually do not have an OS2-table - // => get valid ascent/descent values from other tables - if( !rInfo.m_nAscent ) - rInfo.m_nAscent = +aTTInfo.typoAscender; - if( !rInfo.m_nAscent ) - rInfo.m_nAscent = +aTTInfo.ascender; - if( !rInfo.m_nDescent ) - rInfo.m_nDescent = +aTTInfo.typoDescender; - if( !rInfo.m_nDescent ) - rInfo.m_nDescent = -aTTInfo.descender; - - // subset glyphs and get their properties - // take care that subset fonts require the NotDef glyph in pos 0 - int nOrigCount = nGlyphCount; - sal_uInt16 aShortIDs[ 256 ]; - sal_uInt8 aTempEncs[ 256 ]; - - int nNotDef = -1; - for( int i = 0; i < nGlyphCount; ++i ) - { - aTempEncs[i] = pEncoding[i]; - sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; - if( pGlyphIDs[i] & GF_ISCHAR ) - { - bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0; - nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical ); - if( nGlyphIdx == 0 && pFontData->IsSymbolFont() ) - { - // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX - nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; - nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 ); - nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical ); - } - } - aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx ); - if( !nGlyphIdx ) - if( nNotDef < 0 ) - nNotDef = i; // first NotDef glyph found - } - - if( nNotDef != 0 ) - { - // add fake NotDef glyph if needed - if( nNotDef < 0 ) - nNotDef = nGlyphCount++; - - // NotDef glyph must be in pos 0 => swap glyphids - aShortIDs[ nNotDef ] = aShortIDs[0]; - aTempEncs[ nNotDef ] = aTempEncs[0]; - aShortIDs[0] = 0; - aTempEncs[0] = 0; - } - DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" ); - - // TODO: where to get bVertical? - const bool bVertical = false; - - // fill the pGlyphWidths array - // while making sure that the NotDef glyph is at index==0 - TTSimpleGlyphMetrics* pGlyphMetrics = - ::GetTTSimpleGlyphMetrics( pSftFont, aShortIDs, nGlyphCount, bVertical ); - if( !pGlyphMetrics ) - return sal_False; - sal_uInt16 nNotDefAdv = pGlyphMetrics[0].adv; - pGlyphMetrics[0].adv = pGlyphMetrics[nNotDef].adv; - pGlyphMetrics[nNotDef].adv = nNotDefAdv; - for( int i = 0; i < nOrigCount; ++i ) - pGlyphWidths[i] = pGlyphMetrics[i].adv; - free( pGlyphMetrics ); - - // write subset into destination file - nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.getStr(), aShortIDs, - aTempEncs, nGlyphCount, 0, NULL, 0 ); - ::CloseTTFont(pSftFont); - return (nRC == SF_OK); -} - // ----------------------------------------------------------------------- void AquaSalGraphics::GetGlyphWidths( const ImplFontData* pFontData, bool bVertical, @@ -2483,226 +1138,5 @@ SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const // ----------------------------------------------------------------------- -SystemGraphicsData AquaSalGraphics::GetGraphicsData() const -{ - SystemGraphicsData aRes; - aRes.nSize = sizeof(aRes); - aRes.rCGContext = mrContext; - return aRes; -} - -// ----------------------------------------------------------------------- - -void AquaSalGraphics::SetXORMode( bool bSet, bool bInvertOnly ) -{ - // return early if XOR mode remains unchanged - if( mbPrinter ) - return; - - if( ! bSet && mnXorMode == 2 ) - { - CGContextSetBlendMode( mrContext, kCGBlendModeNormal ); - mnXorMode = 0; - return; - } - else if( bSet && bInvertOnly && mnXorMode == 0) - { - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - mnXorMode = 2; - return; - } - - if( (mpXorEmulation == NULL) && !bSet ) - return; - if( (mpXorEmulation != NULL) && (bSet == mpXorEmulation->IsEnabled()) ) - return; - if( !CheckContext() ) - return; - - // prepare XOR emulation - if( !mpXorEmulation ) - { - mpXorEmulation = new XorEmulation(); - mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer ); - } - - // change the XOR mode - if( bSet ) - { - mpXorEmulation->Enable(); - mrContext = mpXorEmulation->GetMaskContext(); - mnXorMode = 1; - } - else - { - mpXorEmulation->UpdateTarget(); - mpXorEmulation->Disable(); - mrContext = mpXorEmulation->GetTargetContext(); - mnXorMode = 0; - } -} - -// ----------------------------------------------------------------------- - -// apply the XOR mask to the target context if active and dirty -void AquaSalGraphics::ApplyXorContext() -{ - if( !mpXorEmulation ) - return; - if( mpXorEmulation->UpdateTarget() ) - RefreshRect( 0, 0, mnWidth, mnHeight ); // TODO: refresh minimal changerect -} - -// ====================================================================== - -XorEmulation::XorEmulation() -: mxTargetLayer( NULL ) -, mxTargetContext( NULL ) -, mxMaskContext( NULL ) -, mxTempContext( NULL ) -, mpMaskBuffer( NULL ) -, mpTempBuffer( NULL ) -, mnBufferLongs( 0 ) -, mbIsEnabled( false ) -{} - -// ---------------------------------------------------------------------- - -XorEmulation::~XorEmulation() -{ - Disable(); - SetTarget( 0, 0, 0, NULL, NULL ); -} - -// ----------------------------------------------------------------------- - -void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth, - CGContextRef xTargetContext, CGLayerRef xTargetLayer ) -{ - // prepare to replace old mask+temp context - if( mxMaskContext ) - { - // cleanup the mask context - CGContextRelease( mxMaskContext ); - delete[] mpMaskBuffer; - mxMaskContext = NULL; - mpMaskBuffer = NULL; - - // cleanup the temp context if needed - if( mxTempContext ) - { - CGContextRelease( mxTempContext ); - delete[] mpTempBuffer; - mxTempContext = NULL; - mpTempBuffer = NULL; - } - } - - // return early if there is nothing more to do - if( !xTargetContext ) - return; - - // retarget drawing operations to the XOR mask - mxTargetLayer = xTargetLayer; - mxTargetContext = xTargetContext; - - // prepare creation of matching CGBitmaps - CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; - CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst; - int nBitDepth = nTargetDepth; - if( !nBitDepth ) - nBitDepth = 32; - int nBytesPerRow = (nBitDepth == 16) ? 2 : 4; - const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8; - if( nBitDepth <= 8 ) - { - aCGColorSpace = GetSalData()->mxGraySpace; - aCGBmpInfo = kCGImageAlphaNone; - nBytesPerRow = 1; - } - nBytesPerRow *= nWidth; - mnBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / sizeof(sal_uLong); - - // create a XorMask context - mpMaskBuffer = new sal_uLong[ mnBufferLongs ]; - mxMaskContext = ::CGBitmapContextCreate( mpMaskBuffer, - nWidth, nHeight, nBitsPerComponent, nBytesPerRow, - aCGColorSpace, aCGBmpInfo ); - // reset the XOR mask to black - memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(sal_uLong) ); - - // a bitmap context will be needed for manual XORing - // create one unless the target context is a bitmap context - if( nTargetDepth ) - mpTempBuffer = (sal_uLong*)CGBitmapContextGetData( mxTargetContext ); - if( !mpTempBuffer ) - { - // create a bitmap context matching to the target context - mpTempBuffer = new sal_uLong[ mnBufferLongs ]; - mxTempContext = ::CGBitmapContextCreate( mpTempBuffer, - nWidth, nHeight, nBitsPerComponent, nBytesPerRow, - aCGColorSpace, aCGBmpInfo ); - } - - // initialize XOR mask context for drawing - CGContextSetFillColorSpace( mxMaskContext, aCGColorSpace ); - CGContextSetStrokeColorSpace( mxMaskContext, aCGColorSpace ); - CGContextSetShouldAntialias( mxMaskContext, false ); - - // improve the XorMask's XOR emulation a litte - // NOTE: currently only enabled for monochrome contexts - if( aCGColorSpace == GetSalData()->mxGraySpace ) - CGContextSetBlendMode( mxMaskContext, kCGBlendModeDifference ); - - // intialize the transformation matrix to the drawing target - const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext ); - CGContextConcatCTM( mxMaskContext, aCTM ); - if( mxTempContext ) - CGContextConcatCTM( mxTempContext, aCTM ); - - // initialize the default XorMask graphics state - CGContextSaveGState( mxMaskContext ); -} - -// ---------------------------------------------------------------------- - -bool XorEmulation::UpdateTarget() -{ - if( !IsEnabled() ) - return false; - - // update the temp bitmap buffer if needed - if( mxTempContext ) - CGContextDrawLayerAtPoint( mxTempContext, CGPointZero, mxTargetLayer ); - - // do a manual XOR with the XorMask - // this approach suffices for simple color manipulations - // and also the complex-clipping-XOR-trick used in metafiles - const sal_uLong* pSrc = mpMaskBuffer; - sal_uLong* pDst = mpTempBuffer; - for( int i = mnBufferLongs; --i >= 0;) - *(pDst++) ^= *(pSrc++); - - // write back the XOR results to the target context - if( mxTempContext ) - { - CGImageRef xXorImage = CGBitmapContextCreateImage( mxTempContext ); - const int nWidth = (int)CGImageGetWidth( xXorImage ); - const int nHeight = (int)CGImageGetHeight( xXorImage ); - // TODO: update minimal changerect - const CGRect aFullRect = {{0,0},{nWidth,nHeight}}; - CGContextDrawImage( mxTargetContext, aFullRect, xXorImage ); - CGImageRelease( xXorImage ); - } - - // reset the XorMask to black again - // TODO: not needed for last update - memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(sal_uLong) ); - - // TODO: return FALSE if target was not changed - return true; -} - -// ======================================================================= /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |