Create Pango Layout Before Cairo Surface - c++

In my application, I am using Pango and Cairo to create text textures. These textures have their width fixed, but should scale their height to fit text contents. The parent objects involved in this situation will then scale their heights to match the text.
The problem is, the way I have been initializing Pango and Cairo does not allow for this. Currently, the system is set up by:
cairo_surface_t* cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, sizeX, sizeY );
cairo_t* cairoContext = cairo_create( cairoSurface );
PangoLayout* pangoLayout = pango_cairo_create_layout( cairoContext );
Which fixes the height, at least of the surface - something I do not want to do, at least not all the time.
My understanding is that if the layout height is not specified, it will automatically scale the height, which can then be found via pango_layout_get_size(). I would like to create the layout first and then use the output of this function to create the surface.
However, pango_cairo_create_layout() requires the surface to already be created, and I have been unable to find a way to render a layout from pango_layout_new() via Cairo. The API docs one of the render functions, pango_cairo_update_layout(), specify that pango_cairo_create_layout() had to be used to create the layout; however, the more important function, pango_cairo_show_layout(), notes no such requirement, and I am not sure if that means that any Pango layout is allowed or not. While I could test if it works, I'm afraid that trial and error could lead me to undefined behavior.
I feel like I'm stuck in a chicken and egg situation, and the documentation for Pango is mostly an API reference with little explanation of how the library is intended to be used. Is there a way to do this properly?

I've figured this process out. Hopefully the information is helpful - although I make no claims to this being the "correct" way to do any of this, just that this works.
First, set up FontConfig. This might not be necessary on some systems - it is probably OK to leave it automatic on Linux. On Windows, though, FontConfig is problematic. The easiest way to handle it is to create a config in memory and point it to where you want it to look for fonts. I pointed it to the resource directory of my program. You could use "C:\Windows\Fonts", but note this takes forever to load. Loading a proper font.conf file is probably the best approach, but I had little luck myself.
gchar* workingDir = g_get_current_dir();
gchar* resourceDir = g_strjoin( NULL, workingDir, "/Resources", (char*)0 );
FcConfigAppFontAddDir( fontConfig, (const FcChar8*)resourceDir );
g_free(workingDir);
g_free(resourceDir);
FcConfigBuildFonts( fontConfig );
FcConfigSetCurrent( fontConfig );
Then, you have to create a font map, Pango Context, and Pango Layout:
PangoFontMap* fontMap = pango_cairo_font_map_new();
PangoContext* pangoContext = pango_font_map_create_context( fontMap );
PangoLayout* pangoLayout = pango_layout_new( pangoContext );
Now, using a manually created (not from pango_cairo_create_layout()) layout doesn't seem to automatically load fonts. Trying to use a font that is in the font map but not loaded causes Pango-Cairo to crash (using one that is flat out not listed just goes to the default). As such, load all fonts listed in the font map:
FcPattern *p = FcPatternCreate();
FcObjectSet *os = FcObjectSetBuild(FC_FAMILY,NULL);
FcFontSet *fs = FcFontList(fontConfig, p, os);
FcPatternDestroy( p );
FcObjectSetDestroy( os );
for( int i = 0; i < fs->nfont; ++i )
{
guchar* fontName = FcNameUnparse( fs->fonts[i] );
PangoFontDescription* fontDesc = pango_font_description_from_string( (gchar*)fontName );
pango_font_map_load_font( fontMap, pangoContext, fontDesc );
pango_font_description_free( fontDesc );
g_free(fontName);
}
To specify the width:
pango_layout_set_width( pangoLayout, sizeX * PANGO_SCALE );
This is also around the point you should set justification/alignment/etc..
Then you can insert your text:
pango_layout_set_markup( pangoLayout, text.c_str( ), -1 );
After this, you can get the layout height via pango_layout_get_pixel_size() and use that to create Cairo's objects. Then you can render it via:
cairo_move_to(cairoContext, 0, 0);
pango_cairo_update_layout( cairoContext, pangoLayout );
pango_cairo_show_layout( cairoContext, pangoLayout );

Related

Working with Bitmaps in WxWidgets

