2014-08-06 14:52:30 +02:00
/* vi:set ts=8 sts=4 sw=4 noet: */
/*
* Author : MURAOKA Taro < koron . kaoriya @ gmail . com >
*
* Contributors :
* - Ken Takata
2017-11-26 14:29:32 +01:00
* - Yasuhiro Matsumoto
2014-08-06 14:52:30 +02:00
*
* Copyright ( C ) 2013 MURAOKA Taro < koron . kaoriya @ gmail . com >
* THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE .
*/
# define WIN32_LEAN_AND_MEAN
# ifndef DYNAMIC_DIRECTX
# if WINVER < 0x0600
# error WINVER must be 0x0600 or above to use DirectWrite(DirectX)
# endif
# endif
# include <windows.h>
# include <crtdbg.h>
# include <assert.h>
# include <math.h>
# include <d2d1.h>
# include <d2d1helper.h>
2017-11-26 14:29:32 +01:00
// Disable these macros to compile with old VC and newer SDK (V8.1 or later).
# if defined(_MSC_VER) && (_MSC_VER < 1700)
# define _COM_Outptr_ __out
# define _In_reads_(s)
# define _In_reads_opt_(s)
# define _Maybenull_
# define _Out_writes_(s)
# define _Out_writes_opt_(s)
# define _Out_writes_to_(x, y)
# define _Out_writes_to_opt_(x, y)
# define _Outptr_
# endif
2017-12-14 13:15:19 +01:00
# ifdef FEAT_DIRECTX_COLOR_EMOJI
# include <dwrite_2.h>
# else
# include <dwrite.h>
# endif
2014-08-06 14:52:30 +02:00
# include "gui_dwrite.h"
# ifdef __MINGW32__
# define __maybenull SAL__maybenull
# define __in SAL__in
# define __out SAL__out
# endif
2022-06-09 20:53:54 +01:00
# ifdef __MINGW32__
# define UNUSED __attribute__((unused))
# else
# define UNUSED
# endif
2016-03-19 20:51:35 +01:00
# if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
# define FINAL final
# else
# define FINAL
# endif
2014-08-06 14:52:30 +02:00
# ifdef DYNAMIC_DIRECTX
2022-02-12 11:18:37 +00:00
extern " C " HINSTANCE vimLoadLib ( const char * name ) ;
2014-08-06 14:52:30 +02:00
typedef int ( WINAPI * PGETUSERDEFAULTLOCALENAME ) ( LPWSTR , int ) ;
typedef HRESULT ( WINAPI * PD2D1CREATEFACTORY ) ( D2D1_FACTORY_TYPE ,
REFIID , const D2D1_FACTORY_OPTIONS * , void * * ) ;
typedef HRESULT ( WINAPI * PDWRITECREATEFACTORY ) ( DWRITE_FACTORY_TYPE ,
REFIID , IUnknown * * ) ;
static HINSTANCE hD2D1DLL = NULL ;
static HINSTANCE hDWriteDLL = NULL ;
static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL ;
static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL ;
static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL ;
# define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName)
# define D2D1CreateFactory (*pD2D1CreateFactory)
# define DWriteCreateFactory (*pDWriteCreateFactory)
static void
unload ( HINSTANCE & hinst )
{
if ( hinst ! = NULL )
{
FreeLibrary ( hinst ) ;
hinst = NULL ;
}
}
# endif // DYNAMIC_DIRECTX
template < class T > inline void SafeRelease ( T * * ppT )
{
if ( * ppT )
{
( * ppT ) - > Release ( ) ;
* ppT = NULL ;
}
}
static DWRITE_PIXEL_GEOMETRY
ToPixelGeometry ( int value )
{
switch ( value )
{
default :
case 0 :
return DWRITE_PIXEL_GEOMETRY_FLAT ;
case 1 :
return DWRITE_PIXEL_GEOMETRY_RGB ;
case 2 :
return DWRITE_PIXEL_GEOMETRY_BGR ;
}
}
static int
ToInt ( DWRITE_PIXEL_GEOMETRY value )
{
switch ( value )
{
case DWRITE_PIXEL_GEOMETRY_FLAT :
return 0 ;
case DWRITE_PIXEL_GEOMETRY_RGB :
return 1 ;
case DWRITE_PIXEL_GEOMETRY_BGR :
return 2 ;
default :
return - 1 ;
}
}
static DWRITE_RENDERING_MODE
ToRenderingMode ( int value )
{
switch ( value )
{
default :
case 0 :
return DWRITE_RENDERING_MODE_DEFAULT ;
case 1 :
return DWRITE_RENDERING_MODE_ALIASED ;
case 2 :
return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ;
case 3 :
return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ;
case 4 :
return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL ;
case 5 :
return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC ;
case 6 :
return DWRITE_RENDERING_MODE_OUTLINE ;
}
}
static D2D1_TEXT_ANTIALIAS_MODE
ToTextAntialiasMode ( int value )
{
switch ( value )
{
default :
case 0 :
return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT ;
case 1 :
return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE ;
case 2 :
return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE ;
case 3 :
return D2D1_TEXT_ANTIALIAS_MODE_ALIASED ;
}
}
static int
ToInt ( DWRITE_RENDERING_MODE value )
{
switch ( value )
{
case DWRITE_RENDERING_MODE_DEFAULT :
return 0 ;
case DWRITE_RENDERING_MODE_ALIASED :
return 1 ;
case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC :
return 2 ;
case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL :
return 3 ;
case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL :
return 4 ;
case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC :
return 5 ;
case DWRITE_RENDERING_MODE_OUTLINE :
return 6 ;
default :
return - 1 ;
}
}
2017-11-26 14:29:32 +01:00
class FontCache {
public :
struct Item {
HFONT hFont ;
IDWriteTextFormat * pTextFormat ;
DWRITE_FONT_WEIGHT fontWeight ;
DWRITE_FONT_STYLE fontStyle ;
Item ( ) : hFont ( NULL ) , pTextFormat ( NULL ) { }
} ;
private :
int mSize ;
Item * mItems ;
public :
FontCache ( int size = 2 ) :
mSize ( size ) ,
mItems ( new Item [ size ] )
{
}
~ FontCache ( )
{
for ( int i = 0 ; i < mSize ; + + i )
SafeRelease ( & mItems [ i ] . pTextFormat ) ;
delete [ ] mItems ;
}
bool get ( HFONT hFont , Item & item )
{
int n = find ( hFont ) ;
if ( n < 0 )
return false ;
item = mItems [ n ] ;
slide ( n ) ;
return true ;
}
void put ( const Item & item )
{
int n = find ( item . hFont ) ;
if ( n < 0 )
n = mSize - 1 ;
if ( mItems [ n ] . pTextFormat ! = item . pTextFormat )
{
SafeRelease ( & mItems [ n ] . pTextFormat ) ;
2020-12-08 21:12:40 +01:00
if ( item . pTextFormat ! = NULL )
item . pTextFormat - > AddRef ( ) ;
2017-11-26 14:29:32 +01:00
}
mItems [ n ] = item ;
slide ( n ) ;
}
private :
int find ( HFONT hFont )
{
for ( int i = 0 ; i < mSize ; + + i )
{
if ( mItems [ i ] . hFont = = hFont )
return i ;
}
return - 1 ;
}
void slide ( int nextTop )
{
if ( nextTop = = 0 )
return ;
Item tmp = mItems [ nextTop ] ;
for ( int i = nextTop - 1 ; i > = 0 ; - - i )
mItems [ i + 1 ] = mItems [ i ] ;
mItems [ 0 ] = tmp ;
}
} ;
2017-12-05 13:22:16 +01:00
enum DrawingMode {
DM_GDI = 0 ,
DM_DIRECTX = 1 ,
DM_INTEROP = 2 ,
} ;
2017-11-26 14:29:32 +01:00
struct DWriteContext {
HDC mHDC ;
2017-12-05 13:22:16 +01:00
RECT mBindRect ;
DrawingMode mDMode ;
HDC mInteropHDC ;
2017-11-26 14:29:32 +01:00
bool mDrawing ;
bool mFallbackDC ;
ID2D1Factory * mD2D1Factory ;
ID2D1DCRenderTarget * mRT ;
2017-12-05 13:22:16 +01:00
ID2D1GdiInteropRenderTarget * mGDIRT ;
2017-11-26 14:29:32 +01:00
ID2D1SolidColorBrush * mBrush ;
2018-01-31 20:51:47 +01:00
ID2D1Bitmap * mBitmap ;
2017-11-26 14:29:32 +01:00
IDWriteFactory * mDWriteFactory ;
2017-12-14 13:15:19 +01:00
# ifdef FEAT_DIRECTX_COLOR_EMOJI
2017-11-26 14:29:32 +01:00
IDWriteFactory2 * mDWriteFactory2 ;
2017-12-14 13:15:19 +01:00
# endif
2017-11-26 14:29:32 +01:00
IDWriteGdiInterop * mGdiInterop ;
IDWriteRenderingParams * mRenderingParams ;
FontCache mFontCache ;
IDWriteTextFormat * mTextFormat ;
DWRITE_FONT_WEIGHT mFontWeight ;
DWRITE_FONT_STYLE mFontStyle ;
D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode ;
// METHODS
DWriteContext ( ) ;
virtual ~ DWriteContext ( ) ;
2017-12-05 13:22:16 +01:00
HRESULT CreateDeviceResources ( ) ;
void DiscardDeviceResources ( ) ;
2017-11-26 14:29:32 +01:00
HRESULT CreateTextFormatFromLOGFONT ( const LOGFONTW & logFont ,
IDWriteTextFormat * * ppTextFormat ) ;
HRESULT SetFontByLOGFONT ( const LOGFONTW & logFont ) ;
void SetFont ( HFONT hFont ) ;
2018-01-31 20:51:47 +01:00
void Rebind ( ) ;
2017-12-05 13:22:16 +01:00
void BindDC ( HDC hdc , const RECT * rect ) ;
2017-11-26 14:29:32 +01:00
2017-12-05 13:22:16 +01:00
HRESULT SetDrawingMode ( DrawingMode mode ) ;
2017-11-26 14:29:32 +01:00
ID2D1Brush * SolidBrush ( COLORREF color ) ;
2017-12-05 13:22:16 +01:00
void DrawText ( const WCHAR * text , int len ,
2017-11-26 14:29:32 +01:00
int x , int y , int w , int h , int cellWidth , COLORREF color ,
2017-12-05 13:22:16 +01:00
UINT fuOptions , const RECT * lprc , const INT * lpDx ) ;
2017-11-26 14:29:32 +01:00
2017-12-05 13:22:16 +01:00
void FillRect ( const RECT * rc , COLORREF color ) ;
void DrawLine ( int x1 , int y1 , int x2 , int y2 , COLORREF color ) ;
void SetPixel ( int x , int y , COLORREF color ) ;
2017-11-26 14:29:32 +01:00
2018-01-31 20:51:47 +01:00
void Scroll ( int x , int y , const RECT * rc ) ;
2017-11-26 14:29:32 +01:00
void Flush ( ) ;
void SetRenderingParams (
const DWriteRenderingParams * params ) ;
DWriteRenderingParams * GetRenderingParams (
DWriteRenderingParams * params ) ;
} ;
2014-08-06 14:52:30 +02:00
class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
{
private :
2017-11-26 14:29:32 +01:00
FLOAT & mAccum ;
2014-08-06 14:52:30 +02:00
FLOAT mDelta ;
FLOAT * mAdjustedAdvances ;
public :
AdjustedGlyphRun (
const DWRITE_GLYPH_RUN * glyphRun ,
2017-11-26 14:29:32 +01:00
FLOAT cellWidth ,
FLOAT & accum ) :
2014-08-06 14:52:30 +02:00
DWRITE_GLYPH_RUN ( * glyphRun ) ,
2017-11-26 14:29:32 +01:00
mAccum ( accum ) ,
2014-08-06 14:52:30 +02:00
mDelta ( 0.0f ) ,
mAdjustedAdvances ( new FLOAT [ glyphRun - > glyphCount ] )
{
assert ( cellWidth ! = 0.0f ) ;
for ( UINT32 i = 0 ; i < glyphRun - > glyphCount ; + + i )
{
FLOAT orig = glyphRun - > glyphAdvances [ i ] ;
FLOAT adjusted = adjustToCell ( orig , cellWidth ) ;
mAdjustedAdvances [ i ] = adjusted ;
mDelta + = adjusted - orig ;
}
glyphAdvances = mAdjustedAdvances ;
}
2017-11-26 14:29:32 +01:00
~ AdjustedGlyphRun ( )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
mAccum + = mDelta ;
2014-08-06 14:52:30 +02:00
delete [ ] mAdjustedAdvances ;
}
static FLOAT adjustToCell ( FLOAT value , FLOAT cellWidth )
{
2017-11-26 14:29:32 +01:00
int cellCount = int ( floor ( value / cellWidth + 0.5f ) ) ;
2014-08-06 14:52:30 +02:00
if ( cellCount < 1 )
cellCount = 1 ;
return cellCount * cellWidth ;
}
} ;
2017-11-26 14:29:32 +01:00
struct TextRendererContext {
// const fields.
COLORREF color ;
FLOAT cellWidth ;
// working fields.
FLOAT offsetX ;
} ;
class TextRenderer FINAL : public IDWriteTextRenderer
2014-08-06 14:52:30 +02:00
{
public :
2017-11-26 14:29:32 +01:00
TextRenderer (
DWriteContext * pDWC ) :
2014-08-06 14:52:30 +02:00
cRefCount_ ( 0 ) ,
2017-11-26 14:29:32 +01:00
pDWC_ ( pDWC )
2014-08-06 14:52:30 +02:00
{
AddRef ( ) ;
}
2016-02-27 15:27:23 +01:00
// add "virtual" to avoid a compiler warning
2017-11-26 14:29:32 +01:00
virtual ~ TextRenderer ( )
2014-08-06 14:52:30 +02:00
{
}
IFACEMETHOD ( IsPixelSnappingDisabled ) (
2022-06-09 20:53:54 +01:00
__maybenull void * clientDrawingContext UNUSED ,
2014-08-06 14:52:30 +02:00
__out BOOL * isDisabled )
{
* isDisabled = FALSE ;
return S_OK ;
}
IFACEMETHOD ( GetCurrentTransform ) (
2022-06-09 20:53:54 +01:00
__maybenull void * clientDrawingContext UNUSED ,
2014-08-06 14:52:30 +02:00
__out DWRITE_MATRIX * transform )
{
2016-02-27 15:27:23 +01:00
// forward the render target's transform
2017-11-26 14:29:32 +01:00
pDWC_ - > mRT - > GetTransform (
reinterpret_cast < D2D1_MATRIX_3X2_F * > ( transform ) ) ;
2014-08-06 14:52:30 +02:00
return S_OK ;
}
IFACEMETHOD ( GetPixelsPerDip ) (
2022-06-09 20:53:54 +01:00
__maybenull void * clientDrawingContext UNUSED ,
2014-08-06 14:52:30 +02:00
__out FLOAT * pixelsPerDip )
{
2017-11-26 14:29:32 +01:00
float dpiX , unused ;
pDWC_ - > mRT - > GetDpi ( & dpiX , & unused ) ;
* pixelsPerDip = dpiX / 96.0f ;
2014-08-06 14:52:30 +02:00
return S_OK ;
}
IFACEMETHOD ( DrawUnderline ) (
2022-06-09 20:53:54 +01:00
__maybenull void * clientDrawingContext UNUSED ,
FLOAT baselineOriginX UNUSED ,
FLOAT baselineOriginY UNUSED ,
__in DWRITE_UNDERLINE const * underline UNUSED ,
IUnknown * clientDrawingEffect UNUSED )
2014-08-06 14:52:30 +02:00
{
return E_NOTIMPL ;
}
IFACEMETHOD ( DrawStrikethrough ) (
2022-06-09 20:53:54 +01:00
__maybenull void * clientDrawingContext UNUSED ,
FLOAT baselineOriginX UNUSED ,
FLOAT baselineOriginY UNUSED ,
__in DWRITE_STRIKETHROUGH const * strikethrough UNUSED ,
IUnknown * clientDrawingEffect UNUSED )
2014-08-06 14:52:30 +02:00
{
return E_NOTIMPL ;
}
IFACEMETHOD ( DrawInlineObject ) (
2022-06-09 20:53:54 +01:00
__maybenull void * clientDrawingContext UNUSED ,
FLOAT originX UNUSED ,
FLOAT originY UNUSED ,
IDWriteInlineObject * inlineObject UNUSED ,
BOOL isSideways UNUSED ,
BOOL isRightToLeft UNUSED ,
IUnknown * clientDrawingEffect UNUSED )
2014-08-06 14:52:30 +02:00
{
return E_NOTIMPL ;
}
2017-11-26 14:29:32 +01:00
IFACEMETHOD ( DrawGlyphRun ) (
__maybenull void * clientDrawingContext ,
FLOAT baselineOriginX ,
FLOAT baselineOriginY ,
2022-06-09 20:53:54 +01:00
DWRITE_MEASURING_MODE measuringMode UNUSED ,
2017-11-26 14:29:32 +01:00
__in DWRITE_GLYPH_RUN const * glyphRun ,
2022-06-09 20:53:54 +01:00
__in DWRITE_GLYPH_RUN_DESCRIPTION const * glyphRunDescription UNUSED ,
IUnknown * clientDrawingEffect UNUSED )
2017-11-26 14:29:32 +01:00
{
TextRendererContext * context =
reinterpret_cast < TextRendererContext * > ( clientDrawingContext ) ;
AdjustedGlyphRun adjustedGlyphRun ( glyphRun , context - > cellWidth ,
context - > offsetX ) ;
2017-12-14 13:15:19 +01:00
# ifdef FEAT_DIRECTX_COLOR_EMOJI
2017-11-26 14:29:32 +01:00
if ( pDWC_ - > mDWriteFactory2 ! = NULL )
{
IDWriteColorGlyphRunEnumerator * enumerator = NULL ;
HRESULT hr = pDWC_ - > mDWriteFactory2 - > TranslateColorGlyphRun (
baselineOriginX + context - > offsetX ,
baselineOriginY ,
& adjustedGlyphRun ,
NULL ,
DWRITE_MEASURING_MODE_GDI_NATURAL ,
NULL ,
0 ,
& enumerator ) ;
if ( SUCCEEDED ( hr ) )
{
// Draw by IDWriteFactory2 for color emoji
BOOL hasRun = TRUE ;
enumerator - > MoveNext ( & hasRun ) ;
while ( hasRun )
{
const DWRITE_COLOR_GLYPH_RUN * colorGlyphRun ;
enumerator - > GetCurrentRun ( & colorGlyphRun ) ;
pDWC_ - > mBrush - > SetColor ( colorGlyphRun - > runColor ) ;
pDWC_ - > mRT - > DrawGlyphRun (
D2D1 : : Point2F (
colorGlyphRun - > baselineOriginX ,
colorGlyphRun - > baselineOriginY ) ,
& colorGlyphRun - > glyphRun ,
pDWC_ - > mBrush ,
DWRITE_MEASURING_MODE_NATURAL ) ;
enumerator - > MoveNext ( & hasRun ) ;
}
SafeRelease ( & enumerator ) ;
return S_OK ;
}
}
2017-12-14 13:15:19 +01:00
# endif
2017-11-26 14:29:32 +01:00
// Draw by IDWriteFactory (without color emoji)
pDWC_ - > mRT - > DrawGlyphRun (
D2D1 : : Point2F (
baselineOriginX + context - > offsetX ,
baselineOriginY ) ,
& adjustedGlyphRun ,
pDWC_ - > SolidBrush ( context - > color ) ,
DWRITE_MEASURING_MODE_NATURAL ) ;
return S_OK ;
}
2014-08-06 14:52:30 +02:00
public :
IFACEMETHOD_ ( unsigned long , AddRef ) ( )
{
return InterlockedIncrement ( & cRefCount_ ) ;
}
IFACEMETHOD_ ( unsigned long , Release ) ( )
{
long newCount = InterlockedDecrement ( & cRefCount_ ) ;
if ( newCount = = 0 )
{
delete this ;
return 0 ;
}
return newCount ;
}
IFACEMETHOD ( QueryInterface ) (
IID const & riid ,
void * * ppvObject )
{
if ( __uuidof ( IDWriteTextRenderer ) = = riid )
{
* ppvObject = this ;
}
else if ( __uuidof ( IDWritePixelSnapping ) = = riid )
{
* ppvObject = this ;
}
else if ( __uuidof ( IUnknown ) = = riid )
{
* ppvObject = this ;
}
else
{
* ppvObject = NULL ;
return E_FAIL ;
}
return S_OK ;
}
private :
2014-08-07 13:55:10 +02:00
long cRefCount_ ;
2017-11-26 14:29:32 +01:00
DWriteContext * pDWC_ ;
2014-08-06 14:52:30 +02:00
} ;
DWriteContext : : DWriteContext ( ) :
2017-11-26 14:29:32 +01:00
mHDC ( NULL ) ,
2017-12-05 13:22:16 +01:00
mBindRect ( ) ,
mDMode ( DM_GDI ) ,
mInteropHDC ( NULL ) ,
2014-08-06 14:52:30 +02:00
mDrawing ( false ) ,
2017-11-26 14:29:32 +01:00
mFallbackDC ( false ) ,
2014-08-06 14:52:30 +02:00
mD2D1Factory ( NULL ) ,
mRT ( NULL ) ,
2017-12-05 13:22:16 +01:00
mGDIRT ( NULL ) ,
2014-08-06 14:52:30 +02:00
mBrush ( NULL ) ,
2018-01-31 20:51:47 +01:00
mBitmap ( NULL ) ,
2014-08-06 14:52:30 +02:00
mDWriteFactory ( NULL ) ,
2017-12-14 13:15:19 +01:00
# ifdef FEAT_DIRECTX_COLOR_EMOJI
2017-11-26 14:29:32 +01:00
mDWriteFactory2 ( NULL ) ,
2017-12-14 13:15:19 +01:00
# endif
2014-08-06 14:52:30 +02:00
mGdiInterop ( NULL ) ,
mRenderingParams ( NULL ) ,
2017-11-26 14:29:32 +01:00
mFontCache ( 8 ) ,
2014-08-06 14:52:30 +02:00
mTextFormat ( NULL ) ,
mFontWeight ( DWRITE_FONT_WEIGHT_NORMAL ) ,
mFontStyle ( DWRITE_FONT_STYLE_NORMAL ) ,
mTextAntialiasMode ( D2D1_TEXT_ANTIALIAS_MODE_DEFAULT )
{
HRESULT hr ;
hr = D2D1CreateFactory ( D2D1_FACTORY_TYPE_SINGLE_THREADED ,
__uuidof ( ID2D1Factory ) , NULL ,
reinterpret_cast < void * * > ( & mD2D1Factory ) ) ;
_RPT2 ( _CRT_WARN , " D2D1CreateFactory: hr=%p p=%p \n " , hr , mD2D1Factory ) ;
if ( SUCCEEDED ( hr ) )
{
hr = DWriteCreateFactory (
DWRITE_FACTORY_TYPE_SHARED ,
__uuidof ( IDWriteFactory ) ,
reinterpret_cast < IUnknown * * > ( & mDWriteFactory ) ) ;
_RPT2 ( _CRT_WARN , " DWriteCreateFactory: hr=%p p=%p \n " , hr ,
mDWriteFactory ) ;
}
2017-12-14 13:15:19 +01:00
# ifdef FEAT_DIRECTX_COLOR_EMOJI
2017-11-26 14:29:32 +01:00
if ( SUCCEEDED ( hr ) )
{
DWriteCreateFactory (
DWRITE_FACTORY_TYPE_SHARED ,
__uuidof ( IDWriteFactory2 ) ,
reinterpret_cast < IUnknown * * > ( & mDWriteFactory2 ) ) ;
_RPT1 ( _CRT_WARN , " IDWriteFactory2: %s \n " , SUCCEEDED ( hr ) ? " available " : " not available " ) ;
}
2017-12-14 13:15:19 +01:00
# endif
2017-11-26 14:29:32 +01:00
2014-08-06 14:52:30 +02:00
if ( SUCCEEDED ( hr ) )
{
hr = mDWriteFactory - > GetGdiInterop ( & mGdiInterop ) ;
_RPT2 ( _CRT_WARN , " GetGdiInterop: hr=%p p=%p \n " , hr , mGdiInterop ) ;
}
if ( SUCCEEDED ( hr ) )
{
hr = mDWriteFactory - > CreateRenderingParams ( & mRenderingParams ) ;
_RPT2 ( _CRT_WARN , " CreateRenderingParams: hr=%p p=%p \n " , hr ,
mRenderingParams ) ;
}
}
DWriteContext : : ~ DWriteContext ( )
{
SafeRelease ( & mTextFormat ) ;
SafeRelease ( & mRenderingParams ) ;
SafeRelease ( & mGdiInterop ) ;
SafeRelease ( & mDWriteFactory ) ;
2017-12-14 13:15:19 +01:00
# ifdef FEAT_DIRECTX_COLOR_EMOJI
2017-11-26 14:29:32 +01:00
SafeRelease ( & mDWriteFactory2 ) ;
2017-12-14 13:15:19 +01:00
# endif
2018-01-31 20:51:47 +01:00
SafeRelease ( & mBitmap ) ;
2014-08-06 14:52:30 +02:00
SafeRelease ( & mBrush ) ;
2017-12-05 13:22:16 +01:00
SafeRelease ( & mGDIRT ) ;
2014-08-06 14:52:30 +02:00
SafeRelease ( & mRT ) ;
SafeRelease ( & mD2D1Factory ) ;
}
2017-12-05 13:22:16 +01:00
HRESULT
DWriteContext : : CreateDeviceResources ( )
{
HRESULT hr ;
if ( mRT ! = NULL )
return S_OK ;
D2D1_RENDER_TARGET_PROPERTIES props = {
D2D1_RENDER_TARGET_TYPE_DEFAULT ,
{ DXGI_FORMAT_B8G8R8A8_UNORM , D2D1_ALPHA_MODE_IGNORE } ,
0 , 0 ,
D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE ,
D2D1_FEATURE_LEVEL_DEFAULT
} ;
hr = mD2D1Factory - > CreateDCRenderTarget ( & props , & mRT ) ;
_RPT2 ( _CRT_WARN , " CreateDCRenderTarget: hr=%p p=%p \n " , hr , mRT ) ;
if ( SUCCEEDED ( hr ) )
{
// This always succeeds.
mRT - > QueryInterface (
__uuidof ( ID2D1GdiInteropRenderTarget ) ,
reinterpret_cast < void * * > ( & mGDIRT ) ) ;
_RPT1 ( _CRT_WARN , " GdiInteropRenderTarget: p=%p \n " , mGDIRT ) ;
}
if ( SUCCEEDED ( hr ) )
{
hr = mRT - > CreateSolidColorBrush (
D2D1 : : ColorF ( D2D1 : : ColorF : : Black ) ,
& mBrush ) ;
_RPT2 ( _CRT_WARN , " CreateSolidColorBrush: hr=%p p=%p \n " , hr , mBrush ) ;
}
if ( SUCCEEDED ( hr ) )
2018-01-31 20:51:47 +01:00
Rebind ( ) ;
2017-12-05 13:22:16 +01:00
return hr ;
}
void
DWriteContext : : DiscardDeviceResources ( )
{
2018-01-31 20:51:47 +01:00
SafeRelease ( & mBitmap ) ;
2017-12-05 13:22:16 +01:00
SafeRelease ( & mBrush ) ;
SafeRelease ( & mGDIRT ) ;
SafeRelease ( & mRT ) ;
}
2014-08-06 14:52:30 +02:00
HRESULT
2017-11-26 14:29:32 +01:00
DWriteContext : : CreateTextFormatFromLOGFONT ( const LOGFONTW & logFont ,
IDWriteTextFormat * * ppTextFormat )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
// Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
2014-08-06 14:52:30 +02:00
HRESULT hr = S_OK ;
2017-11-26 14:29:32 +01:00
IDWriteTextFormat * pTextFormat = NULL ;
2014-08-06 14:52:30 +02:00
IDWriteFont * font = NULL ;
IDWriteFontFamily * fontFamily = NULL ;
IDWriteLocalizedStrings * localizedFamilyNames = NULL ;
2017-11-26 14:29:32 +01:00
float fontSize = 0 ;
2014-08-06 14:52:30 +02:00
if ( SUCCEEDED ( hr ) )
{
hr = mGdiInterop - > CreateFontFromLOGFONT ( & logFont , & font ) ;
}
// Get the font family to which this font belongs.
if ( SUCCEEDED ( hr ) )
{
hr = font - > GetFontFamily ( & fontFamily ) ;
}
// Get the family names. This returns an object that encapsulates one or
// more names with the same meaning but in different languages.
if ( SUCCEEDED ( hr ) )
{
hr = fontFamily - > GetFamilyNames ( & localizedFamilyNames ) ;
}
// Get the family name at index zero. If we were going to display the name
// we'd want to try to find one that matched the use locale, but for
// purposes of creating a text format object any language will do.
wchar_t familyName [ 100 ] ;
if ( SUCCEEDED ( hr ) )
{
hr = localizedFamilyNames - > GetString ( 0 , familyName ,
ARRAYSIZE ( familyName ) ) ;
}
if ( SUCCEEDED ( hr ) )
{
2017-11-26 14:29:32 +01:00
// Use lfHeight of the LOGFONT as font size.
fontSize = float ( logFont . lfHeight ) ;
if ( fontSize < 0 )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
// Negative lfHeight represents the size of the em unit.
fontSize = - fontSize ;
}
else
{
// Positive lfHeight represents the cell height (ascent +
// descent).
DWRITE_FONT_METRICS fontMetrics ;
font - > GetMetrics ( & fontMetrics ) ;
// Convert the cell height (ascent + descent) from design units
// to ems.
float cellHeight = static_cast < float > (
fontMetrics . ascent + fontMetrics . descent )
/ fontMetrics . designUnitsPerEm ;
// Divide the font size by the cell height to get the font em
// size.
fontSize / = cellHeight ;
2014-08-06 14:52:30 +02:00
}
}
// The text format includes a locale name. Ideally, this would be the
// language of the text, which may or may not be the same as the primary
// language of the user. However, for our purposes the user locale will do.
wchar_t localeName [ LOCALE_NAME_MAX_LENGTH ] ;
if ( SUCCEEDED ( hr ) )
{
if ( GetUserDefaultLocaleName ( localeName , LOCALE_NAME_MAX_LENGTH ) = = 0 )
hr = HRESULT_FROM_WIN32 ( GetLastError ( ) ) ;
}
if ( SUCCEEDED ( hr ) )
{
// Create the text format object.
hr = mDWriteFactory - > CreateTextFormat (
familyName ,
NULL , // no custom font collection
font - > GetWeight ( ) ,
font - > GetStyle ( ) ,
font - > GetStretch ( ) ,
fontSize ,
localeName ,
2017-11-26 14:29:32 +01:00
& pTextFormat ) ;
2014-08-06 14:52:30 +02:00
}
2017-11-26 14:29:32 +01:00
if ( SUCCEEDED ( hr ) )
hr = pTextFormat - > SetTextAlignment ( DWRITE_TEXT_ALIGNMENT_LEADING ) ;
if ( SUCCEEDED ( hr ) )
hr = pTextFormat - > SetParagraphAlignment (
2019-03-16 15:24:42 +01:00
DWRITE_PARAGRAPH_ALIGNMENT_FAR ) ;
2017-11-26 14:29:32 +01:00
if ( SUCCEEDED ( hr ) )
hr = pTextFormat - > SetWordWrapping ( DWRITE_WORD_WRAPPING_NO_WRAP ) ;
SafeRelease ( & localizedFamilyNames ) ;
SafeRelease ( & fontFamily ) ;
SafeRelease ( & font ) ;
if ( SUCCEEDED ( hr ) )
* ppTextFormat = pTextFormat ;
else
SafeRelease ( & pTextFormat ) ;
return hr ;
}
HRESULT
DWriteContext : : SetFontByLOGFONT ( const LOGFONTW & logFont )
{
HRESULT hr = S_OK ;
IDWriteTextFormat * pTextFormat = NULL ;
hr = CreateTextFormatFromLOGFONT ( logFont , & pTextFormat ) ;
2014-08-06 14:52:30 +02:00
if ( SUCCEEDED ( hr ) )
{
2017-11-26 14:29:32 +01:00
SafeRelease ( & mTextFormat ) ;
mTextFormat = pTextFormat ;
2014-08-06 14:52:30 +02:00
mFontWeight = static_cast < DWRITE_FONT_WEIGHT > ( logFont . lfWeight ) ;
mFontStyle = logFont . lfItalic ? DWRITE_FONT_STYLE_ITALIC
: DWRITE_FONT_STYLE_NORMAL ;
}
return hr ;
}
void
DWriteContext : : SetFont ( HFONT hFont )
{
2017-11-26 14:29:32 +01:00
FontCache : : Item item ;
if ( mFontCache . get ( hFont , item ) )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
if ( item . pTextFormat ! = NULL )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
item . pTextFormat - > AddRef ( ) ;
SafeRelease ( & mTextFormat ) ;
mTextFormat = item . pTextFormat ;
mFontWeight = item . fontWeight ;
mFontStyle = item . fontStyle ;
mFallbackDC = false ;
2014-08-06 14:52:30 +02:00
}
2017-11-26 14:29:32 +01:00
else
mFallbackDC = true ;
return ;
2014-08-06 14:52:30 +02:00
}
2017-11-26 14:29:32 +01:00
HRESULT hr = E_FAIL ;
LOGFONTW lf ;
if ( GetObjectW ( hFont , sizeof ( lf ) , & lf ) )
hr = SetFontByLOGFONT ( lf ) ;
item . hFont = hFont ;
if ( SUCCEEDED ( hr ) )
{
item . pTextFormat = mTextFormat ;
item . fontWeight = mFontWeight ;
item . fontStyle = mFontStyle ;
2017-12-05 13:22:16 +01:00
mFallbackDC = false ;
2017-11-26 14:29:32 +01:00
}
2017-12-05 13:22:16 +01:00
else
mFallbackDC = true ;
2017-11-26 14:29:32 +01:00
mFontCache . put ( item ) ;
2014-08-06 14:52:30 +02:00
}
void
2018-01-31 20:51:47 +01:00
DWriteContext : : Rebind ( )
2014-08-06 14:52:30 +02:00
{
2018-01-31 20:51:47 +01:00
SafeRelease ( & mBitmap ) ;
mRT - > BindDC ( mHDC , & mBindRect ) ;
2017-11-26 14:29:32 +01:00
mRT - > SetTransform ( D2D1 : : IdentityMatrix ( ) ) ;
2018-01-31 20:51:47 +01:00
D2D1_BITMAP_PROPERTIES props = {
{ DXGI_FORMAT_B8G8R8A8_UNORM , D2D1_ALPHA_MODE_IGNORE } ,
96.0f , 96.0f
} ;
mRT - > CreateBitmap (
D2D1 : : SizeU ( mBindRect . right - mBindRect . left ,
mBindRect . bottom - mBindRect . top ) ,
props , & mBitmap ) ;
}
void
DWriteContext : : BindDC ( HDC hdc , const RECT * rect )
{
2017-11-26 14:29:32 +01:00
mHDC = hdc ;
2017-12-05 13:22:16 +01:00
mBindRect = * rect ;
2018-01-31 20:51:47 +01:00
if ( mRT = = NULL )
CreateDeviceResources ( ) ;
else
{
Flush ( ) ;
Rebind ( ) ;
}
2017-11-26 14:29:32 +01:00
}
2014-08-06 14:52:30 +02:00
2019-03-25 22:48:18 +01:00
extern " C " void redraw_later_clear ( void ) ;
2017-12-05 13:22:16 +01:00
HRESULT
DWriteContext : : SetDrawingMode ( DrawingMode mode )
2017-11-26 14:29:32 +01:00
{
2017-12-05 13:22:16 +01:00
HRESULT hr = S_OK ;
switch ( mode )
2017-11-26 14:29:32 +01:00
{
2017-12-05 13:22:16 +01:00
default :
case DM_GDI :
if ( mInteropHDC ! = NULL )
{
mGDIRT - > ReleaseDC ( NULL ) ;
mInteropHDC = NULL ;
}
if ( mDrawing )
{
hr = mRT - > EndDraw ( ) ;
2019-05-05 13:20:02 +02:00
if ( hr = = ( HRESULT ) D2DERR_RECREATE_TARGET )
2017-12-05 13:22:16 +01:00
{
hr = S_OK ;
DiscardDeviceResources ( ) ;
CreateDeviceResources ( ) ;
2019-03-25 22:48:18 +01:00
redraw_later_clear ( ) ;
2017-12-05 13:22:16 +01:00
}
mDrawing = false ;
}
break ;
case DM_DIRECTX :
if ( mInteropHDC ! = NULL )
{
mGDIRT - > ReleaseDC ( NULL ) ;
mInteropHDC = NULL ;
}
else if ( mDrawing = = false )
{
CreateDeviceResources ( ) ;
mRT - > BeginDraw ( ) ;
mDrawing = true ;
}
break ;
case DM_INTEROP :
if ( mDrawing = = false )
{
CreateDeviceResources ( ) ;
mRT - > BeginDraw ( ) ;
mDrawing = true ;
}
if ( mInteropHDC = = NULL )
hr = mGDIRT - > GetDC ( D2D1_DC_INITIALIZE_MODE_COPY , & mInteropHDC ) ;
break ;
2017-11-26 14:29:32 +01:00
}
2017-12-05 13:22:16 +01:00
mDMode = mode ;
return hr ;
2017-11-26 14:29:32 +01:00
}
2014-08-06 14:52:30 +02:00
2017-11-26 14:29:32 +01:00
ID2D1Brush *
DWriteContext : : SolidBrush ( COLORREF color )
{
mBrush - > SetColor ( D2D1 : : ColorF ( UINT32 ( GetRValue ( color ) ) < < 16 |
UINT32 ( GetGValue ( color ) ) < < 8 | UINT32 ( GetBValue ( color ) ) ) ) ;
return mBrush ;
2014-08-06 14:52:30 +02:00
}
void
2017-12-05 13:22:16 +01:00
DWriteContext : : DrawText ( const WCHAR * text , int len ,
2017-11-26 14:29:32 +01:00
int x , int y , int w , int h , int cellWidth , COLORREF color ,
2017-12-05 13:22:16 +01:00
UINT fuOptions , const RECT * lprc , const INT * lpDx )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
if ( mFallbackDC )
{
2017-12-05 13:22:16 +01:00
// Fall back to GDI rendering.
HRESULT hr = SetDrawingMode ( DM_INTEROP ) ;
if ( SUCCEEDED ( hr ) )
{
HGDIOBJ hFont = : : GetCurrentObject ( mHDC , OBJ_FONT ) ;
HGDIOBJ hOldFont = : : SelectObject ( mInteropHDC , hFont ) ;
: : SetTextColor ( mInteropHDC , color ) ;
: : SetBkMode ( mInteropHDC , : : GetBkMode ( mHDC ) ) ;
: : ExtTextOutW ( mInteropHDC , x , y , fuOptions , lprc , text , len , lpDx ) ;
: : SelectObject ( mInteropHDC , hOldFont ) ;
}
2014-08-06 14:52:30 +02:00
return ;
2017-11-26 14:29:32 +01:00
}
2014-08-06 14:52:30 +02:00
2017-11-26 14:29:32 +01:00
HRESULT hr ;
IDWriteTextLayout * textLayout = NULL ;
2017-12-05 13:22:16 +01:00
SetDrawingMode ( DM_DIRECTX ) ;
2017-11-26 14:29:32 +01:00
hr = mDWriteFactory - > CreateTextLayout ( text , len , mTextFormat ,
FLOAT ( w ) , FLOAT ( h ) , & textLayout ) ;
2014-08-06 14:52:30 +02:00
if ( SUCCEEDED ( hr ) )
{
2017-11-26 14:29:32 +01:00
DWRITE_TEXT_RANGE textRange = { 0 , UINT32 ( len ) } ;
textLayout - > SetFontWeight ( mFontWeight , textRange ) ;
textLayout - > SetFontStyle ( mFontStyle , textRange ) ;
2014-08-06 14:52:30 +02:00
2017-11-26 14:29:32 +01:00
TextRenderer renderer ( this ) ;
TextRendererContext context = { color , FLOAT ( cellWidth ) , 0.0f } ;
2019-03-21 20:50:12 +01:00
textLayout - > Draw ( & context , & renderer , FLOAT ( x ) , FLOAT ( y ) ) ;
2014-08-06 14:52:30 +02:00
}
2017-11-26 14:29:32 +01:00
SafeRelease ( & textLayout ) ;
2014-08-06 14:52:30 +02:00
}
2017-11-26 14:29:32 +01:00
void
2017-12-05 13:22:16 +01:00
DWriteContext : : FillRect ( const RECT * rc , COLORREF color )
2014-08-06 14:52:30 +02:00
{
2017-12-05 13:22:16 +01:00
if ( mDMode = = DM_INTEROP )
{
// GDI functions are used before this call. Keep using GDI.
// (Switching to Direct2D causes terrible slowdown.)
HBRUSH hbr = : : CreateSolidBrush ( color ) ;
: : FillRect ( mInteropHDC , rc , hbr ) ;
: : DeleteObject ( HGDIOBJ ( hbr ) ) ;
}
else
{
SetDrawingMode ( DM_DIRECTX ) ;
mRT - > FillRectangle (
D2D1 : : RectF ( FLOAT ( rc - > left ) , FLOAT ( rc - > top ) ,
FLOAT ( rc - > right ) , FLOAT ( rc - > bottom ) ) ,
SolidBrush ( color ) ) ;
}
2014-08-06 14:52:30 +02:00
}
2017-11-26 14:29:32 +01:00
void
2017-12-05 13:22:16 +01:00
DWriteContext : : DrawLine ( int x1 , int y1 , int x2 , int y2 , COLORREF color )
2014-08-06 14:52:30 +02:00
{
2017-12-05 13:22:16 +01:00
if ( mDMode = = DM_INTEROP )
2017-11-26 14:29:32 +01:00
{
2017-12-05 13:22:16 +01:00
// GDI functions are used before this call. Keep using GDI.
// (Switching to Direct2D causes terrible slowdown.)
HPEN hpen = : : CreatePen ( PS_SOLID , 1 , color ) ;
HGDIOBJ old_pen = : : SelectObject ( mInteropHDC , HGDIOBJ ( hpen ) ) ;
: : MoveToEx ( mInteropHDC , x1 , y1 , NULL ) ;
: : LineTo ( mInteropHDC , x2 , y2 ) ;
: : SelectObject ( mInteropHDC , old_pen ) ;
: : DeleteObject ( HGDIOBJ ( hpen ) ) ;
}
else
{
SetDrawingMode ( DM_DIRECTX ) ;
mRT - > DrawLine (
D2D1 : : Point2F ( FLOAT ( x1 ) , FLOAT ( y1 ) + 0.5f ) ,
D2D1 : : Point2F ( FLOAT ( x2 ) , FLOAT ( y2 ) + 0.5f ) ,
SolidBrush ( color ) ) ;
}
}
void
DWriteContext : : SetPixel ( int x , int y , COLORREF color )
{
if ( mDMode = = DM_INTEROP )
{
// GDI functions are used before this call. Keep using GDI.
// (Switching to Direct2D causes terrible slowdown.)
: : SetPixel ( mInteropHDC , x , y , color ) ;
}
else
{
SetDrawingMode ( DM_DIRECTX ) ;
// Direct2D doesn't have SetPixel API. Use DrawLine instead.
mRT - > DrawLine (
D2D1 : : Point2F ( FLOAT ( x ) , FLOAT ( y ) + 0.5f ) ,
D2D1 : : Point2F ( FLOAT ( x + 1 ) , FLOAT ( y ) + 0.5f ) ,
SolidBrush ( color ) ) ;
2017-11-26 14:29:32 +01:00
}
2014-08-06 14:52:30 +02:00
}
2018-01-31 20:51:47 +01:00
void
DWriteContext : : Scroll ( int x , int y , const RECT * rc )
{
SetDrawingMode ( DM_DIRECTX ) ;
mRT - > Flush ( ) ;
D2D1_RECT_U srcRect ;
D2D1_POINT_2U destPoint ;
if ( x > = 0 )
{
srcRect . left = rc - > left ;
srcRect . right = rc - > right - x ;
destPoint . x = rc - > left + x ;
}
else
{
srcRect . left = rc - > left - x ;
srcRect . right = rc - > right ;
destPoint . x = rc - > left ;
}
if ( y > = 0 )
{
srcRect . top = rc - > top ;
srcRect . bottom = rc - > bottom - y ;
destPoint . y = rc - > top + y ;
}
else
{
srcRect . top = rc - > top - y ;
srcRect . bottom = rc - > bottom ;
destPoint . y = rc - > top ;
}
mBitmap - > CopyFromRenderTarget ( & destPoint , mRT , & srcRect ) ;
D2D1_RECT_F destRect = {
FLOAT ( destPoint . x ) , FLOAT ( destPoint . y ) ,
FLOAT ( destPoint . x + srcRect . right - srcRect . left ) ,
FLOAT ( destPoint . y + srcRect . bottom - srcRect . top )
} ;
mRT - > DrawBitmap ( mBitmap , destRect , 1.0F ,
D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR , destRect ) ;
}
2017-12-05 13:22:16 +01:00
void
DWriteContext : : Flush ( )
{
SetDrawingMode ( DM_GDI ) ;
}
2014-08-06 14:52:30 +02:00
void
DWriteContext : : SetRenderingParams (
const DWriteRenderingParams * params )
{
if ( mDWriteFactory = = NULL )
return ;
IDWriteRenderingParams * renderingParams = NULL ;
D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
D2D1_TEXT_ANTIALIAS_MODE_DEFAULT ;
HRESULT hr ;
if ( params ! = NULL )
{
hr = mDWriteFactory - > CreateCustomRenderingParams ( params - > gamma ,
params - > enhancedContrast , params - > clearTypeLevel ,
ToPixelGeometry ( params - > pixelGeometry ) ,
ToRenderingMode ( params - > renderingMode ) , & renderingParams ) ;
textAntialiasMode = ToTextAntialiasMode ( params - > textAntialiasMode ) ;
}
else
hr = mDWriteFactory - > CreateRenderingParams ( & renderingParams ) ;
if ( SUCCEEDED ( hr ) & & renderingParams ! = NULL )
{
SafeRelease ( & mRenderingParams ) ;
mRenderingParams = renderingParams ;
mTextAntialiasMode = textAntialiasMode ;
2017-11-26 14:29:32 +01:00
Flush ( ) ;
mRT - > SetTextRenderingParams ( mRenderingParams ) ;
mRT - > SetTextAntialiasMode ( mTextAntialiasMode ) ;
2014-08-06 14:52:30 +02:00
}
}
DWriteRenderingParams *
DWriteContext : : GetRenderingParams (
DWriteRenderingParams * params )
{
if ( params ! = NULL & & mRenderingParams ! = NULL )
{
params - > gamma = mRenderingParams - > GetGamma ( ) ;
params - > enhancedContrast = mRenderingParams - > GetEnhancedContrast ( ) ;
params - > clearTypeLevel = mRenderingParams - > GetClearTypeLevel ( ) ;
params - > pixelGeometry = ToInt ( mRenderingParams - > GetPixelGeometry ( ) ) ;
params - > renderingMode = ToInt ( mRenderingParams - > GetRenderingMode ( ) ) ;
params - > textAntialiasMode = mTextAntialiasMode ;
}
return params ;
}
////////////////////////////////////////////////////////////////////////////
// PUBLIC C INTERFACES
void
DWrite_Init ( void )
{
# ifdef DYNAMIC_DIRECTX
// Load libraries.
2022-02-12 11:18:37 +00:00
hD2D1DLL = vimLoadLib ( " d2d1.dll " ) ;
hDWriteDLL = vimLoadLib ( " dwrite.dll " ) ;
2014-08-06 14:52:30 +02:00
if ( hD2D1DLL = = NULL | | hDWriteDLL = = NULL )
{
DWrite_Final ( ) ;
return ;
}
// Get address of procedures.
pGetUserDefaultLocaleName = ( PGETUSERDEFAULTLOCALENAME ) GetProcAddress (
GetModuleHandle ( " kernel32.dll " ) , " GetUserDefaultLocaleName " ) ;
pD2D1CreateFactory = ( PD2D1CREATEFACTORY ) GetProcAddress ( hD2D1DLL ,
" D2D1CreateFactory " ) ;
pDWriteCreateFactory = ( PDWRITECREATEFACTORY ) GetProcAddress ( hDWriteDLL ,
" DWriteCreateFactory " ) ;
# endif
}
void
DWrite_Final ( void )
{
# ifdef DYNAMIC_DIRECTX
pGetUserDefaultLocaleName = NULL ;
pD2D1CreateFactory = NULL ;
pDWriteCreateFactory = NULL ;
unload ( hDWriteDLL ) ;
unload ( hD2D1DLL ) ;
# endif
}
DWriteContext *
DWriteContext_Open ( void )
{
# ifdef DYNAMIC_DIRECTX
if ( pGetUserDefaultLocaleName = = NULL | | pD2D1CreateFactory = = NULL
| | pDWriteCreateFactory = = NULL )
return NULL ;
# endif
return new DWriteContext ( ) ;
}
void
2017-12-05 13:22:16 +01:00
DWriteContext_BindDC ( DWriteContext * ctx , HDC hdc , const RECT * rect )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
if ( ctx ! = NULL )
ctx - > BindDC ( hdc , rect ) ;
2014-08-06 14:52:30 +02:00
}
void
DWriteContext_SetFont ( DWriteContext * ctx , HFONT hFont )
{
if ( ctx ! = NULL )
ctx - > SetFont ( hFont ) ;
}
void
DWriteContext_DrawText (
DWriteContext * ctx ,
2017-12-05 13:22:16 +01:00
const WCHAR * text ,
2014-08-06 14:52:30 +02:00
int len ,
int x ,
int y ,
int w ,
int h ,
int cellWidth ,
2017-11-26 14:29:32 +01:00
COLORREF color ,
UINT fuOptions ,
2017-12-05 13:22:16 +01:00
const RECT * lprc ,
const INT * lpDx )
2014-08-06 14:52:30 +02:00
{
if ( ctx ! = NULL )
2017-11-26 14:29:32 +01:00
ctx - > DrawText ( text , len , x , y , w , h , cellWidth , color ,
fuOptions , lprc , lpDx ) ;
2014-08-06 14:52:30 +02:00
}
void
2017-12-05 13:22:16 +01:00
DWriteContext_FillRect ( DWriteContext * ctx , const RECT * rc , COLORREF color )
2014-08-06 14:52:30 +02:00
{
2017-11-26 14:29:32 +01:00
if ( ctx ! = NULL )
ctx - > FillRect ( rc , color ) ;
}
2017-12-05 13:22:16 +01:00
void
DWriteContext_DrawLine ( DWriteContext * ctx , int x1 , int y1 , int x2 , int y2 ,
COLORREF color )
{
if ( ctx ! = NULL )
ctx - > DrawLine ( x1 , y1 , x2 , y2 , color ) ;
}
void
DWriteContext_SetPixel ( DWriteContext * ctx , int x , int y , COLORREF color )
{
if ( ctx ! = NULL )
ctx - > SetPixel ( x , y , color ) ;
}
2018-01-31 20:51:47 +01:00
void
DWriteContext_Scroll ( DWriteContext * ctx , int x , int y , const RECT * rc )
{
if ( ctx ! = NULL )
ctx - > Scroll ( x , y , rc ) ;
}
2017-11-26 14:29:32 +01:00
void
DWriteContext_Flush ( DWriteContext * ctx )
{
if ( ctx ! = NULL )
ctx - > Flush ( ) ;
2014-08-06 14:52:30 +02:00
}
void
DWriteContext_Close ( DWriteContext * ctx )
{
delete ctx ;
}
void
DWriteContext_SetRenderingParams (
DWriteContext * ctx ,
const DWriteRenderingParams * params )
{
if ( ctx ! = NULL )
ctx - > SetRenderingParams ( params ) ;
}
DWriteRenderingParams *
DWriteContext_GetRenderingParams (
DWriteContext * ctx ,
DWriteRenderingParams * params )
{
if ( ctx ! = NULL )
return ctx - > GetRenderingParams ( params ) ;
else
return NULL ;
}