125b11142SAndrew Rist /************************************************************** 225b11142SAndrew Rist * 325b11142SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 425b11142SAndrew Rist * or more contributor license agreements. See the NOTICE file 525b11142SAndrew Rist * distributed with this work for additional information 625b11142SAndrew Rist * regarding copyright ownership. The ASF licenses this file 725b11142SAndrew Rist * to you under the Apache License, Version 2.0 (the 825b11142SAndrew Rist * "License"); you may not use this file except in compliance 925b11142SAndrew Rist * with the License. You may obtain a copy of the License at 1025b11142SAndrew Rist * 1125b11142SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 1225b11142SAndrew Rist * 1325b11142SAndrew Rist * Unless required by applicable law or agreed to in writing, 1425b11142SAndrew Rist * software distributed under the License is distributed on an 1525b11142SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1625b11142SAndrew Rist * KIND, either express or implied. See the License for the 1725b11142SAndrew Rist * specific language governing permissions and limitations 1825b11142SAndrew Rist * under the License. 1925b11142SAndrew Rist * 2025b11142SAndrew Rist *************************************************************/ 2125b11142SAndrew Rist 2225b11142SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_cppcanvas.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <canvas/debug.hxx> 28cdf0e10cSrcweir #include <tools/diagnose_ex.h> 29cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 30cdf0e10cSrcweir #include <osl/mutex.hxx> 31cdf0e10cSrcweir #include <vos/mutex.hxx> 32cdf0e10cSrcweir #include <vcl/svapp.hxx> 33cdf0e10cSrcweir #include <rtl/logfile.hxx> 34cdf0e10cSrcweir #include <comphelper/sequence.hxx> 35cdf0e10cSrcweir #include <comphelper/anytostring.hxx> 36cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx> 37cdf0e10cSrcweir #include <cppcanvas/canvas.hxx> 38cdf0e10cSrcweir #include <com/sun/star/rendering/XGraphicDevice.hpp> 39cdf0e10cSrcweir #include <com/sun/star/rendering/TexturingMode.hpp> 40cdf0e10cSrcweir #include <com/sun/star/uno/Sequence.hxx> 41cdf0e10cSrcweir #include <com/sun/star/geometry/RealPoint2D.hpp> 42cdf0e10cSrcweir #include <com/sun/star/rendering/PanoseProportion.hpp> 43cdf0e10cSrcweir #include <com/sun/star/rendering/ViewState.hpp> 44cdf0e10cSrcweir #include <com/sun/star/rendering/RenderState.hpp> 45cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvasFont.hpp> 46cdf0e10cSrcweir #include <com/sun/star/rendering/XPolyPolygon2D.hpp> 47cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvas.hpp> 48cdf0e10cSrcweir #include <com/sun/star/rendering/PathCapType.hpp> 49cdf0e10cSrcweir #include <com/sun/star/rendering/PathJoinType.hpp> 50cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 51cdf0e10cSrcweir #include <basegfx/tools/gradienttools.hxx> 52cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 53cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 54cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 55cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 56cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx> 57cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 58cdf0e10cSrcweir #include <basegfx/vector/b2dsize.hxx> 59cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx> 60cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 61cdf0e10cSrcweir #include <basegfx/tuple/b2dtuple.hxx> 62cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygonclipper.hxx> 63cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx> 64cdf0e10cSrcweir #include <canvas/canvastools.hxx> 65cdf0e10cSrcweir #include <vcl/canvastools.hxx> 66cdf0e10cSrcweir #include <vcl/salbtype.hxx> 67cdf0e10cSrcweir #include <vcl/gdimtf.hxx> 68cdf0e10cSrcweir #include <vcl/metaact.hxx> 69cdf0e10cSrcweir #include <vcl/virdev.hxx> 70cdf0e10cSrcweir #include <vcl/metric.hxx> 71cdf0e10cSrcweir #include <vcl/graphictools.hxx> 72cdf0e10cSrcweir #include <tools/poly.hxx> 73cdf0e10cSrcweir #include <i18npool/mslangid.hxx> 74cdf0e10cSrcweir #include <implrenderer.hxx> 75cdf0e10cSrcweir #include <tools.hxx> 76cdf0e10cSrcweir #include <outdevstate.hxx> 77cdf0e10cSrcweir #include <action.hxx> 78cdf0e10cSrcweir #include <bitmapaction.hxx> 79cdf0e10cSrcweir #include <lineaction.hxx> 80cdf0e10cSrcweir #include <pointaction.hxx> 81cdf0e10cSrcweir #include <polypolyaction.hxx> 82cdf0e10cSrcweir #include <textaction.hxx> 83cdf0e10cSrcweir #include <transparencygroupaction.hxx> 84cdf0e10cSrcweir #include <vector> 85cdf0e10cSrcweir #include <algorithm> 86cdf0e10cSrcweir #include <iterator> 87cdf0e10cSrcweir #include <boost/scoped_array.hpp> 88cdf0e10cSrcweir #include "mtftools.hxx" 89cdf0e10cSrcweir #include "outdevstate.hxx" 90cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx> 91cdf0e10cSrcweir 92cdf0e10cSrcweir 93cdf0e10cSrcweir using namespace ::com::sun::star; 94cdf0e10cSrcweir 95cdf0e10cSrcweir 96cdf0e10cSrcweir // free support functions 97cdf0e10cSrcweir // ====================== 98cdf0e10cSrcweir namespace 99cdf0e10cSrcweir { 100cdf0e10cSrcweir template < class MetaActionType > void setStateColor( MetaActionType* pAct, 101cdf0e10cSrcweir bool& rIsColorSet, 102cdf0e10cSrcweir uno::Sequence< double >& rColorSequence, 103cdf0e10cSrcweir const cppcanvas::CanvasSharedPtr& rCanvas ) 104cdf0e10cSrcweir { 105cdf0e10cSrcweir // set rIsColorSet and check for true at the same time 106cdf0e10cSrcweir if( (rIsColorSet=pAct->IsSetting()) != false ) 107cdf0e10cSrcweir { 108cdf0e10cSrcweir ::Color aColor( pAct->GetColor() ); 109cdf0e10cSrcweir 110cdf0e10cSrcweir // force alpha part of color to 111cdf0e10cSrcweir // opaque. transparent painting is done 112cdf0e10cSrcweir // explicitely via META_TRANSPARENT_ACTION 113cdf0e10cSrcweir aColor.SetTransparency(0); 114cdf0e10cSrcweir //aColor.SetTransparency(128); 115cdf0e10cSrcweir 116cdf0e10cSrcweir rColorSequence = ::vcl::unotools::colorToDoubleSequence( 117cdf0e10cSrcweir aColor, 118cdf0e10cSrcweir rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); 119cdf0e10cSrcweir } 120cdf0e10cSrcweir } 121cdf0e10cSrcweir 122cdf0e10cSrcweir 123cdf0e10cSrcweir // state stack manipulators 124cdf0e10cSrcweir // ------------------------ 125cdf0e10cSrcweir void clearStateStack( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) 126cdf0e10cSrcweir { 127cdf0e10cSrcweir rStates.clear(); 128cdf0e10cSrcweir const ::cppcanvas::internal::OutDevState aDefaultState; 129cdf0e10cSrcweir rStates.push_back( aDefaultState ); 130cdf0e10cSrcweir } 131cdf0e10cSrcweir 132cdf0e10cSrcweir ::cppcanvas::internal::OutDevState& getState( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) 133cdf0e10cSrcweir { 134cdf0e10cSrcweir return rStates.back(); 135cdf0e10cSrcweir } 136cdf0e10cSrcweir 137cdf0e10cSrcweir const ::cppcanvas::internal::OutDevState& getState( const ::cppcanvas::internal::VectorOfOutDevStates& rStates ) 138cdf0e10cSrcweir { 139cdf0e10cSrcweir return rStates.back(); 140cdf0e10cSrcweir } 141cdf0e10cSrcweir 142cdf0e10cSrcweir void pushState( ::cppcanvas::internal::VectorOfOutDevStates& rStates, 143cdf0e10cSrcweir sal_uInt16 nFlags ) 144cdf0e10cSrcweir { 145cdf0e10cSrcweir rStates.push_back( getState( rStates ) ); 146cdf0e10cSrcweir getState( rStates ).pushFlags = nFlags; 147cdf0e10cSrcweir } 148cdf0e10cSrcweir 149cdf0e10cSrcweir void popState( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) 150cdf0e10cSrcweir { 151cdf0e10cSrcweir if( getState( rStates ).pushFlags != PUSH_ALL ) 152cdf0e10cSrcweir { 153cdf0e10cSrcweir // a state is pushed which is incomplete, i.e. does not 154cdf0e10cSrcweir // restore everything to the previous stack level when 155cdf0e10cSrcweir // popped. 156cdf0e10cSrcweir // That means, we take the old state, and restore every 157cdf0e10cSrcweir // OutDevState member whose flag is set, from the new to the 158cdf0e10cSrcweir // old state. Then the new state gets overwritten by the 159cdf0e10cSrcweir // calculated state 160cdf0e10cSrcweir 161cdf0e10cSrcweir // preset to-be-calculated new state with old state 162cdf0e10cSrcweir ::cppcanvas::internal::OutDevState aCalculatedNewState( getState( rStates ) ); 163cdf0e10cSrcweir 164cdf0e10cSrcweir // selectively copy to-be-restored content over saved old 165cdf0e10cSrcweir // state 166cdf0e10cSrcweir rStates.pop_back(); 167cdf0e10cSrcweir 168cdf0e10cSrcweir const ::cppcanvas::internal::OutDevState& rNewState( getState( rStates ) ); 169cdf0e10cSrcweir 170cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_LINECOLOR) ) 171cdf0e10cSrcweir { 172cdf0e10cSrcweir aCalculatedNewState.lineColor = rNewState.lineColor; 173cdf0e10cSrcweir aCalculatedNewState.isLineColorSet = rNewState.isLineColorSet; 174cdf0e10cSrcweir } 175cdf0e10cSrcweir 176cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_FILLCOLOR) ) 177cdf0e10cSrcweir { 178cdf0e10cSrcweir aCalculatedNewState.fillColor = rNewState.fillColor; 179cdf0e10cSrcweir aCalculatedNewState.isFillColorSet = rNewState.isFillColorSet; 180cdf0e10cSrcweir } 181cdf0e10cSrcweir 182cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_FONT) ) 183cdf0e10cSrcweir { 184cdf0e10cSrcweir aCalculatedNewState.xFont = rNewState.xFont; 185cdf0e10cSrcweir aCalculatedNewState.fontRotation = rNewState.fontRotation; 186cdf0e10cSrcweir aCalculatedNewState.textReliefStyle = rNewState.textReliefStyle; 187cdf0e10cSrcweir aCalculatedNewState.textOverlineStyle = rNewState.textOverlineStyle; 188cdf0e10cSrcweir aCalculatedNewState.textUnderlineStyle = rNewState.textUnderlineStyle; 189cdf0e10cSrcweir aCalculatedNewState.textStrikeoutStyle = rNewState.textStrikeoutStyle; 190cdf0e10cSrcweir aCalculatedNewState.textEmphasisMarkStyle = rNewState.textEmphasisMarkStyle; 191cdf0e10cSrcweir aCalculatedNewState.isTextEffectShadowSet = rNewState.isTextEffectShadowSet; 192cdf0e10cSrcweir aCalculatedNewState.isTextWordUnderlineSet = rNewState.isTextWordUnderlineSet; 193cdf0e10cSrcweir aCalculatedNewState.isTextOutlineModeSet = rNewState.isTextOutlineModeSet; 194cdf0e10cSrcweir } 195cdf0e10cSrcweir 196cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_TEXTCOLOR) ) 197cdf0e10cSrcweir { 198cdf0e10cSrcweir aCalculatedNewState.textColor = rNewState.textColor; 199cdf0e10cSrcweir } 200cdf0e10cSrcweir 201cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_MAPMODE) ) 202cdf0e10cSrcweir { 203cdf0e10cSrcweir aCalculatedNewState.mapModeTransform = rNewState.mapModeTransform; 204cdf0e10cSrcweir } 205cdf0e10cSrcweir 206cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_CLIPREGION) ) 207cdf0e10cSrcweir { 208cdf0e10cSrcweir aCalculatedNewState.clip = rNewState.clip; 209cdf0e10cSrcweir aCalculatedNewState.clipRect = rNewState.clipRect; 210cdf0e10cSrcweir aCalculatedNewState.xClipPoly = rNewState.xClipPoly; 211cdf0e10cSrcweir } 212cdf0e10cSrcweir 213cdf0e10cSrcweir // TODO(F2): Raster ops NYI 214cdf0e10cSrcweir // if( (aCalculatedNewState.pushFlags & PUSH_RASTEROP) ) 215cdf0e10cSrcweir // { 216cdf0e10cSrcweir // } 217cdf0e10cSrcweir 218cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_TEXTFILLCOLOR) ) 219cdf0e10cSrcweir { 220cdf0e10cSrcweir aCalculatedNewState.textFillColor = rNewState.textFillColor; 221cdf0e10cSrcweir aCalculatedNewState.isTextFillColorSet = rNewState.isTextFillColorSet; 222cdf0e10cSrcweir } 223cdf0e10cSrcweir 224cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_TEXTALIGN) ) 225cdf0e10cSrcweir { 226cdf0e10cSrcweir aCalculatedNewState.textReferencePoint = rNewState.textReferencePoint; 227cdf0e10cSrcweir } 228cdf0e10cSrcweir 229cdf0e10cSrcweir // TODO(F1): Refpoint handling NYI 230cdf0e10cSrcweir // if( (aCalculatedNewState.pushFlags & PUSH_REFPOINT) ) 231cdf0e10cSrcweir // { 232cdf0e10cSrcweir // } 233cdf0e10cSrcweir 234cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_TEXTLINECOLOR) ) 235cdf0e10cSrcweir { 236cdf0e10cSrcweir aCalculatedNewState.textLineColor = rNewState.textLineColor; 237cdf0e10cSrcweir aCalculatedNewState.isTextLineColorSet = rNewState.isTextLineColorSet; 238cdf0e10cSrcweir } 239cdf0e10cSrcweir 240cdf0e10cSrcweir if( (aCalculatedNewState.pushFlags & PUSH_TEXTLAYOUTMODE) ) 241cdf0e10cSrcweir { 242cdf0e10cSrcweir aCalculatedNewState.textAlignment = rNewState.textAlignment; 243cdf0e10cSrcweir aCalculatedNewState.textDirection = rNewState.textDirection; 244cdf0e10cSrcweir } 245cdf0e10cSrcweir 246cdf0e10cSrcweir // TODO(F2): Text language handling NYI 247cdf0e10cSrcweir // if( (aCalculatedNewState.pushFlags & PUSH_TEXTLANGUAGE) ) 248cdf0e10cSrcweir // { 249cdf0e10cSrcweir // } 250cdf0e10cSrcweir 251cdf0e10cSrcweir // always copy push mode 252cdf0e10cSrcweir aCalculatedNewState.pushFlags = rNewState.pushFlags; 253cdf0e10cSrcweir 254cdf0e10cSrcweir // flush to stack 255cdf0e10cSrcweir getState( rStates ) = aCalculatedNewState; 256cdf0e10cSrcweir } 257cdf0e10cSrcweir else 258cdf0e10cSrcweir { 259cdf0e10cSrcweir rStates.pop_back(); 260cdf0e10cSrcweir } 261cdf0e10cSrcweir } 262cdf0e10cSrcweir 263cdf0e10cSrcweir void setupStrokeAttributes( rendering::StrokeAttributes& o_rStrokeAttributes, 264cdf0e10cSrcweir const ::cppcanvas::internal::ActionFactoryParameters& rParms, 265cdf0e10cSrcweir const LineInfo& rLineInfo ) 266cdf0e10cSrcweir { 267cdf0e10cSrcweir const ::basegfx::B2DSize aWidth( rLineInfo.GetWidth(), 0 ); 268cdf0e10cSrcweir o_rStrokeAttributes.StrokeWidth = 269cdf0e10cSrcweir (getState( rParms.mrStates ).mapModeTransform * aWidth).getX(); 270cdf0e10cSrcweir 271cdf0e10cSrcweir // setup reasonable defaults 272cdf0e10cSrcweir o_rStrokeAttributes.MiterLimit = 15.0; // 1.0 was no good default; GDI+'s limit is 10.0, our's is 15.0 273cdf0e10cSrcweir o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; 274cdf0e10cSrcweir o_rStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; 275cdf0e10cSrcweir 276cdf0e10cSrcweir switch(rLineInfo.GetLineJoin()) 277cdf0e10cSrcweir { 278cdf0e10cSrcweir default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE 279cdf0e10cSrcweir o_rStrokeAttributes.JoinType = rendering::PathJoinType::NONE; 280cdf0e10cSrcweir break; 281cdf0e10cSrcweir case basegfx::B2DLINEJOIN_BEVEL: 282cdf0e10cSrcweir o_rStrokeAttributes.JoinType = rendering::PathJoinType::BEVEL; 283cdf0e10cSrcweir break; 284cdf0e10cSrcweir case basegfx::B2DLINEJOIN_MITER: 285cdf0e10cSrcweir o_rStrokeAttributes.JoinType = rendering::PathJoinType::MITER; 286cdf0e10cSrcweir break; 287cdf0e10cSrcweir case basegfx::B2DLINEJOIN_ROUND: 288cdf0e10cSrcweir o_rStrokeAttributes.JoinType = rendering::PathJoinType::ROUND; 289cdf0e10cSrcweir break; 290cdf0e10cSrcweir } 291cdf0e10cSrcweir 2925aaf853bSArmin Le Grand switch(rLineInfo.GetLineCap()) 2935aaf853bSArmin Le Grand { 2945aaf853bSArmin Le Grand default: /* com::sun::star::drawing::LineCap_BUTT */ 2955aaf853bSArmin Le Grand { 2965aaf853bSArmin Le Grand o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; 2975aaf853bSArmin Le Grand o_rStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; 2985aaf853bSArmin Le Grand break; 2995aaf853bSArmin Le Grand } 3005aaf853bSArmin Le Grand case com::sun::star::drawing::LineCap_ROUND: 3015aaf853bSArmin Le Grand { 3025aaf853bSArmin Le Grand o_rStrokeAttributes.StartCapType = rendering::PathCapType::ROUND; 3035aaf853bSArmin Le Grand o_rStrokeAttributes.EndCapType = rendering::PathCapType::ROUND; 3045aaf853bSArmin Le Grand break; 3055aaf853bSArmin Le Grand } 3065aaf853bSArmin Le Grand case com::sun::star::drawing::LineCap_SQUARE: 3075aaf853bSArmin Le Grand { 3085aaf853bSArmin Le Grand o_rStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE; 3095aaf853bSArmin Le Grand o_rStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE; 3105aaf853bSArmin Le Grand break; 3115aaf853bSArmin Le Grand } 3125aaf853bSArmin Le Grand } 3135aaf853bSArmin Le Grand 314cdf0e10cSrcweir if( LINE_DASH == rLineInfo.GetStyle() ) 315cdf0e10cSrcweir { 316cdf0e10cSrcweir const ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); 317cdf0e10cSrcweir 318cdf0e10cSrcweir // TODO(F1): Interpret OutDev::GetRefPoint() for the start of the dashing. 319cdf0e10cSrcweir 320cdf0e10cSrcweir // interpret dash info only if explicitely enabled as 321cdf0e10cSrcweir // style 322cdf0e10cSrcweir const ::basegfx::B2DSize aDistance( rLineInfo.GetDistance(), 0 ); 323cdf0e10cSrcweir const double nDistance( (rState.mapModeTransform * aDistance).getX() ); 324cdf0e10cSrcweir 325cdf0e10cSrcweir const ::basegfx::B2DSize aDashLen( rLineInfo.GetDashLen(), 0 ); 326cdf0e10cSrcweir const double nDashLen( (rState.mapModeTransform * aDashLen).getX() ); 327cdf0e10cSrcweir 328cdf0e10cSrcweir const ::basegfx::B2DSize aDotLen( rLineInfo.GetDotLen(), 0 ); 329cdf0e10cSrcweir const double nDotLen( (rState.mapModeTransform * aDotLen).getX() ); 330cdf0e10cSrcweir 331cdf0e10cSrcweir const sal_Int32 nNumArryEntries( 2*rLineInfo.GetDashCount() + 332cdf0e10cSrcweir 2*rLineInfo.GetDotCount() ); 333cdf0e10cSrcweir 334cdf0e10cSrcweir o_rStrokeAttributes.DashArray.realloc( nNumArryEntries ); 335cdf0e10cSrcweir double* pDashArray = o_rStrokeAttributes.DashArray.getArray(); 336cdf0e10cSrcweir 337cdf0e10cSrcweir 338cdf0e10cSrcweir // iteratively fill dash array, first with dashs, then 339cdf0e10cSrcweir // with dots. 340cdf0e10cSrcweir // =================================================== 341cdf0e10cSrcweir 342cdf0e10cSrcweir sal_Int32 nCurrEntry=0; 343cdf0e10cSrcweir 344cdf0e10cSrcweir for( sal_Int32 i=0; i<rLineInfo.GetDashCount(); ++i ) 345cdf0e10cSrcweir { 346cdf0e10cSrcweir pDashArray[nCurrEntry++] = nDashLen; 347cdf0e10cSrcweir pDashArray[nCurrEntry++] = nDistance; 348cdf0e10cSrcweir } 349cdf0e10cSrcweir for( sal_Int32 i=0; i<rLineInfo.GetDotCount(); ++i ) 350cdf0e10cSrcweir { 351cdf0e10cSrcweir pDashArray[nCurrEntry++] = nDotLen; 352cdf0e10cSrcweir pDashArray[nCurrEntry++] = nDistance; 353cdf0e10cSrcweir } 354cdf0e10cSrcweir } 355cdf0e10cSrcweir } 356cdf0e10cSrcweir 357cdf0e10cSrcweir 358cdf0e10cSrcweir /** Create masked BitmapEx, where the white areas of rBitmap are 359cdf0e10cSrcweir transparent, and the other appear in rMaskColor. 360cdf0e10cSrcweir */ 361cdf0e10cSrcweir BitmapEx createMaskBmpEx( const Bitmap& rBitmap, 362cdf0e10cSrcweir const ::Color& rMaskColor ) 363cdf0e10cSrcweir { 364cdf0e10cSrcweir const ::Color aWhite( COL_WHITE ); 365cdf0e10cSrcweir BitmapPalette aBiLevelPalette(2); 366cdf0e10cSrcweir aBiLevelPalette[0] = aWhite; 367cdf0e10cSrcweir aBiLevelPalette[1] = rMaskColor; 368cdf0e10cSrcweir 369cdf0e10cSrcweir Bitmap aMask( rBitmap.CreateMask( aWhite )); 370cdf0e10cSrcweir Bitmap aSolid( rBitmap.GetSizePixel(), 371cdf0e10cSrcweir 1, 372cdf0e10cSrcweir &aBiLevelPalette ); 373cdf0e10cSrcweir aSolid.Erase( rMaskColor ); 374cdf0e10cSrcweir 375cdf0e10cSrcweir return BitmapEx( aSolid, aMask ); 376cdf0e10cSrcweir } 377cdf0e10cSrcweir 378cdf0e10cSrcweir /** Shameless rip from vcl/source/gdi/outdev3.cxx 379cdf0e10cSrcweir 380cdf0e10cSrcweir Should consolidate, into something like basetxt... 381cdf0e10cSrcweir */ 382cdf0e10cSrcweir sal_Unicode getLocalizedChar( sal_Unicode nChar, LanguageType eLang ) 383cdf0e10cSrcweir { 384cdf0e10cSrcweir // currently only conversion from ASCII digits is interesting 385cdf0e10cSrcweir if( (nChar < '0') || ('9' < nChar) ) 386cdf0e10cSrcweir return nChar; 387cdf0e10cSrcweir 388cdf0e10cSrcweir sal_Unicode nOffset(0); 389cdf0e10cSrcweir // eLang & LANGUAGE_MASK_PRIMARY catches language independent of region. 390cdf0e10cSrcweir // CAVEAT! To some like Mongolian MS assigned the same primary language 391cdf0e10cSrcweir // although the script type is different! 392cdf0e10cSrcweir switch( eLang & LANGUAGE_MASK_PRIMARY ) 393cdf0e10cSrcweir { 394cdf0e10cSrcweir default: 395cdf0e10cSrcweir break; 396cdf0e10cSrcweir 397cdf0e10cSrcweir case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY: 398cdf0e10cSrcweir case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY: 399cdf0e10cSrcweir case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //??? 400cdf0e10cSrcweir nOffset = 0x0660 - '0'; // arabic/persian/urdu 401cdf0e10cSrcweir break; 402cdf0e10cSrcweir case LANGUAGE_BENGALI & LANGUAGE_MASK_PRIMARY: 403cdf0e10cSrcweir nOffset = 0x09E6 - '0'; // bengali 404cdf0e10cSrcweir break; 405cdf0e10cSrcweir case LANGUAGE_BURMESE & LANGUAGE_MASK_PRIMARY: 406cdf0e10cSrcweir nOffset = 0x1040 - '0'; // burmese 407cdf0e10cSrcweir break; 408cdf0e10cSrcweir case LANGUAGE_HINDI & LANGUAGE_MASK_PRIMARY: 409cdf0e10cSrcweir nOffset = 0x0966 - '0'; // devanagari 410cdf0e10cSrcweir break; 411cdf0e10cSrcweir case LANGUAGE_GUJARATI & LANGUAGE_MASK_PRIMARY: 412cdf0e10cSrcweir nOffset = 0x0AE6 - '0'; // gujarati 413cdf0e10cSrcweir break; 414cdf0e10cSrcweir case LANGUAGE_KANNADA & LANGUAGE_MASK_PRIMARY: 415cdf0e10cSrcweir nOffset = 0x0CE6 - '0'; // kannada 416cdf0e10cSrcweir break; 417cdf0e10cSrcweir case LANGUAGE_KHMER & LANGUAGE_MASK_PRIMARY: 418cdf0e10cSrcweir nOffset = 0x17E0 - '0'; // khmer 419cdf0e10cSrcweir break; 420cdf0e10cSrcweir case LANGUAGE_LAO & LANGUAGE_MASK_PRIMARY: 421cdf0e10cSrcweir nOffset = 0x0ED0 - '0'; // lao 422cdf0e10cSrcweir break; 423cdf0e10cSrcweir case LANGUAGE_MALAYALAM & LANGUAGE_MASK_PRIMARY: 424cdf0e10cSrcweir nOffset = 0x0D66 - '0'; // malayalam 425cdf0e10cSrcweir break; 426cdf0e10cSrcweir case LANGUAGE_MONGOLIAN & LANGUAGE_MASK_PRIMARY: 427cdf0e10cSrcweir if (eLang == LANGUAGE_MONGOLIAN_MONGOLIAN) 428cdf0e10cSrcweir nOffset = 0x1810 - '0'; // mongolian 429cdf0e10cSrcweir else 430cdf0e10cSrcweir nOffset = 0; // mongolian cyrillic 431cdf0e10cSrcweir break; 432cdf0e10cSrcweir case LANGUAGE_ORIYA & LANGUAGE_MASK_PRIMARY: 433cdf0e10cSrcweir nOffset = 0x0B66 - '0'; // oriya 434cdf0e10cSrcweir break; 435cdf0e10cSrcweir case LANGUAGE_TAMIL & LANGUAGE_MASK_PRIMARY: 436cdf0e10cSrcweir nOffset = 0x0BE7 - '0'; // tamil 437cdf0e10cSrcweir break; 438cdf0e10cSrcweir case LANGUAGE_TELUGU & LANGUAGE_MASK_PRIMARY: 439cdf0e10cSrcweir nOffset = 0x0C66 - '0'; // telugu 440cdf0e10cSrcweir break; 441cdf0e10cSrcweir case LANGUAGE_THAI & LANGUAGE_MASK_PRIMARY: 442cdf0e10cSrcweir nOffset = 0x0E50 - '0'; // thai 443cdf0e10cSrcweir break; 444cdf0e10cSrcweir case LANGUAGE_TIBETAN & LANGUAGE_MASK_PRIMARY: 445cdf0e10cSrcweir nOffset = 0x0F20 - '0'; // tibetan 446cdf0e10cSrcweir break; 447cdf0e10cSrcweir } 448cdf0e10cSrcweir 449cdf0e10cSrcweir nChar = sal::static_int_cast<sal_Unicode>(nChar + nOffset); 450cdf0e10cSrcweir return nChar; 451cdf0e10cSrcweir } 452cdf0e10cSrcweir 453cdf0e10cSrcweir void convertToLocalizedNumerals( XubString& rStr, 454cdf0e10cSrcweir LanguageType eTextLanguage ) 455cdf0e10cSrcweir { 456cdf0e10cSrcweir const sal_Unicode* pBase = rStr.GetBuffer(); 457cdf0e10cSrcweir const sal_Unicode* pBegin = pBase + 0; 458cdf0e10cSrcweir const xub_StrLen nEndIndex = rStr.Len(); 459cdf0e10cSrcweir const sal_Unicode* pEnd = pBase + nEndIndex; 460cdf0e10cSrcweir 461cdf0e10cSrcweir for( ; pBegin < pEnd; ++pBegin ) 462cdf0e10cSrcweir { 463cdf0e10cSrcweir // TODO: are there non-digit localizations? 464cdf0e10cSrcweir if( (*pBegin >= '0') && (*pBegin <= '9') ) 465cdf0e10cSrcweir { 466cdf0e10cSrcweir // translate characters to local preference 467cdf0e10cSrcweir sal_Unicode cChar = getLocalizedChar( *pBegin, eTextLanguage ); 468cdf0e10cSrcweir if( cChar != *pBegin ) 469cdf0e10cSrcweir rStr.SetChar( sal::static_int_cast<sal_uInt16>(pBegin - pBase), cChar ); 470cdf0e10cSrcweir } 471cdf0e10cSrcweir } 472cdf0e10cSrcweir } 473cdf0e10cSrcweir } 474cdf0e10cSrcweir 475cdf0e10cSrcweir 476cdf0e10cSrcweir namespace cppcanvas 477cdf0e10cSrcweir { 478cdf0e10cSrcweir namespace internal 479cdf0e10cSrcweir { 480cdf0e10cSrcweir bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolyPolygon& rPolyPoly, 481cdf0e10cSrcweir const ActionFactoryParameters& rParms ) 482cdf0e10cSrcweir { 483cdf0e10cSrcweir const OutDevState& rState( getState( rParms.mrStates ) ); 484cdf0e10cSrcweir if( (!rState.isLineColorSet && 485cdf0e10cSrcweir !rState.isFillColorSet) || 486cdf0e10cSrcweir (rState.lineColor.getLength() == 0 && 487cdf0e10cSrcweir rState.fillColor.getLength() == 0) ) 488cdf0e10cSrcweir { 489cdf0e10cSrcweir return false; 490cdf0e10cSrcweir } 491cdf0e10cSrcweir 492cdf0e10cSrcweir ActionSharedPtr pPolyAction( 493cdf0e10cSrcweir internal::PolyPolyActionFactory::createPolyPolyAction( 494cdf0e10cSrcweir rPolyPoly, rParms.mrCanvas, rState ) ); 495cdf0e10cSrcweir 496cdf0e10cSrcweir if( pPolyAction ) 497cdf0e10cSrcweir { 498cdf0e10cSrcweir maActions.push_back( 499cdf0e10cSrcweir MtfAction( 500cdf0e10cSrcweir pPolyAction, 501cdf0e10cSrcweir rParms.mrCurrActionIndex ) ); 502cdf0e10cSrcweir 503cdf0e10cSrcweir rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; 504cdf0e10cSrcweir } 505cdf0e10cSrcweir 506cdf0e10cSrcweir return true; 507cdf0e10cSrcweir } 508cdf0e10cSrcweir 509cdf0e10cSrcweir bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolygon& rPoly, 510cdf0e10cSrcweir const ActionFactoryParameters& rParms ) 511cdf0e10cSrcweir { 512cdf0e10cSrcweir return createFillAndStroke( ::basegfx::B2DPolyPolygon( rPoly ), 513cdf0e10cSrcweir rParms ); 514cdf0e10cSrcweir } 515cdf0e10cSrcweir 516cdf0e10cSrcweir void ImplRenderer::skipContent( GDIMetaFile& rMtf, 517cdf0e10cSrcweir const char* pCommentString, 518cdf0e10cSrcweir sal_Int32& io_rCurrActionIndex ) const 519cdf0e10cSrcweir { 520cdf0e10cSrcweir ENSURE_OR_THROW( pCommentString, 521cdf0e10cSrcweir "ImplRenderer::skipContent(): NULL string given" ); 522cdf0e10cSrcweir 523cdf0e10cSrcweir MetaAction* pCurrAct; 524cdf0e10cSrcweir while( (pCurrAct=rMtf.NextAction()) != NULL ) 525cdf0e10cSrcweir { 526cdf0e10cSrcweir // increment action index, we've skipped an action. 527cdf0e10cSrcweir ++io_rCurrActionIndex; 528cdf0e10cSrcweir 529cdf0e10cSrcweir if( pCurrAct->GetType() == META_COMMENT_ACTION && 530cdf0e10cSrcweir static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( 531cdf0e10cSrcweir pCommentString ) == COMPARE_EQUAL ) 532cdf0e10cSrcweir { 533cdf0e10cSrcweir // requested comment found, done 534cdf0e10cSrcweir return; 535cdf0e10cSrcweir } 536cdf0e10cSrcweir } 537cdf0e10cSrcweir 538cdf0e10cSrcweir // EOF 539cdf0e10cSrcweir return; 540cdf0e10cSrcweir } 541cdf0e10cSrcweir 542cdf0e10cSrcweir bool ImplRenderer::isActionContained( GDIMetaFile& rMtf, 543cdf0e10cSrcweir const char* pCommentString, 544cdf0e10cSrcweir sal_uInt16 nType ) const 545cdf0e10cSrcweir { 546cdf0e10cSrcweir ENSURE_OR_THROW( pCommentString, 547cdf0e10cSrcweir "ImplRenderer::isActionContained(): NULL string given" ); 548cdf0e10cSrcweir 549cdf0e10cSrcweir bool bRet( false ); 550cdf0e10cSrcweir 551cdf0e10cSrcweir // at least _one_ call to GDIMetaFile::NextAction() is 552cdf0e10cSrcweir // executed 553cdf0e10cSrcweir sal_uIntPtr nPos( 1 ); 554cdf0e10cSrcweir 555cdf0e10cSrcweir MetaAction* pCurrAct; 556cdf0e10cSrcweir while( (pCurrAct=rMtf.NextAction()) != NULL ) 557cdf0e10cSrcweir { 558cdf0e10cSrcweir if( pCurrAct->GetType() == nType ) 559cdf0e10cSrcweir { 560cdf0e10cSrcweir bRet = true; // action type found 561cdf0e10cSrcweir break; 562cdf0e10cSrcweir } 563cdf0e10cSrcweir 564cdf0e10cSrcweir if( pCurrAct->GetType() == META_COMMENT_ACTION && 565cdf0e10cSrcweir static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( 566cdf0e10cSrcweir pCommentString ) == COMPARE_EQUAL ) 567cdf0e10cSrcweir { 568cdf0e10cSrcweir // delimiting end comment found, done 569cdf0e10cSrcweir bRet = false; // not yet found 570cdf0e10cSrcweir break; 571cdf0e10cSrcweir } 572cdf0e10cSrcweir 573cdf0e10cSrcweir ++nPos; 574cdf0e10cSrcweir } 575cdf0e10cSrcweir 576cdf0e10cSrcweir // rewind metafile to previous position (this method must 577cdf0e10cSrcweir // not change the current metaaction) 578cdf0e10cSrcweir while( nPos-- ) 579cdf0e10cSrcweir rMtf.WindPrev(); 580cdf0e10cSrcweir 581cdf0e10cSrcweir if( !pCurrAct ) 582cdf0e10cSrcweir { 583cdf0e10cSrcweir // EOF, and not yet found 584cdf0e10cSrcweir bRet = false; 585cdf0e10cSrcweir } 586cdf0e10cSrcweir 587cdf0e10cSrcweir return bRet; 588cdf0e10cSrcweir } 589cdf0e10cSrcweir 590cdf0e10cSrcweir void ImplRenderer::createGradientAction( const ::PolyPolygon& rPoly, 591cdf0e10cSrcweir const ::Gradient& rGradient, 592cdf0e10cSrcweir const ActionFactoryParameters& rParms, 593cdf0e10cSrcweir bool bIsPolygonRectangle, 594cdf0e10cSrcweir bool bSubsettableActions ) 595cdf0e10cSrcweir { 596cdf0e10cSrcweir DBG_TESTSOLARMUTEX(); 597cdf0e10cSrcweir 598cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aDevicePoly( rPoly.getB2DPolyPolygon() ); 599cdf0e10cSrcweir aDevicePoly.transform( getState( rParms.mrStates ).mapModeTransform ); 600cdf0e10cSrcweir 601cdf0e10cSrcweir // decide, whether this gradient can be rendered natively 602cdf0e10cSrcweir // by the canvas, or must be emulated via VCL gradient 603cdf0e10cSrcweir // action extraction. 604cdf0e10cSrcweir const sal_uInt16 nSteps( rGradient.GetSteps() ); 605cdf0e10cSrcweir 606cdf0e10cSrcweir if( // step count is infinite, can use native canvas 607cdf0e10cSrcweir // gradients here 608cdf0e10cSrcweir nSteps == 0 || 609cdf0e10cSrcweir // step count is sufficiently high, such that no 610cdf0e10cSrcweir // discernible difference should be visible. 611cdf0e10cSrcweir nSteps > 64 ) 612cdf0e10cSrcweir { 613cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory> xFactory( 614cdf0e10cSrcweir rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() ); 615cdf0e10cSrcweir 616cdf0e10cSrcweir if( xFactory.is() ) 617cdf0e10cSrcweir { 618cdf0e10cSrcweir rendering::Texture aTexture; 619cdf0e10cSrcweir 620cdf0e10cSrcweir aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; 621cdf0e10cSrcweir aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; 622cdf0e10cSrcweir aTexture.Alpha = 1.0; 623cdf0e10cSrcweir 624cdf0e10cSrcweir 625cdf0e10cSrcweir // setup start/end color values 626cdf0e10cSrcweir // ---------------------------- 627cdf0e10cSrcweir 628cdf0e10cSrcweir // scale color coefficients with gradient intensities 629cdf0e10cSrcweir const sal_uInt16 nStartIntensity( rGradient.GetStartIntensity() ); 630cdf0e10cSrcweir ::Color aVCLStartColor( rGradient.GetStartColor() ); 631cdf0e10cSrcweir aVCLStartColor.SetRed( (sal_uInt8)(aVCLStartColor.GetRed() * nStartIntensity / 100) ); 632cdf0e10cSrcweir aVCLStartColor.SetGreen( (sal_uInt8)(aVCLStartColor.GetGreen() * nStartIntensity / 100) ); 633cdf0e10cSrcweir aVCLStartColor.SetBlue( (sal_uInt8)(aVCLStartColor.GetBlue() * nStartIntensity / 100) ); 634cdf0e10cSrcweir 635cdf0e10cSrcweir const sal_uInt16 nEndIntensity( rGradient.GetEndIntensity() ); 636cdf0e10cSrcweir ::Color aVCLEndColor( rGradient.GetEndColor() ); 637cdf0e10cSrcweir aVCLEndColor.SetRed( (sal_uInt8)(aVCLEndColor.GetRed() * nEndIntensity / 100) ); 638cdf0e10cSrcweir aVCLEndColor.SetGreen( (sal_uInt8)(aVCLEndColor.GetGreen() * nEndIntensity / 100) ); 639cdf0e10cSrcweir aVCLEndColor.SetBlue( (sal_uInt8)(aVCLEndColor.GetBlue() * nEndIntensity / 100) ); 640cdf0e10cSrcweir 641cdf0e10cSrcweir uno::Reference<rendering::XColorSpace> xColorSpace( 642cdf0e10cSrcweir rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()); 643cdf0e10cSrcweir const uno::Sequence< double > aStartColor( 644cdf0e10cSrcweir ::vcl::unotools::colorToDoubleSequence( aVCLStartColor, 645cdf0e10cSrcweir xColorSpace )); 646cdf0e10cSrcweir const uno::Sequence< double > aEndColor( 647cdf0e10cSrcweir ::vcl::unotools::colorToDoubleSequence( aVCLEndColor, 648cdf0e10cSrcweir xColorSpace )); 649cdf0e10cSrcweir 650cdf0e10cSrcweir uno::Sequence< uno::Sequence < double > > aColors(2); 651cdf0e10cSrcweir uno::Sequence< double > aStops(2); 652cdf0e10cSrcweir 653cdf0e10cSrcweir if( rGradient.GetStyle() == GRADIENT_AXIAL ) 654cdf0e10cSrcweir { 655cdf0e10cSrcweir aStops.realloc(3); 656cdf0e10cSrcweir aColors.realloc(3); 657cdf0e10cSrcweir 658cdf0e10cSrcweir aStops[0] = 0.0; 659cdf0e10cSrcweir aStops[1] = 0.5; 660cdf0e10cSrcweir aStops[2] = 1.0; 661cdf0e10cSrcweir 662cdf0e10cSrcweir aColors[0] = aEndColor; 663cdf0e10cSrcweir aColors[1] = aStartColor; 664cdf0e10cSrcweir aColors[2] = aEndColor; 665cdf0e10cSrcweir } 666cdf0e10cSrcweir else 667cdf0e10cSrcweir { 668cdf0e10cSrcweir aStops[0] = 0.0; 669cdf0e10cSrcweir aStops[1] = 1.0; 670cdf0e10cSrcweir 671cdf0e10cSrcweir aColors[0] = aStartColor; 672cdf0e10cSrcweir aColors[1] = aEndColor; 673cdf0e10cSrcweir } 674cdf0e10cSrcweir 675cdf0e10cSrcweir const ::basegfx::B2DRectangle aBounds( 676cdf0e10cSrcweir ::basegfx::tools::getRange(aDevicePoly) ); 677cdf0e10cSrcweir const ::basegfx::B2DVector aOffset( 678cdf0e10cSrcweir rGradient.GetOfsX() / 100.0, 679cdf0e10cSrcweir rGradient.GetOfsY() / 100.0); 680cdf0e10cSrcweir double fRotation( rGradient.GetAngle() * M_PI / 1800.0 ); 681cdf0e10cSrcweir const double fBorder( rGradient.GetBorder() / 100.0 ); 682cdf0e10cSrcweir 683cdf0e10cSrcweir basegfx::B2DHomMatrix aRot90; 684cdf0e10cSrcweir aRot90.rotate(M_PI_2); 685cdf0e10cSrcweir 686cdf0e10cSrcweir basegfx::ODFGradientInfo aGradInfo; 687cdf0e10cSrcweir rtl::OUString aGradientService; 688cdf0e10cSrcweir switch( rGradient.GetStyle() ) 689cdf0e10cSrcweir { 690cdf0e10cSrcweir case GRADIENT_LINEAR: 691*96fc4b33SArmin Le Grand aGradInfo = basegfx::tools::createLinearODFGradientInfo( 692cdf0e10cSrcweir aBounds, 693cdf0e10cSrcweir nSteps, 694cdf0e10cSrcweir fBorder, 695cdf0e10cSrcweir fRotation); 696cdf0e10cSrcweir // map odf to svg gradient orientation - x 697cdf0e10cSrcweir // instead of y direction 698*96fc4b33SArmin Le Grand aGradInfo.setTextureTransform(aGradInfo.getTextureTransform() * aRot90); 699cdf0e10cSrcweir aGradientService = rtl::OUString::createFromAscii("LinearGradient"); 700cdf0e10cSrcweir break; 701cdf0e10cSrcweir 702cdf0e10cSrcweir case GRADIENT_AXIAL: 703cdf0e10cSrcweir { 704cdf0e10cSrcweir // Adapt the border so that it is suitable 705cdf0e10cSrcweir // for the axial gradient. An axial 706cdf0e10cSrcweir // gradient consists of two linear 707cdf0e10cSrcweir // gradients. Each of those covers half 708cdf0e10cSrcweir // of the total size. In order to 709cdf0e10cSrcweir // compensate for the condensed display of 710cdf0e10cSrcweir // the linear gradients, we have to 711cdf0e10cSrcweir // enlarge the area taken up by the actual 712cdf0e10cSrcweir // gradient (1-fBorder). After that we 713cdf0e10cSrcweir // have to turn the result back into a 714cdf0e10cSrcweir // border value, hence the second (left 715cdf0e10cSrcweir // most 1-... 716cdf0e10cSrcweir const double fAxialBorder (1-2*(1-fBorder)); 717*96fc4b33SArmin Le Grand aGradInfo = basegfx::tools::createAxialODFGradientInfo( 718cdf0e10cSrcweir aBounds, 719cdf0e10cSrcweir nSteps, 720cdf0e10cSrcweir fAxialBorder, 721cdf0e10cSrcweir fRotation); 722cdf0e10cSrcweir // map odf to svg gradient orientation - x 723cdf0e10cSrcweir // instead of y direction 724*96fc4b33SArmin Le Grand aGradInfo.setTextureTransform(aGradInfo.getTextureTransform() * aRot90); 725cdf0e10cSrcweir 726cdf0e10cSrcweir // map odf axial gradient to 3-stop linear 727cdf0e10cSrcweir // gradient - shift left by 0.5 728cdf0e10cSrcweir basegfx::B2DHomMatrix aShift; 729*96fc4b33SArmin Le Grand 730cdf0e10cSrcweir aShift.translate(-0.5,0); 731*96fc4b33SArmin Le Grand aGradInfo.setTextureTransform(aGradInfo.getTextureTransform() * aShift); 732cdf0e10cSrcweir aGradientService = rtl::OUString::createFromAscii("LinearGradient"); 733cdf0e10cSrcweir break; 734cdf0e10cSrcweir } 735cdf0e10cSrcweir 736cdf0e10cSrcweir case GRADIENT_RADIAL: 737*96fc4b33SArmin Le Grand aGradInfo = basegfx::tools::createRadialODFGradientInfo( 738cdf0e10cSrcweir aBounds, 739cdf0e10cSrcweir aOffset, 740cdf0e10cSrcweir nSteps, 741cdf0e10cSrcweir fBorder); 742cdf0e10cSrcweir aGradientService = rtl::OUString::createFromAscii("EllipticalGradient"); 743cdf0e10cSrcweir break; 744cdf0e10cSrcweir 745cdf0e10cSrcweir case GRADIENT_ELLIPTICAL: 746*96fc4b33SArmin Le Grand aGradInfo = basegfx::tools::createEllipticalODFGradientInfo( 747cdf0e10cSrcweir aBounds, 748cdf0e10cSrcweir aOffset, 749cdf0e10cSrcweir nSteps, 750cdf0e10cSrcweir fBorder, 751cdf0e10cSrcweir fRotation); 752cdf0e10cSrcweir aGradientService = rtl::OUString::createFromAscii("EllipticalGradient"); 753cdf0e10cSrcweir break; 754cdf0e10cSrcweir 755cdf0e10cSrcweir case GRADIENT_SQUARE: 756*96fc4b33SArmin Le Grand aGradInfo = basegfx::tools::createSquareODFGradientInfo( 757cdf0e10cSrcweir aBounds, 758cdf0e10cSrcweir aOffset, 759cdf0e10cSrcweir nSteps, 760cdf0e10cSrcweir fBorder, 761cdf0e10cSrcweir fRotation); 762cdf0e10cSrcweir aGradientService = rtl::OUString::createFromAscii("RectangularGradient"); 763cdf0e10cSrcweir break; 764cdf0e10cSrcweir 765cdf0e10cSrcweir case GRADIENT_RECT: 766*96fc4b33SArmin Le Grand aGradInfo = basegfx::tools::createRectangularODFGradientInfo( 767cdf0e10cSrcweir aBounds, 768cdf0e10cSrcweir aOffset, 769cdf0e10cSrcweir nSteps, 770cdf0e10cSrcweir fBorder, 771cdf0e10cSrcweir fRotation); 772cdf0e10cSrcweir aGradientService = rtl::OUString::createFromAscii("RectangularGradient"); 773cdf0e10cSrcweir break; 774cdf0e10cSrcweir 775cdf0e10cSrcweir default: 776cdf0e10cSrcweir ENSURE_OR_THROW( false, 777cdf0e10cSrcweir "ImplRenderer::createGradientAction(): Unexpected gradient type" ); 778cdf0e10cSrcweir break; 779cdf0e10cSrcweir } 780cdf0e10cSrcweir 781cdf0e10cSrcweir // As the texture coordinate space is relative to 782cdf0e10cSrcweir // the polygon coordinate space (NOT to the 783cdf0e10cSrcweir // polygon itself), move gradient to the start of 784cdf0e10cSrcweir // the actual polygon. If we skip this, the 785cdf0e10cSrcweir // gradient will always display at the origin, and 786cdf0e10cSrcweir // not within the polygon bound (which might be 787cdf0e10cSrcweir // miles away from the origin). 788*96fc4b33SArmin Le Grand aGradInfo.setTextureTransform( 789*96fc4b33SArmin Le Grand basegfx::tools::createTranslateB2DHomMatrix( 790*96fc4b33SArmin Le Grand aBounds.getMinX(), 791*96fc4b33SArmin Le Grand aBounds.getMinY()) * aGradInfo.getTextureTransform()); 792cdf0e10cSrcweir ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform, 793*96fc4b33SArmin Le Grand aGradInfo.getTextureTransform() ); 794cdf0e10cSrcweir 795cdf0e10cSrcweir uno::Sequence<uno::Any> args(3); 796cdf0e10cSrcweir beans::PropertyValue aProp; 797cdf0e10cSrcweir aProp.Name = rtl::OUString::createFromAscii("Colors"); 798cdf0e10cSrcweir aProp.Value <<= aColors; 799cdf0e10cSrcweir args[0] <<= aProp; 800cdf0e10cSrcweir aProp.Name = rtl::OUString::createFromAscii("Stops"); 801cdf0e10cSrcweir aProp.Value <<= aStops; 802cdf0e10cSrcweir args[1] <<= aProp; 803cdf0e10cSrcweir aProp.Name = rtl::OUString::createFromAscii("AspectRatio"); 804*96fc4b33SArmin Le Grand aProp.Value <<= aGradInfo.getAspectRatio(); 805cdf0e10cSrcweir args[2] <<= aProp; 806cdf0e10cSrcweir 807cdf0e10cSrcweir aTexture.Gradient.set( 808cdf0e10cSrcweir xFactory->createInstanceWithArguments(aGradientService, 809cdf0e10cSrcweir args), 810cdf0e10cSrcweir uno::UNO_QUERY); 811cdf0e10cSrcweir if( aTexture.Gradient.is() ) 812cdf0e10cSrcweir { 813cdf0e10cSrcweir ActionSharedPtr pPolyAction( 814cdf0e10cSrcweir internal::PolyPolyActionFactory::createPolyPolyAction( 815cdf0e10cSrcweir aDevicePoly, 816cdf0e10cSrcweir rParms.mrCanvas, 817cdf0e10cSrcweir getState( rParms.mrStates ), 818cdf0e10cSrcweir aTexture ) ); 819cdf0e10cSrcweir 820cdf0e10cSrcweir if( pPolyAction ) 821cdf0e10cSrcweir { 822cdf0e10cSrcweir maActions.push_back( 823cdf0e10cSrcweir MtfAction( 824cdf0e10cSrcweir pPolyAction, 825cdf0e10cSrcweir rParms.mrCurrActionIndex ) ); 826cdf0e10cSrcweir 827cdf0e10cSrcweir rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; 828cdf0e10cSrcweir } 829cdf0e10cSrcweir 830cdf0e10cSrcweir // done, using native gradients 831cdf0e10cSrcweir return; 832cdf0e10cSrcweir } 833cdf0e10cSrcweir } 834cdf0e10cSrcweir } 835cdf0e10cSrcweir 836cdf0e10cSrcweir // cannot currently use native canvas gradients, as a 837cdf0e10cSrcweir // finite step size is given (this funny feature is not 838cdf0e10cSrcweir // supported by the XCanvas API) 839cdf0e10cSrcweir pushState( rParms.mrStates, PUSH_ALL ); 840cdf0e10cSrcweir 841cdf0e10cSrcweir if( !bIsPolygonRectangle ) 842cdf0e10cSrcweir { 843cdf0e10cSrcweir // only clip, if given polygon is not a rectangle in 844cdf0e10cSrcweir // the first place (the gradient is always limited to 845cdf0e10cSrcweir // the given bound rect) 846cdf0e10cSrcweir updateClipping( 847cdf0e10cSrcweir aDevicePoly, 848cdf0e10cSrcweir rParms, 849cdf0e10cSrcweir true ); 850cdf0e10cSrcweir } 851cdf0e10cSrcweir 852cdf0e10cSrcweir GDIMetaFile aTmpMtf; 853cdf0e10cSrcweir rParms.mrVDev.AddGradientActions( rPoly.GetBoundRect(), 854cdf0e10cSrcweir rGradient, 855cdf0e10cSrcweir aTmpMtf ); 856cdf0e10cSrcweir 857cdf0e10cSrcweir createActions( aTmpMtf, rParms, bSubsettableActions ); 858cdf0e10cSrcweir 859cdf0e10cSrcweir popState( rParms.mrStates ); 860cdf0e10cSrcweir } 861cdf0e10cSrcweir 862cdf0e10cSrcweir uno::Reference< rendering::XCanvasFont > ImplRenderer::createFont( double& o_rFontRotation, 863cdf0e10cSrcweir const ::Font& rFont, 864cdf0e10cSrcweir const ActionFactoryParameters& rParms ) const 865cdf0e10cSrcweir { 866cdf0e10cSrcweir rendering::FontRequest aFontRequest; 867cdf0e10cSrcweir 868cdf0e10cSrcweir if( rParms.mrParms.maFontName.is_initialized() ) 869cdf0e10cSrcweir aFontRequest.FontDescription.FamilyName = *rParms.mrParms.maFontName; 870cdf0e10cSrcweir else 871cdf0e10cSrcweir aFontRequest.FontDescription.FamilyName = rFont.GetName(); 872cdf0e10cSrcweir 873cdf0e10cSrcweir aFontRequest.FontDescription.StyleName = rFont.GetStyleName(); 874cdf0e10cSrcweir 875cdf0e10cSrcweir aFontRequest.FontDescription.IsSymbolFont = (rFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL) ? util::TriState_YES : util::TriState_NO; 876cdf0e10cSrcweir aFontRequest.FontDescription.IsVertical = rFont.IsVertical() ? util::TriState_YES : util::TriState_NO; 877cdf0e10cSrcweir 878cdf0e10cSrcweir // TODO(F2): improve vclenum->panose conversion 879cdf0e10cSrcweir aFontRequest.FontDescription.FontDescription.Weight = 880cdf0e10cSrcweir rParms.mrParms.maFontWeight.is_initialized() ? 881cdf0e10cSrcweir *rParms.mrParms.maFontWeight : 882cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_Int8>( ::basegfx::fround( rFont.GetWeight() ) ); 883cdf0e10cSrcweir aFontRequest.FontDescription.FontDescription.Letterform = 884cdf0e10cSrcweir rParms.mrParms.maFontLetterForm.is_initialized() ? 885cdf0e10cSrcweir *rParms.mrParms.maFontLetterForm : 886cdf0e10cSrcweir (rFont.GetItalic() == ITALIC_NONE) ? 0 : 9; 887cdf0e10cSrcweir aFontRequest.FontDescription.FontDescription.Proportion = 888cdf0e10cSrcweir rParms.mrParms.maFontProportion.is_initialized() ? 889cdf0e10cSrcweir *rParms.mrParms.maFontProportion : 890cdf0e10cSrcweir (rFont.GetPitch() == PITCH_FIXED) 891cdf0e10cSrcweir ? rendering::PanoseProportion::MONO_SPACED 892cdf0e10cSrcweir : rendering::PanoseProportion::ANYTHING; 893cdf0e10cSrcweir 894cdf0e10cSrcweir LanguageType aLang = rFont.GetLanguage(); 895cdf0e10cSrcweir aFontRequest.Locale = MsLangId::convertLanguageToLocale(aLang, false); 896cdf0e10cSrcweir 897cdf0e10cSrcweir // setup state-local text transformation, 898cdf0e10cSrcweir // if the font be rotated 899cdf0e10cSrcweir const short nFontAngle( rFont.GetOrientation() ); 900cdf0e10cSrcweir if( nFontAngle != 0 ) 901cdf0e10cSrcweir { 902cdf0e10cSrcweir // set to unity transform rotated by font angle 903cdf0e10cSrcweir const double nAngle( nFontAngle * (F_PI / 1800.0) ); 904cdf0e10cSrcweir o_rFontRotation = -nAngle; 905cdf0e10cSrcweir } 906cdf0e10cSrcweir else 907cdf0e10cSrcweir { 908cdf0e10cSrcweir o_rFontRotation = 0.0; 909cdf0e10cSrcweir } 910cdf0e10cSrcweir 911cdf0e10cSrcweir geometry::Matrix2D aFontMatrix; 912cdf0e10cSrcweir ::canvas::tools::setIdentityMatrix2D( aFontMatrix ); 913cdf0e10cSrcweir 914cdf0e10cSrcweir // TODO(F2): use correct scale direction, font 915cdf0e10cSrcweir // height might be width or anything else 916cdf0e10cSrcweir 917cdf0e10cSrcweir // TODO(Q3): This code smells of programming by 918cdf0e10cSrcweir // coincidence (the next two if statements) 919cdf0e10cSrcweir const ::Size rFontSizeLog( rFont.GetSize() ); 920cdf0e10cSrcweir const sal_Int32 nFontWidthLog = rFontSizeLog.Width(); 921cdf0e10cSrcweir if( nFontWidthLog != 0 ) 922cdf0e10cSrcweir { 923cdf0e10cSrcweir ::Font aTestFont = rFont; 924cdf0e10cSrcweir aTestFont.SetWidth( 0 ); 925cdf0e10cSrcweir sal_Int32 nNormalWidth = rParms.mrVDev.GetFontMetric( aTestFont ).GetWidth(); 926cdf0e10cSrcweir if( nNormalWidth != nFontWidthLog ) 927cdf0e10cSrcweir if( nNormalWidth ) 928cdf0e10cSrcweir aFontMatrix.m00 = (double)nFontWidthLog / nNormalWidth; 929cdf0e10cSrcweir } 930cdf0e10cSrcweir 931cdf0e10cSrcweir // #i52608# apply map mode scale also to font matrix - an 932cdf0e10cSrcweir // anisotrophic mapmode must be reflected in an 933cdf0e10cSrcweir // anisotrophic font matrix scale. 934cdf0e10cSrcweir const OutDevState& rState( getState( rParms.mrStates ) ); 935cdf0e10cSrcweir if( !::basegfx::fTools::equal( 936cdf0e10cSrcweir rState.mapModeTransform.get(0,0), 937cdf0e10cSrcweir rState.mapModeTransform.get(1,1)) ) 938cdf0e10cSrcweir { 939cdf0e10cSrcweir const double nScaleX( rState.mapModeTransform.get(0,0) ); 940cdf0e10cSrcweir const double nScaleY( rState.mapModeTransform.get(1,1) ); 941cdf0e10cSrcweir 942cdf0e10cSrcweir // note: no reason to check for division by zero, we 943cdf0e10cSrcweir // always have the value closer (or equal) to zero as 944cdf0e10cSrcweir // the nominator. 945cdf0e10cSrcweir if( fabs(nScaleX) < fabs(nScaleY) ) 946cdf0e10cSrcweir aFontMatrix.m00 *= nScaleX / nScaleY; 947cdf0e10cSrcweir else 948cdf0e10cSrcweir aFontMatrix.m11 *= nScaleY / nScaleX; 949cdf0e10cSrcweir } 950cdf0e10cSrcweir aFontRequest.CellSize = (rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize(rFontSizeLog)).getY(); 951cdf0e10cSrcweir 952cdf0e10cSrcweir return rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest, 953cdf0e10cSrcweir uno::Sequence< beans::PropertyValue >(), 954cdf0e10cSrcweir aFontMatrix ); 955cdf0e10cSrcweir } 956cdf0e10cSrcweir 957cdf0e10cSrcweir // create text effects such as shadow/relief/embossed 958cdf0e10cSrcweir void ImplRenderer::createTextAction( const ::Point& rStartPoint, 959cdf0e10cSrcweir const String rString, 960cdf0e10cSrcweir int nIndex, 961cdf0e10cSrcweir int nLength, 962cdf0e10cSrcweir const sal_Int32* pCharWidths, 963cdf0e10cSrcweir const ActionFactoryParameters& rParms, 964cdf0e10cSrcweir bool bSubsettableActions ) 965cdf0e10cSrcweir { 966cdf0e10cSrcweir ENSURE_OR_THROW( nIndex >= 0 && nLength <= rString.Len() + nIndex, 967cdf0e10cSrcweir "ImplRenderer::createTextWithEffectsAction(): Invalid text index" ); 968cdf0e10cSrcweir 969cdf0e10cSrcweir if( !nLength ) 970cdf0e10cSrcweir return; // zero-length text, no visible output 971cdf0e10cSrcweir 972cdf0e10cSrcweir const OutDevState& rState( getState( rParms.mrStates ) ); 973cdf0e10cSrcweir 974cdf0e10cSrcweir // TODO(F2): implement all text effects 975cdf0e10cSrcweir // if( rState.textAlignment ); // TODO(F2): NYI 976cdf0e10cSrcweir 977cdf0e10cSrcweir ::Color aShadowColor( COL_AUTO ); 978cdf0e10cSrcweir ::Color aReliefColor( COL_AUTO ); 979cdf0e10cSrcweir ::Size aShadowOffset; 980cdf0e10cSrcweir ::Size aReliefOffset; 981cdf0e10cSrcweir 982cdf0e10cSrcweir uno::Reference<rendering::XColorSpace> xColorSpace( 983cdf0e10cSrcweir rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); 984cdf0e10cSrcweir 985cdf0e10cSrcweir if( rState.isTextEffectShadowSet ) 986cdf0e10cSrcweir { 987cdf0e10cSrcweir // calculate shadow offset (similar to outdev3.cxx) 988cdf0e10cSrcweir // TODO(F3): better match with outdev3.cxx 989cdf0e10cSrcweir sal_Int32 nShadowOffset = static_cast<sal_Int32>(1.5 + ((rParms.mrVDev.GetFont().GetHeight()-24.0)/24.0)); 990cdf0e10cSrcweir if( nShadowOffset < 1 ) 991cdf0e10cSrcweir nShadowOffset = 1; 992cdf0e10cSrcweir 993cdf0e10cSrcweir aShadowOffset.setWidth( nShadowOffset ); 994cdf0e10cSrcweir aShadowOffset.setHeight( nShadowOffset ); 995cdf0e10cSrcweir 996cdf0e10cSrcweir // determine shadow color (from outdev3.cxx) 997cdf0e10cSrcweir ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor( 998cdf0e10cSrcweir rState.textColor, xColorSpace ); 999cdf0e10cSrcweir bool bIsDark = (aTextColor.GetColor() == COL_BLACK) 1000cdf0e10cSrcweir || (aTextColor.GetLuminance() < 8); 1001cdf0e10cSrcweir 1002cdf0e10cSrcweir aShadowColor = bIsDark ? COL_LIGHTGRAY : COL_BLACK; 1003cdf0e10cSrcweir aShadowColor.SetTransparency( aTextColor.GetTransparency() ); 1004cdf0e10cSrcweir } 1005cdf0e10cSrcweir 1006cdf0e10cSrcweir if( rState.textReliefStyle ) 1007cdf0e10cSrcweir { 1008cdf0e10cSrcweir // calculate relief offset (similar to outdev3.cxx) 1009cdf0e10cSrcweir sal_Int32 nReliefOffset = rParms.mrVDev.PixelToLogic( Size( 1, 1 ) ).Height(); 1010cdf0e10cSrcweir nReliefOffset += nReliefOffset/2; 1011cdf0e10cSrcweir if( nReliefOffset < 1 ) 1012cdf0e10cSrcweir nReliefOffset = 1; 1013cdf0e10cSrcweir 1014cdf0e10cSrcweir if( rState.textReliefStyle == RELIEF_ENGRAVED ) 1015cdf0e10cSrcweir nReliefOffset = -nReliefOffset; 1016cdf0e10cSrcweir 1017cdf0e10cSrcweir aReliefOffset.setWidth( nReliefOffset ); 1018cdf0e10cSrcweir aReliefOffset.setHeight( nReliefOffset ); 1019cdf0e10cSrcweir 1020cdf0e10cSrcweir // determine relief color (from outdev3.cxx) 1021cdf0e10cSrcweir ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor( 1022cdf0e10cSrcweir rState.textColor, xColorSpace ); 1023cdf0e10cSrcweir 1024cdf0e10cSrcweir aReliefColor = ::Color( COL_LIGHTGRAY ); 1025cdf0e10cSrcweir 1026cdf0e10cSrcweir // we don't have a automatic color, so black is always 1027cdf0e10cSrcweir // drawn on white (literally copied from 1028cdf0e10cSrcweir // vcl/source/gdi/outdev3.cxx) 1029cdf0e10cSrcweir if( aTextColor.GetColor() == COL_BLACK ) 1030cdf0e10cSrcweir { 1031cdf0e10cSrcweir aTextColor = ::Color( COL_WHITE ); 1032cdf0e10cSrcweir getState( rParms.mrStates ).textColor = 1033cdf0e10cSrcweir ::vcl::unotools::colorToDoubleSequence( 1034cdf0e10cSrcweir aTextColor, xColorSpace ); 1035cdf0e10cSrcweir } 1036cdf0e10cSrcweir 1037cdf0e10cSrcweir if( aTextColor.GetColor() == COL_WHITE ) 1038cdf0e10cSrcweir aReliefColor = ::Color( COL_BLACK ); 1039cdf0e10cSrcweir aReliefColor.SetTransparency( aTextColor.GetTransparency() ); 1040cdf0e10cSrcweir } 1041cdf0e10cSrcweir 1042cdf0e10cSrcweir // create the actual text action 1043cdf0e10cSrcweir ActionSharedPtr pTextAction( 1044cdf0e10cSrcweir TextActionFactory::createTextAction( 1045cdf0e10cSrcweir rStartPoint, 1046cdf0e10cSrcweir aReliefOffset, 1047cdf0e10cSrcweir aReliefColor, 1048cdf0e10cSrcweir aShadowOffset, 1049cdf0e10cSrcweir aShadowColor, 1050cdf0e10cSrcweir rString, 1051cdf0e10cSrcweir nIndex, 1052cdf0e10cSrcweir nLength, 1053cdf0e10cSrcweir pCharWidths, 1054cdf0e10cSrcweir rParms.mrVDev, 1055cdf0e10cSrcweir rParms.mrCanvas, 1056cdf0e10cSrcweir rState, 1057cdf0e10cSrcweir rParms.mrParms, 1058cdf0e10cSrcweir bSubsettableActions ) ); 1059cdf0e10cSrcweir 1060cdf0e10cSrcweir ActionSharedPtr pStrikeoutTextAction; 1061cdf0e10cSrcweir 1062cdf0e10cSrcweir if ( rState.textStrikeoutStyle == STRIKEOUT_X || rState.textStrikeoutStyle == STRIKEOUT_SLASH ) 1063cdf0e10cSrcweir { 1064cdf0e10cSrcweir long nWidth = rParms.mrVDev.GetTextWidth( rString,nIndex,nLength ); 1065cdf0e10cSrcweir 1066cdf0e10cSrcweir xub_Unicode pChars[5]; 1067cdf0e10cSrcweir if ( rState.textStrikeoutStyle == STRIKEOUT_X ) 1068cdf0e10cSrcweir pChars[0] = 'X'; 1069cdf0e10cSrcweir else 1070cdf0e10cSrcweir pChars[0] = '/'; 1071cdf0e10cSrcweir pChars[3]=pChars[2]=pChars[1]=pChars[0]; 1072cdf0e10cSrcweir 1073cdf0e10cSrcweir long nStrikeoutWidth = nWidth; 1074cdf0e10cSrcweir String aStrikeoutTest( pChars, 4 ); 1075cdf0e10cSrcweir 1076cdf0e10cSrcweir if( aStrikeoutTest.Len() ) 1077cdf0e10cSrcweir { 1078cdf0e10cSrcweir nStrikeoutWidth = ( rParms.mrVDev.GetTextWidth( aStrikeoutTest ) + 2 ) / 4; 1079cdf0e10cSrcweir aStrikeoutTest.Erase(); 1080cdf0e10cSrcweir 1081cdf0e10cSrcweir if( nStrikeoutWidth <= 0 ) 1082cdf0e10cSrcweir nStrikeoutWidth = 1; 1083cdf0e10cSrcweir } 1084cdf0e10cSrcweir 1085cdf0e10cSrcweir long nMaxWidth = nStrikeoutWidth/2; 1086cdf0e10cSrcweir if ( nMaxWidth < 2 ) 1087cdf0e10cSrcweir nMaxWidth = 2; 1088cdf0e10cSrcweir nMaxWidth += nWidth + 1; 1089cdf0e10cSrcweir 1090cdf0e10cSrcweir long nFullStrikeoutWidth = 0; 1091cdf0e10cSrcweir String aStrikeoutText( pChars, 0 ); 1092cdf0e10cSrcweir while( (nFullStrikeoutWidth+=nStrikeoutWidth ) < nMaxWidth+1 ) 1093cdf0e10cSrcweir aStrikeoutText += pChars[0]; 1094cdf0e10cSrcweir 1095cdf0e10cSrcweir 1096cdf0e10cSrcweir sal_Int32 nStartPos = 0; 1097cdf0e10cSrcweir xub_StrLen nLen = aStrikeoutText.Len(); 1098cdf0e10cSrcweir 1099cdf0e10cSrcweir if( nLen ) 1100cdf0e10cSrcweir { 1101cdf0e10cSrcweir long nInterval = ( nWidth - nStrikeoutWidth * nLen ) / nLen; 1102cdf0e10cSrcweir nStrikeoutWidth += nInterval; 1103cdf0e10cSrcweir sal_Int32* pStrikeoutCharWidths = new sal_Int32[nLen]; 1104cdf0e10cSrcweir 1105cdf0e10cSrcweir for ( int i = 0;i<nLen; i++) 1106cdf0e10cSrcweir { 1107cdf0e10cSrcweir pStrikeoutCharWidths[i] = nStrikeoutWidth; 1108cdf0e10cSrcweir } 1109cdf0e10cSrcweir 1110cdf0e10cSrcweir for ( int i = 1;i< nLen; i++ ) 1111cdf0e10cSrcweir { 1112cdf0e10cSrcweir pStrikeoutCharWidths[ i ] += pStrikeoutCharWidths[ i-1 ]; 1113cdf0e10cSrcweir } 1114cdf0e10cSrcweir 1115cdf0e10cSrcweir pStrikeoutTextAction = 1116cdf0e10cSrcweir TextActionFactory::createTextAction( 1117cdf0e10cSrcweir rStartPoint, 1118cdf0e10cSrcweir aReliefOffset, 1119cdf0e10cSrcweir aReliefColor, 1120cdf0e10cSrcweir aShadowOffset, 1121cdf0e10cSrcweir aShadowColor, 1122cdf0e10cSrcweir aStrikeoutText, 1123cdf0e10cSrcweir nStartPos, 1124cdf0e10cSrcweir aStrikeoutText.Len(), 1125cdf0e10cSrcweir pStrikeoutCharWidths, 1126cdf0e10cSrcweir rParms.mrVDev, 1127cdf0e10cSrcweir rParms.mrCanvas, 1128cdf0e10cSrcweir rState, 1129cdf0e10cSrcweir rParms.mrParms, 1130cdf0e10cSrcweir bSubsettableActions ) ; 1131cdf0e10cSrcweir } 1132cdf0e10cSrcweir } 1133cdf0e10cSrcweir 1134cdf0e10cSrcweir if( pTextAction ) 1135cdf0e10cSrcweir { 1136cdf0e10cSrcweir maActions.push_back( 1137cdf0e10cSrcweir MtfAction( 1138cdf0e10cSrcweir pTextAction, 1139cdf0e10cSrcweir rParms.mrCurrActionIndex ) ); 1140cdf0e10cSrcweir 1141cdf0e10cSrcweir if ( pStrikeoutTextAction ) 1142cdf0e10cSrcweir { 1143cdf0e10cSrcweir maActions.push_back( 1144cdf0e10cSrcweir MtfAction( 1145cdf0e10cSrcweir pStrikeoutTextAction, 1146cdf0e10cSrcweir rParms.mrCurrActionIndex ) ); 1147cdf0e10cSrcweir } 1148cdf0e10cSrcweir 1149cdf0e10cSrcweir rParms.mrCurrActionIndex += pTextAction->getActionCount()-1; 1150cdf0e10cSrcweir } 1151cdf0e10cSrcweir } 1152cdf0e10cSrcweir 1153cdf0e10cSrcweir void ImplRenderer::updateClipping( const ::basegfx::B2DPolyPolygon& rClipPoly, 1154cdf0e10cSrcweir const ActionFactoryParameters& rParms, 1155cdf0e10cSrcweir bool bIntersect ) 1156cdf0e10cSrcweir { 1157cdf0e10cSrcweir ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); 1158cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly( rClipPoly ); 1159cdf0e10cSrcweir 1160cdf0e10cSrcweir const bool bEmptyClipRect( rState.clipRect.IsEmpty() ); 1161cdf0e10cSrcweir const bool bEmptyClipPoly( rState.clip.count() == 0 ); 1162cdf0e10cSrcweir 1163cdf0e10cSrcweir ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect, 1164cdf0e10cSrcweir "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" ); 1165cdf0e10cSrcweir 1166cdf0e10cSrcweir if( !bIntersect || 1167cdf0e10cSrcweir (bEmptyClipRect && bEmptyClipPoly) ) 1168cdf0e10cSrcweir { 1169cdf0e10cSrcweir rState.clip = rClipPoly; 1170cdf0e10cSrcweir } 1171cdf0e10cSrcweir else 1172cdf0e10cSrcweir { 1173cdf0e10cSrcweir if( !bEmptyClipRect ) 1174cdf0e10cSrcweir { 1175cdf0e10cSrcweir // TODO(P3): Use Liang-Barsky polygon clip here, 1176cdf0e10cSrcweir // after all, one object is just a rectangle! 1177cdf0e10cSrcweir 1178cdf0e10cSrcweir // convert rect to polygon beforehand, must revert 1179cdf0e10cSrcweir // to general polygon clipping here. 1180cdf0e10cSrcweir rState.clip = ::basegfx::B2DPolyPolygon( 1181cdf0e10cSrcweir ::basegfx::tools::createPolygonFromRect( 1182cdf0e10cSrcweir // #121100# VCL rectangular clips always 1183cdf0e10cSrcweir // include one more pixel to the right 1184cdf0e10cSrcweir // and the bottom 1185cdf0e10cSrcweir ::basegfx::B2DRectangle( rState.clipRect.Left(), 1186cdf0e10cSrcweir rState.clipRect.Top(), 1187cdf0e10cSrcweir rState.clipRect.Right()+1, 1188cdf0e10cSrcweir rState.clipRect.Bottom()+1 ) ) ); 1189cdf0e10cSrcweir } 1190cdf0e10cSrcweir 1191cdf0e10cSrcweir // AW: Simplified 1192cdf0e10cSrcweir rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon( 1193cdf0e10cSrcweir aClipPoly, rState.clip, true, false); 1194cdf0e10cSrcweir } 1195cdf0e10cSrcweir 1196cdf0e10cSrcweir // by now, our clip resides in the OutDevState::clip 1197cdf0e10cSrcweir // poly-polygon. 1198cdf0e10cSrcweir rState.clipRect.SetEmpty(); 1199cdf0e10cSrcweir 1200cdf0e10cSrcweir if( rState.clip.count() == 0 ) 1201cdf0e10cSrcweir { 1202cdf0e10cSrcweir if( rState.clipRect.IsEmpty() ) 1203cdf0e10cSrcweir { 1204cdf0e10cSrcweir rState.xClipPoly.clear(); 1205cdf0e10cSrcweir } 1206cdf0e10cSrcweir else 1207cdf0e10cSrcweir { 1208cdf0e10cSrcweir rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( 1209cdf0e10cSrcweir rParms.mrCanvas->getUNOCanvas()->getDevice(), 1210cdf0e10cSrcweir ::basegfx::B2DPolyPolygon( 1211cdf0e10cSrcweir ::basegfx::tools::createPolygonFromRect( 1212cdf0e10cSrcweir // #121100# VCL rectangular clips 1213cdf0e10cSrcweir // always include one more pixel to 1214cdf0e10cSrcweir // the right and the bottom 1215cdf0e10cSrcweir ::basegfx::B2DRectangle( rState.clipRect.Left(), 1216cdf0e10cSrcweir rState.clipRect.Top(), 1217cdf0e10cSrcweir rState.clipRect.Right()+1, 1218cdf0e10cSrcweir rState.clipRect.Bottom()+1 ) ) ) ); 1219cdf0e10cSrcweir } 1220cdf0e10cSrcweir } 1221cdf0e10cSrcweir else 1222cdf0e10cSrcweir { 1223cdf0e10cSrcweir rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( 1224cdf0e10cSrcweir rParms.mrCanvas->getUNOCanvas()->getDevice(), 1225cdf0e10cSrcweir rState.clip ); 1226cdf0e10cSrcweir } 1227cdf0e10cSrcweir } 1228cdf0e10cSrcweir 1229cdf0e10cSrcweir void ImplRenderer::updateClipping( const ::Rectangle& rClipRect, 1230cdf0e10cSrcweir const ActionFactoryParameters& rParms, 1231cdf0e10cSrcweir bool bIntersect ) 1232cdf0e10cSrcweir { 1233cdf0e10cSrcweir ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); 1234cdf0e10cSrcweir 1235cdf0e10cSrcweir const bool bEmptyClipRect( rState.clipRect.IsEmpty() ); 1236cdf0e10cSrcweir const bool bEmptyClipPoly( rState.clip.count() == 0 ); 1237cdf0e10cSrcweir 1238cdf0e10cSrcweir ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect, 1239cdf0e10cSrcweir "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" ); 1240cdf0e10cSrcweir 1241cdf0e10cSrcweir if( !bIntersect || 1242cdf0e10cSrcweir (bEmptyClipRect && bEmptyClipPoly) ) 1243cdf0e10cSrcweir { 1244cdf0e10cSrcweir rState.clipRect = rClipRect; 1245cdf0e10cSrcweir rState.clip.clear(); 1246cdf0e10cSrcweir } 1247cdf0e10cSrcweir else if( bEmptyClipPoly ) 1248cdf0e10cSrcweir { 1249cdf0e10cSrcweir rState.clipRect.Intersection( rClipRect ); 1250cdf0e10cSrcweir rState.clip.clear(); 1251cdf0e10cSrcweir } 1252cdf0e10cSrcweir else 1253cdf0e10cSrcweir { 1254cdf0e10cSrcweir // TODO(P3): Handle a fourth case here, when all clip 1255cdf0e10cSrcweir // polygons are rectangular, once B2DMultiRange's 1256cdf0e10cSrcweir // sweep line implementation is done. 1257cdf0e10cSrcweir 1258cdf0e10cSrcweir // general case: convert to polygon and clip 1259cdf0e10cSrcweir // ----------------------------------------- 1260cdf0e10cSrcweir 1261cdf0e10cSrcweir // convert rect to polygon beforehand, must revert 1262cdf0e10cSrcweir // to general polygon clipping here. 1263cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly( 1264cdf0e10cSrcweir ::basegfx::tools::createPolygonFromRect( 1265cdf0e10cSrcweir ::basegfx::B2DRectangle( rClipRect.Left(), 1266cdf0e10cSrcweir rClipRect.Top(), 1267cdf0e10cSrcweir rClipRect.Right(), 1268cdf0e10cSrcweir rClipRect.Bottom() ) ) ); 1269cdf0e10cSrcweir 1270cdf0e10cSrcweir rState.clipRect.SetEmpty(); 1271cdf0e10cSrcweir 1272cdf0e10cSrcweir // AW: Simplified 1273cdf0e10cSrcweir rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon( 1274cdf0e10cSrcweir aClipPoly, rState.clip, true, false); 1275cdf0e10cSrcweir } 1276cdf0e10cSrcweir 1277cdf0e10cSrcweir if( rState.clip.count() == 0 ) 1278cdf0e10cSrcweir { 1279cdf0e10cSrcweir if( rState.clipRect.IsEmpty() ) 1280cdf0e10cSrcweir { 1281cdf0e10cSrcweir rState.xClipPoly.clear(); 1282cdf0e10cSrcweir } 1283cdf0e10cSrcweir else 1284cdf0e10cSrcweir { 1285cdf0e10cSrcweir rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( 1286cdf0e10cSrcweir rParms.mrCanvas->getUNOCanvas()->getDevice(), 1287cdf0e10cSrcweir ::basegfx::B2DPolyPolygon( 1288cdf0e10cSrcweir ::basegfx::tools::createPolygonFromRect( 1289cdf0e10cSrcweir // #121100# VCL rectangular clips 1290cdf0e10cSrcweir // always include one more pixel to 1291cdf0e10cSrcweir // the right and the bottom 1292cdf0e10cSrcweir ::basegfx::B2DRectangle( rState.clipRect.Left(), 1293cdf0e10cSrcweir rState.clipRect.Top(), 1294cdf0e10cSrcweir rState.clipRect.Right()+1, 1295cdf0e10cSrcweir rState.clipRect.Bottom()+1 ) ) ) ); 1296cdf0e10cSrcweir } 1297cdf0e10cSrcweir } 1298cdf0e10cSrcweir else 1299cdf0e10cSrcweir { 1300cdf0e10cSrcweir rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( 1301cdf0e10cSrcweir rParms.mrCanvas->getUNOCanvas()->getDevice(), 1302cdf0e10cSrcweir rState.clip ); 1303cdf0e10cSrcweir } 1304cdf0e10cSrcweir } 1305cdf0e10cSrcweir 1306cdf0e10cSrcweir bool ImplRenderer::createActions( GDIMetaFile& rMtf, 1307cdf0e10cSrcweir const ActionFactoryParameters& rFactoryParms, 1308cdf0e10cSrcweir bool bSubsettableActions ) 1309cdf0e10cSrcweir { 1310cdf0e10cSrcweir /* TODO(P2): interpret mtf-comments 1311cdf0e10cSrcweir ================================ 1312cdf0e10cSrcweir 1313cdf0e10cSrcweir - gradient fillings (do that via comments) 1314cdf0e10cSrcweir 1315cdf0e10cSrcweir - think about mapping. _If_ we do everything in logical 1316cdf0e10cSrcweir coordinates (which would solve the probs for stroke 1317cdf0e10cSrcweir widths and text offsets), then we would have to 1318cdf0e10cSrcweir recalc scaling for every drawing operation. This is 1319cdf0e10cSrcweir because the outdev map mode might change at any time. 1320cdf0e10cSrcweir Also keep in mind, that, although we've double precision 1321cdf0e10cSrcweir float arithmetic now, different offsets might still 1322cdf0e10cSrcweir generate different roundings (aka 1323cdf0e10cSrcweir 'OutputDevice::SetPixelOffset()) 1324cdf0e10cSrcweir 1325cdf0e10cSrcweir */ 1326cdf0e10cSrcweir 1327cdf0e10cSrcweir // alias common parameters 1328cdf0e10cSrcweir VectorOfOutDevStates& rStates(rFactoryParms.mrStates); 1329cdf0e10cSrcweir const CanvasSharedPtr& rCanvas(rFactoryParms.mrCanvas); 1330cdf0e10cSrcweir ::VirtualDevice& rVDev(rFactoryParms.mrVDev); 1331cdf0e10cSrcweir const Parameters& rParms(rFactoryParms.mrParms); 1332cdf0e10cSrcweir sal_Int32& io_rCurrActionIndex(rFactoryParms.mrCurrActionIndex); 1333cdf0e10cSrcweir 1334cdf0e10cSrcweir 1335cdf0e10cSrcweir // Loop over every metaaction 1336cdf0e10cSrcweir // ========================== 1337cdf0e10cSrcweir MetaAction* pCurrAct; 1338cdf0e10cSrcweir 1339cdf0e10cSrcweir // TODO(P1): think about caching 1340cdf0e10cSrcweir for( pCurrAct=rMtf.FirstAction(); 1341cdf0e10cSrcweir pCurrAct; 1342cdf0e10cSrcweir pCurrAct = rMtf.NextAction() ) 1343cdf0e10cSrcweir { 1344cdf0e10cSrcweir // execute every action, to keep VDev state up-to-date 1345cdf0e10cSrcweir // currently used only for 1346cdf0e10cSrcweir // - the map mode 1347cdf0e10cSrcweir // - the line/fill color when processing a META_TRANSPARENT_ACTION 1348cdf0e10cSrcweir // - SetFont to process font metric specific actions 1349cdf0e10cSrcweir pCurrAct->Execute( &rVDev ); 1350cdf0e10cSrcweir 1351cdf0e10cSrcweir switch( pCurrAct->GetType() ) 1352cdf0e10cSrcweir { 1353cdf0e10cSrcweir // ------------------------------------------------------------ 1354cdf0e10cSrcweir 1355cdf0e10cSrcweir // In the first part of this monster-switch, we 1356cdf0e10cSrcweir // handle all state-changing meta actions. These 1357cdf0e10cSrcweir // are all handled locally. 1358cdf0e10cSrcweir 1359cdf0e10cSrcweir // ------------------------------------------------------------ 1360cdf0e10cSrcweir 1361cdf0e10cSrcweir case META_PUSH_ACTION: 1362cdf0e10cSrcweir { 1363cdf0e10cSrcweir MetaPushAction* pPushAction = static_cast<MetaPushAction*>(pCurrAct); 1364cdf0e10cSrcweir pushState( rStates, 1365cdf0e10cSrcweir pPushAction->GetFlags() ); 1366cdf0e10cSrcweir } 1367cdf0e10cSrcweir break; 1368cdf0e10cSrcweir 1369cdf0e10cSrcweir case META_POP_ACTION: 1370cdf0e10cSrcweir popState( rStates ); 1371cdf0e10cSrcweir break; 1372cdf0e10cSrcweir 1373cdf0e10cSrcweir case META_TEXTLANGUAGE_ACTION: 1374cdf0e10cSrcweir // FALLTHROUGH intended 1375cdf0e10cSrcweir case META_REFPOINT_ACTION: 1376cdf0e10cSrcweir // handled via pCurrAct->Execute( &rVDev ) 1377cdf0e10cSrcweir break; 1378cdf0e10cSrcweir 1379cdf0e10cSrcweir case META_MAPMODE_ACTION: 1380cdf0e10cSrcweir // modify current mapModeTransformation 1381cdf0e10cSrcweir // transformation, such that subsequent 1382cdf0e10cSrcweir // coordinates map correctly 1383cdf0e10cSrcweir tools::calcLogic2PixelAffineTransform( getState( rStates ).mapModeTransform, 1384cdf0e10cSrcweir rVDev ); 1385cdf0e10cSrcweir break; 1386cdf0e10cSrcweir 1387cdf0e10cSrcweir // monitor clip regions, to assemble clip polygon on our own 1388cdf0e10cSrcweir case META_CLIPREGION_ACTION: 1389cdf0e10cSrcweir { 1390cdf0e10cSrcweir MetaClipRegionAction* pClipAction = static_cast<MetaClipRegionAction*>(pCurrAct); 1391cdf0e10cSrcweir 1392cdf0e10cSrcweir if( !pClipAction->IsClipping() ) 1393cdf0e10cSrcweir { 1394cdf0e10cSrcweir // clear clipping 1395cdf0e10cSrcweir getState( rStates ).clip.clear(); 1396cdf0e10cSrcweir } 1397cdf0e10cSrcweir else 1398cdf0e10cSrcweir { 1399cdf0e10cSrcweir if( !pClipAction->GetRegion().HasPolyPolygon() ) 1400cdf0e10cSrcweir { 1401cdf0e10cSrcweir VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " 1402cdf0e10cSrcweir "region encountered, falling back to bounding box!" ); 1403cdf0e10cSrcweir 1404cdf0e10cSrcweir // #121806# explicitely kept integer 1405cdf0e10cSrcweir Rectangle aClipRect( 1406cdf0e10cSrcweir rVDev.LogicToPixel( 1407cdf0e10cSrcweir pClipAction->GetRegion().GetBoundRect() ) ); 1408cdf0e10cSrcweir 1409cdf0e10cSrcweir // intersect current clip with given rect 1410cdf0e10cSrcweir updateClipping( 1411cdf0e10cSrcweir aClipRect, 1412cdf0e10cSrcweir rFactoryParms, 1413cdf0e10cSrcweir false ); 1414cdf0e10cSrcweir } 1415cdf0e10cSrcweir else 1416cdf0e10cSrcweir { 1417cdf0e10cSrcweir // set new clip polygon (don't intersect 1418cdf0e10cSrcweir // with old one, just set it) 1419cdf0e10cSrcweir 1420cdf0e10cSrcweir // #121806# explicitely kept integer 1421cdf0e10cSrcweir updateClipping( 1422cdf0e10cSrcweir rVDev.LogicToPixel( 1423cdf0e10cSrcweir pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), 1424cdf0e10cSrcweir rFactoryParms, 1425cdf0e10cSrcweir false ); 1426cdf0e10cSrcweir } 1427cdf0e10cSrcweir } 1428cdf0e10cSrcweir 1429cdf0e10cSrcweir break; 1430cdf0e10cSrcweir } 1431cdf0e10cSrcweir 1432cdf0e10cSrcweir case META_ISECTRECTCLIPREGION_ACTION: 1433cdf0e10cSrcweir { 1434cdf0e10cSrcweir MetaISectRectClipRegionAction* pClipAction = static_cast<MetaISectRectClipRegionAction*>(pCurrAct); 1435cdf0e10cSrcweir 1436cdf0e10cSrcweir // #121806# explicitely kept integer 1437cdf0e10cSrcweir Rectangle aClipRect( 1438cdf0e10cSrcweir rVDev.LogicToPixel( pClipAction->GetRect() ) ); 1439cdf0e10cSrcweir 1440cdf0e10cSrcweir // intersect current clip with given rect 1441cdf0e10cSrcweir updateClipping( 1442cdf0e10cSrcweir aClipRect, 1443cdf0e10cSrcweir rFactoryParms, 1444cdf0e10cSrcweir true ); 1445cdf0e10cSrcweir 1446cdf0e10cSrcweir break; 1447cdf0e10cSrcweir } 1448cdf0e10cSrcweir 1449cdf0e10cSrcweir case META_ISECTREGIONCLIPREGION_ACTION: 1450cdf0e10cSrcweir { 1451cdf0e10cSrcweir MetaISectRegionClipRegionAction* pClipAction = static_cast<MetaISectRegionClipRegionAction*>(pCurrAct); 1452cdf0e10cSrcweir 1453cdf0e10cSrcweir if( !pClipAction->GetRegion().HasPolyPolygon() ) 1454cdf0e10cSrcweir { 1455cdf0e10cSrcweir VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " 1456cdf0e10cSrcweir "region encountered, falling back to bounding box!" ); 1457cdf0e10cSrcweir 1458cdf0e10cSrcweir // #121806# explicitely kept integer 1459cdf0e10cSrcweir Rectangle aClipRect( 1460cdf0e10cSrcweir rVDev.LogicToPixel( pClipAction->GetRegion().GetBoundRect() ) ); 1461cdf0e10cSrcweir 1462cdf0e10cSrcweir // intersect current clip with given rect 1463cdf0e10cSrcweir updateClipping( 1464cdf0e10cSrcweir aClipRect, 1465cdf0e10cSrcweir rFactoryParms, 1466cdf0e10cSrcweir true ); 1467cdf0e10cSrcweir } 1468cdf0e10cSrcweir else 1469cdf0e10cSrcweir { 1470cdf0e10cSrcweir // intersect current clip with given clip polygon 1471cdf0e10cSrcweir 1472cdf0e10cSrcweir // #121806# explicitely kept integer 1473cdf0e10cSrcweir updateClipping( 1474cdf0e10cSrcweir rVDev.LogicToPixel( 1475cdf0e10cSrcweir pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), 1476cdf0e10cSrcweir rFactoryParms, 1477cdf0e10cSrcweir true ); 1478cdf0e10cSrcweir } 1479cdf0e10cSrcweir 1480cdf0e10cSrcweir break; 1481cdf0e10cSrcweir } 1482cdf0e10cSrcweir 1483cdf0e10cSrcweir case META_MOVECLIPREGION_ACTION: 1484cdf0e10cSrcweir // TODO(F2): NYI 1485cdf0e10cSrcweir break; 1486cdf0e10cSrcweir 1487cdf0e10cSrcweir case META_LINECOLOR_ACTION: 1488cdf0e10cSrcweir if( !rParms.maLineColor.is_initialized() ) 1489cdf0e10cSrcweir { 1490cdf0e10cSrcweir setStateColor( static_cast<MetaLineColorAction*>(pCurrAct), 1491cdf0e10cSrcweir getState( rStates ).isLineColorSet, 1492cdf0e10cSrcweir getState( rStates ).lineColor, 1493cdf0e10cSrcweir rCanvas ); 1494cdf0e10cSrcweir } 1495cdf0e10cSrcweir break; 1496cdf0e10cSrcweir 1497cdf0e10cSrcweir case META_FILLCOLOR_ACTION: 1498cdf0e10cSrcweir if( !rParms.maFillColor.is_initialized() ) 1499cdf0e10cSrcweir { 1500cdf0e10cSrcweir setStateColor( static_cast<MetaFillColorAction*>(pCurrAct), 1501cdf0e10cSrcweir getState( rStates ).isFillColorSet, 1502cdf0e10cSrcweir getState( rStates ).fillColor, 1503cdf0e10cSrcweir rCanvas ); 1504cdf0e10cSrcweir } 1505cdf0e10cSrcweir break; 1506cdf0e10cSrcweir 1507cdf0e10cSrcweir case META_TEXTCOLOR_ACTION: 1508cdf0e10cSrcweir { 1509cdf0e10cSrcweir if( !rParms.maTextColor.is_initialized() ) 1510cdf0e10cSrcweir { 1511cdf0e10cSrcweir // Text color is set unconditionally, thus, no 1512cdf0e10cSrcweir // use of setStateColor here 1513cdf0e10cSrcweir ::Color aColor( static_cast<MetaTextColorAction*>(pCurrAct)->GetColor() ); 1514cdf0e10cSrcweir 1515cdf0e10cSrcweir // force alpha part of color to 1516cdf0e10cSrcweir // opaque. transparent painting is done 1517cdf0e10cSrcweir // explicitely via META_TRANSPARENT_ACTION 1518cdf0e10cSrcweir aColor.SetTransparency(0); 1519cdf0e10cSrcweir 1520cdf0e10cSrcweir getState( rStates ).textColor = 1521cdf0e10cSrcweir ::vcl::unotools::colorToDoubleSequence( 1522cdf0e10cSrcweir aColor, 1523cdf0e10cSrcweir rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); 1524cdf0e10cSrcweir } 1525cdf0e10cSrcweir } 1526cdf0e10cSrcweir break; 1527cdf0e10cSrcweir 1528cdf0e10cSrcweir case META_TEXTFILLCOLOR_ACTION: 1529cdf0e10cSrcweir if( !rParms.maTextColor.is_initialized() ) 1530cdf0e10cSrcweir { 1531cdf0e10cSrcweir setStateColor( static_cast<MetaTextFillColorAction*>(pCurrAct), 1532cdf0e10cSrcweir getState( rStates ).isTextFillColorSet, 1533cdf0e10cSrcweir getState( rStates ).textFillColor, 1534cdf0e10cSrcweir rCanvas ); 1535cdf0e10cSrcweir } 1536cdf0e10cSrcweir break; 1537cdf0e10cSrcweir 1538cdf0e10cSrcweir case META_TEXTLINECOLOR_ACTION: 1539cdf0e10cSrcweir if( !rParms.maTextColor.is_initialized() ) 1540cdf0e10cSrcweir { 1541cdf0e10cSrcweir setStateColor( static_cast<MetaTextLineColorAction*>(pCurrAct), 1542cdf0e10cSrcweir getState( rStates ).isTextLineColorSet, 1543cdf0e10cSrcweir getState( rStates ).textLineColor, 1544cdf0e10cSrcweir rCanvas ); 1545cdf0e10cSrcweir } 1546cdf0e10cSrcweir break; 1547cdf0e10cSrcweir 1548cdf0e10cSrcweir case META_TEXTALIGN_ACTION: 1549cdf0e10cSrcweir { 1550cdf0e10cSrcweir ::cppcanvas::internal::OutDevState& rState = getState( rStates ); 1551cdf0e10cSrcweir const TextAlign eTextAlign( static_cast<MetaTextAlignAction*>(pCurrAct)->GetTextAlign() ); 1552cdf0e10cSrcweir 1553cdf0e10cSrcweir rState.textReferencePoint = eTextAlign; 1554cdf0e10cSrcweir } 1555cdf0e10cSrcweir break; 1556cdf0e10cSrcweir 1557cdf0e10cSrcweir case META_FONT_ACTION: 1558cdf0e10cSrcweir { 1559cdf0e10cSrcweir ::cppcanvas::internal::OutDevState& rState = getState( rStates ); 1560cdf0e10cSrcweir const ::Font& rFont( static_cast<MetaFontAction*>(pCurrAct)->GetFont() ); 1561cdf0e10cSrcweir 1562cdf0e10cSrcweir rState.xFont = createFont( rState.fontRotation, 1563cdf0e10cSrcweir rFont, 1564cdf0e10cSrcweir rFactoryParms ); 1565cdf0e10cSrcweir 1566cdf0e10cSrcweir // TODO(Q2): define and use appropriate enumeration types 1567cdf0e10cSrcweir rState.textReliefStyle = (sal_Int8)rFont.GetRelief(); 1568cdf0e10cSrcweir rState.textOverlineStyle = (sal_Int8)rFont.GetOverline(); 1569cdf0e10cSrcweir rState.textUnderlineStyle = rParms.maFontUnderline.is_initialized() ? 1570cdf0e10cSrcweir (*rParms.maFontUnderline ? (sal_Int8)UNDERLINE_SINGLE : (sal_Int8)UNDERLINE_NONE) : 1571cdf0e10cSrcweir (sal_Int8)rFont.GetUnderline(); 1572cdf0e10cSrcweir rState.textStrikeoutStyle = (sal_Int8)rFont.GetStrikeout(); 1573cdf0e10cSrcweir rState.textEmphasisMarkStyle = (sal_Int8)rFont.GetEmphasisMark(); 1574cdf0e10cSrcweir rState.isTextEffectShadowSet = (rFont.IsShadow() != sal_False); 1575cdf0e10cSrcweir rState.isTextWordUnderlineSet = (rFont.IsWordLineMode() != sal_False); 1576cdf0e10cSrcweir rState.isTextOutlineModeSet = (rFont.IsOutline() != sal_False); 1577cdf0e10cSrcweir } 1578cdf0e10cSrcweir break; 1579cdf0e10cSrcweir 1580cdf0e10cSrcweir case META_RASTEROP_ACTION: 1581cdf0e10cSrcweir // TODO(F2): NYI 1582cdf0e10cSrcweir break; 1583cdf0e10cSrcweir 1584cdf0e10cSrcweir case META_LAYOUTMODE_ACTION: 1585cdf0e10cSrcweir { 1586cdf0e10cSrcweir // TODO(F2): A lot is missing here 1587cdf0e10cSrcweir int nLayoutMode = static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode(); 1588cdf0e10cSrcweir ::cppcanvas::internal::OutDevState& rState = getState( rStates ); 1589cdf0e10cSrcweir switch( nLayoutMode & (TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_BIDI_STRONG) ) 1590cdf0e10cSrcweir { 1591cdf0e10cSrcweir case TEXT_LAYOUT_BIDI_LTR: 1592cdf0e10cSrcweir rState.textDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT; 1593cdf0e10cSrcweir break; 1594cdf0e10cSrcweir 1595cdf0e10cSrcweir case (TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG): 1596cdf0e10cSrcweir rState.textDirection = rendering::TextDirection::STRONG_LEFT_TO_RIGHT; 1597cdf0e10cSrcweir break; 1598cdf0e10cSrcweir 1599cdf0e10cSrcweir case TEXT_LAYOUT_BIDI_RTL: 1600cdf0e10cSrcweir rState.textDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT; 1601cdf0e10cSrcweir break; 1602cdf0e10cSrcweir 1603cdf0e10cSrcweir case (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG): 1604cdf0e10cSrcweir rState.textDirection = rendering::TextDirection::STRONG_RIGHT_TO_LEFT; 1605cdf0e10cSrcweir break; 1606cdf0e10cSrcweir } 1607cdf0e10cSrcweir 1608cdf0e10cSrcweir rState.textAlignment = 0; // TODO(F2): rendering::TextAlignment::LEFT_ALIGNED; 1609cdf0e10cSrcweir if( (nLayoutMode & (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_RIGHT) ) 1610cdf0e10cSrcweir && !(nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT ) ) 1611cdf0e10cSrcweir { 1612cdf0e10cSrcweir rState.textAlignment = 1; // TODO(F2): rendering::TextAlignment::RIGHT_ALIGNED; 1613cdf0e10cSrcweir } 1614cdf0e10cSrcweir } 1615cdf0e10cSrcweir break; 1616cdf0e10cSrcweir 1617cdf0e10cSrcweir // ------------------------------------------------------------ 1618cdf0e10cSrcweir 1619cdf0e10cSrcweir // In the second part of this monster-switch, we 1620cdf0e10cSrcweir // handle all recursing meta actions. These are the 1621cdf0e10cSrcweir // ones generating a metafile by themselves, which is 1622cdf0e10cSrcweir // then processed by recursively calling this method. 1623cdf0e10cSrcweir 1624cdf0e10cSrcweir // ------------------------------------------------------------ 1625cdf0e10cSrcweir 1626cdf0e10cSrcweir case META_GRADIENT_ACTION: 1627cdf0e10cSrcweir { 1628cdf0e10cSrcweir MetaGradientAction* pGradAct = static_cast<MetaGradientAction*>(pCurrAct); 1629cdf0e10cSrcweir createGradientAction( ::Polygon( pGradAct->GetRect() ), 1630cdf0e10cSrcweir pGradAct->GetGradient(), 1631cdf0e10cSrcweir rFactoryParms, 1632cdf0e10cSrcweir true, 1633cdf0e10cSrcweir bSubsettableActions ); 1634cdf0e10cSrcweir } 1635cdf0e10cSrcweir break; 1636cdf0e10cSrcweir 1637cdf0e10cSrcweir case META_HATCH_ACTION: 1638cdf0e10cSrcweir { 1639cdf0e10cSrcweir // TODO(F2): use native Canvas hatches here 1640cdf0e10cSrcweir GDIMetaFile aTmpMtf; 1641cdf0e10cSrcweir 1642cdf0e10cSrcweir rVDev.AddHatchActions( static_cast<MetaHatchAction*>(pCurrAct)->GetPolyPolygon(), 1643cdf0e10cSrcweir static_cast<MetaHatchAction*>(pCurrAct)->GetHatch(), 1644cdf0e10cSrcweir aTmpMtf ); 1645cdf0e10cSrcweir createActions( aTmpMtf, rFactoryParms, 1646cdf0e10cSrcweir bSubsettableActions ); 1647cdf0e10cSrcweir } 1648cdf0e10cSrcweir break; 1649cdf0e10cSrcweir 1650cdf0e10cSrcweir case META_EPS_ACTION: 1651cdf0e10cSrcweir { 1652cdf0e10cSrcweir MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pCurrAct); 1653cdf0e10cSrcweir const GDIMetaFile& rSubstitute = pAct->GetSubstitute(); 1654cdf0e10cSrcweir 1655cdf0e10cSrcweir // #121806# explicitely kept integer 1656cdf0e10cSrcweir const Size aMtfSize( rSubstitute.GetPrefSize() ); 1657cdf0e10cSrcweir const Size aMtfSizePixPre( rVDev.LogicToPixel( aMtfSize, 1658cdf0e10cSrcweir rSubstitute.GetPrefMapMode() ) ); 1659cdf0e10cSrcweir 1660cdf0e10cSrcweir // #i44110# correct null-sized output - there 1661cdf0e10cSrcweir // are metafiles which have zero size in at 1662cdf0e10cSrcweir // least one dimension 1663cdf0e10cSrcweir const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ), 1664cdf0e10cSrcweir ::std::max( aMtfSizePixPre.Height(), 1L ) ); 1665cdf0e10cSrcweir 1666cdf0e10cSrcweir // Setup local transform, such that the 1667cdf0e10cSrcweir // metafile renders itself into the given 1668cdf0e10cSrcweir // output rectangle 1669cdf0e10cSrcweir pushState( rStates, PUSH_ALL ); 1670cdf0e10cSrcweir 1671cdf0e10cSrcweir rVDev.Push(); 1672cdf0e10cSrcweir rVDev.SetMapMode( rSubstitute.GetPrefMapMode() ); 1673cdf0e10cSrcweir 1674cdf0e10cSrcweir const ::Point& rPos( rVDev.LogicToPixel( pAct->GetPoint() ) ); 1675cdf0e10cSrcweir const ::Size& rSize( rVDev.LogicToPixel( pAct->GetSize() ) ); 1676cdf0e10cSrcweir 1677cdf0e10cSrcweir getState( rStates ).transform.translate( rPos.X(), 1678cdf0e10cSrcweir rPos.Y() ); 1679cdf0e10cSrcweir getState( rStates ).transform.scale( (double)rSize.Width() / aMtfSizePix.Width(), 1680cdf0e10cSrcweir (double)rSize.Height() / aMtfSizePix.Height() ); 1681cdf0e10cSrcweir 1682cdf0e10cSrcweir createActions( const_cast<GDIMetaFile&>(pAct->GetSubstitute()), 1683cdf0e10cSrcweir rFactoryParms, 1684cdf0e10cSrcweir bSubsettableActions ); 1685cdf0e10cSrcweir 1686cdf0e10cSrcweir rVDev.Pop(); 1687cdf0e10cSrcweir popState( rStates ); 1688cdf0e10cSrcweir } 1689cdf0e10cSrcweir break; 1690cdf0e10cSrcweir 1691cdf0e10cSrcweir // handle metafile comments, to retrieve 1692cdf0e10cSrcweir // meta-information for gradients, fills and 1693cdf0e10cSrcweir // strokes. May skip actions, and may recurse. 1694cdf0e10cSrcweir case META_COMMENT_ACTION: 1695cdf0e10cSrcweir { 1696cdf0e10cSrcweir MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct); 1697cdf0e10cSrcweir 1698cdf0e10cSrcweir // Handle gradients 1699cdf0e10cSrcweir if ( pAct->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL ) 1700cdf0e10cSrcweir { 1701cdf0e10cSrcweir MetaGradientExAction* pGradAction = NULL; 1702cdf0e10cSrcweir bool bDone( false ); 1703cdf0e10cSrcweir while( !bDone && 1704cdf0e10cSrcweir (pCurrAct=rMtf.NextAction()) != NULL ) 1705cdf0e10cSrcweir { 1706cdf0e10cSrcweir switch( pCurrAct->GetType() ) 1707cdf0e10cSrcweir { 1708cdf0e10cSrcweir // extract gradient info 1709cdf0e10cSrcweir case META_GRADIENTEX_ACTION: 1710cdf0e10cSrcweir pGradAction = static_cast<MetaGradientExAction*>(pCurrAct); 1711cdf0e10cSrcweir break; 1712cdf0e10cSrcweir 1713cdf0e10cSrcweir // skip broken-down rendering, output gradient when sequence is ended 1714cdf0e10cSrcweir case META_COMMENT_ACTION: 1715cdf0e10cSrcweir if( static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) 1716cdf0e10cSrcweir { 1717cdf0e10cSrcweir bDone = true; 1718cdf0e10cSrcweir 1719cdf0e10cSrcweir if( pGradAction ) 1720cdf0e10cSrcweir { 1721cdf0e10cSrcweir createGradientAction( pGradAction->GetPolyPolygon(), 1722cdf0e10cSrcweir pGradAction->GetGradient(), 1723cdf0e10cSrcweir rFactoryParms, 1724cdf0e10cSrcweir false, 1725cdf0e10cSrcweir bSubsettableActions ); 1726cdf0e10cSrcweir } 1727cdf0e10cSrcweir } 1728cdf0e10cSrcweir break; 1729cdf0e10cSrcweir } 1730cdf0e10cSrcweir } 1731cdf0e10cSrcweir } 1732cdf0e10cSrcweir // TODO(P2): Handle drawing layer strokes, via 1733cdf0e10cSrcweir // XPATHSTROKE_SEQ_BEGIN comment 1734cdf0e10cSrcweir 1735cdf0e10cSrcweir // Handle drawing layer fills 1736cdf0e10cSrcweir else if( pAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) ) 1737cdf0e10cSrcweir { 1738cdf0e10cSrcweir const sal_uInt8* pData = pAct->GetData(); 1739cdf0e10cSrcweir if ( pData ) 1740cdf0e10cSrcweir { 1741cdf0e10cSrcweir SvMemoryStream aMemStm( (void*)pData, pAct->GetDataSize(), STREAM_READ ); 1742cdf0e10cSrcweir 1743cdf0e10cSrcweir SvtGraphicFill aFill; 1744cdf0e10cSrcweir aMemStm >> aFill; 1745cdf0e10cSrcweir 1746cdf0e10cSrcweir // TODO(P2): Also handle gradients and 1747cdf0e10cSrcweir // hatches like this 1748cdf0e10cSrcweir 1749cdf0e10cSrcweir // only evaluate comment for pure 1750cdf0e10cSrcweir // bitmap fills. If a transparency 1751cdf0e10cSrcweir // gradient is involved (denoted by 1752cdf0e10cSrcweir // the FloatTransparent action), take 1753cdf0e10cSrcweir // the normal meta actions. 1754cdf0e10cSrcweir if( aFill.getFillType() == SvtGraphicFill::fillTexture && 1755cdf0e10cSrcweir !isActionContained( rMtf, 1756cdf0e10cSrcweir "XPATHFILL_SEQ_END", 1757cdf0e10cSrcweir META_FLOATTRANSPARENT_ACTION ) ) 1758cdf0e10cSrcweir { 1759cdf0e10cSrcweir rendering::Texture aTexture; 1760cdf0e10cSrcweir 1761cdf0e10cSrcweir // TODO(F1): the SvtGraphicFill 1762cdf0e10cSrcweir // can also transport metafiles 1763cdf0e10cSrcweir // here, handle that case, too 1764cdf0e10cSrcweir Graphic aGraphic; 1765cdf0e10cSrcweir aFill.getGraphic( aGraphic ); 1766cdf0e10cSrcweir 1767cdf0e10cSrcweir BitmapEx aBmpEx( aGraphic.GetBitmapEx() ); 1768cdf0e10cSrcweir const ::Size aBmpSize( aBmpEx.GetSizePixel() ); 1769cdf0e10cSrcweir 1770cdf0e10cSrcweir ::SvtGraphicFill::Transform aTransform; 1771cdf0e10cSrcweir aFill.getTransform( aTransform ); 1772cdf0e10cSrcweir 1773cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 1774cdf0e10cSrcweir 1775cdf0e10cSrcweir // convert to basegfx matrix 1776cdf0e10cSrcweir aMatrix.set(0,0, aTransform.matrix[ 0 ] ); 1777cdf0e10cSrcweir aMatrix.set(0,1, aTransform.matrix[ 1 ] ); 1778cdf0e10cSrcweir aMatrix.set(0,2, aTransform.matrix[ 2 ] ); 1779cdf0e10cSrcweir aMatrix.set(1,0, aTransform.matrix[ 3 ] ); 1780cdf0e10cSrcweir aMatrix.set(1,1, aTransform.matrix[ 4 ] ); 1781cdf0e10cSrcweir aMatrix.set(1,2, aTransform.matrix[ 5 ] ); 1782cdf0e10cSrcweir 1783cdf0e10cSrcweir ::basegfx::B2DHomMatrix aScale; 1784cdf0e10cSrcweir aScale.scale( aBmpSize.Width(), 1785cdf0e10cSrcweir aBmpSize.Height() ); 1786cdf0e10cSrcweir 1787cdf0e10cSrcweir // post-multiply with the bitmap 1788cdf0e10cSrcweir // size (XCanvas' texture assumes 1789cdf0e10cSrcweir // the given bitmap to be 1790cdf0e10cSrcweir // normalized to [0,1]x[0,1] 1791cdf0e10cSrcweir // rectangle) 1792cdf0e10cSrcweir aMatrix = aMatrix * aScale; 1793cdf0e10cSrcweir 1794cdf0e10cSrcweir // pre-multiply with the 1795cdf0e10cSrcweir // logic-to-pixel scale factor 1796cdf0e10cSrcweir // (the metafile comment works in 1797cdf0e10cSrcweir // logical coordinates). 1798cdf0e10cSrcweir ::basegfx::B2DHomMatrix aLogic2PixelTransform; 1799cdf0e10cSrcweir aMatrix *= tools::calcLogic2PixelLinearTransform( aLogic2PixelTransform, 1800cdf0e10cSrcweir rVDev ); 1801cdf0e10cSrcweir 1802cdf0e10cSrcweir ::basegfx::unotools::affineMatrixFromHomMatrix( 1803cdf0e10cSrcweir aTexture.AffineTransform, 1804cdf0e10cSrcweir aMatrix ); 1805cdf0e10cSrcweir 1806cdf0e10cSrcweir aTexture.Alpha = 1.0 - aFill.getTransparency(); 1807cdf0e10cSrcweir aTexture.Bitmap = 1808cdf0e10cSrcweir ::vcl::unotools::xBitmapFromBitmapEx( 1809cdf0e10cSrcweir rCanvas->getUNOCanvas()->getDevice(), 1810cdf0e10cSrcweir aBmpEx ); 1811cdf0e10cSrcweir if( aFill.isTiling() ) 1812cdf0e10cSrcweir { 1813cdf0e10cSrcweir aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; 1814cdf0e10cSrcweir aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; 1815cdf0e10cSrcweir } 1816cdf0e10cSrcweir else 1817cdf0e10cSrcweir { 1818cdf0e10cSrcweir aTexture.RepeatModeX = rendering::TexturingMode::NONE; 1819cdf0e10cSrcweir aTexture.RepeatModeY = rendering::TexturingMode::NONE; 1820cdf0e10cSrcweir } 1821cdf0e10cSrcweir 1822cdf0e10cSrcweir ::PolyPolygon aPath; 1823cdf0e10cSrcweir aFill.getPath( aPath ); 1824cdf0e10cSrcweir 1825cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aPoly( aPath.getB2DPolyPolygon() ); 1826cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 1827cdf0e10cSrcweir ActionSharedPtr pPolyAction( 1828cdf0e10cSrcweir internal::PolyPolyActionFactory::createPolyPolyAction( 1829cdf0e10cSrcweir aPoly, 1830cdf0e10cSrcweir rCanvas, 1831cdf0e10cSrcweir getState( rStates ), 1832cdf0e10cSrcweir aTexture ) ); 1833cdf0e10cSrcweir 1834cdf0e10cSrcweir if( pPolyAction ) 1835cdf0e10cSrcweir { 1836cdf0e10cSrcweir maActions.push_back( 1837cdf0e10cSrcweir MtfAction( 1838cdf0e10cSrcweir pPolyAction, 1839cdf0e10cSrcweir io_rCurrActionIndex ) ); 1840cdf0e10cSrcweir 1841cdf0e10cSrcweir io_rCurrActionIndex += pPolyAction->getActionCount()-1; 1842cdf0e10cSrcweir } 1843cdf0e10cSrcweir 1844cdf0e10cSrcweir // skip broken-down render output 1845cdf0e10cSrcweir skipContent( rMtf, 1846cdf0e10cSrcweir "XPATHFILL_SEQ_END", 1847cdf0e10cSrcweir io_rCurrActionIndex ); 1848cdf0e10cSrcweir } 1849cdf0e10cSrcweir } 1850cdf0e10cSrcweir } 1851cdf0e10cSrcweir } 1852cdf0e10cSrcweir break; 1853cdf0e10cSrcweir 1854cdf0e10cSrcweir // ------------------------------------------------------------ 1855cdf0e10cSrcweir 1856cdf0e10cSrcweir // In the third part of this monster-switch, we 1857cdf0e10cSrcweir // handle all 'acting' meta actions. These are all 1858cdf0e10cSrcweir // processed by constructing function objects for 1859cdf0e10cSrcweir // them, which will later ease caching. 1860cdf0e10cSrcweir 1861cdf0e10cSrcweir // ------------------------------------------------------------ 1862cdf0e10cSrcweir 1863cdf0e10cSrcweir case META_POINT_ACTION: 1864cdf0e10cSrcweir { 1865cdf0e10cSrcweir const OutDevState& rState( getState( rStates ) ); 1866cdf0e10cSrcweir if( rState.lineColor.getLength() ) 1867cdf0e10cSrcweir { 1868cdf0e10cSrcweir ActionSharedPtr pPointAction( 1869cdf0e10cSrcweir internal::PointActionFactory::createPointAction( 1870cdf0e10cSrcweir rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( 1871cdf0e10cSrcweir static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ), 1872cdf0e10cSrcweir rCanvas, 1873cdf0e10cSrcweir rState ) ); 1874cdf0e10cSrcweir 1875cdf0e10cSrcweir if( pPointAction ) 1876cdf0e10cSrcweir { 1877cdf0e10cSrcweir maActions.push_back( 1878cdf0e10cSrcweir MtfAction( 1879cdf0e10cSrcweir pPointAction, 1880cdf0e10cSrcweir io_rCurrActionIndex ) ); 1881cdf0e10cSrcweir 1882cdf0e10cSrcweir io_rCurrActionIndex += pPointAction->getActionCount()-1; 1883cdf0e10cSrcweir } 1884cdf0e10cSrcweir } 1885cdf0e10cSrcweir } 1886cdf0e10cSrcweir break; 1887cdf0e10cSrcweir 1888cdf0e10cSrcweir case META_PIXEL_ACTION: 1889cdf0e10cSrcweir { 1890cdf0e10cSrcweir const OutDevState& rState( getState( rStates ) ); 1891cdf0e10cSrcweir if( rState.lineColor.getLength() ) 1892cdf0e10cSrcweir { 1893cdf0e10cSrcweir ActionSharedPtr pPointAction( 1894cdf0e10cSrcweir internal::PointActionFactory::createPointAction( 1895cdf0e10cSrcweir rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( 1896cdf0e10cSrcweir static_cast<MetaPixelAction*>(pCurrAct)->GetPoint() ), 1897cdf0e10cSrcweir rCanvas, 1898cdf0e10cSrcweir rState, 1899cdf0e10cSrcweir static_cast<MetaPixelAction*>(pCurrAct)->GetColor() ) ); 1900cdf0e10cSrcweir 1901cdf0e10cSrcweir if( pPointAction ) 1902cdf0e10cSrcweir { 1903cdf0e10cSrcweir maActions.push_back( 1904cdf0e10cSrcweir MtfAction( 1905cdf0e10cSrcweir pPointAction, 1906cdf0e10cSrcweir io_rCurrActionIndex ) ); 1907cdf0e10cSrcweir 1908cdf0e10cSrcweir io_rCurrActionIndex += pPointAction->getActionCount()-1; 1909cdf0e10cSrcweir } 1910cdf0e10cSrcweir } 1911cdf0e10cSrcweir } 1912cdf0e10cSrcweir break; 1913cdf0e10cSrcweir 1914cdf0e10cSrcweir case META_LINE_ACTION: 1915cdf0e10cSrcweir { 1916cdf0e10cSrcweir const OutDevState& rState( getState( rStates ) ); 1917cdf0e10cSrcweir if( rState.lineColor.getLength() ) 1918cdf0e10cSrcweir { 1919cdf0e10cSrcweir MetaLineAction* pLineAct = static_cast<MetaLineAction*>(pCurrAct); 1920cdf0e10cSrcweir 1921cdf0e10cSrcweir const LineInfo& rLineInfo( pLineAct->GetLineInfo() ); 1922cdf0e10cSrcweir 1923cdf0e10cSrcweir const ::basegfx::B2DPoint aStartPoint( 1924cdf0e10cSrcweir rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetStartPoint() )); 1925cdf0e10cSrcweir const ::basegfx::B2DPoint aEndPoint( 1926cdf0e10cSrcweir rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetEndPoint() )); 1927cdf0e10cSrcweir 1928cdf0e10cSrcweir ActionSharedPtr pLineAction; 1929cdf0e10cSrcweir 1930cdf0e10cSrcweir if( rLineInfo.IsDefault() ) 1931cdf0e10cSrcweir { 1932cdf0e10cSrcweir // plain hair line 1933cdf0e10cSrcweir pLineAction = 1934cdf0e10cSrcweir internal::LineActionFactory::createLineAction( 1935cdf0e10cSrcweir aStartPoint, 1936cdf0e10cSrcweir aEndPoint, 1937cdf0e10cSrcweir rCanvas, 1938cdf0e10cSrcweir rState ); 1939cdf0e10cSrcweir 1940cdf0e10cSrcweir if( pLineAction ) 1941cdf0e10cSrcweir { 1942cdf0e10cSrcweir maActions.push_back( 1943cdf0e10cSrcweir MtfAction( 1944cdf0e10cSrcweir pLineAction, 1945cdf0e10cSrcweir io_rCurrActionIndex ) ); 1946cdf0e10cSrcweir 1947cdf0e10cSrcweir io_rCurrActionIndex += pLineAction->getActionCount()-1; 1948cdf0e10cSrcweir } 1949cdf0e10cSrcweir } 1950cdf0e10cSrcweir else if( LINE_NONE != rLineInfo.GetStyle() ) 1951cdf0e10cSrcweir { 1952cdf0e10cSrcweir // 'thick' line 1953cdf0e10cSrcweir rendering::StrokeAttributes aStrokeAttributes; 1954cdf0e10cSrcweir 1955cdf0e10cSrcweir setupStrokeAttributes( aStrokeAttributes, 1956cdf0e10cSrcweir rFactoryParms, 1957cdf0e10cSrcweir rLineInfo ); 1958cdf0e10cSrcweir 1959cdf0e10cSrcweir // XCanvas can only stroke polygons, 1960cdf0e10cSrcweir // not simple lines - thus, handle 1961cdf0e10cSrcweir // this case via the polypolygon 1962cdf0e10cSrcweir // action 1963cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly; 1964cdf0e10cSrcweir aPoly.append( aStartPoint ); 1965cdf0e10cSrcweir aPoly.append( aEndPoint ); 1966cdf0e10cSrcweir pLineAction = 1967cdf0e10cSrcweir internal::PolyPolyActionFactory::createPolyPolyAction( 1968cdf0e10cSrcweir ::basegfx::B2DPolyPolygon( aPoly ), 1969cdf0e10cSrcweir rCanvas, rState, aStrokeAttributes ); 1970cdf0e10cSrcweir 1971cdf0e10cSrcweir if( pLineAction ) 1972cdf0e10cSrcweir { 1973cdf0e10cSrcweir maActions.push_back( 1974cdf0e10cSrcweir MtfAction( 1975cdf0e10cSrcweir pLineAction, 1976cdf0e10cSrcweir io_rCurrActionIndex ) ); 1977cdf0e10cSrcweir 1978cdf0e10cSrcweir io_rCurrActionIndex += pLineAction->getActionCount()-1; 1979cdf0e10cSrcweir } 1980cdf0e10cSrcweir } 1981cdf0e10cSrcweir // else: line style is default 1982cdf0e10cSrcweir // (i.e. invisible), don't generate action 1983cdf0e10cSrcweir } 1984cdf0e10cSrcweir } 1985cdf0e10cSrcweir break; 1986cdf0e10cSrcweir 1987cdf0e10cSrcweir case META_RECT_ACTION: 1988cdf0e10cSrcweir { 1989cdf0e10cSrcweir const Rectangle& rRect( 1990cdf0e10cSrcweir static_cast<MetaRectAction*>(pCurrAct)->GetRect() ); 1991cdf0e10cSrcweir 1992cdf0e10cSrcweir if( rRect.IsEmpty() ) 1993cdf0e10cSrcweir break; 1994cdf0e10cSrcweir 1995cdf0e10cSrcweir const OutDevState& rState( getState( rStates ) ); 1996cdf0e10cSrcweir const ::basegfx::B2DPoint aTopLeftPixel( 1997cdf0e10cSrcweir rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ) ); 1998cdf0e10cSrcweir const ::basegfx::B2DPoint aBottomRightPixel( 1999cdf0e10cSrcweir rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + 2000cdf0e10cSrcweir // #121100# OutputDevice::DrawRect() fills 2001cdf0e10cSrcweir // rectangles Apple-like, i.e. with one 2002cdf0e10cSrcweir // additional pixel to the right and bottom. 2003cdf0e10cSrcweir ::basegfx::B2DPoint(1,1) ); 2004cdf0e10cSrcweir 2005cdf0e10cSrcweir createFillAndStroke( ::basegfx::tools::createPolygonFromRect( 2006cdf0e10cSrcweir ::basegfx::B2DRange( aTopLeftPixel, 2007cdf0e10cSrcweir aBottomRightPixel )), 2008cdf0e10cSrcweir rFactoryParms ); 2009cdf0e10cSrcweir break; 2010cdf0e10cSrcweir } 2011cdf0e10cSrcweir 2012cdf0e10cSrcweir case META_ROUNDRECT_ACTION: 2013cdf0e10cSrcweir { 2014cdf0e10cSrcweir const Rectangle& rRect( 2015cdf0e10cSrcweir static_cast<MetaRoundRectAction*>(pCurrAct)->GetRect()); 2016cdf0e10cSrcweir 2017cdf0e10cSrcweir if( rRect.IsEmpty() ) 2018cdf0e10cSrcweir break; 2019cdf0e10cSrcweir 2020cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly( 2021cdf0e10cSrcweir ::basegfx::tools::createPolygonFromRect( 2022cdf0e10cSrcweir ::basegfx::B2DRange( 2023cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ), 2024cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + 2025cdf0e10cSrcweir ::basegfx::B2DPoint(1,1) ), 2026cdf0e10cSrcweir static_cast<MetaRoundRectAction*>(pCurrAct)->GetHorzRound(), 2027cdf0e10cSrcweir static_cast<MetaRoundRectAction*>(pCurrAct)->GetVertRound() )); 2028cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 2029cdf0e10cSrcweir 2030cdf0e10cSrcweir createFillAndStroke( aPoly, 2031cdf0e10cSrcweir rFactoryParms ); 2032cdf0e10cSrcweir } 2033cdf0e10cSrcweir break; 2034cdf0e10cSrcweir 2035cdf0e10cSrcweir case META_ELLIPSE_ACTION: 2036cdf0e10cSrcweir { 2037cdf0e10cSrcweir const Rectangle& rRect( 2038cdf0e10cSrcweir static_cast<MetaEllipseAction*>(pCurrAct)->GetRect() ); 2039cdf0e10cSrcweir 2040cdf0e10cSrcweir if( rRect.IsEmpty() ) 2041cdf0e10cSrcweir break; 2042cdf0e10cSrcweir 2043cdf0e10cSrcweir const ::basegfx::B2DRange aRange( 2044cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ), 2045cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + 2046cdf0e10cSrcweir ::basegfx::B2DPoint(1,1) ); 2047cdf0e10cSrcweir 2048cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly( 2049cdf0e10cSrcweir ::basegfx::tools::createPolygonFromEllipse( 2050cdf0e10cSrcweir aRange.getCenter(), 2051cdf0e10cSrcweir aRange.getWidth(), 2052cdf0e10cSrcweir aRange.getHeight() )); 2053cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 2054cdf0e10cSrcweir 2055cdf0e10cSrcweir createFillAndStroke( aPoly, 2056cdf0e10cSrcweir rFactoryParms ); 2057cdf0e10cSrcweir } 2058cdf0e10cSrcweir break; 2059cdf0e10cSrcweir 2060cdf0e10cSrcweir case META_ARC_ACTION: 2061cdf0e10cSrcweir { 2062cdf0e10cSrcweir // TODO(F1): Missing basegfx functionality. Mind empty rects! 2063cdf0e10cSrcweir const Polygon aToolsPoly( static_cast<MetaArcAction*>(pCurrAct)->GetRect(), 2064cdf0e10cSrcweir static_cast<MetaArcAction*>(pCurrAct)->GetStartPoint(), 2065cdf0e10cSrcweir static_cast<MetaArcAction*>(pCurrAct)->GetEndPoint(), POLY_ARC ); 2066cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); 2067cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 2068cdf0e10cSrcweir 2069cdf0e10cSrcweir createFillAndStroke( aPoly, 2070cdf0e10cSrcweir rFactoryParms ); 2071cdf0e10cSrcweir } 2072cdf0e10cSrcweir break; 2073cdf0e10cSrcweir 2074cdf0e10cSrcweir case META_PIE_ACTION: 2075cdf0e10cSrcweir { 2076cdf0e10cSrcweir // TODO(F1): Missing basegfx functionality. Mind empty rects! 2077cdf0e10cSrcweir const Polygon aToolsPoly( static_cast<MetaPieAction*>(pCurrAct)->GetRect(), 2078cdf0e10cSrcweir static_cast<MetaPieAction*>(pCurrAct)->GetStartPoint(), 2079cdf0e10cSrcweir static_cast<MetaPieAction*>(pCurrAct)->GetEndPoint(), POLY_PIE ); 2080cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); 2081cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 2082cdf0e10cSrcweir 2083cdf0e10cSrcweir createFillAndStroke( aPoly, 2084cdf0e10cSrcweir rFactoryParms ); 2085cdf0e10cSrcweir } 2086cdf0e10cSrcweir break; 2087cdf0e10cSrcweir 2088cdf0e10cSrcweir case META_CHORD_ACTION: 2089cdf0e10cSrcweir { 2090cdf0e10cSrcweir // TODO(F1): Missing basegfx functionality. Mind empty rects! 2091cdf0e10cSrcweir const Polygon aToolsPoly( static_cast<MetaChordAction*>(pCurrAct)->GetRect(), 2092cdf0e10cSrcweir static_cast<MetaChordAction*>(pCurrAct)->GetStartPoint(), 2093cdf0e10cSrcweir static_cast<MetaChordAction*>(pCurrAct)->GetEndPoint(), POLY_CHORD ); 2094cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); 2095cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 2096cdf0e10cSrcweir 2097cdf0e10cSrcweir createFillAndStroke( aPoly, 2098cdf0e10cSrcweir rFactoryParms ); 2099cdf0e10cSrcweir } 2100cdf0e10cSrcweir break; 2101cdf0e10cSrcweir 2102cdf0e10cSrcweir case META_POLYLINE_ACTION: 2103cdf0e10cSrcweir { 2104cdf0e10cSrcweir const OutDevState& rState( getState( rStates ) ); 2105cdf0e10cSrcweir if( rState.lineColor.getLength() || 2106cdf0e10cSrcweir rState.fillColor.getLength() ) 2107cdf0e10cSrcweir { 2108cdf0e10cSrcweir MetaPolyLineAction* pPolyLineAct = static_cast<MetaPolyLineAction*>(pCurrAct); 2109cdf0e10cSrcweir 2110cdf0e10cSrcweir const LineInfo& rLineInfo( pPolyLineAct->GetLineInfo() ); 2111cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly( pPolyLineAct->GetPolygon().getB2DPolygon() ); 2112cdf0e10cSrcweir aPoly.transform( rState.mapModeTransform ); 2113cdf0e10cSrcweir 2114cdf0e10cSrcweir ActionSharedPtr pLineAction; 2115cdf0e10cSrcweir 2116cdf0e10cSrcweir if( rLineInfo.IsDefault() ) 2117cdf0e10cSrcweir { 2118cdf0e10cSrcweir // plain hair line polygon 2119cdf0e10cSrcweir pLineAction = 2120cdf0e10cSrcweir internal::PolyPolyActionFactory::createLinePolyPolyAction( 2121cdf0e10cSrcweir ::basegfx::B2DPolyPolygon(aPoly), 2122cdf0e10cSrcweir rCanvas, 2123cdf0e10cSrcweir rState ); 2124cdf0e10cSrcweir 2125cdf0e10cSrcweir if( pLineAction ) 2126cdf0e10cSrcweir { 2127cdf0e10cSrcweir maActions.push_back( 2128cdf0e10cSrcweir MtfAction( 2129cdf0e10cSrcweir pLineAction, 2130cdf0e10cSrcweir io_rCurrActionIndex ) ); 2131cdf0e10cSrcweir 2132cdf0e10cSrcweir io_rCurrActionIndex += pLineAction->getActionCount()-1; 2133cdf0e10cSrcweir } 2134cdf0e10cSrcweir } 2135cdf0e10cSrcweir else if( LINE_NONE != rLineInfo.GetStyle() ) 2136cdf0e10cSrcweir { 2137cdf0e10cSrcweir // 'thick' line polygon 2138cdf0e10cSrcweir rendering::StrokeAttributes aStrokeAttributes; 2139cdf0e10cSrcweir 2140cdf0e10cSrcweir setupStrokeAttributes( aStrokeAttributes, 2141cdf0e10cSrcweir rFactoryParms, 2142cdf0e10cSrcweir rLineInfo ); 2143cdf0e10cSrcweir 2144cdf0e10cSrcweir pLineAction = 2145cdf0e10cSrcweir internal::PolyPolyActionFactory::createPolyPolyAction( 2146cdf0e10cSrcweir ::basegfx::B2DPolyPolygon(aPoly), 2147cdf0e10cSrcweir rCanvas, 2148cdf0e10cSrcweir rState, 2149cdf0e10cSrcweir aStrokeAttributes ) ; 2150cdf0e10cSrcweir 2151cdf0e10cSrcweir if( pLineAction ) 2152cdf0e10cSrcweir { 2153cdf0e10cSrcweir maActions.push_back( 2154cdf0e10cSrcweir MtfAction( 2155cdf0e10cSrcweir pLineAction, 2156cdf0e10cSrcweir io_rCurrActionIndex ) ); 2157cdf0e10cSrcweir 2158cdf0e10cSrcweir io_rCurrActionIndex += pLineAction->getActionCount()-1; 2159cdf0e10cSrcweir } 2160cdf0e10cSrcweir } 2161cdf0e10cSrcweir // else: line style is default 2162cdf0e10cSrcweir // (i.e. invisible), don't generate action 2163cdf0e10cSrcweir } 2164cdf0e10cSrcweir } 2165cdf0e10cSrcweir break; 2166cdf0e10cSrcweir 2167cdf0e10cSrcweir case META_POLYGON_ACTION: 2168cdf0e10cSrcweir { 2169cdf0e10cSrcweir ::basegfx::B2DPolygon aPoly( static_cast<MetaPolygonAction*>(pCurrAct)->GetPolygon().getB2DPolygon() ); 2170cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 2171cdf0e10cSrcweir createFillAndStroke( aPoly, 2172cdf0e10cSrcweir rFactoryParms ); 2173cdf0e10cSrcweir } 2174cdf0e10cSrcweir break; 2175cdf0e10cSrcweir 2176cdf0e10cSrcweir case META_POLYPOLYGON_ACTION: 2177cdf0e10cSrcweir { 2178cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aPoly( static_cast<MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon().getB2DPolyPolygon() ); 2179cdf0e10cSrcweir aPoly.transform( getState( rStates ).mapModeTransform ); 2180cdf0e10cSrcweir createFillAndStroke( aPoly, 2181cdf0e10cSrcweir rFactoryParms ); 2182cdf0e10cSrcweir } 2183cdf0e10cSrcweir break; 2184cdf0e10cSrcweir 2185cdf0e10cSrcweir case META_BMP_ACTION: 2186cdf0e10cSrcweir { 2187cdf0e10cSrcweir MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pCurrAct); 2188cdf0e10cSrcweir 2189cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2190cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2191cdf0e10cSrcweir pAct->GetBitmap(), 2192cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2193cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), 2194cdf0e10cSrcweir rCanvas, 2195cdf0e10cSrcweir getState( rStates ) ) ); 2196cdf0e10cSrcweir 2197cdf0e10cSrcweir if( pBmpAction ) 2198cdf0e10cSrcweir { 2199cdf0e10cSrcweir maActions.push_back( 2200cdf0e10cSrcweir MtfAction( 2201cdf0e10cSrcweir pBmpAction, 2202cdf0e10cSrcweir io_rCurrActionIndex ) ); 2203cdf0e10cSrcweir 2204cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2205cdf0e10cSrcweir } 2206cdf0e10cSrcweir } 2207cdf0e10cSrcweir break; 2208cdf0e10cSrcweir 2209cdf0e10cSrcweir case META_BMPSCALE_ACTION: 2210cdf0e10cSrcweir { 2211cdf0e10cSrcweir MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pCurrAct); 2212cdf0e10cSrcweir 2213cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2214cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2215cdf0e10cSrcweir pAct->GetBitmap(), 2216cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2217cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), 2218cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2219cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), 2220cdf0e10cSrcweir rCanvas, 2221cdf0e10cSrcweir getState( rStates ) ) ); 2222cdf0e10cSrcweir 2223cdf0e10cSrcweir if( pBmpAction ) 2224cdf0e10cSrcweir { 2225cdf0e10cSrcweir maActions.push_back( 2226cdf0e10cSrcweir MtfAction( 2227cdf0e10cSrcweir pBmpAction, 2228cdf0e10cSrcweir io_rCurrActionIndex ) ); 2229cdf0e10cSrcweir 2230cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2231cdf0e10cSrcweir } 2232cdf0e10cSrcweir } 2233cdf0e10cSrcweir break; 2234cdf0e10cSrcweir 2235cdf0e10cSrcweir case META_BMPSCALEPART_ACTION: 2236cdf0e10cSrcweir { 2237cdf0e10cSrcweir MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pCurrAct); 2238cdf0e10cSrcweir 2239cdf0e10cSrcweir // crop bitmap to given source rectangle (no 2240cdf0e10cSrcweir // need to copy and convert the whole bitmap) 2241cdf0e10cSrcweir Bitmap aBmp( pAct->GetBitmap() ); 2242cdf0e10cSrcweir const Rectangle aCropRect( pAct->GetSrcPoint(), 2243cdf0e10cSrcweir pAct->GetSrcSize() ); 2244cdf0e10cSrcweir aBmp.Crop( aCropRect ); 2245cdf0e10cSrcweir 2246cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2247cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2248cdf0e10cSrcweir aBmp, 2249cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2250cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), 2251cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2252cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), 2253cdf0e10cSrcweir rCanvas, 2254cdf0e10cSrcweir getState( rStates ) ) ); 2255cdf0e10cSrcweir 2256cdf0e10cSrcweir if( pBmpAction ) 2257cdf0e10cSrcweir { 2258cdf0e10cSrcweir maActions.push_back( 2259cdf0e10cSrcweir MtfAction( 2260cdf0e10cSrcweir pBmpAction, 2261cdf0e10cSrcweir io_rCurrActionIndex ) ); 2262cdf0e10cSrcweir 2263cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2264cdf0e10cSrcweir } 2265cdf0e10cSrcweir } 2266cdf0e10cSrcweir break; 2267cdf0e10cSrcweir 2268cdf0e10cSrcweir case META_BMPEX_ACTION: 2269cdf0e10cSrcweir { 2270cdf0e10cSrcweir MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pCurrAct); 2271cdf0e10cSrcweir 2272cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2273cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2274cdf0e10cSrcweir pAct->GetBitmapEx(), 2275cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2276cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), 2277cdf0e10cSrcweir rCanvas, 2278cdf0e10cSrcweir getState( rStates ) ) ); 2279cdf0e10cSrcweir 2280cdf0e10cSrcweir if( pBmpAction ) 2281cdf0e10cSrcweir { 2282cdf0e10cSrcweir maActions.push_back( 2283cdf0e10cSrcweir MtfAction( 2284cdf0e10cSrcweir pBmpAction, 2285cdf0e10cSrcweir io_rCurrActionIndex ) ); 2286cdf0e10cSrcweir 2287cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2288cdf0e10cSrcweir } 2289cdf0e10cSrcweir } 2290cdf0e10cSrcweir break; 2291cdf0e10cSrcweir 2292cdf0e10cSrcweir case META_BMPEXSCALE_ACTION: 2293cdf0e10cSrcweir { 2294cdf0e10cSrcweir MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pCurrAct); 2295cdf0e10cSrcweir 2296cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2297cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2298cdf0e10cSrcweir pAct->GetBitmapEx(), 2299cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2300cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), 2301cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2302cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), 2303cdf0e10cSrcweir rCanvas, 2304cdf0e10cSrcweir getState( rStates ) ) ); 2305cdf0e10cSrcweir 2306cdf0e10cSrcweir if( pBmpAction ) 2307cdf0e10cSrcweir { 2308cdf0e10cSrcweir maActions.push_back( 2309cdf0e10cSrcweir MtfAction( 2310cdf0e10cSrcweir pBmpAction, 2311cdf0e10cSrcweir io_rCurrActionIndex ) ); 2312cdf0e10cSrcweir 2313cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2314cdf0e10cSrcweir } 2315cdf0e10cSrcweir } 2316cdf0e10cSrcweir break; 2317cdf0e10cSrcweir 2318cdf0e10cSrcweir case META_BMPEXSCALEPART_ACTION: 2319cdf0e10cSrcweir { 2320cdf0e10cSrcweir MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pCurrAct); 2321cdf0e10cSrcweir 2322cdf0e10cSrcweir // crop bitmap to given source rectangle (no 2323cdf0e10cSrcweir // need to copy and convert the whole bitmap) 2324cdf0e10cSrcweir BitmapEx aBmp( pAct->GetBitmapEx() ); 2325cdf0e10cSrcweir const Rectangle aCropRect( pAct->GetSrcPoint(), 2326cdf0e10cSrcweir pAct->GetSrcSize() ); 2327cdf0e10cSrcweir aBmp.Crop( aCropRect ); 2328cdf0e10cSrcweir 2329cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2330cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2331cdf0e10cSrcweir aBmp, 2332cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2333cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), 2334cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2335cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), 2336cdf0e10cSrcweir rCanvas, 2337cdf0e10cSrcweir getState( rStates ) ) ); 2338cdf0e10cSrcweir 2339cdf0e10cSrcweir if( pBmpAction ) 2340cdf0e10cSrcweir { 2341cdf0e10cSrcweir maActions.push_back( 2342cdf0e10cSrcweir MtfAction( 2343cdf0e10cSrcweir pBmpAction, 2344cdf0e10cSrcweir io_rCurrActionIndex ) ); 2345cdf0e10cSrcweir 2346cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2347cdf0e10cSrcweir } 2348cdf0e10cSrcweir } 2349cdf0e10cSrcweir break; 2350cdf0e10cSrcweir 2351cdf0e10cSrcweir case META_MASK_ACTION: 2352cdf0e10cSrcweir { 2353cdf0e10cSrcweir MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pCurrAct); 2354cdf0e10cSrcweir 2355cdf0e10cSrcweir // create masked BitmapEx right here, as the 2356cdf0e10cSrcweir // canvas does not provide equivalent 2357cdf0e10cSrcweir // functionality 2358cdf0e10cSrcweir BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), 2359cdf0e10cSrcweir pAct->GetColor() )); 2360cdf0e10cSrcweir 2361cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2362cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2363cdf0e10cSrcweir aBmp, 2364cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2365cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), 2366cdf0e10cSrcweir rCanvas, 2367cdf0e10cSrcweir getState( rStates ) ) ); 2368cdf0e10cSrcweir 2369cdf0e10cSrcweir if( pBmpAction ) 2370cdf0e10cSrcweir { 2371cdf0e10cSrcweir maActions.push_back( 2372cdf0e10cSrcweir MtfAction( 2373cdf0e10cSrcweir pBmpAction, 2374cdf0e10cSrcweir io_rCurrActionIndex ) ); 2375cdf0e10cSrcweir 2376cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2377cdf0e10cSrcweir } 2378cdf0e10cSrcweir } 2379cdf0e10cSrcweir break; 2380cdf0e10cSrcweir 2381cdf0e10cSrcweir case META_MASKSCALE_ACTION: 2382cdf0e10cSrcweir { 2383cdf0e10cSrcweir MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pCurrAct); 2384cdf0e10cSrcweir 2385cdf0e10cSrcweir // create masked BitmapEx right here, as the 2386cdf0e10cSrcweir // canvas does not provide equivalent 2387cdf0e10cSrcweir // functionality 2388cdf0e10cSrcweir BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), 2389cdf0e10cSrcweir pAct->GetColor() )); 2390cdf0e10cSrcweir 2391cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2392cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2393cdf0e10cSrcweir aBmp, 2394cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2395cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), 2396cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2397cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), 2398cdf0e10cSrcweir rCanvas, 2399cdf0e10cSrcweir getState( rStates ) ) ); 2400cdf0e10cSrcweir 2401cdf0e10cSrcweir if( pBmpAction ) 2402cdf0e10cSrcweir { 2403cdf0e10cSrcweir maActions.push_back( 2404cdf0e10cSrcweir MtfAction( 2405cdf0e10cSrcweir pBmpAction, 2406cdf0e10cSrcweir io_rCurrActionIndex ) ); 2407cdf0e10cSrcweir 2408cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2409cdf0e10cSrcweir } 2410cdf0e10cSrcweir } 2411cdf0e10cSrcweir break; 2412cdf0e10cSrcweir 2413cdf0e10cSrcweir case META_MASKSCALEPART_ACTION: 2414cdf0e10cSrcweir { 2415cdf0e10cSrcweir MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pCurrAct); 2416cdf0e10cSrcweir 2417cdf0e10cSrcweir // create masked BitmapEx right here, as the 2418cdf0e10cSrcweir // canvas does not provide equivalent 2419cdf0e10cSrcweir // functionality 2420cdf0e10cSrcweir BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), 2421cdf0e10cSrcweir pAct->GetColor() )); 2422cdf0e10cSrcweir 2423cdf0e10cSrcweir // crop bitmap to given source rectangle (no 2424cdf0e10cSrcweir // need to copy and convert the whole bitmap) 2425cdf0e10cSrcweir const Rectangle aCropRect( pAct->GetSrcPoint(), 2426cdf0e10cSrcweir pAct->GetSrcSize() ); 2427cdf0e10cSrcweir aBmp.Crop( aCropRect ); 2428cdf0e10cSrcweir 2429cdf0e10cSrcweir ActionSharedPtr pBmpAction( 2430cdf0e10cSrcweir internal::BitmapActionFactory::createBitmapAction( 2431cdf0e10cSrcweir aBmp, 2432cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2433cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), 2434cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2435cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), 2436cdf0e10cSrcweir rCanvas, 2437cdf0e10cSrcweir getState( rStates ) ) ); 2438cdf0e10cSrcweir 2439cdf0e10cSrcweir if( pBmpAction ) 2440cdf0e10cSrcweir { 2441cdf0e10cSrcweir maActions.push_back( 2442cdf0e10cSrcweir MtfAction( 2443cdf0e10cSrcweir pBmpAction, 2444cdf0e10cSrcweir io_rCurrActionIndex ) ); 2445cdf0e10cSrcweir 2446cdf0e10cSrcweir io_rCurrActionIndex += pBmpAction->getActionCount()-1; 2447cdf0e10cSrcweir } 2448cdf0e10cSrcweir } 2449cdf0e10cSrcweir break; 2450cdf0e10cSrcweir 2451cdf0e10cSrcweir case META_GRADIENTEX_ACTION: 2452cdf0e10cSrcweir // TODO(F1): use native Canvas gradients here 2453cdf0e10cSrcweir // action is ignored here, because redundant to META_GRADIENT_ACTION 2454cdf0e10cSrcweir break; 2455cdf0e10cSrcweir 2456cdf0e10cSrcweir case META_WALLPAPER_ACTION: 2457cdf0e10cSrcweir // TODO(F2): NYI 2458cdf0e10cSrcweir break; 2459cdf0e10cSrcweir 2460cdf0e10cSrcweir case META_TRANSPARENT_ACTION: 2461cdf0e10cSrcweir { 2462cdf0e10cSrcweir const OutDevState& rState( getState( rStates ) ); 2463cdf0e10cSrcweir if( rState.lineColor.getLength() || 2464cdf0e10cSrcweir rState.fillColor.getLength() ) 2465cdf0e10cSrcweir { 2466cdf0e10cSrcweir MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pCurrAct); 2467cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aPoly( pAct->GetPolyPolygon().getB2DPolyPolygon() ); 2468cdf0e10cSrcweir aPoly.transform( rState.mapModeTransform ); 2469cdf0e10cSrcweir 2470cdf0e10cSrcweir ActionSharedPtr pPolyAction( 2471cdf0e10cSrcweir internal::PolyPolyActionFactory::createPolyPolyAction( 2472cdf0e10cSrcweir aPoly, 2473cdf0e10cSrcweir rCanvas, 2474cdf0e10cSrcweir rState, 2475cdf0e10cSrcweir pAct->GetTransparence() ) ); 2476cdf0e10cSrcweir 2477cdf0e10cSrcweir if( pPolyAction ) 2478cdf0e10cSrcweir { 2479cdf0e10cSrcweir maActions.push_back( 2480cdf0e10cSrcweir MtfAction( 2481cdf0e10cSrcweir pPolyAction, 2482cdf0e10cSrcweir io_rCurrActionIndex ) ); 2483cdf0e10cSrcweir 2484cdf0e10cSrcweir io_rCurrActionIndex += pPolyAction->getActionCount()-1; 2485cdf0e10cSrcweir } 2486cdf0e10cSrcweir } 2487cdf0e10cSrcweir } 2488cdf0e10cSrcweir break; 2489cdf0e10cSrcweir 2490cdf0e10cSrcweir case META_FLOATTRANSPARENT_ACTION: 2491cdf0e10cSrcweir { 2492cdf0e10cSrcweir MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pCurrAct); 2493cdf0e10cSrcweir 2494cdf0e10cSrcweir internal::MtfAutoPtr pMtf( 2495cdf0e10cSrcweir new ::GDIMetaFile( pAct->GetGDIMetaFile() ) ); 2496cdf0e10cSrcweir 2497cdf0e10cSrcweir // TODO(P2): Use native canvas gradients here (saves a lot of UNO calls) 2498cdf0e10cSrcweir internal::GradientAutoPtr pGradient( 2499cdf0e10cSrcweir new Gradient( pAct->GetGradient() ) ); 2500cdf0e10cSrcweir 2501cdf0e10cSrcweir DBG_TESTSOLARMUTEX(); 2502cdf0e10cSrcweir 2503cdf0e10cSrcweir ActionSharedPtr pFloatTransAction( 2504cdf0e10cSrcweir internal::TransparencyGroupActionFactory::createTransparencyGroupAction( 2505cdf0e10cSrcweir pMtf, 2506cdf0e10cSrcweir pGradient, 2507cdf0e10cSrcweir rParms, 2508cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2509cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), 2510cdf0e10cSrcweir getState( rStates ).mapModeTransform * 2511cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), 2512cdf0e10cSrcweir rCanvas, 2513cdf0e10cSrcweir getState( rStates ) ) ); 2514cdf0e10cSrcweir 2515cdf0e10cSrcweir if( pFloatTransAction ) 2516cdf0e10cSrcweir { 2517cdf0e10cSrcweir maActions.push_back( 2518cdf0e10cSrcweir MtfAction( 2519cdf0e10cSrcweir pFloatTransAction, 2520cdf0e10cSrcweir io_rCurrActionIndex ) ); 2521cdf0e10cSrcweir 2522cdf0e10cSrcweir io_rCurrActionIndex += pFloatTransAction->getActionCount()-1; 2523cdf0e10cSrcweir } 2524cdf0e10cSrcweir } 2525cdf0e10cSrcweir break; 2526cdf0e10cSrcweir 2527cdf0e10cSrcweir case META_TEXT_ACTION: 2528cdf0e10cSrcweir { 2529cdf0e10cSrcweir MetaTextAction* pAct = static_cast<MetaTextAction*>(pCurrAct); 2530cdf0e10cSrcweir XubString sText = XubString( pAct->GetText() ); 2531cdf0e10cSrcweir 2532cdf0e10cSrcweir if( rVDev.GetDigitLanguage()) 2533cdf0e10cSrcweir convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); 2534cdf0e10cSrcweir 2535cdf0e10cSrcweir createTextAction( 2536cdf0e10cSrcweir pAct->GetPoint(), 2537cdf0e10cSrcweir sText, 2538cdf0e10cSrcweir pAct->GetIndex(), 2539cdf0e10cSrcweir pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), 2540cdf0e10cSrcweir NULL, 2541cdf0e10cSrcweir rFactoryParms, 2542cdf0e10cSrcweir bSubsettableActions ); 2543cdf0e10cSrcweir } 2544cdf0e10cSrcweir break; 2545cdf0e10cSrcweir 2546cdf0e10cSrcweir case META_TEXTARRAY_ACTION: 2547cdf0e10cSrcweir { 2548cdf0e10cSrcweir MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pCurrAct); 2549cdf0e10cSrcweir XubString sText = XubString( pAct->GetText() ); 2550cdf0e10cSrcweir 2551cdf0e10cSrcweir if( rVDev.GetDigitLanguage()) 2552cdf0e10cSrcweir convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); 2553cdf0e10cSrcweir 2554cdf0e10cSrcweir createTextAction( 2555cdf0e10cSrcweir pAct->GetPoint(), 2556cdf0e10cSrcweir sText, 2557cdf0e10cSrcweir pAct->GetIndex(), 2558cdf0e10cSrcweir pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), 2559cdf0e10cSrcweir pAct->GetDXArray(), 2560cdf0e10cSrcweir rFactoryParms, 2561cdf0e10cSrcweir bSubsettableActions ); 2562cdf0e10cSrcweir } 2563cdf0e10cSrcweir break; 2564cdf0e10cSrcweir 2565cdf0e10cSrcweir case META_TEXTLINE_ACTION: 2566cdf0e10cSrcweir { 2567cdf0e10cSrcweir MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pCurrAct); 2568cdf0e10cSrcweir 2569cdf0e10cSrcweir const OutDevState& rState( getState( rStates ) ); 2570cdf0e10cSrcweir const ::Size aBaselineOffset( tools::getBaselineOffset( rState, 2571cdf0e10cSrcweir rVDev ) ); 2572cdf0e10cSrcweir const ::Point aStartPoint( pAct->GetStartPoint() ); 2573cdf0e10cSrcweir const ::basegfx::B2DSize aSize( rState.mapModeTransform * 2574cdf0e10cSrcweir ::basegfx::B2DSize(pAct->GetWidth(), 2575cdf0e10cSrcweir 0 )); 2576cdf0e10cSrcweir 2577cdf0e10cSrcweir ActionSharedPtr pPolyAction( 2578cdf0e10cSrcweir PolyPolyActionFactory::createPolyPolyAction( 2579cdf0e10cSrcweir tools::createTextLinesPolyPolygon( 2580cdf0e10cSrcweir rState.mapModeTransform * 2581cdf0e10cSrcweir ::basegfx::B2DPoint( 2582cdf0e10cSrcweir ::vcl::unotools::b2DPointFromPoint(pAct->GetStartPoint()) + 2583cdf0e10cSrcweir ::vcl::unotools::b2DSizeFromSize(aBaselineOffset)), 2584cdf0e10cSrcweir aSize.getX(), 2585cdf0e10cSrcweir tools::createTextLineInfo( rVDev, 2586cdf0e10cSrcweir rState )), 2587cdf0e10cSrcweir rCanvas, 2588cdf0e10cSrcweir rState ) ); 2589cdf0e10cSrcweir 2590cdf0e10cSrcweir if( pPolyAction.get() ) 2591cdf0e10cSrcweir { 2592cdf0e10cSrcweir maActions.push_back( 2593cdf0e10cSrcweir MtfAction( 2594cdf0e10cSrcweir pPolyAction, 2595cdf0e10cSrcweir io_rCurrActionIndex ) ); 2596cdf0e10cSrcweir 2597cdf0e10cSrcweir io_rCurrActionIndex += pPolyAction->getActionCount()-1; 2598cdf0e10cSrcweir } 2599cdf0e10cSrcweir } 2600cdf0e10cSrcweir break; 2601cdf0e10cSrcweir 2602cdf0e10cSrcweir case META_TEXTRECT_ACTION: 2603cdf0e10cSrcweir { 2604cdf0e10cSrcweir MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pCurrAct); 2605cdf0e10cSrcweir 2606cdf0e10cSrcweir pushState( rStates, PUSH_ALL ); 2607cdf0e10cSrcweir 2608cdf0e10cSrcweir // use the VDev to break up the text rect 2609cdf0e10cSrcweir // action into readily formatted lines 2610cdf0e10cSrcweir GDIMetaFile aTmpMtf; 2611cdf0e10cSrcweir rVDev.AddTextRectActions( pAct->GetRect(), 2612cdf0e10cSrcweir pAct->GetText(), 2613cdf0e10cSrcweir pAct->GetStyle(), 2614cdf0e10cSrcweir aTmpMtf ); 2615cdf0e10cSrcweir 2616cdf0e10cSrcweir createActions( aTmpMtf, 2617cdf0e10cSrcweir rFactoryParms, 2618cdf0e10cSrcweir bSubsettableActions ); 2619cdf0e10cSrcweir 2620cdf0e10cSrcweir popState( rStates ); 2621cdf0e10cSrcweir 2622cdf0e10cSrcweir break; 2623cdf0e10cSrcweir } 2624cdf0e10cSrcweir 2625cdf0e10cSrcweir case META_STRETCHTEXT_ACTION: 2626cdf0e10cSrcweir { 2627cdf0e10cSrcweir MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pCurrAct); 2628cdf0e10cSrcweir XubString sText = XubString( pAct->GetText() ); 2629cdf0e10cSrcweir 2630cdf0e10cSrcweir if( rVDev.GetDigitLanguage()) 2631cdf0e10cSrcweir convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); 2632cdf0e10cSrcweir 2633cdf0e10cSrcweir const sal_uInt16 nLen( pAct->GetLen() == (sal_uInt16)STRING_LEN ? 2634cdf0e10cSrcweir pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen() ); 2635cdf0e10cSrcweir 2636cdf0e10cSrcweir // #i70897# Nothing to do, actually... 2637cdf0e10cSrcweir if( nLen == 0 ) 2638cdf0e10cSrcweir break; 2639cdf0e10cSrcweir 2640cdf0e10cSrcweir // have to fit the text into the given 2641cdf0e10cSrcweir // width. This is achieved by internally 2642cdf0e10cSrcweir // generating a DX array, and uniformly 2643cdf0e10cSrcweir // distributing the excess/insufficient width 2644cdf0e10cSrcweir // to every logical character. 2645cdf0e10cSrcweir ::boost::scoped_array< sal_Int32 > pDXArray( new sal_Int32[nLen] ); 2646cdf0e10cSrcweir 2647cdf0e10cSrcweir rVDev.GetTextArray( pAct->GetText(), pDXArray.get(), 2648cdf0e10cSrcweir pAct->GetIndex(), pAct->GetLen() ); 2649cdf0e10cSrcweir 2650cdf0e10cSrcweir const sal_Int32 nWidthDifference( pAct->GetWidth() - pDXArray[ nLen-1 ] ); 2651cdf0e10cSrcweir 2652cdf0e10cSrcweir // Last entry of pDXArray contains total width of the text 2653cdf0e10cSrcweir sal_Int32* p=pDXArray.get(); 2654cdf0e10cSrcweir for( sal_uInt16 i=1; i<=nLen; ++i ) 2655cdf0e10cSrcweir { 2656cdf0e10cSrcweir // calc ratio for every array entry, to 2657cdf0e10cSrcweir // distribute rounding errors 'evenly' 2658cdf0e10cSrcweir // across the characters. Note that each 2659cdf0e10cSrcweir // entry represents the 'end' position of 2660cdf0e10cSrcweir // the corresponding character, thus, we 2661cdf0e10cSrcweir // let i run from 1 to nLen. 2662cdf0e10cSrcweir *p++ += (sal_Int32)i*nWidthDifference/nLen; 2663cdf0e10cSrcweir } 2664cdf0e10cSrcweir 2665cdf0e10cSrcweir createTextAction( 2666cdf0e10cSrcweir pAct->GetPoint(), 2667cdf0e10cSrcweir sText, 2668cdf0e10cSrcweir pAct->GetIndex(), 2669cdf0e10cSrcweir pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), 2670cdf0e10cSrcweir pDXArray.get(), 2671cdf0e10cSrcweir rFactoryParms, 2672cdf0e10cSrcweir bSubsettableActions ); 2673cdf0e10cSrcweir } 2674cdf0e10cSrcweir break; 2675cdf0e10cSrcweir 2676cdf0e10cSrcweir default: 2677cdf0e10cSrcweir OSL_ENSURE( false, 2678cdf0e10cSrcweir "Unknown meta action type encountered" ); 2679cdf0e10cSrcweir break; 2680cdf0e10cSrcweir } 2681cdf0e10cSrcweir 2682cdf0e10cSrcweir // increment action index (each mtf action counts _at 2683cdf0e10cSrcweir // least_ one. Some count for more, therefore, 2684cdf0e10cSrcweir // io_rCurrActionIndex is sometimes incremented by 2685cdf0e10cSrcweir // pAct->getActionCount()-1 above, the -1 being the 2686cdf0e10cSrcweir // correction for the unconditional increment here). 2687cdf0e10cSrcweir ++io_rCurrActionIndex; 2688cdf0e10cSrcweir } 2689cdf0e10cSrcweir 2690cdf0e10cSrcweir return true; 2691cdf0e10cSrcweir } 2692cdf0e10cSrcweir 2693cdf0e10cSrcweir 2694cdf0e10cSrcweir namespace 2695cdf0e10cSrcweir { 2696cdf0e10cSrcweir class ActionRenderer 2697cdf0e10cSrcweir { 2698cdf0e10cSrcweir public: 2699cdf0e10cSrcweir ActionRenderer( const ::basegfx::B2DHomMatrix& rTransformation ) : 2700cdf0e10cSrcweir maTransformation( rTransformation ), 2701cdf0e10cSrcweir mbRet( true ) 2702cdf0e10cSrcweir { 2703cdf0e10cSrcweir } 2704cdf0e10cSrcweir 2705cdf0e10cSrcweir bool result() 2706cdf0e10cSrcweir { 2707cdf0e10cSrcweir return mbRet; 2708cdf0e10cSrcweir } 2709cdf0e10cSrcweir 2710cdf0e10cSrcweir void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction ) 2711cdf0e10cSrcweir { 2712cdf0e10cSrcweir // ANDing the result. We want to fail if at least 2713cdf0e10cSrcweir // one action failed. 2714cdf0e10cSrcweir mbRet &= rAction.mpAction->render( maTransformation ); 2715cdf0e10cSrcweir } 2716cdf0e10cSrcweir 2717cdf0e10cSrcweir void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction, 2718cdf0e10cSrcweir const Action::Subset& rSubset ) 2719cdf0e10cSrcweir { 2720cdf0e10cSrcweir // ANDing the result. We want to fail if at least 2721cdf0e10cSrcweir // one action failed. 2722cdf0e10cSrcweir mbRet &= rAction.mpAction->render( maTransformation, 2723cdf0e10cSrcweir rSubset ); 2724cdf0e10cSrcweir } 2725cdf0e10cSrcweir 2726cdf0e10cSrcweir private: 2727cdf0e10cSrcweir ::basegfx::B2DHomMatrix maTransformation; 2728cdf0e10cSrcweir bool mbRet; 2729cdf0e10cSrcweir }; 2730cdf0e10cSrcweir 2731cdf0e10cSrcweir class AreaQuery 2732cdf0e10cSrcweir { 2733cdf0e10cSrcweir public: 2734cdf0e10cSrcweir AreaQuery( const ::basegfx::B2DHomMatrix& rTransformation ) : 2735cdf0e10cSrcweir maTransformation( rTransformation ), 2736cdf0e10cSrcweir maBounds() 2737cdf0e10cSrcweir { 2738cdf0e10cSrcweir } 2739cdf0e10cSrcweir 2740cdf0e10cSrcweir bool result() 2741cdf0e10cSrcweir { 2742cdf0e10cSrcweir return true; // nothing can fail here 2743cdf0e10cSrcweir } 2744cdf0e10cSrcweir 2745cdf0e10cSrcweir void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction ) 2746cdf0e10cSrcweir { 2747cdf0e10cSrcweir maBounds.expand( rAction.mpAction->getBounds( maTransformation ) ); 2748cdf0e10cSrcweir } 2749cdf0e10cSrcweir 2750cdf0e10cSrcweir void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction, 2751cdf0e10cSrcweir const Action::Subset& rSubset ) 2752cdf0e10cSrcweir { 2753cdf0e10cSrcweir maBounds.expand( rAction.mpAction->getBounds( maTransformation, 2754cdf0e10cSrcweir rSubset ) ); 2755cdf0e10cSrcweir } 2756cdf0e10cSrcweir 2757cdf0e10cSrcweir ::basegfx::B2DRange getBounds() const 2758cdf0e10cSrcweir { 2759cdf0e10cSrcweir return maBounds; 2760cdf0e10cSrcweir } 2761cdf0e10cSrcweir 2762cdf0e10cSrcweir private: 2763cdf0e10cSrcweir ::basegfx::B2DHomMatrix maTransformation; 2764cdf0e10cSrcweir ::basegfx::B2DRange maBounds; 2765cdf0e10cSrcweir }; 2766cdf0e10cSrcweir 2767cdf0e10cSrcweir // Doing that via inline class. Compilers tend to not inline free 2768cdf0e10cSrcweir // functions. 2769cdf0e10cSrcweir struct UpperBoundActionIndexComparator 2770cdf0e10cSrcweir { 2771cdf0e10cSrcweir bool operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rLHS, 2772cdf0e10cSrcweir const ::cppcanvas::internal::ImplRenderer::MtfAction& rRHS ) 2773cdf0e10cSrcweir { 2774cdf0e10cSrcweir const sal_Int32 nLHSCount( rLHS.mpAction ? 2775cdf0e10cSrcweir rLHS.mpAction->getActionCount() : 0 ); 2776cdf0e10cSrcweir const sal_Int32 nRHSCount( rRHS.mpAction ? 2777cdf0e10cSrcweir rRHS.mpAction->getActionCount() : 0 ); 2778cdf0e10cSrcweir 2779cdf0e10cSrcweir // compare end of action range, to have an action selected 2780cdf0e10cSrcweir // by lower_bound even if the requested index points in 2781cdf0e10cSrcweir // the middle of the action's range 2782cdf0e10cSrcweir return rLHS.mnOrigIndex + nLHSCount < rRHS.mnOrigIndex + nRHSCount; 2783cdf0e10cSrcweir } 2784cdf0e10cSrcweir }; 2785cdf0e10cSrcweir 2786cdf0e10cSrcweir /** Algorithm to apply given functor to a subset range 2787cdf0e10cSrcweir 2788cdf0e10cSrcweir @tpl Functor 2789cdf0e10cSrcweir 2790cdf0e10cSrcweir Functor to call for each element of the subset 2791cdf0e10cSrcweir range. Must provide the following method signatures: 2792cdf0e10cSrcweir bool result() (returning false if operation failed) 2793cdf0e10cSrcweir 2794cdf0e10cSrcweir */ 2795cdf0e10cSrcweir template< typename Functor > bool 2796cdf0e10cSrcweir forSubsetRange( Functor& rFunctor, 2797cdf0e10cSrcweir ImplRenderer::ActionVector::const_iterator aRangeBegin, 2798cdf0e10cSrcweir ImplRenderer::ActionVector::const_iterator aRangeEnd, 2799cdf0e10cSrcweir sal_Int32 nStartIndex, 2800cdf0e10cSrcweir sal_Int32 nEndIndex, 2801cdf0e10cSrcweir const ImplRenderer::ActionVector::const_iterator& rEnd ) 2802cdf0e10cSrcweir { 2803cdf0e10cSrcweir if( aRangeBegin == aRangeEnd ) 2804cdf0e10cSrcweir { 2805cdf0e10cSrcweir // only a single action. Setup subset, and call functor 2806cdf0e10cSrcweir Action::Subset aSubset; 2807cdf0e10cSrcweir aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ), 2808cdf0e10cSrcweir nStartIndex - aRangeBegin->mnOrigIndex ); 2809cdf0e10cSrcweir aSubset.mnSubsetEnd = ::std::min( aRangeBegin->mpAction->getActionCount(), 2810cdf0e10cSrcweir nEndIndex - aRangeBegin->mnOrigIndex ); 2811cdf0e10cSrcweir 2812cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, 2813cdf0e10cSrcweir "ImplRenderer::forSubsetRange(): Invalid indices" ); 2814cdf0e10cSrcweir 2815cdf0e10cSrcweir rFunctor( *aRangeBegin, aSubset ); 2816cdf0e10cSrcweir } 2817cdf0e10cSrcweir else 2818cdf0e10cSrcweir { 2819cdf0e10cSrcweir // more than one action. 2820cdf0e10cSrcweir 2821cdf0e10cSrcweir // render partial first, full intermediate, and 2822cdf0e10cSrcweir // partial last action 2823cdf0e10cSrcweir Action::Subset aSubset; 2824cdf0e10cSrcweir aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ), 2825cdf0e10cSrcweir nStartIndex - aRangeBegin->mnOrigIndex ); 2826cdf0e10cSrcweir aSubset.mnSubsetEnd = aRangeBegin->mpAction->getActionCount(); 2827cdf0e10cSrcweir 2828cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, 2829cdf0e10cSrcweir "ImplRenderer::forSubsetRange(): Invalid indices" ); 2830cdf0e10cSrcweir 2831cdf0e10cSrcweir rFunctor( *aRangeBegin, aSubset ); 2832cdf0e10cSrcweir 2833cdf0e10cSrcweir // first action rendered, skip to next 2834cdf0e10cSrcweir ++aRangeBegin; 2835cdf0e10cSrcweir 2836cdf0e10cSrcweir // render full middle actions 2837cdf0e10cSrcweir while( aRangeBegin != aRangeEnd ) 2838cdf0e10cSrcweir rFunctor( *aRangeBegin++ ); 2839cdf0e10cSrcweir 2840cdf0e10cSrcweir if( aRangeEnd == rEnd || 2841cdf0e10cSrcweir aRangeEnd->mnOrigIndex > nEndIndex ) 2842cdf0e10cSrcweir { 2843cdf0e10cSrcweir // aRangeEnd denotes end of action vector, 2844cdf0e10cSrcweir // 2845cdf0e10cSrcweir // or 2846cdf0e10cSrcweir // 2847cdf0e10cSrcweir // nEndIndex references something _after_ 2848cdf0e10cSrcweir // aRangeBegin, but _before_ aRangeEnd 2849cdf0e10cSrcweir // 2850cdf0e10cSrcweir // either way: no partial action left 2851cdf0e10cSrcweir return rFunctor.result(); 2852cdf0e10cSrcweir } 2853cdf0e10cSrcweir 2854cdf0e10cSrcweir aSubset.mnSubsetBegin = 0; 2855cdf0e10cSrcweir aSubset.mnSubsetEnd = nEndIndex - aRangeEnd->mnOrigIndex; 2856cdf0e10cSrcweir 2857cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, 2858cdf0e10cSrcweir "ImplRenderer::forSubsetRange(): Invalid indices" ); 2859cdf0e10cSrcweir 2860cdf0e10cSrcweir rFunctor( *aRangeEnd, aSubset ); 2861cdf0e10cSrcweir } 2862cdf0e10cSrcweir 2863cdf0e10cSrcweir return rFunctor.result(); 2864cdf0e10cSrcweir } 2865cdf0e10cSrcweir } 2866cdf0e10cSrcweir 2867cdf0e10cSrcweir bool ImplRenderer::getSubsetIndices( sal_Int32& io_rStartIndex, 2868cdf0e10cSrcweir sal_Int32& io_rEndIndex, 2869cdf0e10cSrcweir ActionVector::const_iterator& o_rRangeBegin, 2870cdf0e10cSrcweir ActionVector::const_iterator& o_rRangeEnd ) const 2871cdf0e10cSrcweir { 2872cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( io_rStartIndex<=io_rEndIndex, 2873cdf0e10cSrcweir "ImplRenderer::getSubsetIndices(): invalid action range" ); 2874cdf0e10cSrcweir 2875cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( !maActions.empty(), 2876cdf0e10cSrcweir "ImplRenderer::getSubsetIndices(): no actions to render" ); 2877cdf0e10cSrcweir 2878cdf0e10cSrcweir const sal_Int32 nMinActionIndex( maActions.front().mnOrigIndex ); 2879cdf0e10cSrcweir const sal_Int32 nMaxActionIndex( maActions.back().mnOrigIndex + 2880cdf0e10cSrcweir maActions.back().mpAction->getActionCount() ); 2881cdf0e10cSrcweir 2882cdf0e10cSrcweir // clip given range to permissible values (there might be 2883cdf0e10cSrcweir // ranges before and behind the valid indices) 2884cdf0e10cSrcweir io_rStartIndex = ::std::max( nMinActionIndex, 2885cdf0e10cSrcweir io_rStartIndex ); 2886cdf0e10cSrcweir io_rEndIndex = ::std::min( nMaxActionIndex, 2887cdf0e10cSrcweir io_rEndIndex ); 2888cdf0e10cSrcweir 2889cdf0e10cSrcweir if( io_rStartIndex == io_rEndIndex || 2890cdf0e10cSrcweir io_rStartIndex > io_rEndIndex ) 2891cdf0e10cSrcweir { 2892cdf0e10cSrcweir // empty range, don't render anything. The second 2893cdf0e10cSrcweir // condition e.g. happens if the requested range lies 2894cdf0e10cSrcweir // fully before or behind the valid action indices. 2895cdf0e10cSrcweir return false; 2896cdf0e10cSrcweir } 2897cdf0e10cSrcweir 2898cdf0e10cSrcweir 2899cdf0e10cSrcweir const ActionVector::const_iterator aBegin( maActions.begin() ); 2900cdf0e10cSrcweir const ActionVector::const_iterator aEnd( maActions.end() ); 2901cdf0e10cSrcweir 2902cdf0e10cSrcweir 2903cdf0e10cSrcweir // find start and end action 2904cdf0e10cSrcweir // ========================= 2905cdf0e10cSrcweir o_rRangeBegin = ::std::lower_bound( aBegin, aEnd, 2906cdf0e10cSrcweir MtfAction( ActionSharedPtr(), io_rStartIndex ), 2907cdf0e10cSrcweir UpperBoundActionIndexComparator() ); 2908cdf0e10cSrcweir o_rRangeEnd = ::std::lower_bound( aBegin, aEnd, 2909cdf0e10cSrcweir MtfAction( ActionSharedPtr(), io_rEndIndex ), 2910cdf0e10cSrcweir UpperBoundActionIndexComparator() ); 2911cdf0e10cSrcweir return true; 2912cdf0e10cSrcweir } 2913cdf0e10cSrcweir 2914cdf0e10cSrcweir 2915cdf0e10cSrcweir // Public methods 2916cdf0e10cSrcweir // ==================================================================== 2917cdf0e10cSrcweir 2918cdf0e10cSrcweir ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas, 2919cdf0e10cSrcweir const GDIMetaFile& rMtf, 2920cdf0e10cSrcweir const Parameters& rParams ) : 2921cdf0e10cSrcweir CanvasGraphicHelper( rCanvas ), 2922cdf0e10cSrcweir maActions() 2923cdf0e10cSrcweir { 2924cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(mtf)" ); 2925cdf0e10cSrcweir 2926cdf0e10cSrcweir OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(), 2927cdf0e10cSrcweir "ImplRenderer::ImplRenderer(): Invalid canvas" ); 2928cdf0e10cSrcweir OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(), 2929cdf0e10cSrcweir "ImplRenderer::ImplRenderer(): Invalid graphic device" ); 2930cdf0e10cSrcweir 2931cdf0e10cSrcweir // make sure canvas and graphic device are valid; action 2932cdf0e10cSrcweir // creation don't check that every time 2933cdf0e10cSrcweir if( rCanvas.get() == NULL || 2934cdf0e10cSrcweir !rCanvas->getUNOCanvas().is() || 2935cdf0e10cSrcweir !rCanvas->getUNOCanvas()->getDevice().is() ) 2936cdf0e10cSrcweir { 2937cdf0e10cSrcweir // leave actions empty 2938cdf0e10cSrcweir return; 2939cdf0e10cSrcweir } 2940cdf0e10cSrcweir 2941cdf0e10cSrcweir VectorOfOutDevStates aStateStack; 2942cdf0e10cSrcweir 2943cdf0e10cSrcweir VirtualDevice aVDev; 2944cdf0e10cSrcweir aVDev.EnableOutput( sal_False ); 2945cdf0e10cSrcweir 2946cdf0e10cSrcweir // Setup VDev for state tracking and mapping 2947cdf0e10cSrcweir // ========================================= 2948cdf0e10cSrcweir 2949cdf0e10cSrcweir aVDev.SetMapMode( rMtf.GetPrefMapMode() ); 2950cdf0e10cSrcweir 2951cdf0e10cSrcweir const Size aMtfSize( rMtf.GetPrefSize() ); 2952cdf0e10cSrcweir const Size aMtfSizePixPre( aVDev.LogicToPixel( aMtfSize, 2953cdf0e10cSrcweir rMtf.GetPrefMapMode() ) ); 2954cdf0e10cSrcweir const Point aEmptyPt; 2955cdf0e10cSrcweir const Point aMtfOriginPix( aVDev.LogicToPixel( aEmptyPt ) ); 2956cdf0e10cSrcweir 2957cdf0e10cSrcweir // #i44110# correct null-sized output - there are shapes 2958cdf0e10cSrcweir // which have zero size in at least one dimension 2959cdf0e10cSrcweir const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ), 2960cdf0e10cSrcweir ::std::max( aMtfSizePixPre.Height(), 1L ) ); 2961cdf0e10cSrcweir 2962cdf0e10cSrcweir sal_Int32 nCurrActions(0); 2963cdf0e10cSrcweir ActionFactoryParameters aParms(aStateStack, 2964cdf0e10cSrcweir rCanvas, 2965cdf0e10cSrcweir aVDev, 2966cdf0e10cSrcweir rParams, 2967cdf0e10cSrcweir nCurrActions ); 2968cdf0e10cSrcweir 2969cdf0e10cSrcweir // init state stack 2970cdf0e10cSrcweir clearStateStack( aStateStack ); 2971cdf0e10cSrcweir 2972cdf0e10cSrcweir // Setup local state, such that the metafile renders 2973cdf0e10cSrcweir // itself into a one-by-one square at the origin for 2974cdf0e10cSrcweir // identity view and render transformations 2975cdf0e10cSrcweir getState( aStateStack ).transform.scale( 1.0 / aMtfSizePix.Width(), 2976cdf0e10cSrcweir 1.0 / aMtfSizePix.Height() ); 2977cdf0e10cSrcweir 2978cdf0e10cSrcweir tools::calcLogic2PixelAffineTransform( getState( aStateStack ).mapModeTransform, 2979cdf0e10cSrcweir aVDev ); 2980cdf0e10cSrcweir 2981cdf0e10cSrcweir ColorSharedPtr pColor( getCanvas()->createColor() ); 2982cdf0e10cSrcweir 2983cdf0e10cSrcweir // setup default text color to black 2984cdf0e10cSrcweir getState( aStateStack ).textColor = 2985cdf0e10cSrcweir getState( aStateStack ).textFillColor = 2986cdf0e10cSrcweir getState( aStateStack ).textLineColor = pColor->getDeviceColor( 0x000000FF ); 2987cdf0e10cSrcweir 2988cdf0e10cSrcweir // apply overrides from the Parameters struct 2989cdf0e10cSrcweir if( rParams.maFillColor.is_initialized() ) 2990cdf0e10cSrcweir { 2991cdf0e10cSrcweir getState( aStateStack ).isFillColorSet = true; 2992cdf0e10cSrcweir getState( aStateStack ).fillColor = pColor->getDeviceColor( *rParams.maFillColor ); 2993cdf0e10cSrcweir } 2994cdf0e10cSrcweir if( rParams.maLineColor.is_initialized() ) 2995cdf0e10cSrcweir { 2996cdf0e10cSrcweir getState( aStateStack ).isLineColorSet = true; 2997cdf0e10cSrcweir getState( aStateStack ).lineColor = pColor->getDeviceColor( *rParams.maLineColor ); 2998cdf0e10cSrcweir } 2999cdf0e10cSrcweir if( rParams.maTextColor.is_initialized() ) 3000cdf0e10cSrcweir { 3001cdf0e10cSrcweir getState( aStateStack ).isTextFillColorSet = true; 3002cdf0e10cSrcweir getState( aStateStack ).isTextLineColorSet = true; 3003cdf0e10cSrcweir getState( aStateStack ).textColor = 3004cdf0e10cSrcweir getState( aStateStack ).textFillColor = 3005cdf0e10cSrcweir getState( aStateStack ).textLineColor = pColor->getDeviceColor( *rParams.maTextColor ); 3006cdf0e10cSrcweir } 3007cdf0e10cSrcweir if( rParams.maFontName.is_initialized() || 3008cdf0e10cSrcweir rParams.maFontWeight.is_initialized() || 3009cdf0e10cSrcweir rParams.maFontLetterForm.is_initialized() || 3010cdf0e10cSrcweir rParams.maFontUnderline.is_initialized() || 3011cdf0e10cSrcweir rParams.maFontProportion.is_initialized() ) 3012cdf0e10cSrcweir { 3013cdf0e10cSrcweir ::cppcanvas::internal::OutDevState& rState = getState( aStateStack ); 3014cdf0e10cSrcweir 3015cdf0e10cSrcweir rState.xFont = createFont( rState.fontRotation, 3016cdf0e10cSrcweir ::Font(), // default font 3017cdf0e10cSrcweir aParms ); 3018cdf0e10cSrcweir } 3019cdf0e10cSrcweir 3020cdf0e10cSrcweir createActions( const_cast<GDIMetaFile&>(rMtf), // HACK(Q2): 3021cdf0e10cSrcweir // we're 3022cdf0e10cSrcweir // changing 3023cdf0e10cSrcweir // the 3024cdf0e10cSrcweir // current 3025cdf0e10cSrcweir // action 3026cdf0e10cSrcweir // in 3027cdf0e10cSrcweir // createActions! 3028cdf0e10cSrcweir aParms, 3029cdf0e10cSrcweir true // TODO(P1): make subsettability configurable 3030cdf0e10cSrcweir ); 3031cdf0e10cSrcweir } 3032cdf0e10cSrcweir 3033cdf0e10cSrcweir ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas, 3034cdf0e10cSrcweir const BitmapEx& rBmpEx, 3035cdf0e10cSrcweir const Parameters& rParams ) : 3036cdf0e10cSrcweir CanvasGraphicHelper( rCanvas ), 3037cdf0e10cSrcweir maActions() 3038cdf0e10cSrcweir { 3039cdf0e10cSrcweir // TODO(F3): property modification parameters are 3040cdf0e10cSrcweir // currently ignored for Bitmaps 3041cdf0e10cSrcweir (void)rParams; 3042cdf0e10cSrcweir 3043cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(bitmap)" ); 3044cdf0e10cSrcweir 3045cdf0e10cSrcweir OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(), 3046cdf0e10cSrcweir "ImplRenderer::ImplRenderer(): Invalid canvas" ); 3047cdf0e10cSrcweir OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(), 3048cdf0e10cSrcweir "ImplRenderer::ImplRenderer(): Invalid graphic device" ); 3049cdf0e10cSrcweir 3050cdf0e10cSrcweir // make sure canvas and graphic device are valid; action 3051cdf0e10cSrcweir // creation don't check that every time 3052cdf0e10cSrcweir if( rCanvas.get() == NULL || 3053cdf0e10cSrcweir !rCanvas->getUNOCanvas().is() || 3054cdf0e10cSrcweir !rCanvas->getUNOCanvas()->getDevice().is() ) 3055cdf0e10cSrcweir { 3056cdf0e10cSrcweir // leave actions empty 3057cdf0e10cSrcweir return; 3058cdf0e10cSrcweir } 3059cdf0e10cSrcweir 3060cdf0e10cSrcweir OutDevState aState; 3061cdf0e10cSrcweir 3062cdf0e10cSrcweir const Size aBmpSize( rBmpEx.GetSizePixel() ); 3063cdf0e10cSrcweir 3064cdf0e10cSrcweir // Setup local state, such that the bitmap renders itself 3065cdf0e10cSrcweir // into a one-by-one square for identity view and render 3066cdf0e10cSrcweir // transformations 3067cdf0e10cSrcweir aState.transform.scale( 1.0 / aBmpSize.Width(), 3068cdf0e10cSrcweir 1.0 / aBmpSize.Height() ); 3069cdf0e10cSrcweir 3070cdf0e10cSrcweir // create a single action for the provided BitmapEx 3071cdf0e10cSrcweir maActions.push_back( 3072cdf0e10cSrcweir MtfAction( 3073cdf0e10cSrcweir BitmapActionFactory::createBitmapAction( 3074cdf0e10cSrcweir rBmpEx, 3075cdf0e10cSrcweir ::basegfx::B2DPoint(), 3076cdf0e10cSrcweir rCanvas, 3077cdf0e10cSrcweir aState), 3078cdf0e10cSrcweir 0 ) ); 3079cdf0e10cSrcweir } 3080cdf0e10cSrcweir 3081cdf0e10cSrcweir ImplRenderer::~ImplRenderer() 3082cdf0e10cSrcweir { 3083cdf0e10cSrcweir } 3084cdf0e10cSrcweir 3085cdf0e10cSrcweir bool ImplRenderer::drawSubset( sal_Int32 nStartIndex, 3086cdf0e10cSrcweir sal_Int32 nEndIndex ) const 3087cdf0e10cSrcweir { 3088cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::drawSubset()" ); 3089cdf0e10cSrcweir 3090cdf0e10cSrcweir ActionVector::const_iterator aRangeBegin; 3091cdf0e10cSrcweir ActionVector::const_iterator aRangeEnd; 3092cdf0e10cSrcweir 3093cdf0e10cSrcweir try 3094cdf0e10cSrcweir { 3095cdf0e10cSrcweir if( !getSubsetIndices( nStartIndex, nEndIndex, 3096cdf0e10cSrcweir aRangeBegin, aRangeEnd ) ) 3097cdf0e10cSrcweir return true; // nothing to render (but _that_ was successful) 3098cdf0e10cSrcweir 3099cdf0e10cSrcweir // now, aRangeBegin references the action in which the 3100cdf0e10cSrcweir // subset rendering must start, and aRangeEnd references 3101cdf0e10cSrcweir // the action in which the subset rendering must end (it 3102cdf0e10cSrcweir // might also end right at the start of the referenced 3103cdf0e10cSrcweir // action, such that zero of that action needs to be 3104cdf0e10cSrcweir // rendered). 3105cdf0e10cSrcweir 3106cdf0e10cSrcweir 3107cdf0e10cSrcweir // render subset of actions 3108cdf0e10cSrcweir // ======================== 3109cdf0e10cSrcweir 3110cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 3111cdf0e10cSrcweir ::canvas::tools::getRenderStateTransform( aMatrix, 3112cdf0e10cSrcweir getRenderState() ); 3113cdf0e10cSrcweir 3114cdf0e10cSrcweir ActionRenderer aRenderer( aMatrix ); 3115cdf0e10cSrcweir 3116cdf0e10cSrcweir return forSubsetRange( aRenderer, 3117cdf0e10cSrcweir aRangeBegin, 3118cdf0e10cSrcweir aRangeEnd, 3119cdf0e10cSrcweir nStartIndex, 3120cdf0e10cSrcweir nEndIndex, 3121cdf0e10cSrcweir maActions.end() ); 3122cdf0e10cSrcweir } 3123cdf0e10cSrcweir catch( uno::Exception& ) 3124cdf0e10cSrcweir { 3125cdf0e10cSrcweir OSL_ENSURE( false, 3126cdf0e10cSrcweir rtl::OUStringToOString( 3127cdf0e10cSrcweir comphelper::anyToString( cppu::getCaughtException() ), 3128cdf0e10cSrcweir RTL_TEXTENCODING_UTF8 ).getStr() ); 3129cdf0e10cSrcweir 3130cdf0e10cSrcweir // convert error to return value 3131cdf0e10cSrcweir return false; 3132cdf0e10cSrcweir } 3133cdf0e10cSrcweir } 3134cdf0e10cSrcweir 3135cdf0e10cSrcweir ::basegfx::B2DRange ImplRenderer::getSubsetArea( sal_Int32 nStartIndex, 3136cdf0e10cSrcweir sal_Int32 nEndIndex ) const 3137cdf0e10cSrcweir { 3138cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::getSubsetArea()" ); 3139cdf0e10cSrcweir 3140cdf0e10cSrcweir ActionVector::const_iterator aRangeBegin; 3141cdf0e10cSrcweir ActionVector::const_iterator aRangeEnd; 3142cdf0e10cSrcweir 3143cdf0e10cSrcweir if( !getSubsetIndices( nStartIndex, nEndIndex, 3144cdf0e10cSrcweir aRangeBegin, aRangeEnd ) ) 3145cdf0e10cSrcweir return ::basegfx::B2DRange(); // nothing to render -> empty range 3146cdf0e10cSrcweir 3147cdf0e10cSrcweir // now, aRangeBegin references the action in which the 3148cdf0e10cSrcweir // subset querying must start, and aRangeEnd references 3149cdf0e10cSrcweir // the action in which the subset querying must end (it 3150cdf0e10cSrcweir // might also end right at the start of the referenced 3151cdf0e10cSrcweir // action, such that zero of that action needs to be 3152cdf0e10cSrcweir // queried). 3153cdf0e10cSrcweir 3154cdf0e10cSrcweir 3155cdf0e10cSrcweir // query bounds for subset of actions 3156cdf0e10cSrcweir // ================================== 3157cdf0e10cSrcweir 3158cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 3159cdf0e10cSrcweir ::canvas::tools::getRenderStateTransform( aMatrix, 3160cdf0e10cSrcweir getRenderState() ); 3161cdf0e10cSrcweir 3162cdf0e10cSrcweir AreaQuery aQuery( aMatrix ); 3163cdf0e10cSrcweir forSubsetRange( aQuery, 3164cdf0e10cSrcweir aRangeBegin, 3165cdf0e10cSrcweir aRangeEnd, 3166cdf0e10cSrcweir nStartIndex, 3167cdf0e10cSrcweir nEndIndex, 3168cdf0e10cSrcweir maActions.end() ); 3169cdf0e10cSrcweir 3170cdf0e10cSrcweir return aQuery.getBounds(); 3171cdf0e10cSrcweir } 3172cdf0e10cSrcweir 3173cdf0e10cSrcweir bool ImplRenderer::draw() const 3174cdf0e10cSrcweir { 3175cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::draw()" ); 3176cdf0e10cSrcweir 3177cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 3178cdf0e10cSrcweir ::canvas::tools::getRenderStateTransform( aMatrix, 3179cdf0e10cSrcweir getRenderState() ); 3180cdf0e10cSrcweir 3181cdf0e10cSrcweir try 3182cdf0e10cSrcweir { 3183cdf0e10cSrcweir return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer( aMatrix ) ).result(); 3184cdf0e10cSrcweir } 3185cdf0e10cSrcweir catch( uno::Exception& ) 3186cdf0e10cSrcweir { 3187cdf0e10cSrcweir OSL_ENSURE( false, 3188cdf0e10cSrcweir rtl::OUStringToOString( 3189cdf0e10cSrcweir comphelper::anyToString( cppu::getCaughtException() ), 3190cdf0e10cSrcweir RTL_TEXTENCODING_UTF8 ).getStr() ); 3191cdf0e10cSrcweir 3192cdf0e10cSrcweir return false; 3193cdf0e10cSrcweir } 3194cdf0e10cSrcweir } 3195cdf0e10cSrcweir } 3196cdf0e10cSrcweir } 3197