Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit c9dd00c

Browse files
authored
Merge pull request #5732 from livecodeian/bugfix-20035
[[ Bug 20035 ]] Implement Win32 font listing using DirectWrite
2 parents 0189842 + 5ab4658 commit c9dd00c

File tree

5 files changed

+114
-182
lines changed

5 files changed

+114
-182
lines changed

docs/notes/bugfix-20035.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Fix incorrect fontnames listed on Windows

engine/src/w32flst.cpp

Lines changed: 28 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -368,45 +368,12 @@ void MCFontlist::freeprinterfonts()
368368
while (tmp != fonts);
369369
}
370370

371-
// SN-2015-03-02: [[ Bug 14661 ]] New context for the
372-
// font listing callback function.
373-
// An array is used to keep track of the font already
374-
// added (hash comparison faster than that looking for
375-
// a string in a list)
376-
struct MCFontListing
371+
static compare_t _MCFontListCompareNames(const MCValueRef *p_left, const MCValueRef *p_right)
377372
{
378-
MCArrayRef array;
379-
MCListRef list;
380-
};
373+
MCAssert(MCValueGetTypeCode(*p_left) == kMCValueTypeCodeString);
374+
MCAssert(MCValueGetTypeCode(*p_right) == kMCValueTypeCodeString);
381375

382-
int CALLBACK fontnames_FontFamProc(const LOGFONTW * lpelf,
383-
const TEXTMETRICW * lpntm,
384-
DWORD FontType, LPARAM lParam)
385-
{
386-
// SN-2015-03-02: [[ Bug 14661 ]] A MCFontListing struct
387-
// is now passed to the callback functions.
388-
MCFontListing* t_fontlist = (MCFontListing*)lParam;
389-
MCNewAutoNameRef t_name;
390-
391-
size_t t_length;
392-
if (StringCchLengthW(lpelf->lfFaceName, LF_FACESIZE, &t_length) != S_OK)
393-
return False;
394-
395-
if (!MCNameCreateWithChars(lpelf->lfFaceName, t_length, &t_name))
396-
return False;
397-
398-
// SN-2015-03-02: [[ Bug 14661 ]] Skip names that
399-
// we have already added to the array, comparing
400-
// full name to full name. That avoid to skip
401-
// "Segoe UI" if "Segoe UI Light" has already been
402-
// loaded, like it was with MCStringContains
403-
MCValueRef t_value;
404-
if (MCArrayFetchValue(t_fontlist->array, true, *t_name, t_value))
405-
return True;
406-
407-
// Add the font name in the array, and in the list.
408-
MCArrayStoreValue(t_fontlist -> array, true, *t_name, kMCEmptyString);
409-
return MCListAppend(t_fontlist->list, MCNameGetString(*t_name)) ? True : False;
376+
return MCStringCompareTo(MCStringRef(*p_left), MCStringRef(*p_right), kMCStringOptionCompareExact);
410377
}
411378

412379
bool MCFontlist::getfontnames(MCStringRef p_type, MCListRef& r_names)
@@ -417,75 +384,29 @@ bool MCFontlist::getfontnames(MCStringRef p_type, MCListRef& r_names)
417384
return true;
418385
}
419386

420-
MCScreenDC *pms = (MCScreenDC *)MCscreen;
421-
HDC hdc;
422-
#ifdef _DESKTOP
423-
// MM-2013-09-13:: [[ RefactorGraphics ]] Tweak to get things compiling for server.
424-
if (MCStringIsEqualToCString(p_type, "printer", kMCCompareCaseless))
425-
hdc = static_cast<MCWindowsPrinter *>(MCsystemprinter) -> GetDC();
426-
else
427-
#endif
428-
hdc = pms->getsrchdc();
429-
LOGFONTW lf;
430-
lf.lfCharSet = DEFAULT_CHARSET;
431-
lf.lfFaceName[0] = '\0';
432-
lf.lfPitchAndFamily = 0;
433-
434-
// SN-2015-03-02: [[ Bug 14661 ]] Initialise the
435-
// MCFontListing members.
436-
bool t_success;
437-
MCFontListing t_fontlist = {nil, nil};
438-
439-
t_success = MCArrayCreateMutable(t_fontlist.array)
440-
&& MCListCreateMutable('\n', t_fontlist.list);
441-
442-
if (t_success)
443-
t_success = EnumFontFamiliesExW(hdc, &lf, (FONTENUMPROCW)fontnames_FontFamProc, (LPARAM)(&t_fontlist), 0) == True;
444-
445-
if (t_success)
446-
t_success = MCListCopy(t_fontlist.list, r_names);
447-
448-
// SN-2015-03-02: [[ Bug 14661 ]] Cleanup the
449-
// MCFontListing members.
450-
MCValueRelease(t_fontlist . array);
451-
MCValueRelease(t_fontlist . list);
452-
453-
return t_success;
454-
}
387+
MCAutoProperListRef t_names;
388+
if (!MCGFontGetPlatformFontList(&t_names))
389+
return false;
455390

