Sean Egan's Blog
Message Display in Pidgin
During the Summer of Code, one of my students, Jeff, wrote:
Prior to 2001, Gaim used GtkHTML, but now conversations are rendered using the GtkIMHtml engine.referring to the GtkHtml widget from GNOME used by Evolution for its message displays.
I told Jeff he was mistaken; Gaim never used GtkHtml. I went on to explain the history of message rendering in Pidgin and promised to make it an interesting blog post. Here, half a year later, it is.
Jeff was right to be confused. The original HTML renderer used by Gaim was called GtkHtml. However, it was of no relation to the one used by GNOME.
The screenshot above is of Gaim 0.10.0, from September 11, 2000. Gaim's GtkHtml supported a bunch of features; you can see colors and links above. It also supported smileys, background colors, italics, bold, and horizontal separators. GtkHtml is built completely from scratch; all the HTML parsing, postitioning, rendering, etc., was all written by Gaim developers.
I don't remember much of GtkHtml, as I personally got involved in Gaim development in late 2000, when GtkHtml's replacement was already underway.
GtkHtml was deemed by Eric, the maintainer at the time, to be nearing the end of its utility. The biggest issue was that the parser was unbearingly slow, and as we tried to add new formatting abilities, it proved a major bottleneck. GtkIMHtml was to be the successor to GtkHtml; it would have a re-written super-fast parser, considerably better drawing code, and then a bunch of other features made possible by the performance improvements.
GtkImHtml also did all its rendering and drawing by hand. Why didn't we just use Mozilla's Gecko to handle all this for us? Gecko was considered way too massive to be a dependency for the little bit we needed. All we needed were some colors, some images, bold, underline, italics, and links. Who in their right minds would ever want frames in their IM windows?
We did eventually learn the price of writing your own HTML parser; a ton of remotely-exploitable denial-of-service attacks (read: Gaim crashes when it receives HTML it isn't expecting) were found in our parser. Send someone "�"? Ka-boom. These were fixed quickly as we worked on this widget from 2001 to 2003, adding features such as sending embedded images over IM.
GtkImHtml version 2
Released in 2003, Gaim 0.60 was our first release to support GTK+ v2, a hugely significant upgrade to the GUI library Gaim uses. GTK+ 2.0 broke compatibilty with older versions of GTK+, and offered a ton of great new functionality, especially in areas such as international support. (GTK+ has never broken backward compatibility since that release. You can run Gaim 0.60 on the current 2.20 versions of GTK+ just as you can run Pidgin 2.3.0 on GTK+ 2.0.0). Since GTK+ broke compatibility, a lot of Gaim's UI code had to be re-written. One of the great additions to GTK2 was GtkTextView, a really powerful rich-text editor with great internationalization support.
Proper international text rendering is really, really, ridiculously hard. The Unicode standard describes how to properly do it. It contains thousands of pages with stuff like:
For the purpose of rendering, the Lao combining marks above (U+0EB1, U+0EB4..U+0EB7, U+0EBB, U+0EC8..U+0ECD) should be displayed outward from the base character they modify, in the order in which they appear in the text. In particular, a sequence containing <U+0EC8 lao tone mai ek, U+0ECD lao niggahita> should be displayed with the niggahita above the mai ek, and a sequence containing <U+0ECD lao niggahita, U+0EC8 lao tone mai ek> should be displayed with the mai ek above the niggahita.
GTK2 included a library called Pango that takes care of international text rendering. GtkTextView used it to do all its layout and drawing, so it was an obvious choice to base Gaim 0.60's GtkImHtml's replacement on. This was, uncreatively, also called GtkImHtml
This screenshot is from Gaim 0.60. This version of GtkImHtml, around since 2003, is still around today. GtkImHtml2 was made by keeping the original GtkImHtml's parser (as it does the job well, and you don't want to make the same security mistakes twice), but fed the results into a form that GtkTextView can understand. On top of that was added all sorts of additions through the years to add all the features we now have: smooth scrolling, animated smileys, full-width background colors, rich-text input, rich-text copy and paste, etc.
However, just as GtkHtml eventually outlived its usefulness, we're now, after 4 years, seeing GtkImHtml do the same. This way we parse HTML ourselves and then pass it into GtkTextView is proving difficult to work with, and we're choosing to work-around potential denial of service attacks rather than attempting to fix them.
For instance, if our parser sees a whole lot of formatting changes in a single message, each of those requires GtkTextView to recalculate its entire contents. A message with a huge number of formatting changes could cause Pidgin to lock up for minutes, and a proper fix would require a considerable rewrite of our parser, so we now strip formatting away from any message with more than 20 formatting changes.
Another issue is that the way we support animated smileys is fairly expensive to GtkTextView. If you have a large number of animated smileys, it can take up all your CPU time, essentially locking your entire computer. To work around this issue, we only animate the last few animated smileys, changing ones scrolled off screen to not animate.
It's becoming obvious that a true HTML widget, with a proper, well-tested parser, and robust layout engine would be better suited for us than our current solution.
I've been working on a plugin to use the GTK+ port of Webkit in Pidgin and to support Adium's message styles with it. This has turned out not to be hard at all to do, and it only took me a few hours to get to a very useable state
This is my plugin loaded in Pidgin using the Glass message style.
It's worth mentioning that Kopete for KDE has supported these styles for a long time. The Google Talk client for Windows and Banter for GNOME also support them to certain degrees. The plugin isn't very useful for most people right now (it depends on development snapshots of both webkit and Pidgin, and is very difficult to configure), but I hope to make it publically releasable within a few weeks (It's here right now if you think you can figure it out) and then once it has feature parity with GtkIMHtml, and when Webkit's GTK+ port is stable enough to depend on, make it part of Pidgin proper.