[Date Prev][Date Next][Thread Prev][Thread Next][Thread Index]
[XaraXtreme-dev] Current/default font fix
- From: Martin Wuerthner <lists@xxxxxxxxxxxxxxx>
- Date: Wed, 02 Aug 2006 12:07:53 +0200
- Subject: [XaraXtreme-dev] Current/default font fix
Find attached below a patch to replace the current font when loading
a document (or template) in case the current font as saved with the
document is not installed and not used in the document. This finally
means that on machines without Arial, the initial font displayed in
the text tool is no longer "Arial (missing)" but whatever the font
system thinks is the best replacement for Arial.
It was agreed that a similar strategy should be used for the default
font but that is not practicable because it turned out that the
default font is always an installed font (though, obviously, not
necessarily Times New Roman in case it is not available), which means
that the whole discussion about changing the default font in case it
is not installed was pointless because this situation does not occur.
Still, the discussion was valuable because it has highlighted the fact
that in contrast to all other default attributes, the default font
attribute is never inherited by any object in the tree and it now
looks like this is by design (though not documented anywhere up to
now). So, the default font attribute does not take part in attribute
optimisation.
What might have confused the issue is the misconception that font
attributes store font names - they do not, each attribute only holds a
font handle, which identifies the font in the font manager's list. The
default font attribute always holds the default font handle. Not all
of the fonts in the font manager's list need to be installed (some may
be replaced, in which case the font appears under the name of the
unknown font in the font manager's font list and has "(missing)"
appended in the font menu), but the default font is cached under its
real name.
Martin
Index: wxOil/fontbase.h
===================================================================
--- wxOil/fontbase.h (Revision 1640)
+++ wxOil/fontbase.h (Arbeitskopie)
@@ -180,6 +180,7 @@
static void FindClosestFont();
static FontBase* CreateNewFont(FontClass Class, String_64* pFontName);
static OUTLINETEXTMETRIC *GetOutlineTextMetric(FontClass Class, LOGFONT *pLogFont);
+ static String_64* GetNativeFontName(FontClass Class, LOGFONT *pLogFont);
static void InvalidateCharMetrics();
static BOOL GetCharMetrics(wxDC* pDC, WCHAR ch, CharDescription& FontDesc, CharMetrics* pCharMetrics);
static MILLIPOINT GetCharsKerning(wxDC* pDC, WCHAR chLeft, WCHAR chRight,
Index: wxOil/fontbase.cpp
===================================================================
--- wxOil/fontbase.cpp (Revision 1640)
+++ wxOil/fontbase.cpp (Arbeitskopie)
@@ -518,6 +518,24 @@
}
/********************************************************************************************
+> String_64* OILFontMan::GetNativeFontName(FontClass Class, LOGFONT *pLogFont)
+
+ Author: Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+ Created: 01/08/06
+ Inputs: Class - the font class of the font (not used in wxOil but supplied in analogy
+ to GetOutlineTextMetrics)
+ pLogFont - a pointer to it's LOGFONT structure
+ Returns: A pointer to the underlying native font name
+ Purpose: Return the underlying native font name for a font
+
+********************************************************************************************/
+String_64* OILFontMan::GetNativeFontName(FontClass Class, LOGFONT *pLogFont)
+{
+ IGNOREPARAM(Class);
+ return &pLogFont->FaceName;
+}
+
+/********************************************************************************************
> OILFontMan::InvalidateCharMetrics()
Author: Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
Index: Kernel/fontman.h
===================================================================
--- Kernel/fontman.h (Revision 1640)
+++ Kernel/fontman.h (Arbeitskopie)
@@ -223,6 +223,9 @@
BOOL IsFontReplaced(WORD Handle);
BOOL IsFontReplaced(String_64* pFontName, FontClass Class=FC_UNDEFINED);
+ BOOL IsFontUsedInDoc(WORD Handle, Document* pDocument);
+ void OnDocumentLoaded(Document* pDocument);
+
void GetCompatibleFont(const String_64& EncodedName, String_64& CompatibleFont, INT32& Style);
void EncodeFontName(String_64& FontName, String_64& Encoded, INT32 Styles);
void EncodeAndMapFontName(String_64& FontName, String_64& Encoded, INT32 Styles);
@@ -286,6 +289,7 @@
CachedFontItem* AddTempFont(String_64* pFontName, FontClass Class, WORD& hndle);
void InvalidateCache();
void ResetDefaultFont();
+ BOOL IsFontUsedInSiblings(Node* pNode, WORD Handle, WORD CurrentHandle, UINT32 Level);
private:
WORD UniqueHandle;
Index: Kernel/fontman.cpp
===================================================================
--- Kernel/fontman.cpp (Revision 1640)
+++ Kernel/fontman.cpp (Arbeitskopie)
@@ -102,6 +102,9 @@
#include "camtypes.h"
// #include "fontbase.h" - included in fontman.h
+#include "nodetxts.h"
+#include "nodetxtl.h"
+#include "nodetext.h"
#include "fontman.h"
//#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
//#include "txtattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
@@ -333,7 +336,7 @@
{
PORTNOTE("text","CachedFontItem::IsFullyCached - do nothing");
#ifndef DISABLE_TEXT_RENDERING
- TRACEUSER("wuerthne", _T("CachedFontItem::IsFullyCached called") );
+ // TRACEUSER("wuerthne", _T("CachedFontItem::IsFullyCached called") );
ERROR2IF(pFontClass==NULL, FALSE, "A CachedFontItem structure exists without a FontClass!!!");
return (pEnumLogFont!=NULL);
#else
@@ -592,7 +595,7 @@
CachedFontItem* FontManager::AddFont(String_64* Name, FontClass fclass, WORD& retHandle)
{
-
+ TRACEUSER("wuerthne", _T("FontManager::AddFont %s"), (TCHAR*)*Name);
CachedFontItem* pItem = new CachedFontItem;
if (pItem==NULL)
return NULL;
@@ -610,6 +613,7 @@
TheFontList.AddTail(pItem);
retHandle = pItem->Handle;
+ TRACEUSER("wuerthne", _T("AddFont, returning %d"), retHandle);
return pItem;
}
@@ -656,6 +660,10 @@
NULL if unable to find the font
Purpose: Find the entry in the font managers font list which corresponds to this
fontname and font class
+ Note: One might be tempted to include the default font item in the comparison
+ and return the default font handle when the default font name is passed,
+ but this does not happen and this is by design. See OnDocumentLoaded for
+ further information.
********************************************************************************************/
@@ -963,6 +971,136 @@
/********************************************************************************************
+> BOOL FontManager::IsFontUsedInSiblings(Node* pNode, WORD Handle, WORD CurrentHandle, UINT32 Level)
+
+ Author: Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+ Created: 01/08/06
+ Inputs: pNode - the root node of the subtree to check
+ Handle - a font handle
+ CurrentHandle - the font handle applying to the current subtree
+ Level - level in the tree (level 0 is NodeDocument, level 1 are default attributes)
+ Returns: Returns TRUE if a font attribute with the given handle applies to a text
+ object.
+ Purpose: Find out whether a given font is used in a document.
+
+********************************************************************************************/
+
+BOOL FontManager::IsFontUsedInSiblings(Node* pNode, WORD Handle, WORD CurrentHandle, UINT32 Level)
+{
+ // perform a standard child-first recursion keeping track of the current font
+ while(pNode)
+ {
+ Node* pFirstChild = pNode->FindFirstChild();
+ if (pFirstChild && IsFontUsedInSiblings(pFirstChild, Handle, CurrentHandle, Level + 1)) return TRUE;
+ if (IS_A(pNode, AttrTxtFontTypeface))
+ {
+ AttrTxtFontTypeface* pAttr = (AttrTxtFontTypeface*)pNode;
+ CurrentHandle = pAttr->Value.HTypeface;
+ 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");
+ }
+ if (CurrentHandle == Handle && (IS_A(pNode, TextStory) || IS_A(pNode, TextLine) || IS_A(pNode, TextChar)))
+ return TRUE;
+ pNode = pNode->FindNext();
+ }
+ return FALSE;
+}
+
+/********************************************************************************************
+
+> BOOL FontManager::IsFontUsedInDoc(WORD Handle, Document* pDocument)
+
+ Author: Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+ Created: 01/08/06
+ Inputs: Handle - a font handle
+ pDocument - pointer to a document
+ Returns: When called with Handle == DEFAULTHANDLE it returns TRUE if the default
+ attribute applies to a text object. Otherwise, it returns TRUE if the supplied
+ font handle is used in the document
+ Purpose: Find out whether a given font is used in a document.
+
+********************************************************************************************/
+
+BOOL FontManager::IsFontUsedInDoc(WORD Handle, Document* pDocument)
+{
+ Node* pNode = pDocument->GetFirstNode();
+ return IsFontUsedInSiblings(pNode, Handle, ILLEGALFHANDLE, 0);
+}
+
+/********************************************************************************************
+
+> void FontManager::OnDocumentLoaded(Document* pDocument)
+
+ Author: Martin Wuerthner <xara@xxxxxxxxxxxxxxx>
+ Created: 01/08/06
+ Inputs: pDocument - pointer to the newly created/loaded document
+ Purpose: Called after a document has been loaded - allows us to fix the current and
+ default fonts if they are not installed. They are only changed if they are
+ not used in the document.
+
+ Fixing the current font is useful because it stops "Arial (missing)" from
+ being displayed after start-up if Arial is not installed. The same happens
+ when loading a document with the current font set to Arial (or any other
+ font that is not installed). We do not touch the current font if it is
+ actually used in the document because then, it is possible that it was set
+ deliberately (maybe even in a template).
+
+ One might consider a similar approach for the default font, but by definition,
+ the default font is always installed (though it may or may not be Times New
+ Roman), so there is no need to change anything. The default attributes are not
+ saved with the document, so, in contrast to the current font, there cannot be
+ any surprises with fonts that are not installed. The font name referenced by
+ the default font does not matter because the default font attribute is never
+ inherited by any text object in the document.
+
+ This is down to the behaviour of FindFont(String_64*,FontClass), which never
+ returns the default font handle, so any font attribute created by the text tool
+ based on a font name (which involves calling FindFont at some stage) is always
+ different from the default attribute (even if it happens to be the same font as
+ the default font) and hence this attribute is not optimised away. Therefore, each
+ and every text object has a non-default font attribute applied to it.
+
+********************************************************************************************/
+
+void FontManager::OnDocumentLoaded(Document* pDocument)
+{
+ // check if the current font is installed and change it in case it is not (only if the font is not used)
+ NodeAttribute* pAttr = pDocument->GetAttributeMgr().GetCurrentAttribute(CC_RUNTIME_CLASS(BaseTextClass),
+ CC_RUNTIME_CLASS(AttrTxtFontTypeface));
+ if (pAttr)
+ {
+ AttrTxtFontTypeface* pTypeface = (AttrTxtFontTypeface*)pAttr;
+ WORD Handle = pTypeface->Value.HTypeface;
+ TRACEUSER("wuerthne", _T("found current font attribute, handle = %d"), Handle);
+ CachedFontItem *pItem = FindFont(Handle);
+ if (pItem)
+ {
+ String_64* SurfaceFontName = pItem->GetFontName();
+ TRACEUSER("wuerthne", _T("current font name is %s"), (TCHAR*)*SurfaceFontName);
+ ENUMLOGFONT *pEnumLogFont = pItem->GetEnumLogFont();
+ if (pEnumLogFont)
+ {
+ if (!IsFontInstalled(SurfaceFontName) && !IsFontUsedInDoc(Handle, pDocument))
+ {
+ // the current font is not installed and not used in the document,
+ // so find out what the replacement font is and use that instead
+ TRACEUSER("wuerthne", _T("font replaced and not used"));
+ String_64* NativeFontName = OILFontMan::GetNativeFontName(pItem->GetFontClass(),
+ &pEnumLogFont->elfLogFont);
+ WORD NewHandle = CacheNamedFont(NativeFontName, pItem->GetFontClass());
+ if (NewHandle != ILLEGALFHANDLE)
+ {
+ TRACEUSER("wuerthne", _T("change current font to handle %d"), NewHandle);
+ // modify the current attribute directly
+ pTypeface->Value.HTypeface = NewHandle;
+ }
+ }
+ }
+ }
+ }
+}
+
+/********************************************************************************************
+
> CachedFontItem* FontManager::GetFirstFontType(FontClass Class)
Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xxxxxxxx>
@@ -1552,7 +1690,8 @@
// we've done a search for it and it does not exist so we'll use the default
WORD hndle=ILLEGALFHANDLE;
AddTempFont(pFontName, Class, hndle);
-
+
+ TRACEUSER("wuerthne", _T("FontManager::CacheNamedFont = %d"), hndle);
return (hndle);
}
Index: Kernel/camfiltr.cpp
===================================================================
--- Kernel/camfiltr.cpp (Revision 1640)
+++ Kernel/camfiltr.cpp (Arbeitskopie)
@@ -3488,8 +3488,14 @@
// Flag this as a new format document
// But only flag it if we are opening the document rather than importing into an exisiting one
if (TheDocument && !TheDocument->IsImporting())
+ {
TheDocument->SetLoadedAsVersion1File(FALSE);
+ // allow the font manager to fix the current font
+ if (!TheDocument->IsAClipboard())
+ GetApplication()->GetFontManager()->OnDocumentLoaded(TheDocument);
+ }
+
#if !defined(EXCLUDE_FROM_RALPH)
BOOL UpdateBars = TheDocument ? !TheDocument->IsAClipboard() : TRUE;
#endif