1*25ea7f45SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*25ea7f45SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*25ea7f45SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*25ea7f45SAndrew Rist  * distributed with this work for additional information
6*25ea7f45SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*25ea7f45SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*25ea7f45SAndrew Rist  * "License"); you may not use this file except in compliance
9*25ea7f45SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*25ea7f45SAndrew Rist  *
11*25ea7f45SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*25ea7f45SAndrew Rist  *
13*25ea7f45SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*25ea7f45SAndrew Rist  * software distributed under the License is distributed on an
15*25ea7f45SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*25ea7f45SAndrew Rist  * KIND, either express or implied.  See the License for the
17*25ea7f45SAndrew Rist  * specific language governing permissions and limitations
18*25ea7f45SAndrew Rist  * under the License.
19*25ea7f45SAndrew Rist  *
20*25ea7f45SAndrew Rist  *************************************************************/
21*25ea7f45SAndrew Rist 
22*25ea7f45SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_canvas.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <canvas/debug.hxx>
28cdf0e10cSrcweir #include <tools/diagnose_ex.h>
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #include <rtl/logfile.hxx>
31cdf0e10cSrcweir #include <rtl/math.hxx>
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include <com/sun/star/rendering/TexturingMode.hpp>
34cdf0e10cSrcweir #include <com/sun/star/rendering/CompositeOperation.hpp>
35cdf0e10cSrcweir #include <com/sun/star/rendering/RepaintResult.hpp>
36cdf0e10cSrcweir #include <com/sun/star/rendering/PathCapType.hpp>
37cdf0e10cSrcweir #include <com/sun/star/rendering/PathJoinType.hpp>
38cdf0e10cSrcweir 
39cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
40cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
41cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
42cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx>
43cdf0e10cSrcweir 
44cdf0e10cSrcweir #include <comphelper/sequence.hxx>
45cdf0e10cSrcweir #include <canvas/canvastools.hxx>
46cdf0e10cSrcweir 
47cdf0e10cSrcweir #include "dx_spritecanvas.hxx"
48cdf0e10cSrcweir #include "dx_impltools.hxx"
49cdf0e10cSrcweir #include "dx_vcltools.hxx"
50cdf0e10cSrcweir #include "dx_canvasfont.hxx"
51cdf0e10cSrcweir #include "dx_textlayout.hxx"
52cdf0e10cSrcweir #include "dx_canvashelper.hxx"
53cdf0e10cSrcweir 
54cdf0e10cSrcweir #include <algorithm>
55cdf0e10cSrcweir 
56cdf0e10cSrcweir 
57cdf0e10cSrcweir using namespace ::com::sun::star;
58cdf0e10cSrcweir 
59cdf0e10cSrcweir namespace dxcanvas
60cdf0e10cSrcweir {
61cdf0e10cSrcweir     namespace
62cdf0e10cSrcweir     {
gdiCapFromCap(sal_Int8 nCapType)63cdf0e10cSrcweir 		Gdiplus::LineCap gdiCapFromCap( sal_Int8 nCapType )
64cdf0e10cSrcweir         {
65cdf0e10cSrcweir             switch( nCapType )
66cdf0e10cSrcweir             {
67cdf0e10cSrcweir                 case rendering::PathCapType::BUTT:
68cdf0e10cSrcweir                     return Gdiplus::LineCapFlat;
69cdf0e10cSrcweir 
70cdf0e10cSrcweir                 case rendering::PathCapType::ROUND:
71cdf0e10cSrcweir                     return Gdiplus::LineCapRound;
72cdf0e10cSrcweir 
73cdf0e10cSrcweir                 case rendering::PathCapType::SQUARE:
74cdf0e10cSrcweir                     return Gdiplus::LineCapSquare;
75cdf0e10cSrcweir 
76cdf0e10cSrcweir                 default:
77cdf0e10cSrcweir                     ENSURE_OR_THROW( false,
78cdf0e10cSrcweir                                       "gdiCapFromCap(): Unexpected cap type" );
79cdf0e10cSrcweir             }
80cdf0e10cSrcweir 
81cdf0e10cSrcweir             return Gdiplus::LineCapFlat;
82cdf0e10cSrcweir         }
83cdf0e10cSrcweir 
gdiJoinFromJoin(sal_Int8 nJoinType)84cdf0e10cSrcweir         Gdiplus::LineJoin gdiJoinFromJoin( sal_Int8 nJoinType )
85cdf0e10cSrcweir         {
86cdf0e10cSrcweir             switch( nJoinType )
87cdf0e10cSrcweir             {
88cdf0e10cSrcweir                 case rendering::PathJoinType::NONE:
89cdf0e10cSrcweir                     OSL_ENSURE( false,
90cdf0e10cSrcweir                                 "gdiJoinFromJoin(): Join NONE not possible, mapping to MITER" );
91cdf0e10cSrcweir                     // FALLTHROUGH intended
92cdf0e10cSrcweir                 case rendering::PathJoinType::MITER:
93cdf0e10cSrcweir                     return Gdiplus::LineJoinMiter;
94cdf0e10cSrcweir 
95cdf0e10cSrcweir                 case rendering::PathJoinType::ROUND:
96cdf0e10cSrcweir                     return Gdiplus::LineJoinRound;
97cdf0e10cSrcweir 
98cdf0e10cSrcweir                 case rendering::PathJoinType::BEVEL:
99cdf0e10cSrcweir                     return Gdiplus::LineJoinBevel;
100cdf0e10cSrcweir 
101cdf0e10cSrcweir                 default:
102cdf0e10cSrcweir                     ENSURE_OR_THROW( false,
103cdf0e10cSrcweir                                       "gdiJoinFromJoin(): Unexpected join type" );
104cdf0e10cSrcweir             }
105cdf0e10cSrcweir 
106cdf0e10cSrcweir             return Gdiplus::LineJoinMiter;
107cdf0e10cSrcweir         }
108cdf0e10cSrcweir     }
109cdf0e10cSrcweir 
CanvasHelper()110cdf0e10cSrcweir     CanvasHelper::CanvasHelper() :
111cdf0e10cSrcweir         mpGdiPlusUser( GDIPlusUser::createInstance() ),
112cdf0e10cSrcweir         mpDevice( NULL ),
113cdf0e10cSrcweir         mpGraphicsProvider(),
114cdf0e10cSrcweir         maOutputOffset()
115cdf0e10cSrcweir     {
116cdf0e10cSrcweir     }
117cdf0e10cSrcweir 
disposing()118cdf0e10cSrcweir     void CanvasHelper::disposing()
119cdf0e10cSrcweir     {
120cdf0e10cSrcweir         mpGraphicsProvider.reset();
121cdf0e10cSrcweir         mpDevice = NULL;
122cdf0e10cSrcweir         mpGdiPlusUser.reset();
123cdf0e10cSrcweir     }
124cdf0e10cSrcweir 
setDevice(rendering::XGraphicDevice & rDevice)125cdf0e10cSrcweir     void CanvasHelper::setDevice( rendering::XGraphicDevice& rDevice )
126cdf0e10cSrcweir     {
127cdf0e10cSrcweir         mpDevice = &rDevice;
128cdf0e10cSrcweir     }
129cdf0e10cSrcweir 
setTarget(const GraphicsProviderSharedPtr & rTarget)130cdf0e10cSrcweir     void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget )
131cdf0e10cSrcweir     {
132cdf0e10cSrcweir         ENSURE_OR_THROW( rTarget,
133cdf0e10cSrcweir                           "CanvasHelper::setTarget(): Invalid target" );
134cdf0e10cSrcweir         ENSURE_OR_THROW( !mpGraphicsProvider.get(),
135cdf0e10cSrcweir                           "CanvasHelper::setTarget(): target set, old target would be overwritten" );
136cdf0e10cSrcweir 
137cdf0e10cSrcweir         mpGraphicsProvider = rTarget;
138cdf0e10cSrcweir     }
139cdf0e10cSrcweir 
setTarget(const GraphicsProviderSharedPtr & rTarget,const::basegfx::B2ISize & rOutputOffset)140cdf0e10cSrcweir     void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget,
141cdf0e10cSrcweir                                   const ::basegfx::B2ISize& 	   rOutputOffset )
142cdf0e10cSrcweir     {
143cdf0e10cSrcweir         ENSURE_OR_THROW( rTarget,
144cdf0e10cSrcweir                          "CanvasHelper::setTarget(): invalid target" );
145cdf0e10cSrcweir         ENSURE_OR_THROW( !mpGraphicsProvider.get(),
146cdf0e10cSrcweir                          "CanvasHelper::setTarget(): target set, old target would be overwritten" );
147cdf0e10cSrcweir 
148cdf0e10cSrcweir         mpGraphicsProvider = rTarget;
149cdf0e10cSrcweir         maOutputOffset = rOutputOffset;
150cdf0e10cSrcweir     }
151cdf0e10cSrcweir 
clear()152cdf0e10cSrcweir     void CanvasHelper::clear()
153cdf0e10cSrcweir     {
154cdf0e10cSrcweir         if( needOutput() )
155cdf0e10cSrcweir         {
156cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
157cdf0e10cSrcweir             Gdiplus::Color aClearColor = Gdiplus::Color((Gdiplus::ARGB)Gdiplus::Color::White);
158cdf0e10cSrcweir 
159cdf0e10cSrcweir             ENSURE_OR_THROW(
160cdf0e10cSrcweir                 Gdiplus::Ok == pGraphics->SetCompositingMode(
161cdf0e10cSrcweir                     Gdiplus::CompositingModeSourceCopy ), // force set, don't blend
162cdf0e10cSrcweir                 "CanvasHelper::clear(): GDI+ SetCompositingMode call failed" );
163cdf0e10cSrcweir             ENSURE_OR_THROW(
164cdf0e10cSrcweir                 Gdiplus::Ok == pGraphics->Clear( aClearColor ),
165cdf0e10cSrcweir                 "CanvasHelper::clear(): GDI+ Clear call failed" );
166cdf0e10cSrcweir         }
167cdf0e10cSrcweir     }
168cdf0e10cSrcweir 
drawPoint(const rendering::XCanvas *,const geometry::RealPoint2D & aPoint,const rendering::ViewState & viewState,const rendering::RenderState & renderState)169cdf0e10cSrcweir     void CanvasHelper::drawPoint( const rendering::XCanvas* 	/*pCanvas*/,
170cdf0e10cSrcweir                                   const geometry::RealPoint2D& 	aPoint,
171cdf0e10cSrcweir                                   const rendering::ViewState& 	viewState,
172cdf0e10cSrcweir                                   const rendering::RenderState&	renderState )
173cdf0e10cSrcweir     {
174cdf0e10cSrcweir         if( needOutput() )
175cdf0e10cSrcweir         {
176cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
177cdf0e10cSrcweir 
178cdf0e10cSrcweir             setupGraphicsState( pGraphics, viewState, renderState );
179cdf0e10cSrcweir 
180cdf0e10cSrcweir             Gdiplus::SolidBrush aBrush(
181cdf0e10cSrcweir                 Gdiplus::Color(
182cdf0e10cSrcweir                     tools::sequenceToArgb(renderState.DeviceColor)) );
183cdf0e10cSrcweir 
184cdf0e10cSrcweir             // determine size of one-by-one device pixel ellipse
185cdf0e10cSrcweir             Gdiplus::Matrix aMatrix;
186cdf0e10cSrcweir             pGraphics->GetTransform(&aMatrix);
187cdf0e10cSrcweir             aMatrix.Invert();
188cdf0e10cSrcweir             Gdiplus::PointF vector(1, 1);
189cdf0e10cSrcweir             aMatrix.TransformVectors(&vector);
190cdf0e10cSrcweir 
191cdf0e10cSrcweir             // paint a one-by-one circle, with the given point
192cdf0e10cSrcweir             // in the middle (rounded to float)
193cdf0e10cSrcweir             ENSURE_OR_THROW(
194cdf0e10cSrcweir                 Gdiplus::Ok == pGraphics->FillEllipse( &aBrush,
195cdf0e10cSrcweir                                                        // disambiguate call
196cdf0e10cSrcweir                                                        Gdiplus::REAL(aPoint.X),
197cdf0e10cSrcweir                                                        Gdiplus::REAL(aPoint.Y),
198cdf0e10cSrcweir                                                        Gdiplus::REAL(vector.X),
199cdf0e10cSrcweir                                                        Gdiplus::REAL(vector.Y) ),
200cdf0e10cSrcweir                 "CanvasHelper::drawPoint(): GDI+ call failed" );
201cdf0e10cSrcweir         }
202cdf0e10cSrcweir     }
203cdf0e10cSrcweir 
drawLine(const rendering::XCanvas *,const geometry::RealPoint2D & aStartPoint,const geometry::RealPoint2D & aEndPoint,const rendering::ViewState & viewState,const rendering::RenderState & renderState)204cdf0e10cSrcweir     void CanvasHelper::drawLine( const rendering::XCanvas* 		/*pCanvas*/,
205cdf0e10cSrcweir                                  const geometry::RealPoint2D& 	aStartPoint,
206cdf0e10cSrcweir                                  const geometry::RealPoint2D& 	aEndPoint,
207cdf0e10cSrcweir                                  const rendering::ViewState& 	viewState,
208cdf0e10cSrcweir                                  const rendering::RenderState& 	renderState )
209cdf0e10cSrcweir     {
210cdf0e10cSrcweir         if( needOutput() )
211cdf0e10cSrcweir         {
212cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
213cdf0e10cSrcweir 
214cdf0e10cSrcweir             setupGraphicsState( pGraphics, viewState, renderState );
215cdf0e10cSrcweir 
216cdf0e10cSrcweir             Gdiplus::Pen aPen(
217cdf0e10cSrcweir                 Gdiplus::Color(
218cdf0e10cSrcweir                     tools::sequenceToArgb(renderState.DeviceColor)),
219cdf0e10cSrcweir                 Gdiplus::REAL(0.0) );
220cdf0e10cSrcweir 
221cdf0e10cSrcweir             // #122683# Switched precedence of pixel offset
222cdf0e10cSrcweir             // mode. Seemingly, polygon stroking needs
223cdf0e10cSrcweir             // PixelOffsetModeNone to achieve visually pleasing
224cdf0e10cSrcweir             // results, whereas all other operations (e.g. polygon
225cdf0e10cSrcweir             // fills, bitmaps) look better with PixelOffsetModeHalf.
226cdf0e10cSrcweir             const Gdiplus::PixelOffsetMode aOldMode(
227cdf0e10cSrcweir                 pGraphics->GetPixelOffsetMode() );
228cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone );
229cdf0e10cSrcweir 
230cdf0e10cSrcweir             Gdiplus::Status hr = pGraphics->DrawLine( &aPen,
231cdf0e10cSrcweir                                                       Gdiplus::REAL(aStartPoint.X), // disambiguate call
232cdf0e10cSrcweir                                                       Gdiplus::REAL(aStartPoint.Y),
233cdf0e10cSrcweir                                                       Gdiplus::REAL(aEndPoint.X),
234cdf0e10cSrcweir                                                       Gdiplus::REAL(aEndPoint.Y) );
235cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( aOldMode );
236cdf0e10cSrcweir 
237cdf0e10cSrcweir             ENSURE_OR_THROW(
238cdf0e10cSrcweir                 Gdiplus::Ok == hr,
239cdf0e10cSrcweir                 "CanvasHelper::drawLine(): GDI+ call failed" );
240cdf0e10cSrcweir         }
241cdf0e10cSrcweir     }
242cdf0e10cSrcweir 
drawBezier(const rendering::XCanvas *,const geometry::RealBezierSegment2D & aBezierSegment,const geometry::RealPoint2D & aEndPoint,const rendering::ViewState & viewState,const rendering::RenderState & renderState)243cdf0e10cSrcweir     void CanvasHelper::drawBezier( const rendering::XCanvas* 			/*pCanvas*/,
244cdf0e10cSrcweir                                    const geometry::RealBezierSegment2D&	aBezierSegment,
245cdf0e10cSrcweir                                    const geometry::RealPoint2D& 		aEndPoint,
246cdf0e10cSrcweir                                    const rendering::ViewState& 			viewState,
247cdf0e10cSrcweir                                    const rendering::RenderState& 		renderState )
248cdf0e10cSrcweir     {
249cdf0e10cSrcweir         if( needOutput() )
250cdf0e10cSrcweir         {
251cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
252cdf0e10cSrcweir 
253cdf0e10cSrcweir             setupGraphicsState( pGraphics, viewState, renderState );
254cdf0e10cSrcweir 
255cdf0e10cSrcweir             Gdiplus::Pen aPen(
256cdf0e10cSrcweir                 Gdiplus::Color(
257cdf0e10cSrcweir                     tools::sequenceToArgb(renderState.DeviceColor)),
258cdf0e10cSrcweir                 Gdiplus::REAL(0.0) );
259cdf0e10cSrcweir 
260cdf0e10cSrcweir             // #122683# Switched precedence of pixel offset
261cdf0e10cSrcweir             // mode. Seemingly, polygon stroking needs
262cdf0e10cSrcweir             // PixelOffsetModeNone to achieve visually pleasing
263cdf0e10cSrcweir             // results, whereas all other operations (e.g. polygon
264cdf0e10cSrcweir             // fills, bitmaps) look better with PixelOffsetModeHalf.
265cdf0e10cSrcweir             const Gdiplus::PixelOffsetMode aOldMode(
266cdf0e10cSrcweir                 pGraphics->GetPixelOffsetMode() );
267cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone );
268cdf0e10cSrcweir 
269cdf0e10cSrcweir             Gdiplus::Status hr = pGraphics->DrawBezier( &aPen,
270cdf0e10cSrcweir                                                         Gdiplus::REAL(aBezierSegment.Px), // disambiguate call
271cdf0e10cSrcweir                                                         Gdiplus::REAL(aBezierSegment.Py),
272cdf0e10cSrcweir                                                         Gdiplus::REAL(aBezierSegment.C1x),
273cdf0e10cSrcweir                                                         Gdiplus::REAL(aBezierSegment.C1y),
274cdf0e10cSrcweir                                                         Gdiplus::REAL(aEndPoint.X),
275cdf0e10cSrcweir                                                         Gdiplus::REAL(aEndPoint.Y),
276cdf0e10cSrcweir                                                         Gdiplus::REAL(aBezierSegment.C2x),
277cdf0e10cSrcweir                                                         Gdiplus::REAL(aBezierSegment.C2y) );
278cdf0e10cSrcweir 
279cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( aOldMode );
280cdf0e10cSrcweir 
281cdf0e10cSrcweir             ENSURE_OR_THROW(
282cdf0e10cSrcweir                 Gdiplus::Ok == hr,
283cdf0e10cSrcweir                 "CanvasHelper::drawBezier(): GDI+ call failed" );
284cdf0e10cSrcweir         }
285cdf0e10cSrcweir     }
286cdf0e10cSrcweir 
drawPolyPolygon(const rendering::XCanvas *,const uno::Reference<rendering::XPolyPolygon2D> & xPolyPolygon,const rendering::ViewState & viewState,const rendering::RenderState & renderState)287cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* 							/*pCanvas*/,
288cdf0e10cSrcweir                                                                                  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
289cdf0e10cSrcweir                                                                                  const rendering::ViewState& 						viewState,
290cdf0e10cSrcweir                                                                                  const rendering::RenderState& 						renderState )
291cdf0e10cSrcweir     {
292cdf0e10cSrcweir         ENSURE_OR_THROW( xPolyPolygon.is(),
293cdf0e10cSrcweir                           "CanvasHelper::drawPolyPolygon: polygon is NULL");
294cdf0e10cSrcweir 
295cdf0e10cSrcweir         if( needOutput() )
296cdf0e10cSrcweir         {
297cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
298cdf0e10cSrcweir 
299cdf0e10cSrcweir             setupGraphicsState( pGraphics, viewState, renderState );
300cdf0e10cSrcweir 
301cdf0e10cSrcweir             Gdiplus::Pen aPen(
302cdf0e10cSrcweir                 Gdiplus::Color(
303cdf0e10cSrcweir                     tools::sequenceToArgb(renderState.DeviceColor)),
304cdf0e10cSrcweir                 Gdiplus::REAL(0.0) );
305cdf0e10cSrcweir 
306cdf0e10cSrcweir             // #122683# Switched precedence of pixel offset
307cdf0e10cSrcweir             // mode. Seemingly, polygon stroking needs
308cdf0e10cSrcweir             // PixelOffsetModeNone to achieve visually pleasing
309cdf0e10cSrcweir             // results, whereas all other operations (e.g. polygon
310cdf0e10cSrcweir             // fills, bitmaps) look better with PixelOffsetModeHalf.
311cdf0e10cSrcweir             const Gdiplus::PixelOffsetMode aOldMode(
312cdf0e10cSrcweir                 pGraphics->GetPixelOffsetMode() );
313cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone );
314cdf0e10cSrcweir 
315cdf0e10cSrcweir             GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) );
316cdf0e10cSrcweir 
317cdf0e10cSrcweir             // TODO(E1): Return value
318cdf0e10cSrcweir             Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() );
319cdf0e10cSrcweir 
320cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( aOldMode );
321cdf0e10cSrcweir 
322cdf0e10cSrcweir             ENSURE_OR_THROW(
323cdf0e10cSrcweir                 Gdiplus::Ok == hr,
324cdf0e10cSrcweir                 "CanvasHelper::drawPolyPolygon(): GDI+ call failed" );
325cdf0e10cSrcweir         }
326cdf0e10cSrcweir 
327cdf0e10cSrcweir         // TODO(P1): Provide caching here.
328cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
329cdf0e10cSrcweir     }
330cdf0e10cSrcweir 
strokePolyPolygon(const rendering::XCanvas *,const uno::Reference<rendering::XPolyPolygon2D> & xPolyPolygon,const rendering::ViewState & viewState,const rendering::RenderState & renderState,const rendering::StrokeAttributes & strokeAttributes)331cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* 							/*pCanvas*/,
332cdf0e10cSrcweir                                                                                    const uno::Reference< rendering::XPolyPolygon2D >& 	xPolyPolygon,
333cdf0e10cSrcweir                                                                                    const rendering::ViewState& 							viewState,
334cdf0e10cSrcweir                                                                                    const rendering::RenderState& 						renderState,
335cdf0e10cSrcweir                                                                                    const rendering::StrokeAttributes& 					strokeAttributes )
336cdf0e10cSrcweir     {
337cdf0e10cSrcweir         ENSURE_OR_THROW( xPolyPolygon.is(),
338cdf0e10cSrcweir                           "CanvasHelper::drawPolyPolygon: polygon is NULL");
339cdf0e10cSrcweir 
340cdf0e10cSrcweir         if( needOutput() )
341cdf0e10cSrcweir         {
342cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
343cdf0e10cSrcweir 
344cdf0e10cSrcweir             setupGraphicsState( pGraphics, viewState, renderState );
345cdf0e10cSrcweir 
346cdf0e10cSrcweir 
347cdf0e10cSrcweir             // Setup stroke pen
348cdf0e10cSrcweir             // ----------------
349cdf0e10cSrcweir 
350cdf0e10cSrcweir             Gdiplus::Pen aPen(
351cdf0e10cSrcweir                 Gdiplus::Color(
352cdf0e10cSrcweir                     tools::sequenceToArgb(renderState.DeviceColor)),
353cdf0e10cSrcweir                 static_cast< Gdiplus::REAL >(strokeAttributes.StrokeWidth) );
354cdf0e10cSrcweir 
355cdf0e10cSrcweir             // #122683# Switched precedence of pixel offset
356cdf0e10cSrcweir             // mode. Seemingly, polygon stroking needs
357cdf0e10cSrcweir             // PixelOffsetModeNone to achieve visually pleasing
358cdf0e10cSrcweir             // results, whereas all other operations (e.g. polygon
359cdf0e10cSrcweir             // fills, bitmaps) look better with PixelOffsetModeHalf.
360cdf0e10cSrcweir             const Gdiplus::PixelOffsetMode aOldMode(
361cdf0e10cSrcweir                 pGraphics->GetPixelOffsetMode() );
362cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone );
363cdf0e10cSrcweir 
364cdf0e10cSrcweir             const bool bIsMiter(rendering::PathJoinType::MITER == strokeAttributes.JoinType);
365cdf0e10cSrcweir             const bool bIsNone(rendering::PathJoinType::NONE == strokeAttributes.JoinType);
366cdf0e10cSrcweir 
367cdf0e10cSrcweir             if(bIsMiter)
368cdf0e10cSrcweir                 aPen.SetMiterLimit( static_cast< Gdiplus::REAL >(strokeAttributes.MiterLimit) );
369cdf0e10cSrcweir 
370cdf0e10cSrcweir             const ::std::vector< Gdiplus::REAL >& rDashArray(
371cdf0e10cSrcweir                 ::comphelper::sequenceToContainer< ::std::vector< Gdiplus::REAL > >(
372cdf0e10cSrcweir                     strokeAttributes.DashArray ) );
373cdf0e10cSrcweir             if( !rDashArray.empty() )
374cdf0e10cSrcweir             {
375cdf0e10cSrcweir                 aPen.SetDashPattern( &rDashArray[0],
376cdf0e10cSrcweir                                      rDashArray.size() );
377cdf0e10cSrcweir             }
378cdf0e10cSrcweir             aPen.SetLineCap( gdiCapFromCap(strokeAttributes.StartCapType),
379cdf0e10cSrcweir                              gdiCapFromCap(strokeAttributes.EndCapType),
380cdf0e10cSrcweir                              Gdiplus::DashCapFlat );
381cdf0e10cSrcweir             if(!bIsNone)
382cdf0e10cSrcweir                 aPen.SetLineJoin( gdiJoinFromJoin(strokeAttributes.JoinType) );
383cdf0e10cSrcweir 
384cdf0e10cSrcweir             GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon, bIsNone ) );
385cdf0e10cSrcweir 
386cdf0e10cSrcweir             // TODO(E1): Return value
387cdf0e10cSrcweir             Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() );
388cdf0e10cSrcweir 
389cdf0e10cSrcweir 			pGraphics->SetPixelOffsetMode( aOldMode );
390cdf0e10cSrcweir 
391cdf0e10cSrcweir             ENSURE_OR_THROW(
392cdf0e10cSrcweir                 Gdiplus::Ok == hr,
393cdf0e10cSrcweir                 "CanvasHelper::strokePolyPolygon(): GDI+ call failed" );
394cdf0e10cSrcweir         }
395cdf0e10cSrcweir 
396cdf0e10cSrcweir         // TODO(P1): Provide caching here.
397cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
398cdf0e10cSrcweir     }
399cdf0e10cSrcweir 
strokeTexturedPolyPolygon(const rendering::XCanvas *,const uno::Reference<rendering::XPolyPolygon2D> &,const rendering::ViewState &,const rendering::RenderState &,const uno::Sequence<rendering::Texture> &,const rendering::StrokeAttributes &)400cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* 							/*pCanvas*/,
401cdf0e10cSrcweir                                                                                            const uno::Reference< rendering::XPolyPolygon2D >& 	/*xPolyPolygon*/,
402cdf0e10cSrcweir                                                                                            const rendering::ViewState& 							/*viewState*/,
403cdf0e10cSrcweir                                                                                            const rendering::RenderState& 						/*renderState*/,
404cdf0e10cSrcweir                                                                                            const uno::Sequence< rendering::Texture >& 			/*textures*/,
405cdf0e10cSrcweir                                                                                            const rendering::StrokeAttributes& 					/*strokeAttributes*/ )
406cdf0e10cSrcweir     {
407cdf0e10cSrcweir         // TODO
408cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
409cdf0e10cSrcweir     }
410cdf0e10cSrcweir 
strokeTextureMappedPolyPolygon(const rendering::XCanvas *,const uno::Reference<rendering::XPolyPolygon2D> &,const rendering::ViewState &,const rendering::RenderState &,const uno::Sequence<rendering::Texture> &,const uno::Reference<geometry::XMapping2D> &,const rendering::StrokeAttributes &)411cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* 							/*pCanvas*/,
412cdf0e10cSrcweir                                                                                                 const uno::Reference< rendering::XPolyPolygon2D >&	/*xPolyPolygon*/,
413cdf0e10cSrcweir                                                                                                 const rendering::ViewState& 						/*viewState*/,
414cdf0e10cSrcweir                                                                                                 const rendering::RenderState& 						/*renderState*/,
415cdf0e10cSrcweir                                                                                                 const uno::Sequence< rendering::Texture >& 			/*textures*/,
416cdf0e10cSrcweir                                                                                                 const uno::Reference< geometry::XMapping2D >& 		/*xMapping*/,
417cdf0e10cSrcweir                                                                                                 const rendering::StrokeAttributes& 					/*strokeAttributes*/ )
418cdf0e10cSrcweir     {
419cdf0e10cSrcweir         // TODO
420cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
421cdf0e10cSrcweir     }
422cdf0e10cSrcweir 
queryStrokeShapes(const rendering::XCanvas *,const uno::Reference<rendering::XPolyPolygon2D> &,const rendering::ViewState &,const rendering::RenderState &,const rendering::StrokeAttributes &)423cdf0e10cSrcweir     uno::Reference< rendering::XPolyPolygon2D >   CanvasHelper::queryStrokeShapes( const rendering::XCanvas* 							/*pCanvas*/,
424cdf0e10cSrcweir                                                                                    const uno::Reference< rendering::XPolyPolygon2D >& 	/*xPolyPolygon*/,
425cdf0e10cSrcweir                                                                                    const rendering::ViewState& 							/*viewState*/,
426cdf0e10cSrcweir                                                                                    const rendering::RenderState& 						/*renderState*/,
427cdf0e10cSrcweir                                                                                    const rendering::StrokeAttributes& 					/*strokeAttributes*/ )
428cdf0e10cSrcweir     {
429cdf0e10cSrcweir         // TODO
430cdf0e10cSrcweir         return uno::Reference< rendering::XPolyPolygon2D >(NULL);
431cdf0e10cSrcweir     }
432cdf0e10cSrcweir 
fillPolyPolygon(const rendering::XCanvas *,const uno::Reference<rendering::XPolyPolygon2D> & xPolyPolygon,const rendering::ViewState & viewState,const rendering::RenderState & renderState)433cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* 							/*pCanvas*/,
434cdf0e10cSrcweir                                                                                  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
435cdf0e10cSrcweir                                                                                  const rendering::ViewState& 						viewState,
436cdf0e10cSrcweir                                                                                  const rendering::RenderState& 						renderState )
437cdf0e10cSrcweir     {
438cdf0e10cSrcweir         ENSURE_OR_THROW( xPolyPolygon.is(),
439cdf0e10cSrcweir                           "CanvasHelper::fillPolyPolygon: polygon is NULL");
440cdf0e10cSrcweir 
441cdf0e10cSrcweir         if( needOutput() )
442cdf0e10cSrcweir         {
443cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
444cdf0e10cSrcweir 
445cdf0e10cSrcweir 			setupGraphicsState( pGraphics, viewState, renderState );
446cdf0e10cSrcweir 
447cdf0e10cSrcweir             Gdiplus::SolidBrush aBrush(
448cdf0e10cSrcweir                 tools::sequenceToArgb(renderState.DeviceColor));
449cdf0e10cSrcweir 
450cdf0e10cSrcweir             GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) );
451cdf0e10cSrcweir 
452cdf0e10cSrcweir             // TODO(F1): FillRule
453cdf0e10cSrcweir             ENSURE_OR_THROW( Gdiplus::Ok == pGraphics->FillPath( &aBrush, pPath.get() ),
454cdf0e10cSrcweir                              "CanvasHelper::fillPolyPolygon(): GDI+ call failed  " );
455cdf0e10cSrcweir         }
456cdf0e10cSrcweir 
457cdf0e10cSrcweir         // TODO(P1): Provide caching here.
458cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
459cdf0e10cSrcweir     }
460cdf0e10cSrcweir 
fillTextureMappedPolyPolygon(const rendering::XCanvas *,const uno::Reference<rendering::XPolyPolygon2D> &,const rendering::ViewState &,const rendering::RenderState &,const uno::Sequence<rendering::Texture> &,const uno::Reference<geometry::XMapping2D> &)461cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* 							/*pCanvas*/,
462cdf0e10cSrcweir                                                                                               const uno::Reference< rendering::XPolyPolygon2D >& 	/*xPolyPolygon*/,
463cdf0e10cSrcweir                                                                                               const rendering::ViewState& 							/*viewState*/,
464cdf0e10cSrcweir                                                                                               const rendering::RenderState& 						/*renderState*/,
465cdf0e10cSrcweir                                                                                               const uno::Sequence< rendering::Texture >& 			/*textures*/,
466cdf0e10cSrcweir                                                                                               const uno::Reference< geometry::XMapping2D >& 		/*xMapping*/ )
467cdf0e10cSrcweir     {
468cdf0e10cSrcweir         // TODO
469cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
470cdf0e10cSrcweir     }
471cdf0e10cSrcweir 
createFont(const rendering::XCanvas *,const rendering::FontRequest & fontRequest,const uno::Sequence<beans::PropertyValue> & extraFontProperties,const geometry::Matrix2D & fontMatrix)472cdf0e10cSrcweir     uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* 					/*pCanvas*/,
473cdf0e10cSrcweir                                                                        const rendering::FontRequest& 				fontRequest,
474cdf0e10cSrcweir                                                                        const uno::Sequence< beans::PropertyValue >& extraFontProperties,
475cdf0e10cSrcweir                                                                        const geometry::Matrix2D& 					fontMatrix )
476cdf0e10cSrcweir     {
477cdf0e10cSrcweir         if( needOutput() )
478cdf0e10cSrcweir         {
479cdf0e10cSrcweir             return uno::Reference< rendering::XCanvasFont >(
480cdf0e10cSrcweir                     new CanvasFont(fontRequest, extraFontProperties, fontMatrix ) );
481cdf0e10cSrcweir         }
482cdf0e10cSrcweir 
483cdf0e10cSrcweir         return uno::Reference< rendering::XCanvasFont >();
484cdf0e10cSrcweir     }
485cdf0e10cSrcweir 
queryAvailableFonts(const rendering::XCanvas *,const rendering::FontInfo &,const uno::Sequence<beans::PropertyValue> &)486cdf0e10cSrcweir     uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* 						/*pCanvas*/,
487cdf0e10cSrcweir                                                                             const rendering::FontInfo& 						/*aFilter*/,
488cdf0e10cSrcweir                                                                             const uno::Sequence< beans::PropertyValue >& 	/*aFontProperties*/ )
489cdf0e10cSrcweir     {
490cdf0e10cSrcweir         // TODO
491cdf0e10cSrcweir         return uno::Sequence< rendering::FontInfo >();
492cdf0e10cSrcweir     }
493cdf0e10cSrcweir 
drawText(const rendering::XCanvas *,const rendering::StringContext & text,const uno::Reference<rendering::XCanvasFont> & xFont,const rendering::ViewState & viewState,const rendering::RenderState & renderState,sal_Int8)494cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* 						/*pCanvas*/,
495cdf0e10cSrcweir                                                                           const rendering::StringContext& 					text,
496cdf0e10cSrcweir                                                                           const uno::Reference< rendering::XCanvasFont >& 	xFont,
497cdf0e10cSrcweir                                                                           const rendering::ViewState& 						viewState,
498cdf0e10cSrcweir                                                                           const rendering::RenderState& 					renderState,
499cdf0e10cSrcweir                                                                           sal_Int8				 							/*textDirection*/ )
500cdf0e10cSrcweir     {
501cdf0e10cSrcweir         ENSURE_OR_THROW( xFont.is(),
502cdf0e10cSrcweir                           "CanvasHelper::drawText: font is NULL");
503cdf0e10cSrcweir 
504cdf0e10cSrcweir         if( needOutput() )
505cdf0e10cSrcweir         {
506cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
507cdf0e10cSrcweir 
508cdf0e10cSrcweir             setupGraphicsState( pGraphics, viewState, renderState );
509cdf0e10cSrcweir 
510cdf0e10cSrcweir             Gdiplus::SolidBrush aBrush(
511cdf0e10cSrcweir                 Gdiplus::Color(
512cdf0e10cSrcweir                     tools::sequenceToArgb(renderState.DeviceColor)));
513cdf0e10cSrcweir 
514cdf0e10cSrcweir             CanvasFont::ImplRef pFont(
515cdf0e10cSrcweir                 tools::canvasFontFromXFont(xFont) );
516cdf0e10cSrcweir 
517cdf0e10cSrcweir             // Move glyphs up, such that output happens at the font
518cdf0e10cSrcweir             // baseline.
519cdf0e10cSrcweir             Gdiplus::PointF aPoint( 0.0,
520cdf0e10cSrcweir                                     static_cast<Gdiplus::REAL>(-(pFont->getFont()->GetSize()*
521cdf0e10cSrcweir                                                                  pFont->getCellAscent() /
522cdf0e10cSrcweir                                                                  pFont->getEmHeight())) );
523cdf0e10cSrcweir 
524cdf0e10cSrcweir             // TODO(F1): According to
525cdf0e10cSrcweir             // http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q307208,
526cdf0e10cSrcweir             // we might have to revert to GDI and ExTextOut here,
527cdf0e10cSrcweir             // since GDI+ takes the scalability a little bit too
528cdf0e10cSrcweir             // far...
529cdf0e10cSrcweir 
530cdf0e10cSrcweir             // TODO(F2): Proper layout (BiDi, CTL)! IMHO must use
531cdf0e10cSrcweir             // DrawDriverString here, and perform layouting myself...
532cdf0e10cSrcweir             ENSURE_OR_THROW(
533cdf0e10cSrcweir                 Gdiplus::Ok == pGraphics->DrawString( reinterpret_cast<LPCWSTR>(
534cdf0e10cSrcweir                                                           text.Text.copy( text.StartPosition,
535cdf0e10cSrcweir                                                                           text.Length ).getStr()),
536cdf0e10cSrcweir                                                       text.Length,
537cdf0e10cSrcweir                                                       pFont->getFont().get(),
538cdf0e10cSrcweir                                                       aPoint,
539cdf0e10cSrcweir                                                       &aBrush ),
540cdf0e10cSrcweir                 "CanvasHelper::drawText(): GDI+ call failed" );
541cdf0e10cSrcweir         }
542cdf0e10cSrcweir 
543cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
544cdf0e10cSrcweir     }
545cdf0e10cSrcweir 
drawTextLayout(const rendering::XCanvas *,const uno::Reference<rendering::XTextLayout> & xLayoutetText,const rendering::ViewState & viewState,const rendering::RenderState & renderState)546cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* 						/*pCanvas*/,
547cdf0e10cSrcweir                                                                                 const uno::Reference< rendering::XTextLayout >& xLayoutetText,
548cdf0e10cSrcweir                                                                                 const rendering::ViewState& 					viewState,
549cdf0e10cSrcweir                                                                                 const rendering::RenderState& 					renderState )
550cdf0e10cSrcweir     {
551cdf0e10cSrcweir         ENSURE_OR_THROW( xLayoutetText.is(),
552cdf0e10cSrcweir                           "CanvasHelper::drawTextLayout: layout is NULL");
553cdf0e10cSrcweir 
554cdf0e10cSrcweir         if( needOutput() )
555cdf0e10cSrcweir         {
556cdf0e10cSrcweir 			TextLayout* pTextLayout =
557cdf0e10cSrcweir                 dynamic_cast< TextLayout* >( xLayoutetText.get() );
558cdf0e10cSrcweir 
559cdf0e10cSrcweir             ENSURE_OR_THROW( pTextLayout,
560cdf0e10cSrcweir                                 "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" );
561cdf0e10cSrcweir 
562cdf0e10cSrcweir 			pTextLayout->draw( mpGraphicsProvider->getGraphics(),
563cdf0e10cSrcweir                                viewState,
564cdf0e10cSrcweir                                renderState,
565cdf0e10cSrcweir                                maOutputOffset,
566cdf0e10cSrcweir                                mpDevice,
567cdf0e10cSrcweir                                false );
568cdf0e10cSrcweir         }
569cdf0e10cSrcweir 
570cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
571cdf0e10cSrcweir     }
572cdf0e10cSrcweir 
drawBitmap(const rendering::XCanvas *,const uno::Reference<rendering::XBitmap> & xBitmap,const rendering::ViewState & viewState,const rendering::RenderState & renderState)573cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* 					/*pCanvas*/,
574cdf0e10cSrcweir                                                                             const uno::Reference< rendering::XBitmap >& xBitmap,
575cdf0e10cSrcweir                                                                             const rendering::ViewState& 				viewState,
576cdf0e10cSrcweir                                                                             const rendering::RenderState& 				renderState )
577cdf0e10cSrcweir     {
578cdf0e10cSrcweir         ENSURE_OR_THROW( xBitmap.is(),
579cdf0e10cSrcweir                           "CanvasHelper::drawBitmap: bitmap is NULL");
580cdf0e10cSrcweir 
581cdf0e10cSrcweir         if( needOutput() )
582cdf0e10cSrcweir         {
583cdf0e10cSrcweir             // check whether one of our own objects - need to retrieve
584cdf0e10cSrcweir             // bitmap _before_ calling
585cdf0e10cSrcweir             // GraphicsProvider::getGraphics(), to avoid locking our
586cdf0e10cSrcweir             // own surface.
587cdf0e10cSrcweir             BitmapSharedPtr pGdiBitmap;
588cdf0e10cSrcweir             BitmapProvider* pBitmap = dynamic_cast< BitmapProvider* >(xBitmap.get());
589cdf0e10cSrcweir             if( pBitmap )
590cdf0e10cSrcweir             {
591cdf0e10cSrcweir                 IBitmapSharedPtr pDXBitmap( pBitmap->getBitmap() );
592cdf0e10cSrcweir                 if( pDXBitmap )
593cdf0e10cSrcweir                     pGdiBitmap = pDXBitmap->getBitmap();
594cdf0e10cSrcweir             }
595cdf0e10cSrcweir 
596cdf0e10cSrcweir 			GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
597cdf0e10cSrcweir 			setupGraphicsState( pGraphics, viewState, renderState );
598cdf0e10cSrcweir 
599cdf0e10cSrcweir             if( pGdiBitmap )
600cdf0e10cSrcweir                 tools::drawGdiPlusBitmap(pGraphics,pGdiBitmap);
601cdf0e10cSrcweir             else
602cdf0e10cSrcweir                 tools::drawVCLBitmapFromXBitmap(pGraphics,
603cdf0e10cSrcweir                                                 xBitmap);
604cdf0e10cSrcweir         }
605cdf0e10cSrcweir 
606cdf0e10cSrcweir         // TODO(P1): Provide caching here.
607cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
608cdf0e10cSrcweir     }
609cdf0e10cSrcweir 
drawBitmapModulated(const rendering::XCanvas * pCanvas,const uno::Reference<rendering::XBitmap> & xBitmap,const rendering::ViewState & viewState,const rendering::RenderState & renderState)610cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* 						pCanvas,
611cdf0e10cSrcweir                                                                                      const uno::Reference< rendering::XBitmap >& 	xBitmap,
612cdf0e10cSrcweir                                                                                      const rendering::ViewState& 					viewState,
613cdf0e10cSrcweir                                                                                      const rendering::RenderState& 					renderState )
614cdf0e10cSrcweir     {
615cdf0e10cSrcweir         ENSURE_OR_THROW( xBitmap.is(),
616cdf0e10cSrcweir                           "CanvasHelper::drawBitmap: bitmap is NULL");
617cdf0e10cSrcweir 
618cdf0e10cSrcweir         // no color set -> this is equivalent to a plain drawBitmap(), then
619cdf0e10cSrcweir         if( renderState.DeviceColor.getLength() < 3 )
620cdf0e10cSrcweir             return drawBitmap( pCanvas, xBitmap, viewState, renderState );
621cdf0e10cSrcweir 
622cdf0e10cSrcweir         if( needOutput() )
623cdf0e10cSrcweir         {
624cdf0e10cSrcweir             GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() );
625cdf0e10cSrcweir 
626cdf0e10cSrcweir             setupGraphicsState( pGraphics, viewState, renderState );
627cdf0e10cSrcweir 
628cdf0e10cSrcweir             BitmapSharedPtr pBitmap( tools::bitmapFromXBitmap( xBitmap ) );
629cdf0e10cSrcweir             Gdiplus::Rect aRect( 0, 0,
630cdf0e10cSrcweir                                  pBitmap->GetWidth(),
631cdf0e10cSrcweir                                  pBitmap->GetHeight() );
632cdf0e10cSrcweir 
633cdf0e10cSrcweir             // Setup an ImageAttributes with an alpha-modulating
634cdf0e10cSrcweir             // color matrix.
635cdf0e10cSrcweir             const rendering::ARGBColor& rARGBColor(
636cdf0e10cSrcweir                 mpDevice->getDeviceColorSpace()->convertToARGB(renderState.DeviceColor)[0]);
637cdf0e10cSrcweir 
638cdf0e10cSrcweir             Gdiplus::ImageAttributes aImgAttr;
639cdf0e10cSrcweir             tools::setModulateImageAttributes( aImgAttr,
640cdf0e10cSrcweir                                                rARGBColor.Red,
641cdf0e10cSrcweir                                                rARGBColor.Green,
642cdf0e10cSrcweir                                                rARGBColor.Blue,
643cdf0e10cSrcweir                                                rARGBColor.Alpha );
644cdf0e10cSrcweir 
645cdf0e10cSrcweir             ENSURE_OR_THROW(
646cdf0e10cSrcweir                 Gdiplus::Ok == pGraphics->DrawImage( pBitmap.get(),
647cdf0e10cSrcweir                                                      aRect,
648cdf0e10cSrcweir                                                      0, 0,
649cdf0e10cSrcweir                                                      pBitmap->GetWidth(),
650cdf0e10cSrcweir                                                      pBitmap->GetHeight(),
651cdf0e10cSrcweir                                                      Gdiplus::UnitPixel,
652cdf0e10cSrcweir                                                      &aImgAttr,
653cdf0e10cSrcweir                                                      NULL,
654cdf0e10cSrcweir                                                      NULL ),
655cdf0e10cSrcweir                 "CanvasHelper::drawBitmapModulated(): GDI+ call failed" );
656cdf0e10cSrcweir         }
657cdf0e10cSrcweir 
658cdf0e10cSrcweir         // TODO(P1): Provide caching here.
659cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
660cdf0e10cSrcweir     }
661cdf0e10cSrcweir 
getDevice()662cdf0e10cSrcweir     uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice()
663cdf0e10cSrcweir     {
664cdf0e10cSrcweir         return uno::Reference< rendering::XGraphicDevice >(mpDevice);
665cdf0e10cSrcweir     }
666cdf0e10cSrcweir 
667cdf0e10cSrcweir     // private helper
668cdf0e10cSrcweir     // --------------------------------------------------
669cdf0e10cSrcweir 
calcCompositingMode(sal_Int8 nMode)670cdf0e10cSrcweir     Gdiplus::CompositingMode CanvasHelper::calcCompositingMode( sal_Int8 nMode )
671cdf0e10cSrcweir     {
672cdf0e10cSrcweir         Gdiplus::CompositingMode aRet( Gdiplus::CompositingModeSourceOver );
673cdf0e10cSrcweir 
674cdf0e10cSrcweir         switch( nMode )
675cdf0e10cSrcweir         {
676cdf0e10cSrcweir             case rendering::CompositeOperation::OVER:
677cdf0e10cSrcweir                 // FALLTHROUGH intended
678cdf0e10cSrcweir             case rendering::CompositeOperation::CLEAR:
679cdf0e10cSrcweir                 aRet = Gdiplus::CompositingModeSourceOver;
680cdf0e10cSrcweir                 break;
681cdf0e10cSrcweir 
682cdf0e10cSrcweir             case rendering::CompositeOperation::SOURCE:
683cdf0e10cSrcweir                 aRet = Gdiplus::CompositingModeSourceCopy;
684cdf0e10cSrcweir                 break;
685cdf0e10cSrcweir 
686cdf0e10cSrcweir             case rendering::CompositeOperation::DESTINATION:
687cdf0e10cSrcweir                 // FALLTHROUGH intended
688cdf0e10cSrcweir             case rendering::CompositeOperation::UNDER:
689cdf0e10cSrcweir                 // FALLTHROUGH intended
690cdf0e10cSrcweir             case rendering::CompositeOperation::INSIDE:
691cdf0e10cSrcweir                 // FALLTHROUGH intended
692cdf0e10cSrcweir             case rendering::CompositeOperation::INSIDE_REVERSE:
693cdf0e10cSrcweir                 // FALLTHROUGH intended
694cdf0e10cSrcweir             case rendering::CompositeOperation::OUTSIDE:
695cdf0e10cSrcweir                 // FALLTHROUGH intended
696cdf0e10cSrcweir             case rendering::CompositeOperation::OUTSIDE_REVERSE:
697cdf0e10cSrcweir                 // FALLTHROUGH intended
698cdf0e10cSrcweir             case rendering::CompositeOperation::ATOP:
699cdf0e10cSrcweir                 // FALLTHROUGH intended
700cdf0e10cSrcweir             case rendering::CompositeOperation::ATOP_REVERSE:
701cdf0e10cSrcweir                 // FALLTHROUGH intended
702cdf0e10cSrcweir             case rendering::CompositeOperation::XOR:
703cdf0e10cSrcweir                 // FALLTHROUGH intended
704cdf0e10cSrcweir             case rendering::CompositeOperation::ADD:
705cdf0e10cSrcweir                 // FALLTHROUGH intended
706cdf0e10cSrcweir             case rendering::CompositeOperation::SATURATE:
707cdf0e10cSrcweir                 // TODO(F2): Problem, because GDI+ only knows about two compositing modes
708cdf0e10cSrcweir                 aRet = Gdiplus::CompositingModeSourceOver;
709cdf0e10cSrcweir                 break;
710cdf0e10cSrcweir 
711cdf0e10cSrcweir             default:
712cdf0e10cSrcweir                 ENSURE_OR_THROW( false, "CanvasHelper::calcCompositingMode: unexpected mode" );
713cdf0e10cSrcweir                 break;
714cdf0e10cSrcweir         }
715cdf0e10cSrcweir 
716cdf0e10cSrcweir         return aRet;
717cdf0e10cSrcweir     }
718cdf0e10cSrcweir 
setupGraphicsState(GraphicsSharedPtr & rGraphics,const rendering::ViewState & viewState,const rendering::RenderState & renderState)719cdf0e10cSrcweir     void CanvasHelper::setupGraphicsState( GraphicsSharedPtr&            rGraphics,
720cdf0e10cSrcweir                                            const rendering::ViewState& 	 viewState,
721cdf0e10cSrcweir                                            const rendering::RenderState& renderState )
722cdf0e10cSrcweir     {
723cdf0e10cSrcweir         ENSURE_OR_THROW( needOutput(),
724cdf0e10cSrcweir                           "CanvasHelper::setupGraphicsState: primary graphics invalid" );
725cdf0e10cSrcweir         ENSURE_OR_THROW( mpDevice,
726cdf0e10cSrcweir                           "CanvasHelper::setupGraphicsState: reference device invalid" );
727cdf0e10cSrcweir 
728cdf0e10cSrcweir         // setup view transform first. Clipping e.g. depends on it
729cdf0e10cSrcweir         ::basegfx::B2DHomMatrix aTransform;
730cdf0e10cSrcweir         ::canvas::tools::getViewStateTransform(aTransform, viewState);
731cdf0e10cSrcweir 
732cdf0e10cSrcweir         // add output offset
733cdf0e10cSrcweir         if( !maOutputOffset.equalZero() )
734cdf0e10cSrcweir         {
735cdf0e10cSrcweir             const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix(
736cdf0e10cSrcweir                 maOutputOffset.getX(), maOutputOffset.getY()));
737cdf0e10cSrcweir             aTransform = aOutputOffset * aTransform;
738cdf0e10cSrcweir         }
739cdf0e10cSrcweir 
740cdf0e10cSrcweir         Gdiplus::Matrix aMatrix;
741cdf0e10cSrcweir         tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform );
742cdf0e10cSrcweir 
743cdf0e10cSrcweir 		ENSURE_OR_THROW(
744cdf0e10cSrcweir             Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ),
745cdf0e10cSrcweir             "CanvasHelper::setupGraphicsState(): Failed to set GDI+ transformation" );
746cdf0e10cSrcweir 
747cdf0e10cSrcweir         // setup view and render state clipping
748cdf0e10cSrcweir         ENSURE_OR_THROW(
749cdf0e10cSrcweir             Gdiplus::Ok == rGraphics->ResetClip(),
750cdf0e10cSrcweir             "CanvasHelper::setupGraphicsState(): Failed to reset GDI+ clip" );
751cdf0e10cSrcweir 
752cdf0e10cSrcweir         if( viewState.Clip.is() )
753cdf0e10cSrcweir         {
754cdf0e10cSrcweir             GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( viewState.Clip ) );
755cdf0e10cSrcweir 
756cdf0e10cSrcweir             // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+.
757cdf0e10cSrcweir             // Try SetClip( Rect ) or similar for simple clip paths (need some support in
758cdf0e10cSrcweir             // LinePolyPolygon, then)
759cdf0e10cSrcweir             ENSURE_OR_THROW(
760cdf0e10cSrcweir                 Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(),
761cdf0e10cSrcweir                                                    Gdiplus::CombineModeIntersect ),
762cdf0e10cSrcweir                 "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" );
763cdf0e10cSrcweir         }
764cdf0e10cSrcweir 
765cdf0e10cSrcweir         // setup overall transform only now. View clip above was relative to
766cdf0e10cSrcweir         // view transform
767cdf0e10cSrcweir         ::canvas::tools::mergeViewAndRenderTransform(aTransform,
768cdf0e10cSrcweir                                                      viewState,
769cdf0e10cSrcweir                                                      renderState);
770cdf0e10cSrcweir 
771cdf0e10cSrcweir         // add output offset
772cdf0e10cSrcweir         if( !maOutputOffset.equalZero() )
773cdf0e10cSrcweir         {
774cdf0e10cSrcweir             const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix(
775cdf0e10cSrcweir                 maOutputOffset.getX(), maOutputOffset.getY()));
776cdf0e10cSrcweir             aTransform = aOutputOffset * aTransform;
777cdf0e10cSrcweir         }
778cdf0e10cSrcweir 
779cdf0e10cSrcweir         tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform );
780cdf0e10cSrcweir 
781cdf0e10cSrcweir         ENSURE_OR_THROW(
782cdf0e10cSrcweir             Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ),
783cdf0e10cSrcweir             "CanvasHelper::setupGraphicsState(): Cannot set GDI+ transformation" );
784cdf0e10cSrcweir 
785cdf0e10cSrcweir         if( renderState.Clip.is() )
786cdf0e10cSrcweir         {
787cdf0e10cSrcweir             GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( renderState.Clip ) );
788cdf0e10cSrcweir 
789cdf0e10cSrcweir             // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+.
790cdf0e10cSrcweir             // Try SetClip( Rect ) or similar for simple clip paths (need some support in
791cdf0e10cSrcweir             // LinePolyPolygon, then)
792cdf0e10cSrcweir             ENSURE_OR_THROW(
793cdf0e10cSrcweir                 Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(),
794cdf0e10cSrcweir                                                    Gdiplus::CombineModeIntersect ),
795cdf0e10cSrcweir                 "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" );
796cdf0e10cSrcweir         }
797cdf0e10cSrcweir 
798cdf0e10cSrcweir         // setup compositing
799cdf0e10cSrcweir         const Gdiplus::CompositingMode eCompositing( calcCompositingMode( renderState.CompositeOperation ) );
800cdf0e10cSrcweir         ENSURE_OR_THROW(
801cdf0e10cSrcweir             Gdiplus::Ok == rGraphics->SetCompositingMode( eCompositing ),
802cdf0e10cSrcweir             "CanvasHelper::setupGraphicsState(): Cannot set GDI* compositing mode)" );
803cdf0e10cSrcweir     }
804cdf0e10cSrcweir 
flush() const805cdf0e10cSrcweir     void CanvasHelper::flush() const
806cdf0e10cSrcweir     {
807cdf0e10cSrcweir         if( needOutput() )
808cdf0e10cSrcweir             mpGraphicsProvider->getGraphics()->Flush( Gdiplus::FlushIntentionSync );
809cdf0e10cSrcweir     }
810cdf0e10cSrcweir }
811