LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/source/gdi - embeddedfontshelper.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 13 135 9.6 %
Date: 2013-07-09 Functions: 4 9 44.4 %
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             : 
      10             : #include <vcl/embeddedfontshelper.hxx>
      11             : 
      12             : #include <osl/file.hxx>
      13             : #include <rtl/bootstrap.hxx>
      14             : #include <sft.hxx>
      15             : #include <vcl/outdev.hxx>
      16             : #include <vcl/svapp.hxx>
      17             : 
      18             : #include <boost/scoped_ptr.hpp>
      19             : #include <fontsubset.hxx>
      20             : #include <outdev.h>
      21             : #include <outfont.hxx>
      22             : #include <salgdi.hxx>
      23             : 
      24             : using namespace com::sun::star;
      25             : using namespace vcl;
      26             : 
      27         490 : static void clearDir( const OUString& path )
      28             :     {
      29         490 :     osl::Directory dir( path );
      30         490 :     if( dir.reset() == osl::Directory::E_None )
      31             :     {
      32             :         for(;;)
      33             :         {
      34           0 :             osl::DirectoryItem item;
      35           0 :             if( dir.getNextItem( item ) != osl::Directory::E_None )
      36           0 :                 break;
      37           0 :             osl::FileStatus status( osl_FileStatus_Mask_FileURL );
      38           0 :             if( item.getFileStatus( status ) == osl::File::E_None )
      39           0 :                 osl::File::remove( status.getFileURL());
      40           0 :         }
      41         490 :     }
      42         490 : }
      43             : 
      44         245 : void EmbeddedFontsHelper::clearTemporaryFontFiles()
      45             : {
      46         245 :     OUString path = "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
      47         245 :     rtl::Bootstrap::expandMacros( path );
      48         245 :     path += "/user/temp/embeddedfonts/";
      49         245 :     clearDir( path + "fromdocs/" );
      50         245 :     clearDir( path + "fromsystem/" );
      51         245 : }
      52             : 
      53           0 : bool EmbeddedFontsHelper::addEmbeddedFont( uno::Reference< io::XInputStream > stream, const OUString& fontName,
      54             :     const char* extra, std::vector< unsigned char > key )
      55             : {
      56           0 :     OUString fileUrl = EmbeddedFontsHelper::fileUrlForTemporaryFont( fontName, extra );
      57           0 :     osl::File file( fileUrl );
      58           0 :     switch( file.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_Write ))
      59             :     {
      60             :         case osl::File::E_None:
      61           0 :             break; // ok
      62             :         case osl::File::E_EXIST:
      63           0 :             return true; // Assume it's already been added correctly.
      64             :         default:
      65             :             SAL_WARN( "vcl.fonts", "Cannot open file for temporary font" );
      66           0 :             return false;
      67             :     }
      68           0 :     size_t keyPos = 0;
      69           0 :     std::vector< char > fontData;
      70           0 :     fontData.reserve( 1000000 );
      71             :     for(;;)
      72             :     {
      73           0 :         uno::Sequence< sal_Int8 > buffer;
      74           0 :         sal_uInt64 read = stream->readBytes( buffer, 1024 );
      75           0 :         for( sal_uInt64 pos = 0;
      76           0 :              pos < read && keyPos < key.size();
      77             :              ++pos )
      78           0 :             buffer[ pos ] ^= key[ keyPos++ ];
      79           0 :         if( read > 0 )
      80             :         {
      81           0 :             sal_uInt64 writtenTotal = 0;
      82           0 :             while( writtenTotal < read )
      83             :             {
      84             :                 sal_uInt64 written;
      85           0 :                 file.write( buffer.getConstArray(), read, written );
      86           0 :                 writtenTotal += written;
      87             :             }
      88             :         }
      89           0 :         fontData.insert( fontData.end(), buffer.getConstArray(), buffer.getConstArray() + read );
      90           0 :         if( read <= 0 )
      91           0 :             break;
      92           0 :     }
      93           0 :     if( file.close() != osl::File::E_None )
      94             :     {
      95             :         SAL_WARN( "vcl.fonts", "Writing temporary font file failed" );
      96           0 :         osl::File::remove( fileUrl );
      97           0 :         return false;
      98             :     }
      99           0 :     if( !sufficientFontRights( &fontData.front(), fontData.size(), EditingAllowed ))
     100             :     {
     101             :         // It would be actually better to open the document in read-only mode in this case,
     102             :         // warn the user about this, and provide a button to drop the font(s) in order
     103             :         // to switch to editing.
     104             :         SAL_INFO( "vcl.fonts", "Ignoring embedded font that is not usable for editing" );
     105           0 :         osl::File::remove( fileUrl );
     106           0 :         return false;
     107             :     }
     108           0 :     EmbeddedFontsHelper::activateFont( fontName, fileUrl );
     109           0 :     return true;
     110             : }
     111             : 
     112           0 : OUString EmbeddedFontsHelper::fileUrlForTemporaryFont( const OUString& fontName, const char* extra )
     113             : {
     114           0 :     OUString path = "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
     115           0 :     rtl::Bootstrap::expandMacros( path );
     116           0 :     path += "/user/temp/embeddedfonts/fromdocs/";
     117           0 :     osl::Directory::createPath( path );
     118           0 :     OUString filename = fontName;
     119             :     static int uniqueCounter = 0;
     120           0 :     if( strcmp( extra, "?" ) == 0 )
     121           0 :         filename += OUString::number( uniqueCounter++ );
     122             :     else
     123           0 :         filename += OStringToOUString( extra, RTL_TEXTENCODING_ASCII_US );
     124           0 :     filename += ".ttf"; // TODO is it always ttf?
     125           0 :     return path + filename;
     126             : }
     127             : 
     128           0 : void EmbeddedFontsHelper::activateFont( const OUString& fontName, const OUString& fileUrl )
     129             : {
     130           0 :     OutputDevice *pDevice = Application::GetDefaultDevice();
     131           0 :     pDevice->AddTempDevFont( fileUrl, fontName );
     132           0 :     pDevice->ImplUpdateAllFontData( true );
     133           0 : }
     134             : 
     135             : // Check if it's (legally) allowed to embed the font file into a document
     136             : // (ttf has a flag allowing this). PhysicalFontFace::IsEmbeddable() appears
     137             : // to have a different meaning (guessing from code, IsSubsettable() might
     138             : // possibly mean it's ttf, while IsEmbeddable() might mean it's type1).
     139             : // So just try to open the data as ttf and see.
     140           0 : bool EmbeddedFontsHelper::sufficientFontRights( const void* data, long size, FontRights rights )
     141             : {
     142             :     TrueTypeFont* font;
     143           0 :     if( OpenTTFontBuffer( data, size, 0 /*TODO*/, &font ) == SF_OK )
     144             :     {
     145             :         TTGlobalFontInfo info;
     146           0 :         GetTTGlobalFontInfo( font, &info );
     147           0 :         CloseTTFont( font );
     148             :         // http://www.microsoft.com/typography/tt/ttf_spec/ttch02.doc
     149           0 :         int copyright = info.typeFlags & TYPEFLAG_COPYRIGHT_MASK;
     150           0 :         switch( rights )
     151             :         {
     152             :             case ViewingAllowed:
     153             :                 // Embedding not restricted completely.
     154           0 :                 return ( copyright & 0x02 ) != 0x02;
     155             :             case EditingAllowed:
     156             :                 // Font is installable or editable.
     157           0 :                 return copyright == 0 || ( copyright & 0x08 );
     158             :         }
     159             :     }
     160           0 :     return true; // no known restriction
     161             : }
     162             : 
     163           0 : OUString EmbeddedFontsHelper::fontFileUrl( const OUString& familyName, FontFamily family, FontItalic italic,
     164             :     FontWeight weight, FontPitch pitch, rtl_TextEncoding, FontRights rights )
     165             : {
     166           0 :     OUString path = "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
     167           0 :     rtl::Bootstrap::expandMacros( path );
     168           0 :     path += "/user/temp/embeddedfonts/fromsystem/";
     169           0 :     osl::Directory::createPath( path );
     170           0 :     OUString filename = familyName + "_" + OUString::number( family ) + "_" + OUString::number( italic )
     171           0 :         + "_" + OUString::number( weight ) + "_" + OUString::number( pitch );
     172           0 :     filename += ".ttf"; // TODO is it always ttf?
     173           0 :     OUString url = path + filename;
     174           0 :     if( osl::File( url ).open( osl_File_OpenFlag_Read ) == osl::File::E_None ) // = exists()
     175             :     {
     176             :         // File with contents of the font file already exists, assume it's been created by a previous call.
     177           0 :         return url;
     178             :     }
     179           0 :     bool ok = false;
     180           0 :     SalGraphics* graphics = Application::GetDefaultDevice()->ImplGetGraphics();
     181           0 :     ImplDevFontList fonts;
     182           0 :     graphics->GetDevFontList( &fonts );
     183           0 :     boost::scoped_ptr< ImplGetDevFontList > fontInfo( fonts.GetDevFontList());
     184           0 :     PhysicalFontFace* selected = NULL;
     185           0 :     for( int i = 0;
     186           0 :          i < fontInfo->Count();
     187             :          ++i )
     188             :      {
     189           0 :         PhysicalFontFace* f = fontInfo->Get( i );
     190           0 :         if( f->GetFamilyName() == familyName )
     191             :         {
     192             :             // Ignore comparing text encodings, at least for now. They cannot be trivially compared
     193             :             // (e.g. UCS2 and UTF8 are technically the same characters, just have different encoding,
     194             :             // and just having a unicode font doesn't say what glyphs it actually contains).
     195             :             // It is possible that it still may be needed to do at least some checks here
     196             :             // for some encodings (can one font have more font files for more encodings?).
     197           0 :             if(( family == FAMILY_DONTKNOW || f->GetFamilyType() == family )
     198           0 :                 && ( italic == ITALIC_DONTKNOW || f->GetSlant() == italic )
     199           0 :                 && ( weight == WEIGHT_DONTKNOW || f->GetWeight() == weight )
     200           0 :                 && ( pitch == PITCH_DONTKNOW || f->GetPitch() == pitch ))
     201             :             { // Exact match, return it immediately.
     202           0 :                 selected = f;
     203           0 :                 break;
     204             :             }
     205           0 :             if(( f->GetFamilyType() == FAMILY_DONTKNOW || family == FAMILY_DONTKNOW || f->GetFamilyType() == family )
     206           0 :                 && ( f->GetSlant() == ITALIC_DONTKNOW || italic == ITALIC_DONTKNOW || f->GetSlant() == italic )
     207           0 :                 && ( f->GetWeight() == WEIGHT_DONTKNOW || weight == WEIGHT_DONTKNOW || f->GetWeight() == weight )
     208           0 :                 && ( f->GetPitch() == PITCH_DONTKNOW || pitch == PITCH_DONTKNOW || f->GetPitch() == pitch ))
     209             :             { // Some fonts specify 'DONTKNOW' for some things, still a good match, if we don't find a better one.
     210           0 :                 selected = f;
     211             :             }
     212             :         }
     213             :     }
     214           0 :     if( selected != NULL )
     215             :     {
     216             :         sal_Ucs unicodes[ 256 ];
     217           0 :         for( int i = 0;
     218             :              i < 256;
     219             :              ++i )
     220           0 :             unicodes[ i ] = 'A'; // Just something, not needed, but GetEmbedFontData() needs it.
     221             :         sal_Int32 widths[ 256 ];
     222           0 :         FontSubsetInfo info;
     223             :         long size;
     224           0 :         if( const void* data = graphics->GetEmbedFontData( selected, unicodes, widths, info, &size ))
     225             :         {
     226           0 :             if( sufficientFontRights( data, size, rights ))
     227             :             {
     228           0 :                 osl::File file( url );
     229           0 :                 if( file.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ) == osl::File::E_None )
     230             :                 {
     231           0 :                     sal_uInt64 written = 0;
     232           0 :                     sal_uInt64 totalSize = size;
     233           0 :                     bool error = false;
     234           0 :                     while( written < totalSize && !error)
     235             :                     {
     236             :                         sal_uInt64 nowWritten;
     237           0 :                         switch( file.write( static_cast< const char* >( data ) + written, size - written, nowWritten ))
     238             :                         {
     239             :                             case osl::File::E_None:
     240           0 :                                 written += nowWritten;
     241           0 :                                 break;
     242             :                             case osl::File::E_AGAIN:
     243             :                             case osl::File::E_INTR:
     244           0 :                                 break;
     245             :                             default:
     246           0 :                                 error = true;
     247           0 :                                 break;
     248             :                         }
     249             :                     }
     250           0 :                     file.close();
     251           0 :                     if( error )
     252           0 :                         osl::File::remove( url );
     253             :                     else
     254           0 :                         ok = true;
     255           0 :                 }
     256             :             }
     257           0 :             graphics->FreeEmbedFontData( data, size );
     258           0 :         }
     259             :     }
     260           0 :     return ok ? url : "";
     261         465 : }
     262             : 
     263             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10