graphlcd-base/glcdgraphics/font.c
author root@rika
Wed, 06 Feb 2008 17:32:55 +0000
changeset 4 df6a40031aa5
permissions -rw-r--r--
added graphlcd-base
root@4
     1
/*
root@4
     2
 * GraphLCD graphics library
root@4
     3
 *
root@4
     4
 * font.c  -  font handling
root@4
     5
 *
root@4
     6
 * based on graphlcd plugin 0.1.1 for the Video Disc Recorder
root@4
     7
 *  (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
root@4
     8
 *
root@4
     9
 * This file is released under the GNU General Public License. Refer
root@4
    10
 * to the COPYING file distributed with this package.
root@4
    11
 *
root@4
    12
 * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
root@4
    13
 */
root@4
    14
root@4
    15
#include <stdio.h>
root@4
    16
#include <stdint.h>
root@4
    17
#include <syslog.h>
root@4
    18
#include <fcntl.h>
root@4
    19
#include <unistd.h>
root@4
    20
root@4
    21
#include <algorithm>
root@4
    22
root@4
    23
#include "common.h"
root@4
    24
#include "font.h"
root@4
    25
root@4
    26
#ifdef HAVE_FREETYPE2
root@4
    27
#include <ft2build.h>
root@4
    28
#include FT_FREETYPE_H
root@4
    29
#include <iconv.h>
root@4
    30
#endif
root@4
    31
root@4
    32
