Compartir a través de


Conjuntos de fuentes personalizadas

En este tema se describen varias maneras de usar fuentes personalizadas en la aplicación.

Introducción

La mayoría de las veces, las aplicaciones usan las fuentes instaladas localmente en el sistema. DirectWrite proporciona acceso a estas fuentes mediante los métodos IDWriteFactory3::GetSystemFontSet o IDWriteFactory::GetSystemFontCollection. En algunos casos, es posible que las aplicaciones también quieran usar fuentes que se incluyen como parte de Windows 10, pero que no están instaladas actualmente en el sistema actual. Se puede acceder a estas fuentes desde el servicio de fuentes de Windows mediante el método GetSystemFontSet o llamando a IDWriteFactory3::GetSystemFontCollection con includeDownloadableFonts establecido en TRUE. 

Sin embargo, en algunos escenarios de aplicación, las aplicaciones deben usar fuentes que no están instaladas en el sistema y no las proporciona el servicio de fuentes de Windows. Estos son ejemplos de estos escenarios:

  • Las fuentes se incrustan como recursos dentro de un archivo binario de la aplicación.
  • Los archivos de fuente se agrupan dentro de un paquete de aplicación y se almacenan en el disco en la carpeta de instalación de la aplicación.
  • La aplicación es una herramienta de desarrollo de fuentes que necesita cargar archivos de fuente especificados por el usuario. 
  • Las fuentes se incrustan en archivos de documento que se pueden ver o editar en la aplicación. 
  • La aplicación usa fuentes obtenidas de un servicio de fuentes web público. 
  • La aplicación usa los datos de fuente transmitidos a través de un protocolo de red privada. 

DirectWrite proporciona API para trabajar con fuentes personalizadas en estos y otros escenarios similares. Los datos de fuente personalizados pueden provenir de archivos en el sistema de archivos local; desde orígenes remotos basados en la nube a los que se accede mediante HTTP; o desde orígenes arbitrarios después de haberse cargado en un búfer de memoria. 

Nota:

Aunque DirectWrite ha proporcionado API para trabajar con fuentes personalizadas desde Windows 7, las API más recientes se agregaron en Windows 10 y de nuevo en Windows 10 Creators Update (compilación preliminar 15021 o posterior) que facilitan la implementación de varios de los escenarios mencionados. Este tema se centra en las API disponibles en La ventana 10. Para las aplicaciones que necesitan trabajar en versiones anteriores de Windows, consulte Colecciones de fuentes personalizadas (Windows 7/8). 

 

Resumen de API

Este tema se centra en la funcionalidad proporcionada por las siguientes API:

 

Conceptos clave

Para comprender las API de DirectWrite para trabajar con fuentes personalizadas, puede resultar útil comprender el modelo conceptual que subyace a estas API. Aquí se describen los conceptos clave. 

Cuando DirectWrite realiza la representación o el diseño de texto real, debe acceder a los datos de fuente reales. Un objeto de cara de fuente contiene datos de fuente reales, que deben existir en el sistema local. Pero para otras operaciones, como comprobar la disponibilidad de una fuente determinada o presentar opciones de fuente a un usuario, todo lo que se necesita es una referencia a una fuente determinada, no a los datos de fuente reales. En DirectWrite, un objeto de referencia facial de fuente contiene solo la información necesaria para buscar y crear instancias de una fuente. Dado que la referencia de la cara de fuente no contiene datos reales, DirectWrite puede tratar con referencias de caras de fuente para las que los datos reales están en una ubicación de red remota, así como cuando los datos reales son locales.

Un conjunto de fuentes es un conjunto de referencias faciales de fuente, junto con ciertas propiedades básicas e informativas que se pueden usar en hacer referencia a la fuente o compararla con otras fuentes, como el nombre de familia o un valor de peso de fuente. Los datos reales de las distintas fuentes pueden ser locales, o bien todos pueden ser remotos o alguna mezcla.

Se puede usar un conjunto de fuentes para obtener un objeto de colección de fuentes correspondiente. Consulte Conjuntos de fuentes y colecciones de fuentes a continuación para obtener más detalles. 

La interfaz IDWriteFontSet proporciona métodos que permiten consultar valores de propiedad, como el nombre de familia o el peso de fuente, o para las referencias de caras de fuente que coinciden con valores de propiedad determinados. Después de filtrar por una selección determinada, se puede obtener una instancia de la interfaz IDWriteFontFaceReference , con métodos para descargar (si los datos de fuente reales están actualmente remotos), para obtener el objeto IDWriteFontFace3 correspondiente que se puede usar para el diseño y la representación. 

La interfaz IDWriteFontFile subyace a cada cara de fuente o referencia de cara de fuente. Esto representa la ubicación de un archivo de fuente y tiene dos componentes: un cargador de archivos de fuente y una clave de archivo de fuente. El cargador de archivos de fuente (IDWriteFontFileLoader) se usa para abrir un archivo si es necesario y devuelve una secuencia con los datos (IDWriteFontFileStream). Dependiendo del cargador, los datos pueden encontrarse en una ruta de acceso de archivo local, una dirección URL remota o en un búfer de memoria. La clave es un valor definido por el cargador que identifica de forma única el archivo dentro del contexto del cargador, lo que permite al cargador localizar los datos y crear una secuencia para él. 

