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

Generated by: LCOV version 1.10