namespace GLCD
root@4
    33
{
root@4
    34
root@4
    35
static const char * kFontFileSign = "FNT3";
root@4
    36
static const uint32_t kFontHeaderSize = 16;
root@4
    37
static const uint32_t kCharHeaderSize = 4;
root@4
    38
root@4
    39
//#pragma pack(1)
root@4
    40
//struct tFontHeader
root@4
    41
//{
root@4
    42
//    char sign[4];          // = FONTFILE_SIGN
root@4
    43
//    unsigned short height; // total height of the font
root@4
    44
//    unsigned short ascent; // ascender of the font
root@4
    45
//    unsigned short line;   // line height
root@4
    46
//    unsigned short reserved;
root@4
    47
//    unsigned short space;  // space between characters of a string
root@4
    48
//    unsigned short count;  // number of chars in this file
root@4
    49
//};
root@4
    50
//
root@4
    51
//struct tCharHeader
root@4
    52
//{
root@4
    53
//    unsigned short character;
root@4
    54
//    unsigned short width;
root@4
    55
//};
root@4
    56
//#pragma pack()
root@4
    57
root@4
    58
cFont::cFont()
root@4
    59
{
root@4
    60
    Init();
root@4
    61
}
root@4
    62
root@4
    63
cFont::~cFont()
root@4
    64
{
root@4
    65
    Unload();
root@4
    66
}
root@4
    67
root@4
    68
bool cFont::LoadFNT(const std::string & fileName)
root@4
    69
{
root@4
    70
    // cleanup if we already had a loaded font
root@4
    71
    Unload();
root@4
    72
root@4
    73
    FILE * fontFile;
root@4
    74
    int i;
root@4
    75
    uint8_t buffer[10000];
root@4
    76
    uint16_t fontHeight;
root@4
    77
    uint16_t numChars;
root@4
    78
    int maxWidth = 0;
root@4
    79
root@4
    80
    fontFile = fopen(fileName.c_str(), "rb");
root@4
    81
    if (!fontFile)
root@4
    82
        return false;
root@4
    83
root@4
    84
    fread(buffer, kFontHeaderSize, 1, fontFile);
root@4
    85
    if (buffer[0] != kFontFileSign[0] ||
root@4
    86
        buffer[1] != kFontFileSign[1] ||
root@4
    87
        buffer[2] != kFontFileSign[2] ||
root@4
    88
        buffer[3] != kFontFileSign[3])
root@4
    89
    {
root@4
    90
        fclose(fontFile);
root@4
    91
        return false;
root@4
    92
    }
root@4
    93
root@4
    94
    fontHeight = buffer[4] | (buffer[5] << 8);
root@4
    95
    totalAscent = buffer[6] | (buffer[7] << 8);
root@4
    96
    lineHeight = buffer[8] | (buffer[9] << 8);
root@4
    97
    spaceBetween = buffer[12] | (buffer[13] << 8);
root@4
    98
    numChars = buffer[14] | (buffer[15] << 8);
root@4
    99
    for (i = 0; i < numChars; i++)
root@4
   100
    {
root@4
   101
        uint8_t chdr[kCharHeaderSize];
root@4
   102
        uint16_t charWidth;
root@4
   103
        uint16_t character;
root@4
   104
        fread(chdr, kCharHeaderSize, 1, fontFile);
root@4
   105
        character = chdr[0] | (chdr[1] << 8);
root@4
   106
        charWidth = chdr[2] | (chdr[3] << 8);
root@4
   107
        fread(buffer, fontHeight * ((charWidth + 7) / 8), 1, fontFile);
root@4
   108
        if (characters[character])
root@4
   109
            delete characters[character];
root@4
   110
        characters[character] = new cBitmap(charWidth, fontHeight, buffer);
root@4
   111
        if (characters[character]->Width() > maxWidth)
root@4
   112
            maxWidth = characters[character]->Width();
root@4
   113
    }
root@4
   114
    fclose(fontFile);
root@4
   115
root@4
   116
    totalWidth = maxWidth;
root@4
   117
    totalHeight = fontHeight;
root@4
   118
root@4
   119
    return true;
root@4
   120
}
root@4
   121
root@4
   122
bool cFont::SaveFNT(const std::string & fileName) const
root@4
   123
{
root@4
   124
    FILE * fontFile;
root@4
   125
    uint8_t fhdr[kFontHeaderSize];
root@4
   126
    uint8_t chdr[kCharHeaderSize];
root@4
   127
    uint16_t numChars;
root@4
   128
    int i;
root@4
   129
root@4
   130
    fontFile = fopen(fileName.c_str(),"w+b");
root@4
   131
    if (!fontFile)
root@4
   132
    {
root@4
   133
        syslog(LOG_ERR, "cFont::SaveFNT(): Cannot open file: %s for writing\n",fileName.c_str());
root@4
   134
        return false;
root@4
   135
    }
root@4
   136
root@4
   137
    numChars = 0;
root@4
   138
    for (i = 0; i < 256; i++)
root@4
   139
    {
root@4
   140
        if (characters[i])
root@4
   141
        {
root@4
   142
            numChars++;
root@4
   143
        }
root@4
   144
    }
root@4
   145
root@4
   146
    memcpy(fhdr, kFontFileSign, 4);
root@4
   147
    fhdr[4] = (uint8_t) totalHeight;
root@4
   148
    fhdr[5] = (uint8_t) (totalHeight >> 8);
root@4
   149
    fhdr[6] = (uint8_t) totalAscent;
root@4
   150
    fhdr[7] = (uint8_t) (totalAscent >> 8);
root@4
   151
    fhdr[8] = (uint8_t) lineHeight;
root@4
   152
    fhdr[9] = (uint8_t) (lineHeight >> 8);
root@4
   153
    fhdr[10] = 0;
root@4
   154
    fhdr[11] = 0;
root@4
   155
    fhdr[12] = (uint8_t) spaceBetween;
root@4
   156
    fhdr[13] = (uint8_t) (spaceBetween >> 8);
root@4
   157
    fhdr[14] = (uint8_t) numChars;
root@4
   158
    fhdr[15] = (uint8_t) (numChars >> 8);
root@4
   159
root@4
   160
    // write font file header
root@4
   161
    fwrite(fhdr, kFontHeaderSize, 1, fontFile);
root@4
   162
root@4
   163
    for (i = 0; i < 256; i++)
root@4
   164
    {
root@4
   165
        if (characters[i])
root@4
   166
        {
root@4
   167
            chdr[0] = (uint8_t) i;
root@4
   168
            chdr[1] = (uint8_t) (i >> 8);
root@4
   169
            chdr[2] = (uint8_t) characters[i]->Width();
root@4
   170
            chdr[3] = (uint8_t) (characters[i]->Width() >> 8);
root@4
   171
            fwrite(chdr, kCharHeaderSize, 1, fontFile);
root@4
   172
            fwrite(characters[i]->Data(), totalHeight * characters[i]->LineSize(), 1, fontFile);
root@4
   173
        }
root@4
   174
    }
root@4
   175
root@4
   176
    fclose(fontFile);
root@4
   177
root@4
   178
    syslog(LOG_DEBUG, "cFont::SaveFNT(): Font file '%s' written successfully\n", fileName.c_str());
root@4
   179
root@4
   180
    return true;
root@4
   181
}
root@4
   182
root@4
   183
bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding,
root@4
   184
                    int size, bool dingBats)
