2017-01-17 20:06:45 -06:00
// 17 january 2017
2016-05-05 17:23:54 -05:00
# include "uipriv_unix.h"
# include "draw.h"
2017-01-17 20:06:45 -06:00
struct uiDrawTextLayout {
PangoLayout * layout ;
2016-05-05 17:23:54 -05:00
} ;
2017-01-17 20:06:45 -06:00
// See https://developer.gnome.org/pango/1.30/pango-Cairo-Rendering.html#pango-Cairo-Rendering.description
// For the conversion, see https://developer.gnome.org/pango/1.30/pango-Glyph-Storage.html#pango-units-to-double and https://developer.gnome.org/pango/1.30/pango-Glyph-Storage.html#pango-units-from-double
# define pangoToCairo(pango) (pango_units_to_double(pango))
# define cairoToPango(cairo) (pango_units_from_double(cairo))
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
// we need a context for a few things
// the documentation suggests creating cairo_t-specific, GdkScreen-specific, or even GtkWidget-specific contexts, but we can't really do that because we want our uiDrawTextFonts and uiDrawTextLayouts to be context-independent
// we could use pango_font_map_create_context(pango_cairo_font_map_get_default()) but that will ignore GDK-specific settings
// so let's use gdk_pango_context_get() instead; even though it's for the default screen only, it's good enough for us
# define mkGenericPangoCairoContext() (gdk_pango_context_get())
2016-05-05 17:23:54 -05:00
static const PangoStyle pangoItalics [ ] = {
[ uiDrawTextItalicNormal ] = PANGO_STYLE_NORMAL ,
[ uiDrawTextItalicOblique ] = PANGO_STYLE_OBLIQUE ,
[ uiDrawTextItalicItalic ] = PANGO_STYLE_ITALIC ,
} ;
static const PangoStretch pangoStretches [ ] = {
[ uiDrawTextStretchUltraCondensed ] = PANGO_STRETCH_ULTRA_CONDENSED ,
[ uiDrawTextStretchExtraCondensed ] = PANGO_STRETCH_EXTRA_CONDENSED ,
[ uiDrawTextStretchCondensed ] = PANGO_STRETCH_CONDENSED ,
[ uiDrawTextStretchSemiCondensed ] = PANGO_STRETCH_SEMI_CONDENSED ,
[ uiDrawTextStretchNormal ] = PANGO_STRETCH_NORMAL ,
[ uiDrawTextStretchSemiExpanded ] = PANGO_STRETCH_SEMI_EXPANDED ,
[ uiDrawTextStretchExpanded ] = PANGO_STRETCH_EXPANDED ,
[ uiDrawTextStretchExtraExpanded ] = PANGO_STRETCH_EXTRA_EXPANDED ,
[ uiDrawTextStretchUltraExpanded ] = PANGO_STRETCH_ULTRA_EXPANDED ,
} ;
2017-01-17 20:06:45 -06:00
uiDrawTextLayout * uiDrawNewTextLayout ( uiAttributedString * s , uiDrawFontDescriptor * defaultFont , double width )
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
uiDrawTextLayout * tl ;
2016-05-05 17:23:54 -05:00
PangoContext * context ;
2017-01-17 20:06:45 -06:00
PangoFontDescription * desc ;
int pangoWidth ;
tl = uiNew ( uiDrawTextLayout ) ;
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
// in this case, the context is necessary to create the layout
// the layout takes a ref on the context so we can unref it afterward
2016-05-05 17:23:54 -05:00
context = mkGenericPangoCairoContext ( ) ;
2017-01-17 20:06:45 -06:00
tl - > layout = pango_layout_new ( context ) ;
2016-05-05 17:23:54 -05:00
g_object_unref ( context ) ;
2017-01-17 20:06:45 -06:00
// this is safe; pango_layout_set_text() copies the string
pango_layout_set_text ( tl - > layout , uiAttributedStringString ( s ) , - 1 ) ;
desc = pango_font_description_new ( ) ;
pango_font_description_set_family ( desc , defaultFont - > Family ) ;
pango_font_description_set_style ( desc , pangoItalics [ defaultFont - > Italic ] ) ;
// for the most part, pango weights correlate to ours
// the differences:
// - Book — libui: 350, Pango: 380
// - Ultra Heavy — libui: 950, Pango: 1000
// TODO figure out what to do about this misalignment
pango_font_description_set_weight ( desc , defaultFont - > Weight ) ;
pango_font_description_set_stretch ( desc , pangoStretches [ defaultFont - > Stretch ] ) ;
// see https://developer.gnome.org/pango/1.30/pango-Fonts.html#pango-font-description-set-size and https://developer.gnome.org/pango/1.30/pango-Glyph-Storage.html#pango-units-from-double
pango_font_description_set_size ( desc , pango_units_from_double ( defaultFont - > Size ) ) ;
pango_layout_set_font_description ( tl - > layout , desc ) ;
// this is safe; the description is copied
pango_font_description_free ( desc ) ;
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
pangoWidth = cairoToPango ( width ) ;
if ( width < 0 )
pangoWidth = - 1 ;
pango_layout_set_width ( tl - > layout , pangoWidth ) ;
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
// TODO attributes
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
return tl ;
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
void uiDrawFreeTextLayout ( uiDrawTextLayout * tl )
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
g_object_unref ( tl - > layout ) ;
uiFree ( tl ) ;
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
void uiDrawText ( uiDrawContext * c , uiDrawTextLayout * tl , double x , double y )
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
cairo_move_to ( c - > cr , x , y ) ;
pango_cairo_show_layout ( c - > cr , tl - > layout ) ;
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
void uiDrawTextLayoutExtents ( uiDrawTextLayout * tl , double * width , double * height )
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
PangoRectangle logical ;
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
pango_layout_get_extents ( tl - > layout , NULL , & logical ) ;
* width = pangoToCairo ( logical . width ) ;
* height = pangoToCairo ( logical . height ) ;
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
int uiDrawTextLayoutNumLines ( uiDrawTextLayout * tl )
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
return pango_layout_get_line_count ( tl - > layout ) ;
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
void uiDrawTextLayoutLineByteRange ( uiDrawTextLayout * tl , int line , size_t * start , size_t * end )
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
PangoLayoutLine * pll ;
pll = pango_layout_get_line_readonly ( tl - > layout , line ) ;
* start = pll - > start_index ;
* end = pll - > start_index + pll - > length ;
// TODO unref?
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
void uiDrawTextLayoutLineGetMetrics ( uiDrawTextLayout * tl , int line , uiDrawTextLayoutLineMetrics * m )
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
PangoLayoutLine * pll ;
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
pll = pango_layout_get_line_readonly ( tl - > layout , line ) ;
// TODO unref?
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
// TODO
#if 0
2016-05-05 17:23:54 -05:00
{
2017-01-17 20:06:45 -06:00
PangoLayoutLine * pll ;
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
pll = pango_layout_get_line_readonly ( tl - > layout , line ) ;
// TODO unref?
2016-05-05 17:23:54 -05:00
}
2017-01-17 20:06:45 -06:00
# endif
2016-05-05 17:23:54 -05:00
2017-01-17 20:06:45 -06:00
void uiDrawTextLayoutByteIndexToGraphemeRect ( uiDrawTextLayout * tl , size_t pos , int * line , double * x , double * y , double * width , double * height )
2016-05-05 17:23:54 -05:00
{
}
2017-01-17 20:06:45 -06:00
void uiDrawTextLayoutHitTest ( uiDrawTextLayout * tl , double x , double y , uiDrawTextLayoutHitTestResult * result )
2016-05-05 17:23:54 -05:00
{
}
2017-01-17 20:06:45 -06:00
void uiDrawTextLayoutByteRangeToRectangle ( uiDrawTextLayout * tl , size_t start , size_t end , uiDrawTextLayoutByteRangeRectangle * r )
2016-05-05 17:23:54 -05:00
{
}