2015-12-22 15:00:51 -06:00
// 22 december 2015
2016-04-23 15:49:46 -05:00
# include "uipriv_windows.hpp"
2016-05-05 20:49:50 -05:00
# include "draw.hpp"
2016-04-23 15:49:46 -05:00
// TODO really migrate
2015-12-22 15:00:51 -06:00
2015-12-23 14:19:40 -06:00
// notes:
// only available in windows 8 and newer:
// - character spacing
// - kerning control
// - justficiation (how could I possibly be making this up?!)
2015-12-23 14:22:01 -06:00
// - vertical text (SERIOUSLY?! WHAT THE ACTUAL FUCK, MICROSOFT?!?!?!? DID YOU NOT THINK ABOUT THIS THE FIRST TIME, TRYING TO IMPROVE THE INTERNATIONALIZATION OF WINDOWS 7?!?!?! bonus: some parts of MSDN even say 8.1 and up only!)
2015-12-23 14:19:40 -06:00
2015-12-22 19:01:53 -06:00
struct uiDrawFontFamilies {
2016-04-14 18:57:58 -05:00
fontCollection * fc ;
2015-12-22 19:01:53 -06:00
} ;
uiDrawFontFamilies * uiDrawListFontFamilies ( void )
{
2016-04-14 18:57:58 -05:00
struct uiDrawFontFamilies * ff ;
2015-12-22 19:01:53 -06:00
2016-04-14 18:57:58 -05:00
ff = uiNew ( struct uiDrawFontFamilies ) ;
ff - > fc = loadFontCollection ( ) ;
2015-12-22 19:01:53 -06:00
return ff ;
}
uintmax_t uiDrawFontFamiliesNumFamilies ( uiDrawFontFamilies * ff )
{
2016-04-14 18:57:58 -05:00
return ff - > fc - > fonts - > GetFontFamilyCount ( ) ;
2015-12-22 19:01:53 -06:00
}
char * uiDrawFontFamiliesFamily ( uiDrawFontFamilies * ff , uintmax_t n )
{
IDWriteFontFamily * family ;
WCHAR * wname ;
char * name ;
HRESULT hr ;
2016-04-14 18:57:58 -05:00
hr = ff - > fc - > fonts - > GetFontFamily ( n , & family ) ;
2015-12-22 19:01:53 -06:00
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error getting font out of collection " , hr ) ;
2016-04-14 18:57:58 -05:00
wname = fontCollectionFamilyName ( ff - > fc , family ) ;
2015-12-22 19:01:53 -06:00
name = toUTF8 ( wname ) ;
uiFree ( wname ) ;
family - > Release ( ) ;
return name ;
}
void uiDrawFreeFontFamilies ( uiDrawFontFamilies * ff )
{
2016-04-14 18:57:58 -05:00
fontCollectionFree ( ff - > fc ) ;
2015-12-22 19:01:53 -06:00
uiFree ( ff ) ;
}
2015-12-31 11:30:53 -06:00
2016-01-12 17:14:48 -06:00
struct uiDrawTextFont {
IDWriteFont * f ;
WCHAR * family ; // save for convenience in uiDrawNewTextLayout()
double size ;
2016-01-09 00:07:48 -06:00
} ;
2016-04-20 13:17:55 -05:00
uiDrawTextFont * mkTextFont ( IDWriteFont * df , BOOL addRef , WCHAR * family , BOOL copyFamily , double size )
2016-04-18 18:18:29 -05:00
{
uiDrawTextFont * font ;
WCHAR * copy ;
HRESULT hr ;
font = uiNew ( uiDrawTextFont ) ;
font - > f = df ;
2016-04-20 13:17:55 -05:00
if ( addRef )
font - > f - > AddRef ( ) ;
2016-04-18 18:18:29 -05:00
if ( copyFamily ) {
copy = ( WCHAR * ) uiAlloc ( ( wcslen ( family ) + 1 ) * sizeof ( WCHAR ) , " WCHAR[] " ) ;
wcscpy ( copy , family ) ;
font - > family = copy ;
} else
font - > family = family ;
font - > size = size ;
return font ;
}
2016-04-17 23:56:13 -05:00
// TODO consider moving these all to dwrite.cpp
2016-01-09 01:23:01 -06:00
static const struct {
bool lastOne ;
uiDrawTextWeight uival ;
DWRITE_FONT_WEIGHT dwval ;
} dwriteWeights [ ] = {
{ false , uiDrawTextWeightThin , DWRITE_FONT_WEIGHT_THIN } ,
{ false , uiDrawTextWeightUltraLight , DWRITE_FONT_WEIGHT_ULTRA_LIGHT } ,
{ false , uiDrawTextWeightLight , DWRITE_FONT_WEIGHT_LIGHT } ,
{ false , uiDrawTextWeightBook , DWRITE_FONT_WEIGHT_SEMI_LIGHT } ,
{ false , uiDrawTextWeightNormal , DWRITE_FONT_WEIGHT_NORMAL } ,
{ false , uiDrawTextWeightMedium , DWRITE_FONT_WEIGHT_MEDIUM } ,
{ false , uiDrawTextWeightSemiBold , DWRITE_FONT_WEIGHT_SEMI_BOLD } ,
{ false , uiDrawTextWeightBold , DWRITE_FONT_WEIGHT_BOLD } ,
{ false , uiDrawTextWeightUtraBold , DWRITE_FONT_WEIGHT_ULTRA_BOLD } ,
{ false , uiDrawTextWeightHeavy , DWRITE_FONT_WEIGHT_HEAVY } ,
{ true , uiDrawTextWeightUltraHeavy , DWRITE_FONT_WEIGHT_ULTRA_BLACK , } ,
2016-01-09 00:07:48 -06:00
} ;
2016-01-09 01:23:01 -06:00
static const struct {
bool lastOne ;
uiDrawTextItalic uival ;
DWRITE_FONT_STYLE dwval ;
} dwriteItalics [ ] = {
{ false , uiDrawTextItalicNormal , DWRITE_FONT_STYLE_NORMAL } ,
{ false , uiDrawTextItalicOblique , DWRITE_FONT_STYLE_OBLIQUE } ,
{ true , uiDrawTextItalicItalic , DWRITE_FONT_STYLE_ITALIC } ,
2016-01-09 00:07:48 -06:00
} ;
2016-01-09 01:23:01 -06:00
static const struct {
bool lastOne ;
uiDrawTextStretch uival ;
DWRITE_FONT_STRETCH dwval ;
} dwriteStretches [ ] = {
{ false , uiDrawTextStretchUltraCondensed , DWRITE_FONT_STRETCH_ULTRA_CONDENSED } ,
{ false , uiDrawTextStretchExtraCondensed , DWRITE_FONT_STRETCH_EXTRA_CONDENSED } ,
{ false , uiDrawTextStretchCondensed , DWRITE_FONT_STRETCH_CONDENSED } ,
{ false , uiDrawTextStretchSemiCondensed , DWRITE_FONT_STRETCH_SEMI_CONDENSED } ,
{ false , uiDrawTextStretchNormal , DWRITE_FONT_STRETCH_NORMAL } ,
{ false , uiDrawTextStretchSemiExpanded , DWRITE_FONT_STRETCH_SEMI_EXPANDED } ,
{ false , uiDrawTextStretchExpanded , DWRITE_FONT_STRETCH_EXPANDED } ,
{ false , uiDrawTextStretchExtraExpanded , DWRITE_FONT_STRETCH_EXTRA_EXPANDED } ,
{ true , uiDrawTextStretchUltraExpanded , DWRITE_FONT_STRETCH_ULTRA_EXPANDED } ,
2016-01-09 00:07:48 -06:00
} ;
2016-04-17 23:41:17 -05:00
void attrToDWriteAttr ( struct dwriteAttr * attr )
2016-01-09 00:07:48 -06:00
{
2016-01-09 01:23:01 -06:00
bool found ;
int i ;
2016-01-09 00:07:48 -06:00
2016-04-17 23:41:17 -05:00
found = false ;
for ( i = 0 ; ; i + + ) {
if ( dwriteWeights [ i ] . uival = = attr - > weight ) {
attr - > dweight = dwriteWeights [ i ] . dwval ;
found = true ;
break ;
}
if ( dwriteWeights [ i ] . lastOne )
break ;
}
if ( ! found )
complain ( " invalid weight %d passed to attrToDWriteAttr() " , attr - > weight ) ;
2016-01-12 17:14:48 -06:00
2016-04-17 23:41:17 -05:00
found = false ;
for ( i = 0 ; ; i + + ) {
if ( dwriteItalics [ i ] . uival = = attr - > italic ) {
attr - > ditalic = dwriteItalics [ i ] . dwval ;
found = true ;
break ;
}
if ( dwriteItalics [ i ] . lastOne )
break ;
}
if ( ! found )
complain ( " invalid italic %d passed to attrToDWriteAttr() " , attr - > italic ) ;
2016-01-09 00:07:48 -06:00
2016-01-09 01:23:01 -06:00
found = false ;
for ( i = 0 ; ; i + + ) {
2016-04-17 23:41:17 -05:00
if ( dwriteStretches [ i ] . uival = = attr - > stretch ) {
attr - > dstretch = dwriteStretches [ i ] . dwval ;
2016-01-09 01:23:01 -06:00
found = true ;
break ;
}
2016-04-17 23:41:17 -05:00
if ( dwriteStretches [ i ] . lastOne )
2016-01-09 01:23:01 -06:00
break ;
}
if ( ! found )
2016-04-17 23:41:17 -05:00
complain ( " invalid stretch %d passed to attrToDWriteAttr() " , attr - > stretch ) ;
}
void dwriteAttrToAttr ( struct dwriteAttr * attr )
{
int weight , against , n ;
int curdiff , curindex ;
bool found ;
int i ;
// weight is scaled; we need to test to see what's nearest
weight = ( int ) ( attr - > dweight ) ;
against = ( int ) ( dwriteWeights [ 0 ] . dwval ) ;
curdiff = abs ( against - weight ) ;
curindex = 0 ;
for ( i = 1 ; ; i + + ) {
against = ( int ) ( dwriteWeights [ i ] . dwval ) ;
n = abs ( against - weight ) ;
if ( n < curdiff ) {
curdiff = n ;
curindex = i ;
}
if ( dwriteWeights [ i ] . lastOne )
break ;
}
attr - > weight = dwriteWeights [ i ] . uival ;
2016-01-09 01:23:01 -06:00
2016-04-17 23:41:17 -05:00
// italic and stretch are simple values; we can just do a matching search
2016-01-09 01:23:01 -06:00
found = false ;
for ( i = 0 ; ; i + + ) {
2016-04-17 23:41:17 -05:00
if ( dwriteItalics [ i ] . dwval = = attr - > ditalic ) {
attr - > italic = dwriteItalics [ i ] . uival ;
2016-01-09 01:23:01 -06:00
found = true ;
break ;
}
if ( dwriteItalics [ i ] . lastOne )
break ;
}
if ( ! found )
2016-04-17 23:41:17 -05:00
complain ( " invalid italic %d passed to dwriteAttrToAttr() " , attr - > ditalic ) ;
2016-01-09 01:23:01 -06:00
found = false ;
for ( i = 0 ; ; i + + ) {
2016-04-17 23:41:17 -05:00
if ( dwriteStretches [ i ] . dwval = = attr - > dstretch ) {
attr - > stretch = dwriteStretches [ i ] . uival ;
2016-01-09 01:23:01 -06:00
found = true ;
break ;
}
if ( dwriteStretches [ i ] . lastOne )
break ;
}
if ( ! found )
2016-04-17 23:41:17 -05:00
complain ( " invalid stretch %d passed to dwriteAttrToAttr() " , attr - > dstretch ) ;
}
uiDrawTextFont * uiDrawLoadClosestFont ( const uiDrawTextFontDescriptor * desc )
{
uiDrawTextFont * font ;
IDWriteFontCollection * collection ;
UINT32 index ;
BOOL exists ;
struct dwriteAttr attr ;
IDWriteFontFamily * family ;
2016-04-18 18:18:29 -05:00
WCHAR * wfamily ;
IDWriteFont * match ;
2016-04-17 23:41:17 -05:00
HRESULT hr ;
// always get the latest available font information
hr = dwfactory - > GetSystemFontCollection ( & collection , TRUE ) ;
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error getting system font collection " , hr ) ;
2016-04-17 23:41:17 -05:00
2016-04-18 18:18:29 -05:00
wfamily = toUTF16 ( desc - > Family ) ;
hr = collection - > FindFamilyName ( wfamily , & index , & exists ) ;
2016-04-17 23:41:17 -05:00
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error finding font family " , hr ) ;
2016-04-17 23:41:17 -05:00
if ( ! exists )
complain ( " TODO family not found in uiDrawLoadClosestFont() " , hr ) ;
hr = collection - > GetFontFamily ( index , & family ) ;
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error loading font family " , hr ) ;
2016-04-17 23:41:17 -05:00
attr . weight = desc - > Weight ;
attr . italic = desc - > Italic ;
attr . stretch = desc - > Stretch ;
attrToDWriteAttr ( & attr ) ;
hr = family - > GetFirstMatchingFont (
attr . dweight ,
attr . dstretch ,
attr . ditalic ,
2016-04-18 18:18:29 -05:00
& match ) ;
2016-01-12 17:14:48 -06:00
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error loading font " , hr ) ;
2016-01-12 17:14:48 -06:00
2016-04-18 18:18:29 -05:00
font = mkTextFont ( match ,
2016-04-20 13:17:55 -05:00
FALSE , // we own the initial reference; no need to add another one
2016-04-18 18:18:29 -05:00
wfamily , FALSE , // will be freed with font
desc - > Size ) ;
2016-01-12 17:14:48 -06:00
family - > Release ( ) ;
collection - > Release ( ) ;
return font ;
}
void uiDrawFreeTextFont ( uiDrawTextFont * font )
{
font - > f - > Release ( ) ;
uiFree ( font - > family ) ;
uiFree ( font ) ;
}
uintptr_t uiDrawTextFontHandle ( uiDrawTextFont * font )
{
return ( uintptr_t ) ( font - > f ) ;
}
void uiDrawTextFontDescribe ( uiDrawTextFont * font , uiDrawTextFontDescriptor * desc )
{
// TODO
desc - > Size = font - > size ;
// TODO
}
2016-01-12 23:54:52 -06:00
// text sizes are 1/72 of an inch
// points in Direct2D are 1/96 of an inch (https://msdn.microsoft.com/en-us/library/windows/desktop/ff684173%28v=vs.85%29.aspx, https://msdn.microsoft.com/en-us/library/windows/desktop/hh447022%28v=vs.85%29.aspx)
// As for the actual conversion from design units, see:
// - http://cboard.cprogramming.com/windows-programming/136733-directwrite-font-height-issues.html
// - https://sourceforge.net/p/vstgui/mailman/message/32483143/
// - http://xboxforums.create.msdn.com/forums/t/109445.aspx
// - https://msdn.microsoft.com/en-us/library/dd183564%28v=vs.85%29.aspx
// - http://www.fontbureau.com/blog/the-em/
2016-01-16 15:42:33 -06:00
// TODO make points here about how DIPs in DirectWrite == DIPs in Direct2D; if not, figure out what they really are? for the width and layout functions later
2016-01-12 23:54:52 -06:00
static double scaleUnits ( double what , double designUnitsPerEm , double size )
{
return ( what / designUnitsPerEm ) * ( size * ( 96.0 / 72.0 ) ) ;
}
void uiDrawTextFontGetMetrics ( uiDrawTextFont * font , uiDrawTextFontMetrics * metrics )
{
DWRITE_FONT_METRICS dm ;
font - > f - > GetMetrics ( & dm ) ;
metrics - > Ascent = scaleUnits ( dm . ascent , dm . designUnitsPerEm , font - > size ) ;
metrics - > Descent = scaleUnits ( dm . descent , dm . designUnitsPerEm , font - > size ) ;
// TODO what happens if dm.xxx is negative?
2016-05-06 09:31:01 -05:00
// TODO remember what this was for
2016-01-12 23:54:52 -06:00
metrics - > Leading = scaleUnits ( dm . lineGap , dm . designUnitsPerEm , font - > size ) ;
metrics - > UnderlinePos = scaleUnits ( dm . underlinePosition , dm . designUnitsPerEm , font - > size ) ;
metrics - > UnderlineThickness = scaleUnits ( dm . underlineThickness , dm . designUnitsPerEm , font - > size ) ;
}
2016-04-19 17:45:16 -05:00
// some attributes, such as foreground color, can't be applied until after we establish a Direct2D context :/ so we have to prepare all attributes in advance
// also since there's no way to clear the attributes from a layout en masse (apart from overwriting them all), we'll play it safe by creating a new layout each time
enum layoutAttrType {
layoutAttrColor ,
} ;
struct layoutAttr {
enum layoutAttrType type ;
intmax_t start ;
intmax_t end ;
double components [ 4 ] ;
} ;
2016-01-12 17:14:48 -06:00
struct uiDrawTextLayout {
2016-04-19 17:45:16 -05:00
WCHAR * text ;
size_t textlen ;
double width ;
2016-01-12 17:14:48 -06:00
IDWriteTextFormat * format ;
2016-04-19 17:45:16 -05:00
std : : vector < struct layoutAttr > * attrs ;
2016-01-12 17:14:48 -06:00
} ;
2016-01-16 15:42:33 -06:00
uiDrawTextLayout * uiDrawNewTextLayout ( const char * text , uiDrawTextFont * defaultFont , double width )
2016-01-12 17:14:48 -06:00
{
uiDrawTextLayout * layout ;
HRESULT hr ;
layout = uiNew ( uiDrawTextLayout ) ;
hr = dwfactory - > CreateTextFormat ( defaultFont - > family ,
NULL ,
defaultFont - > f - > GetWeight ( ) ,
defaultFont - > f - > GetStyle ( ) ,
defaultFont - > f - > GetStretch ( ) ,
2016-01-09 00:07:48 -06:00
// typographic points are 1/72 inch; this parameter is 1/96 inch
// fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx
2016-01-12 17:14:48 -06:00
defaultFont - > size * ( 96.0 / 72.0 ) ,
2016-01-09 00:07:48 -06:00
// see http://stackoverflow.com/questions/28397971/idwritefactorycreatetextformat-failing and https://msdn.microsoft.com/en-us/library/windows/desktop/dd368203.aspx
// TODO use the current locale again?
L " " ,
& ( layout - > format ) ) ;
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error creating IDWriteTextFormat " , hr ) ;
2016-01-09 00:07:48 -06:00
2016-04-19 17:45:16 -05:00
layout - > text = toUTF16 ( text ) ;
layout - > textlen = wcslen ( layout - > text ) ;
2016-01-09 00:07:48 -06:00
2016-01-16 15:42:33 -06:00
uiDrawTextLayoutSetWidth ( layout , width ) ;
2016-04-19 17:45:16 -05:00
layout - > attrs = new std : : vector < struct layoutAttr > ;
2016-01-09 00:07:48 -06:00
return layout ;
}
void uiDrawFreeTextLayout ( uiDrawTextLayout * layout )
{
2016-04-19 17:45:16 -05:00
delete layout - > attrs ;
2016-01-09 00:07:48 -06:00
layout - > format - > Release ( ) ;
2016-04-19 17:45:16 -05:00
uiFree ( layout - > text ) ;
2016-01-09 00:07:48 -06:00
uiFree ( layout ) ;
}
2016-05-06 09:31:01 -05:00
static ID2D1SolidColorBrush * mkSolidBrush ( ID2D1RenderTarget * rt , double r , double g , double b , double a )
{
D2D1_BRUSH_PROPERTIES props ;
D2D1_COLOR_F color ;
ID2D1SolidColorBrush * brush ;
HRESULT hr ;
ZeroMemory ( & props , sizeof ( D2D1_BRUSH_PROPERTIES ) ) ;
props . opacity = 1.0 ;
// identity matrix
props . transform . _11 = 1 ;
props . transform . _22 = 1 ;
color . r = r ;
color . g = g ;
color . b = b ;
color . a = a ;
hr = rt - > CreateSolidColorBrush (
& color ,
& props ,
& brush ) ;
if ( hr ! = S_OK )
logHRESULT ( L " error creating solid brush " , hr ) ;
return brush ;
}
2016-04-19 17:45:16 -05:00
IDWriteTextLayout * prepareLayout ( uiDrawTextLayout * layout , ID2D1RenderTarget * rt )
2016-01-16 15:42:33 -06:00
{
2016-04-19 17:45:16 -05:00
IDWriteTextLayout * dl ;
DWRITE_TEXT_RANGE range ;
IUnknown * unkBrush ;
2016-01-16 15:42:33 -06:00
DWRITE_WORD_WRAPPING wrap ;
FLOAT maxWidth ;
HRESULT hr ;
2016-04-19 17:45:16 -05:00
hr = dwfactory - > CreateTextLayout ( layout - > text , layout - > textlen ,
layout - > format ,
// FLOAT is float, not double, so this should work... TODO
FLT_MAX , FLT_MAX ,
& dl ) ;
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error creating IDWriteTextLayout " , hr ) ;
2016-04-19 17:45:16 -05:00
for ( const struct layoutAttr & attr : * ( layout - > attrs ) ) {
range . startPosition = attr . start ;
range . length = attr . end - attr . start ;
switch ( attr . type ) {
case layoutAttrColor :
if ( rt = = NULL ) // determining extents, not drawing
break ;
2016-05-06 09:31:01 -05:00
unkBrush = mkSolidBrush ( rt ,
attr . components [ 0 ] ,
attr . components [ 1 ] ,
attr . components [ 2 ] ,
attr . components [ 3 ] ) ;
2016-04-19 17:45:16 -05:00
hr = dl - > SetDrawingEffect ( unkBrush , range ) ;
unkBrush - > Release ( ) ; // associated with dl
break ;
default :
hr = E_FAIL ;
2016-04-23 21:15:33 -05:00
logHRESULT ( L " invalid text attribute type " , hr ) ;
2016-04-19 17:45:16 -05:00
}
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error adding attribute to text layout " , hr ) ;
2016-04-19 17:45:16 -05:00
}
// and set the width
2016-01-16 15:42:33 -06:00
// this is the only wrapping mode (apart from "no wrap") available prior to Windows 8.1
wrap = DWRITE_WORD_WRAPPING_WRAP ;
2016-04-19 17:45:16 -05:00
maxWidth = layout - > width ;
if ( layout - > width < 0 ) {
2016-01-16 15:42:33 -06:00
wrap = DWRITE_WORD_WRAPPING_NO_WRAP ;
// setting the max width in this case technically isn't needed since the wrap mode will simply ignore the max width, but let's do it just to be safe
maxWidth = FLT_MAX ; // see TODO above
}
2016-04-19 17:45:16 -05:00
hr = dl - > SetWordWrapping ( wrap ) ;
2016-01-16 15:42:33 -06:00
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error setting word wrapping mode " , hr ) ;
2016-04-19 17:45:16 -05:00
hr = dl - > SetMaxWidth ( maxWidth ) ;
2016-01-16 15:42:33 -06:00
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error setting max layout width " , hr ) ;
2016-04-19 17:45:16 -05:00
return dl ;
}
void uiDrawTextLayoutSetWidth ( uiDrawTextLayout * layout , double width )
{
layout - > width = width ;
2016-01-16 15:42:33 -06:00
}
2016-01-16 17:22:27 -06:00
// TODO for a single line the height includes the leading; it should not
2016-01-16 15:42:33 -06:00
void uiDrawTextLayoutExtents ( uiDrawTextLayout * layout , double * width , double * height )
{
2016-04-19 17:45:16 -05:00
IDWriteTextLayout * dl ;
2016-01-16 15:42:33 -06:00
DWRITE_TEXT_METRICS metrics ;
HRESULT hr ;
2016-04-19 17:45:16 -05:00
dl = prepareLayout ( layout , NULL ) ;
hr = dl - > GetMetrics ( & metrics ) ;
2016-01-16 15:42:33 -06:00
if ( hr ! = S_OK )
2016-04-23 21:15:33 -05:00
logHRESULT ( L " error getting layout metrics " , hr ) ;
2016-01-16 15:42:33 -06:00
* width = metrics . width ;
// TODO make sure the behavior of this on empty strings is the same on all platforms
* height = metrics . height ;
2016-04-19 17:45:16 -05:00
dl - > Release ( ) ;
2016-01-16 15:42:33 -06:00
}
2016-05-06 09:31:01 -05:00
void uiDrawText ( uiDrawContext * c , double x , double y , uiDrawTextLayout * layout )
2016-01-09 00:07:48 -06:00
{
2016-04-19 17:45:16 -05:00
IDWriteTextLayout * dl ;
2016-01-09 00:07:48 -06:00
D2D1_POINT_2F pt ;
2016-05-06 09:31:01 -05:00
ID2D1Brush * black ;
2016-01-09 00:07:48 -06:00
HRESULT hr ;
2016-05-06 09:31:01 -05:00
// TODO document that fully opaque black is the default text color; figure out whether this is upheld in various scenarios on other platforms
black = mkSolidBrush ( c - > rt , 0.0 , 0.0 , 0.0 , 1.0 ) ;
dl = prepareLayout ( layout , c - > rt ) ;
2016-01-09 00:07:48 -06:00
pt . x = x ;
pt . y = y ;
// TODO D2D1_DRAW_TEXT_OPTIONS_NO_SNAP?
// TODO D2D1_DRAW_TEXT_OPTIONS_CLIP?
// TODO when setting 8.1 as minimum, D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT?
2016-05-06 09:31:01 -05:00
c - > rt - > DrawTextLayout ( pt , dl , black , D2D1_DRAW_TEXT_OPTIONS_NONE ) ;
2016-04-19 17:45:16 -05:00
dl - > Release ( ) ;
2016-05-06 09:31:01 -05:00
black - > Release ( ) ;
2016-04-19 17:45:16 -05:00
}
void uiDrawTextLayoutSetColor ( uiDrawTextLayout * layout , intmax_t startChar , intmax_t endChar , double r , double g , double b , double a )
{
struct layoutAttr attr ;
attr . type = layoutAttrColor ;
attr . start = startChar ;
attr . end = endChar ;
attr . components [ 0 ] = r ;
attr . components [ 1 ] = g ;
attr . components [ 2 ] = b ;
attr . components [ 3 ] = a ;
layout - > attrs - > push_back ( attr ) ;
2015-12-31 11:30:53 -06:00
}