Betűtípus-kijelölés
Az IDWriteFontSet4 felület a betűtípuskészletek betűtípusainak kiválasztására szolgáló módszereket teszi elérhetővé. Ezek a metódusok lehetővé teszik a tipográfiai betűtípuscsalád-modellre való áttérést a meglévő alkalmazásokkal, dokumentumokkal és betűtípusokkal való kompatibilitás fenntartása mellett.
A betűtípus-kijelölés (más néven betűegyeztetés vagy betűleképezés) az alkalmazás által átadott bemeneti paramétereknek leginkább megfelelő betűtípusok kiválasztásának folyamata. A bemeneti paramétereket gyakran logikai betűtípuskéntnevezik. A logikai betűtípus tartalmaz egy betűcsaládnevet, valamint más attribútumokat, amelyek egy adott betűtípust jelölnek a családon belül. A betűtípus-kijelölési algoritmusok a logikai betűtípust ("a kívánt betűtípust") egy elérhető fizikai betűtípussal ("a használt betűtípussal") egyezik meg.
A betűtípuscsaládok olyan betűtípusok nevesített csoportja, amelyek közös kialakítással bírnak, de attribútumaik, például a súlyuk eltérőek lehetnek. A betűtípuscsalád-modell határozza meg, hogy milyen attribútumok használhatók a betűtípusok családon belüli megkülönböztetésére. Az új tipográfiai betűtípuscsalád-modell számos előnnyel rendelkezik a Windowsban használt két korábbi betűtípuscsalád-modellel szemben. A betűtípuscsalád-modellek módosítása azonban lehetőséget teremt a félreértésekre és a kompatibilitási problémákra. Az IDWriteFontSet4 felület által közzétett módszerek hibrid megközelítést implementálnak, amely a tipográfiai betűtípuscsalád-modell előnyeit kínálja a kompatibilitási problémák enyhítése mellett.
Ez a témakör a régebbi betűtípuscsalád-modelleket hasonlítja össze a tipográfiai betűcsaládmodellel; ismerteti a betűcsaládmodellek módosításával felmerülő kompatibilitási kihívásokat; és végül elmagyarázza, hogyan lehet leküzdeni ezeket a kihívásokat az [IDWriteFontSet4](/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontset4) metódusok használatával.
RBIZ betűtípuscsalád modell
A GDI-alkalmazás ökoszisztémájában használt de facto betűcsaládmodellt néha "négybetűs modellnek" vagy "RBIZ" modellnek is nevezik. A modell minden betűcsaládja általában legfeljebb négy betűtípust használ. Az "RBIZ" címke az egyes betűtípusfájlok elnevezési konvenciójából származik, például:
Fájlnév | Betűstílus |
---|---|
verdana.ttf | Rendszeres |
verdanab.ttf | Merész |
verdanai.ttf | Dőlt |
verdanaz.ttf | Félkövér dőlt |
A GDI-vel a betűtípus kiválasztásához használt bemeneti paramétereket a LOGFONT struktúra határozza meg, amely tartalmazza a családnevet (lfFaceName
), a súlyt (lfWeight
) és a dőlt (lfItalic
) mezőket. A lfItalic
mező IGAZ vagy HAMIS. A GDI lehetővé teszi, hogy a lfWeight
mező bármilyen érték legyen a FW_THIN (100) tartományon belül FW_BLACK (900), de előzményként a betűtípusokat régóta úgy tervezték, hogy ugyanabban a GDI-betűtípuscsaládban ne legyen kétnál több súly.
A népszerű alkalmazás felhasználói felületei már a kezdetektől tartalmazták a dőlt gombot (a dőlt be- és kikapcsolásához) és egy félkövér gombot (a normál és félkövér súlyok közötti váltáshoz). A két gomb használata a családon belüli betűtípusok kiválasztásához feltételezi az RBIZ-modellt. Ezért annak ellenére, hogy maga a GDI több mint két súlyt támogat, az alkalmazáskompatibilitás arra késztette a betűtípus-fejlesztőket, hogy az RBIZ-modellnek megfelelő módon állítsa be a GDI-családnevet (OpenType névazonosító 1).
Tegyük fel például, hogy nehezebb "fekete" súlyt szeretne hozzáadni az Arial betűtípuscsaládhoz. Logikailag ez a betűtípus az Arial-család része, ezért előfordulhat, hogy az lfFaceName
"Arial" értékre, lfWeight
pedig FW_BLACK. Az alkalmazásfelhasználók azonban nem választhatnak három súly közül kétállapotú félkövér gombbal. A megoldás az volt, hogy az új betűtípust egy másik családnévvel adja meg, így a felhasználó kiválaszthatja azt a betűcsaládok listájából az "Arial Black" (Arial Black) elemet választva. Hasonlóképpen, nem lehet választani a különböző szélességek között ugyanabban a betűtípuscsaládban csak félkövér és dőlt gombokkal, így az Arial keskeny verziói eltérő családnevekkel rendelkeznek az RBIZ-modellben. Így az RBIZ modellben az "Arial", az "Arial Black" és az "Arial Narrow" betűtípusok is szerepelnek, bár tipográfiailag ezek mind egy családba tartoznak.
Ezekből a példákból megtudhatja, hogy a betűtípuscsalád-modellek korlátai hogyan befolyásolhatják a betűtípusok családokba való csoportosítását. Mivel a betűtípuscsaládok név alapján vannak azonosítva, ez azt jelenti, hogy ugyanaz a betűtípus különböző családneveket tartalmazhat attól függően, hogy melyik betűcsaládmodellt használja.
A DirectWrite nem támogatja közvetlenül az RBIZ betűcsaládmodellt, de az RBIZ-modellre és az azokból való konvertálási módszereket biztosít, például IDWriteGdiInterop::CreateFontFromLOGFONT és IDWriteGdiInterop::ConvertFontToLOGFONT. Egy betűtípus RBIZ-családnevét is lekérheti a IDWriteFont::GetInformationalStrings metódus meghívásával, valamint a DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMESmegadásával.
Súlyzós stílusú betűtípuscsalád-modell
A súlyzós stílusú betűtípuscsalád-modell a DirectWrite által a tipográfiai betűcsaládmodell bevezetése előtt használt eredeti betűtípuscsalád-modell. Súlyszélesség-meredekség (WWS) néven is ismert. A WWS-modellben az ugyanazon családon belüli betűtípusok három tulajdonsággal különbözhetnek: súly (DWRITE_FONT_WEIGHT), stretch (DWRITE_FONT_STRETCH) és stílus (DWRITE_FONT_STYLE).
A WWS-modell két módon rugalmasabb, mint az RBIZ modell. Először is, az ugyanabban a családban lévő betűtípusok nyújtás (vagy szélesség), valamint súly és stílus (normál, dőlt vagy ferde) alapján különböztethetők meg. Másodszor, ugyanabban a családban több mint két súly lehet. Ez a rugalmasság elegendő ahhoz, hogy az Arial összes változata ugyanabban a WWS-családban szerepeljen. Az alábbi táblázat összehasonlítja az RBIZ és a WWS betűtípus tulajdonságait az Arial-betűtípusok kiválasztásához:
Teljes név | RBIZ családnév | lfWeight | lfItalic | WWS FamilyName | Súly | Nyúlik | Stílus |
---|---|---|---|---|---|---|---|
Arial | Arial | 400 | 0 | Arial | 400 | 5 | 0 |
Félkövér Arial | Arial | 700 | 0 | Arial | 700 | 5 | 0 |
Fekete Arial | Fekete Arial | 900 | 0 | Arial | 900 | 5 | 0 |
Arial Narrow | Arial Narrow | 400 | 0 | Arial | 400 | 3 | 0 |
Arial Keskeny félkövér | Arial Narrow | 700 | 0 | Arial | 700 | 3 | 0 |
Mint látható, az "Arial Narrow" ugyanazokkal a lfWeight
és lfItalic
értékekkel rendelkezik, mint az "Arial", ezért a kétértelműség elkerülése érdekében más RBIZ-családnévvel rendelkezik. Az "Arial Black" más RBIZ családnévvel rendelkezik, hogy ne legyen kétnál több súly az "Arial" családban. Ezzel szemben ezek a betűtípusok ugyanabban a súlyzós stílusú családban találhatók.
A súlyzós nyújtásos modell azonban nem nyílt végű. Ha két betűtípus azonos súlyú, stretch és stílusú, de más módon (például optikai méretben) különbözik, akkor nem vehetők fel ugyanabba a WWS betűtípuscsaládba. Ezzel eljutunk a tipográfiai betűtípuscsalád modelljéhez.
Tipográfiai betűcsalád modellje
Az elődöktől eltérően a tipográfiai betűtípuscsalád-modell nyílt végű. Tetszőleges számú változatot támogat egy betűtípuscsaládon belül.
Ha a betűkijelölési paramétereket a tervezési térben koordinátákként tekinti, a súlyzós nyújtás stílusú modell tengelyként definiál egy háromdimenziós koordináta-rendszert, amelynek tengelyei a súly, a nyújtás és a stílus. A WWS-család minden betűtípusának egyedi helynek kell lennie, amelyet a koordinátái határoznak meg a három tengely mentén. Betűtípus kiválasztásához meg kell adnia a WWS-család nevét és súlyát, nyúlási és stílusparamétereit.
Ezzel szemben a tipográfiai betűtípuscsalád modellje N-dimenziós tervezési területtel rendelkezik. A betűtípustervezők tetszőleges számú tervezési tengelyt definiálhatnak, amelyeket egy négy karakterből álló tengelycímkeazonosít. Az N dimenziós tervezési térben egy adott betűtípus helyét tengelyértékektömbje határozza meg, ahol minden tengelyérték egy tengelycímkéből és egy lebegőpontos értékből áll. Betűtípus kiválasztásához meg kell adnia egy tipográfiai családnevet és egy tengelyértékek tömbét (DWRITE_FONT_AXIS_VALUE struktúrákat).
Bár a betűtengelyek száma nyitott végű, van néhány szabványos jelentéssel rendelkező regisztrált tengely, és a súly- és a nyújtás- és stílusértékek a regisztrált tengelyértékekhez rendelhetők. DWRITE_FONT_WEIGHT egy "wght" (DWRITE_FONT_AXIS_TAG_WEIGHT) tengelyértékhez rendelhető. DWRITE_FONT_STRETCH "wdth" (DWRITE_FONT_AXIS_TAG_WIDTH) tengelyértékhez rendelhető. DWRITE_FONT_STYLE "dőlt" és "slnt" (DWRITE_FONT_AXIS_TAG_ITALIC és DWRITE_FONT_AXIS_TAG_SLANT) tengelyértékek kombinációjára képezhetők le.
Egy másik regisztrált tengely az "opsz" (DWRITE_FONT_AXIS_TAG_OPTICAL_SIZE). Az optikai betűtípuscsaládok, például a Sitka olyan betűtípusokat tartalmaznak, amelyek az "opsz" tengely mentén különböznek, ami azt jelenti, hogy különböző pontméretekben használhatók. A WWS betűtípuscsalád modellje nem rendelkezik optikai mérettengelyrel, ezért a Sitka betűtípuscsaládot több WWS betűtípuscsaládra kell felosztani: "Sitka Small", "Sitka Text", "Sitka Subheading" stb. Minden WWS betűtípuscsalád egy másik optikai méretnek felel meg, és a felhasználónak kell megadnia a megfelelő WWS-családnevet egy adott betűmérethez. A tipográfiai betűcsalád modellel a felhasználó egyszerűen kiválaszthatja a "Sitka" értéket, és az alkalmazás automatikusan beállíthatja az "opsz" tengely értékét a betűméret alapján.
Tipográfiai betűtípusok kiválasztása és változó betűtípusok
A variációs tengelyek fogalma gyakran változó betűtípusokhoz van társítva, de a statikus betűtípusokra is vonatkozik. Az OpenType STAT (stílusattribútumok) tábla deklarálja a betűtípusok tervezési tengelyeit és a tengelyek értékeit. Ez a táblázat változó betűtípusokhoz szükséges, de statikus betűtípusokra is vonatkozik.
A DirectWrite API minden betűtípushoz elérhetővé teszi a "wght", a "wdth", a "dőlt" és a "slnt" tengely értékeit, még akkor is, ha nincsenek jelen a STAT táblában, vagy ha nincs STAT tábla. Ezek az értékek lehetőség szerint a STAT táblából származnak. Ellenkező esetben a betűvastagságból, a betűméretből és a betűstílusból származnak.
A betűtengelyek lehetnek változók vagy nem változók. A statikus betűtípusoknak csak nem változó tengelyei vannak, míg a változó betűtípusok mindkettővel rendelkezhetnek. Változó betűtípus használatához létre kell hoznia egy változó betűtípust példányt, amelyben az összes változótengely adott értékekhez lett kötve. Az IDWriteFontFace felület statikus betűtípust vagy egy változó betűtípus adott példányát jelöl. Létrehozhat egy tetszőleges példányt, egy megadott tengelyértékekkel rendelkező változó betűtípusból. Emellett a változó betűtípusok deklarálhatnak elnevezett példányokat a STAT táblában előre definiált tengelyérték-kombinációkkal. Az elnevezett példányok lehetővé teszik, hogy a változó betűtípusok a statikus betűtípusok gyűjteményéhez hasonlóan viselkedjenek. Egy IDWriteFontFamily vagy IDWriteFontSetelemeinek számbavételekor minden statikus betűtípushoz és minden elnevezett változó betűtípuspéldányhoz egy elem tartozik.
A tipográfiai betűegyeztetési algoritmus először a családnév alapján választja ki a lehetséges egyező jelölteket. Ha az egyezésjelöltek változó betűtípusokat tartalmaznak, az azonos változó betűtípushoz tartozó összes egyezésjelölt egyetlen egyező jelöltre van összecsukva, amelyben az egyes változótengelyek egy adott értéket rendelnek a lehető legközelebb az adott tengely kért értékéhez. Ha egy változótengelyhez nincs kért érték, a rendszer az adott tengely alapértelmezett értékét rendeli hozzá. A megfelelő jelöltek sorrendjét ezután a rendszer a tengelyértékek és a kért tengelyértékek összehasonlításával határozza meg.
Vegyük például a Windows Sitka tipográfiai családját. A Sitka egy optikai betűcsalád, ami azt jelenti, hogy "opsz" tengelye van. A Windows 11-ben a Sitka két változó betűtípusként van implementálva a következő tengelyértékekkel. Vegye figyelembe, hogy a opsz
és wght
tengelyek változók, míg a többi tengely nem változó.
Fájlnév | "opsz" | "wght" | "wdth" | "dőlt" | "slnt" |
---|---|---|---|---|---|
SitkaVF.ttf | 6-27.5 | 400-700 | 100 | 0 | 0 |
SitkaVF-Italic.ttf | 6-27.5 | 400-700 | 100 | 1 | -12 |
Tegyük fel, hogy a kért tengelyértékek opsz:12 wght:475 wdth:100 ital:0 slnt:0
. Minden változó betűtípushoz létrehozunk egy hivatkozást egy változó betűtípusára, példányra, amelyben az egyes változótengelyek adott értéket kapnak. A opsz
és wght
tengelyek beállítása 12
, illetve 475
. Ez a következő egyező betűtípusokat eredményezi, és a nem dőlt betűtípus az első, mert jobb egyezés a ital
és slnt
tengelyekhez:
SitkaVF.ttf opsz:12 wght:475 wdth:100 ital:0 slnt0
SitkaVF-Italic.ttf opsz:12 wght:475 wdth:100 ital:1 slnt:-12
A fenti példában az egyező betűtípusok tetszőleges változó betűpéldányok. A Sitka nevesített példánya 475-ös súlyú. Ezzel szemben a súlyzós nyújtás stílusú egyező algoritmus csak nevesített példányokat ad vissza.
Betűegyeztetés sorrendje
Különböző túlterhelt GetMatchingFonts metódusok léteznek a súlyzós stílusú betűtípuscsaládmodellhez (IDWriteFontFamily::GetMatchingFonts) és a tipográfiai betűcsaládmodellhez (IDWriteFontCollection2::GetMatchingFonts). Mindkét esetben a kimenet az egyező betűtípusok listája csökkenő prioritási sorrendben, attól függően, hogy az egyes jelölt betűtípusok mennyire összhangban vannak a bemeneti tulajdonságokkal. Ez a szakasz a prioritás meghatározásának módját ismerteti.
A weight-stretch stílusú modellben a bemeneti paraméterek a betűvastagság (DWRITE_FONT_WEIGHT), a betűméret (DWRITE_FONT_STRETCH) és a betűstílus (DWRITE_FONT_STYLE). A legjobb egyezés megtalálására szolgáló algoritmust Mihail Leonov és David Brown egy 2006-os tanulmányában, a WPF betűtípus-kiválasztási modellben dokumentálta. Lásd a "Arc egyeztetése a jelölt arclistájából" című szakaszt. Ez a cikk a Windows Presentation Foundationről (WPF) szólt, de a DirectWrite később ugyanezt a megközelítést használta.
Az algoritmus a betűattribútum-vektorfogalmát használja, amely a súly, a nyújtás és a stílus adott kombinációjához az alábbiak szerint lesz kiszámítva:
FontAttributeVector.X = (stretch - 5) * 1100;
FontAttributeVector.Y = style * 700;
FontAttributeVector.Z = (weight - 400) * 5;
Vegye figyelembe, hogy minden vektorkoordináta normalizálva van a megfelelő attribútum "normál" értékének kivonásával, és egy állandóval szorozva. A szorzók kompenzálják azt a tényt, hogy a súly, a nyújtás és a stílus bemeneti értékeinek tartományai nagyon eltérőek. Ellenkező esetben a súly (100..999) uralná a stílust (0..2).
Az egyes egyezésjelöltek esetében a rendszer egy vektortávolságot és egy pont szorzatot számít ki a megfelelő jelölt betűtípusattribútum-vektora és a bemeneti betűtípusattribútum-vektor között. Két egyezéses jelölt összehasonlítása esetén a jelölt a kisebb vektortávolsággal a jobb egyezés. Ha a távolságok azonosak, a kisebb ponttal rendelkező jelölt jobb egyezés. Ha a pont szorzata is megegyezik, akkor az X, Y és Z tengelyek mentén mért távolságok ebben a sorrendben vannak összehasonlítva.
A távolságok összehasonlítása elég intuitív, de a pont termék másodlagos mértékként való használata némi magyarázatot igényelhet. Tegyük fel, hogy a bemeneti súly félbold (600), és két jelölt súly fekete (900) és féllámpás (300). Az egyes jelölt súlyok távolsága a bemeneti súlytól azonos, de a fekete súly azonos irányban van a forrástól (azaz 400 vagy normál), így kisebb pontú terméke lesz.
A tipográfiai megfeleltetési algoritmus a súlyzós stílus általánosítása. A rendszer minden tengelyértéket koordinátaként kezel egy N-dimenziós betűttribútum-vektorban. Az egyes egyezésjelöltek esetében a rendszer egy vektortávolságot és egy pont szorzatot számít ki a megfelelő jelölt betűtípusattribútum-vektora és a bemeneti betűtípusattribútum-vektor között. A kisebb vektortávolsággal rendelkező jelölt a jobb egyezés. Ha a távolságok azonosak, a kisebb ponttal rendelkező jelölt jobb egyezés. Ha a pont termék is ugyanaz, a jelenlét egy adott súly-stretch stílusú család lehet használni, mint egy tie-breaker.
A vektor távolságának és pontjának kiszámításához a jelölt betűtípusattribútum-vektorának és a bemeneti betűtípusattribútum-vektornak azonos tengelyekkel kell rendelkeznie. Ezért a hiányzó tengelyértékek bármelyik vektorban ki lesznek töltve az adott tengely standard értékének helyettesítésével. A vektorkoordinátákat a megfelelő tengely standard (vagy "normál") értékének kivonásával normalizáljuk, és az eredményt megszorozzuk egy tengelyspecifikus szorzóval. Az egyes tengelyek szorzói és standard értékei a következők:
Tengely | Szorzó | Standard érték |
---|---|---|
"wght" | 5 | 400 |
"wdth" | 55 | 100 |
"dőlt" | 1400 | 0 |
"slnt" | 35 | 0 |
"opsz" | 1 | 12 |
más | 1 | 0 |
A szorzók összhangban vannak a súlyzós stílusú algoritmus által használtakkal, de szükség szerint skálázhatók. A normál szélesség például 100, ami egyenértékű az 5. nyúlással. Ez 55 és 1100 szorzót eredményez. Az örökölt stílusattribútum (0..2) összefonódik a dőlt és ferdeség között, amely a tipográfiai modellben "dőlt" tengelyre (0..1) és "slnt" tengelyre (-90..90) oszlik. A két tengelyhez választott szorzók egyenértékű eredményt adnak az örökölt algoritmusnak, ha a ferde betűtípusok alapértelmezett 20 fokos dőlésszögét feltételezzük.
Tipográfiai betűtípus kiválasztása és optikai méret
A tipográfiai betűcsaládmodellt használó alkalmazások az optikai méretezést úgy valósíthatják meg, hogy egy opsz
tengelyértéket ad meg betűkijelölési paraméterként. Egy szövegszerkesztő alkalmazás például megadhat egy opsz
tengelyértéket, amely megegyezik a pontok betűméretével. Ebben az esetben a felhasználó kiválaszthatja a "Sitka" betűcsaládot, és az alkalmazás automatikusan kiválaszt egy Sitka-példányt a megfelelő opsz
tengelyértékkel. A WWS-modellben minden optikai méret más családnévként jelenik meg, és a felhasználónak kell kiválasztania a megfelelőt.
Elméletileg az automatikus optikai méretezést a súlyzós stílusú modellben úgy lehet megvalósítani, hogy a opsz
tengely értékét külön lépésként betűkészlet kiválasztása után. Ez azonban csak akkor működik, ha az első egyező betűtípus egy változó opsz
tengelyrel rendelkező változó betűtípus. A opsz
betűtípus-kijelölési paraméterként való megadása egyformán jól működik a statikus betűtípusok esetében. A Sitka betűtípuscsalád például változó betűtípusként van implementálva a Windows 11-ben, de statikus betűtípusok gyűjteményeként a Windows 10-ben. A statikus betűtípusok eltérő, nem átfedésben lévő opsz
tengelytartományokkal rendelkeznek (ezek betűkijelölési célokra tartományként vannak deklarálva, de nem változó tengelyek). A opsz
betűtípus-kijelölési paraméterként való megadása lehetővé teszi az optikai méret megfelelő statikus betűtípusának kiválasztását.
Tipográfiai betűtípus-kiválasztási előnyök és kompatibilitási problémák
A tipográfiai betűtípus-kiválasztási modell számos előnnyel rendelkezik a korábbi modellekkel szemben, de tiszta formájában kompatibilitási problémákat tapasztal. Ez a szakasz az előnyöket és a kompatibilitási problémákat ismerteti. A következő szakasz egy hibrid betűtípus-kijelölési modellt mutat be, amely megőrzi az előnyöket a kompatibilitási problémák enyhítése során.
A tipográfiai betűcsaládmodell előnyei a következők:
A betűtípusok a tervező által tervezett családba csoportosíthatók ahelyett, hogy a betűtípuscsalád-modell korlátozásai miatt alcsaládokra osztanák őket.
Az alkalmazások automatikusan kiválaszthatják a megfelelő
opsz
tengelyértéket a betűméret alapján, ahelyett, hogy különböző optikai méreteket adnak a felhasználónak különböző betűcsaládokként.A változó betűtípusok tetszőleges példányai választhatók. Ha például egy változó betűtípus támogatja a 100–900 közötti folyamatos tartományban lévő súlyokat, a tipográfiai modell kiválaszthatja súlyt ebben a tartományban. A régebbi betűcsaládmodellek csak a betűkészlet által definiált elnevezett példányok közül választhatják ki a legközelebbi súlyt.
A tipográfiai betűtípus-kijelölési modell kompatibilitási problémái a következők:
Egyes régebbi betűtípusok nem jelölhetők ki egyértelműen csak a tipográfiai családnév és tengelyértékek használatával.
A meglévő dokumentumok WWS-családnév vagy RBIZ-családnév szerinti betűtípusokra hivatkozhatnak. A felhasználók WWS- és RBIZ-családneveket is használhatnak. Egy dokumentum például "Sitka Alcím" (WWS-családnév) értéket adhat meg a "Sitka" (tipográfiai családnév) helyett.
Előfordulhat, hogy egy kódtár vagy keretrendszer a tipográfiai betűcsalád modelljét alkalmazza az automatikus optikai méretezés előnyeinek kihasználásához, de nem biztosít API-t tetszőleges tengelyértékek megadásához. Még ha új API is rendelkezésre áll, előfordulhat, hogy a keretrendszernek olyan meglévő alkalmazásokkal kell dolgoznia, amelyek csak súly-, nyújtás- és stílusparamétereket határoznak meg.
A régebbi betűtípusokkal való kompatibilitási probléma azért merült fel, mert a tipográfiai családnév fogalma megelőzi a betűtengely értékeinek fogalmát, amelyeket az OpenType 1.8 változó betűtípusaival együtt vezettünk be. Az OpenType 1.8 előtt a tipográfiai családnév csupán kifejezte a tervező szándékát arra vonatkozóan, hogy a betűtípusok egy készlete kapcsolódik egymáshoz, de nem garantálja, hogy ezek a betűtípusok programozott módon megkülönböztethetők a tulajdonságaik alapján. Tegyük fel, hogy az alábbi betűtípusok mindegyike "Örökölt" tipográfiai családnévvel rendelkezik:
Teljes név | WWS-család | Súly | Nyúlik | Stílus | Typo család | wght | wdth | dőlt | slnt |
---|---|---|---|---|---|---|---|---|---|
Örökség | Örökség | 400 | 5 | 0 | Örökség | 400 | 100 | 0 | 0 |
Régi félkövér | Örökség | 700 | 5 | 0 | Örökség | 700 | 100 | 0 | 0 |
Régi fekete | Örökség | 900 | 5 | 0 | Örökség | 900 | 100 | 0 | 0 |
Örökölt helyreállítható | Örökölt helyreállítható | 400 | 5 | 0 | Örökség | 400 | 100 | 0 | 0 |
Régi, helyreállítható félkövér | Örökölt helyreállítható | 700 | 5 | 0 | Örökség | 700 | 100 | 0 | 0 |
Örökölt soft black | Örökölt helyreállítható | 900 | 5 | 0 | Örökség | 900 | 100 | 0 | 0 |
A "Régi" tipográfiai család három súlyú, és minden súly normál és "Soft" változatokkal rendelkezik. Ha ezek új betűtípusok lennének, akkor implementálhatók SOFT tervezési tengely deklarálásaként. Ezek a betűtípusok azonban előszeret használják az OpenType 1.8-at, így egyetlen tervezési tengelyük a súlyból, a nyújtásból és a stílusból származik. Ez a betűtípuscsalád minden súlyhoz két azonos tengelyértékkel rendelkező betűtípust tartalmaz, így nem lehet egyértelműen kijelölni egy betűtípust ebben a családban, csak tengelyértékekkel.
Hibrid betűkészlet-kijelölési algoritmus
A következő szakaszban ismertetett betűtípus-kijelölési API-k hibrid betűkijelölési algoritmust használnak, amely megőrzi a tipográfiai betűtípus-kijelölés előnyeit, miközben enyhíti a kompatibilitási problémákat.
A hibrid betűtípus-kijelölés hidat biztosít a régebbi betűtípuscsalád-modellekből azáltal, hogy lehetővé teszi a betűvastagság, a betűméret és a betűstílus értékeinek megfeleltetését a megfelelő betűtengely-értékekhez. Ez segít a dokumentum- és alkalmazáskompatibilitási problémák megoldásában.
Emellett a hibrid betűkészlet-kiválasztási algoritmus lehetővé teszi, hogy a megadott családnév tipográfiai családnév, súly-stretch stílusú családnév, GDI/RBIZ családnév vagy teljes betűkészletnév legyen. Az egyeztetés az alábbi módok egyikével, csökkenő prioritási sorrendben történik:
A név megfelel egy tipográfiai családnak (például Sitka). Az egyeztetés a tipográfiai családon belül történik, és a rendszer az összes kért tengelyértéket használja. Ha a név egy WWS-alcsaládnak is megfelel (vagyis egy kisebb, mint a tipográfiai család), akkor a WWS-alcsalád tagsága döntetlen megszakítóként lesz használva.
A név megegyezik egy WWS-családdal (például Sitka Text). Az egyeztetés a WWS-családon belül történik, és a rendszer figyelmen kívül hagyja a kért tengelyértékeket a "wght", a "wdth", a "dőlt" és a "slnt" kivételével.
A név megegyezik egy GDI-családdal (például Bahnschrift Condensed). Az egyeztetés az RBIZ családon belül történik, és a rendszer figyelmen kívül hagyja a kért tengelyértékeket a "wght", a "dőlt" és a "slnt" kivételével.
A név megegyezik egy teljes névvel (például Bahnschrift Bold Condensed). A teljes névnek megfelelő betűtípus lesz visszaadva. A kért tengelyértékek figyelmen kívül lesznek hagyva. A teljes betűnévvel való egyeztetés engedélyezett, mert a GDI támogatja.
Az előző szakasz egy "Örökölt" nevű nem egyértelmű tipográfiai családot ismertet. A hibrid algoritmus lehetővé teszi a kétértelműség elkerülését az "Örökölt" vagy a "Legacy Soft" családi névként való megadásával. Ha a "Legacy Soft" paraméter meg van adva, akkor nincs kétértelműség, mert az egyeztetés csak a WWS-családon belül történik. Ha a "Legacy" specfiied, akkor a tipográfiai család minden betűtípusa egyező jelöltnek minősül, de a kétértelműséget elkerüli, ha a "Legacy" WWS-család tagságát döntetlen megszakítóként használja.
Tegyük fel, hogy egy dokumentum családnevet és súlyt, nyújtást és stílusparamétereket határoz meg, tengelyértékek nélkül. Az alkalmazás először tengelyértékekké alakíthatja a súlyt, a nyújtást, a stílust és a betűméretet IDWriteFontSet4::ConvertWeightStretchStyleToFontAxisValuesmeghívásával. Az alkalmazás ezután a családnév és a tengely értékeit is átadhatja IDWriteFontSet4::GetMatchingFonts. GetMatchingFonts prioritási sorrendben adja vissza az egyező betűtípusok listáját, és az eredmény megfelelő, hogy a megadott családnév tipográfiai családnév, súlyzós stílusú családnév, RBIZ családnév vagy teljes név. Ha a megadott család "opsz" tengelyt használ, akkor a betűméret alapján automatikusan kiválasztja a megfelelő optikai méretet.
Tegyük fel, hogy egy dokumentum súlyt, nyújtást és stílust határoz meg, és tengelyértékeket is meghatároz. Ebben az esetben az explicit tengelyértékek is átadhatók IDWriteFontSet4::ConvertWeightStretchStyleToFontAxisValues, és a metódus által visszaadott származtatott tengelyértékek csak olyan betűtengelyeket tartalmaznak, amelyek nincsenek explicit módon megadva. Így a dokumentum (vagy alkalmazás) által explicit módon megadott tengelyértékek elsőbbséget élveznek a súlyból, a nyújtásból, a stílusból és a betűméretből származtatott tengelyértékekkel szemben.
Hibrid betűtípus-kiválasztási API-k
A hibrid betűtípus-kijelölési modellt az alábbi IDWriteFontSet4 metódusok implementálják:
Az IDWriteFontSet4::ConvertWeightStretchStyleToFontAxisValues metódus a betűméretet, a súlyt, a nyújtást és a stílusparamétereket a megfelelő tengelyértékekké alakítja. Az ügyfél által átadott explicit tengelyértékek ki vannak zárva a származtatott tengely értékeiből.
Az IDWriteFontSet4::GetMatchingFonts metódus a családnév és a tengelyértékek tömbje alapján rangsorolja az egyező betűtípusok listáját. A fentiekben leírtak szerint a családnév paraméter lehet tipográfiai családnév, WWS-családnév, RBIZ-családnév vagy teljes név. (A teljes név azonosít egy adott betűstílust, például "Arial Félkövér dőlt". GetMatchingFonts támogatja a teljes névvel való egyeztetést a GDI-vel való nagyobb mértékű egyeztetéshez, ami szintén lehetővé teszi.)
A következő DirectWrite API-k a hibrid betűkészlet-kiválasztási algoritmust is használják:
IDWriteTextLayout, ha a tipográfiai betűcsalád-modell engedélyezve van az IDWriteTextLayout4::SetFontAxisValues vagy IDWriteTextLayout4::SetAutomaticFontAxes
Példakódok a használt betűtípus-kijelölési API-kra
Ez a szakasz egy teljes konzolalkalmazást mutat be, amely bemutatja az IDWriteFontSet4::GetMatchingFonts és IDWriteFontSet4::ConvertWeightStretchStyleToFontAxisValues metódusokat. Először is foglaljunk bele néhány fejlécet:
#include <dwrite_core.h>
#include <wil/com.h>
#include <iostream>
#include <string>
#include <vector>
Az IDWriteFontSet4::GetMatchingFonts metódus a megadott családnévnek és tengelyértékeknek megfelelő, prioritási sorrendben lévő betűtípusok listáját adja vissza. Az alábbi MatchAxisValues függvény az IDWriteFontSet4::GetMatchingFonts és a visszaadott betűtípuskészlet megfelelő betűtípusainak listáját adja ki.
// Forward declarations of overloaded output operators used by MatchAxisValues.
std::wostream& operator<<(std::wostream& out, DWRITE_FONT_AXIS_VALUE const& axisValue);
std::wostream& operator<<(std::wostream& out, IDWriteFontFile* fileReference);
std::wostream& operator<<(std::wostream& out, IDWriteFontFaceReference1* faceReference);
//
// MatchAxisValues calls IDWriteFontSet4::GetMatchingFonts with the
// specified parameters and outputs the matching fonts.
//
void MatchAxisValues(
IDWriteFontSet4* fontSet,
_In_z_ WCHAR const* familyName,
std::vector<DWRITE_FONT_AXIS_VALUE> const& axisValues,
DWRITE_FONT_SIMULATIONS allowedSimulations
)
{
// Write the input parameters.
std::wcout << L"GetMatchingFonts(\"" << familyName << L"\", {";
for (DWRITE_FONT_AXIS_VALUE const& axisValue : axisValues)
{
std::wcout << L' ' << axisValue;
}
std::wcout << L" }, " << allowedSimulations << L"):\n";
// Get the matching fonts for the specified family name and axis values.
wil::com_ptr<IDWriteFontSet4> matchingFonts;
THROW_IF_FAILED(fontSet->GetMatchingFonts(
familyName,
axisValues.data(),
static_cast<UINT32>(axisValues.size()),
allowedSimulations,
&matchingFonts
));
// Output the matching font face references.
UINT32 const fontCount = matchingFonts->GetFontCount();
for (UINT32 fontIndex = 0; fontIndex < fontCount; fontIndex++)
{
wil::com_ptr<IDWriteFontFaceReference1> faceReference;
THROW_IF_FAILED(matchingFonts->GetFontFaceReference(fontIndex, &faceReference));
std::wcout << L" " << faceReference.get() << L'\n';
}
std::wcout << std::endl;
}
Az alkalmazások tengelyértékek helyett (vagy mellett) súly-, stretch- és stílusparaméterekkel is rendelkezhetnek. Előfordulhat például, hogy az alkalmazásnak olyan dokumentumokkal kell dolgoznia, amelyek RBIZ vagy súlyzós stílusparaméterek használatával hivatkoznak a betűtípusokra. Még ha az alkalmazás támogatja is az tetszőleges tengelyértékek megadását, előfordulhat, hogy a régebbi paramétereket is támogatnia kell. Ehhez az alkalmazás meghívhatja IDWriteFontSet4::ConvertWeightStretchStyleToFontAxisValues, mielőtt meghívja IDWriteFontSet4::GetMatchingFonts.
Az alábbi MatchFont függvény a tengelyértékek mellett a súly, a nyújtás, a stílus és a betűméret paramétereit is figyelembe veszi. Ezeket a paramétereket az IDWriteFontSet4::ConvertWeightStretchStyleToFontAxisValues metódusnak továbbítja a számítási származtatott tengely értékeihez, amelyek hozzá vannak fűzve a bemeneti tengely értékeihez. A kombinált tengely értékeit a fenti MatchAxisValues függvénynek adja át.
struct FontStyleParams
{
FontStyleParams() {}
FontStyleParams(DWRITE_FONT_WEIGHT fontWeight) : fontWeight{ fontWeight } {}
FontStyleParams(float fontSize) : fontSize{ fontSize } {}
DWRITE_FONT_WEIGHT fontWeight = DWRITE_FONT_WEIGHT_NORMAL;
DWRITE_FONT_STRETCH fontStretch = DWRITE_FONT_STRETCH_NORMAL;
DWRITE_FONT_STYLE fontStyle = DWRITE_FONT_STYLE_NORMAL;
float fontSize = 0.0f;
};
//
// MatchFont calls IDWriteFontSet4::ConvertWeightStretchStyleToFontAxisValues to convert
// the input parameters to axis values and then calls MatchAxisValues.
//
void MatchFont(
IDWriteFactory7* factory,
_In_z_ WCHAR const* familyName,
FontStyleParams styleParams = {},
std::vector<DWRITE_FONT_AXIS_VALUE> axisValues = {},
DWRITE_FONT_SIMULATIONS allowedSimulations = DWRITE_FONT_SIMULATIONS_BOLD | DWRITE_FONT_SIMULATIONS_OBLIQUE
)
{
wil::com_ptr<IDWriteFontSet2> fontSet2;
THROW_IF_FAILED(factory->GetSystemFontSet(/*includeDownloadableFonts*/ false, &fontSet2));
wil::com_ptr<IDWriteFontSet4> fontSet;
THROW_IF_FAILED(fontSet2->QueryInterface(&fontSet));
// Ensure the total number of axis values can't overflow a UINT32.
size_t const inputAxisCount = axisValues.size();
if (inputAxisCount > UINT32_MAX - DWRITE_STANDARD_FONT_AXIS_COUNT)
{
THROW_HR(E_INVALIDARG);
}
// Reserve space at the end of axisValues vector for the derived axis values.
// The maximum number of derived axis values is DWRITE_STANDARD_FONT_AXIS_COUNT.
axisValues.resize(inputAxisCount + DWRITE_STANDARD_FONT_AXIS_COUNT);
// Convert the weight, stretch, style, and font size to derived axis values.
UINT32 derivedAxisCount = fontSet->ConvertWeightStretchStyleToFontAxisValues(
/*inputAxisValues*/ axisValues.data(),
static_cast<UINT32>(inputAxisCount),
styleParams.fontWeight,
styleParams.fontStretch,
styleParams.fontStyle,
styleParams.fontSize,
/*out*/ axisValues.data() + inputAxisCount
);
// Resize the vector based on the actual number of derived axis values returned.
axisValues.resize(inputAxisCount + derivedAxisCount);
// Pass the combined axis values (explicit and derived) to MatchAxisValues.
MatchAxisValues(fontSet.get(), familyName, axisValues, allowedSimulations);
}
Az alábbi függvény a fenti MatchFont függvény meghívásának eredményeit mutatja be néhány példabemenettel:
void TestFontSelection(IDWriteFactory7* factory)
{
// Request "Cambria" with bold weight, with and without allowing simulations.
// - Matches a typographic/WWS family.
// - Result includes all fonts in the family ranked by priority.
// - Useful because Cambria Bold might have fewer glyphs than Cambria Regular.
// - Simulations may be applied if allowed.
MatchFont(factory, L"Cambria", DWRITE_FONT_WEIGHT_BOLD);
MatchFont(factory, L"Cambria", DWRITE_FONT_WEIGHT_BOLD, {}, DWRITE_FONT_SIMULATIONS_NONE);
// Request "Cambria Bold".
// - Matches the full name of one static font.
MatchFont(factory, L"Cambria Bold");
// Request "Bahnschrift" with bold weight.
// - Matches a typographic/WWS family.
// - Returns an arbitrary instance of the variable font.
MatchFont(factory, L"Bahnschrift", DWRITE_FONT_WEIGHT_BOLD);
// Request "Segoe UI Variable" with two different font sizes.
// - Matches a typographic family name only (not a WWS family name).
// - Font size maps to "opsz" axis value (Note conversion from DIPs to points.)
// - Returns an arbitrary instance of the variable font.
MatchFont(factory, L"Segoe UI Variable", 16.0f);
MatchFont(factory, L"Segoe UI Variable", 32.0f);
// Same as above with an explicit opsz axis value.
// The explicit value is used instead of an "opsz" value derived from the font size.
MatchFont(factory, L"Segoe UI Variable", 16.0f, { { DWRITE_FONT_AXIS_TAG_OPTICAL_SIZE, 32.0f } });
// Request "Segoe UI Variable Display".
// - Matches a WWS family (NOT a typographic family).
// - The input "opsz" value is ignored; the optical size of the family is used.
MatchFont(factory, L"Segoe UI Variable Display", 16.0f);
// Request "Segoe UI Variable Display Bold".
// - Matches the full name of a variable font instance.
// - All input axes are ignored; the axis values of the matching font are used.
MatchFont(factory, L"Segoe UI Variable Display Bold", 16.0f);
}
A fenti TestFontSelection függvény kimenete a következő:
GetMatchingFonts("Cambria", { wght:700 wdth:100 ital:0 slnt:0 }, 3):
cambriab.ttf wght:700 wdth:100 ital:0 slnt:0
cambria.ttc wght:400 wdth:100 ital:0 slnt:0 BOLDSIM
cambriaz.ttf wght:700 wdth:100 ital:1 slnt:-12.4
cambriai.ttf wght:400 wdth:100 ital:1 slnt:-12.4 BOLDSIM
GetMatchingFonts("Cambria", { wght:700 wdth:100 ital:0 slnt:0 }, 0):
cambriab.ttf wght:700 wdth:100 ital:0 slnt:0
cambriaz.ttf wght:700 wdth:100 ital:1 slnt:-12.4
cambria.ttc wght:400 wdth:100 ital:0 slnt:0
cambriai.ttf wght:400 wdth:100 ital:1 slnt:-12.4
GetMatchingFonts("Cambria Bold", { wght:400 wdth:100 ital:0 slnt:0 }, 3):
cambriab.ttf wght:700 wdth:100 ital:0 slnt:0
GetMatchingFonts("Bahnschrift", { wght:700 wdth:100 ital:0 slnt:0 }, 3):
bahnschrift.ttf wght:700 wdth:100 ital:0 slnt:0
GetMatchingFonts("Segoe UI Variable", { wght:400 wdth:100 ital:0 slnt:0 opsz:12 }, 3):
SegUIVar.ttf opsz:12 wght:400 wdth:100 ital:0 slnt:0
GetMatchingFonts("Segoe UI Variable", { wght:400 wdth:100 ital:0 slnt:0 opsz:24 }, 3):
SegUIVar.ttf opsz:24 wght:400 wdth:100 ital:0 slnt:0
GetMatchingFonts("Segoe UI Variable", { opsz:32 wght:400 wdth:100 ital:0 slnt:0 }, 3):
SegUIVar.ttf opsz:32 wght:400 wdth:100 ital:0 slnt:0
GetMatchingFonts("Segoe UI Variable Display", { wght:400 wdth:100 ital:0 slnt:0 opsz:12 }, 3):
SegUIVar.ttf opsz:36 wght:400 wdth:100 ital:0 slnt:0
GetMatchingFonts("Segoe UI Variable Display Bold", { wght:400 wdth:100 ital:0 slnt:0 opsz:12 }, 3):
SegUIVar.ttf opsz:36 wght:700 wdth:100 ital:0 slnt:0
Az alábbiakban a fent deklarált túlterhelt operátorok implementációit követjük. Ezeket MatchAxisValues használják a bemeneti tengely értékeinek és az eredményül kapott betűtípus-archivatkozásoknak a megírásához:
// Output a font axis value.
std::wostream& operator<<(std::wostream& out, DWRITE_FONT_AXIS_VALUE const& axisValue)
{
UINT32 tagValue = axisValue.axisTag;
WCHAR tagChars[5] =
{
static_cast<WCHAR>(tagValue & 0xFF),
static_cast<WCHAR>((tagValue >> 8) & 0xFF),
static_cast<WCHAR>((tagValue >> 16) & 0xFF),
static_cast<WCHAR>((tagValue >> 24) & 0xFF),
'\0'
};
return out << tagChars << L':' << axisValue.value;
}
// Output a file name given a font file reference.
std::wostream& operator<<(std::wostream& out, IDWriteFontFile* fileReference)
{
wil::com_ptr<IDWriteFontFileLoader> loader;
THROW_IF_FAILED(fileReference->GetLoader(&loader));
wil::com_ptr<IDWriteLocalFontFileLoader> localLoader;
if (SUCCEEDED(loader->QueryInterface(&localLoader)))
{
const void* fileKey;
UINT32 fileKeySize;
THROW_IF_FAILED(fileReference->GetReferenceKey(&fileKey, &fileKeySize));
WCHAR filePath[MAX_PATH];
THROW_IF_FAILED(localLoader->GetFilePathFromKey(fileKey, fileKeySize, filePath, MAX_PATH));
WCHAR* fileName = wcsrchr(filePath, L'\\');
fileName = (fileName != nullptr) ? fileName + 1 : filePath;
out << fileName;
}
return out;
}
// Output a font face reference.
std::wostream& operator<<(std::wostream& out, IDWriteFontFaceReference1* faceReference)
{
// Output the font file name.
wil::com_ptr<IDWriteFontFile> fileReference;
THROW_IF_FAILED(faceReference->GetFontFile(&fileReference));
std::wcout << fileReference.get();
// Output the face index if nonzero.
UINT32 const faceIndex = faceReference->GetFontFaceIndex();
if (faceIndex != 0)
{
out << L'#' << faceIndex;
}
// Output the axis values.
UINT32 const axisCount = faceReference->GetFontAxisValueCount();
std::vector<DWRITE_FONT_AXIS_VALUE> axisValues(axisCount);
THROW_IF_FAILED(faceReference->GetFontAxisValues(axisValues.data(), axisCount));
for (DWRITE_FONT_AXIS_VALUE const& axisValue : axisValues)
{
out << L' ' << axisValue;
}
// Output the simulations.
DWRITE_FONT_SIMULATIONS simulations = faceReference->GetSimulations();
if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
{
out << L" BOLDSIM";
}
if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
{
out << L" OBLIQUESIM";
}
return out;
}
A minta kerekítéséhez kövesse a parancssori elemzési függvényeket és a fő függvényt:
char const g_usage[] =
"ParseCmdLine <args>\n"
"\n"
" -test Test sample font selection parameters.\n"
" <familyname> Sets the font family name.\n"
" -size <value> Sets the font size in DIPs.\n"
" -bold Sets weight to bold (700).\n"
" -weight <value> Sets a weight in the range 100-900.\n"
" -italic Sets style to DWRITE_FONT_STYLE_ITALIC.\n"
" -oblique Sets style to DWRITE_FONT_STYLE_OBLIQUE.\n"
" -stretch <value> Sets a stretch in the range 1-9.\n"
" -<axis>:<value> Sets an axis value (for example, -opsz:24).\n"
" -nosim Disallow font simulations.\n"
"\n";
struct CmdArgs
{
std::wstring familyName;
FontStyleParams styleParams;
std::vector<DWRITE_FONT_AXIS_VALUE> axisValues;
DWRITE_FONT_SIMULATIONS allowedSimulations = DWRITE_FONT_SIMULATIONS_BOLD | DWRITE_FONT_SIMULATIONS_OBLIQUE;
bool test = false;
};
template<typename T>
_Success_(return)
bool ParseEnum(_In_z_ WCHAR const* arg, long minValue, long maxValue, _Out_ T* result)
{
WCHAR* endPtr;
long value = wcstol(arg, &endPtr, 10);
*result = static_cast<T>(value);
return value >= minValue && value <= maxValue && *endPtr == L'\0';
}
_Success_(return)
bool ParseFloat(_In_z_ WCHAR const* arg, _Out_ float* value)
{
WCHAR* endPtr;
*value = wcstof(arg, &endPtr);
return *arg != L'\0' && *endPtr == L'\0';
}
bool ParseCommandLine(int argc, WCHAR** argv, CmdArgs& cmd)
{
for (int argIndex = 1; argIndex < argc; argIndex++)
{
WCHAR const* arg = argv[argIndex];
if (*arg != L'-')
{
if (!cmd.familyName.empty())
return false;
cmd.familyName = argv[argIndex];
}
else if (!wcscmp(arg, L"-test"))
{
cmd.test = true;
}
else if (!wcscmp(arg, L"-size"))
{
if (++argIndex == argc)
return false;
if (!ParseFloat(argv[argIndex], &cmd.styleParams.fontSize))
return false;
}
else if (!wcscmp(arg, L"-bold"))
{
cmd.styleParams.fontWeight = DWRITE_FONT_WEIGHT_BOLD;
}
else if (!wcscmp(arg, L"-weight"))
{
if (++argIndex == argc)
return false;
if (!ParseEnum(argv[argIndex], 100, 900, &cmd.styleParams.fontWeight))
return false;
}
else if (!wcscmp(arg, L"-italic"))
{
cmd.styleParams.fontStyle = DWRITE_FONT_STYLE_ITALIC;
}
else if (!wcscmp(arg, L"-oblique"))
{
cmd.styleParams.fontStyle = DWRITE_FONT_STYLE_OBLIQUE;
}
else if (!wcscmp(arg, L"-stretch"))
{
if (++argIndex == argc)
return false;
if (!ParseEnum(argv[argIndex], 1, 9, &cmd.styleParams.fontStretch))
return false;
}
else if (wcslen(arg) > 5 && arg[5] == L':')
{
// Example: -opsz:12
DWRITE_FONT_AXIS_VALUE axisValue;
axisValue.axisTag = DWRITE_MAKE_FONT_AXIS_TAG(arg[1], arg[2], arg[3], arg[4]);
if (!ParseFloat(arg + 6, &axisValue.value))
return false;
cmd.axisValues.push_back(axisValue);
}
else if (!wcscmp(arg, L"-nosim"))
{
cmd.allowedSimulations = DWRITE_FONT_SIMULATIONS_NONE;
}
else
{
return false;
}
}
return true;
}
int __cdecl wmain(int argc, WCHAR** argv)
{
CmdArgs cmd;
if (!ParseCommandLine(argc, argv, cmd))
{
std::cerr << "Invalid command. Type TestFontSelection with no arguments for usage.\n";
return 1;
}
if (cmd.familyName.empty() && !cmd.test)
{
std::cout << g_usage;
return 0;
}
wil::com_ptr<IDWriteFactory7> factory;
THROW_IF_FAILED(DWriteCoreCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory7),
(IUnknown**)&factory
));
if (!cmd.familyName.empty())
{
MatchFont(
factory.get(),
cmd.familyName.c_str(),
cmd.styleParams,
std::move(cmd.axisValues),
cmd.allowedSimulations
);
}
if (cmd.test)
{
TestFontSelection(factory.get());
}
}