Skip to content

Commit 93d4ed2

Browse files
committed
Add WOFF/WOFF2 decompression option (if running on OS with version of DWrite which supports unpacking it).
1 parent 074b07c commit 93d4ed2

11 files changed

Lines changed: 168 additions & 72 deletions

DWritEx.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ HRESULT GetFileModifiedDate(
107107
_Out_ FILETIME& fileTime
108108
) throw();
109109

110+
HRESULT SaveDWriteFontFile(
111+
IDWriteFontFileStream* fontFileStream,
112+
_In_z_ char16_t const* filePath
113+
);
114+
115+
HRESULT SaveDWriteFontFile(
116+
IDWriteFontFace* fontFace,
117+
_In_z_ char16_t const* filePath
118+
);
119+
110120
// Overload that takes a DWRITE_MEASURING_MODE, since the measuring mode is often used.
111121
HRESULT CreateTextLayout(
112122
IDWriteFactory* factory,

DWritEx.ixx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,41 @@ HRESULT GetFileModifiedDate(
13661366
}
13671367

13681368

1369+
HRESULT SaveDWriteFontFile(
1370+
IDWriteFontFileStream* fontFileStream,
1371+
_In_z_ char16_t const* filePath
1372+
)
1373+
{
1374+
void const* fragment = nullptr;
1375+
void* fragmentContext = nullptr;
1376+
uint64_t fileSize = 0;
1377+
1378+
auto fragmentCleanup = DeferCleanup([&] { fontFileStream->ReleaseFileFragment(fragmentContext); });
1379+
IFR(fontFileStream->GetFileSize(OUT &fileSize));
1380+
IFR(fontFileStream->ReadFileFragment(OUT &fragment, 0, fileSize, OUT &fragmentContext));
1381+
return WriteBinaryFile(filePath, fragment, static_cast<uint32_t>(fileSize));
1382+
}
1383+
1384+
1385+
HRESULT SaveDWriteFontFile(
1386+
IDWriteFontFace* fontFace,
1387+
_In_z_ char16_t const* filePath
1388+
)
1389+
{
1390+
ComPtr<IDWriteFontFile> fontFile;
1391+
ComPtr<IDWriteFontFileStream> fontFileStream;
1392+
ComPtr<IDWriteFontFileLoader> fontFileLoader;
1393+
void const* fontFileReferenceKey = nullptr;
1394+
uint32_t fontFileReferenceKeySize = 0;
1395+
1396+
IFR(GetFontFile(fontFace, &fontFile));
1397+
IFR(fontFile->GetLoader(OUT &fontFileLoader));
1398+
IFR(fontFile->GetReferenceKey(OUT &fontFileReferenceKey, OUT &fontFileReferenceKeySize));
1399+
IFR(fontFileLoader->CreateStreamFromKey(fontFileReferenceKey, fontFileReferenceKeySize, OUT &fontFileStream));
1400+
return SaveDWriteFontFile(fontFileStream, filePath);
1401+
}
1402+
1403+
13691404
HRESULT GetLocalizedStringLanguage(
13701405
IDWriteLocalizedStrings* strings,
13711406
uint32_t stringIndex,

DrawableObject.ixx

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,30 +1039,6 @@ void DrawableObject::GenerateLabel(IAttributeSource& attributeSource, _Inout_ st
10391039
}
10401040

10411041

1042-
HRESULT SaveDWriteFontFile(
1043-
IDWriteFontFace* fontFace,
1044-
_In_z_ char16_t const* filePath
1045-
)
1046-
{
1047-
ComPtr<IDWriteFontFile> fontFile;
1048-
ComPtr<IDWriteFontFileStream> fontFileStream;
1049-
ComPtr<IDWriteFontFileLoader> fontFileLoader;
1050-
void const* fontFileReferenceKey = nullptr;
1051-
void const* fragment = nullptr;
1052-
void* fragmentContext = nullptr;
1053-
uint64_t fileSize = 0;
1054-
uint32_t fontFileReferenceKeySize = 0;
1055-
1056-
IFR(GetFontFile(fontFace, &fontFile));
1057-
IFR(fontFile->GetLoader(OUT &fontFileLoader));
1058-
IFR(fontFile->GetReferenceKey(OUT &fontFileReferenceKey, OUT &fontFileReferenceKeySize));
1059-
IFR(fontFileLoader->CreateStreamFromKey(fontFileReferenceKey, fontFileReferenceKeySize, OUT &fontFileStream));
1060-
IFR(fontFileStream->GetFileSize(OUT &fileSize));
1061-
IFR(fontFileStream->ReadFileFragment(OUT &fragment, 0, fileSize, OUT &fragmentContext));
1062-
return WriteBinaryFile(filePath, fragment, static_cast<uint32_t>(fileSize));
1063-
}
1064-
1065-
10661042
HRESULT SaveGdiFontFile(
10671043
HFONT font,
10681044
_In_z_ char16_t const* filePath
@@ -1090,7 +1066,6 @@ HRESULT SaveGdiFontFile(
10901066
}
10911067

10921068

1093-
10941069
HRESULT DrawableObject::SaveFontFile(
10951070
IAttributeSource& attributeSource,
10961071
DrawingCanvas& drawingCanvas,

FileHelpers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
HRESULT ReadTextFile(const char16_t* filename, OUT std::u16string& text) throw(); // Read UTF-8 or ASCII
1111
HRESULT WriteTextFile(const char16_t* filename, array_ref<char16_t const> text) throw();
12-
HRESULT WriteTextFile(const char16_t* filename, const std::u16string& text) throw(); // Write as UTF-8
1312
HRESULT WriteTextFile(const char16_t* filename, __in_ecount(textLength) const char16_t* text, uint32_t textLength) throw(); // Write as UTF-8
1413
HRESULT ReadBinaryFile(const char16_t* filename, OUT std::vector<uint8_t>& fileBytes);
1514
HRESULT WriteBinaryFile(const char16_t* filename, const std::vector<uint8_t>& fileData);
@@ -31,4 +30,6 @@ const char16_t* FindFileNameStart(array_ref<const char16_t> fileName);
3130
// Returns a pointer to the extension found or the end of the string if not found.
3231
const char16_t* FindFileNameExtension(array_ref<const char16_t> fileName);
3332

33+
void RemoveFileNameExtension(_Inout_ std::u16string& fileName);
34+
3435
bool FileContainsWildcard(array_ref<const char16_t> fileName);

FileHelpers.ixx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,6 @@ HRESULT ReadTextFile(const char16_t* filename, OUT std::u16string& text) throw()
8181
}
8282

8383

84-
HRESULT WriteTextFile(const char16_t* filename, const std::u16string& text) throw()
85-
{
86-
return WriteTextFile(filename, text.c_str(), static_cast<uint32_t>(text.size()));
87-
}
88-
89-
9084
HRESULT WriteTextFile(
9185
const char16_t* filename,
9286
array_ref<char16_t const> text
@@ -318,6 +312,20 @@ const char16_t* FindFileNameExtension(array_ref<char16_t const> fileName)
318312
}
319313

320314

315+
void RemoveFileNameExtension(_Inout_ std::u16string& fileName)
316+
{
317+
auto* extension = FindFileNameExtension(fileName);
318+
319+
if (extension > fileName.data())
320+
{
321+
if (extension[-1] == '.')
322+
--extension;
323+
324+
fileName.erase(extension - fileName.data());
325+
}
326+
}
327+
328+
321329
bool FileContainsWildcard(array_ref<char16_t const> fileName)
322330
{
323331
for (char16_t ch : fileName)

MainWindow.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class MainWindow
6969
HRESULT LoadDrawableObjectsSettings(_In_z_ char16_t const* filePath, bool clearExistingItems = true, bool merge = false);
7070
HRESULT StoreDrawableObjectsSettings(_In_z_ char16_t const* filePath);
7171
HRESULT SaveSelectedFontFile();
72+
HRESULT SaveUnpackedWoffFontFile();
7273
HRESULT ExportFontGlyphData();
7374
HRESULT AutofitDrawableObjects(bool useMaximumWidth, bool useMaximumHeight);
7475
HRESULT GetSelectedDrawableObject(_Out_ uint32_t& selectedDrawableObject); // S_FALSE and ~0 if none.
@@ -115,11 +116,13 @@ class MainWindow
115116
// Miscellaneous public.
116117

117118
public:
118-
void AppendLogCached(const char16_t* logMessage, ...);
119-
void AppendLog(const char16_t* logMessage, ...);
120-
void AppendLogDirect(const char16_t* logMessage);
121-
void ShowMessageAndAppendLog(const char16_t* logMessage, ...);
122-
HRESULT ShowMessageIfError(const char16_t* logMessage, HRESULT hr);
119+
void AppendLogCached(char16_t const* logMessage, ...);
120+
void AppendLog(char16_t const* logMessage, ...);
121+
void AppendLogUnformatted(char16_t const* logMessage);
122+
void ShowMessageAndAppendLog(char16_t const* logMessage, ...);
123+
void ShowMessageAndAppendLogUnformatted(char16_t const* logMessage);
124+
HRESULT ShowMessageIfError(char16_t const* logMessage, HRESULT hr, ...);
125+
123126
void ClearLog();
124127

125128
////////////////////////////////////////

MainWindow.ixx

Lines changed: 97 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,7 @@ HRESULT MainWindow::SaveSelectedFontFile()
19211921
IFR(GetSelectedDrawableObject(OUT selectedDrawableObjectIndex));
19221922
IFR(GetFileOrFamilyName(selectedDrawableObjectIndex, OUT filePath));
19231923

1924-
if (!GetSaveFileName(hwnd_, filePath.c_str(), filters, u"ttf", OUT filePath))
1924+
if (!GetSaveFileName(hwnd_, filters, u"otf", filePath.c_str(), OUT filePath))
19251925
return S_OK;
19261926

19271927
DrawingCanvasControl& drawingCanvas = *DrawingCanvasControl::GetClass(GetWindowFromId(hwnd_, IdcDrawingCanvas));
@@ -1948,6 +1948,61 @@ HRESULT MainWindow::SaveSelectedFontFile()
19481948
}
19491949

19501950

1951+
HRESULT MainWindow::SaveUnpackedWoffFontFile()
1952+
{
1953+
std::u16string openFilePath, saveFilePath;
1954+
auto const* openFilters = u"Fonts (*.woff *.woff2)\0" u"*.woff;*.woff2\0"
1955+
u"All files (*)\0" u"*\0";
1956+
auto const* saveFilters = u"Fonts (*.otf *.ttf)\0" u"*.otf;*.ttf\0"
1957+
u"All files (*)\0" u"*\0";
1958+
1959+
ComPtr<IDWriteFactory5> dwriteFactory;
1960+
1961+
IFR(ShowMessageIfError(
1962+
u"Operating system does not not support IDWriteFactory5. TextLayoutSampler uses DWrite to unpack WOFF files. Error = 0x%08X",
1963+
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), reinterpret_cast<IUnknown**>(OUT &dwriteFactory))
1964+
));
1965+
1966+
if (!GetOpenFileName(hwnd_, openFilters, OUT openFilePath, u"Open WOFF font file"))
1967+
return S_FALSE;
1968+
1969+
saveFilePath = openFilePath;
1970+
RemoveFileNameExtension(IN OUT saveFilePath);
1971+
if (!GetSaveFileName(hwnd_, saveFilters, u"otf", saveFilePath.c_str(), OUT saveFilePath))
1972+
return S_FALSE;
1973+
1974+
std::vector<uint8_t> fileData;
1975+
IFR(ShowMessageIfError(
1976+
u"Could not read file",
1977+
ReadBinaryFile(openFilePath.c_str(), OUT fileData)
1978+
));
1979+
1980+
DWRITE_CONTAINER_TYPE containerType = dwriteFactory->AnalyzeContainerType(fileData.data(), static_cast<uint32_t>(fileData.size()));
1981+
if (containerType == DWRITE_CONTAINER_TYPE_UNKNOWN)
1982+
{
1983+
ShowMessageAndAppendLog(u"Unknown container type for file '%s'", openFilePath.c_str());
1984+
return DWRITE_E_FILEFORMAT;
1985+
}
1986+
1987+
ComPtr<IDWriteFontFileStream> fontFileStream;
1988+
IFR(dwriteFactory->UnpackFontFile(
1989+
containerType,
1990+
fileData.data(),
1991+
static_cast<uint32_t>(fileData.size()),
1992+
OUT &fontFileStream
1993+
));
1994+
1995+
IFR(ShowMessageIfError(
1996+
u"Could not write font to file. Error = 0x%08X writing to '%s'.",
1997+
SaveDWriteFontFile(fontFileStream, saveFilePath.c_str()),
1998+
saveFilePath.c_str()
1999+
));
2000+
2001+
AppendLog(u"Wrote font to file '%s'.\r\n", saveFilePath.c_str());
2002+
return S_OK;
2003+
}
2004+
2005+
19512006
HRESULT MainWindow::GetAllFontCharacters(bool copyToClipboardInstead, bool getOnlyColorFontCharacters)
19522007
{
19532008
uint32_t selectedDrawableObjectIndex;
@@ -1999,12 +2054,10 @@ HRESULT MainWindow::ExportFontGlyphData()
19992054
IFR(GetFileOrFamilyName(selectedDrawableObjectIndex, OUT filePath));
20002055

20012056
// Remove any extension, appending underscore to separate.
2002-
filePath.erase(FindFileNameExtension(filePath) - filePath.data());
2003-
if (!filePath.empty() && filePath.back() == '.')
2004-
filePath.pop_back();
2057+
RemoveFileNameExtension(IN OUT filePath);
20052058
filePath += u"_";
20062059

2007-
if (!GetSaveFileName(hwnd_, filePath.c_str(), filters, nullptr, OUT filePath))
2060+
if (!GetSaveFileName(hwnd_, filters, nullptr, filePath.c_str(), OUT filePath))
20082061
return S_OK;
20092062

20102063
DrawingCanvasControl& drawingCanvas = *DrawingCanvasControl::GetClass(GetWindowFromId(hwnd_, IdcDrawingCanvas));
@@ -2096,7 +2149,7 @@ HRESULT MainWindow::StoreDrawableObjectsSettings()
20962149
{
20972150
std::u16string filePath;
20982151

2099-
if (!GetSaveFileName(hwnd_, previousSettingsFilePath_.c_str(), g_openSaveFiltersList, u"TextLayoutSamplerSettings", OUT filePath))
2152+
if (!GetSaveFileName(hwnd_, g_openSaveFiltersList, u"TextLayoutSamplerSettings", previousSettingsFilePath_.c_str(), OUT filePath))
21002153
return S_OK;
21012154

21022155
HRESULT hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
@@ -2895,7 +2948,8 @@ void MainWindow::Resize(int id)
28952948
void MainWindow::OnAssortedActions(HWND anchorControl)
28962949
{
28972950
TrackPopupMenu_Item constexpr static items[] = {
2898-
{IdcSaveSelectedFontFile, u"Save font file..."},
2951+
{IdcSaveSelectedFontFile, u"Save font file..."},
2952+
{IdcSaveUnpackedWoffFontFile, u"Save unpacked WOFF font file..."},
28992953
{IdcExportGlyphImageData, u"Export all glyph image data..." },
29002954
{ 0, u"-" },
29012955
{IdcGetAllFontCharacters, u"Get all font characters"},
@@ -2915,6 +2969,7 @@ void MainWindow::OnAssortedActions(HWND anchorControl)
29152969
switch (menuId)
29162970
{
29172971
case IdcSaveSelectedFontFile: SaveSelectedFontFile(); break;
2972+
case IdcSaveUnpackedWoffFontFile: SaveUnpackedWoffFontFile(); break;
29182973
case IdcGetAllFontCharacters: GetAllFontCharacters(/*copyToClipboardInstead*/false, /*getOnlyColorFontCharacters*/ false); break;
29192974
case IdcGetAllColorFontCharacters: GetAllFontCharacters(/*copyToClipboardInstead*/false, /*getOnlyColorFontCharacters*/ true); break;
29202975
case IdcCopyAllFontCharacters: GetAllFontCharacters(/*copyToClipboardInstead*/true, /*getOnlyColorFontCharacters*/ false); break;
@@ -2925,73 +2980,82 @@ void MainWindow::OnAssortedActions(HWND anchorControl)
29252980
}
29262981

29272982

2928-
void MainWindow::AppendLogCached(const char16_t* logMessage, ...)
2983+
void MainWindow::AppendLogCached(char16_t const* logMessage, ...)
29292984
{
29302985
va_list argList;
29312986
va_start(argList, logMessage);
2932-
29332987
char16_t buffer[1000];
29342988
buffer[0] = 0;
2935-
StringCchVPrintf(OUT ToWChar(buffer), countof(buffer), ToWChar(logMessage), argList);
29362989

2990+
StringCchVPrintf(OUT ToWChar(buffer), countof(buffer), ToWChar(logMessage), argList);
29372991
cachedLog_ += buffer;
29382992
}
29392993

29402994

2941-
void MainWindow::AppendLogDirect(const char16_t* logMessage)
2995+
void MainWindow::AppendLogUnformatted(char16_t const* logMessage)
29422996
{
29432997
HWND hwndLog = GetWindowFromId(hwnd_, IdcLog);
29442998

2945-
uint32_t textLength = Edit_GetTextLength(hwndLog);
29462999
if (!cachedLog_.empty())
29473000
{
2948-
Edit_SetSel(hwndLog, textLength, textLength);
2949-
Edit_ReplaceSel(hwndLog, cachedLog_.c_str());
2950-
cachedLog_.clear();
2951-
textLength = Edit_GetTextLength(hwndLog);
3001+
cachedLog_ += logMessage;
3002+
logMessage = cachedLog_.data();
29523003
}
2953-
Edit_SetSel(hwndLog, textLength, textLength);
3004+
uint32_t previousTextLength = Edit_GetTextLength(hwndLog);
3005+
Edit_SetSel(hwndLog, previousTextLength, previousTextLength);
29543006
Edit_ReplaceSel(hwndLog, logMessage);
3007+
cachedLog_.clear();
29553008
}
29563009

29573010

2958-
void MainWindow::AppendLog(const char16_t* logMessage, ...)
3011+
void MainWindow::AppendLog(char16_t const* logMessage, ...)
29593012
{
29603013
va_list argList;
29613014
va_start(argList, logMessage);
2962-
29633015
char16_t buffer[1000];
29643016
buffer[0] = 0;
2965-
StringCchVPrintf(OUT ToWChar(buffer), countof(buffer), ToWChar(logMessage), argList);
29663017

2967-
AppendLogDirect(buffer);
3018+
StringCchVPrintf(OUT ToWChar(buffer), countof(buffer), ToWChar(logMessage), argList);
3019+
AppendLogUnformatted(buffer);
29683020
}
29693021

29703022

2971-
HRESULT MainWindow::ShowMessageIfError(const char16_t* logMessage, HRESULT hr)
3023+
void MainWindow::ShowMessageAndAppendLogUnformatted(char16_t const* logMessage)
29723024
{
2973-
if (FAILED(hr))
2974-
{
2975-
MainWindow::ShowMessageAndAppendLog(logMessage, hr);
2976-
}
2977-
return hr;
3025+
MessageBoxShaded::Show(hwnd_, logMessage, u"", MB_OK | MB_ICONWARNING);
3026+
3027+
AppendLogUnformatted(logMessage);
3028+
size_t messageLength = wcslen(ToWChar(logMessage));
3029+
if (messageLength > 0 && logMessage[messageLength - 1] != '\n')
3030+
AppendLogUnformatted(u"\r\n");
29783031
}
29793032

29803033

2981-
void MainWindow::ShowMessageAndAppendLog(const char16_t* logMessage, ...)
3034+
void MainWindow::ShowMessageAndAppendLog(char16_t const* logMessage, ...)
29823035
{
29833036
va_list argList;
29843037
va_start(argList, logMessage);
2985-
29863038
char16_t buffer[1000];
29873039
buffer[0] = 0;
3040+
29883041
StringCchVPrintf(OUT ToWChar(buffer), countof(buffer), ToWChar(logMessage), argList);
3042+
ShowMessageAndAppendLogUnformatted(buffer);
3043+
}
3044+
29893045

2990-
MessageBoxShaded::Show(hwnd_, buffer, u"", MB_OK|MB_ICONWARNING);
3046+
HRESULT MainWindow::ShowMessageIfError(char16_t const* logMessage, HRESULT hr, ...)
3047+
{
3048+
if (FAILED(hr))
3049+
{
3050+
va_list argList;
3051+
va_start(argList, logMessage);
3052+
char16_t buffer[1000];
3053+
buffer[0] = 0;
29913054

2992-
AppendLogDirect(buffer);
2993-
if (buffer[wcslen(ToWChar(buffer))] != '\n')
2994-
AppendLogDirect(u"\r\n");
3055+
StringCchVPrintf(OUT ToWChar(buffer), countof(buffer), ToWChar(logMessage), argList);
3056+
MainWindow::ShowMessageAndAppendLogUnformatted(buffer);
3057+
}
3058+
return hr;
29953059
}
29963060

29973061

MainWindow.rc

-3.55 KB
Binary file not shown.

0 commit comments

Comments
 (0)