I have the following code given in the book "Cross-Platform GUI Programming with wxWidgets" which I'm reading:
BEGIN_EVENT_TABLE(MyWindow, wxWindow)
EVT_ERASE_BACKGROUND(MyWindow::OnErase)
END_EVENT_TABLE()
void MyWindow::OnErase(wxEraseEvent& event)
{
wxClientDC* clientDC = NULL;
if (!event.GetDC())
clientDC = new wxClientDC(this);
wxDC* dc = clientDC ? clientDC : event.GetDC() ;
wxSize sz = GetClientSize();
wxEffects effects;
effects.TileBitmap(wxRect(0, 0, sz.x, sz.y), *dc, m_bitmap);
if (clientDC)
delete clientDC;
}
This code doesn't show how do I load a bitmap so after some searching on google I came up with:
wxBitmap m_bitmap;
bool result = m_bitmap.LoadFile("D:\image.png", wxBITMAP_TYPE_PNG);
But this returns a boolean result of false which means the function LoadFile was failed to load the file. I have also tried to load a BMP file which fails too.
One another problem I'm having is that wxEffects is flagged deprecated by the complier warning.
You need to register the PNG image handler to be able to load PNG bitmaps. The simplest way to do is to call wxInitAllImageHandlers() function at some point during your application initialization, e.g. in your overridden MyApp::OnInit().
As for wxEffects being deprecated, this is just because the book is rather old and quite a few things have changed since then. I strongly recommend you to read the overview of important changes if you are using wxWidgets 3.0. And if you don't, I recommend you even stronger to use it.

linux, C++, xft : how to use it?

I try to use Xft, the tutorial, well let them calling that a tutorial... looks like it was written in a north korean camp... I also found this one. So let me try to do a step-by-step :
// g++ XftTest.cc -lX11 -lXft `pkg-config --cflags freetype2`
#include<unistd.h>
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#include<X11/Xft/Xft.h>
int main()
{
Display *display;
XftFont *font;
XftDraw *xftdraw;
XRenderColor xrcolor;
XftColor xftcolor;
display = XOpenDisplay(0);
Window XP = XCreateSimpleWindow(display,DefaultRootWindow(display),0,0,360,90,0,0,0);
XMapWindow(display,XP);
font = NULL; /* added 6/16 */
//font = XftFontOpenName(display,0,"NorthKorea-50"); // how to check if this is good ?
font = XftFontOpenName(display,0,"") /* added 6/16 */
if (!font) return 1;
xftdraw = XftDrawCreate(display,XP,DefaultVisual(display,0),DefaultColormap(display,0));
xrcolor.red =65535;
xrcolor.green=0;
xrcolor.blue =0;
xrcolor.alpha=65535;
XftColorAllocValue(display,DefaultVisual(display,0),DefaultColormap(display,0),&xrcolor,&xftcolor);
XftDrawString8(xftdraw, &xftcolor, font, 20,70 , (XftChar8 *)"Joe Dalton", 10);
XFlush(display);
sleep(2);
XftDrawDestroy(xftdraw);
XftColorFree(display,DefaultVisual(display,0),DefaultColormap(display,0),&xftcolor);
return 0;
}
as you can see, in the XftFontOpenName :
XftFontOpenName(display,0,"NorthKorea-50")
if you write a bullshit, like I did, there is no error or something to tell me that I don't have a font called NorthKorea. That make sense since XftFontOpenName returns the nearest font from the string.
So, how can I check if my font match or not ? how can I use a font like arial? I tried XftFontOpenName(display,0,"arial-50"), I got nothing different.
On my system, I have these folders in my fonts folder :
$ls /usr/share/fonts/
100dpi 75dpi cyrillic encodings misc OTF TTF Type1 util
can I use any font in these folders by the same way ?
if you guys have some nice internet links, it would be a pleasure for me to take a look.
n.b. : there is no xft tag...
update 6/16
I'm still stuck with dat stuff...
I don't understand, if I replace
font = XftFontOpenName(display,0,"NorthKorea-50");
by
font = XftFontOpenName(display,0,"");
it still loading a font...
xlsfonts return a lot of stuff, like dat one :
-monotype-courier new-bold-r-normal--0-0-0-0-m-0-iso8859-10
but passing this as argument to XftFontOpenName changes nothing; I try to load a font with XftFontOpenXlfd too, it returns always NULL...
xft uses fontconfig for font discovery. xlsfonts is a way to query the old X core fonts system fontconfig replaced. xlsfonts results won't map in any reliable way way to the fontconfig state.
So:
forget about any shortcut where xft work sort-of like the X core font system documented in last centuries tech books. It is completely different. It is not X core fonts with antialiasing and truetype support. It is something that can use modern fonts and do antialiasing, but definitely not X core fonts in any form
Read the fontconfig documentation, the fontconfig configuration files on your system, and use fontconfig utilities (fc-query, fc-list, etc) to query the fontconfig state
as the people who maintain xorg (both x core fonts and fontconfig) already told you, do not try to use xft directly. xft is the product of the first attempt to write a new font stack. Its capabilities are not sufficient to manage modern text and modern fonts. The part dealing with modern font format complexities has been spun out in pango a long time ago (because it was proving complex enough it deserved a separate project). If you try to use xft alone, you'll hit the deficiencies in pre-pango code sooner or later, and no one will be interested in fixing your problems because the same code has already been subjected to a decade of fixes pango-side. Avoiding pango is not a shortcut. Avoiding pango is trying to rely of an half-finished, abandonned for years project.
forget about matching a specific font file. fontconfig will actively fight any attempt to work this way. In the post-core-fonts world, you give the font system a font pattern, and it will build a matching font for you. If the result is not the font file you expected that's because the file was evaluated and found lacking. If you want fontconfig to use this file you will have to fix the font file (add the missing glyphs, the missing font styles, etc), not write code to try to force it anyway. Fontconfig considers that it's more important to render a text your users can read, than to only render the parts your pet font can do. And yes that's now how you're used to think about it on other systems. fontconfig is different. Nothing short of a rewrite will make it behave like you expect. No one is interested in this rewrite because by and large fontconfig has been quite successful those past years.
fonts opentype text-rendering fontconfig linux
You should not pass an empty string to XftFontOpenName and expect to match a font. Xft provides support for core fonts and the structure nested within XftFont is a union of XFontStruct and XftFontStruct. X11 fills in the default font in the XFontStruct when creating new instances, so in the case of empty string you are likely getting the default core font.
In the simplest approach, one can hard code a font name like this:
const char *font_name = "Arial-20";
XftFont *font = XftFontOpenName (display, DefaultScreen(display), font_name);
Or you could use XftFontMatch and check the "results" before passing the pattern to XftFontOpenPattern. See http://keithp.com/~keithp/talks/xtc2001/paper/xft.html#sec-editing
Note that XCloseDisplay is missing.

