1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25*b1cdbd2cSJim Jagielski #include "precompiled_canvas.hxx"
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski #include <math.h>
28*b1cdbd2cSJim Jagielski 
29*b1cdbd2cSJim Jagielski #include <canvas/debug.hxx>
30*b1cdbd2cSJim Jagielski #include <canvas/verbosetrace.hxx>
31*b1cdbd2cSJim Jagielski #include <tools/diagnose_ex.h>
32*b1cdbd2cSJim Jagielski 
33*b1cdbd2cSJim Jagielski #include <vcl/metric.hxx>
34*b1cdbd2cSJim Jagielski #include <vcl/virdev.hxx>
35*b1cdbd2cSJim Jagielski 
36*b1cdbd2cSJim Jagielski #ifdef WNT
37*b1cdbd2cSJim Jagielski #include <tools/prewin.h>
38*b1cdbd2cSJim Jagielski #include <windows.h>
39*b1cdbd2cSJim Jagielski #include <tools/postwin.h>
40*b1cdbd2cSJim Jagielski #ifdef max
41*b1cdbd2cSJim Jagielski #undef max
42*b1cdbd2cSJim Jagielski #endif
43*b1cdbd2cSJim Jagielski #ifdef min
44*b1cdbd2cSJim Jagielski #undef min
45*b1cdbd2cSJim Jagielski #endif
46*b1cdbd2cSJim Jagielski #endif
47*b1cdbd2cSJim Jagielski #include <vcl/sysdata.hxx>
48*b1cdbd2cSJim Jagielski 
49*b1cdbd2cSJim Jagielski #include <basegfx/matrix/b2dhommatrix.hxx>
50*b1cdbd2cSJim Jagielski #include <basegfx/numeric/ftools.hxx>
51*b1cdbd2cSJim Jagielski 
52*b1cdbd2cSJim Jagielski #include <boost/scoped_array.hpp>
53*b1cdbd2cSJim Jagielski 
54*b1cdbd2cSJim Jagielski #include "cairo_textlayout.hxx"
55*b1cdbd2cSJim Jagielski #include "cairo_spritecanvas.hxx"
56*b1cdbd2cSJim Jagielski 
57*b1cdbd2cSJim Jagielski #ifdef CAIRO_HAS_QUARTZ_SURFACE
58*b1cdbd2cSJim Jagielski # include "cairo_quartz_cairo.hxx"
59*b1cdbd2cSJim Jagielski #elif defined CAIRO_HAS_WIN32_SURFACE
60*b1cdbd2cSJim Jagielski # include "cairo_win32_cairo.hxx"
61*b1cdbd2cSJim Jagielski # include <cairo-win32.h>
62*b1cdbd2cSJim Jagielski #elif defined CAIRO_HAS_XLIB_SURFACE
63*b1cdbd2cSJim Jagielski # include "cairo_xlib_cairo.hxx"
64*b1cdbd2cSJim Jagielski # include <cairo-ft.h>
65*b1cdbd2cSJim Jagielski #else
66*b1cdbd2cSJim Jagielski # error Native API needed.
67*b1cdbd2cSJim Jagielski #endif
68*b1cdbd2cSJim Jagielski 
69*b1cdbd2cSJim Jagielski using namespace ::cairo;
70*b1cdbd2cSJim Jagielski using namespace ::com::sun::star;
71*b1cdbd2cSJim Jagielski 
72*b1cdbd2cSJim Jagielski namespace cairocanvas
73*b1cdbd2cSJim Jagielski {
74*b1cdbd2cSJim Jagielski     namespace
75*b1cdbd2cSJim Jagielski     {
setupLayoutMode(OutputDevice & rOutDev,sal_Int8 nTextDirection)76*b1cdbd2cSJim Jagielski         void setupLayoutMode( OutputDevice& rOutDev,
77*b1cdbd2cSJim Jagielski                               sal_Int8		nTextDirection )
78*b1cdbd2cSJim Jagielski         {
79*b1cdbd2cSJim Jagielski             // TODO(P3): avoid if already correctly set
80*b1cdbd2cSJim Jagielski             sal_uLong nLayoutMode;
81*b1cdbd2cSJim Jagielski             switch( nTextDirection )
82*b1cdbd2cSJim Jagielski             {
83*b1cdbd2cSJim Jagielski                 default:
84*b1cdbd2cSJim Jagielski                     nLayoutMode = 0;
85*b1cdbd2cSJim Jagielski                     break;
86*b1cdbd2cSJim Jagielski                 case rendering::TextDirection::WEAK_LEFT_TO_RIGHT:
87*b1cdbd2cSJim Jagielski                     nLayoutMode = TEXT_LAYOUT_BIDI_LTR;
88*b1cdbd2cSJim Jagielski                     break;
89*b1cdbd2cSJim Jagielski                 case rendering::TextDirection::STRONG_LEFT_TO_RIGHT:
90*b1cdbd2cSJim Jagielski                     nLayoutMode = TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG;
91*b1cdbd2cSJim Jagielski                     break;
92*b1cdbd2cSJim Jagielski                 case rendering::TextDirection::WEAK_RIGHT_TO_LEFT:
93*b1cdbd2cSJim Jagielski                     nLayoutMode = TEXT_LAYOUT_BIDI_RTL;
94*b1cdbd2cSJim Jagielski                     break;
95*b1cdbd2cSJim Jagielski                 case rendering::TextDirection::STRONG_RIGHT_TO_LEFT:
96*b1cdbd2cSJim Jagielski                     nLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG;
97*b1cdbd2cSJim Jagielski                     break;
98*b1cdbd2cSJim Jagielski             }
99*b1cdbd2cSJim Jagielski 
100*b1cdbd2cSJim Jagielski             // set calculated layout mode. Origin is always the left edge,
101*b1cdbd2cSJim Jagielski             // as required at the API spec
102*b1cdbd2cSJim Jagielski             rOutDev.SetLayoutMode( nLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
103*b1cdbd2cSJim Jagielski         }
104*b1cdbd2cSJim Jagielski 
compareFallbacks(const SystemGlyphData & rA,const SystemGlyphData & rB)105*b1cdbd2cSJim Jagielski         bool compareFallbacks(const SystemGlyphData&rA, const SystemGlyphData &rB)
106*b1cdbd2cSJim Jagielski         {
107*b1cdbd2cSJim Jagielski             return rA.fallbacklevel < rB.fallbacklevel;
108*b1cdbd2cSJim Jagielski         }
109*b1cdbd2cSJim Jagielski     }
110*b1cdbd2cSJim Jagielski 
TextLayout(const rendering::StringContext & aText,sal_Int8 nDirection,sal_Int64,const CanvasFont::Reference & rFont,const SurfaceProviderRef & rRefDevice)111*b1cdbd2cSJim Jagielski     TextLayout::TextLayout( const rendering::StringContext& 	aText,
112*b1cdbd2cSJim Jagielski                             sal_Int8                        	nDirection,
113*b1cdbd2cSJim Jagielski                             sal_Int64                       	/*nRandomSeed*/,
114*b1cdbd2cSJim Jagielski                             const CanvasFont::Reference&      	rFont,
115*b1cdbd2cSJim Jagielski 							const SurfaceProviderRef&			rRefDevice ) :
116*b1cdbd2cSJim Jagielski         TextLayout_Base( m_aMutex ),
117*b1cdbd2cSJim Jagielski         maText( aText ),
118*b1cdbd2cSJim Jagielski         maLogicalAdvancements(),
119*b1cdbd2cSJim Jagielski         mpFont( rFont ),
120*b1cdbd2cSJim Jagielski         mpRefDevice( rRefDevice ),
121*b1cdbd2cSJim Jagielski         mnTextDirection( nDirection )
122*b1cdbd2cSJim Jagielski     {
123*b1cdbd2cSJim Jagielski     }
124*b1cdbd2cSJim Jagielski 
~TextLayout()125*b1cdbd2cSJim Jagielski     TextLayout::~TextLayout()
126*b1cdbd2cSJim Jagielski     {
127*b1cdbd2cSJim Jagielski     }
128*b1cdbd2cSJim Jagielski 
disposing()129*b1cdbd2cSJim Jagielski     void SAL_CALL TextLayout::disposing()
130*b1cdbd2cSJim Jagielski     {
131*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
132*b1cdbd2cSJim Jagielski 
133*b1cdbd2cSJim Jagielski         mpFont.reset();
134*b1cdbd2cSJim Jagielski         mpRefDevice.clear();
135*b1cdbd2cSJim Jagielski     }
136*b1cdbd2cSJim Jagielski 
137*b1cdbd2cSJim Jagielski     // XTextLayout
queryTextShapes()138*b1cdbd2cSJim Jagielski     uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes(  ) throw (uno::RuntimeException)
139*b1cdbd2cSJim Jagielski     {
140*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
141*b1cdbd2cSJim Jagielski 
142*b1cdbd2cSJim Jagielski         // TODO
143*b1cdbd2cSJim Jagielski         return uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > >();
144*b1cdbd2cSJim Jagielski     }
145*b1cdbd2cSJim Jagielski 
queryInkMeasures()146*b1cdbd2cSJim Jagielski     uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures(  ) throw (uno::RuntimeException)
147*b1cdbd2cSJim Jagielski     {
148*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
149*b1cdbd2cSJim Jagielski 
150*b1cdbd2cSJim Jagielski         // TODO
151*b1cdbd2cSJim Jagielski         return uno::Sequence< geometry::RealRectangle2D >();
152*b1cdbd2cSJim Jagielski     }
153*b1cdbd2cSJim Jagielski 
queryMeasures()154*b1cdbd2cSJim Jagielski     uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures(  ) throw (uno::RuntimeException)
155*b1cdbd2cSJim Jagielski     {
156*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
157*b1cdbd2cSJim Jagielski 
158*b1cdbd2cSJim Jagielski         // TODO
159*b1cdbd2cSJim Jagielski         return uno::Sequence< geometry::RealRectangle2D >();
160*b1cdbd2cSJim Jagielski     }
161*b1cdbd2cSJim Jagielski 
queryLogicalAdvancements()162*b1cdbd2cSJim Jagielski     uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements(  ) throw (uno::RuntimeException)
163*b1cdbd2cSJim Jagielski     {
164*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
165*b1cdbd2cSJim Jagielski 
166*b1cdbd2cSJim Jagielski         return maLogicalAdvancements;
167*b1cdbd2cSJim Jagielski     }
168*b1cdbd2cSJim Jagielski 
applyLogicalAdvancements(const uno::Sequence<double> & aAdvancements)169*b1cdbd2cSJim Jagielski     void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException)
170*b1cdbd2cSJim Jagielski     {
171*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
172*b1cdbd2cSJim Jagielski 
173*b1cdbd2cSJim Jagielski         if( aAdvancements.getLength() != maText.Length )
174*b1cdbd2cSJim Jagielski         {
175*b1cdbd2cSJim Jagielski             OSL_TRACE( "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" );
176*b1cdbd2cSJim Jagielski             throw lang::IllegalArgumentException();
177*b1cdbd2cSJim Jagielski         }
178*b1cdbd2cSJim Jagielski 
179*b1cdbd2cSJim Jagielski         maLogicalAdvancements = aAdvancements;
180*b1cdbd2cSJim Jagielski     }
181*b1cdbd2cSJim Jagielski 
queryTextBounds()182*b1cdbd2cSJim Jagielski     geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds(  ) throw (uno::RuntimeException)
183*b1cdbd2cSJim Jagielski     {
184*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
185*b1cdbd2cSJim Jagielski 
186*b1cdbd2cSJim Jagielski         OutputDevice* pOutDev = mpRefDevice->getOutputDevice();
187*b1cdbd2cSJim Jagielski     	if( !pOutDev )
188*b1cdbd2cSJim Jagielski             return geometry::RealRectangle2D();
189*b1cdbd2cSJim Jagielski 
190*b1cdbd2cSJim Jagielski         VirtualDevice aVDev( *pOutDev );
191*b1cdbd2cSJim Jagielski         aVDev.SetFont( mpFont->getVCLFont() );
192*b1cdbd2cSJim Jagielski 
193*b1cdbd2cSJim Jagielski         // need metrics for Y offset, the XCanvas always renders
194*b1cdbd2cSJim Jagielski         // relative to baseline
195*b1cdbd2cSJim Jagielski         const ::FontMetric& aMetric( aVDev.GetFontMetric() );
196*b1cdbd2cSJim Jagielski 
197*b1cdbd2cSJim Jagielski         setupLayoutMode( aVDev, mnTextDirection );
198*b1cdbd2cSJim Jagielski 
199*b1cdbd2cSJim Jagielski         const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() );
200*b1cdbd2cSJim Jagielski         const sal_Int32 nBelowBaseline( aMetric.GetDescent() );
201*b1cdbd2cSJim Jagielski 
202*b1cdbd2cSJim Jagielski         if( maLogicalAdvancements.getLength() )
203*b1cdbd2cSJim Jagielski         {
204*b1cdbd2cSJim Jagielski             return geometry::RealRectangle2D( 0, nAboveBaseline,
205*b1cdbd2cSJim Jagielski                                               maLogicalAdvancements[ maLogicalAdvancements.getLength()-1 ],
206*b1cdbd2cSJim Jagielski                                               nBelowBaseline );
207*b1cdbd2cSJim Jagielski         }
208*b1cdbd2cSJim Jagielski         else
209*b1cdbd2cSJim Jagielski         {
210*b1cdbd2cSJim Jagielski             return geometry::RealRectangle2D( 0, nAboveBaseline,
211*b1cdbd2cSJim Jagielski                                               aVDev.GetTextWidth(
212*b1cdbd2cSJim Jagielski                                                   maText.Text,
213*b1cdbd2cSJim Jagielski                                                   ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
214*b1cdbd2cSJim Jagielski                                                   ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) ),
215*b1cdbd2cSJim Jagielski                                               nBelowBaseline );
216*b1cdbd2cSJim Jagielski         }
217*b1cdbd2cSJim Jagielski     }
218*b1cdbd2cSJim Jagielski 
justify(double)219*b1cdbd2cSJim Jagielski     double SAL_CALL TextLayout::justify( double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
220*b1cdbd2cSJim Jagielski     {
221*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
222*b1cdbd2cSJim Jagielski 
223*b1cdbd2cSJim Jagielski         // TODO
224*b1cdbd2cSJim Jagielski         return 0.0;
225*b1cdbd2cSJim Jagielski     }
226*b1cdbd2cSJim Jagielski 
combinedJustify(const uno::Sequence<uno::Reference<rendering::XTextLayout>> &,double)227*b1cdbd2cSJim Jagielski     double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& /*aNextLayouts*/,
228*b1cdbd2cSJim Jagielski                                                  double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
229*b1cdbd2cSJim Jagielski     {
230*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
231*b1cdbd2cSJim Jagielski 
232*b1cdbd2cSJim Jagielski         // TODO
233*b1cdbd2cSJim Jagielski         return 0.0;
234*b1cdbd2cSJim Jagielski     }
235*b1cdbd2cSJim Jagielski 
getTextHit(const geometry::RealPoint2D &)236*b1cdbd2cSJim Jagielski     rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& /*aHitPoint*/ ) throw (uno::RuntimeException)
237*b1cdbd2cSJim Jagielski     {
238*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
239*b1cdbd2cSJim Jagielski 
240*b1cdbd2cSJim Jagielski         // TODO
241*b1cdbd2cSJim Jagielski         return rendering::TextHit();
242*b1cdbd2cSJim Jagielski     }
243*b1cdbd2cSJim Jagielski 
getCaret(sal_Int32,sal_Bool)244*b1cdbd2cSJim Jagielski     rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 /*nInsertionIndex*/,
245*b1cdbd2cSJim Jagielski                                                     sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
246*b1cdbd2cSJim Jagielski     {
247*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
248*b1cdbd2cSJim Jagielski 
249*b1cdbd2cSJim Jagielski         // TODO
250*b1cdbd2cSJim Jagielski         return rendering::Caret();
251*b1cdbd2cSJim Jagielski     }
252*b1cdbd2cSJim Jagielski 
getNextInsertionIndex(sal_Int32,sal_Int32,sal_Bool)253*b1cdbd2cSJim Jagielski     sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 /*nStartIndex*/,
254*b1cdbd2cSJim Jagielski                                                           sal_Int32 /*nCaretAdvancement*/,
255*b1cdbd2cSJim Jagielski                                                           sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
256*b1cdbd2cSJim Jagielski     {
257*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
258*b1cdbd2cSJim Jagielski 
259*b1cdbd2cSJim Jagielski         // TODO
260*b1cdbd2cSJim Jagielski         return 0;
261*b1cdbd2cSJim Jagielski     }
262*b1cdbd2cSJim Jagielski 
queryVisualHighlighting(sal_Int32,sal_Int32)263*b1cdbd2cSJim Jagielski     uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 /*nStartIndex*/,
264*b1cdbd2cSJim Jagielski                                                                                               sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
265*b1cdbd2cSJim Jagielski     {
266*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
267*b1cdbd2cSJim Jagielski 
268*b1cdbd2cSJim Jagielski         // TODO
269*b1cdbd2cSJim Jagielski         return uno::Reference< rendering::XPolyPolygon2D >();
270*b1cdbd2cSJim Jagielski     }
271*b1cdbd2cSJim Jagielski 
queryLogicalHighlighting(sal_Int32,sal_Int32)272*b1cdbd2cSJim Jagielski     uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 /*nStartIndex*/,
273*b1cdbd2cSJim Jagielski                                                                                                sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
274*b1cdbd2cSJim Jagielski     {
275*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
276*b1cdbd2cSJim Jagielski 
277*b1cdbd2cSJim Jagielski         // TODO
278*b1cdbd2cSJim Jagielski         return uno::Reference< rendering::XPolyPolygon2D >();
279*b1cdbd2cSJim Jagielski     }
280*b1cdbd2cSJim Jagielski 
getBaselineOffset()281*b1cdbd2cSJim Jagielski     double SAL_CALL TextLayout::getBaselineOffset(  ) throw (uno::RuntimeException)
282*b1cdbd2cSJim Jagielski     {
283*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
284*b1cdbd2cSJim Jagielski 
285*b1cdbd2cSJim Jagielski         // TODO
286*b1cdbd2cSJim Jagielski         return 0.0;
287*b1cdbd2cSJim Jagielski     }
288*b1cdbd2cSJim Jagielski 
getMainTextDirection()289*b1cdbd2cSJim Jagielski     sal_Int8 SAL_CALL TextLayout::getMainTextDirection(  ) throw (uno::RuntimeException)
290*b1cdbd2cSJim Jagielski     {
291*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
292*b1cdbd2cSJim Jagielski 
293*b1cdbd2cSJim Jagielski         return mnTextDirection;
294*b1cdbd2cSJim Jagielski     }
295*b1cdbd2cSJim Jagielski 
getFont()296*b1cdbd2cSJim Jagielski     uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont(  ) throw (uno::RuntimeException)
297*b1cdbd2cSJim Jagielski     {
298*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
299*b1cdbd2cSJim Jagielski 
300*b1cdbd2cSJim Jagielski         return mpFont.getRef();
301*b1cdbd2cSJim Jagielski     }
302*b1cdbd2cSJim Jagielski 
getText()303*b1cdbd2cSJim Jagielski     rendering::StringContext SAL_CALL TextLayout::getText(  ) throw (uno::RuntimeException)
304*b1cdbd2cSJim Jagielski     {
305*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
306*b1cdbd2cSJim Jagielski 
307*b1cdbd2cSJim Jagielski         return maText;
308*b1cdbd2cSJim Jagielski     }
309*b1cdbd2cSJim Jagielski 
useFont(Cairo * pCairo)310*b1cdbd2cSJim Jagielski     void TextLayout::useFont( Cairo* pCairo )
311*b1cdbd2cSJim Jagielski     {
312*b1cdbd2cSJim Jagielski 	rendering::FontRequest aFontRequest = mpFont->getFontRequest();
313*b1cdbd2cSJim Jagielski 	rendering::FontInfo aFontInfo = aFontRequest.FontDescription;
314*b1cdbd2cSJim Jagielski 
315*b1cdbd2cSJim Jagielski 	cairo_select_font_face( pCairo, ::rtl::OUStringToOString( aFontInfo.FamilyName, RTL_TEXTENCODING_UTF8 ), CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL );
316*b1cdbd2cSJim Jagielski 	cairo_set_font_size( pCairo, aFontRequest.CellSize );
317*b1cdbd2cSJim Jagielski     }
318*b1cdbd2cSJim Jagielski 
319*b1cdbd2cSJim Jagielski   /** TextLayout:draw
320*b1cdbd2cSJim Jagielski    *
321*b1cdbd2cSJim Jagielski    * This function uses the "toy" api of the cairo library
322*b1cdbd2cSJim Jagielski    *
323*b1cdbd2cSJim Jagielski    **/
draw(Cairo * pCairo)324*b1cdbd2cSJim Jagielski     bool TextLayout::draw( Cairo* pCairo )
325*b1cdbd2cSJim Jagielski     {
326*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
327*b1cdbd2cSJim Jagielski 
328*b1cdbd2cSJim Jagielski 		::rtl::OUString aSubText = maText.Text.copy( maText.StartPosition, maText.Length );
329*b1cdbd2cSJim Jagielski 		::rtl::OString aUTF8String = ::rtl::OUStringToOString( aSubText, RTL_TEXTENCODING_UTF8 );
330*b1cdbd2cSJim Jagielski 
331*b1cdbd2cSJim Jagielski 		cairo_save( pCairo );
332*b1cdbd2cSJim Jagielski 		/* move to 0, 0 as cairo_show_text advances current point and current point is not restored by cairo_restore.
333*b1cdbd2cSJim Jagielski 		   before we were depending on unmodified current point which I believed was preserved by save/restore */
334*b1cdbd2cSJim Jagielski 		cairo_move_to( pCairo, 0, 0 );
335*b1cdbd2cSJim Jagielski 		useFont( pCairo );
336*b1cdbd2cSJim Jagielski 		cairo_show_text( pCairo, aUTF8String.getStr() );
337*b1cdbd2cSJim Jagielski 		cairo_restore( pCairo );
338*b1cdbd2cSJim Jagielski 
339*b1cdbd2cSJim Jagielski         return true;
340*b1cdbd2cSJim Jagielski     }
341*b1cdbd2cSJim Jagielski 
342*b1cdbd2cSJim Jagielski 
343*b1cdbd2cSJim Jagielski   /**
344*b1cdbd2cSJim Jagielski    * TextLayout::isCairoRenderable
345*b1cdbd2cSJim Jagielski    *
346*b1cdbd2cSJim Jagielski    * Features currenly not supported by Cairo (VCL rendering is used as fallback):
347*b1cdbd2cSJim Jagielski    * - vertical glyphs
348*b1cdbd2cSJim Jagielski    *
349*b1cdbd2cSJim Jagielski    * @return true, if text/font can be rendered with cairo
350*b1cdbd2cSJim Jagielski    **/
isCairoRenderable(SystemFontData aSysFontData) const351*b1cdbd2cSJim Jagielski     bool TextLayout::isCairoRenderable(SystemFontData aSysFontData) const
352*b1cdbd2cSJim Jagielski     {
353*b1cdbd2cSJim Jagielski #if defined UNX && !defined QUARTZ
354*b1cdbd2cSJim Jagielski         // is font usable?
355*b1cdbd2cSJim Jagielski         if (!aSysFontData.nFontId) return false;
356*b1cdbd2cSJim Jagielski #endif
357*b1cdbd2cSJim Jagielski 
358*b1cdbd2cSJim Jagielski         // vertical glyph rendering is not supported in cairo for now
359*b1cdbd2cSJim Jagielski         if (aSysFontData.bVerticalCharacterType) {
360*b1cdbd2cSJim Jagielski             OSL_TRACE(":cairocanvas::TextLayout::isCairoRenderable(): ***************** VERTICAL CHARACTER STYLE!!! ****************");
361*b1cdbd2cSJim Jagielski             return false;
362*b1cdbd2cSJim Jagielski         }
363*b1cdbd2cSJim Jagielski 
364*b1cdbd2cSJim Jagielski         return true;
365*b1cdbd2cSJim Jagielski     }
366*b1cdbd2cSJim Jagielski 
367*b1cdbd2cSJim Jagielski   /**
368*b1cdbd2cSJim Jagielski    * TextLayout::draw
369*b1cdbd2cSJim Jagielski    *
370*b1cdbd2cSJim Jagielski    * Cairo-based text rendering. Draw text directly on the cairo surface with cairo fonts.
371*b1cdbd2cSJim Jagielski    * Avoid using VCL VirtualDevices for that, bypassing VCL DrawText functions, when possible
372*b1cdbd2cSJim Jagielski    *
373*b1cdbd2cSJim Jagielski    * Note: some text effects are not rendered due to lacking generic canvas or cairo canvas
374*b1cdbd2cSJim Jagielski    *       implementation. See issues 92657, 92658, 92659, 92660, 97529
375*b1cdbd2cSJim Jagielski    *
376*b1cdbd2cSJim Jagielski    * @return true, if successful
377*b1cdbd2cSJim Jagielski    **/
draw(SurfaceSharedPtr & pSurface,OutputDevice & rOutDev,const Point & rOutpos,const rendering::ViewState & viewState,const rendering::RenderState & renderState) const378*b1cdbd2cSJim Jagielski     bool TextLayout::draw( SurfaceSharedPtr&             pSurface,
379*b1cdbd2cSJim Jagielski                            OutputDevice&                 rOutDev,
380*b1cdbd2cSJim Jagielski                            const Point&                  rOutpos,
381*b1cdbd2cSJim Jagielski                            const rendering::ViewState&   viewState,
382*b1cdbd2cSJim Jagielski                            const rendering::RenderState& renderState ) const
383*b1cdbd2cSJim Jagielski     {
384*b1cdbd2cSJim Jagielski         ::osl::MutexGuard aGuard( m_aMutex );
385*b1cdbd2cSJim Jagielski         SystemTextLayoutData aSysLayoutData;
386*b1cdbd2cSJim Jagielski #if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1)
387*b1cdbd2cSJim Jagielski         LOGFONTW logfont;
388*b1cdbd2cSJim Jagielski #endif
389*b1cdbd2cSJim Jagielski         setupLayoutMode( rOutDev, mnTextDirection );
390*b1cdbd2cSJim Jagielski 
391*b1cdbd2cSJim Jagielski         // TODO(P2): cache that
392*b1cdbd2cSJim Jagielski         ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]);
393*b1cdbd2cSJim Jagielski 
394*b1cdbd2cSJim Jagielski         if( maLogicalAdvancements.getLength() )
395*b1cdbd2cSJim Jagielski         {
396*b1cdbd2cSJim Jagielski             setupTextOffsets( aOffsets.get(), maLogicalAdvancements, viewState, renderState );
397*b1cdbd2cSJim Jagielski 
398*b1cdbd2cSJim Jagielski             // TODO(F3): ensure correct length and termination for DX
399*b1cdbd2cSJim Jagielski             // array (last entry _must_ contain the overall width)
400*b1cdbd2cSJim Jagielski         }
401*b1cdbd2cSJim Jagielski 
402*b1cdbd2cSJim Jagielski         aSysLayoutData = rOutDev.GetSysTextLayoutData(rOutpos, maText.Text,
403*b1cdbd2cSJim Jagielski                                                       ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
404*b1cdbd2cSJim Jagielski                                                       ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length),
405*b1cdbd2cSJim Jagielski                                                       maLogicalAdvancements.getLength() ? aOffsets.get() : NULL);
406*b1cdbd2cSJim Jagielski 
407*b1cdbd2cSJim Jagielski         // Sort them so that all glyphs on the same glyph fallback level are consecutive
408*b1cdbd2cSJim Jagielski         std::sort(aSysLayoutData.rGlyphData.begin(), aSysLayoutData.rGlyphData.end(), compareFallbacks);
409*b1cdbd2cSJim Jagielski         bool bCairoRenderable = true;
410*b1cdbd2cSJim Jagielski 
411*b1cdbd2cSJim Jagielski         //Pull all the fonts we need to render the text
412*b1cdbd2cSJim Jagielski         typedef std::pair<SystemFontData,int> FontLevel;
413*b1cdbd2cSJim Jagielski         typedef std::vector<FontLevel> FontLevelVector;
414*b1cdbd2cSJim Jagielski         FontLevelVector aFontData;
415*b1cdbd2cSJim Jagielski         SystemGlyphDataVector::const_iterator aIter=aSysLayoutData.rGlyphData.begin();
416*b1cdbd2cSJim Jagielski         const SystemGlyphDataVector::const_iterator aEnd=aSysLayoutData.rGlyphData.end();
417*b1cdbd2cSJim Jagielski         for( ; aIter != aEnd; ++aIter )
418*b1cdbd2cSJim Jagielski         {
419*b1cdbd2cSJim Jagielski             if( aFontData.empty() || aIter->fallbacklevel != aFontData.back().second )
420*b1cdbd2cSJim Jagielski             {
421*b1cdbd2cSJim Jagielski                 aFontData.push_back(FontLevel(rOutDev.GetSysFontData(aIter->fallbacklevel),
422*b1cdbd2cSJim Jagielski                                               aIter->fallbacklevel));
423*b1cdbd2cSJim Jagielski                 if( !isCairoRenderable(aFontData.back().first) )
424*b1cdbd2cSJim Jagielski                 {
425*b1cdbd2cSJim Jagielski                     bCairoRenderable = false;
426*b1cdbd2cSJim Jagielski                     OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): VCL FALLBACK %s%s%s%s - %s",
427*b1cdbd2cSJim Jagielski                               maLogicalAdvancements.getLength() ? "ADV " : "",
428*b1cdbd2cSJim Jagielski                               aFontData.back().first.bAntialias ? "AA " : "",
429*b1cdbd2cSJim Jagielski                               aFontData.back().first.bFakeBold ? "FB " : "",
430*b1cdbd2cSJim Jagielski                               aFontData.back().first.bFakeItalic ? "FI " : "",
431*b1cdbd2cSJim Jagielski                               ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, maText.Length ),
432*b1cdbd2cSJim Jagielski                                                         RTL_TEXTENCODING_UTF8 ).getStr());
433*b1cdbd2cSJim Jagielski                     break;
434*b1cdbd2cSJim Jagielski                 }
435*b1cdbd2cSJim Jagielski             }
436*b1cdbd2cSJim Jagielski         }
437*b1cdbd2cSJim Jagielski 
438*b1cdbd2cSJim Jagielski         // The ::GetSysTextLayoutData(), i.e. layouting of text to glyphs can change the font being used.
439*b1cdbd2cSJim Jagielski         // The fallback checks need to be done after final font is known.
440*b1cdbd2cSJim Jagielski         if (!bCairoRenderable)    // VCL FALLBACKS
441*b1cdbd2cSJim Jagielski         {
442*b1cdbd2cSJim Jagielski             if (maLogicalAdvancements.getLength())        // VCL FALLBACK - with glyph advances
443*b1cdbd2cSJim Jagielski             {
444*b1cdbd2cSJim Jagielski                 rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(),
445*b1cdbd2cSJim Jagielski                                        ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
446*b1cdbd2cSJim Jagielski                                        ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
447*b1cdbd2cSJim Jagielski                 return true;
448*b1cdbd2cSJim Jagielski             }
449*b1cdbd2cSJim Jagielski             else                                               // VCL FALLBACK - without advances
450*b1cdbd2cSJim Jagielski             {
451*b1cdbd2cSJim Jagielski                 rOutDev.DrawText( rOutpos, maText.Text,
452*b1cdbd2cSJim Jagielski                                   ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
453*b1cdbd2cSJim Jagielski                                   ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
454*b1cdbd2cSJim Jagielski                 return true;
455*b1cdbd2cSJim Jagielski             }
456*b1cdbd2cSJim Jagielski         }
457*b1cdbd2cSJim Jagielski 
458*b1cdbd2cSJim Jagielski         if (aSysLayoutData.rGlyphData.empty()) return false; //??? false?
459*b1cdbd2cSJim Jagielski 
460*b1cdbd2cSJim Jagielski         /**
461*b1cdbd2cSJim Jagielski          * Setup platform independent glyph vector into cairo-based glyphs vector.
462*b1cdbd2cSJim Jagielski          **/
463*b1cdbd2cSJim Jagielski 
464*b1cdbd2cSJim Jagielski         // Loop through the fonts used and render the matching glyphs for each
465*b1cdbd2cSJim Jagielski         FontLevelVector::const_iterator aFontDataIter = aFontData.begin();
466*b1cdbd2cSJim Jagielski         const FontLevelVector::const_iterator aFontDataEnd = aFontData.end();
467*b1cdbd2cSJim Jagielski         for( ; aFontDataIter != aFontDataEnd; ++aFontDataIter )
468*b1cdbd2cSJim Jagielski         {
469*b1cdbd2cSJim Jagielski             const SystemFontData &rSysFontData = aFontDataIter->first;
470*b1cdbd2cSJim Jagielski 
471*b1cdbd2cSJim Jagielski             // setup glyphs
472*b1cdbd2cSJim Jagielski             std::vector<cairo_glyph_t> cairo_glyphs;
473*b1cdbd2cSJim Jagielski             cairo_glyphs.reserve( 256 );
474*b1cdbd2cSJim Jagielski 
475*b1cdbd2cSJim Jagielski             SystemGlyphDataVector::const_iterator aIter=aSysLayoutData.rGlyphData.begin();
476*b1cdbd2cSJim Jagielski             const SystemGlyphDataVector::const_iterator aEnd=aSysLayoutData.rGlyphData.end();
477*b1cdbd2cSJim Jagielski             for( ; aIter != aEnd; ++aIter )
478*b1cdbd2cSJim Jagielski             {
479*b1cdbd2cSJim Jagielski                 SystemGlyphData systemGlyph = *aIter;
480*b1cdbd2cSJim Jagielski                 if( systemGlyph.fallbacklevel != aFontDataIter->second )
481*b1cdbd2cSJim Jagielski                     continue;
482*b1cdbd2cSJim Jagielski 
483*b1cdbd2cSJim Jagielski                 cairo_glyph_t aGlyph;
484*b1cdbd2cSJim Jagielski                 aGlyph.index = systemGlyph.index;
485*b1cdbd2cSJim Jagielski     #ifdef CAIRO_HAS_WIN32_SURFACE
486*b1cdbd2cSJim Jagielski                 // Cairo requires standard glyph indexes (ETO_GLYPH_INDEX), while vcl/win/* uses ucs4 chars.
487*b1cdbd2cSJim Jagielski                 // Convert to standard indexes
488*b1cdbd2cSJim Jagielski                 aGlyph.index = cairo::ucs4toindex((unsigned int) aGlyph.index, rSysFontData.hFont);
489*b1cdbd2cSJim Jagielski     #endif
490*b1cdbd2cSJim Jagielski                 aGlyph.x = systemGlyph.x;
491*b1cdbd2cSJim Jagielski                 aGlyph.y = systemGlyph.y;
492*b1cdbd2cSJim Jagielski                 cairo_glyphs.push_back(aGlyph);
493*b1cdbd2cSJim Jagielski             }
494*b1cdbd2cSJim Jagielski 
495*b1cdbd2cSJim Jagielski             if (cairo_glyphs.empty())
496*b1cdbd2cSJim Jagielski                 continue;
497*b1cdbd2cSJim Jagielski 
498*b1cdbd2cSJim Jagielski             /**
499*b1cdbd2cSJim Jagielski              * Setup font
500*b1cdbd2cSJim Jagielski              **/
501*b1cdbd2cSJim Jagielski             cairo_font_face_t* font_face = NULL;
502*b1cdbd2cSJim Jagielski 
503*b1cdbd2cSJim Jagielski     #ifdef CAIRO_HAS_QUARTZ_SURFACE
504*b1cdbd2cSJim Jagielski             // TODO: use cairo_quartz_font_face_create_for_cgfont(cgFont)
505*b1cdbd2cSJim Jagielski             //       when CGFont (Mac OS X 10.5 API) is provided by the AQUA VCL backend.
506*b1cdbd2cSJim Jagielski             font_face = cairo_quartz_font_face_create_for_atsu_font_id((ATSUFontID) rSysFontData.aATSUFontID);
507*b1cdbd2cSJim Jagielski 
508*b1cdbd2cSJim Jagielski     #elif defined CAIRO_HAS_WIN32_SURFACE
509*b1cdbd2cSJim Jagielski       #if (OSL_DEBUG_LEVEL > 1)
510*b1cdbd2cSJim Jagielski             GetObjectW( rSysFontData.hFont, sizeof(logfont), &logfont );
511*b1cdbd2cSJim Jagielski       #endif
512*b1cdbd2cSJim Jagielski             // Note: cairo library uses logfont fallbacks when lfEscapement, lfOrientation and lfWidth are not zero.
513*b1cdbd2cSJim Jagielski             // VCL always has non-zero value for lfWidth
514*b1cdbd2cSJim Jagielski             font_face = cairo_win32_font_face_create_for_hfont(rSysFontData.hFont);
515*b1cdbd2cSJim Jagielski 
516*b1cdbd2cSJim Jagielski     #elif defined CAIRO_HAS_XLIB_SURFACE
517*b1cdbd2cSJim Jagielski             font_face = cairo_ft_font_face_create_for_ft_face((FT_Face)rSysFontData.nFontId,
518*b1cdbd2cSJim Jagielski                                                               rSysFontData.nFontFlags);
519*b1cdbd2cSJim Jagielski     #else
520*b1cdbd2cSJim Jagielski     # error Native API needed.
521*b1cdbd2cSJim Jagielski     #endif
522*b1cdbd2cSJim Jagielski 
523*b1cdbd2cSJim Jagielski             CairoSharedPtr pSCairo = pSurface->getCairo();
524*b1cdbd2cSJim Jagielski 
525*b1cdbd2cSJim Jagielski             cairo_set_font_face( pSCairo.get(), font_face);
526*b1cdbd2cSJim Jagielski 
527*b1cdbd2cSJim Jagielski             // create default font options. cairo_get_font_options() does not retrieve the surface defaults,
528*b1cdbd2cSJim Jagielski             // only what has been set before with cairo_set_font_options()
529*b1cdbd2cSJim Jagielski             cairo_font_options_t* options = cairo_font_options_create();
530*b1cdbd2cSJim Jagielski             if (rSysFontData.bAntialias) {
531*b1cdbd2cSJim Jagielski                 // CAIRO_ANTIALIAS_GRAY provides more similar result to VCL Canvas,
532*b1cdbd2cSJim Jagielski                 // so we're not using CAIRO_ANTIALIAS_SUBPIXEL
533*b1cdbd2cSJim Jagielski                 cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
534*b1cdbd2cSJim Jagielski             }
535*b1cdbd2cSJim Jagielski             cairo_set_font_options( pSCairo.get(), options);
536*b1cdbd2cSJim Jagielski 
537*b1cdbd2cSJim Jagielski             // Font color
538*b1cdbd2cSJim Jagielski             Color mTextColor = rOutDev.GetTextColor();
539*b1cdbd2cSJim Jagielski             cairo_set_source_rgb(pSCairo.get(),
540*b1cdbd2cSJim Jagielski                                  mTextColor.GetRed()/255.0,
541*b1cdbd2cSJim Jagielski                                  mTextColor.GetGreen()/255.0,
542*b1cdbd2cSJim Jagielski                                  mTextColor.GetBlue()/255.0);
543*b1cdbd2cSJim Jagielski 
544*b1cdbd2cSJim Jagielski             // Font rotation and scaling
545*b1cdbd2cSJim Jagielski             cairo_matrix_t m;
546*b1cdbd2cSJim Jagielski             Font aFont = rOutDev.GetFont();
547*b1cdbd2cSJim Jagielski             FontMetric aMetric( rOutDev.GetFontMetric(aFont) );
548*b1cdbd2cSJim Jagielski             long nWidth = 0;
549*b1cdbd2cSJim Jagielski 
550*b1cdbd2cSJim Jagielski             // width calculation is deep magic and platform/font dependant.
551*b1cdbd2cSJim Jagielski             // width == 0 means no scaling, and usually width == height means the same.
552*b1cdbd2cSJim Jagielski             // Other values mean horizontal scaling (narrow or stretching)
553*b1cdbd2cSJim Jagielski             // see issue #101566
554*b1cdbd2cSJim Jagielski 
555*b1cdbd2cSJim Jagielski             //proper scale calculation across platforms
556*b1cdbd2cSJim Jagielski             if (aFont.GetWidth() == 0) {
557*b1cdbd2cSJim Jagielski                 nWidth = aFont.GetHeight();
558*b1cdbd2cSJim Jagielski             } else {
559*b1cdbd2cSJim Jagielski                 // any scaling needs to be relative to the platform-dependent definition
560*b1cdbd2cSJim Jagielski                 // of height of the font
561*b1cdbd2cSJim Jagielski                 nWidth = aFont.GetWidth() * aFont.GetHeight() / aMetric.GetHeight();
562*b1cdbd2cSJim Jagielski             }
563*b1cdbd2cSJim Jagielski 
564*b1cdbd2cSJim Jagielski             cairo_matrix_init_identity(&m);
565*b1cdbd2cSJim Jagielski 
566*b1cdbd2cSJim Jagielski             if (aSysLayoutData.orientation) cairo_matrix_rotate(&m, (3600 - aSysLayoutData.orientation) * M_PI / 1800.0);
567*b1cdbd2cSJim Jagielski 
568*b1cdbd2cSJim Jagielski             cairo_matrix_scale(&m, nWidth, aFont.GetHeight());
569*b1cdbd2cSJim Jagielski 
570*b1cdbd2cSJim Jagielski             //faux italics
571*b1cdbd2cSJim Jagielski             if (rSysFontData.bFakeItalic) m.xy = -m.xx * 0x6000L / 0x10000L;
572*b1cdbd2cSJim Jagielski 
573*b1cdbd2cSJim Jagielski             cairo_set_font_matrix(pSCairo.get(), &m);
574*b1cdbd2cSJim Jagielski 
575*b1cdbd2cSJim Jagielski             OSL_TRACE("\r\n:cairocanvas::TextLayout::draw(S,O,p,v,r): Size:(%d,%d), W:%d->%d, Pos (%d,%d), G(%d,%d,%d) %s%s%s%s || Name:%s - %s",
576*b1cdbd2cSJim Jagielski                       aFont.GetWidth(),
577*b1cdbd2cSJim Jagielski                       aFont.GetHeight(),
578*b1cdbd2cSJim Jagielski                       aMetric.GetWidth(),
579*b1cdbd2cSJim Jagielski                       nWidth,
580*b1cdbd2cSJim Jagielski                       (int) rOutpos.X(),
581*b1cdbd2cSJim Jagielski                       (int) rOutpos.Y(),
582*b1cdbd2cSJim Jagielski                       cairo_glyphs[0].index, cairo_glyphs[1].index, cairo_glyphs[2].index,
583*b1cdbd2cSJim Jagielski                       maLogicalAdvancements.getLength() ? "ADV " : "",
584*b1cdbd2cSJim Jagielski                       rSysFontData.bAntialias ? "AA " : "",
585*b1cdbd2cSJim Jagielski                       rSysFontData.bFakeBold ? "FB " : "",
586*b1cdbd2cSJim Jagielski                       rSysFontData.bFakeItalic ? "FI " : "",
587*b1cdbd2cSJim Jagielski     #if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1)
588*b1cdbd2cSJim Jagielski                       ::rtl::OUStringToOString( reinterpret_cast<const sal_Unicode*> (logfont.lfFaceName), RTL_TEXTENCODING_UTF8 ).getStr(),
589*b1cdbd2cSJim Jagielski     #else
590*b1cdbd2cSJim Jagielski                       ::rtl::OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr(),
591*b1cdbd2cSJim Jagielski     #endif
592*b1cdbd2cSJim Jagielski                       ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, maText.Length ),
593*b1cdbd2cSJim Jagielski                                                 RTL_TEXTENCODING_UTF8 ).getStr()
594*b1cdbd2cSJim Jagielski                 );
595*b1cdbd2cSJim Jagielski 
596*b1cdbd2cSJim Jagielski             cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
597*b1cdbd2cSJim Jagielski 
598*b1cdbd2cSJim Jagielski             //faux bold
599*b1cdbd2cSJim Jagielski             if (rSysFontData.bFakeBold) {
600*b1cdbd2cSJim Jagielski                 double bold_dx = 0.5 * sqrt( 0.7 * aFont.GetHeight() );
601*b1cdbd2cSJim Jagielski                 int total_steps = 2 * ((int) (bold_dx + 0.5));
602*b1cdbd2cSJim Jagielski 
603*b1cdbd2cSJim Jagielski                 // loop to draw the text for every half pixel of displacement
604*b1cdbd2cSJim Jagielski                 for (int nSteps = 0; nSteps < total_steps; nSteps++) {
605*b1cdbd2cSJim Jagielski                     for(int nGlyphIdx = 0; nGlyphIdx < (int) cairo_glyphs.size(); nGlyphIdx++) {
606*b1cdbd2cSJim Jagielski                         cairo_glyphs[nGlyphIdx].x += bold_dx * nSteps / total_steps;
607*b1cdbd2cSJim Jagielski                     }
608*b1cdbd2cSJim Jagielski                     cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
609*b1cdbd2cSJim Jagielski                 }
610*b1cdbd2cSJim Jagielski                 OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): FAKEBOLD - dx:%d", (int) bold_dx);
611*b1cdbd2cSJim Jagielski             }
612*b1cdbd2cSJim Jagielski 
613*b1cdbd2cSJim Jagielski             cairo_restore( pSCairo.get() );
614*b1cdbd2cSJim Jagielski             cairo_font_face_destroy(font_face);
615*b1cdbd2cSJim Jagielski         }
616*b1cdbd2cSJim Jagielski         return true;
617*b1cdbd2cSJim Jagielski     }
618*b1cdbd2cSJim Jagielski 
619*b1cdbd2cSJim Jagielski 
620*b1cdbd2cSJim Jagielski     namespace
621*b1cdbd2cSJim Jagielski     {
622*b1cdbd2cSJim Jagielski         class OffsetTransformer
623*b1cdbd2cSJim Jagielski         {
624*b1cdbd2cSJim Jagielski         public:
OffsetTransformer(const::basegfx::B2DHomMatrix & rMat)625*b1cdbd2cSJim Jagielski             OffsetTransformer( const ::basegfx::B2DHomMatrix& rMat ) :
626*b1cdbd2cSJim Jagielski                 maMatrix( rMat )
627*b1cdbd2cSJim Jagielski             {
628*b1cdbd2cSJim Jagielski             }
629*b1cdbd2cSJim Jagielski 
operator ()(const double & rOffset)630*b1cdbd2cSJim Jagielski             sal_Int32 operator()( const double& rOffset )
631*b1cdbd2cSJim Jagielski             {
632*b1cdbd2cSJim Jagielski                 // This is an optimization of the normal rMat*[x,0]
633*b1cdbd2cSJim Jagielski                 // transformation of the advancement vector (in x
634*b1cdbd2cSJim Jagielski                 // direction), followed by a length calculation of the
635*b1cdbd2cSJim Jagielski                 // resulting vector: advancement' =
636*b1cdbd2cSJim Jagielski                 // ||rMat*[x,0]||. Since advancements are vectors, we
637*b1cdbd2cSJim Jagielski                 // can ignore translational components, thus if [x,0],
638*b1cdbd2cSJim Jagielski                 // it follows that rMat*[x,0]=[x',0] holds. Thus, we
639*b1cdbd2cSJim Jagielski                 // just have to calc the transformation of the x
640*b1cdbd2cSJim Jagielski                 // component.
641*b1cdbd2cSJim Jagielski 
642*b1cdbd2cSJim Jagielski                 // TODO(F2): Handle non-horizontal advancements!
643*b1cdbd2cSJim Jagielski                 return ::basegfx::fround( hypot(maMatrix.get(0,0)*rOffset,
644*b1cdbd2cSJim Jagielski 												maMatrix.get(1,0)*rOffset) );
645*b1cdbd2cSJim Jagielski             }
646*b1cdbd2cSJim Jagielski 
647*b1cdbd2cSJim Jagielski         private:
648*b1cdbd2cSJim Jagielski             ::basegfx::B2DHomMatrix maMatrix;
649*b1cdbd2cSJim Jagielski         };
650*b1cdbd2cSJim Jagielski     }
651*b1cdbd2cSJim Jagielski 
setupTextOffsets(sal_Int32 * outputOffsets,const uno::Sequence<double> & inputOffsets,const rendering::ViewState & viewState,const rendering::RenderState & renderState) const652*b1cdbd2cSJim Jagielski     void TextLayout::setupTextOffsets( sal_Int32*						outputOffsets,
653*b1cdbd2cSJim Jagielski                                        const uno::Sequence< double >& 	inputOffsets,
654*b1cdbd2cSJim Jagielski                                        const rendering::ViewState& 		viewState,
655*b1cdbd2cSJim Jagielski                                        const rendering::RenderState& 	renderState		) const
656*b1cdbd2cSJim Jagielski     {
657*b1cdbd2cSJim Jagielski         ENSURE_OR_THROW( outputOffsets!=NULL,
658*b1cdbd2cSJim Jagielski                           "TextLayout::setupTextOffsets offsets NULL" );
659*b1cdbd2cSJim Jagielski 
660*b1cdbd2cSJim Jagielski         ::basegfx::B2DHomMatrix aMatrix;
661*b1cdbd2cSJim Jagielski 
662*b1cdbd2cSJim Jagielski         ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
663*b1cdbd2cSJim Jagielski                                                      viewState,
664*b1cdbd2cSJim Jagielski                                                      renderState);
665*b1cdbd2cSJim Jagielski 
666*b1cdbd2cSJim Jagielski         // fill integer offsets
667*b1cdbd2cSJim Jagielski         ::std::transform( const_cast< uno::Sequence< double >& >(inputOffsets).getConstArray(),
668*b1cdbd2cSJim Jagielski                           const_cast< uno::Sequence< double >& >(inputOffsets).getConstArray()+inputOffsets.getLength(),
669*b1cdbd2cSJim Jagielski                           outputOffsets,
670*b1cdbd2cSJim Jagielski                           OffsetTransformer( aMatrix ) );
671*b1cdbd2cSJim Jagielski     }
672*b1cdbd2cSJim Jagielski 
673*b1cdbd2cSJim Jagielski #define SERVICE_NAME "com.sun.star.rendering.TextLayout"
674*b1cdbd2cSJim Jagielski #define IMPLEMENTATION_NAME "CairoCanvas::TextLayout"
675*b1cdbd2cSJim Jagielski 
getImplementationName()676*b1cdbd2cSJim Jagielski     ::rtl::OUString SAL_CALL TextLayout::getImplementationName() throw( uno::RuntimeException )
677*b1cdbd2cSJim Jagielski     {
678*b1cdbd2cSJim Jagielski         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
679*b1cdbd2cSJim Jagielski     }
680*b1cdbd2cSJim Jagielski 
supportsService(const::rtl::OUString & ServiceName)681*b1cdbd2cSJim Jagielski     sal_Bool SAL_CALL TextLayout::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException )
682*b1cdbd2cSJim Jagielski     {
683*b1cdbd2cSJim Jagielski         return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
684*b1cdbd2cSJim Jagielski     }
685*b1cdbd2cSJim Jagielski 
getSupportedServiceNames()686*b1cdbd2cSJim Jagielski     uno::Sequence< ::rtl::OUString > SAL_CALL TextLayout::getSupportedServiceNames()  throw( uno::RuntimeException )
687*b1cdbd2cSJim Jagielski     {
688*b1cdbd2cSJim Jagielski         uno::Sequence< ::rtl::OUString > aRet(1);
689*b1cdbd2cSJim Jagielski         aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
690*b1cdbd2cSJim Jagielski 
691*b1cdbd2cSJim Jagielski         return aRet;
692*b1cdbd2cSJim Jagielski     }
693*b1cdbd2cSJim Jagielski }
694