完全披露:我正在研究libui GUI框架的文本API。這包括Windows上的DirectWrite,OS X上的Core Text以及其他Unix上的Pango(使用HarfBuzz進行OpenType整形)。我想指定的一種文本格式屬性是要使用的OpenType功能的集合,這三個屬性都提供了這些功能; DirectWrite的是IDWriteTypography
。如何使用DirectWrite平衡面向腳本的OpenType功能與其他OpenType功能?
現在,當您使用這些庫繪製一些文本時,默認情況下會啓用一些有用的OpenType功能,例如標準連字(liga
),如f + i連字。我認爲這是字體特定的,但事實證明這是特定於正在形成的文本的腳本。 Microsoft provides guidelines for all the scripts supported by OpenType(在「特定腳本開發」下),我可以看到相當複雜的邏輯,在HarfBuzz中完成這一切,以確認它。
在Core Text和Pango上,如果啓用其他屬性,它們將被添加到這些默認值之上。但隨着DirectWrite的,特別是IDWriteTextLayout::SetTypography()
,這樣做移除默認:
產生該輸出可以發現here程序。
很顯然,我的第一個選擇是詢問如何獲取DirectWrite上的默認功能。 Someone did so already on this site, though, and the answer seems to be "no".
我在猜測,DirectWrite允許我完全控制要應用於某些文本的功能列表。這很好,除非我不能用其他API來做到這一點,除非我明確禁用默認功能!當然,我不知道這個列表是否會改變,所以對它進行硬編碼可能不是最好的主意。根據(我認爲)的版本兼容性(例如緬甸),腳本有多種可能的整形器,但是, 。
那麼,爲什麼不使用HarfBuzz的列表重新創建DirectWrite的默認功能列表呢?無論如何,它似乎想要對其他塑造者是準確的,所以這應該工作,對吧?那麼我需要做兩件事:找出要使用的腳本,並找出哪些屬性用於腳本中哪些字符在字中的位置很重要。
DirectWrite提供了一個接口IDWriteTextAnalyzer
,它提供了執行整形的工具。我可以使用它,但看起來腳本數據是在DWRITE_SCRIPT_ANALYSIS
structure中返回的,並且腳本ID的描述是「寫入系統腳本的從零開始的索引表示。」。
這沒有幫助,所以我寫了a program to just dump the script numbers for text I type in。運行它輸入字符串
لللللللللللللاااااااااالا abcd محمد ابن بطوطة Отложения датского яруса
產生輸出
0 - 26 script 3 shapes 0
26 - 5 script 49 shapes 0
31 - 14 script 3 shapes 0
45 - 2 script 1 shapes 1
47 - 25 script 22 shapes 0
我不能在任何Windows頭的這些腳本數字匹配任何東西:如果有阿拉伯文,拉丁文,或限定數目西里爾在任何API,他們不匹配這些。即使我確實得到了腳本和腳本編號之間的映射關係,但仍然無法爲我提供應用單詞內部特徵的數據。
Uniscribe呢?那麼,the equivalent SCRIPT_ANALYSIS
type的文檔說,它的腳本ID是一個「[opaque]值」,它的「這個成員的值是未定義的,應用程序不應該依賴於它的值從一個版本到下一個版本是相同的」。雖然我可以通過獲得一個語言代碼來識別腳本,但對於「西方」(拉丁語?)腳本,除LANG_ENGLISH
之外,還沒有定義值。 DirectWrite值是否與Uniscribe相同?看起來我至少可以通過查看fLinkBefore
和fLinkAfter
字段來查看單詞的初始狀態和最終狀態,但這足以正確應用每個腳本的屬性嗎?
HarfBuzz確實有一個實驗性的DirectWrite後端isn't intended to be used by real programs;我還不確定它是否具有上述我指定的相同功能。如果我發現,我會在這裏更新這部分。
最後,如果我的東西輸入以下等效試驗情況下的第一個像上面這樣kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<FlowDocumentPageViewer>
<FlowDocument FontFamily="Constantia" FontSize="48">
<Paragraph>
afford afire aflight 1/4<LineBreak/>
<Run Typography.Fraction="1">afford afire aflight 1/4</Run>
</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</Grid>
</Page>
我看到正在正確應用的繃帶,即使在後一種情況下:
(最後小數部分只是爲了證明屬性正在被應用。)如果我假設XAML使用DirectWrite,那麼這證明了我的第一個選項(簡單地說就是ove在默認情況下拖拽我的自定義屬性)應該是可能的......(我做出這個假設的基礎是XAML爲繪製2D圖形提供了非常類似於Direct2D的API,並且在其中填充了很多空洞我不得不手動編寫大量的膠水代碼來與vanilla Direct2D做同樣的事情,所以我認爲XAML中可能的任何事情都可以通過Direct2D來實現,並且由於它們在技術上一起被引入到DirectWrite中,因此可以推廣...)
在這一點上,我完全失去了。我想至少可以跨平臺進行預測,而且我不確定程序應該如何,更不用說直接使用OpenType功能,或者不管怎樣。我對文本佈局API有不好的期望嗎?如果我想要這樣做,我將不得不放棄IDWriteTextLayout並完成所有的文本整形和佈局工作嗎?
或者我必須放棄對Windows 7的支持並升級到Platform Update DirectWrite功能集?甚至完全是Windows 7?
如果你只想要這個UI文本,可以說使用系統默認值是「更好」,而不是擺弄功能。我不記得我是否用DirectWrite測試過這個功能,但是完全控制功能列表看起來毫無用處,因爲您必須知道每個腳本的功能集,禁用強制功能並沒有什麼用處。 – bunglehead
如果您確實需要它們,腳本ID在Windows版本中保持穩定,則會附加新腳本以保持順序。要獲得完全的映射,可以使用GetScriptProperties()方法,通過使用增加的腳本ID調用它,直到失敗。受支持的腳本數量取決於系統版本。 Uniscribe腳本ID同樣適用,並且與DirectWrite腳本不兼容。 – bunglehead
@bunglehead謝謝。我不得不通過進一步的討論和調查結果來修改這篇文章,但事實證明,無論如何,你都不能禁用強制性功能,所以真正的問題是如何獲得(或重新獲取)所有可選功能。對劇本的東西感到羞恥; 'GetScriptProperties()'在IDWriteTextAnalyzer1中是新的,我可以用它來猜測哪些腳本得到了什麼,但我可以使用Uniscribe的'ScriptItemizeOpenType()'並獲得OpenType腳本標記而不是ISO腳本代碼,這可能會使這一點更容易...我會在明天更新的問題中寫更多。 – andlabs