ft2_font.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:9k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * ft2_font.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: b0ade15924f41011cb5a209446a36374cb722e5e $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teulière <ipkiss@via.ecp.fr>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #include "ft2_font.hpp"
  25. #include "ft2_bitmap.hpp"
  26. #include "../utils/ustring.hpp"
  27. #ifdef HAVE_FRIBIDI
  28. #include <fribidi/fribidi.h>
  29. #endif
  30. FT2Font::FT2Font( intf_thread_t *pIntf, const string &rName, int size ):
  31.     GenericFont( pIntf ), m_name( rName ), m_buffer( NULL ), m_size( size ),
  32.     m_lib( NULL ), m_face( NULL )
  33. {
  34. }
  35. FT2Font::~FT2Font()
  36. {
  37.     // Clear the glyph cache
  38.     GlyphMap_t::iterator iter;
  39.     for( iter = m_glyphCache.begin(); iter != m_glyphCache.end(); ++iter )
  40.     {
  41.         FT_Done_Glyph( (*iter).second.m_glyph );
  42.     }
  43.     if( m_face )
  44.     {
  45.         FT_Done_Face( m_face );
  46.     }
  47.     if( m_lib )
  48.     {
  49.         FT_Done_FreeType( m_lib );
  50.     }
  51.     free( m_buffer );
  52. }
  53. bool FT2Font::init()
  54. {
  55.     int err;
  56.     // Initialize libfreetype
  57.     if( FT_Init_FreeType( &m_lib ) )
  58.     {
  59.         msg_Err( getIntf(), "failed to initialize freetype" );
  60.         return false;
  61.     }
  62.     // Open the font
  63.     FILE *file = fopen( m_name.c_str(), "rb" );
  64.     if( file )
  65.     {
  66.         msg_Dbg( getIntf(), "loading font %s", m_name.c_str() );
  67.     }
  68.     else
  69.     {
  70.         msg_Dbg( getIntf(), "unable to open the font %s", m_name.c_str() );
  71.         return false;
  72.     }
  73.     // Get the file size
  74.     fseek( file, 0, SEEK_END );
  75.     int size = ftell( file );
  76.     rewind( file );
  77.     // Allocate the buffer
  78.     m_buffer = malloc( size );
  79.     if( !m_buffer )
  80.         return false;
  81.     // Read the font data
  82.     fread( m_buffer, size, 1, file );
  83.     fclose( file );
  84.     // Load the font from the buffer
  85.     err = FT_New_Memory_Face( m_lib, (const FT_Byte*)m_buffer, size, 0,
  86.                               &m_face );
  87.     if ( err == FT_Err_Unknown_File_Format )
  88.     {
  89.         msg_Err( getIntf(), "unsupported font format (%s)", m_name.c_str() );
  90.         return false;
  91.     }
  92.     else if ( err )
  93.     {
  94.         msg_Err( getIntf(), "error opening font (%s)", m_name.c_str() );
  95.         return false;
  96.     }
  97.     // Select the charset
  98.     if( FT_Select_Charmap( m_face, ft_encoding_unicode ) )
  99.     {
  100.         msg_Err( getIntf(), "font has no UNICODE table (%s)", m_name.c_str() );
  101.         return false;
  102.     }
  103.     // Set the pixel size
  104.     if( FT_Set_Pixel_Sizes( m_face, 0, m_size ) )
  105.     {
  106.         msg_Warn( getIntf(), "cannot set a pixel size of %d (%s)", m_size,
  107.                   m_name.c_str() );
  108.     }
  109.     // Get the font metrucs
  110.     m_height = m_face->size->metrics.height >> 6;
  111.     m_ascender = m_face->size->metrics.ascender >> 6;
  112.     m_descender = m_face->size->metrics.descender >> 6;
  113.     return true;
  114. }
  115. GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
  116.                                     int maxWidth ) const
  117. {
  118.     uint32_t code;
  119.     int n;
  120.     int penX = 0;
  121.     int width1 = 0, width2 = 0;
  122.     int yMin = 0, yMax = 0;
  123.     uint32_t *pString = (uint32_t*)rString.u_str();
  124.     // Check if freetype has been initialized
  125.     if( !m_face )
  126.     {
  127.         return NULL;
  128.     }
  129.     // Get the length of the string
  130.     int len = rString.length();
  131.     // Use fribidi if available
  132. #ifdef HAVE_FRIBIDI
  133.     uint32_t *pFribidiString = NULL;
  134.     if( len > 0 )
  135.     {
  136.         pFribidiString = new uint32_t[len+1];
  137.         FriBidiCharType baseDir = FRIBIDI_TYPE_ON;
  138.         fribidi_log2vis( (FriBidiChar*)pString, len, &baseDir,
  139.                          (FriBidiChar*)pFribidiString, 0, 0, 0 );
  140.         pString = pFribidiString;
  141.     }
  142. #endif
  143.     // Array of glyph bitmaps and position
  144.     FT_BitmapGlyphRec **glyphs = new FT_BitmapGlyphRec*[len];
  145.     int *pos = new int[len];
  146.     // Does the font support kerning ?
  147.     FT_Bool useKerning = FT_HAS_KERNING( m_face );
  148.     int previous = 0;
  149.     // Index of the last glyph when the text is truncated with trailing ...
  150.     int maxIndex = 0;
  151.     // Position of the first trailing dot
  152.     int firstDotX = 0;
  153.     /// Get the dot glyph
  154.     Glyph_t &dotGlyph = getGlyph( '.' );
  155.     // First, render all the glyphs
  156.     for( n = 0; n < len; n++ )
  157.     {
  158.         code = *(pString++);
  159.         // Get the glyph for this character
  160.         Glyph_t &glyph = getGlyph( code );
  161.         glyphs[n] = (FT_BitmapGlyphRec*)(glyph.m_glyph);
  162.         // Retrieve kerning distance and move pen position
  163.         if( useKerning && previous && glyph.m_index )
  164.         {
  165.             FT_Vector delta;
  166.             FT_Get_Kerning( m_face, previous, glyph.m_index,
  167.                             ft_kerning_default, &delta );
  168.             penX += delta.x >> 6;
  169.         }
  170.         pos[n] = penX;
  171.         width1 = penX + glyph.m_size.xMax - glyph.m_size.xMin;
  172.         yMin = __MIN( yMin, glyph.m_size.yMin );
  173.         yMax = __MAX( yMax, glyph.m_size.yMax );
  174.         // Next position
  175.         penX += glyph.m_advance;
  176.         // Save glyph index
  177.         previous = glyph.m_index;
  178.         if( maxWidth != -1 )
  179.         {
  180.             // Check if the truncated text with the '...' fit in the maxWidth
  181.             int curX = penX;
  182.             if( useKerning )
  183.             {
  184.                 FT_Vector delta;
  185.                 FT_Get_Kerning( m_face, glyph.m_index, dotGlyph.m_index,
  186.                                 ft_kerning_default, &delta );
  187.                 curX += delta.x >> 6;
  188.             }
  189.             int dotWidth = 2 * dotGlyph.m_advance +
  190.                 dotGlyph.m_size.xMax - dotGlyph.m_size.xMin;
  191.             if( curX + dotWidth < maxWidth )
  192.             {
  193.                 width2 = curX + dotWidth;
  194.                 maxIndex++;
  195.                 firstDotX = curX;
  196.             }
  197.         }
  198.         else
  199.         {
  200.             // No check
  201.             width2 = width1;
  202.             maxIndex++;
  203.         }
  204.         // Stop here if the text is too large
  205.         if( maxWidth != -1 && width1 > maxWidth )
  206.         {
  207.             break;
  208.         }
  209.     }
  210. #ifdef HAVE_FRIBIDI
  211.     if( len > 0 )
  212.     {
  213.         delete[] pFribidiString;
  214.     }
  215. #endif
  216.     // Adjust the size for vertical padding
  217.     yMax = __MAX( yMax, m_ascender );
  218.     yMin = __MIN( yMin, m_descender );
  219.     // Create the bitmap
  220.     FT2Bitmap *pBmp = new FT2Bitmap( getIntf(), __MIN( width1, width2 ),
  221.                                      yMax - yMin );
  222.     // Draw the glyphs on the bitmap
  223.     for( n = 0; n < maxIndex; n++ )
  224.     {
  225.         FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
  226.         // Draw the glyph on the bitmap
  227.         pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
  228.     }
  229.     // Draw the trailing dots if the text is truncated
  230.     if( maxIndex < len )
  231.     {
  232.         int penX = firstDotX;
  233.         FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)dotGlyph.m_glyph;
  234.         for( n = 0; n < 3; n++ )
  235.         {
  236.             // Draw the glyph on the bitmap
  237.             pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top,
  238.                         color );
  239.             penX += dotGlyph.m_advance;
  240.         }
  241.     }
  242.     delete [] glyphs;
  243.     delete [] pos;
  244.     return pBmp;
  245. }
  246. FT2Font::Glyph_t &FT2Font::getGlyph( uint32_t code ) const
  247. {
  248.     // Try to find the glyph in the cache
  249.     GlyphMap_t::iterator iter = m_glyphCache.find( code );
  250.     if( iter != m_glyphCache.end() )
  251.     {
  252.         return (*iter).second;
  253.     }
  254.     else
  255.     {
  256.         // Add a new glyph in the cache
  257.         Glyph_t &glyph = m_glyphCache[code];
  258.         // Load and render the glyph
  259.         glyph.m_index = FT_Get_Char_Index( m_face, code );
  260.         FT_Load_Glyph( m_face, glyph.m_index, FT_LOAD_DEFAULT );
  261.         FT_Get_Glyph( m_face->glyph, &glyph.m_glyph );
  262.         FT_Glyph_Get_CBox( glyph.m_glyph, ft_glyph_bbox_pixels,
  263.                            &glyph.m_size );
  264.         glyph.m_advance = m_face->glyph->advance.x >> 6;
  265.         FT_Glyph_To_Bitmap( &glyph.m_glyph, ft_render_mode_normal, NULL, 1 );
  266.         return glyph;
  267.     }
  268. }