Set di caratteri personalizzati
Questo argomento descrive vari modi in cui è possibile usare tipi di carattere personalizzati nell'app.
- Introduzione
- Riepilogo delle API
- Concetti chiave
- Tipi di carattere e formati di file di carattere
- Set di tipi di carattere e raccolte di tipi di carattere
-
Scenari comuni
- Creazione di un set di caratteri usando tipi di carattere arbitrari nel file system locale
- Creazione di un set di caratteri usando tipi di carattere noti nel file system locale
- Creazione di un set di caratteri personalizzato usando tipi di carattere noti e remoti sul Web
- Creazione di un set di caratteri personalizzato usando i dati dei tipi di carattere caricati in memoria
- Scenari avanzati
Introduzione
La maggior parte del tempo, le app usano i tipi di carattere installati localmente nel sistema. DirectWrite fornisce l'accesso a questi tipi di carattere usando i metodi IDWriteFactory3::GetSystemFontSet o IDWriteFactory::GetSystemFontCollection. In alcuni casi, le app possono anche voler usare i tipi di carattere inclusi nell'ambito di Windows 10, ma che non sono attualmente installati nel sistema corrente. Tali tipi di carattere possono essere accessibili dal servizio carattere di Windows usando il metodo GetSystemFontSet oppure chiamando IDWriteFactory3::GetSystemFontCollection con includeDownloadableFonts impostato su TRUE.
In alcuni scenari dell'applicazione, tuttavia, le app devono usare i tipi di carattere non installati nel sistema e non vengono forniti dal servizio carattere di Windows. Di seguito sono riportati esempi di questi scenari:
- I tipi di carattere vengono incorporati come risorse all'interno di un file binario dell'app.
- I file di carattere vengono raggruppati all'interno di un pacchetto dell'app e archiviati su disco nella cartella di installazione dell'app.
- L'app è uno strumento di sviluppo dei tipi di carattere che deve caricare i file di carattere specificati dall'utente.
- I tipi di carattere sono incorporati nei file di documento che possono essere visualizzati o modificati nell'app.
- L'app usa i tipi di carattere ottenuti da un servizio carattere Web pubblico.
- L'app usa i dati dei tipi di carattere trasmessi tramite un protocollo di rete privato.
DirectWrite fornisce API per l'uso di tipi di carattere personalizzati in questi scenari e altri scenari simili. I dati dei tipi di carattere personalizzati potrebbero venire dai file nel file system locale; da origini remote basate sul cloud a cui è stato eseguito l'accesso tramite HTTP; o da origini arbitrarie dopo essere state caricate in un buffer di memoria.
Nota
Sebbene DirectWrite abbia fornito API per l'uso di tipi di carattere personalizzati dal momento che Windows 7, le API più recenti sono state aggiunte in Windows 10 e nuovamente nell'Windows 10 Creators Update (build di anteprima 15021 o successiva) che semplificano l'implementazione di diversi scenari menzionati. Questo argomento è incentrato sulle API disponibili in Window 10. Per le applicazioni che devono funzionare nelle versioni precedenti di Windows, vedere Raccolte di caratteri personalizzate (Windows 7/8).
Riepilogo delle API
Questo argomento è incentrato sulle funzionalità fornite dalle API seguenti:
- Interfaccia IDWriteFontSet
- Interfaccia IDWriteFontSetBuilder
- Interfaccia IDWriteFontSetBuilder1
- Interfaccia IDWriteFontFaceReference
- Interfaccia IDWriteFontFile
- Metodo IDWriteFactory::CreateFontFileReference
- Metodo IDWriteFactory::CreateCustomFontFileReference
- Metodi IDWriteFactory3::CreateFontFaceReference
- DWRITE_FONT_PROPERTY struttura
- enumerazione DWRITE_FONT_PROPERTY_ID
- Interfaccia IDWriteFontFileLoader
- Metodo IDWriteFactory::RegisterFontFileLoader
- Metodo IDWriteFactory::UnregisterFontFileLoader
- Metodo IDWriteFactory5::CreateInMemoryFontFileLoader
- Interfaccia IDWriteInMemoryFontFileLoader
- Metodo IDWriteFactory5::CreateHttpFontFileLoader
- Interfaccia IDWriteRemoteFontFileLoader
- Interfaccia IDWriteFontDownloadQueue
- Interfaccia IDWriteFontDownloadListener
- Interfaccia IDWriteFontFileStream
- Interfaccia IDWriteRemoteFontFileStream
- Interfaccia IDWriteAsyncResult
- Metodo IDWriteFactory5::AnalysisContainerType
- Metodo IDWriteFactory5::UnpackFontFile
Concetti chiave
Per comprendere le API DirectWrite per l'uso di tipi di carattere personalizzati, può essere utile comprendere il modello concettuale che sottolizza queste API. I concetti chiave verranno descritti qui.
Quando DirectWrite esegue il layout o il rendering del testo effettivi, è necessario accedere ai dati dei tipi di carattere effettivi. Un oggetto viso del carattere contiene dati di carattere effettivi, che devono esistere nel sistema locale. Ma per altre operazioni, ad esempio il controllo della disponibilità di un tipo di carattere specifico o la presentazione di scelte di carattere a un utente, tutto ciò che è necessario è un riferimento a un tipo di carattere specifico, non ai dati effettivi del carattere stesso. In DirectWrite, un oggetto riferimento al viso del carattere contiene solo le informazioni necessarie per individuare e creare un'istanza di un tipo di carattere. Poiché il riferimento al viso del carattere non contiene dati effettivi, DirectWrite può gestire i riferimenti al carattere per i quali i dati effettivi si trovano in una posizione di rete remota e quando i dati effettivi sono locali.
Un set di caratteri è un set di riferimenti al viso del carattere, insieme a determinate proprietà di base, informazioni che possono essere usate in riferimento al tipo di carattere o confrontandolo con altri tipi di carattere, ad esempio il nome della famiglia o un valore di peso del carattere. I dati effettivi per i vari tipi di carattere possono essere locali oppure possono essere tutti remoti o alcune combinazioni.
Un set di caratteri può essere usato per ottenere un oggetto raccolta di caratteri corrispondente. Per altre informazioni, vedere Set di tipi di carattere e raccolte di tipi di carattere seguenti.
L'interfaccia IDWriteFontSet fornisce metodi che consentono di eseguire query per i valori delle proprietà, ad esempio il nome della famiglia o il peso del tipo di carattere o per i riferimenti al carattere che corrispondono a valori di proprietà specifici. Dopo aver filtrato fino a una determinata selezione, è possibile ottenere un'istanza dell'interfaccia IDWriteFontFaceReference , con metodi per il download (se i dati del carattere effettivi sono attualmente remoti), per ottenere l'oggetto IDWriteFontFace3 corrispondente che può essere usato per il layout e il rendering.
L'interfaccia IDWriteFontFile sottoscrive ogni riferimento al viso o al viso del carattere. Rappresenta il percorso di un file di carattere e include due componenti: un caricatore di file di tipo carattere e una chiave di file di tipo carattere. Il caricatore di file di tipo carattere (IDWriteFontFileLoader) viene usato per aprire un file se necessario e restituisce un flusso con i dati (IDWriteFontFileStream). A seconda del caricatore, i dati possono trovarsi in un percorso di file locale, un URL remoto o in un buffer di memoria. La chiave è un valore definito dal caricatore che identifica in modo univoco il file all'interno del contesto del caricatore, consentendo al caricatore di individuare i dati e creare un flusso per esso.
I tipi di carattere personalizzati possono essere aggiunti facilmente a un set di tipi di carattere personalizzato, che a sua volta possono essere usati per filtrare o organizzare le informazioni sul tipo di carattere per scopi come la creazione di un'interfaccia utente selezione caratteri. Il set di caratteri può essere usato anche per creare una raccolta di caratteri da usare nelle API di livello superiore, ad esempio IDWriteTextFormat e IDWriteTextLayout. L'interfaccia IDWriteFontSetBuilder può essere usata per creare un set di caratteri personalizzato che include diversi tipi di carattere personalizzati. Può essere usato anche per creare un set di caratteri personalizzato che combina tipi di carattere personalizzati e tipi di carattere forniti dal sistema; o che combina tipi di carattere con origini diverse per i dati effettivi, ovvero archiviazione locale, URL remoti e memoria.
Come accennato, un riferimento al carattere di riferimento può fare riferimento ai dati dei tipi di carattere in un'origine remota, ma i dati devono essere locali per ottenere un oggetto viso del carattere che può essere usato per il layout e il rendering. Il download dei dati remoti viene gestito da una coda di download dei tipi di carattere. Le app possono usare l'interfaccia IDWriteFontDownloadQueue per richiedere di scaricare tipi di carattere remoti per avviare il processo di download e per registrare un oggetto IDWriteFontDownloadListener per eseguire azioni al termine del processo di download.
Per la maggior parte delle interfacce descritte qui, DirectWrite fornisce implementazioni di sistema. L'unica eccezione è l'interfaccia IDWriteFontDownloadListener , che un'app implementa per eseguire azioni specifiche dell'app quando i tipi di carattere remoti sono stati scaricati in locale. Le app possono avere motivo di fornire implementazioni personalizzate per determinate interfacce, anche se ciò sarebbe necessario solo in scenari specifici e più avanzati. Ad esempio, un'app deve fornire un'implementazione personalizzata dell'interfaccia IDWriteFontFileLoader per gestire i file di carattere nell'archiviazione locale che usano il formato contenitore WOFF2. Di seguito verranno forniti altri dettagli.
Tipi di carattere e formati di file di carattere
Un altro concetto chiave utile per comprendere è la relazione tra i singoli volti dei tipi di carattere e i file di carattere che li contengono. L'idea di un file di carattere OpenType (con estensione ttf o otf) contenente un singolo tipo di carattere è familiare. Ma il formato del tipo di carattere OpenType consente anche una raccolta di caratteri OpenType (con estensione ttc o otc), che è un singolo file che contiene più tipi di carattere. I file di raccolta OpenType vengono spesso usati per tipi di carattere di grandi dimensioni strettamente correlati e hanno valori identici per determinati dati di tipo carattere: combinando i tipi di carattere in un singolo file, i dati comuni possono essere de duplicati. Per questo motivo, un riferimento di tipo carattere o volto carattere deve fare riferimento non solo a un file di tipo di carattere (o a un'origine dati equivalente), ma deve anche specificare un indice del tipo di carattere all'interno di tale file, per il caso generale in cui il file può essere un file Collection.
Per i tipi di carattere usati sul Web, i dati dei tipi di carattere vengono spesso compressi in determinati formati di contenitore, WOFF o WOFF2, che forniscono una compressione dei dati dei tipi di carattere e un certo livello di protezione contro la pirateria e la violazione delle licenze dei tipi di carattere. Dal lato funzionale, un file WOFF o WOFF2 equivale a un tipo di carattere OpenType o a un file di raccolta di tipi di carattere, ma i dati vengono codificati in un formato diverso che richiede la decompressione prima di poterlo usare.
Alcune API di DirectWrite possono gestire i singoli visi dei tipi di carattere, mentre altre API possono gestire file che potrebbero includere file della raccolta OpenType contenenti più visi. Analogamente, alcune API gestiscono solo dati in formato OpenType non elaborati, mentre altre API possono gestire i formati di contenitore WOFF e WOFF2 compressi. Questi dettagli vengono forniti nella discussione seguente.
Set di tipi di carattere e raccolte di tipi di carattere
Alcune applicazioni possono essere implementate per lavorare con i tipi di carattere usando l'interfaccia IDWriteFontCollection . Esiste una corrispondenza diretta tra una raccolta di tipi di carattere e un set di caratteri. Ognuno può contenere gli stessi tipi di carattere, ma li presenta con un'organizzazione diversa. Da qualsiasi raccolta di tipi di carattere è possibile ottenere un set di caratteri corrispondente e viceversa.
Quando si usano diversi tipi di carattere personalizzati, è più semplice usare un'interfaccia del generatore di set di caratteri per creare un set di caratteri personalizzato e quindi ottenere una raccolta di tipi di carattere dopo la creazione del set di caratteri. Il processo di creazione di un set di caratteri personalizzato verrà descritto in dettaglio di seguito. Per ottenere un'interfaccia IDWriteFontCollection1 da un set di tipi di carattere, viene utilizzato il metodo IDWriteFactory3::CreateFontCollectionFromFontSet .
Se l'app ha un oggetto raccolta e deve ottenere un set di tipi di carattere corrispondente, questa operazione può essere eseguita usando il metodo IDWriteFontCollection1::GetFontSet .
Scenari comuni
Questa sezione descrive alcuni degli scenari più comuni che coinvolgono set di tipi di carattere personalizzati:
- Creazione di un set di tipi di carattere personalizzato utilizzando tipi di carattere arbitrari nei percorsi nel file system locale.
- Creazione di un set di tipi di carattere personalizzato usando tipi di carattere noti (forse in bundle con l'app) archiviati nel file system locale.
- Creazione di un set di tipi di carattere personalizzato utilizzando tipi di carattere noti e remoti sul Web.
- Creazione di un set di tipi di carattere personalizzato usando i dati del tipo di carattere caricati in memoria.
Le implementazioni complete per questi scenari sono disponibili nell'esempio DirectWrite set di caratteri personalizzati. Questo esempio illustra anche uno scenario più avanzato per la gestione dei dati dei tipi di carattere compressi in formati di contenitore WOFF o WOFF2, che verranno illustrati di seguito.
Creazione di un set di tipi di carattere utilizzando tipi di carattere arbitrari nel file system locale
Quando si gestisce un set arbitrario di file di tipo di carattere nell'archiviazione locale, il metodo IDWriteFontSetBuilder1::AddFontFile è pratico poiché, in una singola chiamata, può gestire tutti i visi dei tipi di carattere all'interno di un file di raccolta di tipi di carattere OpenType, nonché tutte le istanze per un tipo di carattere di una variabile OpenType. Questa funzionalità è disponibile nella Windows 10 Creators Update (anteprima build 15021 o successiva) ed è consigliata ogni volta che è disponibile.
Per usare questo metodo, usare il processo seguente.
- 1. Iniziare creando l'interfaccia IDWriteFactory5 :
- Per ogni file di tipo di carattere nel file system locale, creare un IDWriteFontFile che fa riferimento al file seguente:
- Dopo aver aggiunto tutti i file al generatore di set di caratteri, è possibile creare il set di caratteri personalizzato:
IDWriteFactory5* pDWriteFactory;
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory5),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
2. Usare la factory per ottenere l'interfaccia IDWriteFontSetBuilder1 :
IDWriteFontSetBuilder1* pFontSetBuilder;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder);
}
IDWriteFontFile* pFontFile;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile);
}
4. Aggiungere l'oggetto IDWriteFontFile al generatore di set di caratteri usando il metodo AddFontFile :
hr = pFontSetBuilder->AddFontFile(pFontFile);
Se il percorso del file specificato nella chiamata a CreateFontFileReference fa riferimento a un elemento diverso da un file OpenType supportato, la chiamata a AddFontFile restituirà un errore, DWRITE_E_FILEFORMAT.
IDWriteFontSet* pFontSet;
hr = pFontSetBuilder->CreateFontSet(&pFontSet);
Se l'app deve essere eseguita in Windows 10 versioni precedenti alla Windows 10 Creators Update, il metodo AddFontFile non sarà disponibile. È possibile rilevare la disponibilità creando un'interfaccia IDWriteFactory3 e quindi usando QueryInterface per provare a ottenere un'interfaccia IDWriteFactory5 : se l'operazione riesce, sarà disponibile anche l'interfaccia IDWriteFontSetBuilder1 e il metodo AddFontFile .
Se il metodo AddFontFile non è disponibile, è necessario utilizzare il metodo IDWriteFontSetBuilder::AddFontFaceReference per aggiungere singoli visi dei tipi di carattere. Per consentire i file della raccolta di tipi di carattere OpenType che contengono più visi, è possibile utilizzare il metodo IDWriteFontFile::Analyze per determinare il numero di visi contenuti nel file. Il processo è il seguente.
- 1. Iniziare creando l'interfaccia IDWriteFactory3 :
- Usare la factory per ottenere l'interfaccia IDWriteFontSetBuilder :
- Per ogni file di carattere, creare un IDWriteFontFile, come indicato di seguito:
- Dopo aver aggiunto tutti i visi al generatore di set di caratteri, creare il set di caratteri personalizzato, come illustrato in precedenza.
IDWriteFactory3* pDWriteFactory;
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory5),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
IDWriteFontSetBuilder* pFontSetBuilder;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder);
}
IDWriteFontFile* pFontFile;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile);
}
Anziché aggiungere il file direttamente al generatore di set di caratteri, è necessario determinare il numero di visi e creare singoli oggetti IDWriteFontFaceReference .
4. Utilizzare il metodo Analyze per ottenere il numero di visi nel file.
BOOL isSupported;
DWRITE_FONT_FILE_TYPE fileType;
UINT32 numberOfFonts;
hr = pFontFile->Analyze(&isSupported, &fileType, /* face type */ nullptr, &numberOfFonts);
Il metodo Analyze imposterà anche i valori per i parametri isSupported e fileType. Se il file non è un formato supportato, isSupported sarà FALSE e sarà possibile eseguire un'azione appropriata, ad esempio ignorando il file.
5. Scorrere il numero di tipi di carattere impostati nel parametro numberOfFonts. All'interno del ciclo creare un IDWriteFontFaceReference per ogni coppia di file/indice e aggiungerlo al generatore di set di caratteri.
for (uint32_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++)
{
IDWriteFontFaceReference* pFontFaceReference;
hr = pDWriteFactory->CreateFontFaceReference(pFontFile, fontIndex, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);
if (SUCCEEDED(hr))
{
hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference);
}
}
È possibile progettare un'app in modo che usi il metodo AddFontFile preferito durante l'esecuzione nel Windows 10 Creators Update, ma eseguire il fallback per usare il metodo AddFontFaceReference quando viene eseguito nelle versioni Windows 10 precedenti. Verificare la disponibilità dell'interfaccia IDWriteFactory5 , come descritto in precedenza, e quindi diramare di conseguenza. Questo approccio è illustrato nell'esempio DirectWrite set di caratteri personalizzati.
Creazione di un set di tipi di carattere usando tipi di carattere noti nel file system locale
Come accennato in precedenza, ogni riferimento al viso del carattere in un set di caratteri è associato a determinate proprietà informative, ad esempio il nome della famiglia e lo spessore del carattere. Quando i tipi di carattere personalizzati vengono aggiunti a un generatore di set di caratteri usando le chiamate API elencate in precedenza, queste proprietà informative vengono ottenute direttamente dai dati effettivi del tipo di carattere, che vengono letti man mano che viene aggiunto il tipo di carattere. In alcune situazioni, tuttavia, se un'app ha un'altra origine di informazioni su un tipo di carattere, potrebbe voler fornire valori personalizzati per queste proprietà.
Come esempio di come questo potrebbe essere utile, si supponga che un'app aggrega alcuni tipi di carattere usati per presentare determinati elementi dell'interfaccia utente all'interno dell'app. A volte, ad esempio con una nuova versione dell'app, potrebbero essere necessari caratteri specifici usati dall'app per questi elementi. Se l'app ha riferimenti codificati ai tipi di carattere specifici, la sostituzione di un tipo di carattere con un altro richiederà la modifica di ognuno di questi riferimenti. Se invece l'app usa proprietà personalizzate per assegnare alias funzionali in base al tipo di elemento o testo di cui viene eseguito il rendering, esegue il mapping di ogni alias a un tipo di carattere specifico in un'unica posizione e quindi usa gli alias in tutti i contesti in cui vengono creati e modificati i tipi di carattere, quindi sostituire un tipo di carattere con un altro richiede solo la modifica di una posizione in cui l'alias viene mappato a un tipo di carattere specifico.
È possibile assegnare valori personalizzati per le proprietà informative quando viene chiamato il metodo IDWriteFontSetBuilder::AddFontFaceReference . Il metodo per eseguire questa operazione è il seguente; può essere usato in qualsiasi versione Windows 10.
Come illustrato in precedenza, iniziare ottenendo le interfacce IDWriteFactory3 e IDWriteFontSet . Per ogni carattere personalizzato da aggiungere, creare un IDWriteFontFaceReference, come illustrato in precedenza. Prima di aggiungerlo al generatore di set di caratteri (all'interno del ciclo nel passaggio 5, illustrato sopra), tuttavia, l'app definisce i valori delle proprietà personalizzate da usare.
Un set di valori di proprietà personalizzati viene definito usando una matrice di strutture DWRITE_FONT_PROPERTY . Ognuno di questi identifica una particolare proprietà dell'enumerazione DWRITE_FONT_PROPERTY_ID e il valore della proprietà corrispondente da utilizzare.
Si noti che tutti i valori delle proprietà vengono assegnati come stringhe. Se questi valori potrebbero essere visualizzati successivamente agli utenti, è possibile impostare valori alternativi per una determinata proprietà per lingue diverse, ma questo non è obbligatorio. Si noti anche che se i valori delle proprietà personalizzate vengono impostati dall'app, solo i valori specificati verranno usati all'interno del set Font; DirectWrite non deriverà alcun valore direttamente dal tipo di carattere per le proprietà informative utilizzate in un set di tipi di carattere.
Nell'esempio seguente vengono definiti valori personalizzati per tre proprietà informative: nome della famiglia, nome completo e spessore del carattere.
DWRITE_FONT_PROPERTY props[] =
{
{ DWRITE_FONT_PROPERTY_ID_FAMILY_NAME, L"My Icon Font", L"en-US" },
{ DWRITE_FONT_PROPERTY_ID_FULL_NAME, L"My Icon Font", L"en-US" },
{ DWRITE_FONT_PROPERTY_ID_WEIGHT, L"400", nullptr }
};
Dopo aver definito la matrice desiderata di valori di proprietà per un tipo di carattere, effettuare una chiamata a AddFontFaceRefence, passando la matrice di proprietà e il riferimento al viso del carattere.
hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference, props, ARRAYSIZE(props));
Dopo aver aggiunto tutti i visi dei tipi di carattere personalizzati al generatore di set di caratteri, insieme alle relative proprietà personalizzate, creare il set di caratteri personalizzato, come illustrato in precedenza.
Creazione di un set di tipi di carattere personalizzato utilizzando tipi di carattere noti e remoti sul Web
Le proprietà personalizzate sono importanti per l'uso dei tipi di carattere remoti. Ogni riferimento al viso del carattere deve avere alcune proprietà informative per caratterizzare il tipo di carattere e distinguerlo da altri tipi di carattere. Poiché i dati del tipo di carattere per i tipi di carattere remoti non sono locali, DirectWrite non possono derivare proprietà direttamente dai dati del tipo di carattere. Di conseguenza, le proprietà devono essere fornite in modo esplicito quando si aggiunge un tipo di carattere remoto al generatore di set di caratteri.
La sequenza di chiamate API per l'aggiunta di tipi di carattere remoti a un set di caratteri è simile alla sequenza descritta per lo scenario precedente. Poiché i dati del tipo di carattere sono remoti, tuttavia, le operazioni coinvolte per la lettura dei dati effettivi del tipo di carattere saranno diverse rispetto a quando si utilizzano file nell'archiviazione locale. Per questa situazione, nella Windows 10 Creators Update è stata aggiunta una nuova interfaccia di livello inferiore, IDWriteRemoteFontFileLoader.
Per usare il caricatore di file di tipo di carattere remoto, deve prima essere registrato con una factory di DirectWrite. Il caricatore dovrà essere mantenuto dall'app per tutto il tempo in cui vengono usati i tipi di carattere associati. Una volta che i tipi di carattere non sono più in uso e a un certo punto prima che la factory venga eliminata, il caricatore deve essere annullata la registrazione. Questa operazione può essere eseguita nel distruttore per la classe proprietaria dell'oggetto caricatore. Questi passaggi verranno illustrati di seguito.
Il metodo per la creazione di un set di tipi di carattere personalizzato utilizzando tipi di carattere remoti è il seguente; richiede il Windows 10 Creators Update.
- 1. Creare un'interfaccia IDWriteFactory5, come illustrato in precedenza.
2. Creare un'interfaccia IDWriteFontSetBuilder , come illustrato in precedenza.
3. Utilizzare la factory per ottenere un IDWriteRemoteFontFileLoader.
- Definire proprietà personalizzate per il tipo di carattere, come illustrato in precedenza.
- Aggiungere il riferimento al viso del carattere insieme alle proprietà personalizzate al generatore di set di caratteri, come illustrato in precedenza.
- Dopo aver aggiunto tutti i tipi di carattere al generatore di set di caratteri, creare il set di caratteri, come illustrato in precedenza.
- A un certo punto, quando i tipi di carattere remoti non verranno più usati, annullare la registrazione del caricatore di file di tipo di carattere remoto.
IDWriteRemoteFontFileLoader* pRemoteFontFileLoader;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateHttpFontFileLoader(
/* referrerURL */ nullptr,
/* extraHeaders */ nullptr,
&pRemoteFontFileLoader
);
}
Viene restituita un'implementazione fornita dal sistema dell'interfaccia del caricatore di file di tipi di carattere remoto in grado di gestire le interazioni HTTP per scaricare i dati dei tipi di carattere per conto dell'app. È possibile specificare un URL del referrer o intestazioni aggiuntive se richiesto dal servizio o dai servizi del tipo di carattere che rappresentano l'origine dei tipi di carattere.
Importante
Nota sulla sicurezza: quando si tenta di recuperare un tipo di carattere remoto, il potenziale esiste per un utente malintenzionato per spoofare il server previsto che verrà chiamato. In tal caso, gli URL di destinazione e referrer e i dettagli dell'intestazione verrebbero divulgati all'utente malintenzionato. Gli sviluppatori di app sono responsabili della mitigazione di questo rischio. È consigliabile usare il protocollo HTTPS anziché HTTP.
È possibile usare un singolo caricatore di file di tipi di carattere remoto per più tipi di carattere, anche se è possibile usare caricatori diversi se i tipi di carattere vengono ottenuti da più servizi con requisiti diversi per l'URL del referrer o le intestazioni aggiuntive.
4. Registrare il caricatore di file del tipo di carattere remoto con la factory.
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->RegisterFontFileLoader(pRemoteFontFileLoader);
}
Da questo punto, i passaggi per la creazione del set di tipi di carattere personalizzato sono simili a quelli descritti per i file di carattere locali noti, con due eccezioni importanti. In primo luogo, l'oggetto IDWriteFontFile viene creato usando l'interfaccia del caricatore di file di tipi di carattere remoto invece di usare la factory. In secondo luogo, il metodo Analyze non può essere utilizzato perché i dati del tipo di carattere non sono locali. L'app deve invece sapere se il file del tipo di carattere remoto è un file di raccolta di tipi di carattere OpenType e, in tal caso, deve conoscere i tipi di carattere all'interno della raccolta che userà e l'indice per ognuno. Di conseguenza, i passaggi rimanenti sono i seguenti.
5. Per ogni file di tipo di carattere remoto, utilizzare l'interfaccia del caricatore di file di tipo di carattere remoto per creare un IDWriteFontFile, specificando l'URL necessario per accedere al file del tipo di carattere.
IDWriteFontFile* pFontFile;
hr = pRemoteFontFileLoader->CreateFontFileReferenceFromUrl(
pDWriteFactory,
/* baseUrl */ L"https://github.com/",
/* fontFileUrl */ L"winjs/winjs/blob/master/src/fonts/Symbols.ttf?raw=true",
&pFontFile
);
Si noti che l'URL completo può essere specificato nel parametro fontFileUrl oppure può essere suddiviso in parti di base e relative. Se viene specificato un URL di base, la concatenazione dei valori baseUrl e fontFileUrl deve fornire l'URL completo, DirectWrite non fornirà alcun delimitatore aggiuntivo.
Importante
Nota sulla sicurezza o sulle prestazioni: quando viene effettuato un tentativo di recupero di un tipo di carattere remoto, non esiste alcuna garanzia che Windows riceverà una risposta dal server. In alcuni casi, un server può rispondere con un errore di file non trovato per un URL relativo non valido, ma interrompere la risposta se riceve più richieste non valide. Se il server non risponde, Windows si verifica un timeout, anche se potrebbero essere necessari alcuni minuti se vengono avviati più recupero. È consigliabile eseguire le operazioni che è possibile per assicurarsi che gli URL siano validi quando vengono effettuate chiamate.
Si noti anche che l'URL può puntare a un file di tipo di carattere OpenType non elaborato (con estensione ttf, otf, ttc, otc), ma può anche puntare ai tipi di carattere in un file contenitore WOFF o WOFF2. Se viene fatto riferimento a un file WOFF o WOFF2, l'implementazione DirectWrite del caricatore di file di carattere remoto decomprime automaticamente i dati del tipo di carattere dal file contenitore.
6. Per ogni indice del tipo di carattere all'interno del file di tipo di carattere remoto da utilizzare, creare un IDWriteFontFaceReference.
IDWriteFontFaceReference* pFontFaceReference;
hr = pDWriteFactory->CreateFontFaceReference(pFontFile, /* faceIndex */ 0, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);
hr = pDWriteFactory->UnregisterFontFileLoader(pRemoteFontFileLoader);
Dopo aver creato un set di tipi di carattere personalizzato con tipi di carattere remoti personalizzati, il set di tipi di carattere contiene riferimenti e proprietà informative per i tipi di carattere remoti, ma i dati effettivi sono ancora remoti. DirectWrite supporto per i tipi di carattere remoti consente di mantenere un riferimento al viso del carattere nel set di caratteri e di selezionare un tipo di carattere per l'uso nel layout e nel rendering, ma che i dati effettivi non vengono scaricati fino a quando non è necessario usarlo, ad esempio quando verrà eseguito il layout di testo.
Un'app può adottare un approccio iniziale richiedendo che DirectWrite scaricare i dati del tipo di carattere e quindi attendere la conferma di un download corretto prima dell'inizio di qualsiasi elaborazione con il tipo di carattere. Tuttavia, un download di rete implica una certa latenza di durata imprevedibile e anche il successo è incerto. Per questo motivo, in genere sarà preferibile adottare un approccio diverso, consentendo di eseguire il layout e il rendering inizialmente usando tipi di carattere alternativi o di fallback già locali, richiedendo il download del tipo di carattere desiderato, remoto in parallelo e quindi aggiornando i risultati dopo il download del tipo di carattere desiderato.
Per richiedere il download dell'intero tipo di carattere prima che venga utilizzato, è possibile utilizzare il metodo IDWriteFontFaceReference::EnqueueFontDownloadRequest . Se il tipo di carattere è molto grande, potrebbe essere necessaria solo una parte dei dati per l'elaborazione di stringhe specifiche. DirectWrite fornisce metodi aggiuntivi che possono essere usati per richiedere parti dei dati del tipo di carattere necessari per contenuti specifici, EnqueueCharacterDownloadRequest e EnqueueGlyphDownloadRequest.
Si supponga che l'approccio da adottare nell'app sia quello di consentire l'elaborazione inizialmente usando tipi di carattere locali, alternativi o di fallback. Il metodo IDWriteFontFallback::MapCharacters può essere usato per identificare i tipi di carattere di fallback locali e accoderà automaticamente una richiesta per scaricare il tipo di carattere preferito. Inoltre, se viene usato IDWriteTextLayout e alcuni o tutti i tipi di testo nel layout vengono formattati usando un riferimento al tipo di carattere remoto, DirectWrite userà automaticamente il metodo MapCharacters per ottenere tipi di carattere di fallback locali e per accodare una richiesta per scaricare i dati del tipo di carattere remoto.
DirectWrite gestisce una coda di download dei tipi di carattere per ogni factory e le richieste effettuate usando i metodi indicati in precedenza vengono aggiunte a tale coda. La coda di download dei tipi di carattere può essere ottenuta usando il metodo IDWriteFactory3::GetFontDownloadQueue .
Se viene effettuata una richiesta di download ma i dati del tipo di carattere sono già locali, verrà generato un no-op: Nothing verrà aggiunto alla coda di download. Un'app può verificare se la coda è vuota o se sono presenti richieste di download in sospeso chiamando il metodo IDWriteFontDownloadQueue::IsEmpty .
Dopo l'aggiunta delle richieste di tipo di carattere remoto alla coda, è necessario avviare il processo di download. Quando i tipi di carattere remoti vengono usati in IDWriteTextLayout, il download verrà avviato automaticamente quando l'app chiama i metodi IDWriteTextLayout che forzano le operazioni di layout o rendering, ad esempio i metodi GetLineMetrics o Draw. In altri scenari, l'app deve avviare il download direttamente chiamando IDWriteFontDownloadQueue::BeginDownload.
Al termine di un download, l'app eseguirà le azioni appropriate, procedendo con operazioni in sospeso o ripetendo le operazioni eseguite inizialmente con i tipi di carattere di fallback. Se si usa il layout di testo di DirectWrite, è possibile usare IDWriteTextLayout3::InvalidateLayout per cancellare i risultati temporanei calcolati usando tipi di carattere di fallback. Affinché l'app venga notificata quando il processo di download è stato completato e per eseguire le azioni appropriate, l'app deve fornire un'implementazione dell'interfaccia IDWriteFontDownloadListener e passarla alla chiamata BeginDownload.
Importante
Nota sulla sicurezza o sulle prestazioni: quando viene effettuato un tentativo di recupero di un tipo di carattere remoto, non esiste alcuna garanzia che Windows riceverà una risposta dal server. Se il server non risponde, Windows si verifica un timeout, anche se potrebbero essere necessari alcuni minuti se vengono recuperati più tipi di carattere remoti ma non riusciti. La chiamata BeginDownload restituirà immediatamente. Le app non devono bloccare l'interfaccia utente durante l'attesa della chiamata di IDWriteFontDownloadListener::D ownloadCompleted .
Le implementazioni di esempio di queste interazioni con la coda di download dei tipi di carattere di DirectWrite e dell'interfaccia IDWriteFontDownloadListener possono essere visualizzate nell'esempio DirectWrite set di caratteri personalizzati e anche nell'esempio di tipi di carattere scaricabili DirectWrite.
Creazione di un set di tipi di carattere personalizzato usando i dati del tipo di carattere caricati in memoria
Come le operazioni di basso livello per la lettura dei dati da un file di tipo di carattere sono diverse per i file in un disco locale rispetto ai file remoti sul Web, lo stesso vale anche per i dati dei tipi di carattere caricati in un buffer di memoria. È stata aggiunta una nuova interfaccia di basso livello per la gestione dei dati dei tipi di carattere in memoria nel Windows 10 Creators Update, IDWriteInMemoryFontFileLoader.
Come per un caricatore di file di tipo di carattere remoto, un caricatore di file di tipo carattere in memoria deve prima essere registrato con una factory di DirectWrite. Il caricatore dovrà essere mantenuto dall'app per tutto il tempo in cui vengono usati i tipi di carattere associati. Una volta che i tipi di carattere non sono più in uso e a un certo punto prima che la factory venga eliminata, il caricatore deve essere annullata la registrazione. Questa operazione può essere eseguita nel distruttore per la classe proprietaria dell'oggetto caricatore. Questi passaggi verranno illustrati di seguito.
Se l'app dispone di informazioni separate sui visi del tipo di carattere rappresentati dai dati, può aggiungere singoli riferimenti di tipo carattere a un generatore di set di caratteri con proprietà personalizzate specificate. Poiché i dati del tipo di carattere sono in memoria locale, tuttavia, non è necessario; DirectWrite sarà in grado di leggere i dati direttamente per derivare i valori delle proprietà.
DirectWrite presuppone che i dati del tipo di carattere siano in formato raw, OpenType, equivalenti a un file OpenType (con estensione ttf, otf, ttc, otc), ma in memoria anziché su disco. I dati non possono essere in un formato contenitore WOFF o WOFF2. I dati possono rappresentare una raccolta di tipi di carattere OpenType. Se le proprietà personalizzate non vengono utilizzate, è possibile utilizzare il metodo IDWriteFontSetBuilder1::AddFontFile per aggiungere tutti i visi dei tipi di carattere nei dati in una singola chiamata.
Una considerazione importante per lo scenario in memoria è la durata dei dati. Se viene fornito un puntatore al buffer per DirectWrite senza un'indicazione chiara che esiste un proprietario, DirectWrite creerà una copia dei dati in un nuovo buffer di memoria di cui sarà proprietario. Per evitare la copia dei dati e l'allocazione di memoria aggiuntiva, l'app può passare un oggetto proprietario dei dati che implementa IUnknown e che possiede il buffer di memoria contenente i dati del tipo di carattere. Implementando questa interfaccia, DirectWrite può aggiungere al conteggio dei riferimenti dell'oggetto, garantendo così la durata dei dati di proprietà.
Il metodo per la creazione di un set di tipi di carattere personalizzato utilizzando i dati del tipo di carattere in memoria è il seguente; richiede il Windows 10 Creators Update. Si presuppone un oggetto proprietario dati implementato dall'app, che implementa IUnknown e include anche metodi che restituiscono un puntatore al buffer di memoria e le dimensioni del buffer.
- 1. Creare un'interfaccia IDWriteFactory5, come illustrato in precedenza.
2. Creare un'interfaccia [**IDWriteFontSetBuilder1**](/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontsetbuilder1), come illustrato in precedenza.
3. Utilizzare la factory per ottenere un IDWriteInMemoryFontFileLoader.
IDWriteInMemoryFontFileLoader* pInMemoryFontFileLoader;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateInMemoryFontFileLoader(&pInMemoryFontFileLoader);
}
In questo modo viene restituita un'implementazione fornita dal sistema dell'interfaccia del caricatore di file di tipi di carattere in memoria.
4. Registrare il caricatore di file di carattere in memoria con la factory.
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->RegisterFontFileLoader(pInMemoryFontFileLoader);
}
5. Per ogni file di tipo di carattere in memoria, utilizzare il caricatore di file di tipo di carattere in memoria per creare un IDWriteFontFile.
IDWriteFontFile* pFontFile;
hr = pInMemoryFontFileLoader->CreateInMemoryFontFileReference(
pDWriteFactory,
pFontDataOwner->fontData /* returns void* */,
pFontDataOwner->fontDataSize /* returns UINT32 */,
pFontDataOwner /* ownerObject, owns the memory with font data and implements IUnknown */,
&pFontFile
);
6. Aggiungere l'oggetto IDWriteFontFile al generatore di set di caratteri usando il metodo AddFontFile , come illustrato in precedenza. In caso di necessità, l'app può invece creare singoli oggetti IDWriteFontFaceReference basati su IDWriteFontFile, definire facoltativamente proprietà personalizzate per ogni riferimento al viso del carattere e quindi aggiungere il riferimento al viso del carattere con proprietà personalizzate al set di caratteri usando il metodo AddFontFaceReference , come illustrato in precedenza.
7. Dopo l'aggiunta di tutti i tipi di carattere al generatore di set di caratteri, creare il set di caratteri personalizzato, come illustrato in precedenza.
8. A un certo punto, quando i tipi di carattere in memoria non verranno più utilizzati, annullare la registrazione del caricatore di file di carattere in memoria.
hr = pDWriteFactory->UnregisterFontFileLoader(pInMemoryFontFileLoader);
Scenari avanzati
Alcune app possono avere requisiti speciali che richiedono un'elaborazione più avanzata di quanto descritto in precedenza.
Combinazione di set di caratteri
Alcune app potrebbero dover creare un set di tipi di carattere che comprende alcune combinazioni di elementi di altri set di caratteri. Ad esempio, un'app può voler creare un set di tipi di carattere che combina tutti i tipi di carattere installati nel sistema con una selezione di tipi di carattere personalizzati o che combina tipi di carattere installati corrispondenti a determinati criteri con altri tipi di carattere. DirectWrite include API per supportare la manipolazione e la combinazione di set di caratteri.
Per combinare due o più set di caratteri, il metodo IDWriteFontSetBuilder::AddFontSet aggiunge tutti i tipi di carattere del set di caratteri specificato da aggiungere a un generatore di set di caratteri in una singola chiamata. Se solo determinati tipi di carattere di un set di tipi di carattere esistente sono desiderati nel nuovo set di tipi di carattere, è possibile utilizzare il metodo IDWriteFontSet::GetMatchingFonts per derivare un nuovo oggetto set di tipi di carattere filtrato in modo da includere solo i tipi di carattere corrispondenti alle proprietà specificate. Questi metodi offrono un modo semplice per creare un set di tipi di carattere personalizzato combinando i tipi di carattere da due o più set di caratteri esistenti
Uso dei dati del tipo di carattere WOFF o WOFF2 locali
Se un'app include file di carattere nel file system locale o in un buffer di memoria, ma usano i formati di contenitore WOFF o WOFF2, DirectWrite (Windows 10 Creator Update o versione successiva) fornisce un metodo per decomprimere il formato del contenitore, IDWriteFactory5::UnpackFontFile, che restituisce un IDWriteFontFileStream.
Tuttavia, l'app richiederà un modo per ottenere IDWriteFontFileStream in un oggetto caricatore di file di tipo carattere. Un modo per eseguire questa operazione consiste nel creare un'implementazione IDWriteFontFileLoader personalizzata che esegue il wrapping del flusso. Come per altri caricatori di file di carattere, è necessario registrarlo prima dell'uso e annullare la registrazione prima che la factory esula dall'ambito.
Se il caricatore personalizzato verrà usato anche con file di carattere non elaborati (non compressi), l'app dovrà anche fornire un'implementazione personalizzata dell'interfaccia IDWriteFontFileStream per la gestione di tali file. Esistono tuttavia modi più semplici per usare le API descritte in precedenza per la gestione dei file di carattere non elaborati. È possibile evitare la necessità di un'implementazione del flusso personalizzata usando percorsi di codice separati per i file di carattere compressi rispetto ai file di carattere non elaborati.
Dopo la creazione di un oggetto caricatore di file di tipi di carattere personalizzato, i dati del file di carattere compressi vengono aggiunti al caricatore in base a mezzi specifici dell'app. Il caricatore può gestire più file di carattere, ognuno dei quali viene identificato usando una chiave definita dall'app opaca per DirectWrite. Dopo l'aggiunta di un file di carattere compresso al caricatore, viene utilizzato il metodo IDWriteFactory::CreateCustomFontFileReference per ottenere un IDWriteFontFile basato su tale caricatore per i dati del tipo di carattere identificati da una determinata chiave.
La decompressione effettiva dei dati del tipo di carattere può essere eseguita quando i tipi di carattere vengono aggiunti al caricatore, ma possono essere gestiti anche nel metodo IDWriteFontFileLoader::CreateStreamFromKey, che DirectWrite chiamerà quando deve prima leggere i dati del tipo di carattere.
Dopo aver creato un oggetto IDWriteFontFile, i passaggi rimanenti per l'aggiunta dei tipi di carattere a un set di tipi di carattere personalizzato saranno descritti in precedenza.
Un'implementazione che usa questo approccio è illustrata nell'esempio DirectWrite set di caratteri personalizzati.
Uso di DirectWrite meccanismi dei tipi di carattere remoti con implementazione di rete personalizzata di basso livello
I meccanismi di DirectWrite per la gestione dei tipi di carattere remoti possono essere suddivisi in meccanismi di livello superiore, con set di tipi di carattere che includono riferimenti ai tipi di carattere per tipi di carattere remoti, verificando la località dei dati del tipo di carattere e gestendo la coda per le richieste di download dei tipi di carattere e i meccanismi di livello inferiore che gestiscono il download effettivo. Alcune app potrebbero voler usare i meccanismi dei tipi di carattere remoti di livello superiore, ma richiedono anche interazioni di rete personalizzate, ad esempio la comunicazione con i server che usano protocolli diversi da HTTP.
Per questa situazione, un'app dovrà creare un'implementazione personalizzata dell'interfaccia IDWriteRemoteFontFileLoader che interagisce con altre interfacce di livello inferiore nei modi necessari. L'app dovrà inoltre fornire implementazioni personalizzate di queste interfacce di livello inferiore: IDWriteRemoteFontFileStream e IDWriteAsyncResult. Queste tre interfacce hanno metodi di callback che DirectWrite chiameranno durante le operazioni di download.
Quando IDWriteFontDownloadQueue::BeginDownload viene chiamato, DirectWrite eseguirà query sul caricatore del file di carattere remoto sulla località dei dati e richiederà il flusso remoto. Se i dati non sono locali, chiamerà il metodo BeginDownload del flusso. L'implementazione del flusso non deve essere bloccata in tale chiamata, ma deve restituire immediatamente un oggetto IDWriteAsyncResult che fornisce l'handle di attesa DirectWrite userà per attendere l'operazione di download asincrona. L'implementazione del flusso personalizzato è responsabile della gestione della comunicazione remota. Quando si è verificato l'evento di completamento, DirectWrite chiamerà IDWriteAsyncResult::GetResult per determinare il risultato dell'operazione. Se il risultato ha esito positivo, si prevede che le chiamate di ReadFragment successive al flusso per gli intervalli scaricati abbiano esito positivo.
Importante
Nota sulla sicurezza/prestazioni: quando viene effettuato un tentativo di recupero di un carattere remoto, il potenziale esiste in generale per un utente malintenzionato per spoofare il server previsto chiamato o che il server potrebbe non rispondere. Se si implementano interazioni di rete personalizzate, è possibile avere un maggiore controllo sulle mitigazioni rispetto a quando si gestiscono server di terze parti. Tuttavia, è consigliabile considerare le mitigazioni appropriate per evitare la divulgazione di informazioni o la negazione del servizio. Sono consigliati protocolli sicuri, ad esempio HTTPS. Inoltre, è necessario compilare in un timeout in modo che l'handle dell'evento restituito a DirectWrite venga impostato.
Scenari di supporto nelle versioni precedenti di Windows
Gli scenari descritti possono essere supportati in DirectWrite nelle versioni precedenti di Windows, ma richiederebbero un'implementazione molto più personalizzata nella parte dell'app usando le API più limitate disponibili prima di Windows 10. Per altre informazioni, vedere Raccolte di caratteri personalizzate (Windows 7/8).