// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #pragma once #include #include "BoxDrawingEffect.h" namespace Microsoft::Console::Render { struct DrawingContext { DrawingContext(ID2D1RenderTarget* renderTarget, ID2D1Brush* foregroundBrush, ID2D1Brush* backgroundBrush, bool forceGrayscaleAA, IDWriteFactory* dwriteFactory, const DWRITE_LINE_SPACING spacing, const D2D_SIZE_F cellSize, const D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE) noexcept { this->renderTarget = renderTarget; this->foregroundBrush = foregroundBrush; this->backgroundBrush = backgroundBrush; this->forceGrayscaleAA = forceGrayscaleAA; this->dwriteFactory = dwriteFactory; this->spacing = spacing; this->cellSize = cellSize; this->options = options; } ID2D1RenderTarget* renderTarget; ID2D1Brush* foregroundBrush; ID2D1Brush* backgroundBrush; bool forceGrayscaleAA; IDWriteFactory* dwriteFactory; DWRITE_LINE_SPACING spacing; D2D_SIZE_F cellSize; D2D1_DRAW_TEXT_OPTIONS options; }; class CustomTextRenderer : public ::Microsoft::WRL::RuntimeClass<::Microsoft::WRL::RuntimeClassFlags<::Microsoft::WRL::ClassicCom | ::Microsoft::WRL::InhibitFtmBase>, IDWriteTextRenderer> { public: // http://www.charlespetzold.com/blog/2014/01/Character-Formatting-Extensions-with-DirectWrite.html // https://docs.microsoft.com/en-us/windows/desktop/DirectWrite/how-to-implement-a-custom-text-renderer // IDWritePixelSnapping methods [[nodiscard]] HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(void* clientDrawingContext, _Out_ BOOL* isDisabled) noexcept override; [[nodiscard]] HRESULT STDMETHODCALLTYPE GetPixelsPerDip(void* clientDrawingContext, _Out_ FLOAT* pixelsPerDip) noexcept override; [[nodiscard]] HRESULT STDMETHODCALLTYPE GetCurrentTransform(void* clientDrawingContext, _Out_ DWRITE_MATRIX* transform) noexcept override; // IDWriteTextRenderer methods [[nodiscard]] HRESULT STDMETHODCALLTYPE DrawGlyphRun(void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, _In_ const DWRITE_GLYPH_RUN* glyphRun, _In_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription, IUnknown* clientDrawingEffect) override; [[nodiscard]] HRESULT STDMETHODCALLTYPE DrawUnderline(void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ const DWRITE_UNDERLINE* underline, IUnknown* clientDrawingEffect) noexcept override; [[nodiscard]] HRESULT STDMETHODCALLTYPE DrawStrikethrough(void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ const DWRITE_STRIKETHROUGH* strikethrough, IUnknown* clientDrawingEffect) noexcept override; [[nodiscard]] HRESULT STDMETHODCALLTYPE DrawInlineObject(void* clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown* clientDrawingEffect) noexcept override; private: [[nodiscard]] HRESULT _FillRectangle(void* clientDrawingContext, IUnknown* clientDrawingEffect, float x, float y, float width, float thickness, DWRITE_READING_DIRECTION readingDirection, DWRITE_FLOW_DIRECTION flowDirection) noexcept; [[nodiscard]] HRESULT _DrawBasicGlyphRun(DrawingContext* clientDrawingContext, D2D1_POINT_2F baselineOrigin, DWRITE_MEASURING_MODE measuringMode, _In_ const DWRITE_GLYPH_RUN* glyphRun, _In_opt_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription, ID2D1Brush* brush, _In_opt_ IUnknown* clientDrawingEffect); [[nodiscard]] HRESULT _DrawBoxRunManually(DrawingContext* clientDrawingContext, D2D1_POINT_2F baselineOrigin, DWRITE_MEASURING_MODE measuringMode, _In_ const DWRITE_GLYPH_RUN* glyphRun, _In_opt_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription, _In_ IBoxDrawingEffect* clientDrawingEffect) noexcept; [[nodiscard]] HRESULT _DrawGlowGlyphRun(DrawingContext* clientDrawingContext, D2D1_POINT_2F baselineOrigin, DWRITE_MEASURING_MODE measuringMode, _In_ const DWRITE_GLYPH_RUN* glyphRun, _In_opt_ const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription) noexcept; }; }