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