root@4
   185
{
root@4
   186
    // cleanup if we already had a loaded font
root@4
   187
    Unload();
root@4
   188
#ifdef HAVE_FREETYPE2
root@4
   189
    if (access(fileName.c_str(), F_OK) != 0)
root@4
   190
    {
root@4
   191
        syslog(LOG_ERR, "cFont::LoadFT2: Font file (%s) does not exist!!", fileName.c_str());
root@4
   192
        return false;
root@4
   193
    }
root@4
   194
    // file exists
root@4
   195
    FT_Library library;
root@4
   196
    FT_Face face;
root@4
   197
    FT_GlyphSlot slot;
root@4
   198
root@4
   199
    int error = FT_Init_FreeType(&library);
root@4
   200
    if (error)
root@4
   201
    {
root@4
   202
        syslog(LOG_ERR, "cFont::LoadFT2: Could not init freetype library");
root@4
   203
        return false;
root@4
   204
    }
root@4
   205
    error = FT_New_Face(library, fileName.c_str(), 0, &face);
root@4
   206
    // everything ok?
root@4
   207
    if (error == FT_Err_Unknown_File_Format)
root@4
   208
    {
root@4
   209
        syslog(LOG_ERR, "cFont::LoadFT2: Font file (%s) could be opened and read, but it appears that its font format is unsupported", fileName.c_str());
root@4
   210
        error = FT_Done_Face(face);
root@4
   211
        syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error);
root@4
   212
        error = FT_Done_FreeType(library);
root@4
   213
        syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error);
root@4
   214
        return false;
root@4
   215
    }
root@4
   216
    else if (error)
root@4
   217
    {
root@4
   218
        syslog(LOG_ERR, "cFont::LoadFT2: Font file (%s) could not be opened or read, or simply it is broken,\n error code was %x", fileName.c_str(), error);
root@4
   219
        error = FT_Done_Face(face);
root@4
   220
        syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error);
root@4
   221
        error = FT_Done_FreeType(library);
root@4
   222
        syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error);
root@4
   223
        return false;
root@4
   224
    }
root@4
   225
root@4
   226
    // set slot
root@4
   227
    slot = face->glyph;
root@4
   228
root@4
   229
    // set Size
root@4
   230
    FT_Set_Char_Size(face, 0, size * 64, 0, 0);
root@4
   231
root@4
   232
    wchar_t utf_buff[256];
root@4
   233
    if (dingBats)
root@4
   234
    {
root@4
   235
/*
root@4
   236
        FT_CharMap charmap = 0;
root@4
   237
        for (int n = 0; n < face->num_charmaps; n++)
root@4
   238
        {
root@4
   239
            if (face->charmaps[n]->platform_id == 3 &&
root@4
   240
                face->charmaps[n]->encoding_id == 0)
root@4
   241
            {
root@4
   242
                charmap = face->charmaps[n];
root@4
   243
                //break;
root@4
   244
            }
root@4
   245
        }
root@4
   246
        if (charmap)
root@4
   247
            syslog(LOG_ERR, "cFont::LoadFT2: platform_id: %d, encoding_id: %d", charmap->platform_id, charmap->encoding_id);
root@4
   248
        error = FT_Set_Charmap(_face, charmap);
root@4
   249
        if (error)
root@4
   250
        {
root@4
   251
            syslog(LOG_ERR, "cFont::LoadFT2: FT_Select_Charmap encoding not supported: %d", charmap->encoding_id);
root@4
   252
        }
root@4
   253
*/
root@4
   254
    }
root@4
   255
    else
root@4
   256
    {
root@4
   257
        iconv_t cd;
root@4
   258
        if ((cd = iconv_open("WCHAR_T", encoding.c_str())) == (iconv_t) -1)
root@4
   259
        {
root@4
   260
            syslog(LOG_ERR, "cFont::LoadFT2: Iconv encoding not supported: %s", encoding.c_str());
root@4
   261
            error = FT_Done_Face(face);
root@4
   262
            syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error);
root@4
   263
            error = FT_Done_FreeType(library);
root@4
   264
            syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error);
root@4
   265
            return false;
root@4
   266
        }
root@4
   267
        for (int c = 0; c < 256; c++)
