LCOV - code coverage report
Current view: top level - canvas/source/cairo - cairo_textlayout.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1 211 0.5 %
Date: 2015-06-13 12:38:46 Functions: 2 34 5.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11