Kaydet (Commit) 9153a36b authored tarafından Chris Sherlock's avatar Chris Sherlock

fdo#74702 Refactor OutputDevice::DrawTransparent()

I have refactored OutputDevice::DrawTransparent() - functionality
is now in the functions DrawInvisiblePolygon(),
DrawTransparentNatively() and EmulateDrawTransparent().

DrawTransparentNatively() will return true if it is successful,
otherwise it will return false if it isn't possible to draw the
transparency natively. This allows us to fall back to a VCL based
emulation.

The function EmulateDrawTransparent() is virtual because Printer
handles transparencies differently to pixel based devices.

Change-Id: I300850ccea03c17673666dadd287bcddd40ec5ef
Reviewed-on: https://gerrit.libreoffice.org/8779Reviewed-by: 's avatarChris Sherlock <chris.sherlock79@gmail.com>
Tested-by: 's avatarChris Sherlock <chris.sherlock79@gmail.com>
üst bb20d370
......@@ -805,6 +805,7 @@ protected:
const Point& rSrcPtPixel, const Size& rSrcSizePixel );
virtual long ImplGetGradientStepCount( long nMinRect );
/** Transform and draw a bitmap directly
@param aFullTransform The B2DHomMatrix used for the transformation
......@@ -839,6 +840,8 @@ protected:
const Point& rSrcPtPixel, const Size& rSrcSizePixel,
BitmapEx& rBitmapEx );
virtual void EmulateDrawTransparent( const PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent );
void DrawInvisiblePolygon( const PolyPolygon& rPolyPoly );
private:
typedef void ( OutputDevice::* FontUpdateHandler_t )( bool );
......@@ -854,6 +857,8 @@ private:
// not implemented; to detect misuses of DrawOutDev(...OutputDevice&);
void DrawOutDev( const Point&, const Size&, const Point&, const Size&, const Printer&);
bool DrawTransparentNatively( const PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent );
public:
virtual ~OutputDevice();
......
......@@ -286,6 +286,7 @@ protected:
virtual void ImplPrintMask ( const Bitmap& rMask, const Color& rMaskColor,
const Point& rDestPt, const Size& rDestSize,
const Point& rSrcPtPixel, const Size& rSrcSizePixel ) SAL_OVERRIDE;
bool DrawTransformBitmapExDirect(
const basegfx::B2DHomMatrix& aFullTransform,
const BitmapEx& rBitmapEx) SAL_OVERRIDE;
......@@ -300,6 +301,8 @@ protected:
const Point& rSrcPtPixel, const Size& rSrcSizePixel,
BitmapEx& rBitmapEx ) SAL_OVERRIDE;
virtual void EmulateDrawTransparent( const PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent ) SAL_OVERRIDE;
public:
Printer();
Printer( const JobSetup& rJobSetup );
......
......@@ -183,7 +183,6 @@ void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, sal_uLon
void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency)
{
// AW: Do NOT paint empty PolyPolygons
if(!rB2DPolyPoly.count())
return;
......@@ -241,51 +240,27 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly,
DrawTransparent(toPolyPolygon(rB2DPolyPoly), static_cast<sal_uInt16>(fTransparency * 100.0));
}
void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
sal_uInt16 nTransparencePercent )
void OutputDevice::DrawInvisiblePolygon( const PolyPolygon& rPolyPoly )
{
// short circuit for drawing an opaque polygon
if( (nTransparencePercent < 1) || ((mnDrawMode & DRAWMODE_NOTRANSPARENCY) != 0) )
{
DrawPolyPolygon( rPolyPoly );
return;
}
// short circuit for drawing an invisible polygon
if( !mbFillColor || (nTransparencePercent >= 100) )
{
// short circuit if the polygon border is invisible too
if( !mbLineColor )
return;
// DrawTransparent() assumes that the border is NOT to be drawn transparently???
// we assume that the border is NOT to be drawn transparently???
Push( PUSH_FILLCOLOR );
SetFillColor();
DrawPolyPolygon( rPolyPoly );
Pop();
return;
}
// handle metafile recording
if( mpMetaFile )
mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
if( bDrawn )
return;
}
// get the device graphics as drawing target
if( !mpGraphics )
if( !ImplGetGraphics() )
return;
bool OutputDevice::DrawTransparentNatively ( const PolyPolygon& rPolyPoly,
sal_uInt16 nTransparencePercent )
{
bool bDrawn = false;
// debug helper:
static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
// try hard to draw it directly, because the emulation layers are slower
if( !pDisableNative
&& mpGraphics->supportsOperation( OutDevSupport_B2DDraw )
// Should iOS be included? Android? Or does this code even get invoked
......@@ -303,7 +278,7 @@ void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
if( mbInitClipRegion )
ImplInitClipRegion();
if( mbOutputClipped )
return;
return false;
if( mbInitLineColor )
ImplInitLineColor();
if( mbInitFillColor )
......@@ -345,12 +320,18 @@ void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
}
}
if( bDrawn )
return;
return bDrawn;
}
VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
void OutputDevice::EmulateDrawTransparent ( const PolyPolygon& rPolyPoly,
sal_uInt16 nTransparencePercent )
{
// debug helper:
static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
// #110958# Disable alpha VDev, we perform the necessary
VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
// operation explicitly further below.
if( mpAlphaVDev )
mpAlphaVDev = NULL;
......@@ -358,63 +339,6 @@ void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
GDIMetaFile* pOldMetaFile = mpMetaFile;
mpMetaFile = NULL;
if( OUTDEV_PRINTER == meOutDevType )
{
Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
const Size aDPISize( LogicToPixel( Size( 1, 1 ), MAP_INCH ) );
const long nBaseExtent = std::max( FRound( aDPISize.Width() / 300. ), 1L );
long nMove;
const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 :
( nTransparencePercent < 38 ) ? 25 :
( nTransparencePercent < 63 ) ? 50 :
( nTransparencePercent < 88 ) ? 75 : 100;
switch( nTrans )
{
case( 25 ): nMove = nBaseExtent * 3; break;
case( 50 ): nMove = nBaseExtent * 4; break;
case( 75 ): nMove = nBaseExtent * 6; break;
// #i112959# very transparent (88 < nTransparencePercent <= 99)
case( 100 ): nMove = nBaseExtent * 8; break;
// #i112959# not transparent (nTransparencePercent < 13)
default: nMove = 0; break;
}
Push( PUSH_CLIPREGION | PUSH_LINECOLOR );
IntersectClipRegion(Region(rPolyPoly));
SetLineColor( GetFillColor() );
const bool bOldMap = mbMap;
EnableMapMode( false );
if(nMove)
{
Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
while( aRect.Top() <= aPolyRect.Bottom() )
{
DrawRect( aRect );
aRect.Move( 0, nMove );
}
aRect = Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
while( aRect.Left() <= aPolyRect.Right() )
{
DrawRect( aRect );
aRect.Move( nMove, 0 );
}
}
else
{
// #i112959# if not transparent, draw full rectangle in clip region
DrawRect( aPolyRect );
}
EnableMapMode( bOldMap );
Pop();
}
else
{
PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
Rectangle aPolyRect( aPolyPoly.GetBoundRect() );
Point aPoint;
......@@ -432,6 +356,8 @@ void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
if( !aDstRect.IsEmpty() )
{
bool bDrawn = false;
// #i66849# Added fast path for exactly rectangular
// polygons
// #i83087# Naturally, system alpha blending cannot
......@@ -615,12 +541,48 @@ void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
DrawPolyPolygon( rPolyPoly );
}
}
}
mpMetaFile = pOldMetaFile;
// #110958# Restore disabled alpha VDev
mpAlphaVDev = pOldAlphaVDev;
}
void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
sal_uInt16 nTransparencePercent )
{
// short circuit for drawing an opaque polygon
if( (nTransparencePercent < 1) || ((mnDrawMode & DRAWMODE_NOTRANSPARENCY) != 0) )
{
DrawPolyPolygon( rPolyPoly );
return;
}
// short circuit for drawing an invisible polygon
if( !mbFillColor || (nTransparencePercent >= 100) )
{
DrawInvisiblePolygon( rPolyPoly );
}
// handle metafile recording
if( mpMetaFile )
mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
if( bDrawn )
return;
// get the device graphics as drawing target
if( !mpGraphics )
if( !ImplGetGraphics() )
return;
// try hard to draw it directly, because the emulation layers are slower
bDrawn = DrawTransparentNatively( rPolyPoly, nTransparencePercent );
if( bDrawn )
return;
EmulateDrawTransparent( rPolyPoly, nTransparencePercent );
// #110958# Apply alpha value also to VDev alpha channel
if( mpAlphaVDev )
......
......@@ -250,6 +250,85 @@ void Printer::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
}
}
void Printer::EmulateDrawTransparent ( const PolyPolygon& rPolyPoly,
sal_uInt16 nTransparencePercent )
{
// #110958# Disable alpha VDev, we perform the necessary
VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
// operation explicitly further below.
if( mpAlphaVDev )
mpAlphaVDev = NULL;
GDIMetaFile* pOldMetaFile = mpMetaFile;
mpMetaFile = NULL;
mpMetaFile = pOldMetaFile;
// #110958# Restore disabled alpha VDev
mpAlphaVDev = pOldAlphaVDev;
Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
const Size aDPISize( LogicToPixel( Size( 1, 1 ), MAP_INCH ) );
const long nBaseExtent = std::max( FRound( aDPISize.Width() / 300. ), 1L );
long nMove;
const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 :
( nTransparencePercent < 38 ) ? 25 :
( nTransparencePercent < 63 ) ? 50 :
( nTransparencePercent < 88 ) ? 75 : 100;
switch( nTrans )
{
case( 25 ): nMove = nBaseExtent * 3; break;
case( 50 ): nMove = nBaseExtent * 4; break;
case( 75 ): nMove = nBaseExtent * 6; break;
// #i112959# very transparent (88 < nTransparencePercent <= 99)
case( 100 ): nMove = nBaseExtent * 8; break;
// #i112959# not transparent (nTransparencePercent < 13)
default: nMove = 0; break;
}
Push( PUSH_CLIPREGION | PUSH_LINECOLOR );
IntersectClipRegion(Region(rPolyPoly));
SetLineColor( GetFillColor() );
const bool bOldMap = mbMap;
EnableMapMode( false );
if(nMove)
{
Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
while( aRect.Top() <= aPolyRect.Bottom() )
{
DrawRect( aRect );
aRect.Move( 0, nMove );
}
aRect = Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
while( aRect.Left() <= aPolyRect.Right() )
{
DrawRect( aRect );
aRect.Move( nMove, 0 );
}
}
else
{
// #i112959# if not transparent, draw full rectangle in clip region
DrawRect( aPolyRect );
}
EnableMapMode( bOldMap );
Pop();
mpMetaFile = pOldMetaFile;
// #110958# Restore disabled alpha VDev
mpAlphaVDev = pOldAlphaVDev;
}
void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ )
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment