summaryrefslogtreecommitdiff
path: root/cppcanvas/source/mtfrenderer/implrenderer.cxx
diff options
context:
space:
mode:
authorRĂ¼diger Timm <rt@openoffice.org>2004-11-26 19:54:32 +0000
committerRĂ¼diger Timm <rt@openoffice.org>2004-11-26 19:54:32 +0000
commit3ccf0dffc2c5dc668d47eb1e5e565a9e3f6db222 (patch)
tree8acd8d43e3c960c90d8ea58499cd0702090c772a /cppcanvas/source/mtfrenderer/implrenderer.cxx
parentfe2666e381ae24bd533e77a8daa6c495f5764f74 (diff)
INTEGRATION: CWS presentationengine01 (1.2.2); FILE MERGED
2004/11/21 22:05:09 thb 1.2.2.23: #110496# After merge, correctOrientations now returns result, no longer modifies passed parameter 2004/11/19 23:57:04 thb 1.2.2.22: #110496# Adapted to AW clipper changes 2004/11/08 05:56:07 thb 1.2.2.21: #i36093# Added native canvas gradients 2004/11/01 22:21:48 thb 1.2.2.20: #110496# Performance optimizations: added profiling traces 2004/10/26 12:39:17 thb 1.2.2.19: #110496# Setup default text color (in contrast to the line/fill color, OutDev inits that to default black) 2004/10/12 14:14:40 thb 1.2.2.18: #i34997# Added support for FLOATTRANSPARENCY meta action 2004/10/01 17:24:52 thb 1.2.2.17: #110496# Normalizing len attribute on text metaactions (might well be magic STRING_LEN, which is handled on VCL's OutputDevice, but not for our DX canvas, and means: simply take the length of the passed string argument) 2004/09/30 21:45:41 thb 1.2.2.16: #110496# Now handling clip meta actions correctly (were mostly ignored before) 2004/09/01 22:02:40 thb 1.2.2.15: #110496# Cosmetical changes, removed extraneous include; added two TODO comments 2004/08/31 15:06:53 hdu 1.2.2.14: #116716# enable text outline effect 2004/08/31 14:14:11 hdu 1.2.2.13: #116716# add text outline effect 2004/08/27 11:33:38 hdu 1.2.2.12: #116716# make gcc happy by replacing an unbalanced ternary expression 2004/08/23 19:15:49 thb 1.2.2.11: #110496# Added more overridable attributes (needed for slideshow attribute animations 2004/07/28 13:08:47 thb 1.2.2.10: #110496# Adapted to reversed template argument order in containerToSequence 2004/07/20 19:08:58 thb 1.2.2.9: #110496# Unified include statements; removed external prefix from boost includes 2004/07/09 09:50:51 hdu 1.2.2.8: #116716# more text effects and text lines 2004/06/03 14:18:46 thb 1.2.2.7: #110496# Fixed crash occuring when no font was set before text rendering 2004/05/27 20:51:28 thb 1.2.2.6: #110496# Added classification code to all TODO/HACK/FIXME comments. There are four categories: - code quality (C) - performance (P) - missing functionality (F) - and missing/incomplete error handling (E) Furthermore, every category has a severity number between 1 and 3 associated, where 1 is lowest and 3 highest severity 2004/05/11 15:19:31 hdu 1.2.2.5: #116716# add text effects and emphasis styles 2004/05/10 09:38:22 hdu 1.2.2.4: #116716# improve text handling 2004/04/21 18:49:39 thb 1.2.2.3: #110496# Added shape-global change functionality to Renderer interface 2004/04/12 15:13:20 thb 1.2.2.2: #110496# Adaptions after canvas01 merge 2004/04/05 15:58:47 thb 1.2.2.1: Resync with canvas01 changes
Diffstat (limited to 'cppcanvas/source/mtfrenderer/implrenderer.cxx')
-rw-r--r--cppcanvas/source/mtfrenderer/implrenderer.cxx1536
1 files changed, 1290 insertions, 246 deletions
diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx
index f3f50c2e9139..07656124a9c3 100644
--- a/cppcanvas/source/mtfrenderer/implrenderer.cxx
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -2,9 +2,9 @@
*
* $RCSfile: implrenderer.cxx,v $
*
- * $Revision: 1.2 $
+ * $Revision: 1.3 $
*
- * last change: $Author: thb $ $Date: 2004-03-18 10:41:04 $
+ * last change: $Author: rt $ $Date: 2004-11-26 20:54:32 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
@@ -59,6 +59,9 @@
*
************************************************************************/
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif
@@ -69,32 +72,59 @@
#include <vcl/svapp.hxx>
#endif
+#ifndef _RTL_LOGFILE_HXX_
+#include <rtl/logfile.hxx>
+#endif
+
#ifndef _COMPHELPER_SEQUENCE_HXX_
#include <comphelper/sequence.hxx>
#endif
#include <cppcanvas/canvas.hxx>
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XGRAPHICDEVICE_HPP_
+#include <drafts/com/sun/star/rendering/XGraphicDevice.hpp>
+#endif
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_TEXTURINGMODE_HPP_
+#include <drafts/com/sun/star/rendering/TexturingMode.hpp>
+#endif
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XPARAMETRICPOLYPOLYGON2DFACTORY_HPP_
+#include <drafts/com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
+#endif
+
#ifndef _VCL_CANVASTOOLS_HXX
#include <vcl/canvastools.hxx>
#endif
#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
#include <basegfx/tools/canvastools.hxx>
#endif
+#ifndef _BGFX_NUMERIC_FTOOLS_HXX
+#include <basegfx/numeric/ftools.hxx>
+#endif
+#ifndef _BGFX_POLYGON_B2DPOLYPOLYGONTOOLS_HXX
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#endif
+#ifndef _BGFX_POLYGON_B2DPOLYGONTOOLS_HXX
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#endif
#ifndef _CANVAS_CANVASTOOLS_HXX
#include <canvas/canvastools.hxx>
#endif
+#ifndef _VCL_CANVASTOOLS_HXX
+#include <vcl/canvastools.hxx>
+#endif
-#include "implrenderer.hxx"
-#include "tools.hxx"
-#include "outdevstate.hxx"
+#include <implrenderer.hxx>
+#include <tools.hxx>
+#include <outdevstate.hxx>
-#include "action.hxx"
-#include "bitmapaction.hxx"
-#include "lineaction.hxx"
-#include "pointaction.hxx"
-#include "polypolyaction.hxx"
-#include "textaction.hxx"
+#include <action.hxx>
+#include <bitmapaction.hxx>
+#include <lineaction.hxx>
+#include <pointaction.hxx>
+#include <polypolyaction.hxx>
+#include <textaction.hxx>
+#include <transparencygroupaction.hxx>
#include <vector>
#include <algorithm>
@@ -125,6 +155,9 @@
#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
#include <basegfx/matrix/b2dhommatrix.hxx>
#endif
+#ifndef _BGFX_TUPLE_B2DTUPLE_HXX
+#include <basegfx/tuple/b2dtuple.hxx>
+#endif
#ifndef _SV_GDIMTF_HXX
#include <vcl/gdimtf.hxx>
@@ -138,11 +171,15 @@
#include <vcl/virdev.hxx>
#endif
+#ifndef _SV_METRIC_HXX
+#include <vcl/metric.hxx>
+#endif
+
#ifndef _TL_POLY_HXX
#include <tools/poly.hxx>
#endif
-#include "outdevstate.hxx"
+#include <outdevstate.hxx>
using namespace ::drafts::com::sun::star;
@@ -224,10 +261,17 @@ namespace cppcanvas
int rActionIndex,
VectorOfOutDevStates& rStates )
{
+ const OutDevState& rState( getState( rStates ) );
+ if( rState.lineColor.getLength() == 0 &&
+ rState.fillColor.getLength() == 0 )
+ {
+ return false;
+ }
+
maActions.push_back(
MtfAction(
ActionSharedPtr(
- new internal::PolyPolyAction( rPolyPoly, rCanvas, getState( rStates ) ) ),
+ new internal::PolyPolyAction( rPolyPoly, rCanvas, rState ) ),
rActionIndex ) );
return true;
@@ -251,60 +295,837 @@ namespace cppcanvas
return;
}
- void ImplRenderer::createGradientAction( const Rectangle& rRect,
- const Gradient& rGradient,
- VirtualDevice& rVDev,
+ void ImplRenderer::createGradientAction( const ::PolyPolygon& rPoly,
+ const ::Gradient& rGradient,
+ ::VirtualDevice& rVDev,
const CanvasSharedPtr& rCanvas,
- VectorOfOutDevStates& rStates )
+ VectorOfOutDevStates& rStates,
+ const Parameters& rParms,
+ int& io_rCurrActionIndex,
+ bool bIsPolygonRectangle )
{
DBG_TESTSOLARMUTEX();
- // TODO: Use native canvas gradients here (saves a lot of UNO calls)
- GDIMetaFile aTmpMtf;
+ ::PolyPolygon aDevicePoly( rVDev.LogicToPixel( rPoly ) );
+
+ // decide, whether this gradient can be rendered natively
+ // by the canvas, or must be emulated via VCL gradient
+ // action extraction.
+ const USHORT nSteps( rGradient.GetSteps() );
- rVDev.AddGradientActions( rRect,
+#if 0
+ if( // step count is infinite, can use native canvas
+ // gradients here
+ nSteps == 0 ||
+ // step count is sufficiently high, such that no
+ // discernible difference should be visible.
+ nSteps > 64 )
+ {
+ uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory(
+ rCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
+
+ if( xFactory.is() )
+ {
+ ::basegfx::B2DHomMatrix aTextureTransformation;
+ rendering::Texture aTexture;
+
+ aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
+ aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
+ aTexture.Alpha = 1.0;
+
+
+ // setup start/end color values
+ // ----------------------------
+
+ // scale color coefficients with gradient intensities
+ const USHORT nStartIntensity( rGradient.GetStartIntensity() );
+ ::Color aVCLStartColor( rGradient.GetStartColor() );
+ aVCLStartColor.SetRed( aVCLStartColor.GetRed() * nStartIntensity / 100 );
+ aVCLStartColor.SetGreen( aVCLStartColor.GetGreen() * nStartIntensity / 100 );
+ aVCLStartColor.SetBlue( aVCLStartColor.GetBlue() * nStartIntensity / 100 );
+
+ const USHORT nEndIntensity( rGradient.GetEndIntensity() );
+ ::Color aVCLEndColor( rGradient.GetEndColor() );
+ aVCLEndColor.SetRed( aVCLEndColor.GetRed() * nEndIntensity / 100 );
+ aVCLEndColor.SetGreen( aVCLEndColor.GetGreen() * nEndIntensity / 100 );
+ aVCLEndColor.SetBlue( aVCLEndColor.GetBlue() * nEndIntensity / 100 );
+
+ const uno::Sequence< double > aStartColor(
+ ::vcl::unotools::colorToDoubleSequence( rCanvas->getUNOCanvas()->getDevice(),
+ aVCLStartColor ) );
+ const uno::Sequence< double > aEndColor(
+ ::vcl::unotools::colorToDoubleSequence( rCanvas->getUNOCanvas()->getDevice(),
+ aVCLEndColor ) );
+
+ // Setup texture transformation
+ // ----------------------------
+
+ const Rectangle aBounds( aDevicePoly.GetBoundRect() );
+
+ // setup rotation angle. VCL rotates
+ // counter-clockwise, while canvas transformation
+ // rotates clockwise
+ double nRotation( -rGradient.GetAngle() * M_PI / 1800.0 );
+
+ switch( rGradient.GetStyle() )
+ {
+ case GRADIENT_LINEAR:
+ // FALLTHROUGH intended
+ case GRADIENT_AXIAL:
+ {
+ // standard orientation for VCL linear
+ // gradient is vertical, thus, rotate 90
+ // degrees
+ nRotation += M_PI/2.0;
+
+ const double nBorder(
+ ::basegfx::pruneScaleValue(
+ (1.0 - rGradient.GetBorder() / 100.0) ) );
+
+ // shrink texture, to account for border
+ // (only in x direction, linear gradient
+ // is constant in y direction, anyway)
+ aTextureTransformation.scale( nBorder,
+ 1.0 );
+
+ // linear gradients don't respect offsets
+ // (they are implicitely assumed to be
+ // 50%). linear gradients don't have
+ // border on both sides, only on the
+ // startColor side, axial gradients have
+ // border on both sides. As both gradients
+ // are invariant in y direction: leave y
+ // offset alone.
+ double nOffsetX( rGradient.GetBorder() / 200.0 );
+
+ // determine type of gradient (and necessary
+ // transformation matrix, should it be emulated by a
+ // generic gradient)
+ switch( rGradient.GetStyle() )
+ {
+ case GRADIENT_LINEAR:
+ nOffsetX = rGradient.GetBorder() / 100.0;
+ aTexture.Gradient = xFactory->createLinearHorizontalGradient( aEndColor,
+ aStartColor );
+ break;
+
+ case GRADIENT_AXIAL:
+ aTexture.Gradient = xFactory->createAxialHorizontalGradient( aStartColor,
+ aEndColor );
+ break;
+ }
+
+ // apply border offset values
+ aTextureTransformation.translate( nOffsetX,
+ 0.0 );
+
+ // rotate texture according to gradient rotation
+ aTextureTransformation.translate( -0.5, -0.5 );
+ aTextureTransformation.rotate( nRotation );
+
+ // to let the first strip of a rotated
+ // gradient start at the _edge_ of the
+ // bound rect (and not, due to rotation,
+ // slightly inside), slightly enlarge the
+ // gradient:
+ //
+ // y/2 sin(alpha) + x/2 cos(alpha)
+ //
+ // (values to change are not actual
+ // gradient scales, but original bound
+ // rect dimensions. Since we still want
+ // the border setting to apply after that,
+ // we multiply with that as above for
+ // nScaleX)
+ const double nScale(
+ ::basegfx::pruneScaleValue(
+ fabs( aBounds.GetHeight()*sin(nRotation) ) +
+ fabs( aBounds.GetWidth()*cos(nRotation) )));
+
+ aTextureTransformation.scale( nScale, nScale );
+
+ // translate back origin to center of
+ // primitive
+ aTextureTransformation.translate( 0.5*aBounds.GetWidth(),
+ 0.5*aBounds.GetHeight() );
+ }
+ break;
+
+ case GRADIENT_RADIAL:
+ // FALLTHROUGH intended
+ case GRADIENT_ELLIPTICAL:
+ // FALLTHROUGH intended
+ case GRADIENT_SQUARE:
+ // FALLTHROUGH intended
+ case GRADIENT_RECT:
+ {
+ // determine scale factors for the gradient (must
+ // be scaled up from [0,1]x[0,1] rect to object
+ // bounds). Will potentially changed in switch
+ // statement below.
+ // Respect border value, while doing so, the VCL
+ // gradient's border will effectively shrink the
+ // resulting gradient.
+ double nScaleX( aBounds.GetWidth() * (1.0 - rGradient.GetBorder() / 100.0) );
+ double nScaleY( aBounds.GetHeight()* (1.0 - rGradient.GetBorder() / 100.0) );
+
+ // determine offset values. Since the border is
+ // divided half-by-half to both sides of the
+ // gradient, divide translation offset by an
+ // additional 2. Also respect offset here, but
+ // since VCL gradients have their center at [0,0]
+ // for zero offset, but canvas gradients have
+ // their top, left edge aligned with the
+ // primitive, and offset of 50% effectively must
+ // yield zero shift. Both values will potentially
+ // be adapted in switch statement below.
+ double nOffsetX( aBounds.GetWidth() *
+ (2.0 * rGradient.GetOfsX() - 100.0 + rGradient.GetBorder()) / 200.0 );
+ double nOffsetY( aBounds.GetHeight() *
+ (2.0 * rGradient.GetOfsY() - 100.0 + rGradient.GetBorder()) / 200.0 );
+
+ // determine type of gradient (and necessary
+ // transformation matrix, should it be emulated by a
+ // generic gradient)
+ switch( rGradient.GetStyle() )
+ {
+ case GRADIENT_RADIAL:
+ {
+ // enlarge gradient slightly
+ aTextureTransformation.translate( -0.5, -0.5 );
+ const double nSqrt2( sqrt(2.0) );
+ aTextureTransformation.scale( nSqrt2,nSqrt2 );
+ aTextureTransformation.translate( 0.5, 0.5 );
+
+ // create isotrophic scaling
+ if( nScaleX > nScaleY )
+ {
+ nOffsetY -= (nScaleX - nScaleY) * 0.5;
+ nScaleY = nScaleX;
+ }
+ else
+ {
+ nOffsetX -= (nScaleY - nScaleX) * 0.5;
+ nScaleX = nScaleY;
+ }
+
+ aTexture.Gradient = xFactory->createCircularGradient( aEndColor,
+ aStartColor );
+ }
+ break;
+
+ case GRADIENT_ELLIPTICAL:
+ {
+ // enlarge gradient slightly
+ aTextureTransformation.translate( -0.5, -0.5 );
+ const double nSqrt2( sqrt(2.0) );
+ aTextureTransformation.scale( nSqrt2,nSqrt2 );
+ aTextureTransformation.translate( 0.5, 0.5 );
+
+ aTexture.Gradient = xFactory->createCircularGradient( aEndColor,
+ aStartColor );
+ }
+ break;
+
+ case GRADIENT_SQUARE:
+ // create isotrophic scaling
+ if( nScaleX > nScaleY )
+ {
+ nOffsetY -= (nScaleX - nScaleY) * 0.5;
+ nScaleY = nScaleX;
+ }
+ else
+ {
+ nOffsetX -= (nScaleY - nScaleX) * 0.5;
+ nScaleX = nScaleY;
+ }
+
+ aTexture.Gradient = xFactory->createRectangularGradient( aEndColor,
+ aStartColor,
+ geometry::RealRectangle2D(0.0,0.0,
+ 1.0,1.0) );
+ break;
+
+ case GRADIENT_RECT:
+ aTexture.Gradient = xFactory->createRectangularGradient(
+ aEndColor,
+ aStartColor,
+ geometry::RealRectangle2D( aBounds.Left(),
+ aBounds.Top(),
+ aBounds.Right(),
+ aBounds.Bottom() ) );
+ break;
+ }
+
+ nScaleX = ::basegfx::pruneScaleValue( nScaleX );
+ nScaleY = ::basegfx::pruneScaleValue( nScaleY );
+
+ aTextureTransformation.scale( nScaleX, nScaleY );
+
+ // rotate texture according to gradient rotation
+ aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY );
+ aTextureTransformation.rotate( nRotation );
+ aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY );
+
+ aTextureTransformation.translate( nOffsetX, nOffsetY );
+ }
+ break;
+
+ default:
+ ENSURE_AND_THROW( false,
+ "ImplRenderer::createGradientAction(): Unexpected gradient type" );
+ break;
+ }
+
+ ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
+ aTextureTransformation );
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::PolyPolyAction( aDevicePoly,
+ rCanvas,
+ getState( rStates ),
+ aTexture ) ),
+ io_rCurrActionIndex ) );
+
+ // done, using native gradients
+ return;
+ }
+ }
+#endif
+
+ // cannot currently use native canvas gradients, as
+ // step size is given
+ pushState( rStates );
+
+ if( !bIsPolygonRectangle )
+ {
+ // only clip, if given polygon is not a rectangle in
+ // the first place (the gradient is always limited to
+ // the given bound rect)
+ updateClipping(
+ rStates,
+ aDevicePoly.getB2DPolyPolygon(),
+ rCanvas,
+ true );
+ }
+
+ GDIMetaFile aTmpMtf;
+ rVDev.AddGradientActions( rPoly.GetBoundRect(),
rGradient,
aTmpMtf );
+ createActions( rCanvas, rVDev, aTmpMtf, rStates, rParms, io_rCurrActionIndex );
+
+ popState( rStates );
+ }
+
+ uno::Reference< rendering::XCanvasFont > ImplRenderer::createFont( ::basegfx::B2DHomMatrix& o_rFontMatrix,
+ const ::Font& rFont,
+ const CanvasSharedPtr& rCanvas,
+ const ::VirtualDevice& rVDev,
+ const Parameters& rParms ) const
+ {
+ rendering::FontRequest aFontRequest;
+
+ if( rParms.maFontName.isValid() )
+ aFontRequest.FontDescription.FamilyName = rParms.maFontName.getValue();
+ else
+ aFontRequest.FontDescription.FamilyName = rFont.GetName();
+
+ aFontRequest.FontDescription.StyleName = rFont.GetStyleName();
+
+ aFontRequest.FontDescription.IsSymbolFont = (rFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL) ? util::TriState_YES : util::TriState_NO;
+ aFontRequest.FontDescription.IsVertical = rFont.IsVertical() ? util::TriState_YES : util::TriState_NO;
+
+ // TODO(F2): improve vclenum->panose conversion
+ aFontRequest.FontDescription.FontDescription.Weight =
+ rParms.maFontWeight.isValid() ?
+ rParms.maFontWeight.getValue() :
+ ::canvas::tools::numeric_cast<sal_Int8>( ::basegfx::fround( rFont.GetWeight() ) );
+ aFontRequest.FontDescription.FontDescription.Letterform =
+ rParms.maFontLetterForm.isValid() ?
+ rParms.maFontLetterForm.getValue() :
+ (rFont.GetItalic() == ITALIC_NONE) ? 0 : 9;
+
+ // TODO(F2): use correct scale direction, font
+ // height might be width or anything else
+ aFontRequest.CellSize = rVDev.LogicToPixel( rFont.GetSize() ).Height();
+
+ // setup state-local text transformation,
+ // if the font be rotated
+ const short nFontAngle( rFont.GetOrientation() );
+ if( nFontAngle != 0 )
+ {
+ // set to unity transform rotated by font angle
+ const double rAngle( nFontAngle * (F_PI / 1800.0) );
+ o_rFontMatrix.identity();
+ o_rFontMatrix.rotate( -rAngle );
+ }
+
+ geometry::Matrix2D aFontMatrix;
+ ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
+
+ // check if the font is stretched or squeezed
+ long nFontWidth = rFont.GetSize().Width();
+ if( nFontWidth != 0 )
+ {
+ ::Font aTestFont = rFont;
+ aTestFont.SetWidth( 0 );
+ int nNormalWidth = rVDev.GetFontMetric( aTestFont ).GetWidth();
+ if( nNormalWidth != nFontWidth )
+ if( nNormalWidth )
+ aFontMatrix.m00 = (double)nFontWidth / nNormalWidth;
+ }
+
+ return rCanvas->getUNOCanvas()->createFont( aFontRequest,
+ uno::Sequence< beans::PropertyValue >(),
+ aFontMatrix );
+ }
+
+ // create text effects such as shadow/relief/embossed
+ void ImplRenderer::createTextWithEffectsAction(
+ const Point& rStartPoint,
+ const String rString,
+ int nIndex,
+ int nLength,
+ const long* pCharWidths,
+ VirtualDevice& rVDev,
+ const CanvasSharedPtr& rCanvas,
+ VectorOfOutDevStates& rStates,
+ const Parameters& rParms,
+ int nCurrActionIndex )
+ {
+ ENSURE_AND_THROW( nIndex >= 0 && nLength <= rString.Len() + nIndex,
+ "ImplRenderer::createTextWithEffectsAction(): Invalid text index" );
+
+ ::cppcanvas::internal::OutDevState& rState = getState( rStates );
+
+ // TODO(F2): implement all text effects
+ if( rState.textAlignment ); // TODO(F2): NYI
+
+ if( rState.isTextEffectShadowSet )
+ {
+ // calculate relief offset (similar to outdev3.cxx)
+ // TODO(F3): better match with outdev3.cxx
+ long nShadowOffset = static_cast<long>(1.5 + ((rVDev.GetFont().GetHeight()-24.0)/24.0));
+ if( nShadowOffset < 1 )
+ nShadowOffset = 1;
+ Point aShadowPoint( nShadowOffset, nShadowOffset );
+ aShadowPoint += rStartPoint;
+
+ // determine shadow color (from outdev3.cxx)
+ ::Color aTextColor = ::vcl::unotools::sequenceToColor(
+ rCanvas->getUNOCanvas()->getDevice(), rState.textColor );
+ bool bIsDark = (aTextColor.GetColor() == COL_BLACK)
+ || (aTextColor.GetLuminance() < 8);
+ ::Color aShadowColor( bIsDark ? COL_LIGHTGRAY : COL_BLACK );
+ aShadowColor.SetTransparency( aTextColor.GetTransparency() );
+
+ // draw shadow text and restore original rState
+ // TODO(P2): just restore textColor instead of push/pop
+ pushState( rStates );
+ // ::com::sun::star::uno::Sequence< double > origTextColor = rState.textColor;
+ getState( rStates ).textColor = ::vcl::unotools::colorToDoubleSequence(
+ rCanvas->getUNOCanvas()->getDevice(), aShadowColor );
+ createTextWithLinesAction(
+ aShadowPoint, rString, nIndex, nLength,
+ pCharWidths, rVDev, rCanvas, rStates, rParms, nCurrActionIndex );
+ popState( rStates );
+ // rState.textColor = origTextColor;
+ }
+
+ // draw the normal text
+ createTextWithLinesAction(
+ rStartPoint, rString, nIndex, nLength,
+ pCharWidths, rVDev, rCanvas, rStates, rParms, nCurrActionIndex );
+
+ if( rState.textReliefStyle )
+ {
+ // calculate relief offset (similar to outdev3.cxx)
+ long nReliefOffset = rVDev.PixelToLogic( Size( 1, 1 ) ).Height();
+ nReliefOffset += nReliefOffset/2;
+ if( nReliefOffset < 1 )
+ nReliefOffset = 1;
+
+ if( rState.textReliefStyle == RELIEF_ENGRAVED )
+ nReliefOffset = -nReliefOffset;
+ Point aReliefPoint( nReliefOffset, nReliefOffset );
+ aReliefPoint += rStartPoint;
+
+ // determine relief color (from outdev3.cxx)
+ ::Color aTextColor = ::vcl::unotools::sequenceToColor(
+ rCanvas->getUNOCanvas()->getDevice(), rState.textColor );
+ ::Color aReliefColor( COL_LIGHTGRAY );
+ if( aTextColor.GetColor() == COL_BLACK )
+ aReliefColor = ::Color( COL_WHITE );
+ else if( aTextColor.GetColor() == COL_WHITE )
+ aReliefColor = ::Color( COL_BLACK );
+ aReliefColor.SetTransparency( aTextColor.GetTransparency() );
+
+ // draw relief text and restore original rState
+ // TODO(P2): just restore textColor instead of push/pop
+ pushState( rStates );
+ // ::com::sun::star::uno::Sequence< double > origTextColor = rState.textColor;
+ getState( rStates ).textColor = ::vcl::unotools::colorToDoubleSequence(
+ rCanvas->getUNOCanvas()->getDevice(), aReliefColor );
+ createTextWithLinesAction(
+ aReliefPoint, rString, nIndex, nLength,
+ pCharWidths, rVDev, rCanvas, rStates, rParms, nCurrActionIndex );
+ popState( rStates );
+ // rState.textColor = origTextColor;
+ }
+ }
+
+
+ // create draw actions for text and underlines/strikeouts/etc.
+ void ImplRenderer::createTextWithLinesAction(
+ const Point& rStartPoint,
+ const String rString,
+ int nIndex,
+ int nLength,
+ const long* pCharWidths,
+ VirtualDevice& rVDev,
+ const CanvasSharedPtr& rCanvas,
+ VectorOfOutDevStates& rStates,
+ const Parameters& rParms,
+ int nCurrActionIndex )
+ {
+ ::cppcanvas::internal::OutDevState& rState = getState( rStates );
+
+ Point aStartPixel = rVDev.LogicToPixel( rStartPoint );
+ internal::Action* pAction = NULL;
+
+ if( rState.isTextOutlineModeSet )
+ {
+ ::PolyPolygon aVclPolyPolygon;
+ if( rVDev.GetTextOutline( aVclPolyPolygon, rString,
+ nIndex, nIndex, nLength, TRUE, 0, pCharWidths ) )
+ {
+ int nOutlineWidth = rVDev.GetFont().GetHeight() / 32;
+ if( nOutlineWidth <= 0 )
+ nOutlineWidth = 1;
+ // TODO(F3): rState.strokeWith = nOutlineWidth;
+ // Path stroking not yet functional for all canvas
+ // implementations
+ aVclPolyPolygon.Translate( rStartPoint ); //####???
+ aVclPolyPolygon = rVDev.LogicToPixel( aVclPolyPolygon );
+
+ // set outline color
+ rState.lineColor = rState.textColor;
+ rState.isLineColorSet = true;
+ // set the fill color to match the VCL fill color for outlined text
+ // TODO: in the current Canvas model setting a fixed color is beyond ugly
+ ColorSharedPtr pColor( rCanvas.get()->createColor() );
+ rState.fillColor = pColor->getDeviceColor( 0xFFFFFFFF ); // solid white
+ rState.isFillColorSet = true;
+ // NOTE: rState.strokeWidth is already set by the caller
+
+ // TODO(F3): use bezier polygon directly when it
+ // is implemented
+ ::PolyPolygon aNOTBEZIER;
+ aVclPolyPolygon.AdaptiveSubdivide( aNOTBEZIER );
+ pAction = new internal::PolyPolyAction( aNOTBEZIER, rCanvas, rState );
+ }
+ }
+
+ // if no outline mode was requested or possible then draw the normal text
+ if( !pAction )
+ {
+ if( !pCharWidths )
+ pAction = new internal::TextAction( aStartPixel, rString,
+ nIndex, nLength, rCanvas, rState,
+ rParms.maTextTransformation );
+ else
+ {
+ uno::Sequence< double > aCharWidthSeq( ::comphelper::arrayToSequence<double>( pCharWidths, nLength ) );
+ // convert character widths from logical units
+ for( int i = 0; i < nLength; ++i )
+ {
+ // TODO(F2): use correct scale direction
+ const Size aSize( ::basegfx::fround( pCharWidths[i] + .5 ), 0 );
+ aCharWidthSeq[i] = rVDev.LogicToPixel( aSize ).Width();
+ }
+
+ pAction = new internal::TextAction( aStartPixel, rString,
+ nIndex, nLength, aCharWidthSeq, rCanvas, rState,
+ rParms.maTextTransformation );
+ }
+ }
+
+ maActions.push_back( MtfAction( ActionSharedPtr( pAction ), nCurrActionIndex ) );
+
+ if( rState.textUnderlineStyle || rState.textStrikeoutStyle )
+ {
+ // TODO: split text lines on word breaks
+ if( rState.isTextWordUnderlineSet ); // TODO: NYI
+
+ long nTextWidth = rVDev.GetTextWidth( rString, nIndex, nLength );
+ createJustTextLinesAction( rStartPoint, nTextWidth, rVDev,
+ rCanvas, rStates, rParms, nCurrActionIndex );
+ }
+
+ // TODO: implement text emphasis mark styles
+ if( rState.textEmphasisMarkStyle ); // TODO: NYI
+ }
+
+
+ // create line actions for text such as underline and strikeout
+ void ImplRenderer::createJustTextLinesAction(
+ const Point& rLogicalStartPoint,
+ long nLineWidth,
+ VirtualDevice& rVDev,
+ const CanvasSharedPtr& rCanvas,
+ VectorOfOutDevStates& rStates,
+ const Parameters& rParms,
+ int nCurrActionIndex )
+ {
pushState( rStates );
- createActions( rCanvas, rVDev, aTmpMtf, rStates );
+ ::cppcanvas::internal::OutDevState& rState = getState( rStates );
+
+ // initialize the color of the text lines
+ if( !rState.isTextOutlineModeSet )
+ {
+ // normal text lines
+ rState.fillColor = rState.textColor;
+ // NOTE: strangely the text line color is ignored by vcl
+ // color = rState.isTextLineColorSet ? rState.textLineColor : rState.textColor;
+ rState.isFillColorSet = true;
+ rState.isLineColorSet = false;
+ }
+#if 0
+ // the line and fill colors are already set by the calling method
+ // when we are in outline mode, because the text rendering already needed it
+ else
+ {
+ // text lines for text using an outline font
+ rState.lineColor = rState.textColor;
+ rState.isLineColorSet = true;
+ // TODO: rState.fillColor = Color( COL_WHITE );
+ // TODO: rState.isFillColorSet = true;
+ // NOTE: rState.strokeWidth is already set by the caller
+ }
+#endif
+
+ // prepare text line position and size
+ ::FontMetric aMetric = rVDev.GetFontMetric();
+ long nLineHeight = (aMetric.GetDescent() + 2) / 4;
+ Point aUnderlineOffset( 0, aMetric.GetDescent() / 2);
+
+ // fill the polypolygon with all text lines
+ ::PolyPolygon aTextLinePolyPoly;
+
+ ::Polygon aPolygon(4);
+ switch( rState.textUnderlineStyle )
+ {
+ case UNDERLINE_NONE: // nothing to do
+ case UNDERLINE_DONTKNOW:
+ break;
+ case UNDERLINE_DASHDOT: // TODO(F3): NYI
+ case UNDERLINE_DASHDOTDOT: // TODO(F3): NYI
+ case UNDERLINE_SMALLWAVE: // TODO(F3): NYI
+ case UNDERLINE_WAVE: // TODO(F3): NYI
+ case UNDERLINE_DOUBLEWAVE: // TODO(F3): NYI
+ case UNDERLINE_BOLDDOTTED: // TODO(F3): NYI
+ case UNDERLINE_BOLDDASH: // TODO(F3): NYI
+ case UNDERLINE_BOLDLONGDASH: // TODO(F3): NYI
+ case UNDERLINE_BOLDDASHDOT: // TODO(F3): NYI
+ case UNDERLINE_BOLDDASHDOTDOT:// TODO(F3): NYI
+ case UNDERLINE_BOLDWAVE: // TODO(F3): NYI
+ case UNDERLINE_SINGLE:
+ {
+ aPolygon = Polygon( Rectangle( aUnderlineOffset, Size( nLineWidth, nLineHeight ) ) );
+ aTextLinePolyPoly.Insert( aPolygon );
+ break;
+ }
+ case UNDERLINE_BOLD:
+ {
+ aPolygon = Polygon( Rectangle( aUnderlineOffset, Size( nLineWidth, 2*nLineHeight ) ) );
+ aTextLinePolyPoly.Insert( aPolygon );
+ break;
+ }
+ case UNDERLINE_DOUBLE:
+ {
+ aPolygon = Polygon( Rectangle( aUnderlineOffset, Size( nLineWidth, nLineHeight ) ) );
+ aPolygon.Move( 0, -nLineHeight );
+ aTextLinePolyPoly.Insert( aPolygon );
+ aPolygon.Move( 0, +nLineHeight * 2 );
+ aTextLinePolyPoly.Insert( aPolygon );
+ break;
+ }
+ case UNDERLINE_DOTTED:
+ {
+ aPolygon = Polygon( Rectangle( aUnderlineOffset, Size( nLineHeight, nLineHeight ) ) );
+ for( int x = 0; x < nLineWidth;)
+ {
+ aTextLinePolyPoly.Insert( aPolygon );
+ aPolygon.Move( 2 * nLineHeight, 0 );
+ x += 6 * nLineHeight ;
+ }
+ break;
+ }
+ case UNDERLINE_DASH:
+ {
+ aPolygon = Polygon( Rectangle( aUnderlineOffset, Size( 3*nLineHeight, nLineHeight ) ) );
+ for( int x = 0; x < nLineWidth;)
+ {
+ aTextLinePolyPoly.Insert( aPolygon );
+ aPolygon.Move( 6 * nLineHeight, 0 );
+ x += 6 * nLineHeight ;
+ }
+ break;
+ }
+ case UNDERLINE_LONGDASH:
+ {
+ aPolygon = Polygon( Rectangle( aUnderlineOffset, Size( 6*nLineHeight, nLineHeight ) ) );
+ for( int x = 0; x < nLineWidth;)
+ {
+ aTextLinePolyPoly.Insert( aPolygon );
+ aPolygon.Move( 12 * nLineHeight, 0 );
+ x += 12 * nLineHeight;
+ }
+ break;
+ }
+ }
+
+ switch( rState.textStrikeoutStyle )
+ {
+ case STRIKEOUT_NONE: // nothing to do
+ case STRIKEOUT_DONTKNOW:
+ break;
+ case STRIKEOUT_SLASH: // TODO: we should handle this in the text layer
+ case STRIKEOUT_X:
+ break;
+ case STRIKEOUT_SINGLE:
+ {
+ Point aOffset( 0, (aMetric.GetIntLeading() - aMetric.GetAscent()) / 3 );
+ Rectangle aRect( aOffset, Size( nLineWidth, nLineHeight ) );
+ aTextLinePolyPoly.Insert( ::Polygon( aRect ) );
+ break;
+ }
+ case STRIKEOUT_BOLD:
+ {
+ Point aOffset( 0, (aMetric.GetIntLeading() - aMetric.GetAscent()) / 3 );
+ Rectangle aRect( aOffset, Size( nLineWidth, 2 * nLineHeight ) );
+ aTextLinePolyPoly.Insert( ::Polygon( aRect ) );
+ break;
+ }
+ case STRIKEOUT_DOUBLE:
+ {
+ Point aOffset( 0, (aMetric.GetIntLeading() - aMetric.GetAscent()) / 3 );
+ aOffset.Y() -= nLineHeight;
+ Rectangle aRect( aOffset, Size( nLineWidth, nLineHeight ) );
+ aTextLinePolyPoly.Insert( ::Polygon( aRect ) );
+ aRect.Move( 0, 2 * nLineHeight );
+ aTextLinePolyPoly.Insert( ::Polygon( aRect ) );
+ break;
+ }
+ }
+
+ if( !aTextLinePolyPoly.Count() )
+ return;
+
+ // prepare text line orientation
+ basegfx::B2DTuple aTScale, aTTrans;
+ double fRotate, fShearX;
+ rState.fontTransform.decompose( aTScale, aTTrans, fRotate, fShearX );
+ fRotate = 3600 - fRotate * (1800.0 / F_PI);
+
+ // adjust to the target coordinate system
+ aTextLinePolyPoly.Rotate( Point(0,0),
+ ::canvas::tools::numeric_cast<USHORT>( ::basegfx::fround( fRotate ) ) );
+ aTextLinePolyPoly.Translate( rLogicalStartPoint );
+ aTextLinePolyPoly = rVDev.LogicToPixel( aTextLinePolyPoly );
+
+ // create the underline + strikethrough line actions
+ maActions.push_back( MtfAction( ActionSharedPtr(
+ new internal::PolyPolyAction( aTextLinePolyPoly, rCanvas, rState ) ),
+ nCurrActionIndex ) );
+
popState( rStates );
}
+ void ImplRenderer::updateClipping( VectorOfOutDevStates& rStates,
+ const ::basegfx::B2DPolyPolygon& rClipPoly,
+ const CanvasSharedPtr& rCanvas,
+ bool bIntersect )
+ {
+ ::cppcanvas::internal::OutDevState& rState( getState( rStates ) );
+ ::basegfx::B2DPolyPolygon aClipPoly( rClipPoly );
+
+ if( !bIntersect ||
+ rState.clip.count() == 0 )
+ {
+ rState.clip = rClipPoly;
+ }
+ else
+ {
+ rState.clip = ::basegfx::tools::correctOrientations( rState.clip );
+ aClipPoly = ::basegfx::tools::correctOrientations( aClipPoly );
+
+ // intersect the two poly-polygons
+ rState.clip = ::basegfx::tools::removeAllIntersections(rState.clip);
+ rState.clip = ::basegfx::tools::removeNeutralPolygons(rState.clip, sal_True);
+ aClipPoly = ::basegfx::tools::removeAllIntersections(aClipPoly);
+ aClipPoly = ::basegfx::tools::removeNeutralPolygons(aClipPoly, sal_True);
+ rState.clip.append(aClipPoly);
+ rState.clip = ::basegfx::tools::removeAllIntersections(rState.clip);
+ rState.clip = ::basegfx::tools::removeNeutralPolygons(rState.clip, sal_False);
+ }
+
+ if( rState.clip.count() == 0 )
+ {
+ rState.xClipPoly.clear();
+ }
+ else
+ {
+ rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ rCanvas->getUNOCanvas()->getDevice(),
+ rState.clip );
+ }
+ }
+
bool ImplRenderer::createActions( const CanvasSharedPtr& rCanvas,
VirtualDevice& rVDev,
GDIMetaFile& rMtf,
- VectorOfOutDevStates& rStates )
+ VectorOfOutDevStates& rStates,
+ const Parameters& rParms,
+ int& io_rCurrActionIndex )
{
- /* TODO:
- =====
+ /* TODO(P2): interpret mtf-comments
+ ================================
- - Float-Transparency (skipped for prototype
+ - Float-Transparency (skipped for prototype)
- bitmap fillings (do that via comments)
- gradient fillings (do that via comments)
- think about mapping. _If_ we do everything in logical
coordinates (which would solve the probs for stroke
- widths and and text offsets), then we would have to
+ widths and text offsets), then we would have to
recalc scaling for every drawing operation. This is
because the outdev map mode might change at any time.
+ Also keep in mind, that, although we've double precision
+ float arithmetic now, different offsets might still
+ generate different roundings (aka
+ 'OutputDevice::SetPixelOffset())
*/
// Loop over every metaaction
// ==========================
MetaAction* pCurrAct;
- int nCurrActionIndex;
- // TODO: think about caching
- for( nCurrActionIndex=0, pCurrAct=rMtf.FirstAction();
+ // TODO(P1): think about caching
+ for( pCurrAct=rMtf.FirstAction();
pCurrAct;
- ++nCurrActionIndex, pCurrAct = rMtf.NextAction() )
+ ++io_rCurrActionIndex, pCurrAct = rMtf.NextAction() )
{
// execute every action, to keep VDev state up-to-date
- // (currently used only for the map mode, and for
- // line/fill color when processing a
- // META_TRANSPARENT_ACTION)
+ // currently used only for
+ // - the map mode
+ // - the line/fill color when processing a META_TRANSPARENT_ACTION
+ // - SetFont to process font metric specific actions
pCurrAct->Execute( &rVDev );
switch( pCurrAct->GetType() )
@@ -327,122 +1148,242 @@ namespace cppcanvas
// monitor clip regions, to assemble clip polygon on our own
case META_CLIPREGION_ACTION:
+ {
+ MetaClipRegionAction* pClipAction = static_cast<MetaClipRegionAction*>(pCurrAct);
+
+ if( !pClipAction->IsClipping() )
+ {
+ // clear clipping
+ getState( rStates ).clip.clear();
+ }
+ else
+ {
+ if( !pClipAction->GetRegion().HasPolyPolygon() )
+ {
+ VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip "
+ "region encountered, falling back to bounding box!" );
+
+ Rectangle aClipRect(
+ rVDev.LogicToPixel(
+ pClipAction->GetRegion().GetBoundRect() ) );
+
+ // intersect current clip with given rect
+ updateClipping(
+ rStates,
+ ::basegfx::B2DPolyPolygon(
+ ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRectangle( aClipRect.Left(),
+ aClipRect.Top(),
+ aClipRect.Right(),
+ aClipRect.Bottom() ) ) ),
+ rCanvas,
+ false );
+ }
+ else
+ {
+ // set new clip polygon (don't intersect
+ // with old one, just set it)
+ updateClipping(
+ rStates,
+ rVDev.LogicToPixel(
+ pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(),
+ rCanvas,
+ false );
+ }
+ }
+
+ break;
+ }
+
case META_ISECTRECTCLIPREGION_ACTION:
+ {
+ MetaISectRectClipRegionAction* pClipAction = static_cast<MetaISectRectClipRegionAction*>(pCurrAct);
+ Rectangle aClipRect(
+ rVDev.LogicToPixel( pClipAction->GetRect() ) );
+
+ // intersect current clip with given rect
+ updateClipping(
+ rStates,
+ ::basegfx::B2DPolyPolygon(
+ ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRectangle( aClipRect.Left(),
+ aClipRect.Top(),
+ aClipRect.Right(),
+ aClipRect.Bottom() ) ) ),
+ rCanvas,
+ true );
+
+ break;
+ }
+
case META_ISECTREGIONCLIPREGION_ACTION:
+ {
+ MetaISectRegionClipRegionAction* pClipAction = static_cast<MetaISectRegionClipRegionAction*>(pCurrAct);
+
+ if( !pClipAction->GetRegion().HasPolyPolygon() )
+ {
+ VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip "
+ "region encountered, falling back to bounding box!" );
+
+ Rectangle aClipRect(
+ rVDev.LogicToPixel( pClipAction->GetRegion().GetBoundRect() ) );
+
+ // intersect current clip with given rect
+ updateClipping(
+ rStates,
+ ::basegfx::B2DPolyPolygon(
+ ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRectangle( aClipRect.Left(),
+ aClipRect.Top(),
+ aClipRect.Right(),
+ aClipRect.Bottom() ) ) ),
+ rCanvas,
+ true );
+ }
+ else
+ {
+ // intersect current clip with given clip polygon
+ updateClipping(
+ rStates,
+ rVDev.LogicToPixel(
+ pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(),
+ rCanvas,
+ true );
+ }
+
+ break;
+ }
+
case META_MOVECLIPREGION_ACTION:
- // TODO: NYI
+ // TODO(F2): NYI
break;
case META_LINECOLOR_ACTION:
- setStateColor( static_cast<MetaLineColorAction*>(pCurrAct),
- getState( rStates ).isLineColorSet,
- getState( rStates ).lineColor,
- rCanvas );
+ if( !rParms.maLineColor.isValid() )
+ {
+ setStateColor( static_cast<MetaLineColorAction*>(pCurrAct),
+ getState( rStates ).isLineColorSet,
+ getState( rStates ).lineColor,
+ rCanvas );
+ }
break;
case META_FILLCOLOR_ACTION:
- setStateColor( static_cast<MetaFillColorAction*>(pCurrAct),
- getState( rStates ).isFillColorSet,
- getState( rStates ).fillColor,
- rCanvas );
+ if( !rParms.maFillColor.isValid() )
+ {
+ setStateColor( static_cast<MetaFillColorAction*>(pCurrAct),
+ getState( rStates ).isFillColorSet,
+ getState( rStates ).fillColor,
+ rCanvas );
+ }
break;
case META_TEXTCOLOR_ACTION:
{
- // Text color is set unconditionally, thus, no
- // use of setStateColor here
- ::Color aColor( static_cast<MetaTextColorAction*>(pCurrAct)->GetColor() );
-
- // force alpha part of color to
- // opaque. transparent painting is done
- // explicitely via META_TRANSPARENT_ACTION
- aColor.SetTransparency(0);
-
- getState( rStates ).textColor =
- ::vcl::unotools::colorToDoubleSequence( rCanvas->getUNOCanvas()->getDevice(),
- aColor );
+ if( !rParms.maTextColor.isValid() )
+ {
+ // Text color is set unconditionally, thus, no
+ // use of setStateColor here
+ ::Color aColor( static_cast<MetaTextColorAction*>(pCurrAct)->GetColor() );
+
+ // force alpha part of color to
+ // opaque. transparent painting is done
+ // explicitely via META_TRANSPARENT_ACTION
+ aColor.SetTransparency(0);
+
+ getState( rStates ).textColor =
+ ::vcl::unotools::colorToDoubleSequence( rCanvas->getUNOCanvas()->getDevice(),
+ aColor );
+ }
}
break;
case META_TEXTFILLCOLOR_ACTION:
- setStateColor( static_cast<MetaTextFillColorAction*>(pCurrAct),
- getState( rStates ).isTextFillColorSet,
- getState( rStates ).textFillColor,
- rCanvas );
+ if( !rParms.maTextColor.isValid() )
+ {
+ setStateColor( static_cast<MetaTextFillColorAction*>(pCurrAct),
+ getState( rStates ).isTextFillColorSet,
+ getState( rStates ).textFillColor,
+ rCanvas );
+ }
break;
case META_TEXTLINECOLOR_ACTION:
- setStateColor( static_cast<MetaTextLineColorAction*>(pCurrAct),
- getState( rStates ).isTextLineColorSet,
- getState( rStates ).textLineColor,
- rCanvas );
+ if( !rParms.maTextColor.isValid() )
+ {
+ setStateColor( static_cast<MetaTextLineColorAction*>(pCurrAct),
+ getState( rStates ).isTextLineColorSet,
+ getState( rStates ).textLineColor,
+ rCanvas );
+ }
break;
case META_TEXTALIGN_ACTION:
- // TODO: NYI
+ // TODO(F2): NYI
break;
case META_FONT_ACTION:
{
- // TODO: For now, only dummy implementation
- rendering::FontRequest aFontRequest;
+ ::cppcanvas::internal::OutDevState& rState = getState( rStates );
const ::Font& rFont( static_cast<MetaFontAction*>(pCurrAct)->GetFont() );
- aFontRequest.FamilyName = rFont.GetName();
- aFontRequest.StyleName = rFont.GetStyleName();
-
- // TODO: use correct scale direction, font
- // height might be width or anything else
- const Size aSize( 0, rFont.GetHeight() );
- aFontRequest.CellSize = rVDev.LogicToPixel( aSize ).Height();
-
- const short nFontAngle( rFont.GetOrientation() );
-
- // setup state-local text transformation,
- // should the font be rotated
- if( nFontAngle != 0 )
- {
- // VCL font does not access system structs here
- const double rAngle( nFontAngle * (F_PI / 1800.0) );
-
- // reset transform
- getState( rStates ).fontTransform.identity();
-
- // rotate by given angle
- getState( rStates ).fontTransform.rotate( -rAngle );
- }
-
- getState( rStates ).xFont = rCanvas->getUNOCanvas()->queryFont( aFontRequest );
+ rState.xFont = createFont( rState.fontTransform,
+ rFont,
+ rCanvas,
+ rVDev,
+ rParms );
+
+ // TODO(Q2): define and use appropriate enumeration types
+ rState.textReliefStyle = (sal_Int8)rFont.GetRelief();
+ rState.textUnderlineStyle = rParms.maFontUnderline.isValid() ?
+ (rParms.maFontUnderline.getValue() ? UNDERLINE_SINGLE : UNDERLINE_NONE) :
+ (sal_Int8)rFont.GetUnderline();
+ rState.textStrikeoutStyle = (sal_Int8)rFont.GetStrikeout();
+ rState.textEmphasisMarkStyle = (sal_Int8)rFont.GetEmphasisMark();
+ rState.isTextEffectShadowSet = (rFont.IsShadow() != FALSE);
+ rState.isTextWordUnderlineSet = (rFont.IsWordLineMode() != FALSE);
+ rState.isTextOutlineModeSet = (rFont.IsOutline() != FALSE);
}
break;
case META_RASTEROP_ACTION:
- // TODO: NYI
+ // TODO(F2): NYI
break;
case META_REFPOINT_ACTION:
- // TODO: NYI
+ // TODO(F2): NYI
break;
case META_LAYOUTMODE_ACTION:
{
- // TODO: A lot is missing here
- switch( static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode() )
+ // TODO(F2): A lot is missing here
+ int nLayoutMode = static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode();
+ ::cppcanvas::internal::OutDevState& rState = getState( rStates );
+ switch( nLayoutMode & (TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_BIDI_STRONG) )
{
+ case TEXT_LAYOUT_BIDI_LTR:
+ rState.textDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
+ break;
+
+ case (TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG):
+ rState.textDirection = rendering::TextDirection::STRONG_LEFT_TO_RIGHT;
+ break;
+
case TEXT_LAYOUT_BIDI_RTL:
- case TEXT_LAYOUT_TEXTORIGIN_RIGHT:
- getState( rStates ).textDirection = rendering::TextDirection::RIGHT_TO_LEFT;
+ rState.textDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
break;
- case TEXT_LAYOUT_BIDI_LTR:
- case TEXT_LAYOUT_BIDI_STRONG:
- case TEXT_LAYOUT_TEXTORIGIN_LEFT:
- case TEXT_LAYOUT_COMPLEX_DISABLED:
- case TEXT_LAYOUT_ENABLE_LIGATURES:
- case TEXT_LAYOUT_SUBSTITUTE_DIGITS:
- getState( rStates ).textDirection = rendering::TextDirection::LEFT_TO_RIGHT;
+ case (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG):
+ rState.textDirection = rendering::TextDirection::STRONG_RIGHT_TO_LEFT;
break;
}
+
+ rState.textAlignment = 0; // TODO(F2): rendering::TextAlignment::LEFT_ALIGNED;
+ if( (nLayoutMode & (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_RIGHT) )
+ && !(nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT ) )
+ {
+ rState.textAlignment = 1; // TODO(F2): rendering::TextAlignment::RIGHT_ALIGNED;
+ }
}
break;
@@ -458,23 +1399,26 @@ namespace cppcanvas
case META_GRADIENT_ACTION:
{
MetaGradientAction* pGradAct = static_cast<MetaGradientAction*>(pCurrAct);
- createGradientAction( pGradAct->GetRect(),
+ createGradientAction( ::Polygon( pGradAct->GetRect() ),
pGradAct->GetGradient(),
rVDev,
rCanvas,
- rStates );
+ rStates,
+ rParms,
+ io_rCurrActionIndex,
+ true );
}
break;
case META_HATCH_ACTION:
{
- // TODO: use native Canvas hatches here
+ // TODO(F2): use native Canvas hatches here
GDIMetaFile aTmpMtf;
rVDev.AddHatchActions( static_cast<MetaHatchAction*>(pCurrAct)->GetPolyPolygon(),
static_cast<MetaHatchAction*>(pCurrAct)->GetHatch(),
aTmpMtf );
- createActions( rCanvas, rVDev, aTmpMtf, rStates );
+ createActions( rCanvas, rVDev, aTmpMtf, rStates, rParms, io_rCurrActionIndex );
}
break;
@@ -505,7 +1449,8 @@ namespace cppcanvas
createActions( rCanvas, rVDev,
const_cast<GDIMetaFile&>(pAct->GetSubstitute()),
- rStates );
+ rStates, rParms,
+ io_rCurrActionIndex );
popState( rStates );
}
@@ -542,23 +1487,14 @@ namespace cppcanvas
if( pGradAction )
{
- pushState( rStates );
-
- // TODO: Hack! If
- // current state
- // already contains a
- // clipping, we'll
- // overwrite it here!
- getState( rStates ).xClipPoly = ::vcl::unotools::xPolyPolygonFromPolyPolygon( rCanvas->getUNOCanvas()->getDevice(),
- rVDev.LogicToPixel( pGradAction->GetPolyPolygon() ) );
-
- createGradientAction( pGradAction->GetPolyPolygon().GetBoundRect(),
+ createGradientAction( pGradAction->GetPolyPolygon(),
pGradAction->GetGradient(),
rVDev,
rCanvas,
- rStates );
-
- popState( rStates );
+ rStates,
+ rParms,
+ io_rCurrActionIndex,
+ false );
}
}
break;
@@ -569,7 +1505,7 @@ namespace cppcanvas
// Handle drawing layer strokes
else if( pAct->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" ) )
{
- // TODO: Later
+ // TODO(F1): Later
#if 0
const BYTE* pData = pAct->GetData();
if ( pData )
@@ -579,11 +1515,11 @@ namespace cppcanvas
SvtGraphicStroke aStroke;
aMemStm >> aStroke;
- // TODO: respect exceptions, like
+ // TODO(F1): respect exceptions, like
// start/end arrows and joins not
// displayable via Canvas
- // TODO: use correct scale direction, stroke
+ // TODO(F1): use correct scale direction, stroke
// width might be height or anything else
const Size aSize( aStroke.getStrokeWidth(), 0 );
@@ -608,7 +1544,7 @@ namespace cppcanvas
// Handle drawing layer fills
else if( pAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
{
- // TODO: Later
+ // TODO(F1): Later
#if 0
const BYTE* pData = pAct->GetData();
if ( pData )
@@ -695,49 +1631,61 @@ namespace cppcanvas
case META_POINT_ACTION:
{
- maActions.push_back(
- MtfAction(
- ActionSharedPtr(
- new internal::PointAction(
- rVDev.LogicToPixel( static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ),
- rCanvas,
- getState( rStates ) ) ),
- nCurrActionIndex ) );
+ const OutDevState& rState( getState( rStates ) );
+ if( rState.lineColor.getLength() )
+ {
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::PointAction(
+ rVDev.LogicToPixel( static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ),
+ rCanvas,
+ rState ) ),
+ io_rCurrActionIndex ) );
+ }
}
break;
case META_PIXEL_ACTION:
{
- maActions.push_back(
- MtfAction(
- ActionSharedPtr(
- new internal::PointAction(
- rVDev.LogicToPixel(
- static_cast<MetaPixelAction*>(pCurrAct)->GetPoint() ),
- rCanvas,
- getState( rStates ),
- static_cast<MetaPixelAction*>(pCurrAct)->GetColor() ) ),
- nCurrActionIndex ) );
+ const OutDevState& rState( getState( rStates ) );
+ if( rState.lineColor.getLength() )
+ {
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::PointAction(
+ rVDev.LogicToPixel(
+ static_cast<MetaPixelAction*>(pCurrAct)->GetPoint() ),
+ rCanvas,
+ rState,
+ static_cast<MetaPixelAction*>(pCurrAct)->GetColor() ) ),
+ io_rCurrActionIndex ) );
+ }
}
break;
case META_LINE_ACTION:
{
- maActions.push_back(
- MtfAction(
- ActionSharedPtr(
- new internal::LineAction(
- rVDev.LogicToPixel( static_cast<MetaLineAction*>(pCurrAct)->GetStartPoint() ),
- rVDev.LogicToPixel( static_cast<MetaLineAction*>(pCurrAct)->GetEndPoint() ),
- rCanvas,
- getState( rStates ) ) ),
- nCurrActionIndex ) );
+ const OutDevState& rState( getState( rStates ) );
+ if( rState.lineColor.getLength() )
+ {
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::LineAction(
+ rVDev.LogicToPixel( static_cast<MetaLineAction*>(pCurrAct)->GetStartPoint() ),
+ rVDev.LogicToPixel( static_cast<MetaLineAction*>(pCurrAct)->GetEndPoint() ),
+ rCanvas,
+ rState ) ),
+ io_rCurrActionIndex ) );
+ }
}
break;
case META_RECT_ACTION:
createFillAndStroke( ::PolyPolygon( ::Polygon( rVDev.LogicToPixel( static_cast<MetaRectAction*>(pCurrAct)->GetRect() ) ) ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
@@ -745,7 +1693,7 @@ namespace cppcanvas
createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaRoundRectAction*>(pCurrAct)->GetRect(),
static_cast<MetaRoundRectAction*>(pCurrAct)->GetHorzRound(),
static_cast<MetaRoundRectAction*>(pCurrAct)->GetVertRound() ) ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
@@ -755,7 +1703,7 @@ namespace cppcanvas
createFillAndStroke( rVDev.LogicToPixel( Polygon( rRect.Center(),
rRect.GetWidth() >> 1,
rRect.GetHeight() >> 1 ) ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
}
@@ -764,7 +1712,7 @@ namespace cppcanvas
createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaArcAction*>(pCurrAct)->GetRect(),
static_cast<MetaArcAction*>(pCurrAct)->GetStartPoint(),
static_cast<MetaArcAction*>(pCurrAct)->GetEndPoint(), POLY_ARC ) ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
@@ -772,7 +1720,7 @@ namespace cppcanvas
createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaPieAction*>(pCurrAct)->GetRect(),
static_cast<MetaPieAction*>(pCurrAct)->GetStartPoint(),
static_cast<MetaPieAction*>(pCurrAct)->GetEndPoint(), POLY_PIE ) ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
@@ -780,33 +1728,38 @@ namespace cppcanvas
createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaChordAction*>(pCurrAct)->GetRect(),
static_cast<MetaChordAction*>(pCurrAct)->GetStartPoint(),
static_cast<MetaChordAction*>(pCurrAct)->GetEndPoint(), POLY_CHORD ) ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
case META_POLYLINE_ACTION:
{
- maActions.push_back(
- MtfAction(
- ActionSharedPtr(
- new internal::PolyPolyAction(
- rVDev.LogicToPixel( static_cast<MetaPolyLineAction*>(pCurrAct)->GetPolygon() ),
- rCanvas,
- getState( rStates ),
- internal::PolyPolyAction::strokeOnly ) ),
- nCurrActionIndex ) );
+ const OutDevState& rState( getState( rStates ) );
+ if( rState.lineColor.getLength() ||
+ rState.fillColor.getLength() )
+ {
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::PolyPolyAction(
+ rVDev.LogicToPixel( static_cast<MetaPolyLineAction*>(pCurrAct)->GetPolygon() ),
+ rCanvas,
+ rState,
+ internal::PolyPolyAction::strokeOnly ) ),
+ io_rCurrActionIndex ) );
+ }
}
break;
case META_POLYGON_ACTION:
createFillAndStroke( rVDev.LogicToPixel( static_cast<MetaPolygonAction*>(pCurrAct)->GetPolygon() ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
case META_POLYPOLYGON_ACTION:
createFillAndStroke( rVDev.LogicToPixel( static_cast<MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon() ),
- rCanvas, nCurrActionIndex,
+ rCanvas, io_rCurrActionIndex,
rStates );
break;
@@ -822,7 +1775,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetPoint() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -839,7 +1792,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetSize() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -858,7 +1811,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetDestSize() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -874,7 +1827,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetPoint() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -891,7 +1844,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetSize() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -910,7 +1863,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetDestSize() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -918,7 +1871,7 @@ namespace cppcanvas
{
MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pCurrAct);
- // TODO: masking NYI. Further members: mask color
+ // TODO(F2): masking NYI. Further members: mask color
maActions.push_back(
MtfAction(
ActionSharedPtr(
@@ -927,7 +1880,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetPoint() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -935,7 +1888,7 @@ namespace cppcanvas
{
MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pCurrAct);
- // TODO: masking NYI. Further members: mask color
+ // TODO(F2): masking NYI. Further members: mask color
maActions.push_back(
MtfAction(
ActionSharedPtr(
@@ -945,7 +1898,7 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetSize() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
@@ -953,7 +1906,7 @@ namespace cppcanvas
{
MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pCurrAct);
- // TODO: masking NYI. Further members: mask color
+ // TODO(F2): masking NYI. Further members: mask color
maActions.push_back(
MtfAction(
ActionSharedPtr(
@@ -965,95 +1918,124 @@ namespace cppcanvas
rVDev.LogicToPixel( pAct->GetDestSize() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
}
break;
case META_GRADIENTEX_ACTION:
- // TODO: use native Canvas gradients here
+ // TODO(F1): use native Canvas gradients here
// action is ignored here, because redundant to META_GRADIENT_ACTION
break;
case META_WALLPAPER_ACTION:
- // TODO: NYI
+ // TODO(F2): NYI
break;
case META_TRANSPARENT_ACTION:
{
- MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pCurrAct);
-
- maActions.push_back(
- MtfAction(
- ActionSharedPtr(
- new internal::PolyPolyAction(
- rVDev.LogicToPixel( pAct->GetPolyPolygon() ),
- rCanvas,
- getState( rStates ),
- pAct->GetTransparence() ) ),
- nCurrActionIndex ) );
- }
+ const OutDevState& rState( getState( rStates ) );
+ if( rState.lineColor.getLength() ||
+ rState.fillColor.getLength() )
+ {
+ MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pCurrAct);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::PolyPolyAction(
+ rVDev.LogicToPixel( pAct->GetPolyPolygon() ),
+ rCanvas,
+ rState,
+ pAct->GetTransparence() ) ),
+ io_rCurrActionIndex ) );
+ }
+ }
break;
case META_FLOATTRANSPARENT_ACTION:
- // TODO: NYI. This has to be rendered into a separate bitmap canvas
- break;
-
- case META_TEXT_ACTION:
{
- MetaTextAction* pAct = static_cast<MetaTextAction*>(pCurrAct);
+ MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pCurrAct);
+
+ internal::MtfAutoPtr pMtf(
+ new ::GDIMetaFile( pAct->GetGDIMetaFile() ) );
+
+ // TODO(P2): Use native canvas gradients here (saves a lot of UNO calls)
+ internal::GradientAutoPtr pGradient(
+ new Gradient( pAct->GetGradient() ) );
+
+ DBG_TESTSOLARMUTEX();
maActions.push_back(
MtfAction(
ActionSharedPtr(
- new internal::TextAction(
- rVDev.LogicToPixel(pAct->GetPoint()),
- pAct->GetText(),
- pAct->GetIndex(),
- pAct->GetLen(),
+ new internal::TransparencyGroupAction(
+ pMtf,
+ pGradient,
+ rParms,
+ rVDev.LogicToPixel( pAct->GetPoint() ),
+ rVDev.LogicToPixel( pAct->GetSize() ),
rCanvas,
getState( rStates ) ) ),
- nCurrActionIndex ) );
+ io_rCurrActionIndex ) );
+ }
+ break;
+
+ case META_TEXT_ACTION:
+ {
+ MetaTextAction* pAct = static_cast<MetaTextAction*>(pCurrAct);
+ createTextWithEffectsAction(
+ pAct->GetPoint(),
+ pAct->GetText(),
+ pAct->GetIndex(),
+ pAct->GetLen() == (USHORT)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(),
+ NULL,
+ rVDev,
+ rCanvas,
+ rStates,
+ rParms,
+ io_rCurrActionIndex );
}
break;
case META_TEXTARRAY_ACTION:
{
MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pCurrAct);
+ createTextWithEffectsAction(
+ pAct->GetPoint(),
+ pAct->GetText(),
+ pAct->GetIndex(),
+ pAct->GetLen() == (USHORT)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(),
+ pAct->GetDXArray(),
+ rVDev,
+ rCanvas,
+ rStates,
+ rParms,
+ io_rCurrActionIndex );
+ }
+ break;
- uno::Sequence< double > offsets( ::comphelper::arrayToSequence<long int, double>( pAct->GetDXArray(),
- pAct->GetLen() ) );
-
- // convert offsets to physical
-
- // TODO: use correct scale direction, text advancement
- // might be horizontal, vertical, or anything else
- int i;
- for( i=0; i<offsets.getLength(); ++i )
- {
- const Size aSize( static_cast<long>( offsets[i] + .5 ), 0 );
- offsets[i] = rVDev.LogicToPixel( aSize ).Width();
- }
-
- maActions.push_back(
- MtfAction(
- ActionSharedPtr(
- new internal::TextAction(
- rVDev.LogicToPixel(pAct->GetPoint()),
- pAct->GetText(),
- pAct->GetIndex(),
- pAct->GetLen(),
- offsets,
- rCanvas,
- getState( rStates ) ) ),
- nCurrActionIndex ) );
+ case META_TEXTLINE_ACTION:
+ {
+ MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pCurrAct);
+ createJustTextLinesAction(
+ pAct->GetStartPoint(),
+ pAct->GetWidth(),
+ rVDev,
+ rCanvas,
+ rStates,
+ rParms,
+ io_rCurrActionIndex );
}
break;
case META_TEXTRECT_ACTION:
+ // TODO(F2): NYI
+ DBG_ERROR("META_TEXTRECT not yet supported");
+ break;
+
case META_STRETCHTEXT_ACTION:
- case META_TEXTLINE_ACTION:
- // TODO: NYI
- DBG_ERROR("META_TEXT* not yet supported");
+ // TODO(F2): NYI
+ DBG_ERROR("META_STRETCHTEXT not yet supported");
break;
default:
@@ -1065,10 +2047,13 @@ namespace cppcanvas
}
ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas,
- const GDIMetaFile& rMtf ) :
+ const GDIMetaFile& rMtf,
+ const Parameters& rParams ) :
CanvasGraphicHelper( rCanvas ),
maActions()
{
+ RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(mtf)" );
+
OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(),
"ImplRenderer::ImplRenderer(): Invalid canvas" );
OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(),
@@ -1094,7 +2079,8 @@ namespace cppcanvas
aVDev.SetMapMode( rMtf.GetPrefMapMode() );
- const Size aMtfSizePix( aVDev.LogicToPixel( rMtf.GetPrefSize(),
+ const Size aMtfSize( rMtf.GetPrefSize() );
+ const Size aMtfSizePix( aVDev.LogicToPixel( aMtfSize,
rMtf.GetPrefMapMode() ) );
const Point aEmptyPt;
const Point aMtfOriginPix( aVDev.LogicToPixel( aEmptyPt ) );
@@ -1113,9 +2099,50 @@ namespace cppcanvas
getState( aStateStack ).transform.scale( 1.0 / aMtfSizePix.Width(),
1.0 / aMtfSizePix.Height() );
+ ColorSharedPtr pColor( getCanvas()->createColor() );
+
+ // setup default text color to black
+ getState( aStateStack ).textColor =
+ getState( aStateStack ).textFillColor =
+ getState( aStateStack ).textLineColor = pColor->getDeviceColor( 0x000000FF );
+
+ // apply overrides from the Parameters struct
+ if( rParams.maFillColor.isValid() )
+ {
+ getState( aStateStack ).isFillColorSet = true;
+ getState( aStateStack ).fillColor = pColor->getDeviceColor( rParams.maFillColor.getValue() );
+ }
+ if( rParams.maLineColor.isValid() )
+ {
+ getState( aStateStack ).isLineColorSet = true;
+ getState( aStateStack ).lineColor = pColor->getDeviceColor( rParams.maLineColor.getValue() );
+ }
+ if( rParams.maTextColor.isValid() )
+ {
+ getState( aStateStack ).isTextFillColorSet = true;
+ getState( aStateStack ).isTextLineColorSet = true;
+ getState( aStateStack ).textColor =
+ getState( aStateStack ).textFillColor =
+ getState( aStateStack ).textLineColor = pColor->getDeviceColor( rParams.maTextColor.getValue() );
+ }
+ if( rParams.maFontName.isValid() ||
+ rParams.maFontWeight.isValid() ||
+ rParams.maFontLetterForm.isValid() ||
+ rParams.maFontUnderline.isValid() )
+ {
+ ::cppcanvas::internal::OutDevState& rState = getState( aStateStack );
+
+ rState.xFont = createFont( rState.fontTransform,
+ ::Font(), // default font
+ rCanvas,
+ aVDev,
+ rParams );
+ }
+
+ int nCurrActions(0);
createActions( rCanvas,
aVDev,
- const_cast<GDIMetaFile&>(rMtf), // HACK:
+ const_cast<GDIMetaFile&>(rMtf), // HACK(Q2):
// we're
// changing
// the
@@ -1123,15 +2150,20 @@ namespace cppcanvas
// action
// in
// createActions!
- aStateStack );
+ aStateStack,
+ rParams,
+ nCurrActions );
}
}
ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas,
- const BitmapEx& rBmpEx ) :
+ const BitmapEx& rBmpEx,
+ const Parameters& rParams ) :
CanvasGraphicHelper( rCanvas ),
maActions()
{
+ RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(bitmap)" );
+
OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(),
"ImplRenderer::ImplRenderer(): Invalid canvas" );
OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(),
@@ -1176,7 +2208,8 @@ namespace cppcanvas
class ActionRenderer
{
public:
- ActionRenderer() :
+ ActionRenderer( const ::basegfx::B2DHomMatrix& rTransformation ) :
+ maTransformation( rTransformation ),
mbRet( true )
{
}
@@ -1190,17 +2223,20 @@ namespace cppcanvas
{
// ANDing the result. We want to fail if at least
// one action failed.
- mbRet &= rAction.mpAction->render();
+ mbRet &= rAction.mpAction->render( maTransformation );
}
private:
- bool mbRet;
+ const ::basegfx::B2DHomMatrix maTransformation;
+ bool mbRet;
};
}
bool ImplRenderer::drawSubset( int startIndex,
int endIndex ) const
{
+ RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::draw()" );
+
OSL_ENSURE( startIndex<=endIndex,
"ImplRenderer::draw() invalid action range" );
@@ -1214,13 +2250,21 @@ namespace cppcanvas
MtfAction( ActionSharedPtr(), endIndex ),
ActionIndexComparator() ) );
+ ::basegfx::B2DHomMatrix aMatrix;
+ ::canvas::tools::getRenderStateTransform( aMatrix, maRenderState );
+
// render subset of actions
- return ::std::for_each( aIterBegin, aIterEnd, ActionRenderer() ).result();
+ return ::std::for_each( aIterBegin, aIterEnd, ActionRenderer( aMatrix ) ).result();
}
bool ImplRenderer::draw() const
{
- return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer() ).result();
+ RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::draw()" );
+
+ ::basegfx::B2DHomMatrix aMatrix;
+ ::canvas::tools::getRenderStateTransform( aMatrix, maRenderState );
+
+ return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer( aMatrix ) ).result();
}
}
}