Las fuentes personalizadas se pueden agregar fácilmente a un conjunto de fuentes personalizado, que a su vez se puede usar para filtrar o organizar la información de fuente con fines como la creación de una interfaz de usuario del selector de fuentes. El conjunto de fuentes también se puede usar para crear una colección de fuentes para su uso en API de nivel superior, como IDWriteTextFormat e IDWriteTextLayout. La interfaz IDWriteFontSetBuilder se puede usar para crear un conjunto de fuentes personalizado que incluya varias fuentes personalizadas. También se puede usar para crear un conjunto de fuentes personalizado que mezcla fuentes personalizadas y fuentes proporcionadas por el sistema; o que mezcla fuentes con orígenes diferentes para los datos reales: almacenamiento local, direcciones URL remotas y memoria. 

Como se mencionó, una referencia de cara de fuente puede hacer referencia a datos de fuente en un origen remoto, pero los datos deben ser locales para obtener un objeto de cara de fuente que se puede usar para el diseño y la representación. La descarga de datos remotos se controla mediante una cola de descarga de fuentes. Las aplicaciones pueden usar la interfaz IDWriteFontDownloadQueue para poner en cola las solicitudes para descargar fuentes remotas para iniciar el proceso de descarga y para registrar un objeto IDWriteFontDownloadListener para tomar medidas cuando se haya completado el proceso de descarga. 

Para la mayoría de las interfaces descritas aquí, DirectWrite proporciona implementaciones del sistema. La única excepción es la interfaz IDWriteFontDownloadListener , que una aplicación implementa para realizar acciones específicas de la aplicación cuando se han descargado fuentes remotas localmente. Las aplicaciones pueden tener motivos para proporcionar sus propias implementaciones personalizadas para determinadas interfaces, aunque eso solo sería necesario en escenarios específicos y más avanzados. Por ejemplo, una aplicación tendría que proporcionar una implementación personalizada de la interfaz IDWriteFontFileLoader para controlar los archivos de fuente en el almacenamiento local que usan el formato de contenedor WOFF2. A continuación se proporcionan detalles adicionales. 

Fuentes y formatos de archivo de fuente

Otro concepto clave que resulta útil para entender es la relación entre caras de fuente individuales y archivos de fuente que los contienen. La idea de un archivo de fuente OpenType (.ttf o .otf) que contiene una sola fuente es familiar. Pero el formato de fuente OpenType también permite una colección de fuentes OpenType (.ttc o .otc), que es un único archivo que contiene varias fuentes. Los archivos openType Collection a menudo se usan para fuentes grandes que están estrechamente relacionadas y tienen valores idénticos para determinados datos de fuente: al combinar las fuentes en un único archivo, los datos comunes se pueden desduplicar. Por este motivo, una referencia de cara a fuente o cara de fuente debe hacer referencia no solo a un archivo de fuente (o a un origen de datos equivalente), sino que también debe especificar un índice de fuente dentro de ese archivo, para el caso general en el que el archivo puede ser un archivo de colección. 

Para las fuentes usadas en la Web, los datos de fuente a menudo se empaquetan en determinados formatos de contenedor, WOFF o WOFF2, que proporcionan cierta compresión de los datos de fuente y algún nivel de protección contra la piratería y la infracción de las licencias de fuentes. Funcionalmente, un archivo WOFF o WOFF2 es equivalente a una fuente OpenType o un archivo de colección de fuentes, pero los datos se codifican en un formato diferente que requiere desempaquetar antes de poder usarse. 

Algunas API de DirectWrite pueden tratar caras de fuente individuales, mientras que otras API pueden controlar archivos que podrían incluir archivos de colección OpenType que contienen varias caras. De forma similar, algunas API solo tratan con datos sin procesar y con formato OpenType, mientras que otras API pueden controlar los formatos de contenedor empaquetados, WOFF y WOFF2. Estos detalles se proporcionan en la explicación siguiente. 

Conjuntos de fuentes y colecciones de fuentes

Es posible que algunas aplicaciones se implementen para trabajar con fuentes mediante la interfaz IDWriteFontCollection . Hay una correspondencia directa entre una colección de fuentes y un conjunto de fuentes. Cada uno puede contener las mismas fuentes, pero las presentan con una organización diferente. Desde cualquier colección de fuentes, se puede obtener un conjunto de fuentes correspondiente y viceversa.

Al trabajar con varias fuentes personalizadas, es más fácil usar una interfaz del generador de conjuntos de fuentes para crear un conjunto de fuentes personalizado y, a continuación, obtener una colección de fuentes después de crear el conjunto de fuentes. El proceso para crear un conjunto de fuentes personalizado se describirá en detalle a continuación. Para obtener una interfaz IDWriteFontCollection1 de un conjunto de fuentes, se usa el método IDWriteFactory3::CreateFontCollectionFromFontSet .

Si la aplicación tiene un objeto de colección y necesita obtener un conjunto de fuentes correspondiente, esto se puede hacer mediante el método IDWriteFontCollection1::GetFontSet

Escenarios frecuentes

En esta sección se describen algunos de los escenarios más comunes que implican conjuntos de fuentes personalizados:

  • Crear un conjunto de fuentes personalizado mediante fuentes arbitrarias en rutas de acceso en el sistema de archivos local.
  • Crear un conjunto de fuentes personalizado mediante fuentes conocidas (quizás agrupadas con la aplicación) almacenadas en el sistema de archivos local.
  • Crear un conjunto de fuentes personalizado mediante fuentes remotas conocidas en la Web.
  • Crear un conjunto de fuentes personalizado mediante los datos de fuente cargados en la memoria.