456-
typedef struct
457-
{
458-
bool success;
459-
MCListRef list;
460-
uint2 *sizes;
461-
uindex_t size_count;
462-
} fontsizes_context;
463-
464-
int CALLBACK fontsizes_FontFamProc(const ENUMLOGFONTW* lpelf,
465-
const NEWTEXTMETRICW* lpntm,
466-
DWORD FontType, LPARAM lParam)
467-
{
468-
fontsizes_context *context = (fontsizes_context*)lParam;
469-
if (!(FontType & TRUETYPE_FONTTYPE))
470-
{ //if not true-type font
471-
uint2 size = uint2((((lpelf->elfLogFont.lfHeight * 72)
472-
/ SCREEN_WIDTH_FOR_FONT_USE) * 8 / 7));
473-
for (uindex_t i = 0; i < context->size_count; i++)
474-
if (context->sizes[i] == size)
475-
return True; //return to callback function again
476-
context->success = MCMemoryResizeArray(context->size_count + 1, context->sizes, context->size_count);
477-
if (context->success)
478-
{
479-
context->sizes[context->size_count - 1] = size;
480-
context->success = MCListAppendInteger(context->list, size);
481-
}
482-
return context->success ? True : False;
483-
}
484-
else
485-
{ //if true-type font, size is always 0.
486-
context->success = MCListAppendInteger(context->list, 0);
487-
return False; //stop right here. no more callback function
391+
MCAssert(MCProperListIsListOfType(*t_names, kMCValueTypeCodeString));
392+
// sort list (of strings) alphabetically
393+
if (!MCProperListSort(*t_names, false, _MCFontListCompareNames))
394+
return false;
395+
396+
MCAutoListRef t_name_list;
397+
if (!MCListCreateMutable('\n', &t_name_list))
398+
return false;
399+
400+
uintptr_t t_index = 0;
401+
MCValueRef t_element = nil;
402+
while (MCProperListIterate(*t_names, t_index, t_element))
403+
{
404+
if (!MCListAppend(*t_name_list, t_element))
405+
return false;
488406
}
407+
408+
r_names = t_name_list.Take();
409+
return true;
489410
}
490411

491412
bool MCFontlist::getfontsizes(MCStringRef p_fname, MCListRef& r_sizes)
@@ -499,76 +420,12 @@ bool MCFontlist::getfontsizes(MCStringRef p_fname, MCListRef& r_sizes)
499420
if (!MCListCreateMutable('\n', &t_list))
500421
return false;
501422

502-
fontsizes_context context;
503-
context.list = *t_list;
504-
context.success = true;
505-
context.sizes = nil;
506-
context.size_count = 0;
507-
508-
MCAutoStringRefAsWString t_fname_wstr;
509-
if (!t_fname_wstr.Lock(p_fname))
510-
return false;
511-
512-
MCScreenDC *pms = (MCScreenDC *)MCscreen;
513-
HDC hdc = pms->getsrchdc();
514-
515-
LOGFONTW lf;
516-
lf.lfCharSet = DEFAULT_CHARSET;
517-
lf.lfPitchAndFamily = 0;
518-
519-
// Copy the font family name
520-
if (StringCchCopyW(lf.lfFaceName, LF_FACESIZE, *t_fname_wstr) != S_OK)
423+
// All DirectWrite fonts are scalable, so size is always 0.
424+
if (!MCListAppendInteger(*t_list, 0))
521425
return false;
522426

523-
EnumFontFamiliesExW(hdc, &lf, (FONTENUMPROCW)fontsizes_FontFamProc, (LPARAM)&context, 0);
524-
525-
MCMemoryDeleteArray(context.sizes);
526-
if (context.success)
527-
return MCListCopy(*t_list, r_sizes);
528-
529-
return false;
530-
}
531-
532-
#ifdef FOR_TRUE_TYPE_ONLY
533-
static uint2 nfonts;
534-
static MCListRef s_style_list;
535-
enum FontQueryType {
536-
FQ_NAMES,
537-
FQ_SIZES,
538-
FQ_STYLES,
539-
};
540-
541-
int CALLBACK MyFontFamProc(ENUMLOGFONTA FAR* lpelf,
542-
NEWTEXTMETRICA FAR* lpntm,
543-
int FontType, LPARAM lParam)
544-
{
545-
switch (lParam)
546-
{
547-
case FQ_STYLES:
548-
{
549-
if (!(FontType & TRUETYPE_FONTTYPE))
550-
{ //not true-type font
551-
/* UNCHECKED */ MCListAppend(s_style_list, MCN_plain) &&
552-
MCListAppend(s_style_list, MCN_bold) &&
553-
MCListAppend(s_style_list, MCN_italic) &&
554-
MCListAppend(s_style_list, MCN_bold_italic);
555-
return False; //stop right here, do not continue looping through callback
556-
}
557-
char *style = (char *)lpelf->elfStyle;
558-
if (strequal(style, "Regular"))
559-
/* UNCHECKED */ MCListAppend(s_style_list, MCN_plain);
560-
else if (strequal(style, "Bold Italic"))
561-
/* UNCHECKED */ MCListAppend(s_style_list, MCN_bold_italic)
562-
else
563-
/* UNCHECKED */ MCListAppendCString(s_style_list, (char*)lpelf->elfStyle);
564-
break;
565-
}
566-
default:
567-
break;
568-
}
569-
return True;
427+
return MCListCopy(*t_list, r_sizes);
570428
}
571-
#endif
572429

