Renderização de texto com Direct2D e DirectWrite
Ao contrário de outras APIs, como GDI, GDI+ ou WPF, Direct2D interopera com outra API, DirectWrite, para manipular e renderizar texto. Este tópico descreve os benefícios e a interoperação desses componentes separados.
Este tópico contém as seguintes seções.
- Direct2D possibilita a adoção incremental
- Serviços de Texto versus Renderização de Texto
- Glifos versus Texto
-
DirectWrite e Direct2D
- DrawText
- DrawTextLayout
- DrawGlyphRun
- Renderização de glifos
- Conclusão
O Direct2D permite a adoção incremental
Mover um aplicativo de uma API gráfica para outra pode ser difícil ou não ser o que você deseja por vários motivos. Isso pode ser porque você tem que suportar plug-ins que ainda usam as interfaces mais antigas, porque o aplicativo em si é muito grande para portar para uma nova API em uma versão ou porque alguma parte da API mais recente é desejável, mas a API mais antiga está funcionando bem o suficiente para outras partes do aplicativo.
Como Direct2D e DirectWrite são implementados como componentes separados, você pode atualizar todo o seu sistema gráfico 2D ou apenas a parte de texto dele. Por exemplo, você pode atualizar um aplicativo para usar DirectWrite para texto, mas ainda usar GDI ou GDI+ para renderização.
Serviços de texto versus renderização de texto
À medida que as aplicações evoluíram, os seus requisitos de processamento de texto tornaram-se cada vez mais complexos. No início, o texto era geralmente limitado à interface do usuário estaticamente definida, e o texto era renderizado em uma caixa bem definida, como um botão. À medida que as aplicações começaram a estar disponíveis num número crescente de línguas, esta abordagem tornou-se mais difícil de sustentar porque tanto a largura como a altura do texto traduzido podem variar significativamente entre línguas. Para se adaptar, os aplicativos começaram a dispor dinamicamente sua interface do usuário para depender do tamanho real renderizado do texto, em vez do contrário.
Para ajudar os aplicativos a concluir essa tarefa, DirectWrite fornece a interfaceIDWriteTextLayout. Essa API permite que um aplicativo especifique um pedaço de texto com características complexas, como diferentes fontes e tamanhos de fonte, sublinhados, tachados, texto bidirecional, efeitos, reticências e até mesmo caracteres não glifos incorporados (como um emoticon bitmap ou um ícone). O aplicativo pode então alterar várias características do texto à medida que determina iterativamente seu layout de interface do usuário. O DirectWrite Hello World Sample, que é mostrado na ilustração a seguir e no tópico Tutorial: Introdução ao DirectWrite, mostra muitos desses efeitos.
O layout pode posicionar os glifos idealmente com base em suas larguras (como o WPF faz), ou pode ajustar os glifos às posições de pixel mais próximas (como GDI faz).
Além de obter medidas de texto, a aplicação pode realizar testes de interseção em várias partes do texto. Por exemplo, ele pode querer saber que um hiperlink no texto foi clicado. (Para obter mais informações sobre testes de colisão, consulte o tópico Como executar testes de colisão em um layout de texto.)
A interface de layout de texto é dissociada da API de renderização que o aplicativo usa, como mostra o diagrama a seguir:
Essa separação é possível porque o DirectWrite fornece uma interface de renderização (IDWriteTextRenderer) que os aplicativos podem implementar para renderizar texto usando qualquer API gráfica desejada. A aplicação implementada IDWriteTextRenderer::DrawGlyphRun função de retorno de chamada é chamada por DirectWrite ao renderizar um layout de texto. É da responsabilidade deste método realizar as operações de desenho ou transmiti-las.
Para glifos de desenho, Direct2D fornece ID2D1RenderTarget::D rawGlyphRun para desenhar em uma superfície Direct2D e DirectWrite fornece IDWriteBitmapRenderTarget::D rawGlyphRun para desenhar em uma superfície GDI que pode ser transferida para uma janela usando GDI. Convenientemente, DrawGlyphRun em Direct2D e DirectWrite têm parâmetros exatamente compatíveis com o métodoDrawGlyphRun que o aplicativo implementa em IDWriteTextRenderer.
Seguindo uma separação semelhante, recursos específicos de texto (como enumeração e gerenciamento de fontes, análise de glifos e assim por diante) são manipulados por DirectWrite em vez de Direct2D. Os objetos DirectWrite são aceitos diretamente pelo Direct2D. Para ajudar os aplicativos GDI existentes a tirar proveito do DirectWrite, fornece a interface do método IDWriteGdiInterop com métodos para fazer o seguinte:
- Crie um DirectWrite Font a partir de uma GDI Logical Font (CreateFontFromLOGFONT).
- Converter de um DirectWrite Font Face para um GDI Logical Font (ConvertFontFaceToLOGFONT).
- Recupere o DirectWrite Font Face daquele que está selecionado num HDC. (CreateFontFaceFromHdc)
- Crie um DirectWritecomo destino de renderização de bitmap na memória do sistema (CreateBitmapRenderTarget).
Glifos versus Texto
O texto é um conjunto de pontos de código Unicode (caracteres), com vários modificadores estilísticos (fontes, pesos, sublinhados, tachados e assim por diante) que é disposto num rectângulo. Um glifo, em contraste, é um índice particular em um determinado arquivo de fonte. Um glifo define um conjunto de curvas que podem ser renderizadas, mas não tem qualquer significado textual. Há potencialmente um mapeamento muitos-para-muitos entre glifos e caracteres. Uma sequência de glifos que vêm do mesmo Font Face e que são colocados sequencialmente em uma linha de base é chamada de GlyphRun. Tanto DirectWrite quanto Direct2D chamam sua API de renderização de glifo mais precisa DrawGlyphRun e têm assinaturas muito semelhantes. O seguinte é de ID2D1RenderTarget no Direct2D:
STDMETHOD_(void, DrawGlyphRun)(
D2D1_POINT_2F baselineOrigin,
__in CONST DWRITE_GLYPH_RUN *glyphRun,
__in ID2D1Brush *foregroundBrush,
DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL
) PURE;
E esse método é de IDWriteBitmapRenderTarget em DirectWrite:
STDMETHOD(DrawGlyphRun)(
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
IDWriteRenderingParams* renderingParams,
COLORREF textColor,
__out_opt RECT* blackBoxRect = NULL
) PURE;
A versão DirectWrite mantém a origem da linha de base, o modo de medição e os parâmetros de execução do glifo e inclui parâmetros adicionais.
DirectWrite também permite que você use um renderizador personalizado para glifos implementando o IDWriteTextRenderer interface. Essa interface também tem um DrawGlyphRun método, como mostra o exemplo de código a seguir.
STDMETHOD(DrawGlyphRun)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
__maybenull IUnknown* clientDrawingEffect
) PURE;
Esta versão inclui mais parâmetros que são úteis quando você implementa um renderizador de texto personalizado . O parâmetro final é usado para efeitos de desenho personalizados implementados pelo aplicativo. (Para obter mais informações sobre efeitos de desenho de cliente, consulte Como adicionar efeitos de desenho de cliente a um layout de texto.
Cada execução de glifos começa numa origem e é posicionada numa linha desde essa origem. Os glifos são alterados pela transformação do mundo atual e pelas configurações de renderização de texto selecionadas no destino de renderização associado. Essa API geralmente é chamada diretamente apenas por aplicativos que fazem seu próprio layout (por exemplo, um processador de texto) ou por um aplicativo que implementou o IDWriteTextRenderer interface.
DirectWrite e Direct2D
Direct2D fornece serviços de renderização em nível de glifo por meio DrawGlyphRun. No entanto, isso requer que o aplicativo implemente os detalhes da renderização, que basicamente reproduz a funcionalidade do DrawText API do GDI por conta própria.
Portanto, Direct2D fornece APIs que aceitam texto em vez de glifos: ID2D1RenderTarget::DrawTextLayout e ID2D1RenderTarget::DrawText. Ambos os métodos são renderizados em uma superfície Direct2D. Para renderizar numa superfície GDI, é fornecido o método IDWriteBitmapRenderTarget::DrawGlyphRun. Mas esse método requer um renderizador de texto personalizado para ser implementado pelo aplicativo. (Para obter mais informações, consulte o tópico Renderizar para uma Superfície GDI.)
O uso de texto por um aplicativo normalmente começa simples: coloque OK ou Cancelar em um botão de layout fixo, por exemplo. No entanto, com o tempo, torna-se mais complexo à medida que a internacionalização e outras características são adicionadas. Eventualmente, muitos aplicativos terão que usar objetos de layout de texto do DirectWrite e implementar o renderizador de texto.
Portanto, Direct2D fornece APIs em camadas que permitem que uma aplicação comece de forma simples e se torne mais sofisticada sem ter que reverter ou abandonar o seu código em funcionamento. Uma exibição simplificada é mostrada no diagrama a seguir:
DrawText
DrawText é a mais simples das APIs para usar. Ele usa uma cadeia de caracteres Unicode, um pincel de primeiro plano, um objeto de formato único e um retângulo de destino. Ele disporá e exibirá todo o texto dentro do retângulo de layout e, opcionalmente, cortará esse texto. Isso é útil quando você coloca um pedaço simples de texto em uma parte da interface do usuário de layout fixo.
DrawTextLayout
Ao criar um objeto IDWriteTextLayout, uma aplicação pode começar a medir e organizar o texto e outros elementos da interface, além de oferecer suporte a várias fontes, estilos, sublinhados e tachados. Direct2D fornece a API DrawTextLayout que aceita diretamente este objeto e renderiza o texto num ponto determinado. (A largura e a altura são fornecidas pelo objeto de layout). Além de implementar todos os recursos de layout de texto esperados, o Direct2D interpretará qualquer objeto de efeito como um pincel e aplicará esse pincel ao intervalo selecionado de glifos. Ele também chamará quaisquer objetos embutidos. Um aplicativo pode então inserir caracteres não glifos (ícones) no texto, se desejar. Outra vantagem de usar um objeto de layout de texto é que as posições do glifo são armazenadas em cache nele. Portanto, um grande ganho de desempenho é possível reutilizando o mesmo objeto de layout para várias chamadas de desenho e evitando recalcular as posições do glifo para cada chamada. Esta funcionalidade não está presente para o DrawText da GDI.
DrawGlyphRun
Finalmente, a aplicação pode implementar a interface IDWriteTextRenderer ela própria e chamar DrawGlyphRun e FillRectangle eles próprios, ou qualquer outra API de renderização. Toda a interação existente com o objeto Text Layout permanecerá inalterada.
Para obter um exemplo de como implementar um renderizador de texto personalizado, consulte o tópico renderizar usando um renderizador de texto personalizado.
Renderização de glifos
Adicionar DirectWrite a um aplicativo GDI existente permite que o aplicativo use a IDWriteBitmapRenderTarget API para renderizar glifos. O IDWriteBitmapRenderTarget::D rawGlyphRun método que o DirectWrite fornece renderizará em cores sólidas para um DC de memória sem exigir APIs adicionais, como Direct2D.
Isso permite que o aplicativo obtenha recursos avançados de renderização de texto, como os seguintes:
- Sub-pixel ClearType permite que um aplicativo coloque glifos em posições de subpixels para permitir a renderização nítida do glifo e o layout do glifo.
- A antialiasing na direção Y permite uma renderização de curvas mais suave em glifos maiores.
Um aplicativo que se move para Direct2D também obterá os seguintes recursos:
- Aceleração de hardware.
- A capacidade de preencher texto com um pincel Direct2D arbitrário, como gradientes radiais, gradientes lineares e bitmaps.
- Mais suporte para camadas e recortes através do PushAxisAlignedClip, PushLayer e APIs de CreateCompatibleRenderTarget.
- A capacidade de suportar a renderização de texto a preto e branco. Isso preenche corretamente o canal alfa de destino de acordo com a opacidade do pincel de texto e o antialiasing do texto.
Para suportar eficientemente a aceleração de hardware, Direct2D usa uma aproximação ligeiramente diferente para a correção Gamma chamada correção alfa . Isso não requer que o Direct2D inspecione o pixel de cor de destino de renderização ao renderizar texto.
Conclusão
Este tópico explica as diferenças e semelhanças entre Direct2D e DirectWrite e as motivações arquitetônicas para fornecê-las como APIs cooperativas separadas.