Las implementaciones completas de estos escenarios se proporcionan en el ejemplo DirectWrite conjuntos de fuentes personalizados. En este ejemplo también se muestra un escenario más avanzado para controlar los datos de fuente empaquetados en formatos de contenedor WOFF o WOFF2, que se analizarán a continuación. 

Creación de un conjunto de fuentes mediante fuentes arbitrarias en el sistema de archivos local

Al tratar con un conjunto arbitrario de archivos de fuente en el almacenamiento local, el método IDWriteFontSetBuilder1::AddFontFile es conveniente, ya que, en una sola llamada, puede controlar todas las caras de fuente dentro de un archivo de colección de fuentes OpenType, así como todas las instancias de una fuente de variable OpenType. Esto está disponible en Windows 10 Creators Update (compilación preliminar 15021 o posterior) y se recomienda siempre que esté disponible. 

Para usar este método, use el siguiente proceso.

1. Comience creando la interfaz IDWriteFactory5 :
IDWriteFactory5* pDWriteFactory; 
HRESULT hr = DWriteCreateFactory( 
  DWRITE_FACTORY_TYPE_SHARED, 
  __uuidof(IDWriteFactory5), 
  reinterpret_cast<IUnknown**>(&pDWriteFactory) 
); 

 
2. Use la fábrica para obtener la interfaz IDWriteFontSetBuilder1:

IDWriteFontSetBuilder1* pFontSetBuilder; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder); 
}  
                
  1. Para cada archivo de fuente del sistema de archivos local, cree un IDWriteFontFile que haga referencia a él:
IDWriteFontFile* pFontFile; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile); 
} 

 
4. Agregue el objeto IDWriteFontFile al generador de conjuntos de fuentes mediante el método AddFontFile :

hr = pFontSetBuilder->AddFontFile(pFontFile); 

Si la ruta de acceso del archivo especificada en la llamada a CreateFontFileReference hace referencia a algo distinto de un archivo OpenType compatible, la llamada a AddFontFile devolverá un error, DWRITE_E_FILEFORMAT.

  1. Una vez agregados todos los archivos al generador del conjunto de fuentes, se puede crear el conjunto de fuentes personalizado:
IDWriteFontSet* pFontSet; 
hr = pFontSetBuilder->CreateFontSet(&pFontSet); 

 

Si la aplicación debe ejecutarse en versiones de Windows 10 anteriores a Windows 10 Creators Update, el método AddFontFile no estará disponible. La disponibilidad se puede detectar mediante la creación de una interfaz IDWriteFactory3 y, a continuación, usar QueryInterface para intentar obtener una interfaz IDWriteFactory5 : si se ejecuta correctamente, también estará disponible la interfaz IDWriteFontSetBuilder1 y el método AddFontFile .

Si el método AddFontFile no está disponible, se debe usar el método IDWriteFontSetBuilder::AddFontFaceReference para agregar caras de fuente individuales. Para permitir archivos openType Font Collection que contienen varias caras, el método IDWriteFontFile::Analyze se puede usar para determinar el número de caras contenidas en el archivo. El proceso es el siguiente.

1. Comience creando la interfaz IDWriteFactory3 :
IDWriteFactory3* pDWriteFactory; 
HRESULT hr = DWriteCreateFactory( 
DWRITE_FACTORY_TYPE_SHARED, 
  __uuidof(IDWriteFactory5), 
  reinterpret_cast<IUnknown**>(&pDWriteFactory) 
); 
  1. Use el generador para obtener la interfaz IDWriteFontSetBuilder :
IDWriteFontSetBuilder* pFontSetBuilder; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder); 
} 
  1. Para cada archivo de fuente, cree un IDWriteFontFile, como se indica anteriormente:
IDWriteFontFile* pFontFile; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile); 
} 

En lugar de agregar el archivo directamente al generador de conjuntos de fuentes, es necesario determinar el número de caras y crear objetos IDWriteFontFaceReference individuales. 
4. Utilice el método Analyze para obtener el número de caras en el archivo. 

BOOL isSupported; 
DWRITE_FONT_FILE_TYPE fileType; 
UINT32 numberOfFonts; 
hr = pFontFile->Analyze(&isSupported, &fileType, /* face type */ nullptr, &numberOfFonts); 

El método Analyze también establecerá valores para los parámetros isSupported y fileType. Si el archivo no es un formato compatible, isSupported será FALSE y se puede realizar una acción adecuada, como omitir el archivo. 
5. Recorra el número de fuentes establecidas en el parámetro numberOfFonts. Dentro del bucle, cree un IDWriteFontFaceReference para cada par de archivo/índice y agréguelo al generador del conjunto de fuentes. 

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);
  }
} 
  1. Una vez agregadas todas las caras al generador de conjuntos de fuentes, cree el conjunto de fuentes personalizado, como se muestra anteriormente.

Se puede diseñar una aplicación para que use el método AddFontFile preferido cuando se ejecute en Windows 10 Creators Update, pero recurra al método AddFontFaceReference cuando se ejecute en versiones anteriores de Windows 10. Pruebe la disponibilidad de la interfaz IDWriteFactory5 , como se describió anteriormente y, a continuación, bifurque en consecuencia. Este enfoque se muestra en el ejemplo DirectWrite conjuntos de fuentes personalizados

