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 <canvas/canvastools.hxx>
29cdf0e10cSrcweir #include <tools/diagnose_ex.h>
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include <vcl/virdev.hxx>
32cdf0e10cSrcweir #include <vcl/metric.hxx>
33cdf0e10cSrcweir #include <vcl/canvastools.hxx>
34cdf0e10cSrcweir 
35cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx>
36cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
37cdf0e10cSrcweir 
38cdf0e10cSrcweir #include "cairo_canvasfont.hxx"
39cdf0e10cSrcweir #include "cairo_textlayout.hxx"
40cdf0e10cSrcweir #include "cairo_canvashelper.hxx"
41cdf0e10cSrcweir 
42cdf0e10cSrcweir using namespace ::cairo;
43cdf0e10cSrcweir using namespace ::com::sun::star;
44cdf0e10cSrcweir 
45cdf0e10cSrcweir namespace cairocanvas
46cdf0e10cSrcweir {
47cdf0e10cSrcweir 	enum ColorType
48cdf0e10cSrcweir 	{
49cdf0e10cSrcweir 		LINE_COLOR, FILL_COLOR, TEXT_COLOR, IGNORE_COLOR
50cdf0e10cSrcweir 	};
51cdf0e10cSrcweir 
createFont(const rendering::XCanvas *,const rendering::FontRequest & fontRequest,const uno::Sequence<beans::PropertyValue> & extraFontProperties,const geometry::Matrix2D & fontMatrix)52cdf0e10cSrcweir     uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* 					,
53cdf0e10cSrcweir                                                                        const rendering::FontRequest& 				fontRequest,
54cdf0e10cSrcweir                                                                        const uno::Sequence< beans::PropertyValue >& extraFontProperties,
55cdf0e10cSrcweir                                                                        const geometry::Matrix2D& 					fontMatrix )
56cdf0e10cSrcweir     {
57cdf0e10cSrcweir         return uno::Reference< rendering::XCanvasFont >( new CanvasFont( fontRequest, extraFontProperties, fontMatrix, mpSurfaceProvider ));
58cdf0e10cSrcweir     }
59cdf0e10cSrcweir 
queryAvailableFonts(const rendering::XCanvas *,const rendering::FontInfo &,const uno::Sequence<beans::PropertyValue> &)60cdf0e10cSrcweir     uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* 						,
61cdf0e10cSrcweir                                                                             const rendering::FontInfo& 						/*aFilter*/,
62cdf0e10cSrcweir                                                                             const uno::Sequence< beans::PropertyValue >& 	/*aFontProperties*/ )
63cdf0e10cSrcweir     {
64cdf0e10cSrcweir         // TODO
65cdf0e10cSrcweir         return uno::Sequence< rendering::FontInfo >();
66cdf0e10cSrcweir     }
67cdf0e10cSrcweir 
68cdf0e10cSrcweir 	static bool
setupFontTransform(::OutputDevice & rOutDev,::Point & o_rPoint,::Font & io_rVCLFont,const rendering::ViewState & rViewState,const rendering::RenderState & rRenderState)69cdf0e10cSrcweir 	setupFontTransform( ::OutputDevice&				    rOutDev,
70cdf0e10cSrcweir 						::Point&						o_rPoint,
71cdf0e10cSrcweir 						::Font& 						io_rVCLFont,
72cdf0e10cSrcweir 						const rendering::ViewState& 	rViewState,
73cdf0e10cSrcweir 						const rendering::RenderState& 	rRenderState )
74cdf0e10cSrcweir 	{
75cdf0e10cSrcweir 		::basegfx::B2DHomMatrix aMatrix;
76cdf0e10cSrcweir 
77cdf0e10cSrcweir 		::canvas::tools::mergeViewAndRenderTransform(aMatrix,
78cdf0e10cSrcweir 													 rViewState,
79cdf0e10cSrcweir 													 rRenderState);
80cdf0e10cSrcweir 
81cdf0e10cSrcweir 		::basegfx::B2DTuple aScale;
82cdf0e10cSrcweir 		::basegfx::B2DTuple aTranslate;
83cdf0e10cSrcweir 		double nRotate, nShearX;
84cdf0e10cSrcweir 
85cdf0e10cSrcweir 		aMatrix.decompose( aScale, aTranslate, nRotate, nShearX );
86cdf0e10cSrcweir 
87cdf0e10cSrcweir 		// query font metric _before_ tampering with width and height
88cdf0e10cSrcweir 		if( !::rtl::math::approxEqual(aScale.getX(), aScale.getY()) )
89cdf0e10cSrcweir         {
90cdf0e10cSrcweir 			// retrieve true font width
91cdf0e10cSrcweir 			const sal_Int32 nFontWidth( rOutDev.GetFontMetric( io_rVCLFont ).GetWidth() );
92cdf0e10cSrcweir 
93cdf0e10cSrcweir 			const sal_Int32 nScaledFontWidth( ::basegfx::fround(nFontWidth * aScale.getX()) );
94cdf0e10cSrcweir 
95cdf0e10cSrcweir 			if( !nScaledFontWidth )
96cdf0e10cSrcweir 			{
97cdf0e10cSrcweir 				// scale is smaller than one pixel - disable text
98cdf0e10cSrcweir 				// output altogether
99cdf0e10cSrcweir 				return false;
100cdf0e10cSrcweir 			}
101cdf0e10cSrcweir 
102cdf0e10cSrcweir 			io_rVCLFont.SetWidth( nScaledFontWidth );
103cdf0e10cSrcweir 		}
104cdf0e10cSrcweir 
105cdf0e10cSrcweir 		if( !::rtl::math::approxEqual(aScale.getY(), 1.0) )
106cdf0e10cSrcweir         {
107cdf0e10cSrcweir 			const sal_Int32 nFontHeight( io_rVCLFont.GetHeight() );
108cdf0e10cSrcweir 			io_rVCLFont.SetHeight( ::basegfx::fround(nFontHeight * aScale.getY()) );
109cdf0e10cSrcweir 		}
110cdf0e10cSrcweir 
111cdf0e10cSrcweir 		io_rVCLFont.SetOrientation( static_cast< short >( ::basegfx::fround(-fmod(nRotate, 2*M_PI)*(1800.0/M_PI)) ) );
112cdf0e10cSrcweir 
113cdf0e10cSrcweir 		// TODO(F2): Missing functionality in VCL: shearing
114cdf0e10cSrcweir 		o_rPoint.X() = ::basegfx::fround(aTranslate.getX());
115cdf0e10cSrcweir 		o_rPoint.Y() = ::basegfx::fround(aTranslate.getY());
116cdf0e10cSrcweir 
117cdf0e10cSrcweir 		return true;
118cdf0e10cSrcweir 	}
119cdf0e10cSrcweir 
120cdf0e10cSrcweir     static int
setupOutDevState(OutputDevice & rOutDev,const rendering::XCanvas * pOwner,const rendering::ViewState & viewState,const rendering::RenderState & renderState,ColorType eColorType)121cdf0e10cSrcweir 	setupOutDevState( OutputDevice&                 rOutDev,
122cdf0e10cSrcweir                       const rendering::XCanvas*     pOwner,
123cdf0e10cSrcweir                       const rendering::ViewState& 	viewState,
124cdf0e10cSrcweir                       const rendering::RenderState& renderState,
125cdf0e10cSrcweir                       ColorType						eColorType )
126cdf0e10cSrcweir     {
127cdf0e10cSrcweir         ::canvas::tools::verifyInput( renderState,
128cdf0e10cSrcweir                                       BOOST_CURRENT_FUNCTION,
129cdf0e10cSrcweir                                       const_cast<rendering::XCanvas*>(pOwner), // only for refcount
130cdf0e10cSrcweir                                       2,
131cdf0e10cSrcweir                                       eColorType == IGNORE_COLOR ? 0 : 3 );
132cdf0e10cSrcweir 
133cdf0e10cSrcweir         int nTransparency(0);
134cdf0e10cSrcweir 
135cdf0e10cSrcweir         // TODO(P2): Don't change clipping all the time, maintain current clip
136cdf0e10cSrcweir         // state and change only when update is necessary
137cdf0e10cSrcweir 
138cdf0e10cSrcweir         // accumulate non-empty clips into one region
139cdf0e10cSrcweir         // ==========================================
140cdf0e10cSrcweir 
141cdf0e10cSrcweir         Region aClipRegion;
142cdf0e10cSrcweir 
143cdf0e10cSrcweir         if( viewState.Clip.is() )
144cdf0e10cSrcweir         {
145cdf0e10cSrcweir             ::basegfx::B2DPolyPolygon aClipPoly(
146cdf0e10cSrcweir                 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
147cdf0e10cSrcweir                     viewState.Clip) );
148cdf0e10cSrcweir 
149cdf0e10cSrcweir             if( aClipPoly.count() )
150cdf0e10cSrcweir             {
151cdf0e10cSrcweir                 // setup non-empty clipping
152cdf0e10cSrcweir                 ::basegfx::B2DHomMatrix aMatrix;
153cdf0e10cSrcweir                 aClipPoly.transform(
154cdf0e10cSrcweir                     ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix,
155cdf0e10cSrcweir                                                                     viewState.AffineTransform ) );
156cdf0e10cSrcweir 
157cdf0e10cSrcweir                 aClipRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) );
158cdf0e10cSrcweir             }
159cdf0e10cSrcweir         }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir         if( renderState.Clip.is() )
162cdf0e10cSrcweir         {
163cdf0e10cSrcweir             ::basegfx::B2DPolyPolygon aClipPoly(
164cdf0e10cSrcweir                 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
165cdf0e10cSrcweir                     renderState.Clip) );
166cdf0e10cSrcweir 
167cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix;
168cdf0e10cSrcweir             aClipPoly.transform(
169cdf0e10cSrcweir                 ::canvas::tools::mergeViewAndRenderTransform( aMatrix,
170cdf0e10cSrcweir                                                               viewState,
171cdf0e10cSrcweir                                                               renderState ) );
172cdf0e10cSrcweir 
173cdf0e10cSrcweir             if( aClipPoly.count() )
174cdf0e10cSrcweir             {
175cdf0e10cSrcweir                 // setup non-empty clipping
176cdf0e10cSrcweir                 Region aRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) );
177cdf0e10cSrcweir 
178cdf0e10cSrcweir                 if( aClipRegion.IsEmpty() )
179cdf0e10cSrcweir                     aClipRegion = aRegion;
180cdf0e10cSrcweir                 else
181cdf0e10cSrcweir                     aClipRegion.Intersect( aRegion );
182cdf0e10cSrcweir             }
183cdf0e10cSrcweir             else
184cdf0e10cSrcweir             {
185cdf0e10cSrcweir                 // clip polygon is empty
186cdf0e10cSrcweir                 aClipRegion.SetEmpty();
187cdf0e10cSrcweir             }
188cdf0e10cSrcweir         }
189cdf0e10cSrcweir 
190cdf0e10cSrcweir         // setup accumulated clip region. Note that setting an
191cdf0e10cSrcweir         // empty clip region denotes "clip everything" on the
192cdf0e10cSrcweir         // OutputDevice (which is why we translate that into
193cdf0e10cSrcweir         // SetClipRegion() here). When both view and render clip
194cdf0e10cSrcweir         // are empty, aClipRegion remains default-constructed,
195cdf0e10cSrcweir         // i.e. empty, too.
196cdf0e10cSrcweir         if( aClipRegion.IsEmpty() )
197cdf0e10cSrcweir         {
198cdf0e10cSrcweir             rOutDev.SetClipRegion();
199cdf0e10cSrcweir         }
200cdf0e10cSrcweir         else
201cdf0e10cSrcweir         {
202cdf0e10cSrcweir             rOutDev.SetClipRegion( aClipRegion );
203cdf0e10cSrcweir         }
204cdf0e10cSrcweir 
205cdf0e10cSrcweir         if( eColorType != IGNORE_COLOR )
206cdf0e10cSrcweir         {
207cdf0e10cSrcweir             Color aColor( COL_WHITE );
208cdf0e10cSrcweir 
209cdf0e10cSrcweir             if( renderState.DeviceColor.getLength() > 2 )
210cdf0e10cSrcweir             {
211cdf0e10cSrcweir                 aColor = ::vcl::unotools::stdColorSpaceSequenceToColor( renderState.DeviceColor );
212cdf0e10cSrcweir             }
213cdf0e10cSrcweir 
214cdf0e10cSrcweir             // extract alpha, and make color opaque
215cdf0e10cSrcweir             // afterwards. Otherwise, OutputDevice won't draw anything
216cdf0e10cSrcweir             nTransparency = aColor.GetTransparency();
217cdf0e10cSrcweir             aColor.SetTransparency(0);
218cdf0e10cSrcweir 
219cdf0e10cSrcweir             switch( eColorType )
220cdf0e10cSrcweir             {
221cdf0e10cSrcweir                 case LINE_COLOR:
222cdf0e10cSrcweir                     rOutDev.SetLineColor( aColor );
223cdf0e10cSrcweir                     rOutDev.SetFillColor();
224cdf0e10cSrcweir 
225cdf0e10cSrcweir                     break;
226cdf0e10cSrcweir 
227cdf0e10cSrcweir                 case FILL_COLOR:
228cdf0e10cSrcweir                     rOutDev.SetFillColor( aColor );
229cdf0e10cSrcweir                     rOutDev.SetLineColor();
230cdf0e10cSrcweir 
231cdf0e10cSrcweir                     break;
232cdf0e10cSrcweir 
233cdf0e10cSrcweir                 case TEXT_COLOR:
234cdf0e10cSrcweir                     rOutDev.SetTextColor( aColor );
235cdf0e10cSrcweir 
236cdf0e10cSrcweir                     break;
237cdf0e10cSrcweir 
238cdf0e10cSrcweir                 default:
239cdf0e10cSrcweir                     ENSURE_OR_THROW( false,
240cdf0e10cSrcweir                                       "CanvasHelper::setupOutDevState(): Unexpected color type");
241cdf0e10cSrcweir                     break;
242cdf0e10cSrcweir             }
243cdf0e10cSrcweir         }
244cdf0e10cSrcweir 
245cdf0e10cSrcweir         return nTransparency;
246cdf0e10cSrcweir     }
247cdf0e10cSrcweir 
setupTextOutput(OutputDevice & rOutDev,const rendering::XCanvas * pOwner,::Point & o_rOutPos,const rendering::ViewState & viewState,const rendering::RenderState & renderState,const uno::Reference<rendering::XCanvasFont> & xFont)248cdf0e10cSrcweir     bool setupTextOutput( OutputDevice&                                     rOutDev,
249cdf0e10cSrcweir                           const rendering::XCanvas*                         pOwner,
250cdf0e10cSrcweir 						  ::Point&										    o_rOutPos,
251cdf0e10cSrcweir 						  const rendering::ViewState& 					    viewState,
252cdf0e10cSrcweir 						  const rendering::RenderState& 					renderState,
253cdf0e10cSrcweir 						  const uno::Reference< rendering::XCanvasFont >&	xFont	)
254cdf0e10cSrcweir     {
255cdf0e10cSrcweir         setupOutDevState( rOutDev, pOwner, viewState, renderState, TEXT_COLOR );
256cdf0e10cSrcweir 
257cdf0e10cSrcweir         ::Font aVCLFont;
258cdf0e10cSrcweir 
259cdf0e10cSrcweir         CanvasFont* pFont = dynamic_cast< CanvasFont* >( xFont.get() );
260cdf0e10cSrcweir 
261cdf0e10cSrcweir         ENSURE_ARG_OR_THROW( pFont,
262cdf0e10cSrcweir                          "CanvasHelper::setupTextOutput(): Font not compatible with this canvas" );
263cdf0e10cSrcweir 
264cdf0e10cSrcweir         aVCLFont = pFont->getVCLFont();
265cdf0e10cSrcweir 
266cdf0e10cSrcweir         Color aColor( COL_BLACK );
267cdf0e10cSrcweir 
268cdf0e10cSrcweir         if( renderState.DeviceColor.getLength() > 2 )
269cdf0e10cSrcweir         {
270cdf0e10cSrcweir             aColor = ::vcl::unotools::stdColorSpaceSequenceToColor(renderState.DeviceColor );
271cdf0e10cSrcweir         }
272cdf0e10cSrcweir 
273cdf0e10cSrcweir         // setup font color
274cdf0e10cSrcweir         aVCLFont.SetColor( aColor );
275cdf0e10cSrcweir         aVCLFont.SetFillColor( aColor );
276cdf0e10cSrcweir 
277cdf0e10cSrcweir         // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here.
278cdf0e10cSrcweir         if( !setupFontTransform( rOutDev, o_rOutPos, aVCLFont, viewState, renderState ) )
279cdf0e10cSrcweir             return false;
280cdf0e10cSrcweir 
281cdf0e10cSrcweir         rOutDev.SetFont( aVCLFont );
282cdf0e10cSrcweir 
283cdf0e10cSrcweir 
284cdf0e10cSrcweir         return true;
285cdf0e10cSrcweir     }
286cdf0e10cSrcweir 
drawText(const rendering::XCanvas * pOwner,const rendering::StringContext & text,const uno::Reference<rendering::XCanvasFont> & xFont,const rendering::ViewState & viewState,const rendering::RenderState & renderState,sal_Int8 textDirection)287cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* 						pOwner,
288cdf0e10cSrcweir                                                                           const rendering::StringContext& 					text,
289cdf0e10cSrcweir                                                                           const uno::Reference< rendering::XCanvasFont >& 	xFont,
290cdf0e10cSrcweir                                                                           const rendering::ViewState& 						viewState,
291cdf0e10cSrcweir                                                                           const rendering::RenderState& 					renderState,
292cdf0e10cSrcweir                                                                           sal_Int8				 							textDirection )
293cdf0e10cSrcweir     {
294cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
295cdf0e10cSrcweir 		struct timespec aTimer;
296cdf0e10cSrcweir 		mxDevice->startPerfTrace( &aTimer );
297cdf0e10cSrcweir #endif
298cdf0e10cSrcweir 
299cdf0e10cSrcweir         ENSURE_ARG_OR_THROW( xFont.is(),
300cdf0e10cSrcweir                          "CanvasHelper::drawText(): font is NULL");
301cdf0e10cSrcweir 
302cdf0e10cSrcweir 		if( !mpVirtualDevice )
303cdf0e10cSrcweir 			mpVirtualDevice = mpSurface->createVirtualDevice();
304cdf0e10cSrcweir 
305cdf0e10cSrcweir         if( mpVirtualDevice )
306cdf0e10cSrcweir 		{
307cdf0e10cSrcweir #if defined CAIRO_HAS_WIN32_SURFACE
308cdf0e10cSrcweir             // FIXME: Some kind of work-araound...
309cdf0e10cSrcweir             cairo_rectangle (mpSurface->getCairo().get(), 0, 0, 0, 0);
310cdf0e10cSrcweir             cairo_fill(mpSurface->getCairo().get());
311cdf0e10cSrcweir #endif
312cdf0e10cSrcweir             ::Point aOutpos;
313cdf0e10cSrcweir 			if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xFont ) )
314cdf0e10cSrcweir 				return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary
315cdf0e10cSrcweir 
316cdf0e10cSrcweir 				// change text direction and layout mode
317cdf0e10cSrcweir 			sal_uLong nLayoutMode(0);
318cdf0e10cSrcweir 			switch( textDirection )
319cdf0e10cSrcweir 				{
320cdf0e10cSrcweir 				case rendering::TextDirection::WEAK_LEFT_TO_RIGHT:
321cdf0e10cSrcweir 					nLayoutMode |= TEXT_LAYOUT_BIDI_LTR;
322cdf0e10cSrcweir 					// FALLTHROUGH intended
323cdf0e10cSrcweir 				case rendering::TextDirection::STRONG_LEFT_TO_RIGHT:
324cdf0e10cSrcweir 					nLayoutMode |= TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG;
325cdf0e10cSrcweir 					nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_LEFT;
326cdf0e10cSrcweir 					break;
327cdf0e10cSrcweir 
328cdf0e10cSrcweir 				case rendering::TextDirection::WEAK_RIGHT_TO_LEFT:
329cdf0e10cSrcweir 					nLayoutMode |= TEXT_LAYOUT_BIDI_RTL;
330cdf0e10cSrcweir 					// FALLTHROUGH intended
331cdf0e10cSrcweir 				case rendering::TextDirection::STRONG_RIGHT_TO_LEFT:
332cdf0e10cSrcweir 					nLayoutMode |= TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG;
333cdf0e10cSrcweir 					nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_RIGHT;
334cdf0e10cSrcweir 					break;
335cdf0e10cSrcweir 				}
336cdf0e10cSrcweir 
337cdf0e10cSrcweir 			// TODO(F2): alpha
338cdf0e10cSrcweir 			mpVirtualDevice->SetLayoutMode( nLayoutMode );
339cdf0e10cSrcweir 
340cdf0e10cSrcweir             OSL_TRACE(":cairocanvas::CanvasHelper::drawText(O,t,f,v,r,d): %s", ::rtl::OUStringToOString( text.Text.copy( text.StartPosition, text.Length ),
341cdf0e10cSrcweir                                                                                                          RTL_TEXTENCODING_UTF8 ).getStr());
342cdf0e10cSrcweir 
343cdf0e10cSrcweir             TextLayout* pTextLayout = new TextLayout(text, textDirection, 0, CanvasFont::Reference(dynamic_cast< CanvasFont* >( xFont.get() )), mpSurfaceProvider);
344cdf0e10cSrcweir             pTextLayout->draw( mpSurface, *mpVirtualDevice, aOutpos, viewState, renderState );
345cdf0e10cSrcweir 		}
346cdf0e10cSrcweir 
347cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
348cdf0e10cSrcweir     }
349cdf0e10cSrcweir 
drawTextLayout(const rendering::XCanvas * pOwner,const uno::Reference<rendering::XTextLayout> & xLayoutedText,const rendering::ViewState & viewState,const rendering::RenderState & renderState)350cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* 						pOwner,
351cdf0e10cSrcweir                                                                                 const uno::Reference< rendering::XTextLayout >& xLayoutedText,
352cdf0e10cSrcweir                                                                                 const rendering::ViewState& 					viewState,
353cdf0e10cSrcweir                                                                                 const rendering::RenderState& 					renderState )
354cdf0e10cSrcweir     {
355cdf0e10cSrcweir         ENSURE_ARG_OR_THROW( xLayoutedText.is(),
356cdf0e10cSrcweir                          "CanvasHelper::drawTextLayout(): layout is NULL");
357cdf0e10cSrcweir 
358cdf0e10cSrcweir         TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() );
359cdf0e10cSrcweir 
360cdf0e10cSrcweir         if( pTextLayout )
361cdf0e10cSrcweir         {
362cdf0e10cSrcweir 			if( !mpVirtualDevice )
363cdf0e10cSrcweir 				mpVirtualDevice = mpSurface->createVirtualDevice();
364cdf0e10cSrcweir 
365cdf0e10cSrcweir             if( mpVirtualDevice )
366cdf0e10cSrcweir             {
367cdf0e10cSrcweir #if defined CAIRO_HAS_WIN32_SURFACE
368cdf0e10cSrcweir                 // FIXME: Some kind of work-araound...
369cdf0e10cSrcweir                 cairo_rectangle( mpSurface->getCairo().get(), 0, 0, 0, 0);
370cdf0e10cSrcweir                 cairo_fill(mpSurface->getCairo().get());
371cdf0e10cSrcweir #endif
372cdf0e10cSrcweir                 // TODO(T3): Race condition. We're taking the font
373cdf0e10cSrcweir                 // from xLayoutedText, and then calling draw() at it,
374cdf0e10cSrcweir                 // without exclusive access. Move setupTextOutput(),
375cdf0e10cSrcweir                 // e.g. to impltools?
376cdf0e10cSrcweir 
377cdf0e10cSrcweir                 ::Point aOutpos;
378cdf0e10cSrcweir                 if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xLayoutedText->getFont() ) )
379cdf0e10cSrcweir                     return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary
380cdf0e10cSrcweir 
381cdf0e10cSrcweir                 // TODO(F2): What about the offset scalings?
382cdf0e10cSrcweir                 pTextLayout->draw( mpSurface, *mpVirtualDevice, aOutpos, viewState, renderState );
383cdf0e10cSrcweir             }
384cdf0e10cSrcweir         }
385cdf0e10cSrcweir         else
386cdf0e10cSrcweir         {
387cdf0e10cSrcweir             ENSURE_ARG_OR_THROW( false,
388cdf0e10cSrcweir                              "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" );
389cdf0e10cSrcweir         }
390cdf0e10cSrcweir 
391cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
392cdf0e10cSrcweir     }
393cdf0e10cSrcweir 
394cdf0e10cSrcweir }
395