PEBL 2.2
Psychology Experiment Building Language - Cross-platform psychological experiment development system
PlatformFont_RTL.cpp
Go to the documentation of this file.
1//* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
3// Name: src/platforms/sdl/PlatformFont.cpp
4// Purpose: Contains SDL-specific Font Classes
5// Author: Shane T. Mueller, Ph.D.
6// Copyright: (c) 2003-2026 Shane T. Mueller <smueller@obereed.net>
7// License: GPL 2
8//
9//
10//
11// This file is part of the PEBL project.
12//
13// PEBL is free software; you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation; either version 2 of the License, or
16// (at your option) any later version.
17//
18// PEBL is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with PEBL; if not, write to the Free Software
25// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
28//look here for hb/sdl example
29//https://github.com/lxnt/ex-sdl-freetype-harfbuzz/blob/master/ex-sdl-freetype-harfbuzz.c
30
31#include "PlatformFont.h"
32#include "../../objects/PFont.h"
33#include "../../objects/PColor.h"
34
35
36#include "../../utility/PEBLPath.h"
37#include "../../utility/PError.h"
38
39#ifdef PEBL_EMSCRIPTEN
40#include "../../base/Evaluator2.h"
41#else
42#include "../../base/Evaluator.h"
43#endif
44
45//this is for right-to-left rendering supported by harfbuzz+freetype.
46#ifdef PEBL_RTL
47#include <harfbuzz/hb.h>
48#include <harfbuzz/hb-ft.h>
49#endif
50
51
52#if defined(PEBL_OSX) | defined(PEBL_EMSCRIPTEN)
53#include "SDL.h"
54#include "SDL_ttf.h"
55#include "SDL_rwops.h"
56#else
57#include "SDL.h"
58#include "SDL_ttf.h"
59#include "SDL_rwops.h"
60#endif
61
62#include <stdio.h>
63#include <iostream>
64
65using std::string;
66using std::cerr;
67using std::endl;
68
69// The following is adapted from code put on
70// http://stackoverflow.com/questions/1031645/how-to-detect-utf-8-in-plain-c
71// It has an implied public domain license
72
73bool is_utf8(std::string str)
74{
75
76
77 if(str.length()==0)
78 return false;
79
80 const unsigned char * bytes = (const unsigned char *)(str.c_str());
81 while(*bytes)
82 {
83 if( (// ASCII
84 bytes[0] == 0x09 ||
85 bytes[0] == 0x0A ||
86 bytes[0] == 0x0D ||
87 (0x20 <= bytes[0] && bytes[0] <= 0x7E)
88 )
89 ) {
90 bytes += 1;
91 continue;
92 }
93
94 if( (// non-overlong 2-byte
95 (0xC2 <= bytes[0] && bytes[0] <= 0xDF) &&
96 (0x80 <= bytes[1] && bytes[1] <= 0xBF)
97 )
98 ) {
99 bytes += 2;
100 continue;
101 }
102
103 if( (// excluding overlongs
104 bytes[0] == 0xE0 &&
105 (0xA0 <= bytes[1] && bytes[1] <= 0xBF) &&
106 (0x80 <= bytes[2] && bytes[2] <= 0xBF)
107 ) ||
108 (// straight 3-byte
109 ((0xE1 <= bytes[0] && bytes[0] <= 0xEC) ||
110 bytes[0] == 0xEE ||
111 bytes[0] == 0xEF) &&
112 (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
113 (0x80 <= bytes[2] && bytes[2] <= 0xBF)
114 ) ||
115 (// excluding surrogates
116 bytes[0] == 0xED &&
117 (0x80 <= bytes[1] && bytes[1] <= 0x9F) &&
118 (0x80 <= bytes[2] && bytes[2] <= 0xBF)
119 )
120 ) {
121 bytes += 3;
122 continue;
123 }
124
125 if( (// planes 1-3
126 bytes[0] == 0xF0 &&
127 (0x90 <= bytes[1] && bytes[1] <= 0xBF) &&
128 (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
129 (0x80 <= bytes[3] && bytes[3] <= 0xBF)
130 ) ||
131 (// planes 4-15
132 (0xF1 <= bytes[0] && bytes[0] <= 0xF3) &&
133 (0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
134 (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
135 (0x80 <= bytes[3] && bytes[3] <= 0xBF)
136 ) ||
137 (// plane 16
138 bytes[0] == 0xF4 &&
139 (0x80 <= bytes[1] && bytes[1] <= 0x8F) &&
140 (0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
141 (0x80 <= bytes[3] && bytes[3] <= 0xBF)
142 )
143 ) {
144 bytes += 4;
145 continue;
146 }
147
148 return false;
149 }
150
151 return true;
152}
153
154
155
156//Stolen from
157// http://stackoverflow.com/questions/5134404/c-read-binary-file-to-memory-alter-buffer-write-buffer-to-file
158
159
160long unsigned int getFileSize(FILE **file){
161 long unsigned int size;
162 if(fseek(*file, 0, SEEK_END) == -1){ return -1; }
163 size = ftell(*file);
164 fseek(*file, 0, SEEK_SET);
165 return size;
166}
167
168
169
170char * getFileBuffer(FILE **file, unsigned int fileSize){
171 char *buffer = (char*)malloc(fileSize + 1);
172 fread(buffer, sizeof(char),fileSize,*file);
173 return buffer;
174}
175
176unsigned long int readFileToMemory(const char path[], char ** buffr){
177
178 unsigned long int fileSize;
179 FILE *file = fopen(path, "rb");
180 if(file != NULL){
181 fileSize = getFileSize(&file);
182 //cerr << "FIlesize: " << fileSize << endl;
183 char* buff = getFileBuffer(&file,(unsigned int)fileSize);
184
185
186 (*buffr) = buff;
187
188
189 fclose(file);
190 return fileSize;
191 }else{
192 *buffr = NULL;
193 return 0;
194 }
195}
196
197
198
200PlatformFont::PlatformFont(const std::string & filename, int style, int size, PColor fgcolor, PColor bgcolor, bool aa):
201 PFont(filename, style, size, fgcolor, bgcolor, aa)
202
203{
204
205 //initialize freetype library
206 FT_Init_FreeType(mLibrary);
207
208
209
210
211 string fontname = Evaluator::gPath.FindFile(mFontFileName);
212 if(fontname == "")
213 PError::SignalFatalError(string("Unable to find font file [") + mFontFileName + string("]."));
214
215 //These convert above properties to sdl-specific font
216 //Open the font. Should do error checking here.
217
218 int tries = 0;
219 //mTTF_Font = NULL;
220 //load freetype face.
221 FT_NewFace(mLibrary,fontname,0,mFace);
222
223 //this line stolen from url below--not clear what it does.
224 // https://github.com/wutipong/drawtext-sdl2-freetype2-harfbuzz/blob/master/sdl-ft-harfbuzz-outlinerender/main.cpp
225 FT_SetPixelSizes(mFace,0,64);
226 mHBFont = hb_ft_font_create(face,0);
227
228
229
230 while(!mTTF_Font & (tries < 10))
231 {
232
233
234 unsigned long int size = readFileToMemory(fontname.c_str(), &mBuffer);
235
236 SDL_RWops *rw = SDL_RWFromMem(mBuffer,(int)size);
237 // SDL_RWops * src = NULL;
238
239 // if (rw != NULL) {
240 //
241 // SDL_RWread(rw, src, sizeof (buf));
242 // SDL_RWclose(rw);
243 // }
244 // SDL_RWops * src = SDL_RWFromFile(fontname.c_str(),"r");
245
246 //src->close();
247
248 mTTF_Font = TTF_OpenFontRW(rw,0,mFontSize); //0 indicates to leave the RW memory stream open
249 //SDL_RWclose(rw); //close the memory stream immediately. file when we are done.
250 //free( buffr);
251 tries++;
252 }
253
254 if(!mTTF_Font)
255 {
256
257 printf("Oh My Goodness, an error : [%s]\n", TTF_GetError());
258 PError::SignalFatalError("Failed to create font\n");
259 }
260
261#ifndef PEBL_EMSCRIPTEN
262 TTF_SetFontStyle(mTTF_Font, mFontStyle);
263#endif
264
265 //Translate PColor to SDLcolor for direct use in rendering.
266 mSDL_FGColor = SDLUtility::PColorToSDLColor(mFontColor);
267 mSDL_BGColor = SDLUtility::PColorToSDLColor(mBackgroundColor);
268
269}
270
271
272void RenderTexture(const std::wstring& text)
273{
274 // const SDL_Color& color, //==mSDL_FGColor
275 // const Font& font, // combines mFace and mHBFont
276 // SDL_Renderer*& renderer, //==mRenderer
277
278 // SDL_Texture*& target, //mTarget???
279 // SDL_Rect& rect)
280
281 const FT_Int32& flags = FT_LOAD_DEFAULT;
282
283
284 hb_buffer_t *buffer = hb_buffer_create();
285
286 //This could be HB_DIRECTION_LTR; HB_DIRECTION_RTL; HB_DIRECTION_TTB, B_DIRECTION_BTT, HB_DIRECTION_INVALID;
287 hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); //hardcode as LTR for testing
288
289 //could be HB_SCRIPT_ARABIC
290 // HB_SCRIPT_LATIN
291 // HB_SCRIPT_INVALID
292 // HB_SCRIPT_UNKNOWN, etc.
293 //could use hb_scirpt_from_string to select this:
294 hb_buffer_set_script(buffer, HB_SCRIPT_THAI);
295
296
297
298
299
300 hb_buffer_add_utf16(buffer,
301 (unsigned short*)(text.c_str()),
302 text.length(),
303 0, text.length());
304
305 hb_shape(mHBFont, buffer, NULL, 0);
306
307 unsigned int glyph_count = hb_buffer_get_length(buffer);
308 hb_glyph_info_t *glyph_infos = hb_buffer_get_glyph_infos(buffer, NULL);
309 hb_glyph_position_t *glyph_positions = hb_buffer_get_glyph_positions(buffer, NULL);
310
311 SDL_Rect rect; //get size of rendering.
312
313 CalculateSurfaceBound(glyph_infos,
314 glyph_positions,
315 glyph_count,
316 mFace,
317 rect,
318 flags);
319
320 mTarget = SDL_CreateTexture(mRenderer,
321 SDL_PIXELFORMAT_ARGB8888,
322 SDL_TEXTUREACCESS_TARGET,
323 rect.w,
324 rect.h);
325
326 SDL_SetTextureBlendMode(mTarget, SDL_BLENDMODE_BLEND);
327 SDL_SetRenderTarget(mRenderer, mTarget);
328 SDL_SetRenderDrawBlendMode(mRenderer, SDL_BLENDMODE_BLEND);
329 SDL_SetRenderDrawColor(mRenderer, 0, 0, 0, 0);
330 SDL_RenderClear(mRenderer);
331 SDL_RenderFillRect(mRenderer, NULL);
332
333 int baseline = -rect.y;
334 int x = 0;
335
336 for (unsigned int i = 0; i < glyph_count; i++)
337 {
338 FT_Load_Glyph( mFace,
339 glyph_infos[i].codepoint,
340 FT_LOAD_RENDER | flags);
341
342 SDL_Surface* glyph_surface = CreateSurfaceFromFT_Bitmap(mFace->glyph->bitmap);//used to take a color--maybe this is needed?
343
344 SDL_Rect dest;
345 SDL_QueryTexture(glyph_texture, NULL, NULL, &dest.w, &dest.h);
346 dest.x = x + (mFace->glyph->metrics.horiBearingX >> 6) + (glyph_positions[i].x_offset >> 6);
347 dest.y = baseline - (mFace->glyph->metrics.horiBearingY >> 6) - (glyph_positions[i].y_offset >> 6);
348
349
350 SDL_RenderCopy(mRenderer, glyph_texture, NULL, &dest);
351
352 x += (glyph_positions[i].x_advance >> 6);
353
354 SDL_DestroyTexture(glyph_texture);
355 }
356
357 hb_buffer_destroy(buffer);
358
359 SDL_SetRenderTarget(mRenderer, NULL);
360 return
361}
362
363
364
365SDL_Surface * CreateSurfaceFromFT_Bitmap(const FT_Bitmap& bitmap)
366{
367 Uint32 rmask, gmask, bmask, amask;
368 int req_format = STBI_rgb_alpha;
369
370 rmask = 0x000000ff;
371 gmask = 0x0000ff00;
372 bmask = 0x00ff0000;
373 amask = (req_format == STBI_rgb) ? 0 : 0xff000000;
374
375 int depth, pitch;
376 if (req_format == STBI_rgb) {
377 depth = 24;
378 pitch = 3*width; // 3 bytes per pixel * pixels per row
379 } else { // STBI_rgb_alpha (RGBA)
380 depth = 32;
381 pitch = 4*width;
382 }
383
384 //we may have to translate buffer to pixels here.
385
386
387 SDL_Surface * tmp = SDL_CreateRGBSurfaceFrom( (void*)(bitmap.buffer), // dest_buffer from CopyTo
388 bitmap.width, // in pixels
389 bitmap.height, // in pixels
390 depth, // in bits, so should be dest_depth * 8
391 pitch, // dest_row_span from CopyTo
392 rmask,gmask,bmas,amask); // RGBA masks, see docs
393
394 return tmp;
395}
396
397//This takes a FT bitmap and creates a texture directly. This mismatches
398//the PEBL/SDL label and texture needs, so we won't move to this unless
399//we can prove it works better.
400
401SDL_Texture* CreateTextureFromFT_Bitmap(SDL_Renderer* renderer,
402 const FT_Bitmap& bitmap,
403 const SDL_Color& color)
404{
405 SDL_Texture* output = SDL_CreateTexture(renderer,
406 SDL_PIXELFORMAT_RGBA8888,
407 SDL_TEXTUREACCESS_STREAMING,
408 bitmap.width,
409 bitmap.rows);
410
411 void *buffer;
412 int pitch;
413 SDL_LockTexture(output, NULL, &buffer, &pitch);
414
415 unsigned char *src_pixels = bitmap.buffer;
416 unsigned int *target_pixels = reinterpret_cast<unsigned int*>(buffer);
417
418 SDL_PixelFormat* pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA8888);
419
420 for (int y = 0; y < bitmap.rows; y++)
421 {
422 for (int x = 0; x < bitmap.width; x++)
423 {
424 int index = (y * bitmap.width) + x;
425
426 unsigned int alpha = src_pixels[index];
427 unsigned int pixel_value =
428 SDL_MapRGBA(pixel_format, color.r, color.g, color.b, alpha);
429
430 target_pixels[index] = pixel_value;
431 }
432 }
433
434 SDL_FreeFormat(pixel_format);
435 SDL_UnlockTexture(output);
436
437 return output;
438}
439
440void CalculateSurfaceBound( hb_glyph_info_t *glyph_infos,
441 hb_glyph_position_t *glyph_positions,
442 const unsigned int& glyph_count,
443 const FT_Face& face,
444 SDL_Rect& rect,
445 const FT_Int32& flags = FT_LOAD_DEFAULT)
446{
447 int width = 0;
448 int above_base_line = 0;
449 int below_base_line = 0;
450
451 for (unsigned int i = 0; i < glyph_count; i++)
452 {
453 FT_Load_Glyph(face, glyph_infos[i].codepoint, FT_LOAD_DEFAULT | flags);
454 width += (glyph_positions[i].x_advance >> 6);
455 int bearing =
456 (face->glyph->metrics.horiBearingY >> 6) + (glyph_positions[i].y_offset >> 6);
457
458 if (bearing > above_base_line)
459 above_base_line = bearing;
460
461 int height_minus_bearing = (face->glyph->metrics.height >> 6) - bearing;
462 if (height_minus_bearing > below_base_line)
463 below_base_line = height_minus_bearing;
464 }
465
466 rect.x = 0;
467 rect.y = -above_base_line;
468 rect.w = width;
469 rect.h = above_base_line + below_base_line;
470
471}
472
473
474void DrawTextHB(conts std::wstring & Text)
475{
476
477 //These are the arguments originally passed in to the function:
478 //const SDL_Color& color,
479 SDL_Color& color = mSDL_FGColor;
480
481 //const int& baseline,
482 const int baseline= 0;
483 //const int& x_start,
484 const int x_start = 0;
485 //const FT_Face& face //===mFace
486 //hb_font_t* hb_font, //== mHBFont
487 //SDL_Renderer*& renderer //= mRenderer
488
489 //this will render directly onto wherever the renderer is currently pointing.
490 //This might be smart, but labels and textboxes _expect_ a tmpSurface to be returned.
491 //and so we need to create one here to use.
492
493
494
495 mSurface = SDL_CreateRGBSurface(SDL_SWSURFACE,
496 (int)mTextureWidth,
497 (int)mTextureHeight, 32,
498 rmask, gmask, bmask, amask);
499
500
501 if(!mSurface) PError::SignalFatalError("Surface not created in TextBox::RenderText.");
502
503
504 hb_buffer_t *buffer = hb_buffer_create();
505
506 //This could be HB_DIRECTION_LTR; HB_DIRECTION_RTL; HB_DIRECTION_TTB, B_DIRECTION_BTT, HB_DIRECTION_INVALID;
507 hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); //hardcode as LTR for testing
508
509 //could be HB_SCRIPT_ARABIC
510 // HB_SCRIPT_LATIN
511 // HB_SCRIPT_INVALID
512 // HB_SCRIPT_UNKNOWN, etc.
513 //could use hb_scirpt_from_string to select this:
514 hb_buffer_set_script(buffer, HB_SCRIPT_THAI);
515
516
517 hb_buffer_add_utf16(buffer,
518 (unsigned short*)(text.c_str()),
519 text.length(),
520 0,
521 text.length());
522
523 hb_shape(mHBfont, buffer, NULL, 0);
524
525 const unsigned int glyph_count = hb_buffer_get_length(buffer);
526 const hb_glyph_info_t *glyph_infos = hb_buffer_get_glyph_infos(buffer, NULL);
527 const hb_glyph_position_t *glyph_positions = hb_buffer_get_glyph_positions(buffer, NULL);
528
529 //This renders directly onto the surface; it does not produce a surface.
530 SDL_SetRenderDrawBlendMode(mRenderer, SDL_BLENDMODE_BLEND);
531
532 int x = x_start;
533
534 SpanAdditionData addl;
535
536 addl.color = color;
537
538 for (unsigned int i = 0; i < glyph_count; i++)
539 {
540 FT_Load_Glyph(mFace, glyph_infos[i].codepoint, FT_LOAD_NO_BITMAP);
541
542 addl.dest.x = x + (glyph_positions[i].x_offset >> 6);
543 addl.dest.y = baseline - (glyph_positions[i].y_offset >> 6);
544
545 if (mFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
546 {
547 FT_Raster_Params params;
548 memset(&params, 0, sizeof(params));
549 params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
550 params.gray_spans = DrawSpansCallback;
551 params.user = &addl;
552
553 FT_Outline_Render(library, &mFace->glyph->outline, &params);
554 }//No fallback
555 x += (glyph_positions[i].x_advance >> 6);
556 }
557
558 hb_buffer_destroy(buffer);
559}
560
561
562
565
566{
567
569 mFontStyle = font.GetFontStyle();
570 mFontSize = font.GetFontSize();
571 mFontColor = font.GetFontColor();
572 mBackgroundColor = font.GetBackgroundColor();
574
575
576 //These convert above properties to sdl-specific font
577 //Open the font. Should do error checking here.
578 mTTF_Font = TTF_OpenFont(mFontFileName.c_str(), mFontSize);
579 TTF_SetFontStyle(mTTF_Font, mFontStyle);
580
581 //Translate PColor to SDLcolor for direct use in rendering.
582 mSDL_FGColor = SDLUtility::PColorToSDLColor(mFontColor);
583 mSDL_BGColor = SDLUtility::PColorToSDLColor(mBackgroundColor);
584
585}
586
587
591{
592
593
594 TTF_CloseFont(mTTF_Font);
595 mTTF_Font = NULL;
596
597 free( mBuffer);
598 mBuffer=NULL;
599}
600
601
602
605{
606 //Chain up to parent method
607 PFont::SetFontColor(color);
608
609 //Set child member data.
610 mSDL_FGColor = SDLUtility::PColorToSDLColor(mFontColor);
611}
612
613
614
617{
618 //Chain up to parent method
620
621 //Set child member data.
622 mSDL_BGColor = SDLUtility::PColorToSDLColor(mBackgroundColor);
623}
624
625
626SDL_Surface * PlatformFont::RenderText(const std::wstring & text)
627{
628
629 int maxchars = 1000;
630#if 0
631 cerr << "About to render text [" << text << "] with font " << *this << endl;
632
633 int i = 0;
634 while(i < text.length())
635 {
636
637 cerr << "[" << text[i] << "|" << (unsigned int)(text[i]) << "]";
638 i++;
639 }
640
641 cerr << endl;
642#endif
643
644
645
646
647 //If there is no text, return a null surface.
648 // if(text=="") return NULL; don't do this;render anyway because this causes updates
649 // to blank labels to fail in 2.0
650
651
652 //Get a temporary pointer that we return
653 std::string toBeRendered = StripText(text);
654 SDL_Surface * tmpSurface = NULL;
655
656 if(toBeRendered.length()>maxchars)
657 {
658 toBeRendered=toBeRendered.substr(0,maxchars);
659 }
660 //The text renderer doesn't like to render empty text.
661 if(toBeRendered.length() == 0) toBeRendered = " ";
662
663 //Using the RenderUTF8 stuff below has a hard time with 'foreign' characters; possibly because
664 //the toberendered needs to be converted to UTF-8????
665 mTexture = DrawTexture(toBeRendered);
666 return tmpSurface;
667}
668
669
670
671
672SDL_Surface * PlatformFont::RenderText_old(const std::wstring & text)
673{
674
675 int maxchars = 1000;
676#if 0
677 cerr << "About to render text [" << text << "] with font " << *this << endl;
678
679 int i = 0;
680 while(i < text.length())
681 {
682
683 cerr << "[" << text[i] << "|" << (unsigned int)(text[i]) << "]";
684 i++;
685 }
686
687 cerr << endl;
688#endif
689
690
691
692 //If there is no text, return a null surface.
693 // if(text=="") return NULL; don't do this;render anyway because this causes updates
694 // to blank labels to fail in 2.0
695
696
697
698
699 //Get a temporary pointer that we return
700 std::string toBeRendered = StripText(text);
701 SDL_Surface * tmpSurface = NULL;
702
703 if(toBeRendered.length()>maxchars)
704 {
705 toBeRendered=toBeRendered.substr(0,maxchars);
706 }
707 //The text renderer doesn't like to render empty text.
708 if(toBeRendered.length() == 0) toBeRendered = " ";
709
710 //Using the RenderUTF8 stuff below has a hard time with 'foreign' characters; possibly because
711 //the toberendered needs to be converted to UTF-8????
712
713
714#ifdef PEBL_EMSCRIPTEN
715 tmpSurface = TTF_RenderText_Blended(mTTF_Font, toBeRendered.c_str(), mSDL_FGColor);
716#else
717
718 //Note, renderUTF paths are not available in EMSCRIPTEN.
719 if(mAntiAliased)
720 {
721
722 // toBeRendered might need to be converted to UTF8
723 if(is_utf8(toBeRendered))
724 {
725 tmpSurface = TTF_RenderUTF8_Shaded(mTTF_Font, toBeRendered.c_str(), mSDL_FGColor, mSDL_BGColor);
726 } else {
727 tmpSurface = TTF_RenderText_Shaded(mTTF_Font, toBeRendered.c_str(), mSDL_FGColor, mSDL_BGColor);
728 }
729
730 }
731 else
732 {
733 // tmpSurface = TTF_RenderText_Blended(mTTF_Font,toBeRendered.c_str(), mSDL_FGColor);
734 if(is_utf8(toBeRendered) )
735 {
736 tmpSurface = TTF_RenderUTF8_Blended(mTTF_Font,toBeRendered.c_str(), mSDL_FGColor);
737 }
738 else
739 {
740 tmpSurface = TTF_RenderText_Blended(mTTF_Font, toBeRendered.c_str(), mSDL_FGColor);
741 }
742 }
743#endif
744 //
745 //TTF_RenderText_Blended(
746 //TTF_Font *font, // This is the TTF_Font to use.
747 //char *cstr, // This is the text to render.
748 // SDL_Color &clr, // This is the color to use.
749 // );
750
751
752
753
754 if(tmpSurface)
755 {
756 return tmpSurface;
757 //we need to copy the surface to the texture, render it, and return I think.
758
759 }
760 else
761 {
762 string message = "Unable to render text [" + toBeRendered + "] in PlatformFont::RenderText. Attempting to render '' instead\n";
763 PError::SignalWarning(message);
764
765 //We have a problem, probably because we are trying to render garbage. Let's try to render "" instead, and
766 //signal a waring. If there is still an error, we will signal a fatal error.
767 std::string tmp = "";
768 tmpSurface = TTF_RenderText_Blended(mTTF_Font, tmp.c_str(), mSDL_FGColor);
769
770 if(tmpSurface)
771 {
772 return tmpSurface;
773 }
774 else
775 {
776 string message = "Unable to render text in PlatformFont::RenderText";
778 }
779 }
780 return NULL;
781}
782
783
784//This transforms an escape-filled text string into its displayable version.
785std::string PlatformFont::StripText(const std::string & text)
786{
787 //First, transform text into the to-be-rendered text. I.E., replace
788 //escape characters etc.
789 //This might destroy UTF-formatting and stuff, so we have to be careful.
790
791 std::string toBeRendered;
792
793 for(unsigned int i = 0; i < text.size(); i++)
794 {
795
796
797 if(text[i] == 10 ||
798 text[i] == 13 ||
799 text[i] == 18)
800 {
801 //Do nothing.;
802
803 }
804 else if(text[i] == 9)
805 {
806 //This is a tab character. First, figure out
807 //what absolute position it should be in: round
808 //the length eof toBeRendered up to the next value
809 //i mod 4.
810
811 int x = 8*(((int)(toBeRendered.length())+1) /8 + 1 );
812 int diff = (int)x-(int)(toBeRendered.length());
813 string tmp = " ";
814 for(int j = 0; j < diff; j++)
815 {
816 toBeRendered.push_back(tmp[0]);
817 }
818
819 }
820 else
821 {
822 toBeRendered.push_back(text[i]);
823 }
824
825 }
826
827 return toBeRendered;
828}
829
830
831unsigned int PlatformFont::GetTextWidth(const std::string & text)
832{
833 int height, width;
834 std::string toBeRendered = StripText(text.c_str());
835
836 if(is_utf8(toBeRendered))
837 TTF_SizeUTF8(mTTF_Font,toBeRendered.c_str(),&width,&height); // should work on all utf8
838 else
839 TTF_SizeText(mTTF_Font,toBeRendered.c_str(),&width,&height); //breaks on non-ascii text
840
841 // TTF_SizeUNICODE(mTTF_Font,toBeRendered.c_str(),&width,&height); //requires conversion to Uint16 array.
842
843 unsigned int uwidth = (unsigned int)width;
844 return uwidth;
845}
846
847unsigned int PlatformFont::GetTextHeight(const std::string & toBeRendered)
848{
849 int height, width;
850
851 if(is_utf8(toBeRendered))
852 TTF_SizeUTF8(mTTF_Font,toBeRendered.c_str(),&width,&height); // should work on all utf8
853 else
854 TTF_SizeText(mTTF_Font,toBeRendered.c_str(),&width,&height); //breaks on non-ascii text
855
856 unsigned int uheight = (unsigned int)height;
857 return uheight;
858}
859
860
861//This returns the nearest character to the pixel column specified by x
862unsigned int PlatformFont::GetPosition(const std::string & text, unsigned int x)
863{
864
865 //Start at 0 and check until the width of the rendered text is bigger than x
866
867 unsigned int cutoff = 1;
868
869 while(cutoff < text.size())
870 {
871
872 //If the width of the rendered text is larger than the x argument,
873 unsigned int width = GetTextWidth(text.substr(0,cutoff));
874 if(width > x)
875 return cutoff-1;
876 //cerr << "***"<<width<< "<" << x << ":" << cutoff <<endl;
877 cutoff++;
878 }
879
880 //If we make it this far, we have run out of letters, so return the last character.
881
882 return (unsigned int)(text.size());
883}
884
885
886 std::ostream & PlatformFont::SendToStream(std::ostream& out) const
887{
888 out << "<SDL-Specific Font>" << std::flush;
889 return out;
890}
891
892
893
#define NULL
Definition BinReloc.cpp:317
void CalculateSurfaceBound(hb_glyph_info_t *glyph_infos, hb_glyph_position_t *glyph_positions, const unsigned int &glyph_count, const FT_Face &face, SDL_Rect &rect, const FT_Int32 &flags=FT_LOAD_DEFAULT)
bool is_utf8(std::string str)
char * getFileBuffer(FILE **file, unsigned int fileSize)
long unsigned int getFileSize(FILE **file)
SDL_Texture * CreateTextureFromFT_Bitmap(SDL_Renderer *renderer, const FT_Bitmap &bitmap, const SDL_Color &color)
void RenderTexture(const std::wstring &text)
void DrawTextHB(conts std::wstring &Text)
SDL_Surface * CreateSurfaceFromFT_Bitmap(const FT_Bitmap &bitmap)
unsigned long int readFileToMemory(const char path[], char **buffr)
static PEBLPath gPath
std::string FindFile(const string &filename)
Definition PEBLPath.cpp:368
Definition PFont.h:53
virtual void SetFontColor(PColor color)
Definition PFont.cpp:303
int mFontStyle
Definition PFont.h:105
virtual PColor GetBackgroundColor() const
Definition PFont.cpp:296
virtual int GetFontStyle() const
Definition PFont.h:84
virtual void SetBackgroundColor(PColor color)
Definition PFont.cpp:315
int mFontSize
Definition PFont.h:106
virtual PColor GetFontColor() const
Definition PFont.cpp:289
virtual std::string GetFontFileName() const
Definition PFont.h:83
std::string mFontFileName
Definition PFont.h:104
virtual bool GetAntiAliased() const
Definition PFont.h:88
bool mAntiAliased
Definition PFont.h:110
virtual int GetFontSize() const
Definition PFont.h:85
unsigned int GetTextHeight(const std::string &text)
SDL_Surface * RenderText(const std::string &text)
This takes care of all the busy work of rendering the text.
virtual std::ostream & SendToStream(std::ostream &out) const
This sends the font descriptions to the specified stream.
PlatformFont(const std::string &filename)
unsigned int GetTextWidth(const std::string &text)
unsigned int GetPosition(const std::string &text, unsigned int x)
virtual void SetBackgroundColor(PColor color)
Set*Color needs to be overridden because it doesn't change the SDL_Color data.
virtual void SetFontColor(PColor color)
Set*Color needs to be overridden because it doesn't change the SDL_Color data.
virtual ~PlatformFont()
Copy constructor.
void SignalWarning(const std::string &message)
Definition PError.cpp:119
void SignalFatalError(const std::string &message)
SDL_Color PColorToSDLColor(PColor pcolor)
This converts between a PColor and an SDL color.