Creación de un conjunto de fuentes mediante fuentes conocidas en el sistema de archivos local

Como se mencionó anteriormente, cada referencia de cara de fuente en un conjunto de fuentes está asociada a determinadas propiedades informativas, como el nombre de familia y el peso de la fuente. Cuando se agregan fuentes personalizadas a un generador de conjuntos de fuentes mediante las llamadas API enumeradas anteriormente, estas propiedades informativas se obtienen directamente de los datos de fuente reales, que se leen cuando se agrega la fuente. Sin embargo, en algunas situaciones, si una aplicación tiene otro origen de información sobre una fuente, es posible que desee proporcionar sus propios valores personalizados para estas propiedades. 

Como ejemplo de cómo podría resultar útil, supongamos que una aplicación agrupa algunas fuentes que se usan para presentar elementos de interfaz de usuario concretos dentro de la aplicación. En ocasiones, como con una nueva versión de la aplicación, es posible que deba cambiar las fuentes específicas que usa la aplicación para estos elementos. Si la aplicación tiene referencias codificadas a las fuentes específicas, la sustitución de una fuente por otra requerirá cambiar cada una de esas referencias. En su lugar, si la aplicación usa propiedades personalizadas para asignar alias funcionales en función del tipo de elemento o texto que se representa, asigna cada alias a una fuente específica en un solo lugar y, a continuación, usa los alias en todos los contextos donde se crean y manipulan las fuentes, reemplazar una fuente por otra requiere cambiar solo el lugar donde el alias se asigna a una fuente específica. 

Se pueden asignar valores personalizados para propiedades informativas cuando se llama al método IDWriteFontSetBuilder::AddFontFaceReference . El método para hacer esto es el siguiente; se puede usar en cualquier versión de Windows 10. 

Como se ha mostrado anteriormente, empiece por obtener las interfaces IDWriteFactory3 e IDWriteFontSet . Para que se agregue cada cara de fuente personalizada, cree un IDWriteFontFaceReference, como se muestra anteriormente. Antes de agregarlo al generador de conjuntos de fuentes (en el bucle del paso 5, mostrado anteriormente), la aplicación define los valores de propiedad personalizados que se van a usar. 

Un conjunto de valores de propiedad personalizados se define mediante una matriz de estructuras de DWRITE_FONT_PROPERTY . Cada uno de estos identifica una propiedad determinada de la enumeración DWRITE_FONT_PROPERTY_ID y el valor de propiedad correspondiente que se va a usar.  

Tenga en cuenta que todos los valores de propiedad se asignan como cadenas. Si posteriormente se muestran a los usuarios, se pueden establecer valores alternativos para una propiedad determinada para distintos idiomas, pero esto no es necesario. Tenga en cuenta también que, si la aplicación establece algún valor de propiedad personalizado, solo se usarán los valores especificados en el conjunto de fuentes; DirectWrite no derivará ningún valor directamente de la fuente para las propiedades informativas usadas en un conjunto de fuentes. 

En el ejemplo siguiente se definen valores personalizados para tres propiedades informativas: nombre de familia, nombre completo y peso de fuente. 

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 } 
}; 
               
            

Después de definir la matriz deseada de valores de propiedad para una fuente, realice una llamada a AddFontFaceRefence, pasando la matriz de propiedades, así como la referencia de la cara de fuente. 

hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference, props, ARRAYSIZE(props)); 

 

Una vez agregadas todas las caras de fuente personalizadas al generador del conjunto de fuentes, junto con sus propiedades personalizadas, cree el conjunto de fuentes personalizado, como se muestra anteriormente. 

Creación de un conjunto de fuentes personalizado mediante fuentes conocidas y remotas en la Web

Las propiedades personalizadas son importantes para trabajar con fuentes remotas. Cada referencia de cara de fuente debe tener algunas propiedades informativas para caracterizar la fuente y distinguirla de otras fuentes. Dado que los datos de fuente para fuentes remotas no son locales, DirectWrite no pueden derivar propiedades directamente de los datos de fuente. Por lo tanto, las propiedades se deben proporcionar explícitamente al agregar una fuente remota al generador de conjuntos de fuentes.

La secuencia de llamadas API para agregar fuentes remotas a un conjunto de fuentes es similar a la secuencia descrita para el escenario anterior. Sin embargo, dado que los datos de fuente son remotos, las operaciones implicadas para leer los datos de fuente reales serán diferentes de cuando trabajen con archivos en el almacenamiento local. Para esta situación, se ha agregado una nueva interfaz de nivel inferior, IDWriteRemoteFontFileLoader, en Windows 10 Creators Update. 

Para usar el cargador de archivos de fuente remoto, primero debe registrarse con un generador de DirectWrite. La aplicación deberá mantener el cargador siempre que se usen las fuentes asociadas a ella. Una vez que las fuentes ya no están en uso y, en algún momento, antes de destruir la fábrica, el cargador debe anular el registro. Esto se puede hacer en el destructor de la clase que posee el objeto del cargador. Estos pasos se mostrarán a continuación. 

El método para crear un conjunto de fuentes personalizado mediante fuentes remotas es el siguiente; esto requiere Windows 10 Creators Update.  