573430
bool MCFontlist::getfontstyles(MCStringRef p_fname, uint2 fsize, MCListRef& r_styles)
574431
{
@@ -583,20 +440,10 @@ bool MCFontlist::getfontstyles(MCStringRef p_fname, uint2 fsize, MCListRef& r_st
583440
return false;
584441

585442
bool t_success = true;
586-
#ifdef FOR_TRUE_TYPE_ONLY
587-
s_style_list = *t_list;
588-
nfonts = 0;
589-
char mappedName[LF_FACESIZE];
590-
mapfacename(mappedName, fname);
591-
MCScreenDC *pms = (MCScreenDC *)MCscreen;
592-
HDC hdc = pms->getmemsrchdc();
593-
EnumFontFamiliesA(hdc, mappedName, (FONTENUMPROC)MyFontFamProc, FQ_STYLES);
594-
#else
595443
t_success = MCListAppend(*t_list, MCN_plain) &&
596444
MCListAppend(*t_list, MCN_bold) &&
597445
MCListAppend(*t_list, MCN_italic) &&
598446
MCListAppend(*t_list, MCN_bold_italic);
599-
#endif
600447

601448
return t_success && MCListCopy(*t_list, r_styles);
602449
}

libfoundation/include/foundation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3362,7 +3362,7 @@ typedef bool (*MCProperListMapCallback)(void *context, MCValueRef element, MCVal
33623362
MC_DLLEXPORT bool MCProperListMap(MCProperListRef list, MCProperListMapCallback p_callback, MCProperListRef& r_new_list, void *context);
33633363

33643364
// Sort list by comparing elements using the provided callback.
3365-
typedef compare_t (*MCProperListQuickSortCallback)(const MCValueRef left, const MCValueRef right);
3365+
typedef compare_t (*MCProperListQuickSortCallback)(const MCValueRef *left, const MCValueRef *right);
33663366
MC_DLLEXPORT bool MCProperListSort(MCProperListRef list, bool p_reverse, MCProperListQuickSortCallback p_callback);
33673367

33683368
typedef compare_t (*MCProperListCompareElementCallback)(void *context, const MCValueRef left, const MCValueRef right);

libgraphics/include/graphics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,9 @@ inline MCGFont MCGFontMake(void *fid, uint16_t size, uint16_t fixed_advance, MCG
564564
bool MCGFontAddPlatformFileResource(MCStringRef p_file_resource_path);
565565
bool MCGFontRemovePlatformFileResource(MCStringRef p_file_resource_path);
566566

567+
// Get list of available font families
568+
bool MCGFontGetPlatformFontList(MCProperListRef &r_fonts);
569+
567570
////////////////////////////////////////////////////////////////////////////////
568571

569572
inline bool MCGPointIsEqual(const MCGPoint &p_a, const MCGPoint &p_b)

libgraphics/src/directwrite-skia.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,87 @@ bool MCGFontRemovePlatformFileResource(MCStringRef p_file)
480480

481481
////////////////////////////////////////////////////////////////////////////////
482482

483+
static bool MCGDWGetDefaultLocalizedString(IDWriteLocalizedStrings *p_strings, MCStringRef &r_string)
484+
{
485+
UINT32 t_index = 0;
486+
BOOL t_found = FALSE;
487+
if (!SUCCEEDED(p_strings->FindLocaleName(L"en-us", &t_index, &t_found)))
488+
return false;
489+
490+
// Fallback to first name in list
491+
if (!t_found)
492+
t_index = 0;
493+
494+
UINT32 t_name_length;
495+
if (!SUCCEEDED(p_strings->GetStringLength(t_index, &t_name_length)))
496+
return false;
497+
498+
MCAutoArray<WCHAR> t_buffer;
499+
if (!t_buffer.New(t_name_length + 1))
500+
return false;
501+
if (!SUCCEEDED(p_strings->GetString(t_index, t_buffer.Ptr(), t_name_length + 1)))
502+
return false;
503+
504+
return MCStringCreateWithWString(t_buffer.Ptr(), r_string);
505+
}
506+
507+
static bool MCGDWAddCollectionFontsToList(IDWriteFontCollection *p_collection, MCProperListRef p_list)
508+
{
509+
if (p_collection == nil)
510+
return true;
511+
512+
bool t_success = true;
513+
514+
UINT32 t_count;
515+
t_count = p_collection->GetFontFamilyCount();
516+
517+
for (uint32_t i = 0; t_success && i < t_count; i++)
518+
{
519+
IDWriteFontFamily *t_family = nil;
520+
t_success = SUCCEEDED(p_collection->GetFontFamily(i, &t_family));
521+
522+
IDWriteLocalizedStrings *t_names = nil;
523+
if (t_success)
524+
t_success = SUCCEEDED(t_family->GetFamilyNames(&t_names));
525+
526+
MCAutoStringRef t_name;
527+
if (t_success)
528+
t_success = MCGDWGetDefaultLocalizedString(t_names, &t_name);
529+
530+
if (t_success)
531+
t_success = MCProperListPushElementOntoBack(p_list, *t_name);
532+
533+
if (t_names != nil)
534+
t_names->Release();
535+
if (t_family != nil)
536+
t_family->Release();
537+
}
538+
}
539+
540+
bool MCGFontGetPlatformFontList(MCProperListRef &r_fonts)
541+
{
542+
bool t_success = true;
543+
544+
MCAutoProperListRef t_fonts;
545+
t_success = MCProperListCreateMutable(&t_fonts);
546+
547+
IDWriteFontCollection *t_system_collection = nil;
548+
if (t_success)
549+
t_success = SUCCEEDED(s_DWFactory->GetSystemFontCollection(&t_system_collection));
550+
if (t_success)
551+
t_success = MCGDWAddCollectionFontsToList(t_system_collection, *t_fonts);
552+
553+
if (t_success && s_DWFontCollection != nil)
554+
t_success = MCGDWAddCollectionFontsToList(s_DWFontCollection, *t_fonts);
555+
556+
if (t_success)
557+
r_fonts = t_fonts.Take();
558+
559+
return t_success;
560+
}
561+
562+
////////////////////////////////////////////////////////////////////////////////
563+
483564
// Creates a DirectWrite text format object from an HFONT
484565
static IDWriteTextFormat* MCGDWTextFormatFromHFONT(HFONT p_hfont, MCGFloat p_size)
485566
{

0 commit comments

Comments
 (0)