Bug Summary

File:font.c
Location:line 613, column 30
Description:Dereference of null pointer (loaded from variable 'p')

Annotated Source Code

1/*
2 * font.c: Font handling for the DVB On Screen Display
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * BiDi support by Osama Alrawab <alrawab@hotmail.com> @2008 Tripoli-Libya.
8 *
9 * $Id: font.c 3.2 2014/01/07 12:19:45 kls Exp $
10 */
11
12#include "font.h"
13#include <ctype.h>
14#include <fontconfig/fontconfig.h>
15#ifdef BIDI
16#include <fribidi.h>
17#endif
18#include <ft2build.h>
19#include FT_FREETYPE_H<freetype.h>
20#include "config.h"
21#include "osd.h"
22#include "tools.h"
23
24const char *DefaultFontOsd = "Sans Serif:Bold";
25const char *DefaultFontSml = "Sans Serif";
26const char *DefaultFontFix = "Courier:Bold";
27
28// --- cFreetypeFont ---------------------------------------------------------
29
30#define KERNING_UNKNOWN(-10000) (-10000)
31
32struct tKerning {
33 uint prevSym;
34 int kerning;
35 tKerning(uint PrevSym, int Kerning = 0) { prevSym = PrevSym; kerning = Kerning; }
36 };
37
38class cGlyph : public cListObject {
39private:
40 uint charCode;
41 uchar *bitmap;
42 int advanceX;
43 int advanceY;
44 int left; ///< The bitmap's left bearing expressed in integer pixels.
45 int top; ///< The bitmap's top bearing expressed in integer pixels.
46 int width; ///< The number of pixels per bitmap row.
47 int rows; ///< The number of bitmap rows.
48 int pitch; ///< The pitch's absolute value is the number of bytes taken by one bitmap row, including padding.
49 cVector<tKerning> kerningCache;
50public:
51 cGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData);
52 virtual ~cGlyph();
53 uint CharCode(void) const { return charCode; }
54 uchar *Bitmap(void) const { return bitmap; }
55 int AdvanceX(void) const { return advanceX; }
56 int AdvanceY(void) const { return advanceY; }
57 int Left(void) const { return left; }
58 int Top(void) const { return top; }
59 int Width(void) const { return width; }
60 int Rows(void) const { return rows; }
61 int Pitch(void) const { return pitch; }
62 int GetKerningCache(uint PrevSym) const;
63 void SetKerningCache(uint PrevSym, int Kerning);
64 };
65
66cGlyph::cGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData)
67{
68 charCode = CharCode;
69 advanceX = GlyphData->advance.x >> 6;
70 advanceY = GlyphData->advance.y >> 6;
71 left = GlyphData->bitmap_left;
72 top = GlyphData->bitmap_top;
73 width = GlyphData->bitmap.width;
74 rows = GlyphData->bitmap.rows;
75 pitch = GlyphData->bitmap.pitch;
76 bitmap = MALLOC(uchar, rows * pitch)(uchar *)malloc(sizeof(uchar) * (rows * pitch));
77 memcpy(bitmap, GlyphData->bitmap.buffer, rows * pitch);
78}
79
80cGlyph::~cGlyph()
81{
82 free(bitmap);
83}
84
85int cGlyph::GetKerningCache(uint PrevSym) const
86{
87 for (int i = kerningCache.Size(); --i > 0; ) {
88 if (kerningCache[i].prevSym == PrevSym)
89 return kerningCache[i].kerning;
90 }
91 return KERNING_UNKNOWN(-10000);
92}
93
94void cGlyph::SetKerningCache(uint PrevSym, int Kerning)
95{
96 kerningCache.Append(tKerning(PrevSym, Kerning));
97}
98
99class cFreetypeFont : public cFont {
100private:
101 cString fontName;
102 int size;
103 int height;
104 int bottom;
105 FT_Library library; ///< Handle to library
106 FT_Face face; ///< Handle to face object
107 mutable cList<cGlyph> glyphCacheMonochrome;
108 mutable cList<cGlyph> glyphCacheAntiAliased;
109 int Bottom(void) const { return bottom; }
110 int Kerning(cGlyph *Glyph, uint PrevSym) const;
111 cGlyph* Glyph(uint CharCode, bool AntiAliased = false) const;
112public:
113 cFreetypeFont(const char *Name, int CharHeight, int CharWidth = 0);
114 virtual ~cFreetypeFont();
115 virtual const char *FontName(void) const { return fontName; }
116 virtual int Size(void) const { return size; }
117 virtual int Width(uint c) const;
118 virtual int Width(const char *s) const;
119 virtual int Height(void) const { return height; }
120 virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const;
121 virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const;
122 };
123
124cFreetypeFont::cFreetypeFont(const char *Name, int CharHeight, int CharWidth)
125{
126 fontName = Name;
127 size = CharHeight;
128 height = 0;
129 bottom = 0;
130 int error = FT_Init_FreeType(&library);
131 if (!error) {
132 error = FT_New_Face(library, Name, 0, &face);
133 if (!error) {
134 if (face->num_fixed_sizes && face->available_sizes) { // fixed font
135 // TODO what exactly does all this mean?
136 height = face->available_sizes->height;
137 for (uint sym ='A'; sym < 'z'; sym++) { // search for descender for fixed font FIXME
138 FT_UInt glyph_index = FT_Get_Char_Index(face, sym);
139 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT0x0);
140 if (!error) {
141 error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
142 if (!error) {
143 if (face->glyph->bitmap.rows-face->glyph->bitmap_top > bottom)
144 bottom = face->glyph->bitmap.rows-face->glyph->bitmap_top;
145 }
146 else
147 esyslog("ERROR: FreeType: error %d in FT_Render_Glyph", error)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: FreeType: error %d in FT_Render_Glyph"
, error) : void() )
;
148 }
149 else
150 esyslog("ERROR: FreeType: error %d in FT_Load_Glyph", error)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: FreeType: error %d in FT_Load_Glyph"
, error) : void() )
;
151 }
152 }
153 else {
154 error = FT_Set_Char_Size(face, // handle to face object
155 CharWidth * 64, // CharWidth in 1/64th of points
156 CharHeight * 64, // CharHeight in 1/64th of points
157 0, // horizontal device resolution
158 0); // vertical device resolution
159 if (!error) {
160 height = (face->size->metrics.ascender - face->size->metrics.descender + 63) / 64;
161 bottom = abs((face->size->metrics.descender - 63) / 64);
162 }
163 else
164 esyslog("ERROR: FreeType: error %d during FT_Set_Char_Size (font = %s)\n", error, Name)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: FreeType: error %d during FT_Set_Char_Size (font = %s)\n"
, error, Name) : void() )
;
165 }
166 }
167 else
168 esyslog("ERROR: FreeType: load error %d (font = %s)", error, Name)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: FreeType: load error %d (font = %s)"
, error, Name) : void() )
;
169 }
170 else
171 esyslog("ERROR: FreeType: initialization error %d (font = %s)", error, Name)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: FreeType: initialization error %d (font = %s)"
, error, Name) : void() )
;
172}
173
174cFreetypeFont::~cFreetypeFont()
175{
176 FT_Done_Face(face);
177 FT_Done_FreeType(library);
178}
179
180int cFreetypeFont::Kerning(cGlyph *Glyph, uint PrevSym) const
181{
182 int kerning = 0;
183 if (Glyph && PrevSym) {
184 kerning = Glyph->GetKerningCache(PrevSym);
185 if (kerning == KERNING_UNKNOWN(-10000)) {
186 FT_Vector delta;
187 FT_UInt glyph_index = FT_Get_Char_Index(face, Glyph->CharCode());
188 FT_UInt glyph_index_prev = FT_Get_Char_Index(face, PrevSym);
189 FT_Get_Kerning(face, glyph_index_prev, glyph_index, FT_KERNING_DEFAULT, &delta);
190 kerning = delta.x / 64;
191 Glyph->SetKerningCache(PrevSym, kerning);
192 }
193 }
194 return kerning;
195}
196
197cGlyph* cFreetypeFont::Glyph(uint CharCode, bool AntiAliased) const
198{
199 // Non-breaking space:
200 if (CharCode == 0xA0)
201 CharCode = 0x20;
202
203 // Lookup in cache:
204 cList<cGlyph> *glyphCache = AntiAliased ? &glyphCacheAntiAliased : &glyphCacheMonochrome;
205 for (cGlyph *g = glyphCache->First(); g; g = glyphCache->Next(g)) {
206 if (g->CharCode() == CharCode)
207 return g;
208 }
209
210 FT_UInt glyph_index = FT_Get_Char_Index(face, CharCode);
211
212 // Load glyph image into the slot (erase previous one):
213 int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT0x0);
214 if (error)
215 esyslog("ERROR: FreeType: error during FT_Load_Glyph")void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: FreeType: error during FT_Load_Glyph"
) : void() )
;
216 else {
217#if ((FREETYPE_MAJOR2 == 2 && FREETYPE_MINOR5 == 1 && FREETYPE_PATCH2 >= 7) || (FREETYPE_MAJOR2 == 2 && FREETYPE_MINOR5 == 2 && FREETYPE_PATCH2 <= 1))// TODO workaround for bug? which one?
218 if (AntiAliased || CharCode == 32)
219#else
220 if (AntiAliased)
221#endif
222 error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
223 else
224 error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
225 if (error)
226 esyslog("ERROR: FreeType: error during FT_Render_Glyph %d, %d\n", CharCode, glyph_index)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: FreeType: error during FT_Render_Glyph %d, %d\n"
, CharCode, glyph_index) : void() )
;
227 else { //new bitmap
228 cGlyph *Glyph = new cGlyph(CharCode, face->glyph);
229 glyphCache->Add(Glyph);
230 return Glyph;
231 }
232 }
233#define UNKNOWN_GLYPH_INDICATOR'?' '?'
234 if (CharCode != UNKNOWN_GLYPH_INDICATOR'?')
235 return Glyph(UNKNOWN_GLYPH_INDICATOR'?', AntiAliased);
236 return NULL__null;
237}
238
239int cFreetypeFont::Width(uint c) const
240{
241 cGlyph *g = Glyph(c, Setup.AntiAlias);
242 return g ? g->AdvanceX() : 0;
243}
244
245int cFreetypeFont::Width(const char *s) const
246{
247 int w = 0;
248 if (s) {
249#ifdef BIDI
250 cString bs = Bidi(s);
251 s = bs;
252#endif
253 uint prevSym = 0;
254 while (*s) {
255 int sl = Utf8CharLen(s);
256 uint sym = Utf8CharGet(s, sl);
257 s += sl;
258 cGlyph *g = Glyph(sym, Setup.AntiAlias);
259 if (g)
260 w += g->AdvanceX() + Kerning(g, prevSym);
261 prevSym = sym;
262 }
263 }
264 return w;
265}
266
267#define MAX_BLEND_LEVELS256 256
268
269void cFreetypeFont::DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const
270{
271 if (s && height) { // checking height to make sure we actually have a valid font
272#ifdef BIDI
273 cString bs = Bidi(s);
274 s = bs;
275#endif
276 bool AntiAliased = Setup.AntiAlias && Bitmap->Bpp() >= 8;
277 bool TransparentBackground = ColorBg == clrTransparent;
278 int16_t BlendLevelIndex[MAX_BLEND_LEVELS256]; // tIndex is 8 bit unsigned, so a negative value can be used to mark unused entries
279 if (AntiAliased && !TransparentBackground)
280 memset(BlendLevelIndex, 0xFF, sizeof(BlendLevelIndex)); // initializes the array with negative values
281 tIndex fg = Bitmap->Index(ColorFg);
282 uint prevSym = 0;
283 while (*s) {
284 int sl = Utf8CharLen(s);
285 uint sym = Utf8CharGet(s, sl);
286 s += sl;
287 cGlyph *g = Glyph(sym, AntiAliased);
288 if (!g)
289 continue;
290 int kerning = Kerning(g, prevSym);
291 prevSym = sym;
292 uchar *buffer = g->Bitmap();
293 int symWidth = g->Width();
294 if (Width && x + symWidth + g->Left() + kerning - 1 > Width)
295 break; // we don't draw partial characters
296 if (x + symWidth + g->Left() + kerning > 0) {
297 for (int row = 0; row < g->Rows(); row++) {
298 for (int pitch = 0; pitch < g->Pitch(); pitch++) {
299 uchar bt = *(buffer + (row * g->Pitch() + pitch));
300 if (AntiAliased) {
301 if (bt > 0x00) {
302 int px = x + pitch + g->Left() + kerning;
303 int py = y + row + (height - Bottom() - g->Top());
304 tColor bg;
305 if (bt == 0xFF)
306 bg = fg;
307 else if (TransparentBackground)
308 bg = Bitmap->Index(Bitmap->Blend(ColorFg, Bitmap->GetColor(px, py), bt));
309 else if (BlendLevelIndex[bt] >= 0)
310 bg = BlendLevelIndex[bt];
311 else
312 bg = BlendLevelIndex[bt] = Bitmap->Index(Bitmap->Blend(ColorFg, ColorBg, bt));
313 Bitmap->SetIndex(px, py, bg);
314 }
315 }
316 else { //monochrome rendering
317 for (int col = 0; col < 8 && col + pitch * 8 <= symWidth; col++) {
318 if (bt & 0x80)
319 Bitmap->SetIndex(x + col + pitch * 8 + g->Left() + kerning, y + row + (height - Bottom() - g->Top()), fg);
320 bt <<= 1;
321 }
322 }
323 }
324 }
325 }
326 x += g->AdvanceX() + kerning;
327 if (x > Bitmap->Width() - 1)
328 break;
329 }
330 }
331}
332
333void cFreetypeFont::DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const
334{
335 if (s && height) { // checking height to make sure we actually have a valid font
336#ifdef BIDI
337 cString bs = Bidi(s);
338 s = bs;
339#endif
340 bool AntiAliased = Setup.AntiAlias;
341 uint prevSym = 0;
342 while (*s) {
343 int sl = Utf8CharLen(s);
344 uint sym = Utf8CharGet(s, sl);
345 s += sl;
346 cGlyph *g = Glyph(sym, AntiAliased);
347 if (!g)
348 continue;
349 int kerning = Kerning(g, prevSym);
350 prevSym = sym;
351 uchar *buffer = g->Bitmap();
352 int symWidth = g->Width();
353 if (Width && x + symWidth + g->Left() + kerning - 1 > Width)
354 break; // we don't draw partial characters
355 if (x + symWidth + g->Left() + kerning > 0) {
356 for (int row = 0; row < g->Rows(); row++) {
357 for (int pitch = 0; pitch < g->Pitch(); pitch++) {
358 uchar bt = *(buffer + (row * g->Pitch() + pitch));
359 if (AntiAliased) {
360 if (bt > 0x00)
361 Pixmap->DrawPixel(cPoint(x + pitch + g->Left() + kerning, y + row + (height - Bottom() - g->Top())), AlphaBlend(ColorFg, ColorBg, bt));
362 }
363 else { //monochrome rendering
364 for (int col = 0; col < 8 && col + pitch * 8 <= symWidth; col++) {
365 if (bt & 0x80)
366 Pixmap->DrawPixel(cPoint(x + col + pitch * 8 + g->Left() + kerning, y + row + (height - Bottom() - g->Top())), ColorFg);
367 bt <<= 1;
368 }
369 }
370 }
371 }
372 }
373 x += g->AdvanceX() + kerning;
374 if (x > Pixmap->DrawPort().Width() - 1)
375 break;
376 }
377 }
378}
379
380// --- cDummyFont ------------------------------------------------------------
381
382// A dummy font, in case there are no fonts installed:
383
384class cDummyFont : public cFont {
385private:
386 int height;
387public:
388 cDummyFont(int CharHeight) { height = CharHeight; }
389 virtual int Width(uint c) const { return height; }
390 virtual int Width(const char *s) const { return height; }
391 virtual int Height(void) const { return height; }
392 virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
393 virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {};
394 };
395
396// --- cFont -----------------------------------------------------------------
397
398cFont *cFont::fonts[eDvbFontSize(fontSml + 1)] = { NULL__null };
399
400void cFont::SetFont(eDvbFont Font, const char *Name, int CharHeight)
401{
402 delete fonts[Font];
403 fonts[Font] = CreateFont(Name, constrain(CharHeight, MINFONTSIZE10, MAXFONTSIZE64));
404}
405
406const cFont *cFont::GetFont(eDvbFont Font)
407{
408 if (Setup.UseSmallFont == 0 && Font == fontSml)
409 Font = fontOsd;
410 else if (Setup.UseSmallFont == 2)
411 Font = fontSml;
412 if (!fonts[Font]) {
413 switch (Font) {
414 case fontOsd: SetFont(Font, Setup.FontOsd, Setup.FontOsdSize); break;
415 case fontSml: SetFont(Font, Setup.FontSml, min(Setup.FontSmlSize, Setup.FontOsdSize)); break;
416 case fontFix: SetFont(Font, Setup.FontFix, Setup.FontFixSize); break;
417 default: esyslog("ERROR: unknown Font %d (%s %d)", Font, __FUNCTION__, __LINE__)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: unknown Font %d (%s %d)"
, Font, __FUNCTION__, 417) : void() )
;
418 }
419 }
420 return fonts[Font];
421}
422
423cFont *cFont::CreateFont(const char *Name, int CharHeight, int CharWidth)
424{
425 cString fn = GetFontFileName(Name);
426 cFont *f = *fn ? new cFreetypeFont(fn, CharHeight, CharWidth) : NULL__null;
427 if (!f || !f->Height())
428 f = new cDummyFont(CharHeight);
429 return f;
430}
431
432bool cFont::GetAvailableFontNames(cStringList *FontNames, bool Monospaced)
433{
434 if (!FontNames->Size()) {
435 FcInit();
436 FcObjectSet *os = FcObjectSetBuild(FC_FAMILY"family", FC_STYLE"style", NULL__null);
437 FcPattern *pat = FcPatternCreate();
438 FcPatternAddBool(pat, FC_SCALABLE"scalable", FcTrue1);
439 if (Monospaced)
440 FcPatternAddInteger(pat, FC_SPACING"spacing", FC_MONO100);
441 FcFontSet* fontset = FcFontList(NULL__null, pat, os);
442 for (int i = 0; i < fontset->nfont; i++) {
443 char *s = (char *)FcNameUnparse(fontset->fonts[i]);
444 if (s) {
445 // Strip i18n stuff:
446 char *c = strchr(s, ':');
447 if (c) {
448 char *p = strchr(c + 1, ',');
449 if (p)
450 *p = 0;
451 }
452 char *p = strchr(s, ',');
453 if (p) {
454 if (c)
455 memmove(p, c, strlen(c) + 1);
456 else
457 *p = 0;
458 }
459 // Make it user presentable:
460 s = strreplace(s, "\\", ""); // '-' is escaped
461 s = strreplace(s, "style=", "");
462 FontNames->Append(s); // takes ownership of s
463 }
464 }
465 FcFontSetDestroy(fontset);
466 FcPatternDestroy(pat);
467 FcObjectSetDestroy(os);
468 //FcFini(); // older versions of fontconfig are broken - and FcInit() can be called more than once
469 FontNames->Sort();
470 }
471 return FontNames->Size() > 0;
472}
473
474cString cFont::GetFontFileName(const char *FontName)
475{
476 cString FontFileName;
477 if (FontName) {
478 char *fn = strdup(FontName);
479 fn = strreplace(fn, ":", ":style=");
480 fn = strreplace(fn, "-", "\\-");
481 FcInit();
482 FcPattern *pat = FcNameParse((FcChar8 *)fn);
483 FcPatternAddBool(pat, FC_SCALABLE"scalable", FcTrue1);
484 FcConfigSubstitute(NULL__null, pat, FcMatchPattern);
485 FcDefaultSubstitute(pat);
486 FcResult fresult;
487 FcFontSet *fontset = FcFontSort(NULL__null, pat, FcFalse0, NULL__null, &fresult);
488 if (fontset) {
489 for (int i = 0; i < fontset->nfont; i++) {
490 FcBool scalable;
491 FcPatternGetBool(fontset->fonts[i], FC_SCALABLE"scalable", 0, &scalable);
492 if (scalable) {
493 FcChar8 *s = NULL__null;
494 FcPatternGetString(fontset->fonts[i], FC_FILE"file", 0, &s);
495 FontFileName = (char *)s;
496 break;
497 }
498 }
499 FcFontSetDestroy(fontset);
500 }
501 else
502 esyslog("ERROR: no usable font found for '%s'", FontName)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: no usable font found for '%s'"
, FontName) : void() )
;
503 FcPatternDestroy(pat);
504 free(fn);
505 //FcFini(); // older versions of fontconfig are broken - and FcInit() can be called more than once
506 }
507 return FontFileName;
508}
509
510#ifdef BIDI
511cString cFont::Bidi(const char *Ltr)
512{
513 if (!cCharSetConv::SystemCharacterTable()) { // bidi requires UTF-8
514 fribidi_set_mirroring(true);
515 fribidi_set_reorder_nsm(false);
516 FriBidiCharSet fribidiCharset = FRIBIDI_CHAR_SET_UTF8;
517 int LtrLen = strlen(Ltr);
518 FriBidiCharType Base = FRIBIDI_TYPE_L;
519 FriBidiChar *Logical = MALLOC(FriBidiChar, LtrLen + 1)(FriBidiChar *)malloc(sizeof(FriBidiChar) * (LtrLen + 1)) ;
520 int RtlLen = fribidi_charset_to_unicode(fribidiCharset, const_cast<char *>(Ltr), LtrLen, Logical);
521 FriBidiChar *Visual = MALLOC(FriBidiChar, LtrLen + 1)(FriBidiChar *)malloc(sizeof(FriBidiChar) * (LtrLen + 1)) ;
522 char *Rtl = NULL__null;
523 bool ok = fribidi_log2vis(Logical, RtlLen, &Base, Visual, NULL__null, NULL__null, NULL__null);
524 if (ok) {
525 fribidi_remove_bidi_marks(Visual, RtlLen, NULL__null, NULL__null, NULL__null);
526 Rtl = MALLOC(char, RtlLen * 4 + 1)(char *)malloc(sizeof(char) * (RtlLen * 4 + 1));
527 fribidi_unicode_to_charset(fribidiCharset, Visual, RtlLen, Rtl);
528 }
529 free(Logical);
530 free(Visual);
531 if (ok)
532 return cString(Rtl, true);
533 }
534 return cString(Ltr);
535}
536#endif
537
538// --- cTextWrapper ----------------------------------------------------------
539
540cTextWrapper::cTextWrapper(void)
541{
542 text = eol = NULL__null;
543 lines = 0;
544 lastLine = -1;
545}
546
547cTextWrapper::cTextWrapper(const char *Text, const cFont *Font, int Width)
548{
549 text = NULL__null;
550 Set(Text, Font, Width);
551}
552
553cTextWrapper::~cTextWrapper()
554{
555 free(text);
556}
557
558void cTextWrapper::Set(const char *Text, const cFont *Font, int Width)
559{
560 free(text);
561 text = Text ? strdup(Text) : NULL__null;
1
Assuming 'Text' is non-null
2
'?' condition is true
562 eol = NULL__null;
563 lines = 0;
564 lastLine = -1;
565 if (!text)
3
Taking false branch
566 return;
567 lines = 1;
568 if (Width <= 0)
4
Assuming 'Width' is > 0
5
Taking false branch
569 return;
570
571 char *Blank = NULL__null;
572 char *Delim = NULL__null;
573 int w = 0;
574
575 stripspace(text); // strips trailing newlines
576
577 for (char *p = text; *p; ) {
6
Loop condition is true. Entering loop body
11
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
22
Loop condition is true. Entering loop body
578 int sl = Utf8CharLen(p);
579 uint sym = Utf8CharGet(p, sl);
580 if (sym == '\n') {
7
Taking false branch
12
Taking false branch
17
Taking false branch
23
Taking false branch
581 lines++;
582 w = 0;
583 Blank = Delim = NULL__null;
584 p++;
585 continue;
586 }
587 else if (sl == 1 && isspace(sym))
8
Assuming 'sl' is not equal to 1
13
Assuming 'sl' is not equal to 1
18
Assuming 'sl' is not equal to 1
24
Assuming 'sl' is equal to 1
25
Taking true branch
588 Blank = p;
589 int cw = Font->Width(sym);
590 if (w + cw > Width) {
9
Taking false branch
14
Taking false branch
19
Taking false branch
26
Taking true branch
591 if (Blank) {
27
Assuming 'Blank' is null
28
Taking false branch
592 *Blank = '\n';
593 p = Blank;
594 continue;
595 }
596 else if (w > 0) { // there has to be at least one character before the newline
29
Assuming 'w' is <= 0
30
Taking false branch
597 // Here's the ugly part, where we don't have any whitespace to
598 // punch in a newline, so we need to make room for it:
599 if (Delim)
600 p = Delim + 1; // let's fall back to the most recent delimiter
601 char *s = MALLOC(char, strlen(text) + 2)(char *)malloc(sizeof(char) * (strlen(text) + 2)); // The additional '\n' plus the terminating '\0'
602 int l = p - text;
603 strncpy(s, text, l);
604 s[l] = '\n';
605 strcpy(s + l + 1, p);
606 free(text);
607 text = s;
608 p = text + l;
609 continue;
610 }
611 }
612 w += cw;
613 if (strchr("-.,:;!?_", *p)) {
10
Taking false branch
15
Taking false branch
20
Taking false branch
31
Dereference of null pointer (loaded from variable 'p')
614 Delim = p;
615 Blank = NULL__null;
616 }
617 p += sl;
21
Value assigned to 'p'
618 }
619}
620
621const char *cTextWrapper::Text(void)
622{
623 if (eol) {
624 *eol = '\n';
625 eol = NULL__null;
626 }
627 return text;
628}
629
630const char *cTextWrapper::GetLine(int Line)
631{
632 char *s = NULL__null;
633 if (Line < lines) {
634 if (eol) {
635 *eol = '\n';
636 if (Line == lastLine + 1)
637 s = eol + 1;
638 eol = NULL__null;
639 }
640 if (!s) {
641 s = text;
642 for (int i = 0; i < Line; i++) {
643 s = strchr(s, '\n');
644 if (s)
645 s++;
646 else
647 break;
648 }
649 }
650 if (s) {
651 if ((eol = strchr(s, '\n')) != NULL__null)
652 *eol = 0;
653 }
654 lastLine = Line;
655 }
656 return s;
657}