1. Cree una interfaz IDWriteFactory5, como se muestra anteriormente.  2. Cree una interfaz IDWriteFontSetBuilder , como se muestra anteriormente.  3. Use la fábrica para obtener un IDWriteRemoteFontFileLoader
IDWriteRemoteFontFileLoader* pRemoteFontFileLoader; 
if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->CreateHttpFontFileLoader( 
        /* referrerURL */ nullptr, 
        /* extraHeaders */ nullptr, 
        &pRemoteFontFileLoader 
    ); 
} 

Esto devuelve una implementación proporcionada por el sistema de la interfaz del cargador de archivos de fuente remota que puede controlar las interacciones HTTP para descargar datos de fuente en nombre de la aplicación. Se puede especificar una dirección URL de referencia o encabezados adicionales si es necesario por el servicio de fuentes o los servicios que son el origen de las fuentes.  

Importante

Nota de seguridad: cuando se intenta capturar una fuente remota, existe la posibilidad de que un atacante suplantar el servidor deseado al que se llamará. En ese caso, las direcciones URL de destino y el remitente y los detalles del encabezado se revelarían al atacante. Los desarrolladores de aplicaciones son responsables de mitigar este riesgo. Se recomienda el uso del protocolo HTTPS, en lugar de HTTP. 

 

Se puede usar un único cargador de archivos de fuente remoto para varias fuentes, aunque se pueden usar cargadores diferentes si las fuentes se obtienen de varios servicios que tienen requisitos diferentes para la dirección URL de referencia o encabezados adicionales. 
4. Registre el cargador de archivos de fuente remoto con la fábrica. 

 if (SUCCEEDED(hr)) 
 { 
     hr = pDWriteFactory->RegisterFontFileLoader(pRemoteFontFileLoader); 
 } 

Desde este punto, los pasos para crear el conjunto de fuentes personalizados son similares a los descritos para los archivos de fuente locales conocidos, con dos excepciones importantes. En primer lugar, el objeto IDWriteFontFile se crea mediante la interfaz del cargador de archivos de fuente remoto en lugar de usar el generador. En segundo lugar, no se puede usar el método Analyze porque los datos de fuente no son locales. En su lugar, la aplicación debe saber si el archivo de fuente remoto es un archivo openType Font Collection y, si es así, debe saber cuáles de las fuentes de la colección que usará y el índice de cada uno. Por lo tanto, los pasos restantes son los siguientes. 
5. Para cada archivo de fuente remoto, use la interfaz del cargador de archivos de fuente remota para crear un IDWriteFontFile, especificando la dirección URL necesaria para acceder al archivo de fuente. 

 IDWriteFontFile* pFontFile; 
 hr = pRemoteFontFileLoader->CreateFontFileReferenceFromUrl( 
     pDWriteFactory, 
     /* baseUrl */ L"https://github.com/", 
     /* fontFileUrl */ L"winjs/winjs/blob/master/src/fonts/Symbols.ttf?raw=true", 
     &pFontFile 
 ); 

Tenga en cuenta que la dirección URL completa se puede especificar en el parámetro fontFileUrl, o bien puede dividirse en partes base y relativas. Si se especifica una dirección URL base, la concatenación de los valores baseUrl y fontFileUrl debe proporcionar la dirección URL completa, DirectWrite no proporcionará ningún delimitador adicional.

Importante

Nota de seguridad y rendimiento: cuando se intenta capturar una fuente remota, no hay ninguna garantía de que Windows recibirá una respuesta del servidor. En algunos casos, un servidor puede responder con un error de archivo no encontrado para una dirección URL relativa no válida, pero dejar de responder si recibe varias solicitudes no válidas. Si el servidor no responde, Windows agotará el tiempo de espera, aunque esto puede tardar varios minutos si se inician varias capturas. Debe hacer lo que puede para asegurarse de que las direcciones URL serán válidas cuando se realicen llamadas. 

 

Tenga en cuenta también que la dirección URL puede apuntar a un archivo de fuente OpenType sin formato (.ttf, .otf, .ttc, .otc), pero también puede apuntar a fuentes en un archivo de contenedor WOFF o WOFF2. Si se hace referencia a un archivo WOFF o WOFF2, la implementación DirectWrite del cargador de archivos de fuente remoto desempaquetará automáticamente los datos de fuente del archivo de contenedor. 
6. Para cada índice de cara de fuente dentro del archivo de fuente remoto que se va a usar, cree un IDWriteFontFaceReference

 IDWriteFontFaceReference* pFontFaceReference; 
 hr = pDWriteFactory->CreateFontFaceReference(pFontFile, /* faceIndex */ 0, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);
  1. Defina propiedades personalizadas para la cara de fuente, como se muestra anteriormente. 
  2. Agregue la referencia de la cara de fuente junto con las propiedades personalizadas al generador de conjuntos de fuentes, como se muestra anteriormente. 
  3. Una vez agregadas todas las fuentes al generador del conjunto de fuentes, cree el conjunto de fuentes, como se muestra anteriormente. 
  4. En algún momento en el que ya no se usarán las fuentes remotas, anule el registro del cargador de archivos de fuente remoto. 
hr = pDWriteFactory->UnregisterFontFileLoader(pRemoteFontFileLoader); 

