Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

CEGUIFont.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUIFont.cpp
00003         created:        21/2/2004
00004         author:         Paul D Turner
00005         
00006         purpose:        Implements Font class
00007 *************************************************************************/
00008 /*************************************************************************
00009     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00010     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00011 
00012     This library is free software; you can redistribute it and/or
00013     modify it under the terms of the GNU Lesser General Public
00014     License as published by the Free Software Foundation; either
00015     version 2.1 of the License, or (at your option) any later version.
00016 
00017     This library is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020     Lesser General Public License for more details.
00021 
00022     You should have received a copy of the GNU Lesser General Public
00023     License along with this library; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 *************************************************************************/
00026 #include "CEGUIFont.h"
00027 #include "CEGUIExceptions.h"
00028 #include "CEGUISystem.h"
00029 #include "CEGUIFontManager.h"
00030 #include "CEGUIImagesetManager.h"
00031 #include "CEGUIImageset.h"
00032 #include "CEGUITexture.h"
00033 #include "CEGUILogger.h"
00034 #include "CEGUITextUtils.h"
00035 #include "CEGUIFont_xmlHandler.h"
00036 #include "CEGUIFont_implData.h"
00037 #include "CEGUIResourceProvider.h"
00038 
00039 #include "xercesc/sax2/SAX2XMLReader.hpp"
00040 #include "xercesc/sax2/XMLReaderFactory.hpp"
00041 #include "xercesc/framework/MemBufInputSource.hpp"
00042 #include <ft2build.h>
00043 #include FT_FREETYPE_H
00044 
00045 #include <algorithm>
00046 #include <sstream>
00047 
00048 // Start of CEGUI namespace section
00049 namespace CEGUI
00050 {
00051 /*************************************************************************
00052         static data definitions
00053 *************************************************************************/
00054 const uint32 Font::DefaultColour                                        = 0xFFFFFFFF;
00055 const uint      Font::InterGlyphPadSpace                        = 2;
00056 
00057 // XML related strings
00058 const char      Font::FontSchemaName[]                          = "Font.xsd";
00059 
00060 
00061 /*************************************************************************
00062         Constructs a new Font object from a font definition file
00063 *************************************************************************/
00064 Font::Font(const String& filename, const String& resourceGroup, FontImplData* dat)
00065 {
00066         d_antiAliased = false;
00067         d_impldat = dat;
00068         d_freetype = false;
00069         d_glyph_images = NULL;
00070 
00071         // defaults for scaling options
00072         d_autoScale = false;
00073         setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00074 
00075         load(filename, resourceGroup);
00076 
00077         // complete y spacing set-up for bitmap / static fonts
00078         calculateStaticVertSpacing();
00079 }
00080 
00081 
00082 /*************************************************************************
00083         Constructs a new Font object (via FreeType & a true-type font file)
00084         'glyph-set' describes the set of code points to be available via
00085         this font
00086 *************************************************************************/
00087 Font::Font(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, const String& glyph_set, FontImplData* dat)
00088 {
00089         d_impldat = dat;
00090         d_freetype = false;
00091         d_glyph_images = NULL;
00092 
00093         // defaults for scaling options
00094         d_autoScale = false;
00095         setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00096 
00097         constructor_impl(name, fontname, resourceGroup, size, flags, glyph_set);
00098 }
00099 
00100 
00101 /*************************************************************************
00102         Constructs a new Font object (via FreeType & a true-type font file)
00103         [first_code_point, last_code_point] describes the range of code
00104         points to be available via this font
00105 *************************************************************************/
00106 Font::Font(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, utf32 first_code_point, utf32 last_code_point, FontImplData* dat)
00107 {
00108         d_impldat = dat;
00109         d_freetype = false;
00110         d_glyph_images = NULL;
00111 
00112         // defaults for scaling options
00113         d_autoScale = false;
00114         setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00115 
00116         String tmp;
00117 
00118         for (utf32 cp = first_code_point; cp <= last_code_point; ++cp)
00119         {
00120                 tmp += cp;
00121         }
00122 
00123         constructor_impl(name, fontname, resourceGroup, size, flags, tmp);
00124 }
00125 
00126 
00127 /*************************************************************************
00128         Constructs a new Font object (via FreeType & a true-type font file)
00129         The font file will provide support for 7-bit ASCII characters only
00130 *************************************************************************/
00131 Font::Font(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, FontImplData* dat)
00132 {
00133         d_impldat = dat;
00134         d_freetype = false;
00135         d_glyph_images = NULL;
00136 
00137         // defaults for scaling options
00138         d_autoScale = false;
00139         setNativeResolution(Size(DefaultNativeHorzRes, DefaultNativeVertRes));
00140 
00141         String tmp;
00142 
00143         for (utf32 cp = 32; cp <= 127; ++cp)
00144         {
00145                 tmp += cp;
00146         }
00147 
00148         constructor_impl(name, fontname, resourceGroup, size, flags, tmp);
00149 }
00150 
00151 
00152 /*************************************************************************
00153         Destroys a Font object
00154 *************************************************************************/
00155 Font::~Font(void)
00156 {
00157         unload();
00158         delete d_impldat;
00159 }
00160 
00161 
00162 /*************************************************************************
00163         Return the pixel width of the specified text if rendered with this Font.
00164 *************************************************************************/
00165 float Font::getTextExtent(const String& text, float x_scale) const
00166 {
00167         float cur_extent = 0;
00168 
00169         uint char_count = text.length();
00170         CodepointMap::const_iterator    pos, end = d_cp_map.end();
00171 
00172         for (uint c = 0; c < char_count; ++c)
00173         {
00174                 pos = d_cp_map.find(text[c]);
00175 
00176                 if (pos != end)
00177                 {
00178                         cur_extent += (float)pos->second.d_horz_advance * x_scale;
00179                 }
00180 
00181         }
00182 
00183         return cur_extent;
00184 }
00185 
00186 
00187 /*************************************************************************
00188         Return the index of the closest text character in String 'text' that
00189         corresponds to pixel location 'pixel' if the text were rendered.
00190 *************************************************************************/
00191 uint Font::getCharAtPixel(const String& text, uint start_char, float pixel, float x_scale) const
00192 {
00193         float cur_extent = 0;
00194         uint char_count = text.length();
00195 
00196         // handle simple cases
00197         if ((pixel <= 0) || (char_count <= start_char))
00198         {
00199                 return start_char;
00200         }
00201 
00202         CodepointMap::const_iterator    pos, end = d_cp_map.end();
00203 
00204         for (uint c = start_char; c < char_count; ++c)
00205         {
00206                 pos = d_cp_map.find(text[c]);
00207 
00208                 if (pos != end)
00209                 {
00210                         cur_extent += (float)pos->second.d_horz_advance * x_scale;
00211 
00212                         if (pixel < cur_extent)
00213                         {
00214                                 return c;
00215                         }
00216 
00217                 }
00218 
00219         }
00220 
00221         return char_count;
00222 }
00223 
00224 
00225 /*************************************************************************
00226         Renders text on the display.  Return number of lines output.
00227 *************************************************************************/
00228 uint Font::drawText(const String& text, const Rect& draw_area, float z, const Rect& clip_rect, TextFormatting fmt, const ColourRect& colours, float x_scale, float y_scale) const
00229 {
00230         uint thisCount;
00231         uint lineCount = 0;
00232 
00233         float   y_base = draw_area.d_top + getBaseline(y_scale);
00234 
00235         Rect tmpDrawArea(
00236                 PixelAligned(draw_area.d_left),
00237                 PixelAligned(draw_area.d_top),
00238                 PixelAligned(draw_area.d_right),
00239                 PixelAligned(draw_area.d_bottom)
00240                 );
00241 
00242         uint lineStart = 0, lineEnd = 0;
00243         String  currLine;
00244 
00245         while (lineEnd < text.length())
00246         {
00247                 if ((lineEnd = text.find_first_of('\n', lineStart)) == String::npos)
00248                 {
00249                         lineEnd = text.length();
00250                 }
00251 
00252                 currLine = text.substr(lineStart, lineEnd - lineStart);
00253                 lineStart = lineEnd + 1;        // +1 to skip \n char
00254 
00255                 switch(fmt)
00256                 {
00257                 case LeftAligned:
00258                         drawTextLine(currLine, Vector3(tmpDrawArea.d_left, y_base, z), clip_rect, colours, x_scale, y_scale);
00259                         thisCount = 1;
00260                         y_base += getLineSpacing(y_scale);
00261                         break;
00262 
00263                 case RightAligned:
00264                         drawTextLine(currLine, Vector3(tmpDrawArea.d_right - getTextExtent(currLine, x_scale), y_base, z), clip_rect, colours, x_scale, y_scale);
00265                         thisCount = 1;
00266                         y_base += getLineSpacing(y_scale);
00267                         break;
00268 
00269                 case Centred:
00270                         drawTextLine(currLine, Vector3(PixelAligned(tmpDrawArea.d_left + ((tmpDrawArea.getWidth() - getTextExtent(currLine, x_scale)) / 2.0f)), y_base, z), clip_rect, colours, x_scale, y_scale);
00271                         thisCount = 1;
00272                         y_base += getLineSpacing(y_scale);
00273                         break;
00274 
00275                 case WordWrapLeftAligned:
00276                         thisCount = drawWrappedText(currLine, tmpDrawArea, z, clip_rect, LeftAligned, colours, x_scale, y_scale);
00277                         tmpDrawArea.d_top += thisCount * getLineSpacing(y_scale);
00278                         break;
00279 
00280                 case WordWrapRightAligned:
00281                         thisCount = drawWrappedText(currLine, tmpDrawArea, z, clip_rect, RightAligned, colours, x_scale, y_scale);
00282                         tmpDrawArea.d_top += thisCount * getLineSpacing(y_scale);
00283                         break;
00284 
00285                 case WordWrapCentred:
00286                         thisCount = drawWrappedText(currLine, tmpDrawArea, z, clip_rect, Centred, colours, x_scale, y_scale);
00287                         tmpDrawArea.d_top += thisCount * getLineSpacing(y_scale);
00288                         break;
00289 
00290                 default:
00291                         throw InvalidRequestException((utf8*)"Font::drawText - Unknown or unsupported TextFormatting value specified.");
00292                 }
00293 
00294                 lineCount += thisCount;
00295 
00296         }
00297 
00298         return lineCount;
00299 }
00300 
00301 
00302 /*************************************************************************
00303         Define the set of glyphs available for this font
00304 *************************************************************************/
00305 void Font::defineFontGlyphs(const String& glyph_set)
00306 {
00307         d_glyphset = glyph_set;
00308         defineFontGlyphs_impl();
00309 
00310         Logger::getSingleton().logEvent("Font '" + d_name + "' now has the following glyphs defined: '" + d_glyphset + "'.", Informative);
00311 }
00312 
00313 
00314 /*************************************************************************
00315         Return the required texture size required to store imagery for the
00316         glyphs specified in 'glyph_set'
00317 *************************************************************************/
00318 uint Font::getRequiredTextureSize(const String& glyph_set)
00319 {
00320         d_maxGlyphHeight = 0;
00321 
00322         uint    texSize = 32;                   // start with a texture this size
00323         uint    width;
00324 
00325         uint    cur_x = 0;
00326         uint    cur_y = d_maxGlyphHeight;
00327 
00328         uint    glyph_set_length = glyph_set.length();
00329 
00330         for (uint i = 0; i < glyph_set_length; ++i)
00331         {
00332                 // load-up required glyph
00333                 if (FT_Load_Char(d_impldat->fontFace, glyph_set[i], FT_LOAD_RENDER|(d_antiAliased ? 0 : FT_LOAD_MONOCHROME)))
00334                 {
00335                         // skip errors
00336                         continue;
00337                 }
00338 
00339                 // if this glyph is taller than all others so far, update height and re-calculate cur_y
00340                 if ((uint)d_impldat->fontFace->glyph->bitmap.rows + InterGlyphPadSpace > d_maxGlyphHeight)
00341                 {
00342                         d_maxGlyphHeight = d_impldat->fontFace->glyph->bitmap.rows + InterGlyphPadSpace;
00343                         cur_y = (i + 1) * d_maxGlyphHeight;
00344                 }
00345 
00346                 width = d_impldat->fontFace->glyph->bitmap.width + InterGlyphPadSpace;
00347                 cur_x += width;
00348 
00349                 // check for fit
00350                 if (cur_x >= texSize)
00351                 {
00352                         cur_x = width;
00353                         cur_y += d_maxGlyphHeight;
00354 
00355                         if (cur_y >= texSize)
00356                         {
00357                                 // texture is too small, set-up to start again...
00358                                 texSize *= 2;
00359                                 cur_x = 0;
00360                                 cur_y = d_maxGlyphHeight;
00361                                 i = (uint)-1;
00362                         }
00363 
00364                 }
00365 
00366         }
00367 
00368         return texSize;
00369 }
00370 
00371 
00372 /*************************************************************************
00373         Render a set of glyph images into the given memory buffer.
00374         pixels will be in A8R8G8B8 format
00375 *************************************************************************/
00376 void Font::createFontGlyphSet(const String& glyph_set, uint size, uint32* buffer)
00377 {
00378         String  imageName;
00379         Rect    rect;
00380         Point   offset;
00381 
00382         FT_GlyphSlot glyph = d_impldat->fontFace->glyph;
00383 
00384         d_max_bearingY = 0;
00385 
00386         uint    glyph_set_length = glyph_set.length();
00387         uint    cur_x = 0;
00388         uint    cur_y = 0;
00389         uint    width;
00390 
00391         for (uint i = 0; i < glyph_set_length; ++i)
00392         {
00393                 // load-up required glyph
00394                 if (FT_Load_Char(d_impldat->fontFace, glyph_set[i], FT_LOAD_RENDER|(d_antiAliased ? 0 : FT_LOAD_MONOCHROME)))
00395                 {
00396                         // skip errors (but now we log them!)
00397                         std::stringstream err;
00398                         err << "Font::createFontGlyphSet - Failed to load glyph for codepoint: ";
00399                         err << static_cast<unsigned int>(glyph_set[i]);
00400                         Logger::getSingleton().logEvent(err.str(), Errors);
00401 
00402                         continue;
00403                 }
00404 
00405                 width = glyph->bitmap.width + InterGlyphPadSpace;
00406 
00407                 // see if we need to wrap to next row
00408                 if (cur_x + width >= size)
00409                 {
00410                         cur_x = 0;
00411                         cur_y += d_maxGlyphHeight;
00412                 }
00413 
00414                 // calculate offset into buffer for this glyph
00415                 uint32* dest_buff = buffer + (cur_y * size) + cur_x;
00416 
00417                 // draw glyph into buffer
00418                 drawGlyphToBuffer(dest_buff, size);
00419 
00420                 // define Image on Imageset for this glyph to save re-rendering glyph later
00421                 imageName               = glyph_set[i];
00422                 rect.d_left             = (float)cur_x;
00423                 rect.d_top              = (float)cur_y;
00424                 rect.d_right    = (float)(cur_x + width - InterGlyphPadSpace);
00425                 rect.d_bottom   = (float)(cur_y + d_maxGlyphHeight - InterGlyphPadSpace);
00426                 offset.d_x              = (float)(glyph->metrics.horiBearingX >> 6);
00427                 offset.d_y              = -(float)(glyph->metrics.horiBearingY >> 6);
00428 
00429                 d_glyph_images->defineImage(imageName, rect, offset);
00430 
00431                 cur_x += width;
00432 
00433 //              // check and update maximum bearingY value
00434 //              if (static_cast<float>(glyph->metrics.horiBearingY >> 6) > d_max_bearingY)
00435 //              {
00436 //                      d_max_bearingY = static_cast<float>(glyph->metrics.horiBearingY >> 6);
00437 //              }
00438 
00439                 // create entry in code-point to Image map
00440                 glyphDat        dat;
00441                 dat.d_image = &d_glyph_images->getImage(imageName);
00442                 dat.d_horz_advance = glyph->advance.x >> 6;
00443                 d_cp_map[glyph_set[i]] = dat;
00444         }
00445 
00446 }
00447 
00448 
00449 /*************************************************************************
00450         Render a range of glyph images into the given memory buffer.
00451         pixels will be in A8R8G8B8 format
00452 *************************************************************************/
00453 void Font::createFontGlyphSet(utf32 first_code_point, utf32 last_code_point, uint size, uint32* buffer)
00454 {
00455         String tmp;
00456 
00457         for (utf32 cp = first_code_point; cp <=last_code_point; ++cp)
00458         {
00459                 tmp += cp;
00460         }
00461 
00462         createFontGlyphSet(tmp, size, buffer);
00463 }
00464 
00465 
00466 /*************************************************************************
00467         Return the required texture size required to store imagery for the
00468         glyphs specified in by the inclusive range
00469         [first_code_point, last_code_point]
00470 *************************************************************************/
00471 uint Font::getRequiredTextureSize(utf32 first_code_point, utf32 last_code_point)
00472 {
00473         String tmp;
00474 
00475         for (utf32 cp = first_code_point; cp <=last_code_point; ++cp)
00476         {
00477                 tmp += cp;
00478         }
00479 
00480         return getRequiredTextureSize(tmp);
00481 }
00482 
00483 
00484 /*************************************************************************
00485         Define the range of glyphs available for this font
00486 *************************************************************************/
00487 void Font::defineFontGlyphs(utf32 first_code_point, utf32 last_code_point)
00488 {
00489         String tmp;
00490 
00491         for (utf32 cp = first_code_point; cp <=last_code_point; ++cp)
00492         {
00493                 tmp += cp;
00494         }
00495 
00496         defineFontGlyphs(tmp);
00497 }
00498 
00499 
00500 /*************************************************************************
00501         Copy the FreeType glyph bitmap into the given memory buffer
00502 *************************************************************************/
00503 void Font::drawGlyphToBuffer(uint32* buffer, uint buf_width)
00504 {
00505         FT_Bitmap* glyph_bitmap = &d_impldat->fontFace->glyph->bitmap;
00506 
00507         for (int i = 0; i < glyph_bitmap->rows; ++i)
00508         {
00509                 for (int j = 0; j < glyph_bitmap->width; ++j)
00510                 {
00511                         switch (glyph_bitmap->pixel_mode)
00512                         {
00513                         case FT_PIXEL_MODE_GRAY:
00514                                 {
00515                                         uchar* bytebuff = reinterpret_cast<uchar*>(&buffer[j]);
00516                                         *bytebuff++ = 0xFF;
00517                                         *bytebuff++ = 0xFF;
00518                                         *bytebuff++ = 0xFF;
00519                                         *bytebuff = glyph_bitmap->buffer[(i * glyph_bitmap->pitch) + j];
00520                                 }
00521                                 break;
00522 
00523                         case FT_PIXEL_MODE_MONO:
00524                                 buffer[j] = ((glyph_bitmap->buffer[(i * glyph_bitmap->pitch) + j / 8] << (j % 8)) & 0x80) ? 0xFFFFFFFF : 0x00000000;
00525                                 break;
00526 
00527                         default:
00528                                 throw InvalidRequestException((utf8*)"Font::drawGlyphToBuffer - The glyph could not be drawn because the pixel mode is unsupported.");
00529                                 break;
00530                         }
00531 
00532                 }
00533 
00534                 buffer += buf_width;
00535         }
00536 
00537 }
00538 
00539 
00540 /*************************************************************************
00541         draws wrapped text
00542 *************************************************************************/
00543 uint Font::drawWrappedText(const String& text, const Rect& draw_area, float z, const Rect& clip_rect, TextFormatting fmt, const ColourRect& colours, float x_scale, float y_scale) const
00544 {
00545         uint    line_count = 0;
00546         Rect    dest_area(draw_area);
00547         float   wrap_width = draw_area.getWidth();
00548 
00549         String  whitespace = TextUtils::DefaultWhitespace;
00550         String  thisLine, thisWord;
00551         uint    currpos = 0;
00552 
00553         // get first word.
00554         currpos += getNextWord(text, currpos, thisLine);
00555 
00556         // while there are words left in the string...
00557         while (String::npos != text.find_first_not_of(whitespace, currpos)) {
00558                 // get next word of the string...
00559                 currpos += getNextWord(text, currpos, thisWord);
00560 
00561                 // if the new word would make the string too long
00562                 if ((getTextExtent(thisLine, x_scale) + getTextExtent(thisWord, x_scale)) > wrap_width) {
00563                         // output what we had until this new word
00564                         line_count += drawText(thisLine, dest_area, z, clip_rect, fmt, colours, x_scale, y_scale);
00565 
00566                         // remove whitespace from next word - it will form start of next line
00567                         thisWord = thisWord.substr(thisWord.find_first_not_of(whitespace));
00568 
00569                         // reset for a new line.
00570                         thisLine.clear();
00571 
00572                         // update y co-ordinate for next line
00573                         dest_area.d_top += getLineSpacing(y_scale);
00574                 }
00575 
00576                 // add the next word to the line
00577                 thisLine += thisWord;
00578         }
00579 
00580         // output last bit of string
00581         line_count += drawText(thisLine, dest_area, z, clip_rect, fmt, colours, x_scale, y_scale);
00582 
00583         return line_count;
00584 }
00585 
00586 
00587 /*************************************************************************
00588         helper function for renderWrappedText to get next word of a string
00589 *************************************************************************/
00590 uint Font::getNextWord(const String& in_string, uint start_idx, String& out_string) const
00591 {
00592         out_string = TextUtils::getNextWord(in_string, start_idx, TextUtils::DefaultWrapDelimiters);
00593 
00594         return out_string.length();
00595 }
00596 
00597 
00598 /*************************************************************************
00599         Draw a line of text.  No formatting is applied.
00600 *************************************************************************/
00601 void Font::drawTextLine(const String& text, const Vector3& position, const Rect& clip_rect, const ColourRect& colours, float x_scale, float y_scale) const
00602 {
00603         Vector3 cur_pos(position);
00604 
00605         float base_y = position.d_y;
00606 
00607         uint char_count = text.length();
00608         CodepointMap::const_iterator    pos, end = d_cp_map.end();
00609 
00610         for (uint c = 0; c < char_count; ++c)
00611         {
00612                 pos = d_cp_map.find(text[c]);
00613 
00614                 if (pos != end)
00615                 {
00616                         const Image* img = pos->second.d_image;
00617                         cur_pos.d_y = base_y - (img->getOffsetY() - img->getOffsetY() * y_scale);
00618                         Size sz(img->getWidth() * x_scale, img->getHeight() * y_scale);
00619                         img->draw(cur_pos, sz, clip_rect, colours);
00620                         cur_pos.d_x += (float)pos->second.d_horz_advance * x_scale;
00621                 }
00622 
00623         }
00624 
00625 }
00626 
00627 
00628 /*************************************************************************
00629         Function to do real work of constructor
00630 *************************************************************************/
00631 void Font::constructor_impl(const String& name, const String& fontname, const String& resourceGroup, uint size, uint flags, const String& glyph_set)
00632 {
00633         FontManager&     fman   = FontManager::getSingleton();
00634         ImagesetManager& ismgr  = ImagesetManager::getSingleton();
00635 
00636         // pull a-a setting from flags
00637         d_antiAliased = (flags == NoAntiAlias) ? false : true;
00638 
00639         // create an blank Imageset
00640         d_glyph_images = ismgr.createImageset(name + "_auto_glyph_images", System::getSingleton().getRenderer()->createTexture());
00641 
00642         uint            horzdpi         = System::getSingleton().getRenderer()->getHorzScreenDPI();
00643         uint            vertdpi         = System::getSingleton().getRenderer()->getVertScreenDPI();
00644         String          errMsg;
00645 
00646     System::getSingleton().getResourceProvider()->loadRawDataContainer(fontname, d_impldat->fontData, resourceGroup);
00647 
00648         // create face using input font
00649         if (FT_New_Memory_Face(d_impldat->library, d_impldat->fontData.getDataPtr(), 
00650                 (FT_Long)d_impldat->fontData.getSize(), 0, &d_impldat->fontFace) == 0)
00651         {
00652                 // check that default Unicode character map is available
00653                 if (d_impldat->fontFace->charmap != NULL)       
00654                 {
00655                         try
00656                         {
00657                                 d_glyphset = glyph_set;
00658                                 d_name = name;
00659                                 d_freetype = true;
00660                                 createFontFromFT_Face(size, horzdpi, vertdpi);
00661                                 return;
00662                         }
00663                         catch(...)
00664                         {
00665                                 ismgr.destroyImageset(d_glyph_images);
00666                                 d_glyph_images = NULL;
00667 
00668                                 FT_Done_Face(d_impldat->fontFace);
00669                                 d_freetype = false;
00670 
00671                                 // re-throw
00672                                 throw;
00673                         }
00674 
00675                 }
00676                 // missing Unicode character map
00677                 else
00678                 {
00679                         FT_Done_Face(d_impldat->fontFace);
00680                         d_freetype = false;
00681 
00682                         errMsg = (utf8*)"Font::constructor_impl - The source font '" + fontname +"' does not have a Unicode charmap, and cannot be used.";
00683                 }
00684 
00685         }
00686         // failed to create face (a problem with the font file?)
00687         else
00688         {
00689                 errMsg = (utf8*)"Font::constructor_impl - An error occurred while trying to create a FreeType face from source font '" + fontname + "'.";
00690         }
00691 
00692         // cleanup image set we created here
00693         ismgr.destroyImageset(d_glyph_images);
00694 
00695         throw GenericException(errMsg);
00696 }
00697 
00698 
00699 /*************************************************************************
00700         Load and complete construction of 'this' via an XML file
00701 *************************************************************************/
00702 void Font::load(const String& filename, const String& resourceGroup)
00703 {
00704         XERCES_CPP_NAMESPACE_USE
00705 
00706         // unload old data
00707         unload();
00708 
00709         if (filename.empty() || (filename == (utf8*)""))
00710         {
00711                 throw InvalidRequestException((utf8*)"Font::load - Filename supplied for Font loading must be valid");
00712         }
00713 
00714         SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
00715 
00716         // set basic settings we want from parser
00717         parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
00718         parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
00719         parser->setFeature(XMLUni::fgXercesSchema, true);
00720         parser->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);
00721 
00722 //    InputSourceContainer fontSchemaData;
00723 //    System::getSingleton().getResourceProvider()->loadInputSourceContainer(FontSchemaName, fontSchemaData);
00724 //    parser->loadGrammar(*(fontSchemaData.getDataPtr()), Grammar::SchemaGrammarType, true);
00725 
00726     RawDataContainer rawSchemaData;
00727     System::getSingleton().getResourceProvider()->loadRawDataContainer(FontSchemaName, rawSchemaData, resourceGroup);
00728     MemBufInputSource  fontSchemaData(rawSchemaData.getDataPtr(), rawSchemaData.getSize(), FontSchemaName, false);
00729     parser->loadGrammar(fontSchemaData, Grammar::SchemaGrammarType, true);
00730     // enable grammar reuse
00731     parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
00732 
00733         // setup schema for Font data
00734         XMLCh* pval = XMLString::transcode(FontSchemaName);
00735         parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, pval);
00736         XMLString::release(&pval);
00737 
00738         // setup handler object
00739         Font_xmlHandler handler(this);
00740         parser->setContentHandler(&handler);
00741         parser->setErrorHandler(&handler);
00742 
00743 //    InputSourceContainer fontData;
00744 //    System::getSingleton().getResourceProvider()->loadInputSourceContainer(filename, fontData);
00745 
00746     RawDataContainer rawXMLData;
00747     System::getSingleton().getResourceProvider()->loadRawDataContainer(filename, rawXMLData, resourceGroup);
00748     MemBufInputSource  fontData(rawXMLData.getDataPtr(), rawXMLData.getSize(), filename.c_str(), false);
00749 
00750         // do parse (which uses handler to create actual data)
00751         try
00752         {
00753 //        parser->parse(*(fontData.getDataPtr()));
00754         parser->parse(fontData);
00755         }
00756         catch(const XMLException& exc)
00757         {
00758                 if (exc.getCode() != XMLExcepts::NoError)
00759                 {
00760                         unload();
00761                         delete parser;
00762 
00763                         char* excmsg = XMLString::transcode(exc.getMessage());
00764                         String message((utf8*)"Font::load - An error occurred while parsing Font file '" + filename + "'.  Additional information: ");
00765                         message += excmsg;
00766                         XMLString::release(&excmsg);
00767 
00768                         throw FileIOException(message);
00769                 }
00770 
00771         }
00772         catch(const SAXParseException& exc)
00773         {
00774                 unload();
00775                 delete parser;
00776 
00777                 char* excmsg = XMLString::transcode(exc.getMessage());
00778                 String message((utf8*)"Font::load - An error occurred while parsing Font file '" + filename + "'.  Additional information: ");
00779                 message += excmsg;
00780                 XMLString::release(&excmsg);
00781 
00782                 throw FileIOException(message);
00783         }
00784         catch(...)
00785         {
00786                 unload();
00787                 delete parser;
00788 
00789                 throw FileIOException((utf8*)"Font::load - An unexpected error occurred while parsing Font file '" + filename + "'.");
00790         }
00791 
00792         // cleanup
00793         delete parser;
00794 }
00795 
00796 
00797 /*************************************************************************
00798         Unload data associated with the font (font is then useless.
00799         this is intended for cleanup).
00800 *************************************************************************/
00801 void Font::unload(void)
00802 {
00803         d_cp_map.clear();
00804 
00805         // cleanup Imageset if it's valid
00806         if (d_glyph_images != NULL)
00807         {
00808                 ImagesetManager::getSingleton().destroyImageset(d_glyph_images);
00809                 d_glyph_images = NULL;
00810         }
00811 
00812         // cleanup FreeType face if this is a FreeType based font.
00813         if (d_freetype)
00814         {
00815                 FT_Done_Face(d_impldat->fontFace);
00816                 d_freetype = false;
00817         }
00818 
00819 }
00820 
00821 
00822 /*************************************************************************
00823         Defines the set of code points on the font. (implementation).
00824 *************************************************************************/
00825 void Font::defineFontGlyphs_impl(void)
00826 {
00827         // must be a font using the FreeType system
00828         if (!d_freetype)
00829         {
00830                 throw InvalidRequestException((utf8*)"Font::defineFontGlyphs_impl - operation not supported on bitmap based fonts.");
00831         }
00832 
00833         uint texture_size = getRequiredTextureSize(d_glyphset);
00834 
00835         // check renderer can do a texture big enough
00836         if (texture_size > System::getSingleton().getRenderer()->getMaxTextureSize())
00837         {
00838                 throw   RendererException((utf8*)"Font::defineFontGlyphs_impl - operation requires a texture larger than the supported maximum.");
00839         }
00840 
00841         // allocate memory buffer where we will define the imagery
00842         uint32* mem_buffer;
00843 
00844         try
00845         {
00846                 mem_buffer = new uint32[texture_size * texture_size];
00847         }
00848         catch (std::bad_alloc)
00849         {
00850                 throw   MemoryException((utf8*)"Font::defineFontGlyphs_impl - failed to allocate required memory buffer.");
00851         }
00852 
00853         // initialise background to transparent black.
00854         memset(mem_buffer, 0, ((texture_size * texture_size) * sizeof(uint32)));
00855 
00856         // clear old data about glyphs and images
00857         d_cp_map.clear();
00858         d_glyph_images->undefineAllImages();
00859 
00860         // render new glyphs and define Imageset images.
00861         createFontGlyphSet(d_glyphset, texture_size, mem_buffer);
00862 
00863         // update Imageset texture with new imagery.
00864         d_glyph_images->getTexture()->loadFromMemory(mem_buffer, texture_size, texture_size);
00865 
00866         delete[] mem_buffer;
00867 
00868         d_lineHeight = (float)d_maxGlyphHeight;
00869 
00870         // calculate spacing and base-line
00871     d_max_bearingY = ((float)d_impldat->fontFace->ascender / (float)d_impldat->fontFace->units_per_EM) * (float)d_impldat->fontFace->size->metrics.y_ppem;
00872         d_lineSpacing = ((float)d_impldat->fontFace->height / (float)d_impldat->fontFace->units_per_EM) * (float)d_impldat->fontFace->size->metrics.y_ppem;
00873 }
00874 
00875 
00876 /*************************************************************************
00877         Calculate the vertical spacing fields for a static / bitmap font
00878 *************************************************************************/
00879 void Font::calculateStaticVertSpacing(void)
00880 {
00881         if (!d_freetype)
00882         {
00883                 float scale = d_autoScale ? d_vertScaling : 1.0f;
00884 
00885                 d_lineHeight    = 0;
00886                 d_max_bearingY  = 0;
00887 
00888                 CodepointMap::iterator pos = d_cp_map.begin(), end = d_cp_map.end();
00889 
00890                 for (;pos != end; ++pos)
00891                 {
00892                         const Image* img = pos->second.d_image;
00893 
00894                         if (img->getOffsetY() > d_max_bearingY)
00895                                 d_max_bearingY = img->getOffsetY();
00896 
00897                         if (img->getHeight() > d_lineHeight)
00898                                 d_lineHeight = img->getHeight();
00899                 }
00900 
00901                 d_max_bearingY *= scale;
00902                 d_lineHeight *= scale;
00903                 d_lineSpacing = d_lineHeight;
00904         }
00905 
00906 }
00907 
00908 
00909 /*************************************************************************
00910         Set the native resolution for this Font
00911 *************************************************************************/
00912 void Font::setNativeResolution(const Size& size)
00913 {
00914         d_nativeHorzRes = size.d_width;
00915         d_nativeVertRes = size.d_height;
00916 
00917         // set native resolution for underlying imageset for bitmap fonts
00918         if ((!d_freetype) && (d_glyph_images != NULL))
00919         {
00920                 d_glyph_images->setNativeResolution(size);
00921         }
00922 
00923         // re-calculate scaling factors & notify images as required
00924         notifyScreenResolution(System::getSingleton().getRenderer()->getSize());
00925 }
00926 
00927 
00928 /*************************************************************************
00929         Notify the Font of the current (usually new) display resolution.
00930 *************************************************************************/
00931 void Font::notifyScreenResolution(const Size& size)
00932 {
00933         // notification should come from System which would have notified the Imageset anyway, but
00934         // in case client code decides to call us, we must pass on notification here too.
00935         if (d_glyph_images)
00936         {
00937                 d_glyph_images->notifyScreenResolution(size);
00938         }
00939 
00940         d_horzScaling = size.d_width / d_nativeHorzRes;
00941         d_vertScaling = size.d_height / d_nativeVertRes;
00942 
00943         if (d_autoScale)
00944         {
00945                 updateFontScaling();
00946         }
00947 
00948 }
00949 
00950 
00951 /*************************************************************************
00952         Enable or disable auto-scaling for this Font.
00953 *************************************************************************/
00954 void Font::setAutoScalingEnabled(bool setting)
00955 {
00956         if (setting != d_autoScale)
00957         {
00958                 if ((!d_freetype) && (d_glyph_images != NULL))
00959                 {
00960                         d_glyph_images->setAutoScalingEnabled(setting);
00961                 }
00962 
00963                 d_autoScale = setting;
00964                 updateFontScaling();
00965         }
00966 
00967 }
00968 
00969 
00970 /*************************************************************************
00971         Update the font as required according to the current scaling
00972 *************************************************************************/
00973 void Font::updateFontScaling(void)
00974 {
00975         if (d_freetype)
00976         {
00977                 uint hdpi = System::getSingleton().getRenderer()->getHorzScreenDPI();
00978                 uint vdpi = System::getSingleton().getRenderer()->getVertScreenDPI();
00979 
00980                 createFontFromFT_Face(d_ptSize, hdpi, vdpi);
00981         }
00982         // bitmapped font
00983         else
00984         {
00985                 float hscale = d_autoScale ? d_horzScaling : 1.0f;
00986 
00987                 // perform update on font mapping advance values
00988                 CodepointMap::iterator pos = d_cp_map.begin(), end = d_cp_map.end();
00989                 for (; pos != end; ++pos)
00990                 {
00991                         pos->second.d_horz_advance = (uint)(((float)pos->second.d_horz_advance_unscaled) * hscale);
00992                 }
00993 
00994                 // re-calculate height
00995                 calculateStaticVertSpacing();
00996         }
00997 
00998 }
00999 
01000 
01001 /*************************************************************************
01002         Set the size of the free-type font (via d_impldat->fontFace which should already
01003         be setup) and render the glyphs in d_glyphset.
01004 *************************************************************************/
01005 void Font::createFontFromFT_Face(uint size, uint horzDpi, uint vertDpi)
01006 {
01007         if (d_autoScale)
01008         {
01009                 horzDpi = (uint)(((float)horzDpi) * d_horzScaling);
01010                 vertDpi = (uint)(((float)vertDpi) * d_vertScaling);
01011         }
01012 
01013         d_ptSize = size;
01014 
01015         if (FT_Set_Char_Size(d_impldat->fontFace, 0, d_ptSize * 64, horzDpi, vertDpi) == 0)
01016         {
01017                 defineFontGlyphs_impl();
01018         }
01019         // failed to set size for font
01020         else
01021         {
01022                 throw GenericException((utf8*)"Font::createFontFromFT_Face - An error occurred while creating a source font with the requested size.");
01023         }
01024 
01025 }
01026 
01027 
01028 /*************************************************************************
01029         Return the number of lines the given text would be formatted to.        
01030 *************************************************************************/
01031 uint Font::getFormattedLineCount(const String& text, const Rect& format_area, TextFormatting fmt, float x_scale) const
01032 {
01033         // handle simple non-wrapped cases.
01034         if ((fmt == LeftAligned) || (fmt == Centred) || (fmt == RightAligned))
01035         {
01036                 return std::count(text.begin(), text.end(), '\n') + 1;
01037         }
01038 
01039         // handle wraping cases
01040         uint lineStart = 0, lineEnd = 0;
01041         String  sourceLine;
01042 
01043         float   wrap_width = format_area.getWidth();
01044         String  whitespace = TextUtils::DefaultWhitespace;
01045         String  thisLine, thisWord;
01046         uint    line_count = 0, currpos = 0;
01047 
01048         while (lineEnd < text.length())
01049         {
01050                 if ((lineEnd = text.find_first_of('\n', lineStart)) == String::npos)
01051                 {
01052                         lineEnd = text.length();
01053                 }
01054 
01055                 sourceLine = text.substr(lineStart, lineEnd - lineStart);
01056                 lineStart = lineEnd + 1;
01057 
01058                 // get first word.
01059                 currpos = getNextWord(sourceLine, 0, thisLine);
01060 
01061                 // while there are words left in the string...
01062                 while (String::npos != sourceLine.find_first_not_of(whitespace, currpos))
01063                 {
01064                         // get next word of the string...
01065                         currpos += getNextWord(sourceLine, currpos, thisWord);
01066 
01067                         // if the new word would make the string too long
01068                         if ((getTextExtent(thisLine, x_scale) + getTextExtent(thisWord, x_scale)) > wrap_width)
01069                         {
01070                                 // too long, so that's another line of text
01071                                 line_count++;
01072 
01073                                 // remove whitespace from next word - it will form start of next line
01074                                 thisWord = thisWord.substr(thisWord.find_first_not_of(whitespace));
01075 
01076                                 // reset for a new line.
01077                                 thisLine.clear();
01078                         }
01079 
01080                         // add the next word to the line
01081                         thisLine += thisWord;
01082                 }
01083 
01084                 // plus one for final line
01085                 line_count++;
01086         }
01087 
01088         return line_count;
01089 }
01090 
01091 
01092 /*************************************************************************
01093         Return whether this font is anti-aliased or not.
01094 *************************************************************************/
01095 bool Font::isAntiAliased(void) const
01096 {
01097         return d_freetype ? d_antiAliased : false;
01098 }
01099 
01100 
01101 /*************************************************************************
01102         Set whether the font is anti-aliased or not.
01103 *************************************************************************/
01104 void Font::setAntiAliased(bool setting)
01105 {
01106         if (d_freetype && (d_antiAliased != setting))
01107         {
01108                 d_antiAliased = setting;
01109 
01110                 // regenerate font
01111                 createFontFromFT_Face(d_ptSize, System::getSingleton().getRenderer()->getHorzScreenDPI(), System::getSingleton().getRenderer()->getVertScreenDPI());
01112         }
01113 
01114 }
01115 
01116 
01117 /*************************************************************************
01118         Return the horizontal pixel extent given text would be formatted to.    
01119 *************************************************************************/
01120 float Font::getFormattedTextExtent(const String& text, const Rect& format_area, TextFormatting fmt, float x_scale) const
01121 {
01122         float lineWidth;
01123         float widest = 0;
01124 
01125         uint lineStart = 0, lineEnd = 0;
01126         String  currLine;
01127 
01128         while (lineEnd < text.length())
01129         {
01130                 if ((lineEnd = text.find_first_of('\n', lineStart)) == String::npos)
01131                 {
01132                         lineEnd = text.length();
01133                 }
01134 
01135                 currLine = text.substr(lineStart, lineEnd - lineStart);
01136                 lineStart = lineEnd + 1;        // +1 to skip \n char
01137 
01138                 switch(fmt)
01139                 {
01140                 case Centred:
01141                 case RightAligned:
01142                 case LeftAligned:
01143                         lineWidth = getTextExtent(currLine, x_scale);
01144                         break;
01145 
01146                 case WordWrapLeftAligned:
01147                 case WordWrapRightAligned:
01148                 case WordWrapCentred:
01149                         lineWidth = getWrappedTextExtent(currLine, format_area.getWidth(), x_scale);
01150                         break;
01151 
01152                 default:
01153                         throw InvalidRequestException((utf8*)"Font::getFormattedTextExtent - Unknown or unsupported TextFormatting value specified.");
01154                 }
01155 
01156                 if (lineWidth > widest)
01157                 {
01158                         widest = lineWidth;
01159                 }
01160 
01161         }
01162 
01163         return widest;
01164 }
01165 
01166 
01167 /*************************************************************************
01168         returns extent of widest line of wrapped text.
01169 *************************************************************************/
01170 float Font::getWrappedTextExtent(const String& text, float wrapWidth, float x_scale) const
01171 {
01172         String  whitespace = TextUtils::DefaultWhitespace;
01173         String  thisWord;
01174         uint    currpos;
01175         float   lineWidth, wordWidth;
01176         float   widest = 0;
01177 
01178         // get first word.
01179         currpos = getNextWord(text, 0, thisWord);
01180         lineWidth = getTextExtent(thisWord, x_scale);
01181 
01182         // while there are words left in the string...
01183         while (String::npos != text.find_first_not_of(whitespace, currpos)) {
01184                 // get next word of the string...
01185                 currpos += getNextWord(text, currpos, thisWord);
01186                 wordWidth = getTextExtent(thisWord, x_scale);
01187 
01188                 // if the new word would make the string too long
01189                 if ((lineWidth + wordWidth) > wrapWidth) {
01190                         
01191                         if (lineWidth > widest)
01192                         {
01193                                 widest = lineWidth;
01194                         }
01195 
01196                         // remove whitespace from next word - it will form start of next line
01197                         thisWord = thisWord.substr(thisWord.find_first_not_of(whitespace));
01198                         wordWidth = getTextExtent(thisWord, x_scale);
01199 
01200                         // reset for a new line.
01201                         lineWidth = 0;
01202                 }
01203 
01204                 // add the next word to the line
01205                 lineWidth += wordWidth;
01206         }
01207 
01208         if (lineWidth > widest)
01209         {
01210                 widest = lineWidth;
01211         }
01212 
01213         return widest;
01214 }
01215 
01216 
01217 /*************************************************************************
01218         Return a String object that contains the code-points that the font
01219         is currently configured to render.
01220 *************************************************************************/
01221 const String& Font::getAvailableGlyphs(void) const
01222 {
01223         return d_glyphset;
01224 }
01225 
01226 
01227 /*************************************************************************
01228         Return the point size of a dynamic (ttf based) font.
01229 *************************************************************************/
01230 uint Font::getPointSize(void) const
01231 {
01232         if (d_freetype)
01233         {
01234                 return d_ptSize;
01235         }
01236         else
01237         {
01238                 throw InvalidRequestException("Font::getPointSize - unable to return point size for a static (bitmap based) font.");
01239         }
01240 }
01241 
01242 } // End of  CEGUI namespace section

Generated on Wed Feb 16 12:41:06 2005 for Crazy Eddies GUI System by  doxygen 1.3.9.1