ftfonts.cpp

Go to the documentation of this file.
00001 // $Id: ftfonts.cpp 1535 2006-07-25 16:50:32Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // implementation file for the FreeType font manager - will compile to an
00099 // empty object file on non-GTK builds
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 DECLARE_SOURCE( "$Revision: 1535 $" );
00106 
00107 // we do not compile any of the functions on non-wxGTK builds
00108 #if defined(__WXGTK__)
00109 
00110 #include "ftfonts.h"
00111 #include "fontman.h"
00112 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "textfuns.h"
00114 #include "oilpanse.h"
00115 
00116 #include <pango/pango.h>
00117 #include <pango/pangofc-font.h>
00118 #include <ft2build.h>
00119 #include FT_FREETYPE_H
00120 #include FT_OUTLINE_H
00121 #include FT_TRUETYPE_TABLES_H
00122 #include FT_TYPE1_TABLES_H
00123 
00124 #ifdef __WXGTK20__
00125 #include <gtk/gtk.h>
00126 extern GtkWidget *wxGetRootWindow();
00127 #endif
00128 
00129 CC_IMPLEMENT_DYNCREATE( FTFontMan, CCObject )
00130 CC_IMPLEMENT_DYNCREATE( FTFont, FontBase )
00131 
00132 #define new CAM_DEBUG_NEW     
00133 
00134 // static class members
00135 FTFontCache* FTFontMan::m_cache = NULL;
00136 
00137 // forward declarations
00138 static PangoContext* GetPangoContext();
00139 static BOOL ToASCII(TCHAR* src, char* buffer, UINT32 len);
00140 static BOOL GetPangoFcFontAndFreeTypeFaceForFaceName(String_64* pFaceName,
00141                                                      PangoFcFont** ppPangoFcFont, FT_Face* ppFreeTypeFace);
00142 
00143 // compare ENUMLOGFONT structures - needed to allow use to use ENUMLOGFONTs as map keys
00144 bool operator<(const ENUMLOGFONT &e1, const ENUMLOGFONT &e2)
00145 {
00146     return e1.elfLogFont.FaceName.CompareTo(e2.elfLogFont.FaceName, FALSE) < 0;
00147 }
00148 
00149 bool operator==(const ENUMLOGFONT &e1, const ENUMLOGFONT &e2)
00150 {
00151     return e1.elfLogFont.FaceName.CompareTo(e2.elfLogFont.FaceName, FALSE) == 0;
00152 }
00153 
00154 /********************************************************************************************
00155 
00156 >   FTFont::FTFont()
00157 
00158     Author:     Martin Wuerthner <xara@mw-software.com>
00159     Created:    18/05/06
00160     Purpose:    Constructor
00161 
00162 ********************************************************************************************/
00163 
00164 FTFont::FTFont(FontClass fc)
00165 {
00166     m_FontClass = fc;
00167 }
00168 
00169 /********************************************************************************************
00170 
00171 >   FTFont::~FTFont()
00172 
00173     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00174     Created:    12/09/95                
00175     Purpose:    destructor for the FTFont class
00176 
00177 ********************************************************************************************/
00178 
00179 FTFont::~FTFont()
00180 {
00181 }
00182 
00183 /********************************************************************************************
00184 
00185 >   void FTFont::Dump()
00186 
00187     Author:     Martin Wuerthner <xara@mw-software.com>
00188     Created:    18/05/06
00189     Purpose:    Dump the contents of this cache entry out
00190 
00191 ********************************************************************************************/
00192 
00193 void FTFont::Dump()
00194 {
00195     FontBase::Dump();
00196     if (m_FontClass == FC_TRUETYPE)
00197         TRACE( _T(" FontClass = TrueType\n"));
00198     else if (m_FontClass == FC_ATM)
00199         TRACE( _T(" FontClass = ATM\n"));
00200     else 
00201         TRACE( _T(" FontClass = <unknown>\n"));
00202 }
00203 
00204 /********************************************************************************************
00205 
00206 >   FTFontMan::FTFontMan() 
00207 
00208     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00209     Created:    12/09/95                
00210     Purpose:    Default constructor
00211 
00212 ********************************************************************************************/
00213 
00214 FTFontMan::FTFontMan()
00215 {
00216 }
00217 
00218 /********************************************************************************************
00219 
00220     static BOOL TTFontMan::IsOkToCall()
00221 
00222     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00223     Created:    01/9/95
00224     Returns:    TRUE if the FreeType manager is actually running and can be used on this OpSys
00225     Purpose:    Determine whether we can make further calls to the TrueType Manager
00226 
00227 ********************************************************************************************/
00228 
00229 BOOL FTFontMan::IsOkToCall()
00230 {
00231     // Currently its always true as this is the wxOil
00232     return TRUE;
00233 }
00234 
00235 // debugging routine to conveniently output a String_64 string
00236 static void DumpString64User(char* user, TCHAR* msg, const String_64* pString)
00237 {
00238     TRACEUSER(user, msg);
00239     TRACEUSER(user, (const TCHAR*)(*pString));  // use TCHAR* conversion operator
00240 }
00241 
00242 /********************************************************************************************
00243 
00244 >   static BOOL FTFontMan::CacheFontCore(String_64* pFontName, BOOL compatible)
00245 
00246     Author:     Martin Wuerthner <xara@mw-software.com>
00247     Created:    06/03/06
00248     Inputs:     pFontName = a pointer to a fontname to find and cache
00249                 compatible = if TRUE, an inexact match can be tolerated, else we want
00250                              an exact match
00251     Outputs:    -
00252     Returns:    TRUE if the font has been cached
00253                 FALSE if not.
00254     Purpose:    This function attempts to cache a font supported by FreeType. It caches
00255                 the font in the kernels font list, and hence can be accessed via 
00256                 FONTMANAGER-> calls
00257 
00258 ********************************************************************************************/
00259 
00260 BOOL FTFontMan::CacheFontCore(String_64* pFontName, BOOL compatible)
00261 {
00262     DumpString64User("wuerthne", _T("FTFontMan::CacheNamedFont"), pFontName);
00263     TRACEUSER("wuerthne", _T("compatible = %d"), compatible);
00264     
00265     PangoContext* pPangoContext = GetPangoContext();
00266     PangoFontMap* pFontMap = pango_context_get_font_map(pPangoContext);
00267     PangoFontDescription* pDescription = pango_font_description_new();
00268 
00269     char ASCIIName[64];   // TYPENOTE: Correct - Pango wants a plain char name
00270     if (!ToASCII((TCHAR*)*pFontName, ASCIIName, 64)) return FALSE;
00271 
00272     // we ask Pango for a font with the given name
00273     pango_font_description_set_family_static(pDescription, ASCIIName);
00274     pango_font_description_set_style(pDescription, PANGO_STYLE_NORMAL);
00275     pango_font_description_set_weight(pDescription, PANGO_WEIGHT_NORMAL);
00276     pango_font_description_set_size(pDescription, 12 * PANGO_SCALE);
00277 
00278     PangoFont* pFont = pango_font_map_load_font(pFontMap, pPangoContext,
00279                                                 pDescription);
00280     pango_font_description_free(pDescription);
00281 
00282     // Pango will always give us some font, no matter whether the font we asked
00283     // for is installed or not, so check what we really got
00284     PangoFontDescription *pRealDesc = pango_font_describe(pFont);
00285 
00286     wxString wxName(pango_font_description_get_family(pRealDesc), wxConvUTF8);
00287     String_64 OurFontName(wxName);
00288     DumpString64User("wuerthne", _T("Got font"), &OurFontName);
00289     TRACEUSER("wuerthne", _T("real font description has style = %d, weight = %d"),
00290               pango_font_description_get_style(pRealDesc), pango_font_description_get_weight(pRealDesc));
00291     pango_font_description_free(pRealDesc);
00292     
00293     // NB - Apart from the following "if" this routine only fails in case of a technical error
00294     //      not because the required font is not present. At the moment, we only check that we
00295     //      got the right font if compatible == FALSE, but we are always called with
00296     //      compatible == TRUE afterwards, so effectively, we always find a font, in the worst
00297     //      case some system default font. That means that the clever Panose matching code is
00298     //      never used because it is only called if both passes (first with compatible == FALSE
00299     //      then with compatible == TRUE) fail. Removing the "!compatible" check on the other
00300     //      hand means that we only allow an exact match and hence cannot make use of fontconfig's
00301     //      font substitution service, most notably using the user's own font substitution rules.
00302 
00303     // check whether the font name is the same as the one we asked for (case-insensitive)
00304     if (!compatible && !pFontName->IsEmpty() && OurFontName.CompareTo(*pFontName, FALSE) != 0) {
00305         // we wanted an exact match, but the names do not match, so do not cache the font
00306         TRACEUSER("wuerthne", _T("Name did not match, so fail"));
00307         return FALSE;
00308     }
00309 
00310     // register the font with the kernel
00311     TRACEUSER("wuerthne", _T("Register font"));
00312     Application* pApp = GetApplication();
00313     FontManager* pFontMan = pApp->GetFontManager();
00314     ENUMLOGFONT OurEnumLogFont;
00315     OurEnumLogFont.elfLogFont.FaceName = OurFontName;
00316     FontClass Class = GetFontClass(OurFontName);
00317     if (Class == FC_TRUETYPE || Class == FC_ATM)
00318     {
00319         pFontMan->SetTempFont(Class, &OurFontName, &OurEnumLogFont);  // kernel copies the ENUMLOGFONT structure
00320         return TRUE;
00321     }
00322     return FALSE;
00323 }
00324 
00325 /********************************************************************************************
00326 
00327 >   static BOOL FTFontMan::CacheNamedFont(String_64* pFontName)
00328 
00329     Author:     Martin Wuerthner <xara@mw-software.com>
00330     Created:    06/03/06
00331     Inputs:     pFontName = a pointer to a fontname to find and cache
00332     Outputs:    -
00333     Returns:    TRUE if the font has been cached
00334                 FALSE if not.
00335     Purpose:    This function attempts to cache a font supported by FreeType. It caches
00336                 the font in the kernels font list, and hence can be accessed via 
00337                 FONTMANAGER-> calls
00338 
00339 ********************************************************************************************/
00340 
00341 BOOL FTFontMan::CacheNamedFont(String_64* pFontName)
00342 {
00343     TRACEUSER("wuerthne", _T("CacheNamedFont %08x"), pFontName);
00344     if (pFontName == NULL) {
00345         // we are called with a NULL pointer from the kernel, so pass an empty string instead,
00346         // which will probably prompt Pango to return its default font
00347         TRACEUSER("wuerthne", _T("CacheNamedFont called with NULL ptr, using emtpy string instead"));
00348         String_64 FontName(_T(""));
00349         return CacheFontCore(&FontName, FALSE);
00350     }
00351     else return CacheFontCore(pFontName, FALSE);
00352 }
00353 
00354 /********************************************************************************************
00355 
00356 >   static BOOL FTFontMan::CacheCompatibleFont(String_64* pFontName)
00357 
00358     Author:     Martin Wuerthner <xara@mw-software.com>
00359     Created:    06/03/06
00360     Inputs:     pFontName = a pointer to a fontname to find and cache
00361     Outputs:    -
00362     Returns:    TRUE if the font has been cached
00363                 FALSE if not.
00364     Purpose:    This function attempts to cache a compatible font
00365 
00366 ********************************************************************************************/
00367 
00368 BOOL FTFontMan::CacheCompatibleFont(String_64* pFontName)
00369 {
00370     return CacheFontCore(pFontName, TRUE);
00371 }
00372 
00373 /********************************************************************************************
00374 
00375 >   static void TTFontMan::ValidateCache()
00376 
00377     Author:     Martin Wuerthner <xara@mw-software.com>
00378     Created:    06/03/06
00379     Purpose:    This function will attempt to recache all FreeType fonts within the kernels
00380                 font manager cache.
00381 
00382 ********************************************************************************************/
00383 
00384 void FTFontMan::ValidateCache()
00385 {
00386     PORTNOTETRACE("text", "FTFontMan::ValidateCache - do nothing");
00387 }
00388 
00389 // ****************
00390 // Font enumeration
00391 // ****************
00392 
00393 /********************************************************************************************
00394 
00395 >   FontClass FTFontMan::GetFontClass(String_64& FaceName)
00396 
00397     Author:     Martin Wuerthner <xara@mw-software.com>
00398     Created:    18/05/06
00399     Inputs:     FaceName - the name of the font we want to enquire about
00400     Purpose:    Checks that the font is installed, is scalable and not a virtual font.
00401                 Reports FC_TRUETYPE or FC_ATM. Reports FC_UNDEFINED if either of the above
00402                 is not true or if the type could not be established.
00403 
00404 ********************************************************************************************/
00405 
00406 FontClass FTFontMan::GetFontClass(String_64& FaceName)
00407 {
00408     FontClass fc = FC_UNDEFINED;
00409     PangoFcFont* pPangoFcFont;
00410     FT_Face pFreeTypeFace;
00411     if (GetPangoFcFontAndFreeTypeFaceForFaceName(&FaceName, &pPangoFcFont, &pFreeTypeFace))
00412     {
00413         // At this stage, we know that the font is scalable, otherwise the above call
00414         // would have returned an error already. Now, check whether this is a virtual
00415         // font (e.g., "Monospace") presented to us by fontconfig. We do that by reading
00416         // back the family name and comparing it to the one we passed.
00417         PangoFontDescription *pRealDesc = pango_font_describe((PangoFont*)pPangoFcFont);
00418         wxString wxName(pango_font_description_get_family(pRealDesc), wxConvUTF8);
00419         String_64 OurFontName(wxName);
00420         pango_font_description_free(pRealDesc);
00421         if (OurFontName.CompareTo(FaceName, FALSE) == 0)
00422         {
00423             PS_FontInfoRec PSRec;
00424             if (FT_Get_PS_Font_Info(pFreeTypeFace, &PSRec) != FT_Err_Invalid_Argument)
00425                 fc = FC_ATM;
00426             else
00427             {
00428                 if (FT_IS_SFNT(pFreeTypeFace)) fc = FC_TRUETYPE;
00429                 else
00430                 {
00431                     // scalable, but not PS-based and not SFNT-based, so not TrueType either
00432                     // ignore this for the time being, but we can probably support this type
00433                     // of font
00434                 }
00435             }
00436         }
00437         pango_fc_font_unlock_face(pPangoFcFont);
00438     }
00439     return fc;
00440 }
00441 
00442 // To enumerate fonts using wxWidgets we need to derive from wxFontEnumerator
00443 // and override the OnFacename method
00444 class ClosestFontEnumerator: public wxFontEnumerator
00445 {
00446 public:
00447     bool OnFacename(const wxString& font);         // TYPENOTE: Correct - overriding wx method
00448 };
00449 
00450 // Our ClosestFontEnumerator calls the fixed callback routine in FontMan to report the font
00451 
00452 
00453 /********************************************************************************************
00454 
00455 >   bool ClosestFontEnumerator::OnFacename(const wxString& font)
00456 
00457     Author:     Martin Wuerthner <xara@mw-software.com>
00458     Created:    19/04/06
00459     Inputs:     font - the Facename of an enumerated font
00460     Purpose:    Callback function for font enumeration - passes call on to the kernel Panose
00461                 Panose matcher
00462 
00463 ********************************************************************************************/
00464 bool ClosestFontEnumerator::OnFacename(const wxString& font)
00465 {
00466     // we need to pass a ENUMLOGFONT structure to the kernel
00467     // we can pass pointers to transient structures - the kernel copies the data if it is the
00468     // best match so far
00469     // We can only handle names that have less than 64 characters - see MyFontEnumerator::OnFacename
00470     if (font.length() > 63) return TRUE;
00471     String_64 OurFontName = font;
00472     ENUMLOGFONT OurEnumLogFont;
00473     OurEnumLogFont.elfLogFont.FaceName = font;
00474     FontManager* pFontMan = GetApplication()->GetFontManager();
00475     return pFontMan->FindClosestFontFullTry(FTFontMan::GetFontClass(OurFontName),
00476                                             &OurEnumLogFont.elfLogFont.FaceName, &OurEnumLogFont);
00477 }
00478 
00479 /********************************************************************************************
00480 
00481 >   static void FTFontMan::FindClosestFont()
00482 
00483     Author:     Martin Wuerthner <xara@mw-software.com>
00484     Created:    19/04/06
00485     Purpose:    Enumerates all the fonts reporting each to the Panose matcher in FontMan.
00486 
00487 ********************************************************************************************/
00488 
00489 void FTFontMan::FindClosestFont()
00490 {
00491     // use wxWidgets to enumerate all font families
00492     TRACEUSER("wuerthne", _T("FTFonMan::FindClosestFont"));
00493     ClosestFontEnumerator WxEnumerator;
00494     WxEnumerator.EnumerateFacenames();  
00495 }
00496 
00497 // To enumerate fonts using wxWidgets we need to derive from wxFontEnumerator
00498 // and override the OnFacename method
00499 class MyFontEnumerator: public wxFontEnumerator
00500 {
00501 public:
00502     enum CacheAction { FillCache, UpdateCache };
00503     MyFontEnumerator(CacheAction action) { m_action = action; }
00504     bool OnFacename(const wxString& font);         // TYPENOTE: Correct - overriding wx method
00505 private:
00506     CacheAction m_action;
00507 };
00508 
00509 /********************************************************************************************
00510 
00511 >   bool MyFontEnumerator::OnFacename(const wxString& font)
00512 
00513     Author:     Martin Wuerthner <xara@mw-software.com>
00514     Created:    06/03/06
00515     Inputs:     font - the Facename of an enumerated font
00516     Purpose:    Callback function for font enumeration - fills/updates the font list cache
00517 
00518 ********************************************************************************************/
00519 
00520 bool MyFontEnumerator::OnFacename(const wxString& font)
00521 {
00522     // we need to pass an ENUMLOGFONT structure to the kernel
00523     // TRACEUSER("wuerthne", _T("OnFacename %s"), (const TCHAR*)font);
00524 
00525     // We can only handle names that have less than 64 characters. Longer
00526     // names are not sensible but there are silly fonts out there that have
00527     // names exceeding our limit (even though the one font that highlighted
00528     // this problem seemed to have its copyright message reported as the name
00529     // which would look silly on the menu anyway). Truncating the name does
00530     // not make any sense because we would not be able to handle it later on,
00531     // so the best we can do is to silently ignore the font.
00532     if (font.length() > 63) return TRUE;
00533     String_64 OurFontName = font;
00534     
00535     ENUMLOGFONT OurEnumLogFont;
00536     OurEnumLogFont.elfLogFont.FaceName = OurFontName;
00537 
00538     if (m_action == FillCache)
00539     {
00540         // first of all, add the font to our cache list - we do that even with fonts that
00541         // we cannot use, so we can easily see when the available font set has changed
00542         FTFontMan::AddFontToCache(OurEnumLogFont);
00543         // TRACEUSER("wuerthne", _T("%s added to font list cache"), (TCHAR*)OurFontName);
00544     }
00545     else if (m_action == UpdateCache)
00546     {
00547         // check whether the font is in the cache already
00548         // if it is, update its Referenced field as a side-effect
00549         if (!FTFontMan::FontIsCached(OurEnumLogFont))
00550         {
00551             // not yet cached, so add it now
00552             FTFontMan::AddFontToCache(OurEnumLogFont);
00553             TRACEUSER("wuerthne", _T("%s added to font list cache"), (TCHAR*)OurFontName);
00554         }
00555     }
00556     return TRUE;
00557 }
00558 
00559 /********************************************************************************************
00560 
00561 >   FTFontMan::FontIsCached(ENUMLOGFONT &EnumLogFont)
00562 
00563     Author:     Martin Wuerthner <xara@mw-software.com>
00564     Created:    19/05/06
00565     Inputs:     EnumLogFont - the face name wrapped in a LOGFONT/ENUMLOGFONT structure
00566     Returns:    TRUE if the font is in the cache
00567     Purpose:    Check whether the given font is in the font list cache
00568                 If it is, update its Referenced field as a side-effect
00569 
00570 ********************************************************************************************/
00571 
00572 BOOL FTFontMan::FontIsCached(ENUMLOGFONT &EnumLogFont)
00573 {
00574     FTFontCache::iterator it = m_cache->find(EnumLogFont);
00575     if (it != m_cache->end())
00576     {
00577         (*it).second.m_Referenced = TRUE;
00578         return TRUE;
00579     }
00580     return FALSE;
00581 }
00582 
00583 /********************************************************************************************
00584 
00585 >   FTFontMan::AddFontToCache(ENUMLOGFONT &EnumLogFont)
00586 
00587     Author:     Martin Wuerthner <xara@mw-software.com>
00588     Created:    19/05/06
00589     Inputs:     EnumLogFont - the face name wrapped in a LOGFONT/ENUMLOGFONT structure
00590     Purpose:    Add the given font to the font list cache
00591 
00592 ********************************************************************************************/
00593 
00594 void FTFontMan::AddFontToCache(ENUMLOGFONT &EnumLogFont)
00595 {
00596     FontClass OurFontClass = FTFontMan::GetFontClass(EnumLogFont.elfLogFont.FaceName);
00597     FTFontCacheEntry OurEntry(OurFontClass, TRUE);
00598     (*m_cache)[EnumLogFont] = OurEntry;
00599 }
00600 
00601 /********************************************************************************************
00602 
00603 >   FTFontMan::UpdateCache()
00604 
00605     Author:     Martin Wuerthner <xara@mw-software.com>
00606     Created:    19/05/06
00607     Inputs:     -
00608     Purpose:    Update the font list cache to reflect the wxWidgets font enumeration
00609 
00610 ********************************************************************************************/
00611 
00612 void FTFontMan::UpdateCache()
00613 {
00614     MyFontEnumerator::CacheAction action;
00615     if (m_cache)
00616     {
00617         // we already have a cache, so just update it incrementally
00618         action = MyFontEnumerator::UpdateCache;
00619         // we want to purge entries that are no longer installed, so mark all entries as unreferenced
00620         // the cache update step will mark all the fonts it finds as Referenced
00621         for (FTFontCache::iterator it = m_cache->begin(); it != m_cache->end(); ++it)
00622             (*it).second.m_Referenced = FALSE;
00623     }
00624     else
00625     {
00626         // initial run
00627         m_cache = new FTFontCache;
00628         action = MyFontEnumerator::FillCache;
00629     }
00630     MyFontEnumerator FontEnumerator(action);
00631     FontEnumerator.EnumerateFacenames();
00632 
00633     if (action == MyFontEnumerator::UpdateCache) {
00634         // delete all fonts that have been deinstalled since we last checked
00635         for (FTFontCache::iterator it = m_cache->begin(); it != m_cache->end();)
00636         {
00637             if (!(*it).second.m_Referenced)
00638             {
00639                 TRACEUSER("wuerthne", _T("%s removed from font list cache"),
00640                           (const TCHAR*)((*it).first.elfLogFont.FaceName));
00641                 // NB - it++ first increments the iterator, then returns the iterator
00642                 //      to the current element, which is then deleted - this is safe,
00643                 //      as opposed to first deleting and then incrementing
00644                 m_cache->erase(it++);
00645             }
00646             else
00647             {
00648                 ++it;       
00649             }
00650         }
00651     }
00652 }
00653 
00654 /********************************************************************************************
00655 
00656 >   static void FTFontMan::EnumAllFonts(OILEnumFonts* pOilEnumerator)
00657 
00658     Author:     Martin Wuerthner <xara@mw-software.com>
00659     Created:    06/03/06
00660     Inputs:     pOilEnumerator = A pointer to an object to call back.
00661     Purpose:    Gives the kernel a way of enumerating fonts itself
00662 
00663 ********************************************************************************************/
00664 
00665 void FTFontMan::EnumAllFonts(OILEnumFonts* pOilEnumerator)
00666 {
00667     // use wxWidgets to enumerate all font families
00668     TRACEUSER("wuerthne", _T("FTFontMan::EnumAllFonts"));
00669 
00670     // we cache the results so we first check whether the cache can still be used
00671     UpdateCache();
00672 
00673     // now, simply return the information from the cache
00674     BOOL go_on = TRUE;
00675     for (FTFontCache::iterator it = m_cache->begin(); go_on && it != m_cache->end(); ++it)
00676     {
00677         FontClass OurFontClass = (*it).second.m_Class;
00678         if (OurFontClass == FC_TRUETYPE || OurFontClass == FC_ATM)
00679         {
00680             ENUMLOGFONT EnumLogFont = (*it).first;
00681             go_on = pOilEnumerator->NewFont(OurFontClass, &EnumLogFont);
00682         }
00683     }
00684     TRACEUSER("wuerthne", _T("FTFontMan::EnumAllFonts done"));
00685 }
00686 
00687 /********************************************************************************************
00688 
00689 >   FontBase* FTFontMan::CreateNewFont(String_64* pFontName)
00690 
00691     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00692     Created:    12/9/95
00693     Inputs:     pFontName = a pointer to a fontname
00694     Returns:    NULL if no FreeType font structure has been created
00695                 A pointer to a FreeType font structure if successfull.
00696     Purpose:    This function attempts to create a font instance and will be called by
00697                 the font manager when new fonts are added.
00698 
00699 ********************************************************************************************/
00700 
00701 FTFont* FTFontMan::CreateNewFont(String_64* pFontName, FontClass Class)
00702 {
00703     DumpString64User("wuerthne", _T("FTFontMan::CreateNewFont"), pFontName);
00704     FTFont* pFont = new FTFont(Class);
00705     if (pFont && !pFont->Initialise(pFontName))
00706     {
00707         delete pFont;
00708         return NULL;
00709     }
00710     return pFont;
00711 }
00712 
00713 /********************************************************************************************
00714 
00715 >   static String_64* GetFacenameFromCharDesc(CharDescription &ChDesc)
00716 
00717     Author:     Martin Wuerthner <xara@mw-software.com>
00718     Created:    06/03/06
00719     Inputs:     ChDesc - a Kernel character description
00720     Outputs:    -
00721     Returns:    The Facename of the referenced font
00722                 NULL if the found could not be found (e.g., not cached - should not happen)
00723     Purpose:    Extract the name of the font referenced by a Kernel character description
00724 
00725 ********************************************************************************************/
00726 
00727 static String_64* GetFacenameFromCharDesc(CharDescription &ChDesc)
00728 {
00729     // get LogFont from face handle in char descriptor
00730     WORD            FaceHandle    = ChDesc.GetTypefaceHandle();
00731     CachedFontItem* pFontDataItem = FONTMANAGER->GetFont(FaceHandle);
00732     ERROR2IF(pFontDataItem==NULL,FALSE,"FTFontMan::GetCharOutline could not find cached font");
00733     ENUMLOGFONT*    pEnumLogFont  = pFontDataItem->GetEnumLogFont();
00734     ERROR2IF(pEnumLogFont==NULL,FALSE,"FTFontMan::GetCharOutline could not find cached EnumLogFont");
00735     // DumpString64User("wuerthne", _T("GetFacenameFromCharDesc returning"), &pEnumLogFont->elfLogFont.FaceName);
00736     return &pEnumLogFont->elfLogFont.FaceName;
00737 }
00738 
00739 // convert a possibly unicoded ASCII string into a plain ASCII string
00740 
00741 /********************************************************************************************
00742 
00743 >   static BOOL ToASCII(TCHAR* src, char* buffer, UINT32 len)
00744 
00745     Author:     Martin Wuerthner <xara@mw-software.com>
00746     Created:    06/03/06
00747     Inputs:     src - a pointer to a TCHAR* string
00748     Outputs:    The converted string in the char* buffer
00749     Returns:    TRUE if the string was converted OK
00750                 FALSE if not (e.g., buffer overflow, invalid character found)
00751     Purpose:    Convert a possibly unicoded ASCII string into a plain ASCII string
00752 
00753 ********************************************************************************************/
00754 
00755 static BOOL ToASCII(TCHAR* src, char* buffer, UINT32 len)    // TYPENOTE: correct - we need to use char
00756 {
00757     char* dest = buffer;
00758     while(*src >= 32 && len)
00759     {
00760         TCHAR b = *src++;
00761         if (b > 127)
00762         {
00763             // outside ASCII range, so fail
00764             *dest = '\0';
00765             return FALSE;
00766         }
00767         *dest++ = b;
00768         len--;
00769     }
00770     if (!len)
00771     {
00772         // buffer overflow, so fail
00773         dest[-1] = '\0';
00774         return FALSE;
00775     }
00776     else {
00777         *dest = '\0';
00778         return TRUE;
00779     }
00780 }
00781 
00782 /********************************************************************************************
00783 
00784 >   static PangoFont* GetPangoFontForFaceName(String_64* pFaceName)
00785 
00786     Author:     Martin Wuerthner <xara@mw-software.com>
00787     Created:    19/04/06
00788     Inputs:     pFaceName - pointer to a face name
00789     Outputs:    -
00790     Returns:    a pointer to the corresponding PangoFont structure
00791                 may return NULL if the font could not be loaded
00792                 the Pango documentation does not state anything about how to or having to
00793                 free the PangoFont object, so we assume it is managed by the FontMap
00794     Purpose:    return a PangoFont for a particular font face
00795 
00796 ********************************************************************************************/
00797 
00798 static PangoFont* GetPangoFontForFaceName(String_64* pFaceName, BOOL IsBold, BOOL IsItalic)
00799 {
00800     // DumpString64User("wuerthne", _T("FTFontMan::GetPangoFontForFaceName"), pFaceName);
00801 
00802     char ASCIIFaceName[64]; // TYPENOTE: correct (needed as parameter to Pango)
00803     if (!ToASCII(*pFaceName, ASCIIFaceName, 64)) return NULL;
00804 
00805     PangoContext* pPangoContext = GetPangoContext();
00806     ERROR2IF(pPangoContext==NULL,NULL,"FTFontMan::GetPangoFontForCharDesc failed to get PangoContext");
00807     PangoFontMap* pFontMap = pango_context_get_font_map(pPangoContext);
00808     ERROR2IF(pPangoContext==NULL,NULL,"FTFontMan::GetPangoFontForCharDesc failed to get PangoFontMan");
00809 
00810     PangoFontDescription* pDescription = pango_font_description_new();
00811     pango_font_description_set_family_static(pDescription, ASCIIFaceName);
00812     pango_font_description_set_style(pDescription, IsItalic ? PANGO_STYLE_ITALIC :  PANGO_STYLE_NORMAL);
00813     pango_font_description_set_weight(pDescription, IsBold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
00814     pango_font_description_set_size(pDescription, 12 * PANGO_SCALE);  // arbitrary, we get unscaled outlines later
00815 
00816     PangoFont* pFont = pango_font_map_load_font(pFontMap, pPangoContext, pDescription);
00817     pango_font_description_free(pDescription);
00818     if (!PANGO_IS_FONT(pFont)) return NULL;
00819     return pFont;
00820 }
00821 
00822 /********************************************************************************************
00823 
00824 >   static PangoFont* GetPangoFontForCharDesc(CharDescription &ChDesc)
00825 
00826     Author:     Martin Wuerthner <xara@mw-software.com>
00827     Created:    06/03/06
00828     Inputs:     ChDesc - a Kernel character description
00829     Outputs:    -
00830     Returns:    a pointer to the corresponding PangoFont structure
00831                 may return NULL if the font could not be loaded
00832                 the Pango documentation does not state anything about how to or having to
00833                 free the PangoFont object, so we assume it is managed by the FontMap
00834     Purpose:    return a PangoFont for the font referenced by ChDesc
00835 
00836 ********************************************************************************************/
00837 
00838 static PangoFont* GetPangoFontForCharDesc(CharDescription &ChDesc)
00839 {
00840     String_64* pFaceName = GetFacenameFromCharDesc(ChDesc);
00841     return GetPangoFontForFaceName(pFaceName, ChDesc.GetBold(), ChDesc.GetItalic());
00842 }
00843 
00844 // Get the application's Pango context - in wxGTK we already have one since wxGTK
00845 // itself uses Pango.
00846 
00847 /********************************************************************************************
00848 
00849 >   static PangoContext* GetPangoContext()
00850 
00851     Author:     Martin Wuerthner <xara@mw-software.com>
00852     Created:    06/03/06
00853     Inputs:     -
00854     Outputs:    -
00855     Returns:    the PangoContext of the application
00856     Purpose:    Get access to the application's PangoContext - as wxWidgets does it
00857 
00858 ********************************************************************************************/
00859 
00860 static PangoContext* GetPangoContext()
00861 {
00862     // The magic code to get the Pango context for wxGTK2 and below is copied
00863     // from wxWidgets/unix/fontenum.cpp
00864     PangoContext *pPangoContext =
00865 #ifdef __WXGTK20__
00866         gtk_widget_get_pango_context( wxGetRootWindow() );
00867 #elif defined(__WXGTK__)
00868         wxTheApp->GetPangoContext();
00869 #else
00870         #error "Sorry, this source file can only be compiled for wxGTK"
00871 #endif
00872         return pPangoContext;
00873 }
00874 
00875 /********************************************************************************************
00876 
00877 >   static INT32 ScaleToDefaultHeight(INT32 coord, INT32 DesignSize)
00878 
00879     Author:     Martin Wuerthner <xara@mw-software.com>
00880     Created:    06/03/06
00881     Inputs:     coord - the coordinate to scale
00882                 DesignSize - the design size of the font
00883     Outputs:    -
00884     Returns:    the scaled size
00885     Purpose:    Scale a coordinate according to the font's design size
00886 
00887 ********************************************************************************************/
00888 
00889 static INT32 ScaleToDefaultHeight(INT32 coord, INT32 DesignSize)
00890 {
00891     return coord * TextManager::GetDefaultHeight() / DesignSize;
00892 }
00893 
00894 /********************************************************************************************
00895 
00896 >   static BOOL GetPangoFcFontAndFreeTypeFaceForPangoFont(PangoFont* pFont,
00897                                                      PangoFcFont** ppPangoFcFont, FT_Face* ppFreeTypeFace)
00898 
00899     Author:     Martin Wuerthner <xara@mw-software.com>
00900     Created:    19/04/06
00901     Inputs:     pFont - pointer to a PangoFont
00902     Outputs:    a pointer to the PangoFcFont is stored in ppPangoFcFont
00903                 a pointer to the FreeType font is stored in ppFreeTypeFace
00904                 When finished with the font and face, the client has to call
00905                 pango_fc_font_unlock_face(*ppPangoFcFont) to free the font
00906     Returns:    TRUE if the font descriptors have been returned correctly
00907                 FALSE if not.
00908     Purpose:    Get a PangoFc font and a FreeType face for a Pango font
00909 
00910 ********************************************************************************************/
00911 
00912 static BOOL GetPangoFcFontAndFreeTypeFaceForPangoFont(PangoFont* pFont, PangoFcFont** ppPangoFcFont, FT_Face* ppFreeTypeFace)
00913 {
00914     if (!pFont) return FALSE;
00915 
00916     // We need to get at the underlying FreeType information, which only works for
00917     // Pango backends that are based on FreeType. The common factor for those
00918     // backends is that they are based on FontConfig, so we check whether the font
00919     // we got is indeed managed by a FontConfig-based backend (Xft or Cairo).
00920     if (!PANGO_IS_FC_FONT(pFont))
00921     {
00922         ERROR2(FALSE, "FTFontMan: font is not a PangoFcFont!");
00923     }
00924 
00925     // OK, so we can safely cast to PangoFcFont
00926     PangoFcFont* pFcFont = (PangoFcFont*)pFont;
00927 
00928     // The magic call to get at the underlying FreeType data
00929     // We must unlock this before returning!
00930     FT_Face pFreeTypeFace = pango_fc_font_lock_face(pFcFont);
00931     if (!pFreeTypeFace) {
00932         pango_fc_font_unlock_face(pFcFont);
00933         return FALSE;
00934     }
00935 
00936     // The default charmap is always unicode if present, but we may
00937     // have a symbol font which we may want to drive in symbol mode.
00938     // Check whether there is just an Adobe custom or MS Symbol encoding
00939     // in addition to the synthesized unicode charmap and if so, use that
00940     // instead.
00941     FT_CharMap pCustomCharmap = NULL;
00942     for (INT32 mapnum = 0; mapnum < pFreeTypeFace->num_charmaps; mapnum++)
00943     {
00944         FT_CharMap pThisMap = pFreeTypeFace->charmaps[mapnum];
00945         if (pThisMap->encoding == FT_ENCODING_ADOBE_CUSTOM
00946             || pThisMap->encoding == FT_ENCODING_MS_SYMBOL) {
00947             pCustomCharmap = pThisMap;
00948             // we go on checking the other encodings
00949         }
00950         else if (pThisMap->encoding != FT_ENCODING_UNICODE) {
00951             // there is an encoding that is neither a custom one
00952             // nor a Unicode encoding, so this is a language font
00953             pCustomCharmap = NULL;
00954             break;
00955         }
00956     }
00957     if (pCustomCharmap) FT_Set_Charmap(pFreeTypeFace, pCustomCharmap);
00958     
00959     // We do not support non-scalable fonts - do not report an error, this routine
00960     // is called during font enumeration and simply returns FALSE in this case
00961     if (!FT_IS_SCALABLE(pFreeTypeFace))
00962     {
00963         pango_fc_font_unlock_face(pFcFont);
00964         return FALSE;
00965     }
00966     *ppPangoFcFont = pFcFont;
00967     *ppFreeTypeFace = pFreeTypeFace;
00968     return TRUE;
00969 }
00970 
00971 /********************************************************************************************
00972 
00973 >   static BOOL GetPangoFcFontAndFreeTypeFaceForCharDesc(CharDescription& ChDesc,
00974                                                      PangoFcFont** ppPangoFcFont, FT_Face* ppFreeTypeFace)
00975 
00976     Author:     Martin Wuerthner <xara@mw-software.com>
00977     Created:    06/03/06
00978     Inputs:     ChDesc - a Kernel character description
00979     Outputs:    a pointer to the PangoFcFont is stored in ppPangoFcFont
00980                 a pointer to the FreeType font is stored in ppFreeTypeFace
00981                 When finished with the font and face, the client has to call
00982                 pango_fc_font_unlock_face(*ppPangoFcFont) to free the font
00983     Returns:    TRUE if the font descriptors have been returned correctly
00984                 FALSE if not.
00985     Purpose:    Get a PangoFc font and a FreeType face for a char description
00986 
00987 ********************************************************************************************/
00988 
00989 static BOOL GetPangoFcFontAndFreeTypeFaceForCharDesc(CharDescription& ChDesc,
00990                                                      PangoFcFont** ppPangoFcFont, FT_Face* ppFreeTypeFace)
00991 {
00992     // We extract the font description from ChDesc and find a PangoFont for it
00993     PangoFont* pFont = GetPangoFontForCharDesc(ChDesc);
00994     return GetPangoFcFontAndFreeTypeFaceForPangoFont(pFont, ppPangoFcFont, ppFreeTypeFace);
00995 }
00996 
00997 /********************************************************************************************
00998 
00999 >   static BOOL GetPangoFcFontAndFreeTypeFaceForFaceName(String_64* pFaceName,
01000                                                      PangoFcFont** ppPangoFcFont, FT_Face* ppFreeTypeFace)
01001 
01002     Author:     Martin Wuerthner <xara@mw-software.com>
01003     Created:    19/04/06
01004     Inputs:     pFaceName - pointer to a face name
01005     Outputs:    a pointer to the PangoFcFont is stored in ppPangoFcFont
01006                 a pointer to the FreeType font is stored in ppFreeTypeFace
01007                 When finished with the font and face, the client has to call
01008                 pango_fc_font_unlock_face(*ppPangoFcFont) to free the font
01009     Returns:    TRUE if the font descriptors have been returned correctly
01010                 FALSE if not.
01011     Purpose:    Get a PangoFc font and a FreeType face for a particular font face
01012 
01013 ********************************************************************************************/
01014 
01015 static BOOL GetPangoFcFontAndFreeTypeFaceForFaceName(String_64* pFaceName,
01016                                                      PangoFcFont** ppPangoFcFont, FT_Face* ppFreeTypeFace)
01017 {
01018     PangoFont* pFont = GetPangoFontForFaceName(pFaceName, FALSE, FALSE);
01019     return GetPangoFcFontAndFreeTypeFaceForPangoFont(pFont, ppPangoFcFont, ppFreeTypeFace);
01020 }
01021 
01022 // *********************************
01023 // Text Character Outline Extraction
01024 // *********************************
01025 
01026 // the state we have to keep during outline decomposition
01027 typedef struct OutlineDecompositionState {
01028     BOOL IsFirstMove;        // TRUE if we have not generated a Move command yet
01029     INT32 DesignSize;        // the DesignSize of the font (for scaling)
01030     FT_Vector CurrentPoint;  // we need to keep track of the current point for quadratic curve conversion
01031 } DecompState;
01032 
01033 // callback functions for FreeType outline decomposition - we need to use return type "int"   // TYPENOTE: Correct
01034 // rather than any of our types to conform to the FreeType interface
01035 
01036 // Unfortunately, the FreeType interface was changed for version 2.2 - the FT_Vector parameters
01037 // are now const.
01038 #if FREETYPE_MAJOR >= 2
01039 #if FREETYPE_MINOR >= 2
01040 /* new interface, make parameters const */
01041 #define FREETYPE_CALLBACK_CONST const
01042 #else
01043 #define FREETYPE_CALLBACK_CONST
01044 #endif
01045 #else
01046 #error "XaraLX requires FreeType 2"
01047 #endif
01048 
01049 /********************************************************************************************
01050 
01051 >   static int AddMoveTo(FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)  // TYPENOTE: Correct
01052 
01053     Author:     Martin Wuerthner <xara@mw-software.com>
01054     Created:    28/03/06
01055     Inputs:     to - target point of move
01056                 user - pointer to our decomposition state
01057     Outputs:    -
01058     Returns:    0 for success, non-0 for failure
01059     Purpose:    Callback to emit a move command
01060 
01061 ********************************************************************************************/
01062 
01063 static int AddMoveTo(FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)  // TYPENOTE: Correct - FreeType callback interface
01064 {
01065     DecompState* state = (DecompState*)user;
01066     if (!state->IsFirstMove) {
01067         // this is the beginning of a subsequent contour (subpath), so close the current one
01068         // TRACEUSER("wuerthne", _T("calling ClosePath()"));
01069         OILFontMan::ClosePath();
01070     }
01071     POINT p;
01072     p.x = ScaleToDefaultHeight(to->x, state->DesignSize);
01073     p.y = ScaleToDefaultHeight(to->y, state->DesignSize);
01074     // TRACEUSER("wuerthne", _T("calling MoveTo(%d,%d)"), p.x, p.y);
01075     OILFontMan::AddMoveTo(p);
01076     state->CurrentPoint = *to;
01077     state->IsFirstMove = FALSE;
01078     return 0;
01079 }
01080 
01081 
01082 /********************************************************************************************
01083 
01084 >   static int AddLineTo(FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)   // TYPENOTE: Correct
01085 
01086     Author:     Martin Wuerthner <xara@mw-software.com>
01087     Created:    28/03/06
01088     Inputs:     to - endpoint of line
01089                 user - pointer to our decomposition state
01090     Outputs:    -
01091     Returns:    0 for success, non-0 for failure
01092     Purpose:    Callback to emit a line command
01093 
01094 ********************************************************************************************/
01095 
01096 static int AddLineTo(FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)       // TYPENOTE: Correct - FreeType callback interface
01097 {
01098     DecompState* state = (DecompState*)user;
01099     POINT p;
01100     p.x = ScaleToDefaultHeight(to->x, state->DesignSize);
01101     p.y = ScaleToDefaultHeight(to->y, state->DesignSize);
01102     // TRACEUSER("wuerthne", _T("calling LineTo(%d,%d)"), p.x, p.y);
01103     OILFontMan::AddLineTo(p);
01104     state->CurrentPoint = *to;
01105     return 0;
01106 }
01107 
01108 /********************************************************************************************
01109 
01110 >   static int AddConicTo(FREETYPE_CALLBACK_CONST FT_Vector* control,         // TYPENOTE: Correct
01111                           FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)
01112 
01113     Author:     Martin Wuerthner <xara@mw-software.com>
01114     Created:    28/03/06
01115     Inputs:     control - control point of quadratic Bezier curve
01116                 to - endpoint of curve
01117                 user - pointer to our decomposition state
01118     Outputs:    -
01119     Returns:    0 for success, non-0 for failure
01120     Purpose:    Callback to deal with a quadratic Bezier curve
01121 
01122 ********************************************************************************************/
01123 
01124 static int AddConicTo(FREETYPE_CALLBACK_CONST FT_Vector* control,             // TYPENOTE: Correct - FreeType callback interface
01125                       FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)
01126 {
01127     DecompState* state = (DecompState*)user;
01128 
01129     // OK, we got a quadratic curve but we can only handle cubic ones, so convert
01130     // from quadratic to cubic - fortunately, this is lossless. The following
01131     // algorithm (with a major error) was found in an article in comp.lang.postscript
01132     // and, corrected, reads as follows:
01133     //
01134     // Let (xb, yb) and (xe, ye) be the beginning and ending coordinates of
01135     // the Bezier curve, respectively.  Let (xq1, yq1) be the interior control
01136     // point for the quadratric Bezier curve. Our task is to determine
01137     // (xc1, yc1) and (xc2, yc), the interior control points of the cubic
01138     // Bezier segment which matches the quadratic segment.
01139     // 
01140     // Solving the algebra led to this conversion:
01141     //   xc1 = (xb + 2 * xq1) / 3        yc1 = (yb + 2 * yq1) / 3
01142     //   xc2 = (2 * xq1 + xe) / 3        yc2 = (2 * yq1 + ye) / 3
01143 
01144     POINT p1;
01145     POINT p2;
01146     POINT p3;
01147     p3.x = ScaleToDefaultHeight(to->x, state->DesignSize);
01148     p3.y = ScaleToDefaultHeight(to->y, state->DesignSize);
01149 
01150     // we need the starting point, which we can find in the current state
01151     p1.x = ScaleToDefaultHeight((state->CurrentPoint.x + 2 * control->x) / 3, state->DesignSize);
01152     p1.y = ScaleToDefaultHeight((state->CurrentPoint.y + 2 * control->y) / 3, state->DesignSize);
01153 
01154     p2.x = ScaleToDefaultHeight((2 * control->x + to->x) / 3, state->DesignSize);
01155     p2.y = ScaleToDefaultHeight((2 * control->y + to->y) / 3, state->DesignSize);
01156     // TRACEUSER("wuerthne", _T("q calling BezierTo(%d,%d)(%d,%d)(%d,%d)"), p1.x, p1.y, p2.x, p2.y, p3.x ,p3.y);
01157     OILFontMan::AddBezierTo(p1, p2, p3);
01158     state->CurrentPoint = *to;
01159     return 0;
01160 }
01161 
01162 /********************************************************************************************
01163 
01164 >   static int AddCubicTo(FREETYPE_CALLBACK_CONST FT_Vector* control1,     // TYPENOTE: Correct
01165                           FREETYPE_CALLBACK_CONST FT_Vector* control2,
01166                           FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)
01167 
01168     Author:     Martin Wuerthner <xara@mw-software.com>
01169     Created:    28/03/06
01170     Inputs:     control1, control2 - control points of cubic Bezier curve
01171                 to - endpoint of curve
01172                 user - pointer to our decomposition state
01173     Outputs:    -
01174     Returns:    0 for success, non-0 for failure
01175     Purpose:    Callback to deal with a cubic Bezier curve
01176 
01177 ********************************************************************************************/
01178 
01179 static int AddCubicTo(FREETYPE_CALLBACK_CONST FT_Vector *control1,          // TYPENOTE: Correct
01180                       FREETYPE_CALLBACK_CONST FT_Vector *control2,
01181                       FREETYPE_CALLBACK_CONST FT_Vector* to, void* user)
01182 {
01183     DecompState* state = (DecompState*)user;
01184     POINT p1;
01185     POINT p2;
01186     POINT p3;
01187     p1.x = ScaleToDefaultHeight(control1->x, state->DesignSize);
01188     p1.y = ScaleToDefaultHeight(control1->y, state->DesignSize);
01189     p2.x = ScaleToDefaultHeight(control2->x, state->DesignSize);
01190     p2.y = ScaleToDefaultHeight(control2->y, state->DesignSize);
01191     p3.x = ScaleToDefaultHeight(to->x, state->DesignSize);
01192     p3.y = ScaleToDefaultHeight(to->y, state->DesignSize);
01193     // TRACEUSER("wuerthne", _T("c calling BezierTo(%d,%d)(%d,%d)(%d,%d)"), p1.x, p1.y, p2.x, p2.y, p3.x ,p3.y);
01194     OILFontMan::AddBezierTo(p1, p2, p3);
01195     state->CurrentPoint = *to;
01196     return 0;
01197 }
01198 
01199 /********************************************************************************************
01200 
01201 >   BOOL FTFontMan::GetCharOutline(CharDescription& ChDesc, 
01202                                    DocCoord** ppCoords,
01203                                    PathVerb** ppVerbs,
01204                                    UINT32* pNumCoords,
01205                                    wxDC* pDC)
01206 
01207     Author:     Martin Wuerthner <xara@mw-software.com>
01208     Created:    06/03/06
01209     Inputs:     ChDesc  = description of char
01210                 pDC     = (possible) pointer to a DC (for optimisation) defaults to NULL
01211     Outputs:    ppCoords    = pointer to path coords buffer
01212                 ppVerbs     = pointer to path verbs buffer
01213                 pNumCoords  = number of elements in path
01214     Returns:    FALSE if unable to generate the character outline
01215     Purpose:    Get the path associated with a given character
01216 
01217 ********************************************************************************************/
01218 
01219 BOOL FTFontMan::GetCharOutline(CharDescription& ChDesc, 
01220                                DocCoord** ppCoords,
01221                                PathVerb** ppVerbs,
01222                                UINT32* pNumCoords,
01223                                wxDC* pDC)
01224 {
01225     // TRACEUSER("wuerthne", _T("FTFontMan::GetCharOutline %04x"), ChDesc.GetCharCode());
01226     // Check some input parameters
01227     ERROR2IF(ppCoords==NULL,FALSE,"FTFontMan::GetCharOutline ppCoords==NULL");
01228     ERROR2IF(ppVerbs==NULL,FALSE,"FTFontMan::GetCharOutline ppVerbs==NULL");
01229     ERROR2IF(pNumCoords==NULL,FALSE,"FTFontMan::GetCharOutline pNumCoords==NULL");
01230 
01231     PangoFcFont* pPangoFcFont;
01232     FT_Face pFreeTypeFace;
01233     if (!GetPangoFcFontAndFreeTypeFaceForCharDesc(ChDesc, &pPangoFcFont, &pFreeTypeFace)) return FALSE;
01234 
01235     // get the design size
01236     INT32 DesignSize = pFreeTypeFace->units_per_EM;
01237     // TRACEUSER("wuerthne", _T("DesignSize = %d"), DesignSize);
01238 
01239     // load the glyph data for our character into the font's glyph slot
01240     if (FT_Load_Char(pFreeTypeFace, ChDesc.GetCharCode(), FT_LOAD_NO_SCALE))
01241     {
01242         pango_fc_font_unlock_face(pPangoFcFont);
01243         ERROR2(FALSE, "FTFontMan::GetCharOutline - could not load glyph");
01244     }
01245 
01246     FT_GlyphSlotRec *pGlyph = pFreeTypeFace->glyph;
01247 
01248     // TRACEUSER("wuerthne", _T("found outline, %d contours, %d points"),
01249     //        pGlyph->outline.n_contours, pGlyph->outline.n_points);
01250     // finally, we have the glyph we want, so transfer it to the outlines cache
01251     OILFontMan::InitialiseOutlineCache();
01252 
01253     FT_Outline_Funcs funcs = { AddMoveTo, AddLineTo, AddConicTo, AddCubicTo, 0, 0 };
01254     DecompState state;
01255     state.DesignSize = DesignSize;
01256     state.IsFirstMove = TRUE;
01257 
01258     // TRACEUSER("wuerthne", _T("calling Outline_Decompose"));
01259     if (FT_Outline_Decompose(&pGlyph->outline, &funcs, &state))
01260     {
01261         OILFontMan::FinaliseOutlineCache();
01262         pango_fc_font_unlock_face(pPangoFcFont);
01263         return FALSE;
01264     }
01265     // TRACEUSER("wuerthne", _T("Outline_Decompose success"));
01266 
01267     // close the last contour if there was any output at all
01268     if (!state.IsFirstMove)
01269     {
01270         OILFontMan::ClosePath();
01271     }
01272     OILFontMan::FinaliseOutlineCache();
01273     pango_fc_font_unlock_face(pPangoFcFont);
01274     (*pNumCoords) = OILFontMan::GetOutlineCache(ppCoords,ppVerbs);
01275     // TRACEUSER("wuerthne", _T("FTFontMan::GetCharOutline Returning %d coords"), *pNumCoords);
01276     return TRUE;
01277 }
01278 
01279 // *******************
01280 // Metrics and kerning
01281 // *******************
01282 
01283 /********************************************************************************************
01284 
01285 >   OUTLINETEXTMETRIC* FTFontMan::GetOutlineTextMetric(LOGFONT *pLogFont)
01286 
01287     Author:     Martin Wuerthner <xara@mw-software.com>
01288     Created:    19/04/06
01289     Inputs:     pLogFont  = font descriptor
01290     Returns:    an OUTLINETEXTMETRIC structure or NULL if the information cannot be obtained
01291                 (Panose information is only available for TrueType fonts, not for Type-1 fonts)
01292                 The caller is responsible for freeing the structure
01293     Purpose:    get the Panose structure for a font
01294 
01295 ********************************************************************************************/
01296 
01297 OUTLINETEXTMETRIC* FTFontMan::GetOutlineTextMetric(LOGFONT *pLogFont)
01298 {
01299     String_64* pFaceName = &pLogFont->FaceName;
01300     PangoFcFont* pPangoFcFont;
01301     FT_Face pFreeTypeFace;
01302     // DumpString64User("wuerthne", _T("FTFontMan::GetOutlineTextMetric"), pFaceName);
01303 
01304     // first of all, retrieve the underlying font information
01305     if (!GetPangoFcFontAndFreeTypeFaceForFaceName(pFaceName, &pPangoFcFont, &pFreeTypeFace)) return NULL;
01306     // we have successfully retrieved the FreeType information (we need to release it below!)
01307 
01308     // ask FreeType for the Panose information - this is found in the OS/2 font table,
01309     // so check whether this font has a TrueType OS/2 font table
01310     TT_OS2* pOS2_Table;
01311     if ((pOS2_Table = (TT_OS2*)FT_Get_Sfnt_Table(pFreeTypeFace, ft_sfnt_os2)) == NULL   /* error loading */
01312         || pOS2_Table->version == 0xffff /* Mac font without OS/2 table */)
01313     {
01314         // we could not get the table with the Panose information, either because there
01315         // was an error when trying to load it or because the font is not a TrueType font,
01316         // or because it is an old Mac TrueType font without Panose information
01317         pango_fc_font_unlock_face(pPangoFcFont);
01318         return NULL;
01319     }
01320 
01321     // we have got the OS/2 table - it is owned by the face object so we need not free it,
01322     // it will disappear when we unlock the font face below
01323 
01324     // We need a permanent structure - the pointer may be cached. Otherwise, the kernel
01325     // will free the structure.
01326     OUTLINETEXTMETRIC* pMetric = new OUTLINETEXTMETRIC;
01327     pMetric->otmPanoseNumber = *((struct PANOSE*)&pOS2_Table->panose);
01328     // TRACEUSER("wuerthne", _T("returning valid OUTLINEFONTMETRIC structure"));
01329 
01330     pango_fc_font_unlock_face(pPangoFcFont);
01331     return pMetric;
01332 }
01333 
01334 /********************************************************************************************
01335 
01336 >   BOOL FTFontMan::GetAscentDescent(CharDescription& ChDesc, INT32* pAscent, INT32* pDescent)
01337 
01338     Author:     Martin Wuerthner <xara@mw-software.com>
01339     Created:    09/03/06
01340     Inputs:     chDesc - a Kernel character description (to identify the font)
01341     Outputs:    font ascent and descent in pAscent and pDescent
01342     Returns:    TRUE if the values could be retrieved
01343                 FALSE if not.
01344     Purpose:    This function returns the ascent and descent of a given font scaled
01345                 to DefaultHeight
01346 
01347 ********************************************************************************************/
01348 
01349 BOOL FTFontMan::GetAscentDescent(CharDescription& ChDesc, INT32* pAscent, INT32* pDescent)
01350 {
01351     PangoFcFont* pPangoFcFont;
01352     FT_Face pFreeTypeFace;
01353     // TRACEUSER("wuerthne", _T("GetAscentDescent"));
01354     if (!GetPangoFcFontAndFreeTypeFaceForCharDesc(ChDesc, &pPangoFcFont, &pFreeTypeFace)) return FALSE;
01355 
01356     // get the design size
01357     INT32 DesignSize = pFreeTypeFace->units_per_EM;
01358     *pAscent = ScaleToDefaultHeight(pFreeTypeFace->ascender, DesignSize);
01359     *pDescent = ScaleToDefaultHeight(-pFreeTypeFace->descender, DesignSize);
01360     // TRACEUSER("wuerthne", _T("returning ascent = %d, descent = %d"), *pAscent, *pDescent);
01361     pango_fc_font_unlock_face(pPangoFcFont);
01362     return TRUE;
01363 }
01364 
01365 /********************************************************************************************
01366 
01367 >   BOOL FTFontMan::GetCharWidth(CharDescription& ChDesc, TCHAR FirstChar, TCHAR LastChar,
01368                              INT32* pCharWidthsBuf)
01369 
01370     Author:     Martin Wuerthner <xara@mw-software.com>
01371     Created:    09/03/06
01372     Inputs:     chDesc - a Kernel character description (to identify the font)
01373                 FirstChar - first character to get the width for
01374                 LastChar - last character
01375     Outputs:    character widths into pCharWidthsBuf
01376     Returns:    TRUE if the widths could be retrieved
01377                 FALSE if not.
01378     Purpose:    This function returns the widths of a range of characters scaled
01379                 to DefaultHeight
01380 
01381 ********************************************************************************************/
01382 
01383 BOOL FTFontMan::GetCharWidth(CharDescription& ChDesc, TCHAR FirstChar, TCHAR LastChar,
01384                              INT32* pCharWidthsBuf)
01385 {
01386     // TRACEUSER("wuerthne", _T("FTFontMan::GetCharWidth first=%04x last=%04x"), FirstChar, LastChar);
01387     UINT32 NumChars = LastChar - FirstChar + 1;
01388     PangoFcFont* pPangoFcFont;
01389     FT_Face pFreeTypeFace;
01390     if (!GetPangoFcFontAndFreeTypeFaceForCharDesc(ChDesc, &pPangoFcFont, &pFreeTypeFace)) return FALSE;
01391 
01392     // get the design size
01393     INT32 DesignSize = pFreeTypeFace->units_per_EM;
01394     // TRACEUSER("wuerthne", _T("GetCharWidth, DesignSize = %d"), DesignSize);
01395 
01396     for (UINT32 i = 0; i < NumChars; i++) {
01397         // load the glyph data for our character into the font's glyph slot
01398         if (FT_Load_Char(pFreeTypeFace, FirstChar + i, FT_LOAD_NO_SCALE | FT_LOAD_LINEAR_DESIGN))
01399         {
01400             pango_fc_font_unlock_face(pPangoFcFont);
01401             ERROR2(FALSE, "FTFontMan::GetCharWidth - could not load glyph");
01402         }
01403         FT_GlyphSlotRec *pGlyph = pFreeTypeFace->glyph;
01404         pCharWidthsBuf[i] = ScaleToDefaultHeight(pGlyph->linearHoriAdvance, DesignSize);
01405     }
01406     pango_fc_font_unlock_face(pPangoFcFont);
01407     return TRUE;
01408 }
01409 
01410 /********************************************************************************************
01411 
01412 >   BOOL FTFontMan::GetCharsKerning(CharDescription& FontDesc, TCHAR LeftChar, TCHAR RightChar)
01413 
01414     Author:     Martin Wuerthner <xara@mw-software.com>
01415     Created:    19/04/06
01416     Inputs:     FontDesc - a Kernel character description (to identify the font)
01417                 LeftChar, RightChar - left and right character
01418     Outputs:    -
01419     Returns:    the kerning to be applied between LeftChar and RightChar
01420     Purpose:    This function returns the kerning between two glyphs scaled to DefaultHeight
01421 
01422 ********************************************************************************************/
01423 
01424 INT32 FTFontMan::GetCharsKerning(CharDescription& FontDesc, TCHAR LeftChar, TCHAR RightChar)
01425 {
01426     PangoFcFont* pPangoFcFont;
01427     FT_Face pFreeTypeFace;
01428 
01429     // TRACEUSER("wuerthne", _T("GetCharsKerning, %04x %04x"), LeftChar, RightChar);
01430     if (!GetPangoFcFontAndFreeTypeFaceForCharDesc(FontDesc, &pPangoFcFont, &pFreeTypeFace)) return 0;
01431 
01432     // get the design size
01433     INT32 DesignSize = pFreeTypeFace->units_per_EM;
01434 
01435     FT_ULong LeftIndex = FT_Get_Char_Index(pFreeTypeFace, LeftChar);
01436     FT_ULong RightIndex = FT_Get_Char_Index(pFreeTypeFace, RightChar);;
01437 
01438     FT_Vector kerning;
01439     FT_Error FreeTypeError;
01440     if ((FreeTypeError = FT_Get_Kerning(pFreeTypeFace, LeftIndex, RightIndex, FT_KERNING_UNSCALED, &kerning)) != 0)
01441     {
01442         TRACEUSER("wuerthne", _T("could not get kerning, error = %d"), FreeTypeError);
01443         return 0;
01444     }
01445 
01446     // TRACEUSER("wuerthne", _T("Got kerning: %d"), kerning.x);
01447     pango_fc_font_unlock_face(pPangoFcFont);
01448     return ScaleToDefaultHeight(kerning.x, DesignSize);
01449 }
01450 
01451 #endif // __WXGTK__

Generated on Sat Nov 10 03:48:29 2007 for Camelot by  doxygen 1.4.4