Una vez creado un conjunto de fuentes personalizado con fuentes remotas personalizadas, el conjunto de fuentes contiene referencias y propiedades informativas para las fuentes remotas, pero los datos reales siguen siendo remotos. DirectWrite compatibilidad con fuentes remotas permite mantener una referencia de cara de fuente en el conjunto de fuentes y para que se seleccione una fuente para su uso en el diseño y la representación, pero que los datos reales no se descarguen hasta que haya una necesidad real de usarlo, como cuando se realizará el diseño de texto.  

Una aplicación puede adoptar un enfoque inicial solicitando que DirectWrite descargue los datos de fuente y, a continuación, espere a que se confirme una descarga correcta antes de que se inicie cualquier procesamiento con la fuente. Pero una descarga de red implica cierta latencia de duración impredecible y el éxito también es incierta. Por este motivo, normalmente será mejor adoptar un enfoque diferente, lo que permite que el diseño y la representación se realicen inicialmente mediante fuentes alternativas o de reserva que ya son locales, mientras solicita la descarga de la fuente deseada, remota en paralelo y, a continuación, actualizando los resultados una vez descargada la fuente deseada. 

Para solicitar que se descargue toda la fuente antes de su uso, se puede usar el método IDWriteFontFaceReference::EnqueueFontDownloadRequest . Si la fuente es muy grande, solo se puede necesitar una parte de los datos para procesar cadenas concretas. DirectWrite proporciona métodos adicionales que se pueden usar para solicitar partes de los datos de fuente necesarios para contenido determinado, EnqueueCharacterDownloadRequest y EnqueueGlyphDownloadRequest.  

Supongamos que el enfoque que se debe adoptar en la aplicación es permitir que el procesamiento se realice inicialmente mediante fuentes locales, alternativas o de reserva. El método IDWriteFontFallback::MapCharacters se puede usar para identificar fuentes de reserva locales y también pondrá en cola automáticamente una solicitud para descargar la fuente preferida. Además, si se usa IDWriteTextLayout y se da formato a parte o todo el texto del diseño mediante una referencia de fuente remota, DirectWrite usará automáticamente el método MapCharacters para obtener fuentes de reserva locales y poner en cola una solicitud para descargar los datos de fuente remotos. 

DirectWrite mantiene una cola de descarga de fuentes para cada generador y las solicitudes realizadas mediante los métodos mencionados anteriormente se agregan a esa cola. La cola de descarga de fuentes se puede obtener mediante el método IDWriteFactory3::GetFontDownloadQueue

Si se realiza una solicitud de descarga, pero los datos de fuente ya son locales, esto dará como resultado una operación no operativa: No se agregará nada a la cola de descarga. Una aplicación puede comprobar si la cola está vacía o hay solicitudes de descarga pendientes llamando al método IDWriteFontDownloadQueue::IsEmpty

Una vez agregadas las solicitudes de fuente remotas a la cola, se debe iniciar el proceso de descarga. Cuando se usan fuentes remotas en IDWriteTextLayout, la descarga se iniciará automáticamente cuando la aplicación llame a los métodos IDWriteTextLayout que fuerzan el diseño o las operaciones de representación, como los métodos GetLineMetrics o Draw. En otros escenarios, la aplicación debe iniciar la descarga directamente llamando a IDWriteFontDownloadQueue::BeginDownload.  

Cuando se complete una descarga, dependerá de la aplicación realizar las acciones adecuadas, continuar con las operaciones pendientes o repetir las operaciones que se realizaron inicialmente con fuentes de reserva. (Si se usa el diseño de texto de DirectWrite, se puede usar IDWriteTextLayout3::InvalidateLayout para borrar los resultados temporales calculados mediante fuentes de reserva). Para que la aplicación se notifique cuando se haya completado el proceso de descarga y para realizar las acciones adecuadas, la aplicación debe proporcionar una implementación de la interfaz IDWriteFontDownloadListener y pasarla a la llamada BeginDownload. 

Importante

Nota de seguridad y rendimiento: cuando se intenta capturar una fuente remota, no hay ninguna garantía de que Windows recibirá una respuesta del servidor. Si el servidor no responde, Windows terminará agotando el tiempo de espera, aunque esto puede tardar varios minutos si se capturan varias fuentes remotas pero se producen errores. La llamada BeginDownload se devolverá inmediatamente. Las aplicaciones no deben bloquear la interfaz de usuario mientras se espera a que se llame a IDWriteFontDownloadListener::D ownloadCompleted

 

Las implementaciones de ejemplo de estas interacciones con la cola de descarga de fuentes de DirectWrite y de la interfaz IDWriteFontDownloadListener se pueden ver en el ejemplo de conjuntos de fuentes personalizados de DirectWrite y también en el ejemplo de fuentes descargables de DirectWrite

Creación de un conjunto de fuentes personalizado mediante datos de fuente cargados en memoria

Al igual que las operaciones de bajo nivel para leer datos de un archivo de fuente son diferentes para los archivos de un disco local frente a los archivos remotos en la Web, lo mismo sucede con los datos de fuente cargados en un búfer de memoria. Se ha agregado una nueva interfaz de bajo nivel para controlar los datos de fuente en memoria en Windows 10 Creators Update, IDWriteInMemoryFontFileLoader