Is it necessary to explicitly restore a control font when its parent window is destroyed?

I use the following code in my windows create method
HANDLE hFont = ::GetStockObject(DEFAULT_GUI_FONT);
m_InfoTab.SendMessage(WM_SETFONT, (WPARAM)hFont);
m_InfoTab is a standard Windows/MFC tab control. Is it necessary to save the original font and restore it when the parent window is destroyed?
It is not required to restore the original font. You are however responsible for managing the font object yourself, i.e. deleting it when it is no longer used. The documentation for WM_SETFONT is fairly explicit here:
The application should call the DeleteObject function to delete the font when it is no longer needed; for example, after it destroys the control.
In this particular case you will not run into any problems since you retrieved the font object through a call to GetStockObject(). These objects are controlled by the system and it is not required to call DeleteObject on them (although it is not harmful either).
Whether or not your application leaks GDI handles can easily be verified using Task Manager. Go to the Processes tab, select View -> Select Columns... and tick GDI Objects. With the monitoring in place change your code and install a timer using SetTimer() with uElapsed = 1000 (once a second). Add an OnTimer handler with the following code:
void CMyDialog::OnTimer(UINT_PTR nIDEvent)
{
// Retrieve the system font
HFONT hFontSystem = (HFONT)GetStockObject( DEFAULT_GUI_FONT );
LOGFONT lfSystem = { 0 };
GetObject( hFontSystem, sizeof( lfSystem ), &lfSystem );
// And construct and identical font object
HFONT hFontNew = CreateFontIndirect( &lfSystem );
// This will leak the font object
m_InfoTab.SendMessage( WM_SETFONT, (WPARAM)hFontNew );
__super::OnTimer(nIDEvent);
}
Now open Task Manager, start the application and watch the GDI Objects count increase by 1 each second.
No, the window in question (m_infoTab) is responsible for managing its fonts, and freeing the old one if necessary.