root@4
   268
        {
root@4
   269
            char char_buff = c;
root@4
   270
            wchar_t wchar_buff;
root@4
   271
            char * in_buff,* out_buff;
root@4
   272
            size_t in_len, out_len, count;
root@4
   273
root@4
   274
            in_len = 1;
root@4
   275
            out_len = 4;
root@4
   276
            in_buff = (char *) &char_buff;
root@4
   277
            out_buff = (char *) &wchar_buff;
root@4
   278
            count = iconv(cd, &in_buff, &in_len, &out_buff, &out_len);
root@4
   279
            if ((size_t) -1 == count)
root@4
   280
            {
root@4
   281
                utf_buff[c] = 0;
root@4
   282
            }
root@4
   283
            utf_buff[c] = wchar_buff;
root@4
   284
        }
root@4
   285
        iconv_close(cd);
root@4
   286
    }
root@4
   287
root@4
   288
    // get some global parameters
root@4
   289
    totalHeight = (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6);
root@4
   290
    totalWidth = face->size->metrics.max_advance >> 6;
root@4
   291
    totalAscent = face->size->metrics.ascender >> 6;
root@4
   292
    lineHeight = face->size->metrics.height >> 6;
root@4
   293
    spaceBetween = 0;
root@4
   294
#if 0
root@4
   295
    syslog(LOG_DEBUG, "cFont::LoadFT2: totalHeight = %d", totalHeight);
root@4
   296
    syslog(LOG_DEBUG, "cFont::LoadFT2: totalWidth = %d", totalWidth);
root@4
   297
    syslog(LOG_DEBUG, "cFont::LoadFT2: totalAscent = %d", totalAscent);
root@4
   298
    syslog(LOG_DEBUG, "cFont::LoadFT2: lineHeight = %d", lineHeight);
root@4
   299
    syslog(LOG_DEBUG, "cFont::LoadFT2: spaceBetween = %d", spaceBetween);
root@4
   300
#endif
root@4
   301
    // render glyphs for ASCII codes 0 to 255 in our bitmap class
root@4
   302
    FT_UInt glyph_index;
root@4
   303
    int num_char;
root@4
   304
root@4
   305
    for (num_char = 0; num_char < 256; num_char++)
root@4
   306
    {
root@4
   307
        if (dingBats)
root@4
   308
        {
root@4
   309
            //Get FT char index & load the char
root@4
   310
            error = FT_Load_Char(face, num_char, FT_LOAD_DEFAULT);
root@4
   311
        }
root@4
   312
        else
root@4
   313
        {
root@4
   314
            //Get FT char index
root@4
   315
            glyph_index = FT_Get_Char_Index(face, utf_buff[num_char]);
root@4
   316
            //Load the char
root@4
   317
            error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
root@4
   318
        }
root@4
   319
        if (error)
root@4
   320
        {
root@4
   321
            syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Load_Glyph: %x", error);
root@4
   322
        }
root@4
   323
root@4
   324
        // convert to a mono bitmap
root@4
   325
        error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
root@4
   326
        if (error)
root@4
   327
        {
root@4
   328
            syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Render_Glyph: %x", error);
root@4
   329
        }
root@4
   330
root@4
   331
        // now, fill our pixel data
root@4
   332
        cBitmap * charBitmap = new cBitmap(face->glyph->advance.x >> 6, totalHeight);
root@4
   333
        charBitmap->Clear();
root@4
   334
        unsigned char * bufPtr = face->glyph->bitmap.buffer;
root@4
   335
        unsigned char pixel;
root@4
   336
        for (int y = 0; y < face->glyph->bitmap.rows; y++)
root@4
   337
        {
root@4
   338
            for (int x = 0; x < face->glyph->bitmap.width; x++)
root@4
   339
            {
root@4
   340
                pixel = (bufPtr[x / 8] >> (7 - x % 8)) & 1;
root@4
   341
                if (pixel)
root@4
   342
                    charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x,
root@4
   343
                                          (face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y,
root@4
   344
                                          GLCD::clrBlack);
root@4
   345
            }
root@4
   346
            bufPtr += face->glyph->bitmap.pitch;
root@4
   347
        }
root@4
   348
        SetCharacter((char) num_char, charBitmap);
root@4
   349
    }
root@4
   350
    error = FT_Done_Face(face);
root@4
   351
    if (error)
root@4
   352
    {
root@4
   353
        syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error);
root@4
   354
    }
root@4
   355
    error = FT_Done_FreeType(library);
root@4
   356
    if (error)
root@4
   357
    {
root@4
   358
        syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error);
root@4
   359
    }
root@4
   360
    return true;
root@4
   361
#else
root@4
   362
    syslog(LOG_ERR, "cFont::LoadFT2: glcdgraphics was compiled without FreeType2 support!!!");
