12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501 |
- /*
- SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
- Copyright (C) 2001-2018 Sam Lantinga <slouken@libsdl.org>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ft2build.h>
- #include FT_FREETYPE_H
- #include FT_OUTLINE_H
- #include FT_STROKER_H
- #include FT_GLYPH_H
- #include FT_TRUETYPE_IDS_H
- #include "SDL.h"
- #include "SDL_endian.h"
- #include "SDL_ttf.h"
- #ifdef HAVE_RAQM
- #include "raqm.h"
- #endif
- /* FIXME: Right now we assume the gray-scale renderer Freetype is using
- supports 256 shades of gray, but we should instead key off of num_grays
- in the result FT_Bitmap after the FT_Render_Glyph() call. */
- #define NUM_GRAYS 256
- /* Handy routines for converting from fixed point */
- #define FT_FLOOR(X) ((X & -64) / 64)
- #define FT_CEIL(X) (((X + 63) & -64) / 64)
- #define CACHED_METRICS 0x10
- #define CACHED_BITMAP 0x01
- #define CACHED_PIXMAP 0x02
- /* Cached glyph information */
- typedef struct cached_glyph {
- int stored;
- FT_UInt index;
- FT_Bitmap bitmap;
- FT_Bitmap pixmap;
- int minx;
- int maxx;
- int miny;
- int maxy;
- int yoffset;
- int advance;
- Uint32 cached;
- } c_glyph;
- /* The structure used to hold internal font information */
- struct _TTF_Font {
- /* Freetype2 maintains all sorts of useful info itself */
- FT_Face face;
- /* We'll cache these ourselves */
- int height;
- int ascent;
- int descent;
- int lineskip;
- /* The font style */
- int face_style;
- int style;
- int outline;
- /* Whether kerning is desired */
- int kerning;
- /* Extra width in glyph bounds for text styles */
- int glyph_overhang;
- float glyph_italics;
- /* Information in the font for underlining */
- int underline_offset;
- int underline_height;
- /* Cache for style-transformed glyphs */
- c_glyph *current;
- c_glyph cache[257]; /* 257 is a prime */
- /* We are responsible for closing the font stream */
- SDL_RWops *src;
- int freesrc;
- FT_Open_Args args;
- /* For non-scalable formats, we must remember which font index size */
- int font_size_family;
- /* really just flags passed into FT_Load_Glyph */
- int hinting;
- };
- /* Handle a style only if the font does not already handle it */
- #define TTF_HANDLE_STYLE_BOLD(font) (((font)->style & TTF_STYLE_BOLD) && \
- !((font)->face_style & TTF_STYLE_BOLD))
- #define TTF_HANDLE_STYLE_ITALIC(font) (((font)->style & TTF_STYLE_ITALIC) && \
- !((font)->face_style & TTF_STYLE_ITALIC))
- #define TTF_HANDLE_STYLE_UNDERLINE(font) ((font)->style & TTF_STYLE_UNDERLINE)
- #define TTF_HANDLE_STYLE_STRIKETHROUGH(font) ((font)->style & TTF_STYLE_STRIKETHROUGH)
- /* Font styles that does not impact glyph drawing */
- #define TTF_STYLE_NO_GLYPH_CHANGE (TTF_STYLE_UNDERLINE | TTF_STYLE_STRIKETHROUGH)
- /* The FreeType font engine/library */
- static FT_Library library;
- static int TTF_initialized = 0;
- static int TTF_byteswapped = 0;
- #define TTF_CHECKPOINTER(p, errval) \
- if (!TTF_initialized) { \
- TTF_SetError("Library not initialized"); \
- return errval; \
- } \
- if (!p) { \
- TTF_SetError("Passed a NULL pointer"); \
- return errval; \
- }
- /* Gets the top row of the underline. The outline
- is taken into account.
- */
- static int TTF_underline_top_row(TTF_Font *font)
- {
- /* With outline, the underline_offset is underline_offset+outline. */
- /* So, we don't have to remove the top part of the outline height. */
- return font->ascent - font->underline_offset - 1;
- }
- /* Gets the top row of the underline. for a given glyph. The outline
- is taken into account.
- Need to update row according to height difference between font and glyph:
- font_value - font->ascent + glyph->maxy
- */
- static int TTF_Glyph_underline_top_row(TTF_Font *font, c_glyph *glyph)
- {
- return glyph->maxy - font->underline_offset - 1;
- }
- /* Gets the bottom row of the underline. The outline
- is taken into account.
- */
- static int TTF_underline_bottom_row(TTF_Font *font)
- {
- int row = TTF_underline_top_row(font) + font->underline_height;
- if (font->outline > 0) {
- /* Add underline_offset outline offset and */
- /* the bottom part of the outline. */
- row += font->outline * 2;
- }
- return row;
- }
- /* Gets the bottom row of the underline. for a given glyph. The outline
- is taken into account.
- Need to update row according to height difference between font and glyph:
- font_value - font->ascent + glyph->maxy
- */
- static int TTF_Glyph_underline_bottom_row(TTF_Font *font, c_glyph *glyph)
- {
- return TTF_underline_bottom_row(font) - font->ascent + glyph->maxy;
- }
- /* Gets the top row of the strikethrough. The outline
- is taken into account.
- */
- static int TTF_strikethrough_top_row(TTF_Font *font)
- {
- /* With outline, the first text row is 'outline'. */
- /* So, we don't have to remove the top part of the outline height. */
- return font->height / 2;
- }
- /* Gets the top row of the strikethrough for a given glyph. The outline
- is taken into account.
- Need to update row according to height difference between font and glyph:
- font_value - font->ascent + glyph->maxy
- */
- static int TTF_Glyph_strikethrough_top_row(TTF_Font *font, c_glyph *glyph)
- {
- return TTF_strikethrough_top_row(font) - font->ascent + glyph->maxy;
- }
- static void TTF_initLineMectrics(const TTF_Font *font, const SDL_Surface *textbuf, const int row, Uint8 **pdst, int *pheight)
- {
- Uint8 *dst;
- int height;
- dst = (Uint8 *)textbuf->pixels;
- if (row > 0) {
- dst += row * textbuf->pitch;
- }
- height = font->underline_height;
- /* Take outline into account */
- if (font->outline > 0) {
- height += font->outline * 2;
- }
- *pdst = dst;
- *pheight = height;
- }
- /* Draw a solid line of underline_height (+ optional outline)
- at the given row. The row value must take the
- outline into account.
- */
- static void TTF_drawLine_Solid(const TTF_Font *font, const SDL_Surface *textbuf, const int row)
- {
- int line;
- Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
- Uint8 *dst;
- int height;
- TTF_initLineMectrics(font, textbuf, row, &dst, &height);
- /* Draw line */
- for (line=height; line>0 && dst < dst_check; --line) {
- /* 1 because 0 is the bg color */
- SDL_memset(dst, 1, textbuf->w);
- dst += textbuf->pitch;
- }
- }
- /* Draw a shaded line of underline_height (+ optional outline)
- at the given row. The row value must take the
- outline into account.
- */
- static void TTF_drawLine_Shaded(const TTF_Font *font, const SDL_Surface *textbuf, const int row)
- {
- int line;
- Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
- Uint8 *dst;
- int height;
- TTF_initLineMectrics(font, textbuf, row, &dst, &height);
- /* Draw line */
- for (line=height; line>0 && dst < dst_check; --line) {
- SDL_memset(dst, NUM_GRAYS - 1, textbuf->w);
- dst += textbuf->pitch;
- }
- }
- /* Draw a blended line of underline_height (+ optional outline)
- at the given row. The row value must take the
- outline into account.
- */
- static void TTF_drawLine_Blended(const TTF_Font *font, const SDL_Surface *textbuf, const int row, const Uint32 color)
- {
- int line;
- Uint32 *dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h;
- Uint8 *dst8; /* destination, byte version */
- Uint32 *dst;
- int height;
- int col;
- Uint32 pixel = color | 0xFF000000; /* Amask */
- TTF_initLineMectrics(font, textbuf, row, &dst8, &height);
- dst = (Uint32 *) dst8;
- /* Draw line */
- for (line=height; line>0 && dst < dst_check; --line) {
- for (col=0; col < textbuf->w; ++col) {
- dst[col] = pixel;
- }
- dst += textbuf->pitch/4;
- }
- }
- /* rcg06192001 get linked library's version. */
- const SDL_version *TTF_Linked_Version(void)
- {
- static SDL_version linked_version;
- SDL_TTF_VERSION(&linked_version);
- return(&linked_version);
- }
- /* This function tells the library whether UNICODE text is generally
- byteswapped. A UNICODE BOM character at the beginning of a string
- will override this setting for that string.
- */
- void TTF_ByteSwappedUNICODE(int swapped)
- {
- TTF_byteswapped = swapped;
- }
- static void TTF_SetFTError(const char *msg, FT_Error error)
- {
- #ifdef USE_FREETYPE_ERRORS
- #undef FTERRORS_H
- #define FT_ERRORDEF(e, v, s) { e, s },
- static const struct
- {
- int err_code;
- const char* err_msg;
- } ft_errors[] = {
- #include <freetype/fterrors.h>
- };
- int i;
- const char *err_msg;
- char buffer[1024];
- err_msg = NULL;
- for (i=0; i<((sizeof ft_errors)/(sizeof ft_errors[0])); ++i) {
- if (error == ft_errors[i].err_code) {
- err_msg = ft_errors[i].err_msg;
- break;
- }
- }
- if (!err_msg) {
- err_msg = "unknown FreeType error";
- }
- TTF_SetError("%s: %s", msg, err_msg);
- #else
- TTF_SetError("%s", msg);
- #endif /* USE_FREETYPE_ERRORS */
- }
- static FT_Error Find_Glyph( TTF_Font* font, Uint32 ch, int want );
- static Uint32 UTF8_getch(const char **src, size_t *srclen);
- #ifndef HAVE_RAQM
- typedef struct {
- int index;
- int x_offset;
- int x_advance;
- int y_offset;
- } raqm_glyph_t;
- typedef struct {
- raqm_glyph_t* g_info;
- } raqm_t;
- void raqm_destroy(raqm_t *rq)
- {
- free(rq->g_info);
- free(rq);
- }
- #endif
- static FT_Error Find_GlyphByIndex( TTF_Font* font, Uint16 idx, int want );
- int text_layout(const char *text, size_t textlen, TTF_Font *font,
- raqm_t **rq, raqm_glyph_t **g_info, size_t *glyph_count)
- {
- #ifdef HAVE_RAQM
- *rq = raqm_create();
- if ( *rq == NULL )
- {
- return -1;
- }
- if ( !raqm_set_text_utf8(*rq, text, textlen) )
- {
- raqm_destroy(*rq);
- return -1;
- }
- if ( !raqm_set_freetype_face(*rq, font->face) )
- {
- raqm_destroy(*rq);
- return -1;
- }
- if ( !raqm_set_par_direction(*rq, RAQM_DIRECTION_DEFAULT) )
- {
- raqm_destroy(*rq);
- return -1;
- }
- if ( !raqm_layout(*rq) )
- {
- raqm_destroy(*rq);
- return -1;
- }
- *g_info = raqm_get_glyphs(*rq, glyph_count);
- if ( *g_info == NULL )
- {
- raqm_destroy(*rq);
- return -1;
- }
- return 0;
- #else
- int xstart;
- c_glyph *glyph;
- FT_Error error;
- FT_Long use_kerning;
- FT_UInt prev_index = 0;
- size_t count = 0;
- /* check kerning */
- use_kerning = FT_HAS_KERNING( font->face ) && font->kerning;
- *rq = (raqm_t*) malloc(sizeof(raqm_t));
- *g_info = (raqm_glyph_t*) malloc(sizeof(raqm_glyph_t) * (textlen));
- (*rq)->g_info = *g_info;
- xstart = 0;
- for ( count = 0; textlen > 0; count++ ) {
- Uint16 c = UTF8_getch(&text, &textlen);
- if ( c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED ) {
- continue;
- }
- FT_UInt index = FT_Get_Char_Index( font->face, c );
- error = Find_GlyphByIndex(font, index, CACHED_METRICS|CACHED_BITMAP);
- if ( error ) {
- TTF_SetFTError("Couldn't find glyph", error);
- raqm_destroy(*rq);
- *glyph_count = 0;
- return -1;
- }
- glyph = font->current;
- (*g_info)[count].index = glyph->index;
- (*g_info)[count].y_offset = 0;
- (*g_info)[count].x_offset = 0;
- (*g_info)[count].x_advance = glyph->advance;
- /* do kerning, if possible AC-Patch */
- if ( use_kerning && prev_index && glyph->index ) {
- FT_Vector delta;
- FT_Get_Kerning( font->face, prev_index, (*g_info)->index, ft_kerning_default, &delta );
- xstart += delta.x >> 6;
- (*g_info)[count - 1].x_advance += delta.x;
- }
- }
- *glyph_count = count;
- return 0;
- #endif
- }
- int TTF_Init(void)
- {
- int status = 0;
- if (!TTF_initialized) {
- FT_Error error = FT_Init_FreeType(&library);
- if (error) {
- TTF_SetFTError("Couldn't init FreeType engine", error);
- status = -1;
- }
- }
- if (status == 0) {
- ++TTF_initialized;
- }
- return status;
- }
- static unsigned long RWread(
- FT_Stream stream,
- unsigned long offset,
- unsigned char* buffer,
- unsigned long count
- )
- {
- SDL_RWops *src;
- src = (SDL_RWops *)stream->descriptor.pointer;
- SDL_RWseek(src, (int)offset, RW_SEEK_SET);
- if (count == 0) {
- return 0;
- }
- return (unsigned long)SDL_RWread(src, buffer, 1, (int)count);
- }
- TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index)
- {
- TTF_Font* font;
- FT_Error error;
- FT_Face face;
- FT_Fixed scale;
- FT_Stream stream;
- FT_CharMap found;
- Sint64 position;
- int i;
- if (!TTF_initialized) {
- TTF_SetError("Library not initialized");
- if (src && freesrc) {
- SDL_RWclose(src);
- }
- return NULL;
- }
- if (!src) {
- TTF_SetError("Passed a NULL font source");
- return NULL;
- }
- /* Check to make sure we can seek in this stream */
- position = SDL_RWtell(src);
- if (position < 0) {
- TTF_SetError("Can't seek in stream");
- if (freesrc) {
- SDL_RWclose(src);
- }
- return NULL;
- }
- font = (TTF_Font*)SDL_malloc(sizeof *font);
- if (font == NULL) {
- TTF_SetError("Out of memory");
- if (freesrc) {
- SDL_RWclose(src);
- }
- return NULL;
- }
- SDL_memset(font, 0, sizeof(*font));
- font->src = src;
- font->freesrc = freesrc;
- stream = (FT_Stream)SDL_malloc(sizeof(*stream));
- if (stream == NULL) {
- TTF_SetError("Out of memory");
- TTF_CloseFont(font);
- return NULL;
- }
- SDL_memset(stream, 0, sizeof(*stream));
- stream->read = RWread;
- stream->descriptor.pointer = src;
- stream->pos = (unsigned long)position;
- stream->size = (unsigned long)(SDL_RWsize(src) - position);
- font->args.flags = FT_OPEN_STREAM;
- font->args.stream = stream;
- error = FT_Open_Face(library, &font->args, index, &font->face);
- if (error) {
- TTF_SetFTError("Couldn't load font file", error);
- TTF_CloseFont(font);
- return NULL;
- }
- face = font->face;
- /* Set charmap for loaded font */
- found = 0;
- #if 0 /* Font debug code */
- for (i = 0; i < face->num_charmaps; i++) {
- FT_CharMap charmap = face->charmaps[i];
- printf("Found charmap: platform id %d, encoding id %d\n", charmap->platform_id, charmap->encoding_id);
- }
- #endif
- if (!found) {
- for (i = 0; i < face->num_charmaps; i++) {
- FT_CharMap charmap = face->charmaps[i];
- if (charmap->platform_id == 3 && charmap->encoding_id == 10) { /* UCS-4 Unicode */
- found = charmap;
- break;
- }
- }
- }
- if (!found) {
- for (i = 0; i < face->num_charmaps; i++) {
- FT_CharMap charmap = face->charmaps[i];
- if ((charmap->platform_id == 3 && charmap->encoding_id == 1) /* Windows Unicode */
- || (charmap->platform_id == 3 && charmap->encoding_id == 0) /* Windows Symbol */
- || (charmap->platform_id == 2 && charmap->encoding_id == 1) /* ISO Unicode */
- || (charmap->platform_id == 0)) { /* Apple Unicode */
- found = charmap;
- break;
- }
- }
- }
- if (found) {
- /* If this fails, continue using the default charmap */
- FT_Set_Charmap(face, found);
- }
- /* Make sure that our font face is scalable (global metrics) */
- if (FT_IS_SCALABLE(face)) {
- /* Set the character size and use default DPI (72) */
- error = FT_Set_Char_Size(font->face, 0, ptsize * 64, 0, 0);
- if (error) {
- TTF_SetFTError("Couldn't set font size", error);
- TTF_CloseFont(font);
- return NULL;
- }
- /* Get the scalable font metrics for this font */
- scale = face->size->metrics.y_scale;
- font->ascent = FT_CEIL(FT_MulFix(face->ascender, scale));
- font->descent = FT_CEIL(FT_MulFix(face->descender, scale));
- font->height = font->ascent - font->descent + /* baseline */ 1;
- font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
- font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
- font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
- } else {
- /* Non-scalable font case. ptsize determines which family
- * or series of fonts to grab from the non-scalable format.
- * It is not the point size of the font.
- * */
- if (ptsize >= font->face->num_fixed_sizes)
- ptsize = font->face->num_fixed_sizes - 1;
- font->font_size_family = ptsize;
- error = FT_Set_Pixel_Sizes(face,
- face->available_sizes[ptsize].width,
- face->available_sizes[ptsize].height);
- /* With non-scalale fonts, Freetype2 likes to fill many of the
- * font metrics with the value of 0. The size of the
- * non-scalable fonts must be determined differently
- * or sometimes cannot be determined.
- * */
- font->ascent = face->available_sizes[ptsize].height;
- font->descent = 0;
- font->height = face->available_sizes[ptsize].height;
- font->lineskip = FT_CEIL(font->ascent);
- font->underline_offset = FT_FLOOR(face->underline_position);
- font->underline_height = FT_FLOOR(face->underline_thickness);
- }
- if (font->underline_height < 1) {
- font->underline_height = 1;
- }
- #ifdef DEBUG_FONTS
- printf("Font metrics:\n");
- printf("\tascent = %d, descent = %d\n",
- font->ascent, font->descent);
- printf("\theight = %d, lineskip = %d\n",
- font->height, font->lineskip);
- printf("\tunderline_offset = %d, underline_height = %d\n",
- font->underline_offset, font->underline_height);
- printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n",
- TTF_underline_top_row(font), TTF_strikethrough_top_row(font));
- #endif
- /* Initialize the font face style */
- font->face_style = TTF_STYLE_NORMAL;
- if (font->face->style_flags & FT_STYLE_FLAG_BOLD) {
- font->face_style |= TTF_STYLE_BOLD;
- }
- if (font->face->style_flags & FT_STYLE_FLAG_ITALIC) {
- font->face_style |= TTF_STYLE_ITALIC;
- }
- /* Set the default font style */
- font->style = font->face_style;
- font->outline = 0;
- font->kerning = 1;
- font->glyph_overhang = face->size->metrics.y_ppem / 10;
- /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
- font->glyph_italics = 0.207f;
- font->glyph_italics *= font->height;
- return font;
- }
- TTF_Font* TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize)
- {
- return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0);
- }
- TTF_Font* TTF_OpenFontIndex(const char *file, int ptsize, long index)
- {
- SDL_RWops *rw = SDL_RWFromFile(file, "rb");
- if (rw == NULL) {
- return NULL;
- }
- return TTF_OpenFontIndexRW(rw, 1, ptsize, index);
- }
- TTF_Font* TTF_OpenFont(const char *file, int ptsize)
- {
- return TTF_OpenFontIndex(file, ptsize, 0);
- }
- static void Flush_Glyph(c_glyph* glyph)
- {
- glyph->stored = 0;
- glyph->index = 0;
- if (glyph->bitmap.buffer) {
- SDL_free(glyph->bitmap.buffer);
- glyph->bitmap.buffer = 0;
- }
- if (glyph->pixmap.buffer) {
- SDL_free(glyph->pixmap.buffer);
- glyph->pixmap.buffer = 0;
- }
- glyph->cached = 0;
- }
- static void Flush_Cache(TTF_Font* font)
- {
- int i;
- int size = sizeof(font->cache) / sizeof(font->cache[0]);
- for (i = 0; i < size; ++i) {
- if (font->cache[i].cached) {
- Flush_Glyph(&font->cache[i]);
- }
- }
- }
- static FT_Error Load_Glyph(TTF_Font* font, Uint32 ch, c_glyph* cached, int want)
- {
- FT_Face face;
- FT_Error error;
- FT_GlyphSlot glyph;
- FT_Glyph_Metrics* metrics;
- FT_Outline* outline;
- if (!font || !font->face) {
- return FT_Err_Invalid_Handle;
- }
- face = font->face;
- /* Load the glyph */
- if (!cached->index) {
- cached->index = FT_Get_Char_Index(face, ch);
- }
- error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT | font->hinting);
- if (error) {
- return error;
- }
- /* Get our glyph shortcuts */
- glyph = face->glyph;
- metrics = &glyph->metrics;
- outline = &glyph->outline;
- /* Get the glyph metrics if desired */
- if ((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS)) {
- if (FT_IS_SCALABLE(face)) {
- /* Get the bounding box */
- cached->minx = FT_FLOOR(metrics->horiBearingX);
- cached->maxx = FT_CEIL(metrics->horiBearingX + metrics->width);
- cached->maxy = FT_FLOOR(metrics->horiBearingY);
- cached->miny = cached->maxy - FT_CEIL(metrics->height);
- cached->yoffset = font->ascent - cached->maxy;
- cached->advance = metrics->horiAdvance;
- } else {
- /* Get the bounding box for non-scalable format.
- * Again, freetype2 fills in many of the font metrics
- * with the value of 0, so some of the values we
- * need must be calculated differently with certain
- * assumptions about non-scalable formats.
- * */
- cached->minx = FT_FLOOR(metrics->horiBearingX);
- cached->maxx = FT_CEIL(metrics->horiBearingX + metrics->width);
- cached->maxy = FT_FLOOR(metrics->horiBearingY);
- cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height);
- cached->yoffset = 0;
- cached->advance = metrics->horiAdvance;
- }
- /* Adjust for bold and italic text */
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- cached->maxx += font->glyph_overhang;
- }
- if (TTF_HANDLE_STYLE_ITALIC(font)) {
- cached->maxx += (int)SDL_ceil(font->glyph_italics);
- }
- cached->stored |= CACHED_METRICS;
- }
- if (((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
- ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP))) {
- int mono = (want & CACHED_BITMAP);
- int i;
- FT_Bitmap* src;
- FT_Bitmap* dst;
- FT_Glyph bitmap_glyph = NULL;
- /* Handle the italic style */
- if (TTF_HANDLE_STYLE_ITALIC(font)) {
- FT_Matrix shear;
- shear.xx = 1 << 16;
- shear.xy = (int) (font->glyph_italics * (1 << 16)) / font->height;
- shear.yx = 0;
- shear.yy = 1 << 16;
- FT_Outline_Transform(outline, &shear);
- }
- /* Render as outline */
- if ((font->outline > 0) && glyph->format != FT_GLYPH_FORMAT_BITMAP) {
- FT_Stroker stroker;
- FT_Get_Glyph(glyph, &bitmap_glyph);
- error = FT_Stroker_New(library, &stroker);
- if (error) {
- return error;
- }
- FT_Stroker_Set(stroker, font->outline * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
- FT_Glyph_Stroke(&bitmap_glyph, stroker, 1 /* delete the original glyph */);
- FT_Stroker_Done(stroker);
- /* Render the glyph */
- error = FT_Glyph_To_Bitmap(&bitmap_glyph, mono ? ft_render_mode_mono : ft_render_mode_normal, 0, 1);
- if (error) {
- FT_Done_Glyph(bitmap_glyph);
- return error;
- }
- src = &((FT_BitmapGlyph)bitmap_glyph)->bitmap;
- } else {
- /* Render the glyph */
- error = FT_Render_Glyph(glyph, mono ? ft_render_mode_mono : ft_render_mode_normal);
- if (error) {
- return error;
- }
- src = &glyph->bitmap;
- }
- /* Copy over information to cache */
- if (mono) {
- dst = &cached->bitmap;
- } else {
- dst = &cached->pixmap;
- }
- SDL_memcpy(dst, src, sizeof(*dst));
- /* FT_Render_Glyph() and .fon fonts always generate a
- * two-color (black and white) glyphslot surface, even
- * when rendered in ft_render_mode_normal. */
- /* FT_IS_SCALABLE() means that the font is in outline format,
- * but does not imply that outline is rendered as 8-bit
- * grayscale, because embedded bitmap/graymap is preferred
- * (see FT_LOAD_DEFAULT section of FreeType2 API Reference).
- * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256-
- * color graymap according to the format of embedded bitmap/
- * graymap. */
- if (src->pixel_mode == FT_PIXEL_MODE_MONO) {
- dst->pitch *= 8;
- } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) {
- dst->pitch *= 4;
- } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) {
- dst->pitch *= 2;
- }
- /* Adjust for bold and italic text */
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- int bump = font->glyph_overhang;
- dst->pitch += bump;
- dst->width += bump;
- }
- if (TTF_HANDLE_STYLE_ITALIC(font)) {
- int bump = (int)SDL_ceil(font->glyph_italics);
- dst->pitch += bump;
- dst->width += bump;
- }
- if (dst->rows != 0) {
- dst->buffer = (unsigned char *)SDL_malloc(dst->pitch * dst->rows);
- if (!dst->buffer) {
- return FT_Err_Out_Of_Memory;
- }
- SDL_memset(dst->buffer, 0, dst->pitch * dst->rows);
- for (i = 0; i < src->rows; i++) {
- int soffset = i * src->pitch;
- int doffset = i * dst->pitch;
- if (mono) {
- unsigned char *srcp = src->buffer + soffset;
- unsigned char *dstp = dst->buffer + doffset;
- int j;
- if (src->pixel_mode == FT_PIXEL_MODE_MONO) {
- for (j = 0; j < src->width; j += 8) {
- unsigned char c = *srcp++;
- *dstp++ = (c&0x80) >> 7;
- c <<= 1;
- *dstp++ = (c&0x80) >> 7;
- c <<= 1;
- *dstp++ = (c&0x80) >> 7;
- c <<= 1;
- *dstp++ = (c&0x80) >> 7;
- c <<= 1;
- *dstp++ = (c&0x80) >> 7;
- c <<= 1;
- *dstp++ = (c&0x80) >> 7;
- c <<= 1;
- *dstp++ = (c&0x80) >> 7;
- c <<= 1;
- *dstp++ = (c&0x80) >> 7;
- }
- } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) {
- for (j = 0; j < src->width; j += 4) {
- unsigned char c = *srcp++;
- *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
- c <<= 2;
- *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
- c <<= 2;
- *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
- c <<= 2;
- *dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
- }
- } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) {
- for (j = 0; j < src->width; j += 2) {
- unsigned char c = *srcp++;
- *dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
- c <<= 4;
- *dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
- }
- } else {
- for (j = 0; j < src->width; j++) {
- unsigned char c = *srcp++;
- *dstp++ = (c >= 0x80) ? 1 : 0;
- }
- }
- } else if (src->pixel_mode == FT_PIXEL_MODE_MONO) {
- /* This special case wouldn't
- * be here if the FT_Render_Glyph()
- * function wasn't buggy when it tried
- * to render a .fon font with 256
- * shades of gray. Instead, it
- * returns a black and white surface
- * and we have to translate it back
- * to a 256 gray shaded surface.
- * */
- unsigned char *srcp = src->buffer + soffset;
- unsigned char *dstp = dst->buffer + doffset;
- unsigned char c;
- int j, k;
- for (j = 0; j < src->width; j += 8) {
- c = *srcp++;
- for (k = 0; k < 8; ++k) {
- if ((c&0x80) >> 7) {
- *dstp++ = NUM_GRAYS - 1;
- } else {
- *dstp++ = 0x00;
- }
- c <<= 1;
- }
- }
- } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) {
- unsigned char *srcp = src->buffer + soffset;
- unsigned char *dstp = dst->buffer + doffset;
- unsigned char c;
- int j, k;
- for (j = 0; j < src->width; j += 4) {
- c = *srcp++;
- for (k = 0; k < 4; ++k) {
- if ((c&0xA0) >> 6) {
- *dstp++ = NUM_GRAYS * ((c&0xA0) >> 6) / 3 - 1;
- } else {
- *dstp++ = 0x00;
- }
- c <<= 2;
- }
- }
- } else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) {
- unsigned char *srcp = src->buffer + soffset;
- unsigned char *dstp = dst->buffer + doffset;
- unsigned char c;
- int j, k;
- for (j = 0; j < src->width; j += 2) {
- c = *srcp++;
- for (k = 0; k < 2; ++k) {
- if ((c&0xF0) >> 4) {
- *dstp++ = NUM_GRAYS * ((c&0xF0) >> 4) / 15 - 1;
- } else {
- *dstp++ = 0x00;
- }
- c <<= 4;
- }
- }
- } else {
- SDL_memcpy(dst->buffer+doffset,
- src->buffer+soffset, src->pitch);
- }
- }
- }
- /* Handle the bold style */
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- int row;
- int col;
- int offset;
- int pixel;
- Uint8* pixmap;
- /* The pixmap is a little hard, we have to add and clamp */
- for (row = dst->rows - 1; row >= 0; --row) {
- pixmap = (Uint8*) dst->buffer + row * dst->pitch;
- for (offset=1; offset <= font->glyph_overhang; ++offset) {
- for (col = dst->width - 1; col > 0; --col) {
- if (mono) {
- pixmap[col] |= pixmap[col-1];
- } else {
- pixel = (pixmap[col] + pixmap[col-1]);
- if (pixel > NUM_GRAYS - 1) {
- pixel = NUM_GRAYS - 1;
- }
- pixmap[col] = (Uint8) pixel;
- }
- }
- }
- }
- }
- /* Mark that we rendered this format */
- if (mono) {
- cached->stored |= CACHED_BITMAP;
- } else {
- cached->stored |= CACHED_PIXMAP;
- }
- /* Free outlined glyph */
- if (bitmap_glyph) {
- FT_Done_Glyph(bitmap_glyph);
- }
- }
- /* We're done, mark this glyph cached */
- cached->cached = ch;
- return 0;
- }
- static FT_Error Find_Glyph(TTF_Font* font, Uint32 ch, int want)
- {
- int retval = 0;
- int hsize = sizeof(font->cache) / sizeof(font->cache[0]);
- int h = ch % hsize;
- font->current = &font->cache[h];
- if (font->current->cached != ch)
- Flush_Glyph(font->current);
- if ((font->current->stored & want) != want) {
- retval = Load_Glyph(font, ch, font->current, want);
- }
- return retval;
- }
- static FT_Error Find_GlyphByIndex( TTF_Font* font, Uint16 idx, int want )
- {
- int retval = 0;
- int hsize = sizeof( font->cache ) / sizeof( font->cache[0] );
- int h = idx % hsize;
- font->current = &font->cache[h];
- if (font->current->cached != idx)
- Flush_Glyph( font->current );
- if ( (font->current->stored & want) != want ) {
- font->current->index = idx;
- retval = Load_Glyph( font, idx, font->current, want );
- }
- return retval;
- }
- void TTF_CloseFont(TTF_Font* font)
- {
- if (font) {
- Flush_Cache(font);
- if (font->face) {
- FT_Done_Face(font->face);
- }
- if (font->args.stream) {
- SDL_free(font->args.stream);
- }
- if (font->freesrc) {
- SDL_RWclose(font->src);
- }
- SDL_free(font);
- }
- }
- /* Gets the number of bytes needed to convert a Latin-1 string to UTF-8 */
- static size_t LATIN1_to_UTF8_len(const char *text)
- {
- size_t bytes = 1;
- while (*text) {
- Uint8 ch = *(Uint8*)text++;
- if (ch <= 0x7F) {
- bytes += 1;
- } else {
- bytes += 2;
- }
- }
- return bytes;
- }
- /* Gets the number of bytes needed to convert a UCS2 string to UTF-8 */
- static size_t UCS2_to_UTF8_len(const Uint16 *text)
- {
- size_t bytes = 1;
- while (*text) {
- Uint16 ch = *text++;
- if (ch <= 0x7F) {
- bytes += 1;
- } else if (ch <= 0x7FF) {
- bytes += 2;
- } else {
- bytes += 3;
- }
- }
- return bytes;
- }
- /* Convert a Latin-1 string to a UTF-8 string */
- static void LATIN1_to_UTF8(const char *src, Uint8 *dst)
- {
- while (*src) {
- Uint8 ch = *(Uint8*)src++;
- if (ch <= 0x7F) {
- *dst++ = ch;
- } else {
- *dst++ = 0xC0 | ((ch >> 6) & 0x1F);
- *dst++ = 0x80 | (ch & 0x3F);
- }
- }
- *dst = '\0';
- }
- /* Convert a UCS-2 string to a UTF-8 string */
- static void UCS2_to_UTF8(const Uint16 *src, Uint8 *dst)
- {
- int swapped = TTF_byteswapped;
- while (*src) {
- Uint16 ch = *src++;
- if (ch == UNICODE_BOM_NATIVE) {
- swapped = 0;
- continue;
- }
- if (ch == UNICODE_BOM_SWAPPED) {
- swapped = 1;
- continue;
- }
- if (swapped) {
- ch = SDL_Swap16(ch);
- }
- if (ch <= 0x7F) {
- *dst++ = (Uint8) ch;
- } else if (ch <= 0x7FF) {
- *dst++ = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
- *dst++ = 0x80 | (Uint8) (ch & 0x3F);
- } else {
- *dst++ = 0xE0 | (Uint8) ((ch >> 12) & 0x0F);
- *dst++ = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
- *dst++ = 0x80 | (Uint8) (ch & 0x3F);
- }
- }
- *dst = '\0';
- }
- /* Gets a unicode value from a UTF-8 encoded string and advance the string */
- #define UNKNOWN_UNICODE 0xFFFD
- static Uint32 UTF8_getch(const char **src, size_t *srclen)
- {
- const Uint8 *p = *(const Uint8**)src;
- size_t left = 0;
- SDL_bool overlong = SDL_FALSE;
- SDL_bool underflow = SDL_FALSE;
- Uint32 ch = UNKNOWN_UNICODE;
- if (*srclen == 0) {
- return UNKNOWN_UNICODE;
- }
- if (p[0] >= 0xFC) {
- if ((p[0] & 0xFE) == 0xFC) {
- if (p[0] == 0xFC && (p[1] & 0xFC) == 0x80) {
- overlong = SDL_TRUE;
- }
- ch = (Uint32) (p[0] & 0x01);
- left = 5;
- }
- } else if (p[0] >= 0xF8) {
- if ((p[0] & 0xFC) == 0xF8) {
- if (p[0] == 0xF8 && (p[1] & 0xF8) == 0x80) {
- overlong = SDL_TRUE;
- }
- ch = (Uint32) (p[0] & 0x03);
- left = 4;
- }
- } else if (p[0] >= 0xF0) {
- if ((p[0] & 0xF8) == 0xF0) {
- if (p[0] == 0xF0 && (p[1] & 0xF0) == 0x80) {
- overlong = SDL_TRUE;
- }
- ch = (Uint32) (p[0] & 0x07);
- left = 3;
- }
- } else if (p[0] >= 0xE0) {
- if ((p[0] & 0xF0) == 0xE0) {
- if (p[0] == 0xE0 && (p[1] & 0xE0) == 0x80) {
- overlong = SDL_TRUE;
- }
- ch = (Uint32) (p[0] & 0x0F);
- left = 2;
- }
- } else if (p[0] >= 0xC0) {
- if ((p[0] & 0xE0) == 0xC0) {
- if ((p[0] & 0xDE) == 0xC0) {
- overlong = SDL_TRUE;
- }
- ch = (Uint32) (p[0] & 0x1F);
- left = 1;
- }
- } else {
- if ((p[0] & 0x80) == 0x00) {
- ch = (Uint32) p[0];
- }
- }
- ++*src;
- --*srclen;
- while (left > 0 && *srclen > 0) {
- ++p;
- if ((p[0] & 0xC0) != 0x80) {
- ch = UNKNOWN_UNICODE;
- break;
- }
- ch <<= 6;
- ch |= (p[0] & 0x3F);
- ++*src;
- --*srclen;
- --left;
- }
- if (left > 0) {
- underflow = SDL_TRUE;
- }
- /* Technically overlong sequences are invalid and should not be interpreted.
- However, it doesn't cause a security risk here and I don't see any harm in
- displaying them. The application is responsible for any other side effects
- of allowing overlong sequences (e.g. string compares failing, etc.)
- See bug 1931 for sample input that triggers this.
- */
- /*if (overlong) return UNKNOWN_UNICODE;*/
- if (underflow ||
- (ch >= 0xD800 && ch <= 0xDFFF) ||
- (ch == 0xFFFE || ch == 0xFFFF) || ch > 0x10FFFF) {
- ch = UNKNOWN_UNICODE;
- }
- return ch;
- }
- int TTF_FontHeight(const TTF_Font *font)
- {
- return(font->height);
- }
- int TTF_FontAscent(const TTF_Font *font)
- {
- return(font->ascent);
- }
- int TTF_FontDescent(const TTF_Font *font)
- {
- return(font->descent);
- }
- int TTF_FontLineSkip(const TTF_Font *font)
- {
- return(font->lineskip);
- }
- int TTF_GetFontKerning(const TTF_Font *font)
- {
- return(font->kerning);
- }
- void TTF_SetFontKerning(TTF_Font *font, int allowed)
- {
- font->kerning = allowed;
- }
- long TTF_FontFaces(const TTF_Font *font)
- {
- return(font->face->num_faces);
- }
- int TTF_FontFaceIsFixedWidth(const TTF_Font *font)
- {
- return(FT_IS_FIXED_WIDTH(font->face));
- }
- char *TTF_FontFaceFamilyName(const TTF_Font *font)
- {
- return(font->face->family_name);
- }
- char *TTF_FontFaceStyleName(const TTF_Font *font)
- {
- return(font->face->style_name);
- }
- int TTF_GlyphIsProvided(const TTF_Font *font, Uint16 ch)
- {
- return(FT_Get_Char_Index(font->face, ch));
- }
- int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch,
- int* minx, int* maxx, int* miny, int* maxy, int* advance)
- {
- FT_Error error;
- error = Find_Glyph(font, ch, CACHED_METRICS);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- return -1;
- }
- if (minx) {
- *minx = font->current->minx;
- }
- if (maxx) {
- *maxx = font->current->maxx;
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- *maxx += font->glyph_overhang;
- }
- }
- if (miny) {
- *miny = font->current->miny;
- }
- if (maxy) {
- *maxy = font->current->maxy;
- }
- if (advance) {
- *advance = FT_CEIL(font->current->advance);
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- *advance += font->glyph_overhang;
- }
- }
- return 0;
- }
- int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)
- {
- int status = -1;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, -1);
- utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
- if (utf8) {
- LATIN1_to_UTF8(text, utf8);
- status = TTF_SizeUTF8(font, (char *)utf8, w, h);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return status;
- }
- static int CalculateSize(TTF_Font *font, raqm_glyph_t *g_info, size_t glyph_count, int *w, int*h)
- {
- int status;
- int x, z;
- int minx, maxx;
- int miny, maxy;
- c_glyph *glyph;
- FT_Error error;
- FT_UInt prev_index = 0;
- int outline_delta = 0;
- int i;
- /* Initialize everything to 0 */
- status = 0;
- minx = maxx = 0;
- miny = maxy = 0;
- /* Init outline handling */
- if (font->outline > 0) {
- outline_delta = font->outline * 2;
- }
- /* Load each character and sum it's bounding box */
- x= 0;
- for (i = 0; i < glyph_count; i++) {
- error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- return -1;
- }
- glyph = font->current;
- z = x + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
- if (minx > z) {
- minx = z;
- }
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- x += font->glyph_overhang;
- }
- if (glyph->advance > glyph->maxx) {
- z = x + FT_FLOOR(g_info[i].x_advance);
- } else {
- z = x + FT_FLOOR(g_info[i].x_offset) + glyph->maxx;
- }
- if (maxx < z) {
- maxx = z;
- }
- x += FT_FLOOR(g_info[i].x_advance);
- if (glyph->miny < miny) {
- miny = glyph->miny;
- }
- if (glyph->maxy > maxy) {
- maxy = glyph->maxy;
- }
- prev_index = g_info[i].index;
- }
- /* Fill the bounds rectangle */
- if (w) {
- /* Add outline extra width */
- *w = (maxx - minx) + outline_delta;
- }
- if (h) {
- /* Some fonts descend below font height (FletcherGothicFLF) */
- /* Add outline extra height */
- *h = (font->ascent - miny) + outline_delta;
- if (*h < font->height) {
- *h = font->height;
- }
- /* Update height according to the needs of the underline style */
- if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
- int bottom_row = TTF_underline_bottom_row(font);
- if (*h < bottom_row) {
- *h = bottom_row;
- }
- }
- }
- return status;
- }
- int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h)
- {
- size_t textlen;
- raqm_t *rq = NULL;
- raqm_glyph_t *g_info = NULL;
- size_t glyph_count = 0;
- TTF_CHECKPOINTER(text, -1);
- textlen = SDL_strlen(text);
- /* Shape text */
- if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
- {
- return 0;
- }
- else
- {
- /* Calculate the size */
- int size = CalculateSize(font, g_info, glyph_count, w, h);
- raqm_destroy(rq);
- return size;
- }
- }
- int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h)
- {
- int status = -1;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, -1);
- utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
- if (utf8) {
- UCS2_to_UTF8(text, utf8);
- status = TTF_SizeUTF8(font, (char *)utf8, w, h);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return status;
- }
- SDL_Surface *TTF_RenderText_Solid(TTF_Font *font,
- const char *text, SDL_Color fg)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
- if (utf8) {
- LATIN1_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Solid(font, (char *)utf8, fg);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font,
- const char *text, SDL_Color fg)
- {
- SDL_bool first;
- int xstart;
- int width;
- int height;
- SDL_Surface* textbuf;
- SDL_Palette* palette;
- Uint8* src;
- Uint8* dst;
- Uint8 *dst_check;
- int row, col;
- int i;
- c_glyph *glyph;
- raqm_t *rq = NULL;
- raqm_glyph_t *g_info = NULL;
- size_t glyph_count = 0;
- FT_Bitmap *current;
- FT_Error error;
- FT_UInt prev_index = 0;
- size_t textlen;
- TTF_CHECKPOINTER(text, NULL);
- textlen = SDL_strlen(text);
- /* Shape text */
- if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
- {
- TTF_SetError( "Text layout failed" );
- return NULL;
- }
- /* Get the dimensions of the text surface */
- if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
- TTF_SetError("Text has zero width");
- raqm_destroy(rq);
- return NULL;
- }
- /* Create the target surface */
- textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
- if (textbuf == NULL) {
- raqm_destroy(rq);
- return NULL;
- }
- /* Adding bound checking to avoid all kinds of memory corruption errors
- that may occur. */
- dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
- /* Fill the palette with the foreground color */
- palette = textbuf->format->palette;
- palette->colors[0].r = 255 - fg.r;
- palette->colors[0].g = 255 - fg.g;
- palette->colors[0].b = 255 - fg.b;
- palette->colors[1].r = fg.r;
- palette->colors[1].g = fg.g;
- palette->colors[1].b = fg.b;
- palette->colors[1].a = fg.a ? fg.a : SDL_ALPHA_OPAQUE;
- SDL_SetColorKey(textbuf, SDL_TRUE, 0);
- /* Load and render each glyph */
- first = SDL_TRUE;
- xstart = 0;
- for (i = 0; i < glyph_count; i++) {
- int y_offset;
- error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_BITMAP);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- SDL_FreeSurface(textbuf);
- raqm_destroy(rq);
- return NULL;
- }
- glyph = font->current;
- y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
- current = &glyph->bitmap;
- /* Ensure the width of the pixmap is correct. On some cases,
- * freetype may report a larger pixmap than possible.*/
- width = current->width;
- if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
- width = glyph->maxx - glyph->minx;
- }
- /* Compensate for wrap around bug with negative minx's */
- if (first && (glyph->minx < 0)) {
- xstart -= glyph->minx;
- }
- first = SDL_FALSE;
- for (row = 0; row < current->rows; ++row) {
- /* Make sure we don't go either over, or under the
- * limit */
- if ( row+y_offset < 0 ) {
- continue;
- }
- if ( row+y_offset >= textbuf->h ) {
- continue;
- }
- dst = (Uint8*) textbuf->pixels +
- (row+y_offset) * textbuf->pitch +
- xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
- src = current->buffer + row * current->pitch;
- for (col = width; col > 0 && dst < dst_check; --col) {
- *dst++ |= *src++;
- }
- }
- xstart += FT_FLOOR(g_info[i].x_advance);
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- xstart += font->glyph_overhang;
- }
- prev_index = g_info[i].index;
- }
- /* Handle the underline style */
- if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
- row = TTF_underline_top_row(font);
- TTF_drawLine_Solid(font, textbuf, row);
- }
- /* Handle the strikethrough style */
- if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
- row = TTF_strikethrough_top_row(font);
- TTF_drawLine_Solid(font, textbuf, row);
- }
- raqm_destroy(rq);
- return textbuf;
- }
- SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font,
- const Uint16 *text, SDL_Color fg)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
- if (utf8) {
- UCS2_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Solid(font, (char *)utf8, fg);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font *font, Uint16 ch, SDL_Color fg)
- {
- Uint16 ucs2[2];
- Uint8 utf8[4];
- ucs2[0] = ch;
- ucs2[1] = 0;
- UCS2_to_UTF8(ucs2, utf8);
- return TTF_RenderUTF8_Solid(font, (char *)utf8, fg);
- }
- SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font,
- const char *text, SDL_Color fg, SDL_Color bg)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
- if (utf8) {
- LATIN1_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Shaded(font, (char *)utf8, fg, bg);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- /* Convert the UTF-8 text to UNICODE and render it
- */
- SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font,
- const char *text, SDL_Color fg, SDL_Color bg)
- {
- SDL_bool first;
- int xstart;
- int width;
- int height;
- int i;
- SDL_Surface* textbuf;
- SDL_Palette* palette;
- int index;
- int rdiff;
- int gdiff;
- int bdiff;
- int adiff;
- Uint8* src;
- Uint8* dst;
- Uint8* dst_check;
- int row, col;
- FT_Bitmap* current;
- c_glyph *glyph;
- raqm_t *rq = NULL;
- raqm_glyph_t *g_info = NULL;
- size_t glyph_count = 0;
- size_t textlen;
- FT_Error error;
- FT_UInt prev_index = 0;
- TTF_CHECKPOINTER(text, NULL);
- textlen = SDL_strlen(text);
- /* Shape text */
- if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
- {
- TTF_SetError("Text layout failed");
- return NULL;
- }
- /* Get the dimensions of the text surface */
- if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
- raqm_destroy(rq);
- TTF_SetError("Text has zero width");
- return NULL;
- }
- /* Create the target surface */
- textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
- if (textbuf == NULL) {
- raqm_destroy(rq);
- return NULL;
- }
- /* Adding bound checking to avoid all kinds of memory corruption errors
- that may occur. */
- dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
- /* Support alpha blending */
- if (!fg.a) {
- fg.a = SDL_ALPHA_OPAQUE;
- }
- if (!bg.a) {
- bg.a = SDL_ALPHA_OPAQUE;
- }
- if (fg.a != SDL_ALPHA_OPAQUE || bg.a != SDL_ALPHA_OPAQUE) {
- SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
- }
- /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
- palette = textbuf->format->palette;
- rdiff = fg.r - bg.r;
- gdiff = fg.g - bg.g;
- bdiff = fg.b - bg.b;
- adiff = fg.a - bg.a;
- for (index = 0; index < NUM_GRAYS; ++index) {
- palette->colors[index].r = bg.r + (index*rdiff) / (NUM_GRAYS-1);
- palette->colors[index].g = bg.g + (index*gdiff) / (NUM_GRAYS-1);
- palette->colors[index].b = bg.b + (index*bdiff) / (NUM_GRAYS-1);
- palette->colors[index].a = bg.a + (index*adiff) / (NUM_GRAYS-1);
- }
- /* Load and render each glyph */
- first = SDL_TRUE;
- xstart = 0;
- for (i = 0; i < glyph_count; i++) {
- int y_offset;
- error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_PIXMAP);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- SDL_FreeSurface(textbuf);
- raqm_destroy(rq);
- return NULL;
- }
- glyph = font->current;
- y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
- /* Ensure the width of the pixmap is correct. On some cases,
- * freetype may report a larger pixmap than possible.*/
- width = glyph->pixmap.width;
- if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
- width = glyph->maxx - glyph->minx;
- }
- /* Compensate for the wrap around with negative minx's */
- if (first && (glyph->minx < 0)) {
- xstart -= glyph->minx;
- }
- first = SDL_FALSE;
- current = &glyph->pixmap;
- for (row = 0; row < current->rows; ++row) {
- /* Make sure we don't go either over, or under the
- * limit */
- if ( row+ y_offset < 0 ) {
- continue;
- }
- if ( row+ y_offset >= textbuf->h ) {
- continue;
- }
- dst = (Uint8*) textbuf->pixels +
- (row+y_offset) * textbuf->pitch +
- xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
- src = current->buffer + row * current->pitch;
- for (col = width; col > 0 && dst < dst_check; --col) {
- *dst++ |= *src++;
- }
- }
- xstart += FT_FLOOR(g_info[i].x_advance);
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- xstart += font->glyph_overhang;
- }
- prev_index = g_info[i].index;
- }
- /* Handle the underline style */
- if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
- row = TTF_underline_top_row(font);
- TTF_drawLine_Shaded(font, textbuf, row);
- }
- /* Handle the strikethrough style */
- if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
- row = TTF_strikethrough_top_row(font);
- TTF_drawLine_Shaded(font, textbuf, row);
- }
- raqm_destroy(rq);
- return textbuf;
- }
- SDL_Surface* TTF_RenderUNICODE_Shaded(TTF_Font* font,
- const Uint16* text,
- SDL_Color fg,
- SDL_Color bg)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
- if (utf8) {
- UCS2_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Shaded(font, (char *)utf8, fg, bg);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- SDL_Surface* TTF_RenderGlyph_Shaded(TTF_Font* font,
- Uint16 ch,
- SDL_Color fg,
- SDL_Color bg)
- {
- Uint16 ucs2[2];
- Uint8 utf8[4];
- ucs2[0] = ch;
- ucs2[1] = 0;
- UCS2_to_UTF8(ucs2, utf8);
- return TTF_RenderUTF8_Shaded(font, (char *)utf8, fg, bg);
- }
- SDL_Surface *TTF_RenderText_Blended(TTF_Font *font,
- const char *text, SDL_Color fg)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
- if (utf8) {
- LATIN1_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Blended(font, (char *)utf8, fg);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font,
- const char *text, SDL_Color fg)
- {
- SDL_bool first;
- int i;
- int xstart;
- int width, height;
- SDL_Surface *textbuf;
- Uint8 alpha;
- Uint8 alpha_table[256];
- Uint32 pixel;
- Uint8 *src;
- Uint32 *dst;
- Uint32 *dst_check;
- int row, col;
- c_glyph *glyph;
- raqm_t *rq = NULL;
- raqm_glyph_t *g_info = NULL;
- size_t glyph_count = 0;
- FT_Error error;
- FT_UInt prev_index = 0;
- size_t textlen;
- TTF_CHECKPOINTER(text, NULL);
- textlen = SDL_strlen(text);
- /* Shape text */
- if (text_layout(text, textlen, font, &rq, &g_info, &glyph_count) < 0)
- {
- TTF_SetError("Text layout failed");
- return NULL;
- }
- /* Get the dimensions of the text surface */
- if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
- raqm_destroy(rq);
- TTF_SetError("Text has zero width");
- return(NULL);
- }
- /* Create the target surface */
- textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
- 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
- if (textbuf == NULL) {
- raqm_destroy(rq);
- TTF_SetError("SDL_Surface creation failed");
- return NULL;
- }
- /* Adding bound checking to avoid all kinds of memory corruption errors
- that may occur. */
- dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h;
- /* Support alpha blending */
- if (!fg.a) {
- fg.a = SDL_ALPHA_OPAQUE;
- }
- if (fg.a == SDL_ALPHA_OPAQUE) {
- for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
- alpha_table[i] = (Uint8)i;
- }
- } else {
- for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
- alpha_table[i] = (Uint8)(i * fg.a / 255);
- }
- SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
- }
- /* Load and render each glyph */
- first = SDL_TRUE;
- xstart = 0;
- pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
- SDL_FillRect(textbuf, NULL, pixel); /* Initialize with fg and 0 alpha */
- for (i = 0; i < glyph_count; i++) {
- int y_offset;
- error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_PIXMAP);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- SDL_FreeSurface(textbuf);
- raqm_destroy(rq);
- return NULL;
- }
- glyph = font->current;
- y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
- /* Ensure the width of the pixmap is correct. On some cases,
- * freetype may report a larger pixmap than possible.*/
- width = glyph->pixmap.width;
- if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
- width = glyph->maxx - glyph->minx;
- }
- for (row = 0; row < glyph->pixmap.rows; ++row) {
- /* Make sure we don't go either over, or under the
- * limit */
- if ( row+y_offset < 0 ) {
- continue;
- }
- if ( row+y_offset >= textbuf->h ) {
- continue;
- }
- dst = (Uint32*) textbuf->pixels +
- (row+y_offset) * textbuf->pitch/4 +
- xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
- /* Added code to adjust src pointer for pixmaps to
- * account for pitch.
- * */
- dst_check = (Uint32*) textbuf->pixels + (row + y_offset + 1) * textbuf->pitch/4;
- src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
- for (col = width; col>0 && dst < dst_check; --col) {
- alpha = *src++;
- *dst++ |= pixel | ((Uint32)alpha_table[alpha] << 24);
- }
- }
- xstart += FT_FLOOR(g_info[i].x_advance);
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- xstart += font->glyph_overhang;
- }
- prev_index = g_info[i].index;
- }
- /* Handle the underline style */
- if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
- row = TTF_underline_top_row(font);
- TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
- }
- /* Handle the strikethrough style */
- if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
- row = TTF_strikethrough_top_row(font);
- TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
- }
- raqm_destroy(rq);
- return(textbuf);
- }
- SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font,
- const Uint16 *text, SDL_Color fg)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
- if (utf8) {
- UCS2_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Blended(font, (char *)utf8, fg);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- SDL_Surface *TTF_RenderText_Blended_Wrapped(TTF_Font *font, const char *text, SDL_Color fg, Uint32 wrapLength)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, LATIN1_to_UTF8_len(text));
- if (utf8) {
- LATIN1_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Blended_Wrapped(font, (char *)utf8, fg, wrapLength);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- static SDL_bool CharacterIsDelimiter(char c, const char *delimiters)
- {
- while (*delimiters) {
- if (c == *delimiters) {
- return SDL_TRUE;
- }
- ++delimiters;
- }
- return SDL_FALSE;
- }
- /* Don't define this until we have a release where we can change font rendering
- #define TTF_USE_LINESKIP
- */
- SDL_Surface *TTF_RenderUTF8_Blended_Wrapped(TTF_Font *font,
- const char *text, SDL_Color fg, Uint32 wrapLength)
- {
- SDL_bool first;
- int i;
- int xstart;
- int width, height;
- SDL_Surface *textbuf;
- Uint8 alpha;
- Uint8 alpha_table[256];
- Uint32 pixel;
- Uint8 *src;
- Uint32 *dst;
- Uint32 *dst_check;
- int row, col;
- c_glyph *glyph;
- raqm_t *rq = NULL;
- raqm_glyph_t *g_info = NULL;
- size_t glyph_count = 0;
- FT_Error error;
- FT_UInt prev_index = 0;
- #ifndef TTF_USE_LINESKIP
- const int lineSpace = 2;
- #endif
- int line, numLines, rowSize;
- char *str, **strLines, **newLines;
- size_t textlen;
- TTF_CHECKPOINTER(text, NULL);
- textlen = SDL_strlen(text);
- /* Shape text */
- if (text_layout(text,textlen, font, &rq, &g_info, &glyph_count) < 0)
- {
- TTF_SetError("Text layout failed");
- return NULL;
- }
- /* Get the dimensions of the text surface */
- if ( ( CalculateSize(font, g_info, glyph_count, &width, &height) < 0 ) || !width ) {
- raqm_destroy(rq);
- TTF_SetError("Text has zero width");
- return(NULL);
- }
- numLines = 1;
- str = NULL;
- strLines = NULL;
- if (wrapLength > 0 && *text) {
- const char *wrapDelims = " \t\r\n";
- int w, h;
- char *spot, *tok, *next_tok, *end;
- char delim;
- size_t str_len = SDL_strlen(text);
- numLines = 0;
- str = SDL_stack_alloc(char, str_len+1);
- if (str == NULL) {
- raqm_destroy(rq);
- TTF_SetError("Out of memory");
- return(NULL);
- }
- SDL_strlcpy(str, text, str_len+1);
- tok = str;
- end = str + str_len;
- do {
- newLines = (char **)SDL_realloc(strLines, (numLines+1)*sizeof(*strLines));
- if (!newLines) {
- raqm_destroy(rq);
- TTF_SetError("Out of memory");
- SDL_free(strLines);
- SDL_stack_free(str);
- return(NULL);
- }
- strLines = newLines;
- strLines[numLines++] = tok;
- /* Look for the end of the line */
- if ((spot = SDL_strchr(tok, '\r')) != NULL ||
- (spot = SDL_strchr(tok, '\n')) != NULL) {
- if (*spot == '\r') {
- ++spot;
- }
- if (*spot == '\n') {
- ++spot;
- }
- } else {
- spot = end;
- }
- next_tok = spot;
- /* Get the longest string that will fit in the desired space */
- for (; ;) {
- /* Strip trailing whitespace */
- while (spot > tok &&
- CharacterIsDelimiter(spot[-1], wrapDelims)) {
- --spot;
- }
- if (spot == tok) {
- if (CharacterIsDelimiter(*spot, wrapDelims)) {
- *spot = '\0';
- }
- break;
- }
- delim = *spot;
- *spot = '\0';
- TTF_SizeUTF8(font, tok, &w, &h);
- if ((Uint32)w <= wrapLength) {
- break;
- } else {
- /* Back up and try again... */
- *spot = delim;
- }
- while (spot > tok &&
- !CharacterIsDelimiter(spot[-1], wrapDelims)) {
- --spot;
- }
- if (spot > tok) {
- next_tok = spot;
- }
- }
- tok = next_tok;
- } while (tok < end);
- }
- /* Create the target surface */
- textbuf = SDL_CreateRGBSurface(SDL_SWSURFACE,
- (numLines > 1) ? wrapLength : width,
- #ifdef TTF_USE_LINESKIP
- numLines * TTF_FontLineSkip(font),
- #else
- height * numLines + (lineSpace * (numLines - 1)),
- #endif
- 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
- if (textbuf == NULL) {
- if (strLines) {
- SDL_free(strLines);
- SDL_stack_free(str);
- }
- raqm_destroy(rq);
- return(NULL);
- }
- #ifdef TTF_USE_LINESKIP
- rowSize = textbuf->pitch/4 * TTF_FontLineSkip(font);
- #else
- rowSize = textbuf->pitch/4 * height;
- #endif
- /* Adding bound checking to avoid all kinds of memory corruption errors
- that may occur. */
- dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h;
- /* Support alpha blending */
- if (!fg.a) {
- fg.a = SDL_ALPHA_OPAQUE;
- }
- if (fg.a == SDL_ALPHA_OPAQUE) {
- for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
- alpha_table[i] = (Uint8)i;
- }
- } else {
- for (i = 0; i < SDL_arraysize(alpha_table); ++i) {
- alpha_table[i] = (Uint8)(i * fg.a / 255);
- }
- SDL_SetSurfaceBlendMode(textbuf, SDL_BLENDMODE_BLEND);
- }
- /* Load and render each glyph */
- pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
- SDL_FillRect(textbuf, NULL, pixel); /* Initialize with fg and 0 alpha */
- for (line = 0; line < numLines; line++) {
- if (strLines) {
- text = strLines[line];
- }
- first = SDL_TRUE;
- xstart = 0;
- for (i = 0; i < glyph_count; i++) {
- int y_offset;
- error = Find_GlyphByIndex(font, g_info[i].index, CACHED_METRICS|CACHED_PIXMAP);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- SDL_FreeSurface(textbuf);
- if (strLines) {
- SDL_free(strLines);
- SDL_stack_free(str);
- }
- return NULL;
- }
- glyph = font->current;
- y_offset = glyph->yoffset - FT_FLOOR(g_info[i].y_offset);
- /* Ensure the width of the pixmap is correct. On some cases,
- * freetype may report a larger pixmap than possible.*/
- width = glyph->pixmap.width;
- if (font->outline <= 0 && width > glyph->maxx - glyph->minx) {
- width = glyph->maxx - glyph->minx;
- }
- /* Compensate for the wrap around bug with negative minx's */
- if (first && (glyph->minx < 0)) {
- xstart -= glyph->minx;
- }
- first = SDL_FALSE;
- for (row = 0; row < glyph->pixmap.rows; ++row) {
- /* Make sure we don't go either over, or under the
- * limit */
- if ( row+y_offset < 0 ) {
- continue;
- }
- if ( row+y_offset >= textbuf->h ) {
- continue;
- }
- dst = ((Uint32*)textbuf->pixels + rowSize * line) +
- (row+y_offset) * textbuf->pitch/4 +
- xstart + FT_FLOOR(g_info[i].x_offset) + glyph->minx;
- /* Added code to adjust src pointer for pixmaps to
- * account for pitch.
- * */
- src = (Uint8*) (glyph->pixmap.buffer + glyph->pixmap.pitch * row);
- for (col = width; col>0 && dst < dst_check; --col) {
- alpha = *src++;
- *dst++ |= pixel | ((Uint32)alpha_table[alpha] << 24);
- }
- }
- xstart += FT_FLOOR(g_info[i].x_advance);
- if (TTF_HANDLE_STYLE_BOLD(font)) {
- xstart += font->glyph_overhang;
- }
- prev_index = g_info[i].index;
- }
- /* Handle the underline style *
- if (TTF_HANDLE_STYLE_UNDERLINE(font)) {
- row = TTF_underline_top_row(font);
- TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
- }
- */
- /* Handle the strikethrough style *
- if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) {
- row = TTF_strikethrough_top_row(font);
- TTF_drawLine_Blended(font, textbuf, row, pixel | (Uint32)fg.a << 24);
- }
- */
- }
- if (strLines) {
- SDL_free(strLines);
- SDL_stack_free(str);
- }
- raqm_destroy(rq);
- return(textbuf);
- }
- SDL_Surface *TTF_RenderUNICODE_Blended_Wrapped(TTF_Font *font, const Uint16* text,
- SDL_Color fg, Uint32 wrapLength)
- {
- SDL_Surface *surface = NULL;
- Uint8 *utf8;
- TTF_CHECKPOINTER(text, NULL);
- utf8 = SDL_stack_alloc(Uint8, UCS2_to_UTF8_len(text));
- if (utf8) {
- UCS2_to_UTF8(text, utf8);
- surface = TTF_RenderUTF8_Blended_Wrapped(font, (char *)utf8, fg, wrapLength);
- SDL_stack_free(utf8);
- } else {
- SDL_OutOfMemory();
- }
- return surface;
- }
- SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg)
- {
- Uint16 ucs2[2];
- Uint8 utf8[4];
- ucs2[0] = ch;
- ucs2[1] = 0;
- UCS2_to_UTF8(ucs2, utf8);
- return TTF_RenderUTF8_Blended(font, (char *)utf8, fg);
- }
- void TTF_SetFontStyle(TTF_Font* font, int style)
- {
- int prev_style = font->style;
- font->style = style | font->face_style;
- /* Flush the cache if the style has changed.
- * Ignore UNDERLINE which does not impact glyph drawning.
- * */
- if ((font->style | TTF_STYLE_NO_GLYPH_CHANGE) != (prev_style | TTF_STYLE_NO_GLYPH_CHANGE)) {
- Flush_Cache(font);
- }
- }
- int TTF_GetFontStyle(const TTF_Font* font)
- {
- return font->style;
- }
- void TTF_SetFontOutline(TTF_Font* font, int outline)
- {
- font->outline = outline;
- Flush_Cache(font);
- }
- int TTF_GetFontOutline(const TTF_Font* font)
- {
- return font->outline;
- }
- void TTF_SetFontHinting(TTF_Font* font, int hinting)
- {
- if (hinting == TTF_HINTING_LIGHT)
- font->hinting = FT_LOAD_TARGET_LIGHT;
- else if (hinting == TTF_HINTING_MONO)
- font->hinting = FT_LOAD_TARGET_MONO;
- else if (hinting == TTF_HINTING_NONE)
- font->hinting = FT_LOAD_NO_HINTING;
- else
- font->hinting = 0;
- Flush_Cache(font);
- }
- int TTF_GetFontHinting(const TTF_Font* font)
- {
- if (font->hinting == FT_LOAD_TARGET_LIGHT)
- return TTF_HINTING_LIGHT;
- else if (font->hinting == FT_LOAD_TARGET_MONO)
- return TTF_HINTING_MONO;
- else if (font->hinting == FT_LOAD_NO_HINTING)
- return TTF_HINTING_NONE;
- return 0;
- }
- void TTF_Quit(void)
- {
- if (TTF_initialized) {
- if (--TTF_initialized == 0) {
- FT_Done_FreeType(library);
- }
- }
- }
- int TTF_WasInit(void)
- {
- return TTF_initialized;
- }
- /* don't use this function. It's just here for binary compatibility. */
- int TTF_GetFontKerningSize(TTF_Font* font, int prev_index, int index)
- {
- FT_Vector delta;
- FT_Get_Kerning(font->face, prev_index, index, ft_kerning_default, &delta);
- return (delta.x >> 6);
- }
- int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, Uint16 previous_ch, Uint16 ch)
- {
- int error;
- int glyph_index, prev_index;
- FT_Vector delta;
- if (ch == UNICODE_BOM_NATIVE || ch == UNICODE_BOM_SWAPPED) {
- return 0;
- }
- if (previous_ch == UNICODE_BOM_NATIVE || previous_ch == UNICODE_BOM_SWAPPED) {
- return 0;
- }
- error = Find_Glyph(font, ch, CACHED_METRICS);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- return -1;
- }
- glyph_index = font->current->index;
- error = Find_Glyph(font, previous_ch, CACHED_METRICS);
- if (error) {
- TTF_SetFTError("Couldn't find glyph", error);
- return -1;
- }
- prev_index = font->current->index;
- error = FT_Get_Kerning(font->face, prev_index, glyph_index, ft_kerning_default, &delta);
- if (error) {
- TTF_SetFTError("Couldn't get glyph kerning", error);
- return -1;
- }
- return (delta.x >> 6);
- }
- /* vi: set ts=4 sw=4 expandtab: */
|