Al igual que con un cargador de archivos de fuente remoto, primero se debe registrar un cargador de archivos de fuente en memoria con un generador de DirectWrite. La aplicación deberá mantener el cargador siempre que se usen las fuentes asociadas a ella. Una vez que las fuentes ya no están en uso y, en algún momento, antes de destruir la fábrica, el cargador debe anular el registro. Esto se puede hacer en el destructor de la clase que posee el objeto del cargador. Estos pasos se mostrarán a continuación. 

Si la aplicación tiene información independiente sobre las caras de fuente representadas por los datos, puede agregar referencias de caras de fuente individuales a un generador de conjuntos de fuentes con propiedades personalizadas especificadas. Sin embargo, dado que los datos de fuente están en memoria local, esto no es necesario; DirectWrite podrá leer los datos directamente para derivar los valores de propiedad. 

DirectWrite supone que los datos de fuente están en formato Raw, OpenType, equivalente a un archivo OpenType (.ttf, .otf, .ttc, .otc), pero en memoria en lugar de en disco. Los datos no pueden estar en un formato de contenedor WOFF o WOFF2. Los datos pueden representar una colección de fuentes OpenType. Si no se usan propiedades personalizadas, se puede usar el método IDWriteFontSetBuilder1::AddFontFile para agregar todas las caras de fuente de los datos en una sola llamada. 

Una consideración importante para el escenario en memoria es la duración de los datos. Si se proporciona un puntero al búfer para DirectWrite sin una indicación clara de que hay un propietario, DirectWrite realizará una copia de los datos en un nuevo búfer de memoria que poseerá. Para evitar la copia de datos y la asignación de memoria adicional, la aplicación puede pasar un objeto propietario de datos que implementa IUnknown y que posee el búfer de memoria que contiene los datos de fuente. Al implementar esta interfaz, DirectWrite puede agregar al recuento de referencias del objeto, lo que garantiza la duración de los datos propiedad. 

El método para crear un conjunto de fuentes personalizado mediante datos de fuente en memoria es el siguiente; esto requiere Windows 10 Creators Update. Esto supone un objeto propietario de datos implementado por la aplicación, que implementa IUnknown y también tiene métodos que devuelven un puntero al búfer de memoria y el tamaño del búfer. 

1. Cree una interfaz IDWriteFactory5, como se muestra anteriormente. 2. Cree una interfaz [**IDWriteFontSetBuilder1**](/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontsetbuilder1), como se muestra anteriormente. 3. Use la fábrica para obtener un IDWriteInMemoryFontFileLoader. 
 IDWriteInMemoryFontFileLoader* pInMemoryFontFileLoader; 
if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->CreateInMemoryFontFileLoader(&pInMemoryFontFileLoader); 
}

Esto devuelve una implementación proporcionada por el sistema de la interfaz del cargador de archivos de fuente en memoria. 
4. Registre el cargador de archivos de fuente en memoria con el generador. 

if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->RegisterFontFileLoader(pInMemoryFontFileLoader); 
}

 
5. Para cada archivo de fuente en memoria, use el cargador de archivos de fuente en memoria para crear 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. Agregue el objeto IDWriteFontFile al generador de conjuntos de fuentes mediante el método AddFontFile , como se muestra anteriormente.  Si es necesario, la aplicación puede crear en su lugar objetos IDWriteFontFaceReference individuales basados en IDWriteFontFile, definir opcionalmente propiedades personalizadas para cada referencia de cara de fuente y, a continuación, agregar la referencia de cara de fuente con propiedades personalizadas al conjunto de fuentes mediante el método AddFontFaceReference , como se muestra anteriormente. 
7. Una vez agregadas todas las fuentes al generador del conjunto de fuentes, cree el conjunto de fuentes personalizado, como se muestra anteriormente. 
8. En algún momento en el que ya no se usarán las fuentes en memoria, anule el registro del cargador de archivos de fuente en memoria. 

hr = pDWriteFactory->UnregisterFontFileLoader(pInMemoryFontFileLoader);

 

Escenarios avanzados

Algunas aplicaciones pueden tener requisitos especiales que requieren un procesamiento más avanzado que el descrito anteriormente. 

Combinación de conjuntos de fuentes

Es posible que algunas aplicaciones necesiten crear un conjunto de fuentes que consta de alguna combinación de elementos de otros conjuntos de fuentes. Por ejemplo, una aplicación puede querer crear un conjunto de fuentes que combine todas las fuentes instaladas en el sistema con una selección de fuentes personalizadas o que combine fuentes instaladas que coincidan con determinados criterios con otras fuentes. DirectWrite tiene API para admitir la manipulación y combinación de conjuntos de fuentes. 

Para combinar dos o más conjuntos de fuentes, el método IDWriteFontSetBuilder::AddFontSet agrega todas las fuentes de un conjunto de fuentes determinado que se agregarán a un generador de conjuntos de fuentes en una sola llamada. Si solo se quieren determinadas fuentes de un conjunto de fuentes existente en el nuevo conjunto de fuentes, el método IDWriteFontSet::GetMatchingFonts se puede usar para derivar un nuevo objeto de conjunto de fuentes que se ha filtrado para incluir solo las fuentes que coincidan con las propiedades especificadas. Estos métodos proporcionan una manera sencilla de crear un conjunto de fuentes personalizado que combina fuentes a partir de dos o más conjuntos de fuentes existentes.

Uso de datos de fuente WOFF o WOFF2 locales