Custom text (code) areas in QTextEdit

I am interested in creating a text object type (inheriting QTextObjectInterface) that behaves like a code area:
distinctive background
border
fixed-width font
editable content
the instances need to be identifiable to code, so that content inside them may be extracted (separate code from surrounding content)
saving / loading (from regular html files)
syntax highlighting would be a plus, but is not really required
The other areas of the document would need to behave the usual way (font properties editable, colors editable, etc).
Qt provides an example for implementing custom text objects with QTextEdit. This looks like the hard way, since new text object can't make use of the existing infrastructure inside QTextEdit / QTextDocument.
QTextObject is
a base class for different kinds of objects that can group parts of a QTextDocument together
so inheriting it may be a choice, but neither its source files in Qt SDK package nor Google searches revealed helpful information.
QTextFrame inherits QTextObject so, again, it may be a feasible base class if some hints about this path are to be found.
In an simple HTML file all this (except syntax highlighting) would be easy. QTextEdit takes html as input and is able to export html, but the structure is lost in the process.
<code class="code-sample">
int i = 0;
</code>
QWebView is read-only, by the way. It advertises that:
Parts of HTML documents can be editable for example through the contenteditable attribute on HTML elements.
There may be other platforms where this is readily available, but the text editor needs to be used inside Qt Creator as a plug-in, so using Qt framework makes sense.
Bottom line: how does one implement code areas in a QTextEdit widget?
Later edits:
using Qt sdk from trunk (identifies itself as 4.8.4)
Qt Creator from trunk (Qt Creator 2.6.81)
I have found out that implementing this is possible using QTextEdit / QTextDocument.The most simple implementation that I can think of is presented in this answer for the reference of future seeker.
Notice that saving/loading needs to be customised as regular .toHtml() will not preserve the information needed.
Inserting a code block is simple:
QTextFrame * frame;
frame = cursor.insertFrame( code_block_format_ );
connect( frame, SIGNAL( destroyed() ),
this, SLOT( codeBlockDeleted() ) );
code_blocks_.append( frame );
notice the two variables that you can save in the class:
QTextFrameFormat code_block_format_;
QList<const QTextFrame*> code_blocks_;
We need the format for frame to be consistent and distinctive. It mat be initialised in constructor to something like:
code_block_format_.setBackground( QBrush( Qt::yellow ) );
code_block_format_.setBorder( 1 );
code_block_format_.setBorderStyle( QTextFrameFormat::BorderStyle_Inset);
code_block_format_.setMargin( 10 );
code_block_format_.setPadding( 4 );
We need the list so we can tell if a certain frame is a code box or not. Since all objects inheriting QTextObject need to be created by QTextDocument::createObject() we can't simply subclass the QTextFrame (actually I think we can, but not sure yet).
Now separating the code content from the rest may be done the usual way:
for ( it = frame->begin(); !(it.atEnd()); ++it ) {
child_frame = it.currentFrame();
child_block = it.currentBlock();
if ( child_frame != NULL )
{
if ( code_blocks_.contains( frame ) )
{
/* ... */
}
}
} /* for ( it = frame->begin(); !(it.atEnd()); ++it ) */
but notice that this is over-simplified for the sake of brevity. One needs to take into account nested frames.
If you are interested in a full implementation check out the git repository (work in progress, November 2012).

Fixed width font - Symbian C++ CEikLabel

I want to change the font I am using in a CEikLabel on S60 device
I believe I can do the following
const CFont* aPlainFont = LatinPlain12();
aLabel->SetFont(aPlainFont);
where LatinPlain12 is one from this list..
Albi12
Alp13
Alpi13
Albi13
alp17
Alb17b
albi17b
alpi17
Aco13
Aco21
Acalc21
LatinBold12
LatinBold13
LatinBold17
LatinBold19
LatinPlain12
Acb14
Acb30
Acp5
However, who can help me find out which ones from this list are fixed width.. Thanks :)
You may use the FontViewer application to view and find out which of the fonts are proportional and fixed-width.
Programatically, you can determine if a font is proportional using:
const CFont* myFont;
// Initialize your font
// ....
TBool isProportional = (myFont->FontSpecInTwips().iTypeface.Attributes() & TTypeFace::EProportional);
BTW you might be better off enumerating the fonts on the device and/or using the logical font API than relying on the static font accessor functions.