Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Макет DirectWriteтекста может быть нарисован пользовательским отрисовщиком текста, производным от IDWriteTextRenderer. Пользовательский отрисовщик необходим для использования некоторых расширенных функций DirectWrite, таких как отрисовка в растровом рисунке или поверхности GDI, встроенные объекты и клиентские эффекты рисования. В этом руководстве описаны методы IDWriteTextRenderer и приведен пример реализации, в котором Direct2D используется для отрисовки текста с растровой заливкой.
Это руководство содержит следующие части:
- Конструктор
- DrawGlyphRun()
- DrawUnderline() и DrawStrikethrough()
- Привязка пикселей, пикселей на DIP и преобразование
- DrawInlineObject()
- Деструктор
- Использование пользовательского отрисовщика текста
Пользовательский отрисовщик текста должен реализовывать методы, унаследованные от IUnknown, в дополнение к методам, перечисленным на странице ссылки IDWriteTextRenderer и ниже.
Полный исходный код пользовательского отрисовщика текста см. в файлах CustomTextRenderer.cpp и CustomTextRenderer.h примера DirectWrite Hello World.
Конструктор
Для пользовательского отрисовщика текста потребуется конструктор. В этом примере для отрисовки текста используются как кисти Direct2D сплошной, так и точечный рисунок.
По этой причине конструктор принимает параметры, приведенные в таблице ниже, с описаниями.
Параметр | Описание |
---|---|
pD2DFactory | Указатель на объект ID2D1Factory , который будет использоваться для создания необходимых ресурсов Direct2D. |
Prt | Указатель на объект ID2D1HwndRenderTarget , в который будет отображаться текст. |
pOutlineBrush | Указатель на ID2D1SolidColorBrush , который будет использоваться для рисования контура текста |
pFillBrush | Указатель на ID2D1BitmapBrush , который будет использоваться для заполнения текста. |
Они будут храниться конструктором, как показано в следующем коде.
CustomTextRenderer::CustomTextRenderer(
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pOutlineBrush,
ID2D1BitmapBrush* pFillBrush
)
:
cRefCount_(0),
pD2DFactory_(pD2DFactory),
pRT_(pRT),
pOutlineBrush_(pOutlineBrush),
pFillBrush_(pFillBrush)
{
pD2DFactory_->AddRef();
pRT_->AddRef();
pOutlineBrush_->AddRef();
pFillBrush_->AddRef();
}
DrawGlyphRun()
Метод DrawGlyphRun является main методом обратного вызова отрисовщика текста. В дополнение к таким сведениям, как источник базового плана и режим измерения, передается выполнение глифов, которые будут отображаться. Он также передает объект клиентского эффекта рисования для применения к выполнению глифа. Дополнительные сведения см. в разделе Добавление клиентских эффектов рисования в текстовый макет .
Эта реализация отрисовщика текста отрисовывает глифы, преобразуя их в геометрические объекты Direct2D , а затем рисуя и заполняя геометрические объекты. Это состоит из следующих шагов.
Создайте объект ID2D1PathGeometry , а затем получите объект ID2D1GeometrySink с помощью метода ID2D1PathGeometry::Open .
// Create the path geometry. ID2D1PathGeometry* pPathGeometry = NULL; hr = pD2DFactory_->CreatePathGeometry( &pPathGeometry ); // Write to the path geometry using the geometry sink. ID2D1GeometrySink* pSink = NULL; if (SUCCEEDED(hr)) { hr = pPathGeometry->Open( &pSink ); }
DWRITE_GLYPH_RUN, передаваемый в DrawGlyphRun, содержит объект IDWriteFontFace с именем fontFace, который представляет лицо шрифта для всего выполнения глифа. Поместите контур глифа в приемник geometry с помощью метода IDWriteFontFace:: GetGlyphRunOutline , как показано в следующем коде.
// Get the glyph run outline geometries back from DirectWrite and place them within the // geometry sink. if (SUCCEEDED(hr)) { hr = glyphRun->fontFace->GetGlyphRunOutline( glyphRun->fontEmSize, glyphRun->glyphIndices, glyphRun->glyphAdvances, glyphRun->glyphOffsets, glyphRun->glyphCount, glyphRun->isSideways, glyphRun->bidiLevel%2, pSink ); }
После заполнения приемника geometry закройте его.
// Close the geometry sink if (SUCCEEDED(hr)) { hr = pSink->Close(); }
Источник выполнения глифа должен быть преобразован таким образом, чтобы он отображался из правильного базового источника, как показано в следующем коде.
// Initialize a matrix to translate the origin of the glyph run. D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY );
BaselineOriginX и baselineOriginY передаются в качестве параметров методу обратного вызова DrawGlyphRun.
Создайте преобразованную геометрию с помощью метода ID2D1Factory::CreateTransformedGeometry и передав геометрию пути и матрицу перевода.
// Create the transformed geometry ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pPathGeometry, &matrix, &pTransformedGeometry ); }
Наконец, нарисуйте контур преобразованной геометрии и заполните ее с помощью методов ID2D1RenderTarget::D rawGeometry и ID2D1RenderTarget::FillGeometry и кистей Direct2D , хранящихся в виде переменных-членов.
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );
Теперь, когда рисование завершено, не забудьте очистить объекты, созданные в этом методе.
SafeRelease(&pPathGeometry); SafeRelease(&pSink); SafeRelease(&pTransformedGeometry);
DrawUnderline() и DrawStrikethrough()
IDWriteTextRenderer также имеет обратные вызовы для рисования подчеркивания и зачеркиния. В этом примере рисуется простой прямоугольник для подчеркивания или зачеркиния, но могут быть нарисованы и другие фигуры.
Рисование подчеркивания с помощью Direct2D состоит из следующих шагов.
Сначала создайте D2D1_RECT_F структуру размера и формы подчеркивания. Структура DWRITE_UNDERLINE , передаваемая методу обратного вызова DrawUnderline , обеспечивает смещение, ширину и толщину подчеркивания.
D2D1_RECT_F rect = D2D1::RectF( 0, underline->offset, underline->width, underline->offset + underline->thickness );
Затем создайте объект ID2D1RectangleGeometry с помощью метода ID2D1Factory::CreateRectangleGeometry и инициализированнойструктуры D2D1_RECT_F .
ID2D1RectangleGeometry* pRectangleGeometry = NULL; hr = pD2DFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry );
Как и при выполнении глифа, источник геометрии подчеркивания должен быть преобразован на основе базовых исходных значений с помощью метода CreateTransformedGeometry .
// Initialize a matrix to translate the origin of the underline D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY ); ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pRectangleGeometry, &matrix, &pTransformedGeometry ); }
Наконец, нарисуйте контур преобразованной геометрии и заполните ее с помощью методов ID2D1RenderTarget::D rawGeometry и ID2D1RenderTarget::FillGeometry и кистей Direct2D , хранящихся в виде переменных-членов.
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );
Теперь, когда рисование завершено, не забудьте очистить объекты, созданные в этом методе.
SafeRelease(&pRectangleGeometry); SafeRelease(&pTransformedGeometry);
Процесс рисования зачеркивки такой же. Однако зачеркивная будет иметь другое смещение и, скорее всего, другую ширину и толщину.
Привязка пикселей, пикселей на DIP и преобразование
IsPixelSnappingDisabled()
Этот метод вызывается для определения того, отключена ли привязка пикселей. Рекомендуемое значение по умолчанию — FALSE, и это выходные данные этого примера.
*isDisabled = FALSE;
GetCurrentTransform()
В этом примере выполняется отрисовка в целевой объект отрисовки Direct2D, поэтому пересылайте преобразование из целевого объекта отрисовки с помощью ID2D1RenderTarget::GetTransform.
//forward the render target's transform
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
GetPixelsPerDip()
Этот метод вызывается для получения количества пикселей на устройство независимого пикселя (DIP).
float x, yUnused;
pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;
DrawInlineObject()
Пользовательский отрисовщик текста также имеет обратный вызов для рисования встроенных объектов. В этом примере DrawInlineObject возвращает E_NOTIMPL. Объяснение того, как рисовать встроенные объекты, выходит за область этого руководства. Дополнительные сведения см. в разделе Добавление встроенных объектов в текстовый макет .
Деструктор
Важно освободить все указатели, которые использовались классом пользовательского отрисовщика текста.
CustomTextRenderer::~CustomTextRenderer()
{
SafeRelease(&pD2DFactory_);
SafeRelease(&pRT_);
SafeRelease(&pOutlineBrush_);
SafeRelease(&pFillBrush_);
}
Использование пользовательского отрисовщика текста
Отрисовка выполняется с помощью пользовательского отрисовщика с помощью метода IDWriteTextLayout::D raw , который принимает интерфейс обратного вызова, производный от IDWriteTextRenderer , в качестве аргумента, как показано в следующем коде.
// Draw the text layout using DirectWrite and the CustomTextRenderer class.
hr = pTextLayout_->Draw(
NULL,
pTextRenderer_, // Custom text renderer.
origin.x,
origin.y
);
Метод IDWriteTextLayout::D raw вызывает методы пользовательского обратного вызова отрисовщика, который вы предоставляете. Описанные выше методы DrawGlyphRun, DrawUnderline, DrawInlineObject и DrawStrikethrough выполняют функции рисования.