-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Font Spec #4842
base: master
Are you sure you want to change the base?
Font Spec #4842
Changes from 4 commits
82001af
7e4d0cc
6f29e8f
aae5df0
525b902
26b69db
91f932b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,387 @@ | ||
--- | ||
author: Ryan Fu @ryfu-msft | ||
created on: 2024-10-1 | ||
last updated: 2024-10-1 | ||
issue id: 166 | ||
--- | ||
|
||
# Support for installation of fonts | ||
|
||
For [#66](https://github.com/microsoft/winget-cli/issues/166) | ||
|
||
## Abstract | ||
This spec outlines the design for supporting the installation of fonts. | ||
|
||
## Context | ||
|
||
### Font File Types | ||
|
||
This feature will support font files with the following file types: | ||
- .ttf (True Type File) - Most common format | ||
- .ttc (True Type Collection) | ||
- .otf (Open Type Font) | ||
|
||
The following font types to my knowledge are not supported: | ||
- .woff & .woff2 (developed by Google for the modern browser) | ||
- .eot (Embedded OpenType font file) Not used because of security issues. | ||
|
||
### Installing Fonts | ||
Typically, a user would download the font file and drag it to the `C:\Windows\Fonts` directory in the explorer view, but there are a couple things happening behind the scenes. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the drag and drop flow trigger the same endpoints as double clicking the file in File Explorer? Just trying to understand if all the current methods of installing fonts end up at the same place |
||
|
||
Depending on the scope of the user, the font will be stored in two locations: | ||
- `C:\Windows\Fonts` (Machine ) | ||
- `%LOCALAPPDATA%\Microsoft\Windows\Fonts` (User Mode) | ||
|
||
In addition, a new registry entry is created in the following registry paths: | ||
The name of the registry key typically matches the title of the font file, and the value is set to the path of the font file. | ||
|
||
#### Local Machine Registry | ||
--- | ||
|
||
`Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts` | ||
|
||
| Name | Type | Value | | ||
| -------- | ------- | ------- | | ||
| Calibri Bold Italic (TrueType) | REG_SZ | calibriz.ttf | | ||
Check failure on line 45 in doc/specs/#166 - Font Support.md GitHub Actions / Check Spelling
|
||
|
||
> Note that for the LOCAL_MACHINE registry entry, only the file name is specified, not the full path. | ||
|
||
#### Current User Registry | ||
--- | ||
|
||
`Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts` | ||
|
||
| Name | Type | Value | | ||
| -------- | ------- | ------- | | ||
| Roboto Bold Italic (TrueType) | REG_SZ | C:\Users\ryfu\AppData\Local\Microsoft\Windows\Fonts\Roboto-BoldItalic.ttf | | ||
|
||
|
||
### Uninstalling Fonts | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
To remove a font, the inverse operation of the steps above need to be completed. | ||
1. Remove the registry key entry for that specific font file | ||
2. Remove the file from the font directory | ||
|
||
|
||
## Manifest Changes | ||
- Addition of `font` to `installerType` and `nestedInstallerType` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any way for the manifest to specify the font name and not just the path to it? Thinking of a use case where the file is something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that the font files contain face and family metadata already and we are planning to always use that. If that is not always the case, then we do probably need a way to specify the name. The registry value names don't appear to have any actual impact on the enumerated fonts (from what I remember of @ryfu-msft investigation), but maybe they are important in the event that the file doesn't contain the relevant metadata. |
||
|
||
Manifest Example: | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
```yaml | ||
PackageIdentifier: Microsoft.CascadiaCode | ||
PackageName: Cascadia | ||
PackageVersion: 2404.23 | ||
Installers: | ||
- InstallerType: zip | ||
InstallerUrl: https://github.com/microsoft/cascadia-code/releases/download/v2404.23/CascadiaCode-2404.23.zip | ||
InstallerSha256: a911410626c0e09d03fa3fdda827188fda96607df50fecc3c5fee5906e33251b | ||
NestedInstallerFiles: | ||
- RelativeFilePath: ttf/CascadiaCodeItalic.ttf | ||
- RelativeFilePath: ttf/CascadiaMonoNFItalic.ttf | ||
ManifestType: installer | ||
ManifestVersion: 1.9.0 | ||
``` | ||
|
||
## Font Index | ||
A new `PredefinedSource` will be created for `Fonts`. `PredefinedInstalledFontFactory` will be defined that creates a SQLite index from the installed font information. The table below shows how a font is analogous to a package. | ||
|
||
| Property | Package | Font | | ||
| -------- | ------- | ---- | | ||
| Id | MSIX\NotepadPlusPlus_1.0.0.0_neutral__7njy0v32s6xk6 | Machine\Arial\Bold | | ||
| Version | 1.0.0.0 | 7.01 | | ||
| Name | NotepadPlusPlus | Arial Bold | | ||
| PackageFamilyName | NotepadPlusPlus_1.0.0.0_neutral__7njy0v32s6xk6 | Arial | | ||
| InstalledLocation | N/A | %LOCALAPPDATA%/Microsoft/Windows/Fonts/Arial.ttf | | ||
| InstalledScope | | User | | ||
|
||
> The unique identifer for each font will be a combination of the scope, font font family name, and font face name. | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
> The version of the font only exists at the font face level and not at the family level | ||
|
||
## CLI Behavior / Implementation Details | ||
|
||
New Command: `winget fonts` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will there be any new GPO to prevent the installation of fonts, or uninstallation of specific fonts? Thinking about how an enterprise could use a custom standard font for all of their branding / marketing and would want to ensure that users at the company can't uninstall it using WinGet There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, how will this interact with existing Font GPOs, if at all? |
||
--- | ||
Fonts should be completely separate from the existing package management experience. Fonts aren't as complex as installing packages so having new subcommands can help simplify the necessary arguments for proper functionality. To support this, a new command called `font` will be added. The following subcommands will be available: | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- `winget fonts list` | ||
- `winget fonts install` | ||
- `winget fonts uninstall` | ||
- `winget fonts upgrade` | ||
- `winget fonts show` | ||
|
||
`winget fonts list` | ||
--- | ||
The default behavior of `winget fonts list` is to display all installed font families and the number of faces that belong to each font family. | ||
|
||
| Family Name | Face Count | | ||
| -------- | ------- | | ||
| Arial | 6 | | ||
| Bahnschrift | 1 | | ||
| Cascadia Code | 30 | | ||
|
||
```c++ | ||
// How to enumerate the list of installed font family names. | ||
wchar_t localeNameBuffer[LOCALE_NAME_MAX_LENGTH]; | ||
const auto localeName = GetUserDefaultLocaleName(localeNameBuffer, LOCALE_NAME_MAX_LENGTH) ? localeNameBuffer : L"en-US"; | ||
|
||
wil::com_ptr<IDWriteFactory7> factory; | ||
THROW_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), factory.put_unknown())); | ||
Check failure on line 127 in doc/specs/#166 - Font Support.md GitHub Actions / Check Spelling
|
||
|
||
wil::com_ptr<IDWriteFontCollection> collection; | ||
THROW_IF_FAILED(factory->GetSystemFontCollection(collection.addressof(), FALSE)); | ||
|
||
const auto familyCount = collection->GetFontFamilyCount(); | ||
|
||
for (UINT32 familyIndex = 0; familyIndex < familyCount; familyIndex++) | ||
{ | ||
// Get font family from font collection by index. | ||
wil::com_ptr<IDWriteFontFamily> family; | ||
THROW_IF_FAILED(collection->GetFontFamily(familyIndex, family.addressof())); | ||
|
||
// Get font family name. | ||
wil::com_ptr<IDWriteLocalizedStrings> names; | ||
THROW_IF_FAILED(family->GetFamilyNames(names.addressof())); | ||
|
||
UINT32 index; | ||
BOOL exists; | ||
if (FAILED(names->FindLocaleName(localeName, &index, &exists)) || !exists) | ||
{ | ||
index = 0; | ||
} | ||
|
||
UINT32 nameLength; | ||
THROW_IF_FAILED(names->GetStringLength(index, &nameLength)); | ||
nameLength += 1; // Account for the trailing null terminator during allocation. | ||
|
||
wchar_t name[512]; | ||
const auto fontCount = family->GetFontCount(); | ||
THROW_HR_IF(E_OUTOFMEMORY, nameLength > ARRAYSIZE(name)); | ||
THROW_IF_FAILED(names->GetString(0, &name[0], nameLength)); | ||
} | ||
``` | ||
|
||
If a user specifies a specific name such as : | ||
|
||
`winget fonts list --name 'Arial'` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this support a substring match like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or also There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am thinking of creating an index in memory that we can use to better search the installed fonts like the examples you have above. |
||
|
||
Then the tool will display all of the font faces related to that font family name along with the corresponding font file path. | ||
|
||
| Face Name | Face Version | Font Family | Font File Path | | ||
| -------- | ------- | ------- | ------- | | ||
| Regular | 7.01 | Arial | C:\Windows\Fonts\arial.ttf | | ||
| Narrow | 7.01 | Arial | C:\Windows\Fonts\ARIALN.TTF | | ||
| Italic | 7.01 | Arial | C:\Windows\Fonts\ariali.ttf | | ||
| Narrow Italic | 7.01 | Arial | C:\Windows\Fonts\ARIALNI.TTF | | ||
| Narrow Bold | 7.01 | Arial | C:\Windows\Fonts\ARIALNB.TTF | | ||
| Narrow Bold Oblique | 7.01 | Arial | C:\Windows\Fonts\ARIALNB.TTF | | ||
|
||
> Note that some font faces share the same font file path. This will need to be handled properly during uninstall. | ||
|
||
Sample Code: | ||
|
||
```c++ | ||
// Obtaining all font file paths associated with a font face. | ||
wil::com_ptr<IDWriteFontFace> fontFace; | ||
THROW_IF_FAILED(font->CreateFontFace(fontFace.addressof())); | ||
|
||
// https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontface-getfiles | ||
UINT32 fileCount; | ||
THROW_IF_FAILED(fontFace->GetFiles(&fileCount, nullptr)); // Use null initially to retrieve the number of files. | ||
|
||
wil::com_ptr<IDWriteFontFile> fontFiles[8]; | ||
THROW_HR_IF(E_OUTOFMEMORY, fileCount > ARRAYSIZE(fontFiles)); | ||
THROW_IF_FAILED(fontFace->GetFiles(&fileCount, fontFiles[0].addressof())); | ||
|
||
// Iterate through all the files corresponding to that font face name. | ||
for (UINT32 i = 0; i < fileCount; ++i) { | ||
wil::com_ptr<IDWriteFontFileLoader> loader; | ||
THROW_IF_FAILED(fontFiles[i]->GetLoader(loader.addressof())); | ||
|
||
const void* fontFileReferenceKey; | ||
UINT32 fontFileReferenceKeySize; | ||
THROW_IF_FAILED(fontFiles[i]->GetReferenceKey(&fontFileReferenceKey, &fontFileReferenceKeySize)); | ||
|
||
// Retrieve and print the full font file path. | ||
if (const auto localLoader = loader.try_query<IDWriteLocalFontFileLoader>()) { | ||
UINT32 pathLength; | ||
THROW_IF_FAILED(localLoader->GetFilePathLengthFromKey(fontFileReferenceKey, fontFileReferenceKeySize, &pathLength)); | ||
pathLength += 1; // Account for the trailing null terminator during allocation. | ||
|
||
wchar_t path[512]; | ||
THROW_HR_IF(E_OUTOFMEMORY, pathLength > ARRAYSIZE(path)); | ||
THROW_IF_FAILED(localLoader->GetFilePathFromKey(fontFileReferenceKey, fontFileReferenceKeySize, &path[0], pathLength)); | ||
|
||
// Normalize path for better readability | ||
// Use backup semantics so we can access protected files. | ||
const auto h = CreateFileW(path, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); | ||
GetFinalPathNameByHandleW(h, path, ARRAYSIZE(path), 0); | ||
CloseHandle(h); | ||
|
||
wprintf(L"%s\n", &path[0]); | ||
} | ||
} | ||
``` | ||
|
||
`winget fonts install` | ||
--- | ||
|
||
### 1. Initial Validation | ||
Winget will check that `effectiveInstallerType == font` before kicking off the font installation flow. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that this check is necessary. My expectation is that we:
The goal is logically separate fonts for our repository. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated spec to align with this. Made sure to call out that the workflow should not change post source selection. |
||
|
||
The flow will start by validating the font file using the [IDWriteFontFile::Analyze](https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontfile-analyze) method. The `isValid` boolean value will be checked first to determine if we can support installing this font file. If it is not valid, the workflow will terminate and an error message will be displayed to the user. | ||
|
||
```C++ | ||
BOOL isValid; | ||
DWRITE_FONT_FILE_TYPE fileType; | ||
DWRITE_FONT_FACE_TYPE faceType; | ||
UINT32 numOfFaces; | ||
THROW_IF_FAILED(localFontFile->Analyze(&isValid, &fileType, &faceType, &numOfFaces)); | ||
``` | ||
|
||
### 2. Determining expected states | ||
Based on the `--scope` argument, this will be used to determine where the font file will be copied to, and where we will create a new registry key. | ||
We will check whether those files/entries already exist and return an error to the user. The user can bypass these checks by including the `--force` argument, which will overwrite these files/entries. | ||
|
||
| | User Scope | Machine Scope | | ||
| --- | --- | --- | | ||
| Font Name | Roboto | Roboto | | ||
| Font Path | `%LOCALAPPDATA%/Microsoft/Windows/Fonts/Roboto.ttf` | `C:\Windows\Fonts\Roboto.ttf` | | ||
| Registry Path | `HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts` | `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts` | | ||
| Registry Entry Name | `Roboto (TrueType)` | `Roboto (TrueType)` | | ||
| Registry Entry Value | `%LOCALAPPDATA%/Microsoft/Windows/Fonts/Roboto.ttf` | `Roboto.ttf` | | ||
|
||
|
||
> Nearly all of the font types are .ttf and append the `(True Type)` font type to the end of the font name. We will follow the same pattern if the font type is True Type. | ||
|
||
> Machine scope font folder has a known folder id for the fonts directory: `CSIDL_FONTS`, which typically points to `C:\Windows\Fonts`. | ||
|
||
**Registry Entry Name** | ||
|
||
The font's registry name will be acquired from the file's title (right click-> properties -> details -> title). There are a few font titles that have multiple font names separated by a semicolon. The semicolon will be replaced with an `&` character. `TrueType` will be appended if the file is a true type font. | ||
|
||
| Font File | Font Title | Font Registry Name| | ||
| --- | --- | --- | | ||
| timesbd.ttf | Times New Roman Bold | Times New Roman Bold (TrueType) | | ||
| simsun.ttc | SimSun; NSimSun | SimSun & NSimSun (TrueType) | | ||
| YuGothL.ttc | Yu Gothic Light; Yu Gothic UI Light | Yu Gothic Light & Yu Gothic UI Light (TrueType) | | ||
|
||
```c++ | ||
// Retrieving the title of the font file. | ||
#include <ShObjIdl_core.h> | ||
#include <propkey.h> | ||
CoInitialize(nullptr); | ||
IPropertyStore* pps = nullptr; | ||
HRESULT hr = SHGetPropertyStoreFromParsingName(fontFilePath.c_str(), nullptr, GPS_DEFAULT, IID_PPV_ARGS(&pps)); | ||
|
||
if (SUCCEEDED(hr)) { | ||
PROPVARIANT prop; | ||
PropVariantInit(&prop); | ||
hr = pps->GetValue(PKEY_Title, &prop); | ||
if (SUCCEEDED(hr)) { | ||
std::wstring title = prop.pwszVal; | ||
PropVariantClear(&prop); | ||
pps->Release(); | ||
wprintf(L"%s\n", &title[0]); | ||
} | ||
|
||
PropVariantClear(&prop); | ||
pps->Release(); | ||
} | ||
``` | ||
|
||
### 3. Applying desired state | ||
Once all checks have been verified, we will apply the desired state so that the font file will exist in the appropriate location and a new registry entry will be created along with updating the font index. | ||
|
||
`winget fonts uninstall` | ||
--- | ||
|
||
1. Determine which font file(s) matches the font family/face name | ||
|
||
Utilizing the enumeration code from [`winget fonts list`](#winget-fonts-list), we will determine which file(s) corresponds to the specified font family. During enumeration, it is possible to have duplicate entries for the same font family name if the font is installed in both user and system scope. The user will need to provide the `--scope` argument to filter down to exactly one font family. | ||
|
||
`std::vector<std::filesystem::path> GetFontFilePathsByName(familyName, faceName (optional))` | ||
|
||
2. Check the registry values for matching font path | ||
|
||
We will iterate through all font registry keys to create a map of all registered fonts and font files and determine if there is key value that matches each font path. | ||
|
||
There is no guarantee that the key name must match the intended name of the font. The registry key name has no impact on how the font is registered by the OS. Because of this, the only guaranteed solution is to scan through all font registry entries and look for a single match. | ||
|
||
3. Remove the file and the registry entry. | ||
|
||
Once we have determined the matching font file and registry key entry, both of these items will be removed from the system and the font index will be updated. | ||
|
||
### Uninstall Scenarios: | ||
--- | ||
|
||
1. **Uninstalling a font family with a single font face:** | ||
|
||
`winget fonts uninstall --name 'Baskerville Old Face'` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to make things work throughout, we should treat font family as the "package" and faces as "versions". Alternatively, we need a completely new set of COM APIs to expose fonts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thinking was that:
How should we reason about the versioning of these faces? I haven't thought much about COM APIs but that is a good callout. Will address that later once the client implementation is a little more concrete. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your model is how I would put it into the existing index schema (if package == identifier). But with the current code (at least my belief in how it should work) and a font available remotely, the search for the family would return one package result with multiple installed versions. I would argue that this is a better model generally, and unlike executable packages we have a well-defined mechanism to do the correlation even without external data to drive it. Thus, I would put some additional wrapper in place to always join the face "packages" together into one result based on the family name. I feel like the existing composite code can already handle this. |
||
|
||
Winget will uninstall a font family with a single font face without any warnings. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A warning should only be generated when the set of things being removed would be larger than the set of things requested to be removed. Specifying a single face might require removing multiple faces or families because they are all in the same file. This applies to all uninstall command permutations. So generally:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated spec to align with above. |
||
|
||
2. **Uninstalling a font family with multiple font faces:** | ||
|
||
`winget fonts uninstall --name 'Bahnschrift' --remove-multiple-fonts` | ||
|
||
If a font family contains multiple font faces, the user must include the `--remove-multiple-fonts`. Otherwise, a blocking warning will be shown to the user. | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
3. **Uninstalling a specific font face:** | ||
|
||
`winget fonts uninstall --name 'Bahnschrift' --font-face 'Semibold'` | ||
|
||
4. **Uninstalling a font face that shares the same font file as another font face:** | ||
|
||
`winget fonts uninstall --name 'Arial' --font-face 'Bold'` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand how this example and example 1 exist together. It doesn't seem like name has a consistent meaning across these commands. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realized that using a font family that includes the word 'face' was slightly confusing... I've updated the arguments to more accurately reflect the difference between |
||
|
||
If a specific font face that is being removed shares a font file with another font face, an error will be shown to the user and the workflow will be terminated. | ||
|
||
The user must include the `--force` argument to remove both files. This means that the registry entry from the other font face must be removed as well. The client should notify the user, which font faces are removed. | ||
|
||
`winget fonts upgrade` | ||
--- | ||
Identifying the version only applies at the font face level. | ||
|
||
Retrieving the version of the font face: | ||
```c++ | ||
wil::com_ptr<IDWriteLocalizedStrings> versionString; | ||
BOOL versionStringExists; | ||
THROW_IF_FAILED(font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, &versionString, &versionStringExists)); | ||
UINT32 versionStringIndex; | ||
if (FAILED(versionString->FindLocaleName(localeName, &versionStringIndex, &versionStringExists)) || !versionStringExists) { | ||
versionStringIndex = 0; | ||
} | ||
|
||
UINT32 versionStringLength = 0; | ||
THROW_IF_FAILED(versionString->GetStringLength(versionStringIndex, &versionStringLength)); | ||
versionStringLength += 1; // Account for the trailing null terminator during allocation. | ||
|
||
wchar_t result[512]; | ||
THROW_HR_IF(E_OUTOFMEMORY, versionStringLength > ARRAYSIZE(result)); | ||
THROW_IF_FAILED(versionString->GetString(versionStringIndex, &result[0], versionStringLength)); | ||
|
||
wprintf(L"%s\n", &result[0]); | ||
``` | ||
|
||
We will compare this font version with what is the latest available version from the repository. If `all current font face versions < latest available font version`, we will remove the previous font and install the latest. | ||
|
||
## Validation | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Fonts should be submitted in their own directory in the winget-pkgs repository in order to maintain separation between fonts and manifests. Package manifests will continue to live in the `manifests` directory, while font manifests will be added to a new `fonts` directory with a similar directory structure (sorted by starting letter) | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
``` | ||
winget-pkgs | ||
│ README.md | ||
│ file001.txt | ||
│ | ||
└───manifests | ||
│ └───a | ||
│ └───b | ||
│ | ||
└───fonts | ||
│ └───a | ||
| | American Kestrel | ||
| | Autumn Voyage | ||
│ └───b | ||
``` | ||
|
||
- PRSS validation is required to verify that the downloaded fonts file does not contain potential malware. | ||
- DAAS validation is not completely necessary. If we decide to go this route, DAAS will need to be updated to avoid checking for a valid executable and just verify that the font file/entries were correctly placed. | ||
ryfu-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From our talks, do we actually need to specify the file types that are supported? It seemed like we could support whatever font formats Windows supports with no additional work per-type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just for general knowledge, I don't plan to do anything different based on file type. Installation support will be based on the results from IdWriteFontFile::Analyze