fontman.cpp

Go to the documentation of this file.
00001 // $Id: fontman.cpp 1642 2006-08-02 10:15:44Z 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 Camelots Font Managler, supposidly
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 // #include "fontbase.h" - included in fontman.h
00105 #include "nodetxts.h"
00106 #include "nodetxtl.h"
00107 #include "nodetext.h"
00108 #include "fontman.h"
00109 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "txtattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "richard2.h"
00112 
00113 DECLARE_SOURCE( "$Revision: 1642 $" );
00114 
00115 CC_IMPLEMENT_DYNCREATE( CachedFontItem, ListItem )
00116 CC_IMPLEMENT_DYNCREATE( FontManager, CCObject )
00117 CC_IMPLEMENT_DYNCREATE( EnumAllFonts, OILEnumFonts )
00118 
00119 
00120 // Declare smart memory handling in Debug builds
00121 #define new CAM_DEBUG_NEW     
00122 
00123 
00124 /*
00125     THEORY N ALL
00126 
00127     (1) The font manager controls its fonts in a simple list. Each entry contains a
00128         font description which knows what kind of font it is.
00129     (2) All access to fonts should be via the font manager, which in turn asks each
00130         font list item.
00131     (3) For speed and general lack of gobbling memory, the font list is initialised with
00132         font names only. If someone actually wants information about a fonts metrics
00133         or its log font structure (heaven forbid) they call the fontmanagers functions
00134         to return these items. If the items are null at the time then the info has not
00135         been cached yet and will immediately get cached (cor cache on demand!). A little
00136         slower for the first use but nice there after.
00137     (4) A font name is now no longer enough to uniquely specify a font. The name and class
00138         need to be used as you can be using an ATM font called Courier as well as a
00139         True Type font of the same name. Eeek.
00140     (5) Any new stuff added should NOT be naughty and follow its own guide lines. The idea
00141         is simple. Provide a function in the font manager that the external user can call,
00142         then implement the same function inside CachedFontItem (ie the font manager usually
00143         asks the font item if it wants information from it (it does not simply dig the
00144         data straight out itself!). The font item then asks a virtual function derived
00145         from FontBase cause the actually font class only knows whats going on at the
00146         device level.
00147         That way we might even be able to get risc os fonts working one day. Ha Ha Ha Ha!
00148     (6) THOU SHALL'T NOT CHANGE SCOPE!
00149         Anyone found leaping into structures having promoted things from private to public
00150         will be shot.
00151     (7) To add a new font controller, simply derive from FontBase and implement the necessary
00152         functionality, simple as that although currently we do not have our own internal
00153         font descriptors, we currently rely on the one API structure: ENUMLOGFONT
00154         The structure OUTLINETEXTMETRIC is cached on demand, since its 'expensive' to
00155         retrieve. The only time we need to do it for all the fonts should be when the
00156         new file format needs to do some smart font subsitution.
00157 */
00158 
00159 
00160 /********************************************************************************************
00161 
00162 >   CachedFontItem::CachedFontItem() 
00163 
00164     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00165     Created:    12/09/95                
00166     Purpose:    Default constructor
00167 
00168 ********************************************************************************************/
00169 
00170 CachedFontItem::CachedFontItem()
00171 {
00172     pFontClass          = NULL;
00173     Handle              = ILLEGALFHANDLE;
00174     pEnumLogFont        = NULL;
00175     pOutlineTextMetric  = NULL;
00176     FlagIsCorrupt       = FALSE;
00177     FlagIsReplaced      = FALSE;
00178 }
00179 
00180 CachedFontItem::~CachedFontItem()
00181 {
00182     Delete();
00183 }
00184 
00185 /********************************************************************************************
00186     For all the rest of these functions see their FontManager equivalents
00187 ********************************************************************************************/
00188 
00189 /********************************************************************************************
00190 
00191 >   ENUMLOGFONT* CachedFontItem::GetEnumLogFont()
00192 
00193     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00194     Created:    12/09/95
00195     Inputs:     -
00196     Returns:    A pointer to the ENUMLOGFONT structure for this font                
00197     Purpose:    Returns the ENUMLOGFONT structure for this cached font.
00198 
00199 ********************************************************************************************/
00200 
00201 ENUMLOGFONT* CachedFontItem::GetEnumLogFont()
00202 {
00203     ERROR2IF(pFontClass==NULL, NULL, "structure exists without a FontClass!!!");
00204 
00205     if (pEnumLogFont!=NULL)
00206         return pEnumLogFont;
00207 
00208     return NULL;
00209 }
00210 
00211 /********************************************************************************************
00212 
00213 >   OUTLINETEXTMETRIC* CachedFontItem::GetOutlineTextMetric()
00214 
00215     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
00216     Created:    15/08/96
00217     Inputs:     -
00218     Returns:    A pointer to the OUTLINETEXTMETRIC structure for this font, or NULL if
00219                 one doesn't exist (non-truetype fonts).
00220     Purpose:    Returns the OUTLINETEXTMETRIC structure for this cached font.
00221 
00222 ********************************************************************************************/
00223 
00224 OUTLINETEXTMETRIC* CachedFontItem::GetOutlineTextMetric()
00225 {
00226     ERROR2IF(pFontClass==NULL, NULL, "this.pFontClass==NULL.");
00227     ERROR2IF(pEnumLogFont==NULL, NULL, "this.pEnumLogFont==NULL.");
00228 
00229     if (pOutlineTextMetric==NULL)
00230     {
00231         // ask the font class for this structure, and cache it
00232         FontClass Class = GetFontClass();
00233         pOutlineTextMetric=OILFontMan::GetOutlineTextMetric(Class, &(pEnumLogFont->elfLogFont));
00234     }
00235 
00236     // return the result.
00237     return pOutlineTextMetric;
00238 }
00239 
00240 /********************************************************************************************
00241 
00242 >   String_64* CachedFontItem::GetFontName()
00243 
00244     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00245     Created:    12/09/95
00246     Inputs:     -
00247     Returns:    A font name
00248     Purpose:    Get this items name
00249 
00250 ********************************************************************************************/
00251 
00252 String_64* CachedFontItem::GetFontName()
00253 {
00254     ERROR2IF(pFontClass==NULL, NULL, "structure exists without a FontClass!!!");
00255     return pFontClass->GetFontName();
00256 }
00257 
00258 /********************************************************************************************
00259 
00260 >   FontClass CachedFontItem::GetFontClass()
00261 
00262     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00263     Created:    12/09/95
00264     Inputs:     -
00265     Returns:    A font class
00266     Purpose:    Get this items class
00267 
00268 ********************************************************************************************/
00269 
00270 FontClass CachedFontItem::GetFontClass()
00271 {
00272     ERROR3IF(pFontClass==NULL, "structure exists without a FontClass!!!");
00273     return pFontClass->GetFontClass();
00274 }
00275 
00276 /********************************************************************************************
00277 
00278 >   void CachedFontItem::DeleteMetrics()
00279 
00280     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00281     Created:    12/09/95
00282     Inputs:     -
00283     Returns:    -
00284     Purpose:    Delete this items LOGFONT cached structure
00285 
00286 ********************************************************************************************/
00287 
00288 void CachedFontItem::DeleteMetrics()
00289 {
00290     if( NULL == pFontClass )
00291     {
00292         TRACE( _T("structure exists without a FontClass!!!") );
00293     }
00294     
00295     if (pEnumLogFont!=NULL)
00296     {
00297         delete pEnumLogFont;
00298         pEnumLogFont = NULL;
00299     }
00300     
00301     if (pOutlineTextMetric!=NULL)
00302     {
00303         delete pOutlineTextMetric;
00304         pOutlineTextMetric = NULL;
00305     }
00306 }
00307 
00308 void CachedFontItem::DeleteFontClass()
00309 {
00310     if (pFontClass!=NULL)
00311     {
00312         delete pFontClass;
00313         pFontClass=NULL;
00314     }
00315 }
00316 
00317 void CachedFontItem::Delete()
00318 {
00319     DeleteMetrics();    
00320     DeleteFontClass();
00321 }
00322 
00323 /********************************************************************************************
00324 
00325 >   BOOL CachedFontItem::IsFullyCached()
00326 
00327     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00328     Created:    12/09/95
00329     Inputs:     -
00330     Returns:    TRUE if this item is fully cached, FALSE if not
00331     Purpose:    See if this item has all its cached structures resident
00332 
00333 ********************************************************************************************/
00334 
00335 BOOL CachedFontItem::IsFullyCached()
00336 {
00337     PORTNOTE("text","CachedFontItem::IsFullyCached - do nothing");
00338 #ifndef DISABLE_TEXT_RENDERING
00339     // TRACEUSER("wuerthne", _T("CachedFontItem::IsFullyCached called") );
00340     ERROR2IF(pFontClass==NULL, FALSE, "A CachedFontItem structure exists without a FontClass!!!");
00341     return (pEnumLogFont!=NULL);
00342 #else
00343     return TRUE;
00344 #endif
00345 }
00346 
00347 /********************************************************************************************
00348 
00349 >   BOOL CachedFontItem::Compare(String_64* pFontName)
00350 
00351     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00352     Created:    12/09/95
00353     Inputs:     pFontName = A pointer to a font name
00354     Returns:    TRUE if the font name on entry matchs that of this cached font
00355                 FALSE if not
00356     Purpose:    See if this font has the same name as that passed as a param.
00357 
00358 ********************************************************************************************/
00359 
00360 BOOL CachedFontItem::Compare(String_64 *pFontName)
00361 {
00362     if( pFontClass == NULL )
00363     {
00364         TRACE( _T("A CachedFontItem structure exists without a FontClass!!!") );
00365         return FALSE;
00366     }
00367     
00368     return pFontClass->Compare( pFontName );
00369 }   
00370 
00371 
00372 /********************************************************************************************
00373 
00374 >   void CachedFontItem::Dump()
00375 
00376     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00377     Created:    12/09/95
00378     Purpose:    Dump the contents of this cache entry out
00379 
00380 ********************************************************************************************/
00381 
00382 
00383 void CachedFontItem::Dump()
00384 {
00385 #ifdef _DEBUG
00386     ERROR3IF(pFontClass==NULL, "A CachedFontItem structure exists without a FontClass!!!");
00387     TRACE( _T("Font item:\n Handle = %d\n"),Handle);
00388     if (IsFullyCached())
00389     {       
00390         TRACE( _T(" Fully cached\n"));
00391         OILFontMan::DumpEnumLogFont(pEnumLogFont);
00392     }
00393     else
00394     {
00395         TRACE( _T(" Not fully cached\n"));
00396     }
00397     pFontClass->Dump();
00398 #endif
00399 }
00400 
00401 
00402 /********************************************************************************************
00403 
00404 >   BOOL CachedFontItem::SetCacheData(ENUMLOGFONT FAR* lpelf)
00405 
00406     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00407     Created:    12/09/95
00408     Inputs:     lpelf   = a pointer to the logical font description
00409     Returns:    TRUE if we manage to cache this data
00410                 FALSE if not (out of memory)                
00411     Purpose:    This function is called to set the cached data (or metrics) for a particular
00412                 font item. The metrics will have been returned to us from an oil layer
00413                 font manager after a request from us to it to cache them.
00414 
00415 ********************************************************************************************/
00416 
00417 BOOL CachedFontItem::SetCacheData(ENUMLOGFONT FAR* lpelf)
00418 {
00419     ERROR2IF(lpelf==NULL,FALSE,"CachedFontItem::SetCacheData() given a null ENUMLOGFONT structure");
00420     ERROR3IF(pFontClass==NULL, "A CachedFontItem structure exists without a FontClass!!!");
00421 
00422     if (pEnumLogFont!=NULL)
00423     {
00424         ERROR3("Replacing ENUMLOGFONT structure inside CachedFontItem::SetCacheData()");
00425         delete pEnumLogFont;
00426         pEnumLogFont=NULL;
00427     }
00428 
00429     // try a claim memory for the new structure
00430     ENUMLOGFONT * MyEnumLogFont = new ENUMLOGFONT;
00431 
00432     if (MyEnumLogFont==NULL)
00433     {
00434         return FALSE;
00435     }
00436     
00437     // copy the the contents of the structures given as arguments into the new structures
00438     *MyEnumLogFont = *lpelf;
00439 
00440     // and point the pointers to these new structures
00441     pEnumLogFont = MyEnumLogFont;
00442 
00443     return TRUE;
00444 }
00445 
00446 
00447 
00448 // ---------------------- End of CachedFontItem functions -----------------------------------
00449 
00450 
00451 /********************************************************************************************
00452 
00453 >   FontManager::FontManager() 
00454 
00455     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00456     Created:    12/09/95                
00457     Purpose:    Constructor for the font manager class
00458 
00459 ********************************************************************************************/
00460 
00461 FontManager::FontManager()
00462 {
00463     UniqueHandle  = FIRSTFONTHANDLE;
00464     DefaultHandle = DEFAULTHANDLE;
00465     TempFontClass = FC_UNDEFINED;
00466 }
00467 
00468 FontManager::~FontManager()
00469 {
00470     TheFontList.DeleteAll();
00471 }
00472 
00473 /********************************************************************************************
00474 
00475 >   BOOL FontManager::LegalFontClass(INT32 Class, FontClass& RealClass)
00476 
00477     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00478     Created:    12/09/95                
00479     Inputs:     A INT32 describing the font class
00480     Outputs:    The real font class to use for this numeric value
00481     Returns:    TRUE if the font class is supported, FALSE if not
00482     Purpose:    Check whether a numeric value actually indicates a valid class of font
00483                 ie lies in the range of supported font types. This is used generally for
00484                 loading purpose where the font class is loaded as a numeric value.
00485 
00486 ********************************************************************************************/
00487 
00488 BOOL FontManager::LegalFontClass(INT32 Class, FontClass& RealClass)
00489 {
00490     return OILFontMan::LegalFontClass(Class, RealClass);
00491 }
00492 
00493 
00494 /********************************************************************************************
00495 
00496 >   WORD FontManager::GetNextHandle()
00497 
00498     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00499     Created:    12/9/95
00500     Inputs:     -
00501     Outputs:    The next font handle. 
00502     Returns:    -
00503     Purpose:    Return a unique handle for the font cache handler
00504                 Handles range from 1..n, 0 is explicitly reserved for the default
00505                 handle, 0x7FFF is defined as an illegal handle.
00506 
00507 ********************************************************************************************/
00508 
00509 WORD FontManager::GetNextHandle()
00510 {
00511     WORD CurrHandle=UniqueHandle;
00512     UniqueHandle++;
00513     return (CurrHandle);
00514 }
00515 
00516 /********************************************************************************************
00517 
00518 >   BOOL FontManager::Init()
00519 
00520     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00521     Created:    12/09/95                
00522     Inputs:     -
00523     Outputs:    -
00524     Returns:    TRUE if the fontmanager was able to initialise correctly
00525                 FALSE if not
00526     Purpose:    Get Camelots Font manager going. We simply cache the default font so
00527                 unknown fonts can be sensibly replaced.
00528     
00529 ********************************************************************************************/
00530 
00531 BOOL FontManager::Init()
00532 {
00533     // initialise the OIL cache of enumerated fonts by simply enumerating them
00534     // and ignoring the result - since we do not want to see the names, we do
00535     // not even have to create a subclass
00536     OILEnumFonts enumerator;
00537     enumerator.Execute();
00538     if (!CacheDefaultFont())    
00539     {
00540         ERROR3("FontManager::Init() - Unable to cache the default font");
00541     }
00542     return TRUE;
00543 }
00544 
00545 /********************************************************************************************
00546 
00547 >   CachedFontItem* FontManager::GetFirstFont()
00548 
00549     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00550     Created:    12/9/95
00551     Returns:    A pointer to the first cached font item (NULL if none)
00552 
00553 ********************************************************************************************/
00554 
00555 CachedFontItem* FontManager::GetFirstFont()
00556 {
00557     return (CachedFontItem*)TheFontList.GetHead();
00558 }
00559 
00560 /********************************************************************************************
00561 
00562 >   CachedFontItem* FontManager::GetNextFont(CachedFontItem *pItem)
00563 
00564     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00565     Created:    12/9/95
00566     Inputs:     A pointer to a font item to find the next from.
00567     Returns:    A pointer to the next cached font item from pItem 
00568                 (NULL if none)
00569 
00570 ********************************************************************************************/
00571 
00572 CachedFontItem* FontManager::GetNextFont(CachedFontItem* pItem)
00573 {
00574     return (CachedFontItem*)TheFontList.GetNext(pItem);
00575 }
00576 
00577 
00578 
00579 /********************************************************************************************
00580 
00581 >   CachedFontItem* FontManager::AddFont(String_64* Name, FontClass fclass, WORD& Handle)
00582 
00583     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00584     Created:    12/9/95
00585     Inputs:     Name    = a pointer to the font name
00586                 fclass  = a reference to the class of font to add
00587     Outputs:    Handle = ILLEGALFHANDLE if the font could not be added
00588                 Handle = The font handle if ok
00589     Returns:    NULL if the font could not be added
00590                 A pointer to the font record
00591     Purpose:    Creates a new font item for this named font. The font will not be fully
00592                 cached. To cache all the data for the font, call CacheFontData(Handle)
00593 
00594 ********************************************************************************************/
00595 
00596 CachedFontItem* FontManager::AddFont(String_64* Name, FontClass fclass, WORD& retHandle)
00597 {
00598     TRACEUSER("wuerthne", _T("FontManager::AddFont %s"), (TCHAR*)*Name);
00599     CachedFontItem* pItem = new CachedFontItem;
00600     if (pItem==NULL)
00601         return NULL;
00602 
00603     FontBase* pClass = OILFontMan::CreateNewFont(fclass,Name);
00604     if (pClass==NULL)
00605     {
00606         delete pItem;
00607         pItem=NULL;
00608         return NULL;
00609     }
00610 
00611     pItem->pFontClass = pClass;
00612     pItem->Handle = GetNextHandle();
00613     TheFontList.AddTail(pItem);
00614 
00615     retHandle = pItem->Handle;
00616     TRACEUSER("wuerthne", _T("AddFont, returning %d"), retHandle);
00617 
00618     return pItem;
00619 }
00620 
00621 /********************************************************************************************
00622 
00623 >   CachedFontItem* FontManager::FindFont(WORD Handle)
00624 
00625     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00626     Created:    12/9/95
00627     Inputs:     Handle = The font manager font handle
00628     Outputs:    -
00629     Returns:    A pointer to the font managers cached font record for this handle
00630     Purpose:    Find the entry in the font managers font cache which corresponds to this
00631                 handle.
00632 
00633 ********************************************************************************************/
00634 
00635 CachedFontItem* FontManager::FindFont(WORD Handle)
00636 {
00637     // Check the cache first
00638     CachedFontItem* pItem = GetFirstFont();
00639     while (pItem!=NULL)
00640     {
00641         if (pItem->Handle == Handle)
00642             return pItem;
00643         pItem = GetNextFont(pItem);
00644     }
00645     return NULL;
00646 }
00647 
00648 /********************************************************************************************
00649 
00650 >   CachedFontItem* FontManager::FindFont(String_64* pFontName, FontClass Class=FC_UNDEFINED)
00651 
00652     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00653     Created:    12/9/95
00654     Inputs:     pFontName = a pointer to a font name
00655                 Class     = describes the type of class (see typedef for details)
00656                             FC_UNDEFINED then ignore the class match and match the first
00657                             item with the same name whatever font class it is
00658     Outputs:    -
00659     Returns:    A pointer to the font managers cached font record for this font
00660                 NULL if unable to find the font
00661     Purpose:    Find the entry in the font managers font list which corresponds to this
00662                 fontname and font class
00663     Note:       One might be tempted to include the default font item in the comparison
00664                 and return the default font handle when the default font name is passed,
00665                 but this does not happen and this is by design. See OnDocumentLoaded for
00666                 further information.
00667 
00668 ********************************************************************************************/
00669 
00670 CachedFontItem* FontManager::FindFont(String_64* pFontName, FontClass Class)
00671 {
00672     CachedFontItem* pItem = GetFirstFont();
00673 
00674     if (Class==FC_UNDEFINED)
00675     {
00676         while (pItem!=NULL)
00677         {
00678             if (pItem->Compare(pFontName))
00679                 return pItem;
00680             pItem = GetNextFont(pItem); 
00681         }
00682     }
00683     else
00684     {
00685         while (pItem!=NULL)
00686         {
00687             if (pItem->Compare(pFontName))
00688             {
00689                 if (pItem->GetFontClass() == Class)
00690                     return pItem;
00691             }
00692             pItem = GetNextFont(pItem); 
00693         }
00694     }
00695     return NULL;
00696 }
00697 
00698 /********************************************************************************************
00699 
00700 >   CachedFontItem* FontManager::GetCachedFont(WORD Handle)
00701 
00702     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00703     Created:    12/9/95
00704     Inputs:     Handle = The font manager font handle
00705     Outputs:    -
00706     Returns:    A pointer to a cached font record or NULL
00707     Purpose:    This function returns the font associated with the handle passed. If the
00708                 font is not in the cache it will return NULL. It differs from GetFont in
00709                 that it will not attempt to return the DefaultFontItem if it cannot find
00710                 the item specified.
00711 
00712 ********************************************************************************************/
00713 
00714 CachedFontItem* FontManager::GetCachedFont(WORD Handle)
00715 {
00716     if (Handle==DefaultHandle) return (&DefaultFontItem);
00717     return FindFont(Handle);
00718 }
00719 
00720 /********************************************************************************************
00721 
00722 >   WORD FontManager::GetFontHandle(String_64* pFontName, FontClass Class=FC_UNDEFINED)
00723 
00724     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00725     Created:    12/9/95
00726     Inputs:     pFontName = a pointer to a font name
00727                 Class     = describes the class of font to get the handle of
00728     Outputs:    -
00729     Returns:    The handle of the font if the font exists
00730                 The default handle if the font does not exist and Replace is true
00731                 ILLEGALFHANDLE if not
00732     Purpose:    Get the handle on a cached font (if cached) otherwise return the default
00733                 font handle.
00734 
00735 ********************************************************************************************/
00736 
00737 WORD FontManager::GetFontHandle(String_64* pFontName, FontClass Class)
00738 {
00739     ERROR2IF(pFontName==NULL, 0, "FontManager::GetFontHandle() called with an illegal font name pointer");
00740     CachedFontItem* pItem=FindFont(pFontName,Class);
00741     if (pItem!=NULL)
00742         return pItem->GetFontHandle();
00743     
00744     return DefaultHandle;
00745 }
00746 
00747 /********************************************************************************************
00748 
00749 >   CachedFontItem* FontManager::GetFont()
00750 
00751     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00752     Created:    12/9/95
00753     Inputs:     -
00754     Outputs:    -
00755     Returns:    A pointer to a cached font record or NULL
00756     Purpose:    Return the precached default font data to use for rendering.
00757     
00758 ********************************************************************************************/
00759 
00760 CachedFontItem* FontManager::GetFont()
00761 {
00762     return &DefaultFontItem;
00763 }
00764 
00765 /********************************************************************************************
00766 
00767 >   CachedFontItem* FontManager::GetFont(WORD Handle)
00768 
00769     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00770     Created:    12/9/95
00771     Inputs:     Handle = The font manager font handle
00772     Outputs:    -
00773     Returns:    A pointer to a cached font record or NULL
00774     Purpose:    Return the font data to use for rendering. This function performs a specific
00775                 job in avoiding caching the font data. If the font is already cached then
00776                 fine, it is returned for use. If not, the default font is returned.
00777 
00778 ********************************************************************************************/
00779 
00780 CachedFontItem* FontManager::GetFont(WORD Handle)
00781 {
00782     CachedFontItem* pItem = FindFont(Handle);
00783     if ((pItem!=NULL) && (pItem->IsFullyCached()))
00784         return pItem;
00785     return &DefaultFontItem;
00786 }
00787 
00788 /********************************************************************************************
00789 
00790 >   CachedFontItem* FontManager::GetFont(String_64* pFontName, FontClass Class=FC_UNDEFINED)
00791 
00792     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00793     Created:    12/9/95
00794     Inputs:     pFontName = a pointer to a font name
00795                 Class     = describes the type of class (see typedef for details)
00796                             FC_UNDEFINED then ignore the class match and match the first
00797                             item with the same name whatever font class it is
00798     Outputs:    -
00799     Returns:    A pointer to a cached font record or NULL
00800     Purpose:    Return the font data to use for rendering. This function performs a specific
00801                 job in avoiding caching the font data. If the font is already cached then
00802                 fine, it is returned for use. If not, the default font is returned.
00803 
00804 ********************************************************************************************/
00805 
00806 CachedFontItem* FontManager::GetFont(String_64 *pFontName, FontClass Class)
00807 {
00808     CachedFontItem* pItem = FindFont(pFontName, Class);
00809     if ((pItem!=NULL) && (pItem->IsFullyCached()))
00810         return pItem;
00811     return &DefaultFontItem;
00812 }
00813 
00814 /********************************************************************************************
00815 
00816 >   INT32 FontManager::DoesFontExist(String_64* pFontName, 
00817                                     BOOL SearchCache,
00818                                     BOOL SearchInstalled) 
00819 
00820     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00821     Created:    19/05/95
00822     Inputs:     FontName : Name of font to find
00823                 SearchCache : TRUE then search our internal cached fonts
00824                 SearchInstalled: TRUE then search through the installed set of fonts too
00825     Outputs:    -
00826     Returns:    0 if the font cannot be found in the specified search areas
00827                 1 if the font has been installed
00828                 2 if the font has been cached
00829     Purpose:    First check in the cache if necessary, then through the installed set of
00830                 fonts to find whether the named font actually exists
00831 
00832 ********************************************************************************************/
00833 
00834 INT32 FontManager::DoesFontExist(String_64 *pFontName, BOOL SearchCache, BOOL SearchInstalled)
00835 {
00836     if (SearchCache)
00837         if (FindFont(pFontName) != NULL)
00838             return 2;
00839 
00840     if (SearchInstalled)
00841         if (IsFontInstalled(pFontName))
00842             return 1;
00843 
00844     return 0;
00845 }
00846 
00847 /********************************************************************************************
00848 
00849 >   BOOL FontManager::IsFontValid(WORD Handle)
00850 
00851     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00852     Created:    12/9/95
00853     Inputs:     Handle = The font manager font handle
00854     Outputs:    -
00855     Returns:    TRUE if the font is valid and ready to use
00856                 FALSE if not.
00857     Purpose:    Check to see if the font described is actually valid, ie all the metrics
00858                 for the font have been cached correctly.
00859 
00860 ********************************************************************************************/
00861     
00862 BOOL FontManager::IsFontValid(WORD Handle)
00863 {
00864     CachedFontItem* pItem = GetCachedFont(Handle);
00865     return ( (pItem!=NULL) && (pItem->IsFullyCached()) );
00866 }
00867 
00868 /********************************************************************************************
00869 
00870 >   BOOL FontManager::IsFontReplaced(WORD FontHandle)
00871     BOOL FontManager::IsFontReplaced(String_64* pFontName, FontClass Class=FC_UNDEFINED)
00872 
00873     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00874     Created:    12/9/95
00875     Inputs:     pFontName = a pointer to a font name
00876                 Class     = describes the type of class (see typedef for details)
00877                             FC_UNDEFINED then ignore the class match and match the first
00878                             item with the same name whatever font class it is
00879     Outputs:    -
00880     Returns:    TRUE if the font has been replaced by the default
00881                 FALSE if not.
00882     Purpose:    Check to see if the font described has been replaced.
00883 
00884 ********************************************************************************************/
00885 
00886 BOOL FontManager::IsFontReplaced(WORD FontHandle)
00887 {
00888     BOOL Result = FALSE;
00889 
00890     // check whether its the default font, if it is then obviously it's not been replaced.
00891     if (IsFontDefault(FontHandle))
00892     {
00893         Result = FALSE;
00894     }
00895     else
00896     {
00897         CachedFontItem *pItem = FindFont(FontHandle);
00898 
00899         if (pItem==NULL)
00900         {
00901             Result = TRUE;      // font doesn't exist
00902         }
00903         else if (pItem->IsReplaced())
00904         {
00905             Result = TRUE;      // IsReplaced flag is set
00906         }
00907         else if (!pItem->IsValid())
00908         {
00909             Result = TRUE;      // The font isn't valid
00910         }
00911     }
00912 
00913     return Result;
00914 }
00915 
00916 BOOL FontManager::IsFontReplaced(String_64* pFontName, FontClass Class)
00917 {
00918     BOOL Result = FALSE;
00919 
00920     // Check whether its the default font, if it is then obviously it's not been replaced.
00921     if (DefaultFontItem.Compare(pFontName))
00922     {
00923         Result = FALSE;
00924     }
00925     else
00926     {
00927         CachedFontItem *pItem = FindFont(pFontName, Class);
00928 
00929         if (pItem==NULL)
00930         {
00931             Result = TRUE;      // font doesn't exist
00932         }
00933         else if (pItem->IsReplaced())
00934         {
00935             Result = TRUE;      // IsReplaced flag is set
00936         }
00937         else if (!pItem->IsValid())
00938         {
00939             Result = TRUE;      // The font isn't valid
00940         }
00941     }
00942 
00943     return Result;
00944 }
00945 
00946 /********************************************************************************************
00947 
00948 >   BOOL FontManager::IsFontDefault(WORD Handle)
00949 
00950     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00951     Created:    12/9/95
00952     Inputs:     Handle = The font manager font handle
00953     Outputs:    -
00954     Returns:    TRUE if the font handle is the handle describing the default font
00955                 FALSE if not.
00956     Purpose:    Check to see if the font handle described is the handle of the default font
00957                 ie the font which is used to replace unknown fonts (fonts not resident on
00958                 the host machine)
00959 
00960 ********************************************************************************************/
00961 
00962 BOOL FontManager::IsFontDefault(WORD Handle)
00963 {
00964     return (Handle==DefaultHandle);
00965 }
00966 
00967 BOOL FontManager::IsFontDefault(CachedFontItem* pItem)
00968 {
00969     return (pItem == (&DefaultFontItem));
00970 }
00971 
00972 /********************************************************************************************
00973 
00974 >   BOOL FontManager::IsFontUsedInSiblings(Node* pNode, WORD Handle, WORD CurrentHandle, UINT32 Level)
00975 
00976     Author:     Martin Wuerthner <xara@mw-software.com>
00977     Created:    01/08/06
00978     Inputs:     pNode - the root node of the subtree to check
00979                 Handle - a font handle
00980                 CurrentHandle - the font handle applying to the current subtree
00981                 Level - level in the tree (level 0 is NodeDocument, level 1 are default attributes)
00982     Returns:    Returns TRUE if a font attribute with the given handle applies to a text
00983                 object.
00984     Purpose:    Find out whether a given font is used in a document.
00985 
00986 ********************************************************************************************/
00987 
00988 BOOL FontManager::IsFontUsedInSiblings(Node* pNode, WORD Handle, WORD CurrentHandle, UINT32 Level)
00989 {
00990     // perform a standard child-first recursion keeping track of the current font
00991     while(pNode)
00992     {
00993         Node* pFirstChild = pNode->FindFirstChild();
00994         if (pFirstChild && IsFontUsedInSiblings(pFirstChild, Handle, CurrentHandle, Level + 1)) return TRUE;
00995         if (IS_A(pNode, AttrTxtFontTypeface))
00996         {
00997             AttrTxtFontTypeface* pAttr = (AttrTxtFontTypeface*)pNode;
00998             CurrentHandle = pAttr->Value.HTypeface;
00999             ENSURE(!(CurrentHandle == DEFAULTHANDLE && Level > 1), "FontManager::IsFontUsedInSiblings is based on the assumption that we do not have non-default attribute nodes referencing the default font");
01000         }
01001         if (CurrentHandle == Handle && (IS_A(pNode, TextStory) || IS_A(pNode, TextLine) || IS_A(pNode, TextChar)))
01002             return TRUE;
01003         pNode = pNode->FindNext();
01004     }
01005     return FALSE;
01006 }
01007 
01008 /********************************************************************************************
01009 
01010 >   BOOL FontManager::IsFontUsedInDoc(WORD Handle, Document* pDocument)
01011 
01012     Author:     Martin Wuerthner <xara@mw-software.com>
01013     Created:    01/08/06
01014     Inputs:     Handle - a font handle
01015                 pDocument - pointer to a document
01016     Returns:    When called with Handle == DEFAULTHANDLE it returns TRUE if the default
01017                 attribute applies to a text object. Otherwise, it returns TRUE if the supplied
01018                 font handle is used in the document
01019     Purpose:    Find out whether a given font is used in a document.
01020 
01021 ********************************************************************************************/
01022 
01023 BOOL FontManager::IsFontUsedInDoc(WORD Handle, Document* pDocument)
01024 {
01025     Node* pNode = pDocument->GetFirstNode();
01026     return IsFontUsedInSiblings(pNode, Handle, ILLEGALFHANDLE, 0);
01027 }
01028 
01029 /********************************************************************************************
01030 
01031 >   void FontManager::OnDocumentLoaded(Document* pDocument)
01032 
01033     Author:     Martin Wuerthner <xara@mw-software.com>
01034     Created:    01/08/06
01035     Inputs:     pDocument - pointer to the newly created/loaded document
01036     Purpose:    Called after a document has been loaded - allows us to fix the current and
01037                 default fonts if they are not installed. They are only changed if they are
01038                 not used in the document.
01039 
01040                 Fixing the current font is useful because it stops "Arial (missing)" from
01041                 being displayed after start-up if Arial is not installed. The same happens
01042                 when loading a document with the current font set to Arial (or any other
01043                 font that is not installed). We do not touch the current font if it is
01044                 actually used in the document because then, it is possible that it was set
01045                 deliberately (maybe even in a template).
01046 
01047                 One might consider a similar approach for the default font, but by definition,
01048                 the default font is always installed (though it may or may not be Times New
01049                 Roman), so there is no need to change anything. The default attributes are not
01050                 saved with the document, so, in contrast to the current font, there cannot be
01051                 any surprises with fonts that are not installed. The font name referenced by
01052                 the default font does not matter because the default font attribute is never
01053                 inherited by any text object in the document.
01054 
01055                 This is down to the behaviour of FindFont(String_64*,FontClass), which never
01056                 returns the default font handle, so any font attribute created by the text tool
01057                 based on a font name (which involves calling FindFont at some stage) is always
01058                 different from the default attribute (even if it happens to be the same font as
01059                 the default font) and hence this attribute is not optimised away. Therefore, each
01060                 and every text object has a non-default font attribute applied to it.
01061 
01062 ********************************************************************************************/
01063 
01064 void FontManager::OnDocumentLoaded(Document* pDocument)
01065 {
01066     // check if the current font is installed and change it in case it is not (only if the font is not used)
01067     NodeAttribute* pAttr = pDocument->GetAttributeMgr().GetCurrentAttribute(CC_RUNTIME_CLASS(BaseTextClass),
01068                                                                             CC_RUNTIME_CLASS(AttrTxtFontTypeface));
01069     if (pAttr)
01070     {
01071         AttrTxtFontTypeface* pTypeface = (AttrTxtFontTypeface*)pAttr;
01072         WORD Handle = pTypeface->Value.HTypeface;
01073         TRACEUSER("wuerthne", _T("found current font attribute, handle = %d"), Handle);
01074         CachedFontItem *pItem = FindFont(Handle);
01075         if (pItem)
01076         {
01077             String_64* SurfaceFontName = pItem->GetFontName();
01078             TRACEUSER("wuerthne", _T("current font name is %s"), (TCHAR*)*SurfaceFontName);
01079             ENUMLOGFONT *pEnumLogFont = pItem->GetEnumLogFont();
01080             if (pEnumLogFont)
01081             {
01082                 if (!IsFontInstalled(SurfaceFontName) && !IsFontUsedInDoc(Handle, pDocument))
01083                 {
01084                     // the current font is not installed and not used in the document,
01085                     // so find out what the replacement font is and use that instead
01086                     TRACEUSER("wuerthne", _T("font replaced and not used"));
01087                     String_64* NativeFontName = OILFontMan::GetNativeFontName(pItem->GetFontClass(),
01088                                                                               &pEnumLogFont->elfLogFont);
01089                     WORD NewHandle = CacheNamedFont(NativeFontName, pItem->GetFontClass());
01090                     if (NewHandle != ILLEGALFHANDLE)
01091                     {
01092                         TRACEUSER("wuerthne", _T("change current font to handle %d"), NewHandle);
01093                         // modify the current attribute directly
01094                         pTypeface->Value.HTypeface = NewHandle;
01095                     }
01096                 }
01097             }
01098         }
01099     }
01100 }
01101 
01102 /********************************************************************************************
01103 
01104 >   CachedFontItem* FontManager::GetFirstFontType(FontClass Class)
01105 
01106     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01107     Created:    12/9/95
01108     Inputs:     Class = the class of font to retrieve
01109     Outputs:    -
01110     Returns:    A pointer to a cached font record or NULL
01111     Purpose:    Find the entry in the font managers font list which corresponds to the first
01112                 'FontClass' font cached.
01113 
01114 ********************************************************************************************/
01115 
01116 CachedFontItem* FontManager::GetFirstFontType(FontClass Class)
01117 {
01118     CachedFontItem* pItem = GetFirstFont();
01119     while (pItem!=NULL)
01120     {
01121         if (pItem->GetFontClass() == Class)
01122             return pItem;
01123         pItem = GetNextFont(pItem);
01124     }
01125     return NULL;
01126 }
01127 
01128 /********************************************************************************************
01129 
01130 >   ENUMLOGFONT* FontManager::GetEnumLogFont(WORD Handle)
01131 
01132     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01133     Created:    12/9/95
01134     Inputs:     Handle = The font manager font handle
01135     Outputs:    -
01136     Returns:    A pointer to the ENUMLOGFONT structure for this font
01137                 NULL if none
01138     Purpose:    Return the ENUMLOGFONT structure for this font handle.
01139                 Note the function will automatically substitute the default font if the
01140                 handle provided is invalid or the font it describes is not fully cached.
01141 
01142 ********************************************************************************************/
01143 
01144 ENUMLOGFONT* FontManager::GetEnumLogFont(WORD Handle)
01145 {
01146     // ok, we need to get the font data for this particular font item   
01147     CachedFontItem *pItem = GetFont(Handle);
01148     if (pItem!=NULL)
01149     {
01150         return (pItem->GetEnumLogFont());
01151     }
01152     else
01153     {
01154         return NULL;
01155     }
01156 }
01157 
01158 /********************************************************************************************
01159 
01160 >   OUTLINETEXTMETRIC* FontManager::GetOutlineTextMetric(WORD Handle)
01161 
01162     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
01163     Created:    15/08/96
01164     Inputs:     Handle = the font manager handle
01165     Returns:    Pointer to the OUTLINETEXTMETRIC structure for this font, NULL if none
01166     Purpose:    Return the ENUMLOGFONT structure for this font handle
01167                 Note the function will automatically substitute the default font if the
01168                 handle provided is invalid or the font it describes is not fully cached.
01169 
01170 ********************************************************************************************/
01171 
01172 OUTLINETEXTMETRIC* FontManager::GetOutlineTextMetric(WORD Handle)
01173 {
01174     // ok, we need to get the font data for this particular font item
01175     CachedFontItem *pItem = GetFont(Handle);
01176     if (pItem!=NULL)
01177     {
01178         return pItem->GetOutlineTextMetric();
01179     }
01180     else
01181     {
01182         return NULL;
01183     }
01184 }
01185 
01186 /********************************************************************************************
01187 
01188 >   String_64* FontManager::GetFontName(WORD Handle)
01189 
01190     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01191     Created:    12/9/95
01192     Inputs:     Handle = The font manager font handle
01193     Outputs:    -
01194     Returns:    A pointer to the font name associated with this handle
01195                 NULL if the handle is illegal
01196     Purpose:    Return a pointer to the font name given its font handle
01197 
01198 ********************************************************************************************/
01199 
01200 String_64* FontManager::GetFontName(WORD Handle)
01201 {
01202     CachedFontItem* pItem = GetCachedFont(Handle);
01203     if (pItem==NULL)
01204     {
01205         ERROR3("FontManager::GetFontName() - given an illegal handle");
01206         return NULL;
01207     }
01208     return pItem->GetFontName();
01209 }
01210 
01211 
01212 BOOL FontManager::GetFontName(WORD Handle, String_64& OutputString)
01213 {
01214     CachedFontItem* pItem = GetCachedFont(Handle);
01215     if (pItem==NULL)
01216     {
01217         ERROR3("FontManager::GetFontName() - given an illegal handle");
01218         return FALSE;
01219     }
01220     OutputString = *(pItem->GetFontName());
01221     return TRUE;
01222 }
01223 
01224 /********************************************************************************************
01225 
01226 >   FontClass FontManager::GetFontClass(WORD Handle)
01227