summaryrefslogtreecommitdiff
path: root/cppcanvas/source/mtfrenderer/implrenderer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'cppcanvas/source/mtfrenderer/implrenderer.cxx')
-rw-r--r--cppcanvas/source/mtfrenderer/implrenderer.cxx1226
1 files changed, 1226 insertions, 0 deletions
diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx
new file mode 100644
index 000000000000..f3f50c2e9139
--- /dev/null
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -0,0 +1,1226 @@
+/*************************************************************************
+ *
+ * $RCSfile: implrenderer.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: thb $ $Date: 2004-03-18 10:41:04 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _OSL_MUTEX_HXX_
+#include <osl/mutex.hxx>
+#endif
+#ifndef _VOS_MUTEX_HXX_
+#include <vos/mutex.hxx>
+#endif
+#ifndef _SV_SVAPP_HXX
+#include <vcl/svapp.hxx>
+#endif
+
+#ifndef _COMPHELPER_SEQUENCE_HXX_
+#include <comphelper/sequence.hxx>
+#endif
+
+#include <cppcanvas/canvas.hxx>
+
+#ifndef _VCL_CANVASTOOLS_HXX
+#include <vcl/canvastools.hxx>
+#endif
+#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
+#include <basegfx/tools/canvastools.hxx>
+#endif
+#ifndef _CANVAS_CANVASTOOLS_HXX
+#include <canvas/canvastools.hxx>
+#endif
+
+#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 <vector>
+#include <algorithm>
+
+#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
+#include <com/sun/star/uno/Sequence.hxx>
+#endif
+
+#ifndef _DRAFTS_COM_SUN_STAR_GEOMETRY_REALPOINT2D_HPP__
+#include <drafts/com/sun/star/geometry/RealPoint2D.hpp>
+#endif
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_VIEWSTATE_HPP__
+#include <drafts/com/sun/star/rendering/ViewState.hpp>
+#endif
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_RENDERSTATE_HPP__
+#include <drafts/com/sun/star/rendering/RenderState.hpp>
+#endif
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XCANVASFONT_HPP__
+#include <drafts/com/sun/star/rendering/XCanvasFont.hpp>
+#endif
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XPOLYPOLYGON2D_HPP__
+#include <drafts/com/sun/star/rendering/XPolyPolygon2D.hpp>
+#endif
+#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XCANVAS_HPP__
+#include <drafts/com/sun/star/rendering/XCanvas.hpp>
+#endif
+
+#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#endif
+
+#ifndef _SV_GDIMTF_HXX
+#include <vcl/gdimtf.hxx>
+#endif
+
+#ifndef _SV_METAACT_HXX
+#include <vcl/metaact.hxx>
+#endif
+
+#ifndef _SV_VIRDEV_HXX
+#include <vcl/virdev.hxx>
+#endif
+
+#ifndef _TL_POLY_HXX
+#include <tools/poly.hxx>
+#endif
+
+#include "outdevstate.hxx"
+
+
+using namespace ::drafts::com::sun::star;
+using namespace ::com::sun::star;
+
+
+// free support functions
+// ======================
+namespace
+{
+ template < class MetaActionType > void setStateColor( MetaActionType* pAct,
+ bool& rIsColorSet,
+ uno::Sequence< double >& rColorSequence,
+ const cppcanvas::CanvasSharedPtr& rCanvas )
+ {
+ // set rIsColorSet and check for true at the same time
+ if( (rIsColorSet=pAct->IsSetting()) )
+ {
+ ::Color aColor( pAct->GetColor() );
+
+ // force alpha part of color to
+ // opaque. transparent painting is done
+ // explicitely via META_TRANSPARENT_ACTION
+ aColor.SetTransparency(0);
+ //aColor.SetTransparency(128);
+
+ rColorSequence = ::vcl::unotools::colorToDoubleSequence( rCanvas->getUNOCanvas()->getDevice(),
+ aColor );
+ }
+ }
+
+ // Doing that via inline class. Compilers tend to not inline free
+ // functions.
+ class ActionIndexComparator
+ {
+ public:
+ ActionIndexComparator() {}
+
+ bool operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rLHS,
+ const ::cppcanvas::internal::ImplRenderer::MtfAction& rRHS )
+ {
+ return rLHS.mnOrigIndex < rRHS.mnOrigIndex;
+ }
+ };
+
+ // state stack manipulators
+ // ------------------------
+ void clearStateStack( ::cppcanvas::internal::VectorOfOutDevStates& rStates )
+ {
+ rStates.clear();
+ const ::cppcanvas::internal::OutDevState aDefaultState;
+ rStates.push_back( aDefaultState );
+ }
+
+ ::cppcanvas::internal::OutDevState& getState( ::cppcanvas::internal::VectorOfOutDevStates& rStates )
+ {
+ return rStates.back();
+ }
+
+ void pushState( ::cppcanvas::internal::VectorOfOutDevStates& rStates )
+ {
+ rStates.push_back( getState( rStates ) );
+ }
+
+ void popState( ::cppcanvas::internal::VectorOfOutDevStates& rStates )
+ {
+ rStates.pop_back();
+ }
+
+}
+
+
+namespace cppcanvas
+{
+ namespace internal
+ {
+ bool ImplRenderer::createFillAndStroke( const ::PolyPolygon& rPolyPoly,
+ const CanvasSharedPtr& rCanvas,
+ int rActionIndex,
+ VectorOfOutDevStates& rStates )
+ {
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::PolyPolyAction( rPolyPoly, rCanvas, getState( rStates ) ) ),
+ rActionIndex ) );
+
+ return true;
+ }
+
+ void ImplRenderer::skipContent( GDIMetaFile& rMtf,
+ const char& rCommentString ) const
+ {
+ MetaAction* pCurrAct;
+ while( (pCurrAct=rMtf.NextAction()) )
+ {
+ if( pCurrAct->GetType() == META_COMMENT_ACTION &&
+ static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( rCommentString ) == COMPARE_EQUAL )
+ {
+ // requested comment found, done
+ return;
+ }
+ }
+
+ // EOF
+ return;
+ }
+
+ void ImplRenderer::createGradientAction( const Rectangle& rRect,
+ const Gradient& rGradient,
+ VirtualDevice& rVDev,
+ const CanvasSharedPtr& rCanvas,
+ VectorOfOutDevStates& rStates )
+ {
+ DBG_TESTSOLARMUTEX();
+
+ // TODO: Use native canvas gradients here (saves a lot of UNO calls)
+ GDIMetaFile aTmpMtf;
+
+ rVDev.AddGradientActions( rRect,
+ rGradient,
+ aTmpMtf );
+
+ pushState( rStates );
+ createActions( rCanvas, rVDev, aTmpMtf, rStates );
+ popState( rStates );
+ }
+
+ bool ImplRenderer::createActions( const CanvasSharedPtr& rCanvas,
+ VirtualDevice& rVDev,
+ GDIMetaFile& rMtf,
+ VectorOfOutDevStates& rStates )
+ {
+ /* TODO:
+ =====
+
+ - 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
+ recalc scaling for every drawing operation. This is
+ because the outdev map mode might change at any time.
+
+ */
+
+ // Loop over every metaaction
+ // ==========================
+ MetaAction* pCurrAct;
+ int nCurrActionIndex;
+
+ // TODO: think about caching
+ for( nCurrActionIndex=0, pCurrAct=rMtf.FirstAction();
+ pCurrAct;
+ ++nCurrActionIndex, 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)
+ pCurrAct->Execute( &rVDev );
+
+ switch( pCurrAct->GetType() )
+ {
+ // ------------------------------------------------------------
+
+ // In the first part of this monster-switch, we
+ // handle all state-changing meta actions. These
+ // are all handled locally.
+
+ // ------------------------------------------------------------
+
+ case META_PUSH_ACTION:
+ pushState( rStates );
+ break;
+
+ case META_POP_ACTION:
+ popState( rStates );
+ break;
+
+ // monitor clip regions, to assemble clip polygon on our own
+ case META_CLIPREGION_ACTION:
+ case META_ISECTRECTCLIPREGION_ACTION:
+ case META_ISECTREGIONCLIPREGION_ACTION:
+ case META_MOVECLIPREGION_ACTION:
+ // TODO: NYI
+ break;
+
+ case META_LINECOLOR_ACTION:
+ 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 );
+ 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 );
+ }
+ break;
+
+ case META_TEXTFILLCOLOR_ACTION:
+ 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 );
+ break;
+
+ case META_TEXTALIGN_ACTION:
+ // TODO: NYI
+ break;
+
+ case META_FONT_ACTION:
+ {
+ // TODO: For now, only dummy implementation
+ rendering::FontRequest aFontRequest;
+ 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 );
+ }
+ break;
+
+ case META_RASTEROP_ACTION:
+ // TODO: NYI
+ break;
+
+ case META_REFPOINT_ACTION:
+ // TODO: NYI
+ break;
+
+ case META_LAYOUTMODE_ACTION:
+ {
+ // TODO: A lot is missing here
+ switch( static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode() )
+ {
+ case TEXT_LAYOUT_BIDI_RTL:
+ case TEXT_LAYOUT_TEXTORIGIN_RIGHT:
+ getState( rStates ).textDirection = rendering::TextDirection::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;
+ break;
+ }
+ }
+ break;
+
+ // ------------------------------------------------------------
+
+ // In the second part of this monster-switch, we
+ // handle all recursing meta actions. These are the
+ // ones generating a metafile by themselves, which is
+ // then processed by recursively calling this method.
+
+ // ------------------------------------------------------------
+
+ case META_GRADIENT_ACTION:
+ {
+ MetaGradientAction* pGradAct = static_cast<MetaGradientAction*>(pCurrAct);
+ createGradientAction( pGradAct->GetRect(),
+ pGradAct->GetGradient(),
+ rVDev,
+ rCanvas,
+ rStates );
+ }
+ break;
+
+ case META_HATCH_ACTION:
+ {
+ // TODO: 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 );
+ }
+ break;
+
+ case META_EPS_ACTION:
+ {
+ MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pCurrAct);
+ const GDIMetaFile& pSubstitute = pAct->GetSubstitute();
+
+ const Size aMtfSizePix( rVDev.LogicToPixel( pSubstitute.GetPrefSize(),
+ pSubstitute.GetPrefMapMode() ) );
+
+ // skip null-sized output
+ if( aMtfSizePix.Width() != 0 &&
+ aMtfSizePix.Height() != 0 )
+ {
+ const Point aEmptyPt;
+ const Point aMtfOriginPix( rVDev.LogicToPixel( aEmptyPt,
+ pSubstitute.GetPrefMapMode() ) );
+
+ // Setup local transform, such that the
+ // metafile renders itself into the given
+ // output rectangle
+ pushState( rStates );
+
+ getState( rStates ).transform.translate( -aMtfOriginPix.X(), -aMtfOriginPix.Y() );
+ getState( rStates ).transform.scale( 1.0 / aMtfSizePix.Width(),
+ 1.0 / aMtfSizePix.Height() );
+
+ createActions( rCanvas, rVDev,
+ const_cast<GDIMetaFile&>(pAct->GetSubstitute()),
+ rStates );
+
+ popState( rStates );
+ }
+ }
+ break;
+
+ // handle metafile comments, to retrieve
+ // meta-information for gradients, fills and
+ // strokes. May skip actions, and may recurse.
+ case META_COMMENT_ACTION:
+ {
+ MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
+
+ // Handle gradients
+ if ( pAct->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL )
+ {
+ MetaGradientExAction* pGradAction = NULL;
+ bool bDone( false );
+ while( !bDone &&
+ (pCurrAct=rMtf.NextAction()) )
+ {
+ switch( pCurrAct->GetType() )
+ {
+ // extract gradient info
+ case META_GRADIENTEX_ACTION:
+ pGradAction = static_cast<MetaGradientExAction*>(pCurrAct);
+ break;
+
+ // skip broken-down rendering, output gradient when sequence is ended
+ case META_COMMENT_ACTION:
+ if( static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL )
+ {
+ bDone = true;
+
+ 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(),
+ pGradAction->GetGradient(),
+ rVDev,
+ rCanvas,
+ rStates );
+
+ popState( rStates );
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // Handle drawing layer strokes
+ else if( pAct->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" ) )
+ {
+ // TODO: Later
+#if 0
+ const BYTE* pData = pAct->GetData();
+ if ( pData )
+ {
+ SvMemoryStream aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
+
+ SvtGraphicStroke aStroke;
+ aMemStm >> aStroke;
+
+ // TODO: respect exceptions, like
+ // start/end arrows and joins not
+ // displayable via Canvas
+
+ // TODO: use correct scale direction, stroke
+ // width might be height or anything else
+ const Size aSize( aStroke.getStrokeWidth(), 0 );
+
+ internal::StrokeAction aStrokeAction( rVDev.LogicToPixel( aStroke.getPath() ),
+ aStroke.getTransparency(),
+ rVDev.LogicToPixel( aSize ).Width(),
+ aStroke.getJoinType(),
+ aStroke.getDashArray(),
+ aStroke.getMiterLimit(),
+ aStroke.getCapType(),
+ rCanvas,
+ getState( rStates ) );
+
+ aStrokeAction.render( rViewState );
+
+ // skip broken-down render output
+ skipContent( rMtf, "XPATHSTROKE_SEQ_END" );
+ }
+#endif
+ }
+
+ // Handle drawing layer fills
+ else if( pAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
+ {
+ // TODO: Later
+#if 0
+ const BYTE* pData = pAct->GetData();
+ if ( pData )
+ {
+ SvMemoryStream aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
+
+ SvtGraphicFill aFill;
+ aMemStm >> aFill;
+
+ switch( aFill.getType() )
+ {
+ case SvtGraphicFill::fillSolid:
+ {
+ internal::SolidFillAction aFillAction( rVDev.LogicToPixel( aFill.getPath() ),
+ aFill.getFillColor(),
+ aFill.getTransparency(),
+ aFill.getFillRule(),
+ rCanvas,
+ getState( rStates ) );
+ aFillAction.render( rViewState );
+ }
+ break;
+
+ case SvtGraphicFill::fillGradient:
+ {
+ internal::GradientFillAction aFillAction( rVDev.LogicToPixel( aFill.getPath() ),
+ aFill.getTransparency(),
+ aFill.getFillRule(),
+ aFill.getTransform(),
+ aFill.getGradientType(),
+ aFill.getGradient1stColor(),
+ aFill.getGradient2ndColor(),
+ aFill.getGradientStepCount(),
+ rCanvas,
+ getState( rStates ) );
+ aFillAction.render( rViewState );
+ }
+ break;
+
+ case SvtGraphicFill::fillHatch:
+ {
+ internal::HatchedFillAction aFillAction( rVDev.LogicToPixel( aFill.getPath() ),
+ aFill.getTransparency(),
+ aFill.getFillRule(),
+ aFill.getTransform(),
+ aFill.getHatchType(),
+ aFill.getHatchColor(),
+ rCanvas,
+ getState( rStates ) );
+ aFillAction.render( rViewState );
+ }
+ break;
+
+ case SvtGraphicFill::fillTexture:
+ {
+ internal::BitmapFillAction aFillAction( rVDev.LogicToPixel( aFill.getPath() ),
+ aFill.getTransparency(),
+ aFill.getFillRule(),
+ aFill.getTransform(),
+ aFill.getFillGraphic(),
+ rCanvas,
+ getState( rStates ) );
+ aFillAction.render( rViewState );
+ }
+ break;
+ }
+
+ // skip broken-down render output
+ skipContent( rMtf, "XPATHFILL_SEQ_END" );
+ }
+#endif
+ }
+ }
+ break;
+
+ // ------------------------------------------------------------
+
+ // In the third part of this monster-switch, we
+ // handle all 'acting' meta actions. These are all
+ // processed by constructing function objects for
+ // them, which will later ease caching.
+
+ // ------------------------------------------------------------
+
+ case META_POINT_ACTION:
+ {
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::PointAction(
+ rVDev.LogicToPixel( static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ 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 ) );
+ }
+ 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 ) );
+ }
+ break;
+
+ case META_RECT_ACTION:
+ createFillAndStroke( ::PolyPolygon( ::Polygon( rVDev.LogicToPixel( static_cast<MetaRectAction*>(pCurrAct)->GetRect() ) ) ),
+ rCanvas, nCurrActionIndex,
+ rStates );
+ break;
+
+ case META_ROUNDRECT_ACTION:
+ createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaRoundRectAction*>(pCurrAct)->GetRect(),
+ static_cast<MetaRoundRectAction*>(pCurrAct)->GetHorzRound(),
+ static_cast<MetaRoundRectAction*>(pCurrAct)->GetVertRound() ) ),
+ rCanvas, nCurrActionIndex,
+ rStates );
+ break;
+
+ case META_ELLIPSE_ACTION:
+ {
+ const Rectangle& rRect = static_cast<MetaEllipseAction*>(pCurrAct)->GetRect();
+ createFillAndStroke( rVDev.LogicToPixel( Polygon( rRect.Center(),
+ rRect.GetWidth() >> 1,
+ rRect.GetHeight() >> 1 ) ),
+ rCanvas, nCurrActionIndex,
+ rStates );
+ break;
+ }
+
+ case META_ARC_ACTION:
+ createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaArcAction*>(pCurrAct)->GetRect(),
+ static_cast<MetaArcAction*>(pCurrAct)->GetStartPoint(),
+ static_cast<MetaArcAction*>(pCurrAct)->GetEndPoint(), POLY_ARC ) ),
+ rCanvas, nCurrActionIndex,
+ rStates );
+ break;
+
+ case META_PIE_ACTION:
+ createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaPieAction*>(pCurrAct)->GetRect(),
+ static_cast<MetaPieAction*>(pCurrAct)->GetStartPoint(),
+ static_cast<MetaPieAction*>(pCurrAct)->GetEndPoint(), POLY_PIE ) ),
+ rCanvas, nCurrActionIndex,
+ rStates );
+ break;
+
+ case META_CHORD_ACTION:
+ createFillAndStroke( rVDev.LogicToPixel( Polygon( static_cast<MetaChordAction*>(pCurrAct)->GetRect(),
+ static_cast<MetaChordAction*>(pCurrAct)->GetStartPoint(),
+ static_cast<MetaChordAction*>(pCurrAct)->GetEndPoint(), POLY_CHORD ) ),
+ rCanvas, nCurrActionIndex,
+ 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 ) );
+ }
+ break;
+
+ case META_POLYGON_ACTION:
+ createFillAndStroke( rVDev.LogicToPixel( static_cast<MetaPolygonAction*>(pCurrAct)->GetPolygon() ),
+ rCanvas, nCurrActionIndex,
+ rStates );
+ break;
+
+ case META_POLYPOLYGON_ACTION:
+ createFillAndStroke( rVDev.LogicToPixel( static_cast<MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon() ),
+ rCanvas, nCurrActionIndex,
+ rStates );
+ break;
+
+ case META_BMP_ACTION:
+ {
+ MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pCurrAct);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmap(),
+ rVDev.LogicToPixel( pAct->GetPoint() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_BMPSCALE_ACTION:
+ {
+ MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pCurrAct);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmap(),
+ rVDev.LogicToPixel( pAct->GetPoint() ),
+ rVDev.LogicToPixel( pAct->GetSize() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_BMPSCALEPART_ACTION:
+ {
+ MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pCurrAct);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmap(),
+ pAct->GetSrcPoint(),
+ pAct->GetSrcSize(),
+ rVDev.LogicToPixel( pAct->GetDestPoint() ),
+ rVDev.LogicToPixel( pAct->GetDestSize() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_BMPEX_ACTION:
+ {
+ MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pCurrAct);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmapEx(),
+ rVDev.LogicToPixel( pAct->GetPoint() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_BMPEXSCALE_ACTION:
+ {
+ MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pCurrAct);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmapEx(),
+ rVDev.LogicToPixel( pAct->GetPoint() ),
+ rVDev.LogicToPixel( pAct->GetSize() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_BMPEXSCALEPART_ACTION:
+ {
+ MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pCurrAct);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmapEx(),
+ pAct->GetSrcPoint(),
+ pAct->GetSrcSize(),
+ rVDev.LogicToPixel( pAct->GetDestPoint() ),
+ rVDev.LogicToPixel( pAct->GetDestSize() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_MASK_ACTION:
+ {
+ MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pCurrAct);
+
+ // TODO: masking NYI. Further members: mask color
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmap(),
+ rVDev.LogicToPixel( pAct->GetPoint() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_MASKSCALE_ACTION:
+ {
+ MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pCurrAct);
+
+ // TODO: masking NYI. Further members: mask color
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmap(),
+ rVDev.LogicToPixel( pAct->GetPoint() ),
+ rVDev.LogicToPixel( pAct->GetSize() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_MASKSCALEPART_ACTION:
+ {
+ MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pCurrAct);
+
+ // TODO: masking NYI. Further members: mask color
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::BitmapAction(
+ pAct->GetBitmap(),
+ pAct->GetSrcPoint(),
+ pAct->GetSrcSize(),
+ rVDev.LogicToPixel( pAct->GetDestPoint() ),
+ rVDev.LogicToPixel( pAct->GetDestSize() ),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_GRADIENTEX_ACTION:
+ // TODO: use native Canvas gradients here
+ // action is ignored here, because redundant to META_GRADIENT_ACTION
+ break;
+
+ case META_WALLPAPER_ACTION:
+ // TODO: 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 ) );
+ }
+ 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);
+
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr(
+ new internal::TextAction(
+ rVDev.LogicToPixel(pAct->GetPoint()),
+ pAct->GetText(),
+ pAct->GetIndex(),
+ pAct->GetLen(),
+ rCanvas,
+ getState( rStates ) ) ),
+ nCurrActionIndex ) );
+ }
+ break;
+
+ case META_TEXTARRAY_ACTION:
+ {
+ MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pCurrAct);
+
+ 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 ) );
+ }
+ break;
+
+ case META_TEXTRECT_ACTION:
+ case META_STRETCHTEXT_ACTION:
+ case META_TEXTLINE_ACTION:
+ // TODO: NYI
+ DBG_ERROR("META_TEXT* not yet supported");
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas,
+ const GDIMetaFile& rMtf ) :
+ CanvasGraphicHelper( rCanvas ),
+ maActions()
+ {
+ OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(),
+ "ImplRenderer::ImplRenderer(): Invalid canvas" );
+ OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(),
+ "ImplRenderer::ImplRenderer(): Invalid graphic device" );
+
+ // make sure canvas and graphic device are valid; action
+ // creation don't check that every time
+ if( rCanvas.get() == NULL ||
+ !rCanvas->getUNOCanvas().is() ||
+ !rCanvas->getUNOCanvas()->getDevice().is() )
+ {
+ // leave actions empty
+ return;
+ }
+
+ VectorOfOutDevStates aStateStack;
+
+ VirtualDevice aVDev;
+ aVDev.EnableOutput( FALSE );
+
+ // Setup VDev for state tracking and mapping
+ // =========================================
+
+ aVDev.SetMapMode( rMtf.GetPrefMapMode() );
+
+ const Size aMtfSizePix( aVDev.LogicToPixel( rMtf.GetPrefSize(),
+ rMtf.GetPrefMapMode() ) );
+ const Point aEmptyPt;
+ const Point aMtfOriginPix( aVDev.LogicToPixel( aEmptyPt ) );
+
+ // skip null-sized output
+ if( aMtfSizePix.Width() != 0 &&
+ aMtfSizePix.Height() != 0 )
+ {
+ // init state stack
+ clearStateStack( aStateStack );
+
+ // Setup local state, such that the metafile renders
+ // itself into a one-by-one square for identity view
+ // and render transformations
+ getState( aStateStack ).transform.translate( -aMtfOriginPix.X(), -aMtfOriginPix.Y() );
+ getState( aStateStack ).transform.scale( 1.0 / aMtfSizePix.Width(),
+ 1.0 / aMtfSizePix.Height() );
+
+ createActions( rCanvas,
+ aVDev,
+ const_cast<GDIMetaFile&>(rMtf), // HACK:
+ // we're
+ // changing
+ // the
+ // current
+ // action
+ // in
+ // createActions!
+ aStateStack );
+ }
+ }
+
+ ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas,
+ const BitmapEx& rBmpEx ) :
+ CanvasGraphicHelper( rCanvas ),
+ maActions()
+ {
+ OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(),
+ "ImplRenderer::ImplRenderer(): Invalid canvas" );
+ OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(),
+ "ImplRenderer::ImplRenderer(): Invalid graphic device" );
+
+ // make sure canvas and graphic device are valid; action
+ // creation don't check that every time
+ if( rCanvas.get() == NULL ||
+ !rCanvas->getUNOCanvas().is() ||
+ !rCanvas->getUNOCanvas()->getDevice().is() )
+ {
+ // leave actions empty
+ return;
+ }
+
+ OutDevState aState;
+
+ const Size aBmpSize( rBmpEx.GetSizePixel() );
+
+ // Setup local state, such that the bitmap renders itself
+ // into a one-by-one square for identity view and render
+ // transformations
+ aState.transform.scale( 1.0 / aBmpSize.Width(),
+ 1.0 / aBmpSize.Height() );
+
+ // create a single action for the provided BitmapEx
+ maActions.push_back(
+ MtfAction(
+ ActionSharedPtr( new BitmapAction(rBmpEx,
+ Point(),
+ rCanvas,
+ aState) ),
+ 0 ) );
+ }
+
+ ImplRenderer::~ImplRenderer()
+ {
+ }
+
+ namespace
+ {
+ class ActionRenderer
+ {
+ public:
+ ActionRenderer() :
+ mbRet( true )
+ {
+ }
+
+ bool result()
+ {
+ return mbRet;
+ }
+
+ void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction )
+ {
+ // ANDing the result. We want to fail if at least
+ // one action failed.
+ mbRet &= rAction.mpAction->render();
+ }
+
+ private:
+ bool mbRet;
+ };
+ }
+
+ bool ImplRenderer::drawSubset( int startIndex,
+ int endIndex ) const
+ {
+ OSL_ENSURE( startIndex<=endIndex,
+ "ImplRenderer::draw() invalid action range" );
+
+ // find start and end action
+ ActionVector::const_iterator aIterBegin( ::std::lower_bound( maActions.begin(),
+ maActions.end(),
+ MtfAction( ActionSharedPtr(), startIndex ),
+ ActionIndexComparator() ) );
+ ActionVector::const_iterator aIterEnd( ::std::lower_bound( maActions.begin(),
+ maActions.end(),
+ MtfAction( ActionSharedPtr(), endIndex ),
+ ActionIndexComparator() ) );
+
+ // render subset of actions
+ return ::std::for_each( aIterBegin, aIterEnd, ActionRenderer() ).result();
+ }
+
+ bool ImplRenderer::draw() const
+ {
+ return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer() ).result();
+ }
+ }
+}