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__