Si una aplicación tiene archivos de fuente en el sistema de archivos local o en un búfer de memoria, pero usan los formatos de contenedor WOFF o WOFF2, DirectWrite (Windows 10 Creator Update o posterior) proporciona un método para desempaquetar el formato de contenedor, IDWriteFactory5::UnpackFontFile, que devuelve un IDWriteFontFileStream

Sin embargo, la aplicación necesitará una manera de obtener idWriteFontFileStream en un objeto de cargador de archivos de fuente. Una manera de hacerlo es crear una implementación idWriteFontFileLoader personalizada que encapsula la secuencia. Al igual que con otros cargadores de archivos de fuente, debe registrarse antes de su uso y anular el registro antes de que el generador salga del ámbito.  

Si el cargador personalizado también se usará con archivos de fuente sin procesar (no empaquetados), la aplicación también tendría que proporcionar una implementación personalizada de la interfaz IDWriteFontFileStream para controlar esos archivos. Sin embargo, hay maneras más sencillas de usar las API descritas anteriormente para controlar los archivos de fuente sin procesar. La necesidad de una implementación de flujo personalizada podría evitarse mediante rutas de acceso de código independientes para archivos de fuente empaquetados frente a archivos de fuente sin procesar. 

Después de crear un objeto de cargador de archivos de fuente personalizado, los datos del archivo de fuente empaquetado se agregan al cargador mediante medios específicos de la aplicación. El cargador puede controlar varios archivos de fuente, cada uno de los cuales se identifica mediante una clave definida por la aplicación que es opaca para DirectWrite. Después de agregar un archivo de fuente empaquetado al cargador, el método IDWriteFactory::CreateCustomFontFileReference se usa para obtener un IDWriteFontFile basado en ese cargador para los datos de fuente identificados por una clave determinada.  

El desempaquetado real de los datos de fuente se puede realizar a medida que se agregan fuentes al cargador, pero también se puede controlar en el método IDWriteFontFileLoader::CreateStreamFromKey, que DirectWrite llamará cuando primero necesite leer los datos de fuente. 

Una vez creado un objeto IDWriteFontFile, los pasos restantes para agregar las fuentes a un conjunto de fuentes personalizados serán como se describió anteriormente. 

Una implementación con este enfoque se muestra en el ejemplo de conjuntos de fuentes personalizados de DirectWrite

Uso de DirectWrite mecanismos de fuente remotos con implementación de red de bajo nivel personalizada

Los mecanismos de DirectWrite para controlar las fuentes remotas se pueden dividir en mecanismos de nivel superior, con conjuntos de fuentes que incluyen referencias de caras de fuente para fuentes remotas, comprobando la localidad de los datos de fuente y administrando la cola para las solicitudes de descarga de fuentes y los mecanismos de nivel inferior que controlan la descarga real. Es posible que algunas aplicaciones quieran usar los mecanismos de fuente remotos de nivel superior, pero también requieren interacciones de red personalizadas, como la comunicación con servidores que usan protocolos distintos de HTTP. 

En esta situación, una aplicación tendrá que crear una implementación personalizada de la interfaz IDWriteRemoteFontFileLoader que interactúe con otras interfaces de nivel inferior de las maneras necesarias. La aplicación también tendrá que proporcionar implementaciones personalizadas de estas interfaces de nivel inferior: IDWriteRemoteFontFileStream y IDWriteAsyncResult. Estas tres interfaces tienen métodos de devolución de llamada que DirectWrite llamarán durante las operaciones de descarga. 

Cuando se llama a IDWriteFontDownloadQueue::BeginDownload, DirectWrite realizará consultas al cargador de archivos de fuente remoto sobre la localidad de los datos y solicitará la secuencia remota. Si los datos no son locales, llamará al método BeginDownload de la secuencia. La implementación de la secuencia no debe bloquearse en esa llamada, pero debe devolver inmediatamente, pasando un objeto IDWriteAsyncResult que proporciona el identificador de espera DirectWrite usará para esperar en la operación de descarga asincrónica. La implementación de secuencia personalizada es responsable de controlar la comunicación remota. Cuando se haya producido el evento de finalización, DirectWrite llamará a IDWriteAsyncResult::GetResult para determinar el resultado de la operación. Si el resultado es correcto, se espera que las llamadas de ReadFragment posteriores a la secuencia para los intervalos descargados se realicen correctamente. 

Importante

Nota de seguridad y rendimiento: cuando se intenta capturar una fuente remota, existe el potencial en general para que un atacante suplantar el servidor deseado al que se llama o que el servidor no responda. Si va a implementar interacciones de red personalizadas, es posible que tenga un mayor control sobre las mitigaciones que cuando se trabaja con servidores de terceros. Sin embargo, es necesario tener en cuenta las mitigaciones adecuadas para evitar la divulgación de información o la denegación de servicio. Se recomiendan protocolos seguros como HTTPS. Además, debe compilar en algún tiempo de espera para que el identificador de eventos devuelto a DirectWrite finalmente se establezca. 

 

Escenarios auxiliares en versiones anteriores de Windows

Los escenarios descritos se pueden admitir en DirectWrite en versiones anteriores de Windows, pero requerirían una implementación mucho más personalizada en parte de la aplicación mediante las API más limitadas que estaban disponibles antes de Windows 10. Para obtener más información, vea Colecciones de fuentes personalizadas (Windows 7/8).