root@4
   363
    return false;
root@4
   364
#endif
root@4
   365
}
root@4
   366
root@4
   367
int cFont::Width(char ch) const
root@4
   368
{
root@4
   369
    if (characters[(unsigned char) ch])
root@4
   370
        return characters[(unsigned char) ch]->Width();
root@4
   371
    else
root@4
   372
        return 0;
root@4
   373
}
root@4
   374
root@4
   375
int cFont::Width(const std::string & str) const
root@4
   376
{
root@4
   377
    unsigned int i;
root@4
   378
    int sum = 0;
root@4
   379
root@4
   380
    for (i = 0; i < str.length(); i++)
root@4
   381
    {
root@4
   382
        sum += Width(str[i]);
root@4
   383
    }
root@4
   384
    if (str.length() > 1)
root@4
   385
    {
root@4
   386
        sum += spaceBetween * (str.length() - 1);
root@4
   387
    }
root@4
   388
    return sum;
root@4
   389
}
root@4
   390
root@4
   391
int cFont::Width(const std::string & str, unsigned int len) const
root@4
   392
{
root@4
   393
    unsigned int i;
root@4
   394
    int sum = 0;
root@4
   395
root@4
   396
    for (i = 0; i < str.length() && i < len; i++)
root@4
   397
    {
root@4
   398
        sum += Width(str[i]);
root@4
   399
    }
root@4
   400
    if (std::min(str.length(), (size_t) len) > 1)
root@4
   401
    {
root@4
   402
        sum += spaceBetween * (std::min(str.length(), (size_t) len) - 1);
root@4
   403
    }
root@4
   404
    return sum;
root@4
   405
}
root@4
   406
root@4
   407
int cFont::Height(char ch) const
root@4
   408
{
root@4
   409
    if (characters[(unsigned char) ch])
root@4
   410
        return characters[(unsigned char) ch]->Height();
root@4
   411
    else
root@4
   412
        return 0;
root@4
   413
}
root@4
   414
root@4
   415
int cFont::Height(const std::string & str) const
root@4
   416
{
root@4
   417
    unsigned int i;
root@4
   418
    int sum = 0;
root@4
   419
root@4
   420
    for (i = 0; i < str.length(); i++)
root@4
   421
        sum = std::max(sum, Height(str[i]));
root@4
   422
    return sum;
root@4
   423
}
root@4
   424
root@4
   425
int cFont::Height(const std::string & str, unsigned int len) const
root@4
   426
{
root@4
   427
    unsigned int i;
root@4
   428
    int sum = 0;
root@4
   429
root@4
   430
    for (i = 0; i < str.length() && i < len; i++)
root@4
   431
        sum = std::max(sum, Height(str[i]));
root@4
   432
    return sum;
root@4
   433
}
root@4
   434
root@4
   435
const cBitmap * cFont::GetCharacter(char ch) const
root@4
   436
{
root@4
   437
    return characters[(unsigned char) ch];
root@4
   438
}
root@4
   439
root@4
   440
void cFont::SetCharacter(char ch, cBitmap * bitmapChar)
root@4
   441
{
root@4
   442
    // adjust maxwidth if necessary
root@4
   443
    if (totalWidth < bitmapChar->Width())
root@4
   444
        totalWidth = bitmapChar->Width();
root@4
   445
root@4
   446
    // delete if already allocated
root@4
   447
    if (characters[(unsigned char) ch])
root@4
   448
        delete characters[(unsigned char) ch];
root@4
   449
root@4
   450
    // store new character
root@4
   451
    characters[(unsigned char) ch] = bitmapChar;
root@4
   452
}
root@4
   453
root@4
   454
void cFont::Init()
root@4
   455
{
root@4
   456
    totalWidth = 0;
root@4
   457
    totalHeight = 0;
root@4
   458
    totalAscent = 0;
root@4
   459
    spaceBetween = 0;
root@4
   460
    lineHeight = 0;
root@4
   461
    for (int i = 0; i < 256; i++)
root@4
   462
    {
root@4
   463
        characters[i] = NULL;
root@4
   464
    }
root@4
   465
}
root@4
   466
root@4
   467
void cFont::Unload()
root@4
   468
{
root@4
   469
    // cleanup
root@4
   470
    for (int i = 0; i < 256; i++)
root@4
   471
    {
root@4
   472
        if (characters[i])
root@4
   473
        {
root@4
   474
            delete characters[i];
root@4
   475
        }
root@4
   476
    }
root@4
   477
    // re-init
root@4
   478
    Init();
root@4
   479
}
root@4
   480
