+#include "physfs/physfs_sdl.hpp"
+#include "supertux/screen.hpp"
+#include "util/file_system.hpp"
+#include "util/log.hpp"
+#include "util/utf8_iterator.hpp"
+#include "video/drawing_context.hpp"
+#include "video/font.hpp"
+#include "video/renderer.hpp"
+
+namespace {
+
+bool vline_empty(SDL_Surface* surface, int x, int start_y, int end_y, Uint8 threshold)
+{
+ Uint8* pixels = (Uint8*)surface->pixels;
+
+ for(int y = start_y; y < end_y; ++y)
+ {
+ const Uint8& p = pixels[surface->pitch*y + x*surface->format->BytesPerPixel + 3];
+ if (p > threshold)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+Font::Font(GlyphWidth glyph_width_,
+ const std::string& filename,
+ int shadowsize_) :
+ glyph_width(glyph_width_),
+ glyph_surfaces(),
+ shadow_surfaces(),
+ char_height(),
+ shadowsize(shadowsize_),
+ glyphs(65536)
+{
+ for(unsigned int i=0; i<65536;i++) glyphs[i].surface_idx = -1;
+
+ const std::string fontdir = FileSystem::dirname(filename);
+ const std::string fontname = FileSystem::basename(filename);
+
+ // scan for prefix-filename in addons search path
+ char **rc = PHYSFS_enumerateFiles(fontdir.c_str());
+ for (char **i = rc; *i != NULL; i++) {
+ std::string filename(*i);
+ if( filename.rfind(fontname) != std::string::npos ) {
+ loadFontFile(fontdir + filename);
+ }
+ }
+ PHYSFS_freeList(rc);
+}
+
+void
+Font::loadFontFile(const std::string &filename)
+{
+ lisp::Parser parser;
+ log_debug << "Loading font: " << filename << std::endl;
+ const lisp::Lisp* root = parser.parse(filename);
+ const lisp::Lisp* config_l = root->get_lisp("supertux-font");
+
+ if(!config_l) {
+ std::ostringstream msg;
+ msg << "Font file:" << filename << ": is not a supertux-font file";
+ throw std::runtime_error(msg.str());
+ }
+
+ int def_char_width=0;
+
+ if( !config_l->get("glyph-width",def_char_width) ) {
+ log_warning << "Font:"<< filename << ": misses default glyph-width" << std::endl;
+ }
+
+ if( !config_l->get("glyph-height",char_height) ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": misses glyph-height";
+ throw std::runtime_error(msg.str());
+ }
+
+ lisp::ListIterator iter(config_l);
+ while(iter.next()) {
+ const std::string& token = iter.item();
+ if( token == "surface" ) {
+ const lisp::Lisp * glyphs_val = iter.lisp();
+ int local_char_width;
+ bool monospaced;
+ GlyphWidth local_glyph_width;
+ std::string glyph_image;
+ std::string shadow_image;
+ std::vector<std::string> chars;
+ if( ! glyphs_val->get("glyph-width", local_char_width) ) {
+ local_char_width = def_char_width;
+ }
+ if( ! glyphs_val->get("monospace", monospaced ) ) {
+ local_glyph_width = glyph_width;
+ }
+ else {
+ if( monospaced ) local_glyph_width = FIXED;
+ else local_glyph_width = VARIABLE;
+ }
+ if( ! glyphs_val->get("glyphs", glyph_image) ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": missing glyphs image";
+ throw std::runtime_error(msg.str());
+ }
+ if( ! glyphs_val->get("shadows", shadow_image) ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": missing shadows image";
+ throw std::runtime_error(msg.str());
+ }
+ if( ! glyphs_val->get("chars", chars) || chars.size() == 0) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": missing chars definition";
+ throw std::runtime_error(msg.str());
+ }
+
+ if( local_char_width==0 ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": misses glyph-width for some surface";
+ throw std::runtime_error(msg.str());
+ }
+
+ loadFontSurface(glyph_image, shadow_image, chars,
+ local_glyph_width, local_char_width);
+ }
+ }
+}
+
+void
+Font::loadFontSurface(
+ const std::string &glyphimage,
+ const std::string &shadowimage,
+ const std::vector<std::string> &chars,
+ GlyphWidth glyph_width,
+ int char_width
+ )