# HG changeset patch
# User Vanya Sergeev <vsergeev@gmail.com>
# Date 1313503290 25200
# Node ID 27c3251d1a5039dcdba7bd1dba645c69fac0f3fc
# Parent  e4f82a337d666f9e3de2539d0a9236ab664090bb
More pixel accurate opengl multi-line text alignment, and fixed previously out-of-bounds unrendered pixels.

txt-eng-ft.cc: Accounted for the face->glyph->bitmap_left x offset in both rendering and bounding box mode, which was previously ignored and occasionally led to scrunched characters (bitmap_left < 0 -> x0 = 0) or a column of missing pixels (bitmap_left > 0 -> ignored out of bounds pixels). Added comments explaining some of the glyph rendering code.

diff -r e4f82a337d66 -r 27c3251d1a50 src/txt-eng-ft.cc
--- a/src/txt-eng-ft.cc	Tue Aug 16 04:01:08 2011 -0500
+++ b/src/txt-eng-ft.cc	Tue Aug 16 07:01:30 2011 -0700
@@ -297,6 +297,10 @@
                 case MODE_RENDER:
                   if (str[i] == '\n')
                     {
+                    // Load a space (' ') character for now, in case there was
+                    // not a previously rendered glyph (e.g. "\ntest").
+                    // We need some sort of glyph height to increment our
+                    // yoffset by for a newline. FIXME?
                     glyph_index = FT_Get_Char_Index(face, ' ');
                     if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
                       {
@@ -305,6 +309,8 @@
                     else 
                       {
                         line_index++;
+                        // Start out this line with our precomputed alignment
+                        // x offset to achieve left/center/right alignment.
                         xoffset = multiline_align_xoffsets[line_index];
                         yoffset -= (face->size->metrics.height >> 6);
                       }
@@ -317,6 +323,7 @@
                       FT_Bitmap& bitmap = face->glyph->bitmap;
                       int x0, y0;
 
+                      // Kerning
                       if (previous)
                         {
                           FT_Vector delta;
@@ -325,13 +332,14 @@
                           xoffset += (delta.x >> 6);
                         }
 
+                      // Pen Position
                       x0 = xoffset+face->glyph->bitmap_left;
                       y0 = yoffset+face->glyph->bitmap_top;
 
-                      // 'w' seems to have a negative -1
-                      // face->glyph->bitmap_left, this is so we don't
-                      // index out of bound, and assumes we we allocated
-                      // the right amount of horizontal space in the bbox.
+                      // face->glyph->bitmap_left might be negative (e.g. 'w')
+                      // and may want to move our pen too far to the left into
+                      // a negative out-of-bounds position. Move forward to 0,
+                      // but compensate afterwords.
                       if (x0 < 0)
                         x0 = 0;
 
@@ -353,6 +361,11 @@
                               }
                           }
 
+                      // Compensate for moving up from a x0 negative index to
+                      // 0 by making that amount of x room for the next glyph.
+                      if (x0 == 0 && face->glyph->bitmap_left < 0)
+                        xoffset += (0-face->glyph->bitmap_left);
+
                       xoffset += (face->glyph->advance.x >> 6);
                     }
                   break;
@@ -371,14 +384,20 @@
                         multiline_align_xoffsets.push_back(box_line_width);
                         // Reset the pixel width for this newline, so we don't
                         // allocate a bounding box larger than the horizontal
-                        // width of the multi-line
+                        // width of the multi-line.
                         box_line_width = 0; 
                         bbox(1) -= (face->size->metrics.height >> 6);
                       }
                     } 
+                  // Normally we don't render the glyph in bounding box mode,
+                  // but this is to account for offsets due to
+                  // face->glyph->bitmap_left.
+                  else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
+                    ::warning ("ft_render: unable to render glyph for character `%c'",
+                               str[i]);
                   else 
                     {
-                    // width
+                    // Kerning
                     if (previous)
                       {
                         FT_Vector delta;
@@ -389,6 +408,15 @@
                         box_line_width += (delta.x >> 6);
                       }
 
+                    // If we have a negative bitmap_left, then make room
+                    // for the shift to zero we make in render mode.
+                    if (box_line_width == 0 && face->glyph->bitmap_left < 0)
+                      box_line_width += (0-face->glyph->bitmap_left);
+                    // If we have a positive bitmap_left, then make room
+                    // at the end for the whole bitmap width to fit.
+                    else if (face->glyph->bitmap_left > 0)
+                      box_line_width += face->glyph->bitmap_left;
+
                     box_line_width += (face->glyph->advance.x >> 6);
 
                     int asc, desc;
@@ -427,7 +455,7 @@
         }
       if (mode == MODE_BBOX)
         {
-          /* Push last the width associated with the last line */ 
+          /* Push the last width associated with the last line */
           multiline_align_xoffsets.push_back(box_line_width);
 
           for (unsigned int i = 0; i < multiline_align_xoffsets.size(); i++)