root@4
   481
void cFont::WrapText(int Width, int Height, std::string & Text,
root@4
   482
                     std::vector <std::string> & Lines, int * ActualWidth) const
root@4
   483
{
root@4
   484
    int maxLines;
root@4
   485
    int lineCount;
root@4
   486
    int textWidth;
root@4
   487
    std::string::size_type start;
root@4
   488
    std::string::size_type pos;
root@4
   489
    std::string::size_type posLast;
root@4
   490
root@4
   491
    Lines.clear();
root@4
   492
    maxLines = 2000;
root@4
   493
    if (Height > 0)
root@4
   494
    {
root@4
   495
        maxLines = Height / LineHeight();
root@4
   496
        if (maxLines == 0)
root@4
   497
            maxLines = 1;
root@4
   498
    }
root@4
   499
    lineCount = 0;
root@4
   500
root@4
   501
    pos = 0;
root@4
   502
    start = 0;
root@4
   503
    posLast = 0;
root@4
   504
    textWidth = 0;
root@4
   505
    while (pos < Text.length() && (Height == 0 || lineCount < maxLines))
root@4
   506
    {
root@4
   507
        if (Text[pos] == '\n')
root@4
   508
        {
root@4
   509
            Lines.push_back(trim(Text.substr(start, pos - start)));
root@4
   510
            start = pos + 1;
root@4
   511
            posLast = pos + 1;
root@4
   512
            textWidth = 0;
root@4
   513
            lineCount++;
root@4
   514
        }
root@4
   515
        else if (textWidth > Width && (lineCount + 1) < maxLines)
root@4
   516
        {
root@4
   517
            if (posLast > start)
root@4
   518
            {
root@4
   519
                Lines.push_back(trim(Text.substr(start, posLast - start)));
root@4
   520
                start = posLast + 1;
root@4
   521
                posLast = start;
root@4
   522
                textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween;
root@4
   523
            }
root@4
   524
            else
root@4
   525
            {
root@4
   526
                Lines.push_back(trim(Text.substr(start, pos - start)));
root@4
   527
                start = pos + 1;
root@4
   528
                posLast = start;
root@4
   529
                textWidth = this->Width(Text[pos]) + spaceBetween;
root@4
   530
            }
root@4
   531
            lineCount++;
root@4
   532
        }
root@4
   533
        else if (Text[pos] == ' ')
root@4
   534
        {
root@4
   535
            posLast = pos;
root@4
   536
            textWidth += this->Width(Text[pos]) + spaceBetween;
root@4
   537
        }
root@4
   538
        else
root@4
   539
        {
root@4
   540
            textWidth += this->Width(Text[pos]) + spaceBetween;
root@4
   541
        }
root@4
   542
        pos++;
root@4
   543
    }
root@4
   544
root@4
   545
    if (Height == 0 || lineCount < maxLines)
root@4
   546
    {
root@4
   547
        if (textWidth > Width && (lineCount + 1) < maxLines)
root@4
   548
        {
root@4
   549
            if (posLast > start)
root@4
   550
            {
root@4
   551
                Lines.push_back(trim(Text.substr(start, posLast - start)));
root@4
   552
                start = posLast + 1;
root@4
   553
                posLast = start;
root@4
   554
                textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween;
root@4
   555
            }
root@4
   556
            else
root@4
   557
            {
root@4
   558
                Lines.push_back(trim(Text.substr(start, pos - start)));
root@4
   559
                start = pos + 1;
root@4
   560
                posLast = start;
root@4
   561
                textWidth = this->Width(Text[pos]) + spaceBetween;
root@4
   562
            }
root@4
   563
            lineCount++;
root@4
   564
        }
root@4
   565
        if (pos > start)
root@4
   566
        {
root@4
   567
            Lines.push_back(trim(Text.substr(start)));
root@4
   568
            lineCount++;
root@4
   569
        }
root@4
   570
        textWidth = 0;
root@4
   571
        for (int i = 0; i < lineCount; i++)
root@4
   572
            textWidth = std::max(textWidth, this->Width(Lines[i]));
root@4
   573
        textWidth = std::min(textWidth, Width);
root@4
   574
    }
root@4
   575
    else
root@4
   576
        textWidth = Width;
root@4
   577
    if (ActualWidth)
root@4
   578
        *ActualWidth = textWidth;
root@4
   579
}
root@4
   580
root@4
   581
} // end of namespace