PDA

View Full Version : QGraphicsTextItem and text on pixmap caching problem



jbarnesweb
11th August 2012, 04:57
Hello,

I've inherited some code that uses a pixmap texture to cache glyphs in the ascii/latin1 set based on font and size of the text. Each face/size gets its own texture and the positioning metadata is stored in a glyph struct. When preparing to paint, a subclass of QGraphicsTextItem consults the glyph metadata about its position on the pixmap. If all the string characters in the text are in the pixmap, the texture positions are passed to a tree that gets rendered via OpenGL.

When the glyph falls outside the ascii/latin1 range, the texture is not used. Instead, QGraphicsTextItem::paint() renders the text.

The difficulty I'm having is that, depending on the glyph code point(s) that fall outside the range, I get varying amounts of offset from the baseline, from 5 to 10 pixels on a 32 pixel size font. When two QGraphicsTextItems are supposed to be on the same baseline, it looks bad when they aren't.

The pixmap was created with QPainter::drawText(x, y + ascent, QString) for each glyph. The ascent value was obtained from QFontMetrics. The x and y values were obtained from QFontMetrics::boundingRect. I also had to offset the ascent, because the font doesn't always honor it. The offset is also stored in the metadata and used to calculate the y in the QGraphicsTextItem preparation for painting.

I've double checked the document margin. I don't think that is the problem because different glyphs produce different baselines. QGraphicsTextItem seems to be positioning based on the tallest bounding rectangle enclosing the glyphs in the string. Can someone confirm this?

The performance improvement is about 40% when the cache is used, so it would be great to keep it and resort to QGraphicsTextItem in the small number of cases where glyph code points fall outside the range.

Could someone point me in the right direction for fixing this?

Thanks in advance.
Jeff Barnes

d_stranz
11th August 2012, 17:00
A QGraphicItem's internal position (origin) is always at (0,0) - the upper left corner of the bounding box, which is then transformed relative to its parent into a parent coordinate position. So setPos() is basically moving the upper left corner of the box within the parent's coordinate space.

The QGraphicsItem::boundingRect() is the largest rect that encloses the graphics item and all of its children. In the case of text, it would probably be the largest box that encloses the particular string, and would vary depending on the length and height of the characters in the string, including both ascent and descent.

My guess is that you will have to deconstruct each string and determine the maximum ascent and descent by examining each character, and use that to position the text item on the baseline. Seems a bit silly that this functionality isn't already present in QGraphicsTextItem, to solve exactly the problem you are facing.

EDIT: Also see this earlier post (http://www.qtcentre.org/threads/24814-QGraphicsTextItem-Vertical-text-alignment).