reactos/subsys/win32k/objects
diff -u -r1.85 -r1.86
--- text.c 27 Mar 2004 00:35:02 -0000 1.85
+++ text.c 28 Mar 2004 22:39:59 -0000 1.86
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id: text.c,v 1.85 2004/03/27 00:35:02 weiden Exp $ */
+/* $Id: text.c,v 1.86 2004/03/28 22:39:59 gvg Exp $ */
#undef WIN32_LEAN_AND_MEAN
@@ -1057,6 +1057,7 @@
Lf->lfHeight = TM->tmHeight;
Lf->lfWidth = TM->tmAveCharWidth;
Lf->lfWeight = TM->tmWeight;
+ Lf->lfItalic = TM->tmItalic;
Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
Lf->lfCharSet = TM->tmCharSet;
Lf->lfOutPrecision = OUT_STROKE_PRECIS;
@@ -2566,93 +2567,189 @@
return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL);
}
+static UINT FASTCALL
+GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
+{
+ ANSI_STRING EntryFaceNameA;
+ UNICODE_STRING EntryFaceNameW;
+ unsigned Size;
+ OUTLINETEXTMETRICW *Otm;
+ LONG WeightDiff;
+ NTSTATUS Status;
+ UINT Score = 1;
+
+ RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
+ Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+ {
+ EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
+ EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+ }
+ if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
+ {
+ Score += 49;
+ }
+ RtlFreeUnicodeString(&EntryFaceNameW);
+ }
+
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (NULL == Otm)
+ {
+ return Score;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+
+ if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
+ (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
+ {
+ Score += 25;
+ }
+ if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
+ {
+ WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
+ }
+ else
+ {
+ WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
+ }
+ Score += (1000 - WeightDiff) / (1000 / 25);
+
+ ExFreePool(Otm);
+
+ return Score;
+}
+
+static VOID FASTCALL
+FindBestFontFromList(HFONT *Font, UINT *MatchScore, LOGFONTW *LogFont,
+ PUNICODE_STRING FaceName, PLIST_ENTRY Head)
+{
+ PLIST_ENTRY Entry;
+ PFONT_ENTRY CurrentEntry;
+ PFONTGDI FontGDI;
+ UINT Score;
+
+ Entry = Head->Flink;
+ while (Entry != Head)
+ {
+ CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+ if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont)))
+ {
+ Entry = Entry->Flink;
+ continue;
+ }
+ Score = GetFontScore(LogFont, FaceName, FontGDI);
+ if (*MatchScore < Score)
+ {
+ *Font = CurrentEntry->hFont;
+ *MatchScore = Score;
+ }
+ Entry = Entry->Flink;
+ }
+}
+
+static BOOLEAN FASTCALL
+SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
+ LPCWSTR Key)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ NTSTATUS Status;
+ UNICODE_STRING Value;
+
+ RtlInitUnicodeString(&Value, NULL);
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
+ RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = FaceName->Buffer;
+ QueryTable[0].EntryContext = &Value;
+ QueryTable[0].DefaultType = REG_NONE;
+ QueryTable[0].DefaultData = NULL;
+ QueryTable[0].DefaultLength = 0;
+
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
+ Key,
+ QueryTable,
+ NULL,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ RtlFreeUnicodeString(FaceName);
+ *FaceName = Value;
+ }
+
+ return NT_SUCCESS(Status);
+}
+
+static void FASTCALL
+SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
+{
+ if (10 < Level) /* Enough is enough */
+ {
+ return;
+ }
+
+ if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
+ SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
+ {
+ SubstituteFontFamily(FaceName, Level + 1);
+ }
+}
+
NTSTATUS FASTCALL
TextIntRealizeFont(HFONT FontHandle)
{
NTSTATUS Status = STATUS_SUCCESS;
PTEXTOBJ TextObj;
UNICODE_STRING FaceName;
- PLIST_ENTRY Entry;
- PFONT_ENTRY CurrentEntry;
PW32PROCESS Win32Process;
- BOOL Private = FALSE;
+ UINT MatchScore;
TextObj = TEXTOBJ_LockText(FontHandle);
- ASSERT(TextObj);
- if (NULL != TextObj)
+ if (NULL == TextObj)
{
- RtlInitUnicodeString(&FaceName, TextObj->logfont.lfFaceName);
-
- /* find font in private fonts */
- Win32Process = PsGetWin32Process();
-
- IntLockProcessPrivateFonts(Win32Process);
-
- Entry = Win32Process->PrivateFontListHead.Flink;
- while(Entry != &Win32Process->PrivateFontListHead)
- {
- CurrentEntry = (PFONT_ENTRY)CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
-
- if (0 == RtlCompareUnicodeString(&CurrentEntry->FaceName, &FaceName, TRUE))
- {
- TextObj->GDIFontHandle = CurrentEntry->hFont;
- Private = TRUE;
- goto check;
- }
- Entry = Entry->Flink;
+ return STATUS_INVALID_HANDLE;
}
- IntUnLockProcessPrivateFonts(Win32Process);
-
- /* find font in system fonts */
- IntLockGlobalFonts;
-
- Entry = FontListHead.Flink;
- while(Entry != &FontListHead)
+
+ if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
{
- CurrentEntry = (PFONT_ENTRY)CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
-
- if (0 == RtlCompareUnicodeString(&CurrentEntry->FaceName, &FaceName, TRUE))
- {
- TextObj->GDIFontHandle = CurrentEntry->hFont;
- break;
- }
- Entry = Entry->Flink;
+ TEXTOBJ_UnlockText(FontHandle);
+ return STATUS_NO_MEMORY;
}
+ SubstituteFontFamily(&FaceName, 0);
+ MatchScore = 0;
+ TextObj->GDIFontHandle = NULL;
- check:
- if (NULL == TextObj->GDIFontHandle)
- {
- Entry = (Private ? Win32Process->PrivateFontListHead.Flink : FontListHead.Flink);
-
- if(Entry != (Private ? &Win32Process->PrivateFontListHead : &FontListHead))
- {
- DPRINT("Requested font %S not found, using first available font\n",
- TextObj->logfont.lfFaceName)
- CurrentEntry = (PFONT_ENTRY)CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
- TextObj->GDIFontHandle = CurrentEntry->hFont;
- }
- else
- {
- DPRINT1("Requested font %S not found, no fonts loaded at all\n",
- TextObj->logfont.lfFaceName);
- Status = STATUS_NOT_FOUND;
- }
-
- }
+ /* First search private fonts */
+ Win32Process = PsGetWin32Process();
+ IntLockProcessPrivateFonts(Win32Process);
+ FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
+ &TextObj->logfont, &FaceName,
+ &Win32Process->PrivateFontListHead);
+ IntUnLockProcessPrivateFonts(Win32Process);
- if(Private)
- IntUnLockProcessPrivateFonts(Win32Process);
- else
- IntUnLockGlobalFonts;
+ /* Search system fonts */
+ IntLockGlobalFonts;
+ FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
+ &TextObj->logfont, &FaceName,
+ &FontListHead);
+ IntUnLockGlobalFonts;
- ASSERT(! NT_SUCCESS(Status) || NULL != TextObj->GDIFontHandle);
+ if (NULL == TextObj->GDIFontHandle)
+ {
+ DPRINT1("Requested font %S not found, no fonts loaded at all\n",
+ TextObj->logfont.lfFaceName);
+ Status = STATUS_NOT_FOUND;
+ }
- TEXTOBJ_UnlockText(FontHandle);
- }
- else
- {
- Status = STATUS_INVALID_HANDLE;
- }
+ RtlFreeUnicodeString(&FaceName);
+ TEXTOBJ_UnlockText(FontHandle);
+ ASSERT(! NT_SUCCESS(Status) || NULL != TextObj->GDIFontHandle);
return Status;
}