Loïc LAMBERT to Sam
authorSam Lantinga <slouken@libsdl.org>
Sat, 17 Oct 2009 18:16:33 +0000
changeset 1440f803b00e43b
parent 143 b6ab85f6d9d5
child 145 29cc5aba8af2
Loïc LAMBERT to Sam

You'll find attached a new patch:
- add font style TTF_STYLE_STRIKETHROUGH
- fix the drawing of outlined underlined text
- cleaning: take all the relevant attributes into account in TTF_SizeUNICODE (outline, underline)

For strikethrough:
- the line has the same height as the underline
- the line is drawn half the height of the font. I tried half the ascent, but it was much to high. Maybe someone could find a better formula.
CHANGES
SDL_ttf.c
SDL_ttf.h
     1.1 --- a/CHANGES	Fri Oct 16 13:39:46 2009 +0000
     1.2 +++ b/CHANGES	Sat Oct 17 18:16:33 2009 +0000
     1.3 @@ -1,4 +1,8 @@
     1.4  2.0.10:
     1.5 +Loc LAMBERT - Sat Oct 17 11:15:33 PDT 2009
     1.6 + * Set the appropriate font styles for bold and italic fonts
     1.7 + * Added font style TTF_STYLE_STRIKETHROUGH
     1.8 + * Fixed size calculations taking outline and underline into account
     1.9  Adam Strzelecki - Sun Oct 11 03:51:31 PDT 2009
    1.10   * Added API for font outlining: TTF_GetFontOutline()/TTF_SetFontOutline()
    1.11  Sam Lantinga - Sat Sep 26 01:13:29 PDT 2009
     2.1 --- a/SDL_ttf.c	Fri Oct 16 13:39:46 2009 +0000
     2.2 +++ b/SDL_ttf.c	Sat Oct 17 18:16:33 2009 +0000
     2.3 @@ -128,6 +128,10 @@
     2.4  #define TTF_HANDLE_STYLE_ITALIC(font) (((font)->style & TTF_STYLE_ITALIC) && \
     2.5                                        !((font)->face_style & TTF_STYLE_ITALIC))
     2.6  #define TTF_HANDLE_STYLE_UNDERLINE(font) ((font)->style & TTF_STYLE_UNDERLINE)
     2.7 +#define TTF_HANDLE_STYLE_STRIKETHROUGH(font) ((font)->style & TTF_STYLE_STRIKETHROUGH)
     2.8 +
     2.9 +/* Font styles that does not impact glyph drawing */
    2.10 +#define TTF_STYLE_NO_GLYPH_CHANGE	(TTF_STYLE_UNDERLINE | TTF_STYLE_STRIKETHROUGH)
    2.11  
    2.12  /* The FreeType font engine/library */
    2.13  static FT_Library library;
    2.14 @@ -162,13 +166,138 @@
    2.15  	}
    2.16  }
    2.17  
    2.18 -static __inline__ int TTF_underline_row(TTF_Font *font, int height)
    2.19 +/* Gets the top row of the underline. The outline
    2.20 +   is taken into account.
    2.21 +*/
    2.22 +static __inline__ int TTF_underline_top_row(TTF_Font *font)
    2.23  {
    2.24 -	int result = font->ascent - font->underline_offset - 1;
    2.25 -	if ( result >= height) {
    2.26 -		result = (height-1) - font->underline_height;
    2.27 +	/* With outline, the underline_offset is underline_offset+outline. */
    2.28 +	/* So, we don't have to remove the top part of the outline height. */
    2.29 +	return font->ascent - font->underline_offset - 1;
    2.30 +}
    2.31 +
    2.32 +/* Gets the bottom row of the underline. The outline
    2.33 +   is taken into account.
    2.34 +*/
    2.35 +static __inline__ int TTF_underline_bottom_row(TTF_Font *font)
    2.36 +{
    2.37 +	int row = TTF_underline_top_row(font) + font->underline_height;
    2.38 +	if( font->outline  > 0 ) {
    2.39 +		/* Add underline_offset outline offset and */
    2.40 +		/* the bottom part of the outline. */
    2.41 +		row += font->outline * 2;
    2.42  	}
    2.43 -	return result;
    2.44 +	return row;
    2.45 +}
    2.46 +
    2.47 +/* Gets the top row of the strikethrough. The outline
    2.48 +   is taken into account.
    2.49 +*/
    2.50 +static __inline__ int TTF_strikethrough_top_row(TTF_Font *font)
    2.51 +{
    2.52 +	/* With outline, the first text row is 'outline'. */
    2.53 +	/* So, we don't have to remove the top part of the outline height. */
    2.54 +	return font->height / 2;
    2.55 +}
    2.56 +
    2.57 +/* Gets the bottom row of the strikethrough. The outline
    2.58 +   is taken into account.
    2.59 +*/
    2.60 +static __inline__ int TTF_strikethrough_bottom_row(TTF_Font *font)
    2.61 +{
    2.62 +	int row = TTF_strikethrough_top_row(font) + font->underline_height;
    2.63 +	if( font->outline  > 0 ) {
    2.64 +		/* Add first text row outline offset and */
    2.65 +		/* the bottom part of the outline. */
    2.66 +		row += font->outline * 2;
    2.67 +	}
    2.68 +	return row;
    2.69 +}
    2.70 +
    2.71 +static void TTF_initLineMectrics(const TTF_Font *font, const SDL_Surface *textbuf, const int row, Uint8 **pdst, int *pheight)
    2.72 +{
    2.73 +	Uint8 *dst;
    2.74 +	int height;
    2.75 +
    2.76 +	dst = (Uint8 *)textbuf->pixels;
    2.77 +	if( row > 0 ) {
    2.78 +		dst += row * textbuf->pitch;
    2.79 +	}
    2.80 +
    2.81 +	height = font->underline_height;
    2.82 +	/* Take outline into account */
    2.83 +	if( font->outline > 0 ) {
    2.84 +		height += font->outline * 2;
    2.85 +	}
    2.86 +	*pdst = dst;
    2.87 +	*pheight = height;
    2.88 +}
    2.89 +
    2.90 +/* Draw a solid line of underline_height (+ optional outline)
    2.91 +   at the given row. The row value must take the
    2.92 +   outline into account.
    2.93 +*/
    2.94 +static void TTF_drawLine_Solid(const TTF_Font *font, const SDL_Surface *textbuf, const int row)
    2.95 +{
    2.96 +	int line;
    2.97 +	Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
    2.98 +	Uint8 *dst;
    2.99 +	int height;
   2.100 +
   2.101 +	TTF_initLineMectrics(font, textbuf, row, &dst, &height);
   2.102 +
   2.103 +	/* Draw line */
   2.104 +	for ( line=height; line>0 && dst < dst_check; --line ) {
   2.105 +		/* 1 because 0 is the bg color */
   2.106 +		memset( dst, 1, textbuf->w );
   2.107 +		dst += textbuf->pitch;
   2.108 +	}
   2.109 +}
   2.110 +
   2.111 +/* Draw a shaded line of underline_height (+ optional outline)
   2.112 +   at the given row. The row value must take the
   2.113 +   outline into account.
   2.114 +*/
   2.115 +static void TTF_drawLine_Shaded(const TTF_Font *font, const SDL_Surface *textbuf, const int row)
   2.116 +{
   2.117 +	int line;
   2.118 +	Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h;
   2.119 +	Uint8 *dst;
   2.120 +	int height;
   2.121 +
   2.122 +	TTF_initLineMectrics(font, textbuf, row, &dst, &height);
   2.123 +
   2.124 +	/* Draw line */
   2.125 +	for ( line=height; line>0 && dst < dst_check; --line ) {
   2.126 +		memset( dst, NUM_GRAYS - 1, textbuf->w );
   2.127 +		dst += textbuf->pitch;
   2.128 +	}
   2.129 +}
   2.130 +
   2.131 +/* Draw a blended line of underline_height (+ optional outline)
   2.132 +   at the given row. The row value must take the
   2.133 +   outline into account.
   2.134 +*/
   2.135 +static void TTF_drawLine_Blended(const TTF_Font *font, const SDL_Surface *textbuf, const int row, const Uint32 color)
   2.136 +{
   2.137 +	int line;
   2.138 +	Uint32 *dst_check = (Uint32*)textbuf->pixels + textbuf->pitch/4 * textbuf->h;
   2.139 +	Uint8 *dst8; /* destination, byte version */
   2.140 +	Uint32 *dst;
   2.141 +	int height;
   2.142 +	int col;
   2.143 +	Uint32 pixel = color | 0xFF000000; /* Amask */
   2.144 +
   2.145 +	TTF_initLineMectrics(font, textbuf, row, &dst8, &height);
   2.146 +	dst = (Uint32 *) dst8;
   2.147 +
   2.148 +	/* Draw line */
   2.149 +	for ( line=height; line>0 && dst < dst_check; --line ) {
   2.150 +		for ( col=0; col < textbuf->w; ++col ) {
   2.151 +			dst[col] = pixel;
   2.152 +		}
   2.153 +		dst += textbuf->pitch/4;
   2.154 +	}
   2.155  }
   2.156  
   2.157  /* rcg06192001 get linked library's version. */
   2.158 @@ -368,6 +497,8 @@
   2.159  		font->height, font->lineskip);
   2.160  	printf("\tunderline_offset = %d, underline_height = %d\n",
   2.161  		font->underline_offset, font->underline_height);
   2.162 +	printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n",
   2.163 +		TTF_underline_top_row(font), TTF_strikethrough_top_row(font));
   2.164  #endif
   2.165  
   2.166  	/* Initialize the font face style */
   2.167 @@ -995,6 +1126,12 @@
   2.168  	/* check kerning */
   2.169  	use_kerning = FT_HAS_KERNING( font->face ) && font->kerning;
   2.170  
   2.171 +	/* Init outline handling */
   2.172 +	int outline_delta = 0;
   2.173 +	if ( font->outline  > 0 ) {
   2.174 +		outline_delta = font->outline * 2;
   2.175 +	}
   2.176 +
   2.177  	/* Load each character and sum it's bounding box */
   2.178  	x= 0;
   2.179  	for ( ch=text; *ch; ++ch ) {
   2.180 @@ -1078,19 +1215,21 @@
   2.181  
   2.182  	/* Fill the bounds rectangle */
   2.183  	if ( w ) {
   2.184 -		*w = (maxx - minx);
   2.185 +		/* Add outline extra width */
   2.186 +		*w = (maxx - minx) + outline_delta;
   2.187  	}
   2.188  	if ( h ) {
   2.189  		/* Some fonts descend below font height (FletcherGothicFLF) */
   2.190 -		*h = (font->ascent - miny);
   2.191 -		if (*h < font->height) {
   2.192 +		/* Add outline extra height */
   2.193 +		*h = (font->ascent - miny) + outline_delta;
   2.194 +		if ( *h < font->height ) {
   2.195  			*h = font->height;
   2.196  		}
   2.197  		/* Update height according to the needs of the underline style */
   2.198  		if( TTF_HANDLE_STYLE_UNDERLINE(font) ) {
   2.199 -			int rowMax = TTF_underline_row(font, *h) + font->underline_height;
   2.200 -			if ( rowMax > *h ) {
   2.201 -				*h = rowMax;
   2.202 +			int bottom_row = TTF_underline_bottom_row(font);
   2.203 +			if ( *h < bottom_row ) {
   2.204 +				*h = bottom_row;
   2.205  			}
   2.206  		}
   2.207  	}
   2.208 @@ -1179,7 +1318,7 @@
   2.209  	}
   2.210  
   2.211  	/* Create the target surface */
   2.212 -	textbuf = SDL_AllocSurface(SDL_SWSURFACE, width + font->outline * 2, height + font->outline * 2, 8, 0, 0, 0, 0);
   2.213 +	textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
   2.214  	if( textbuf == NULL ) {
   2.215  		return NULL;
   2.216  	}
   2.217 @@ -1276,13 +1415,14 @@
   2.218  
   2.219  	/* Handle the underline style */
   2.220  	if( TTF_HANDLE_STYLE_UNDERLINE(font) ) {
   2.221 -		row = TTF_underline_row(font, textbuf->h);
   2.222 -		dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
   2.223 -		for ( row=font->underline_height; row>0 && dst < dst_check; --row ) {
   2.224 -			/* 1 because 0 is the bg color */
   2.225 -			memset( dst, 1, textbuf->w );
   2.226 -			dst += textbuf->pitch;
   2.227 -		}
   2.228 +		row = TTF_underline_top_row(font);
   2.229 +		TTF_drawLine_Solid(font, textbuf, row);
   2.230 +	}
   2.231 +
   2.232 +	/* Handle the strikethrough style */
   2.233 +	if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) {
   2.234 +		row = TTF_strikethrough_top_row(font);
   2.235 +		TTF_drawLine_Solid(font, textbuf, row);
   2.236  	}
   2.237  	return textbuf;
   2.238  }
   2.239 @@ -1333,13 +1473,14 @@
   2.240  
   2.241  	/* Handle the underline style */
   2.242  	if( TTF_HANDLE_STYLE_UNDERLINE(font) ) {
   2.243 -		row = TTF_underline_row(font, textbuf->h);
   2.244 -		dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
   2.245 -		for ( row=font->underline_height; row>0; --row ) {
   2.246 -			/* 1 because 0 is the bg color */
   2.247 -			memset( dst, 1, textbuf->w );
   2.248 -			dst += textbuf->pitch;
   2.249 -		}
   2.250 +		row = TTF_underline_top_row(font);
   2.251 +		TTF_drawLine_Solid(font, textbuf, row);
   2.252 +	}
   2.253 +
   2.254 +	/* Handle the strikethrough style */
   2.255 +	if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) {
   2.256 +		row = TTF_strikethrough_top_row(font);
   2.257 +		TTF_drawLine_Solid(font, textbuf, row);
   2.258  	}
   2.259  	return(textbuf);
   2.260  }
   2.261 @@ -1432,7 +1573,7 @@
   2.262  	}
   2.263  
   2.264  	/* Create the target surface */
   2.265 -	textbuf = SDL_AllocSurface(SDL_SWSURFACE, width + font->outline * 2, height + font->outline * 2, 8, 0, 0, 0, 0);
   2.266 +	textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
   2.267  	if( textbuf == NULL ) {
   2.268  		return NULL;
   2.269  	}
   2.270 @@ -1530,12 +1671,14 @@
   2.271  
   2.272  	/* Handle the underline style */
   2.273  	if( TTF_HANDLE_STYLE_UNDERLINE(font) ) {
   2.274 -		row = TTF_underline_row(font, textbuf->h);
   2.275 -		dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
   2.276 -		for ( row=font->underline_height; row>0 && dst < dst_check; --row ) {
   2.277 -			memset( dst, NUM_GRAYS - 1, textbuf->w );
   2.278 -			dst += textbuf->pitch;
   2.279 -		}
   2.280 +		row = TTF_underline_top_row(font);
   2.281 +		TTF_drawLine_Shaded(font, textbuf, row);
   2.282 +	}
   2.283 +
   2.284 +	/* Handle the strikethrough style */
   2.285 +	if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) {
   2.286 +		row = TTF_strikethrough_top_row(font);
   2.287 +		TTF_drawLine_Shaded(font, textbuf, row);
   2.288  	}
   2.289  	return textbuf;
   2.290  }
   2.291 @@ -1595,12 +1738,14 @@
   2.292  
   2.293  	/* Handle the underline style */
   2.294  	if( TTF_HANDLE_STYLE_UNDERLINE(font) ) {
   2.295 -		row = TTF_underline_row(font, textbuf->h);
   2.296 -		dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch;
   2.297 -		for ( row=font->underline_height; row>0; --row ) {
   2.298 -			memset( dst, NUM_GRAYS - 1, textbuf->w );
   2.299 -			dst += textbuf->pitch;
   2.300 -		}
   2.301 +		row = TTF_underline_top_row(font);
   2.302 +		TTF_drawLine_Shaded(font, textbuf, row);
   2.303 +	}
   2.304 +
   2.305 +	/* Handle the strikethrough style */
   2.306 +	if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) {
   2.307 +		row = TTF_strikethrough_top_row(font);
   2.308 +		TTF_drawLine_Shaded(font, textbuf, row);
   2.309  	}
   2.310  	return textbuf;
   2.311  }
   2.312 @@ -1685,7 +1830,7 @@
   2.313  	}
   2.314  
   2.315  	/* Create the target surface */
   2.316 -	textbuf = SDL_AllocSurface(SDL_SWSURFACE, width + font->outline * 2, height + font->outline * 2, 32,
   2.317 +	textbuf = SDL_AllocSurface(SDL_SWSURFACE, width, height, 32,
   2.318  	                           0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
   2.319  	if ( textbuf == NULL ) {
   2.320  		return(NULL);
   2.321 @@ -1779,15 +1924,14 @@
   2.322  
   2.323  	/* Handle the underline style */
   2.324  	if( TTF_HANDLE_STYLE_UNDERLINE(font) ) {
   2.325 -		row = TTF_underline_row(font, textbuf->h);
   2.326 -		dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
   2.327 -		pixel |= 0xFF000000; /* Amask */
   2.328 -		for ( row=font->underline_height; row>0 && dst < dst_check; --row ) {
   2.329 -			for ( col=0; col < textbuf->w; ++col ) {
   2.330 -				dst[col] = pixel;
   2.331 -			}
   2.332 -			dst += textbuf->pitch/4;
   2.333 -		}
   2.334 +		row = TTF_underline_top_row(font);
   2.335 +		TTF_drawLine_Blended(font, textbuf, row, pixel);
   2.336 +	}
   2.337 +
   2.338 +	/* Handle the strikethrough style */
   2.339 +	if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) {
   2.340 +		row = TTF_strikethrough_top_row(font);
   2.341 +		TTF_drawLine_Blended(font, textbuf, row, pixel);
   2.342  	}
   2.343  	return(textbuf);
   2.344  }
   2.345 @@ -1833,15 +1977,14 @@
   2.346  
   2.347  	/* Handle the underline style */
   2.348  	if( TTF_HANDLE_STYLE_UNDERLINE(font) ) {
   2.349 -		row = TTF_underline_row(font, textbuf->h);
   2.350 -		dst = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4;
   2.351 -		pixel |= 0xFF000000; /* Amask */
   2.352 -		for ( row=font->underline_height; row>0; --row ) {
   2.353 -			for ( col=0; col < textbuf->w; ++col ) {
   2.354 -				dst[col] = pixel;
   2.355 -			}
   2.356 -			dst += textbuf->pitch/4;
   2.357 -		}
   2.358 +		row = TTF_underline_top_row(font);
   2.359 +		TTF_drawLine_Blended(font, textbuf, row, pixel);
   2.360 +	}
   2.361 +
   2.362 +	/* Handle the strikethrough style */
   2.363 +	if( TTF_HANDLE_STYLE_STRIKETHROUGH(font) ) {
   2.364 +		row = TTF_strikethrough_top_row(font);
   2.365 +		TTF_drawLine_Blended(font, textbuf, row, pixel);
   2.366  	}
   2.367  	return(textbuf);
   2.368  }
   2.369 @@ -1854,7 +1997,7 @@
   2.370  	/* Flush the cache if the style has changed.
   2.371  	 * Ignore UNDERLINE which does not impact glyph drawning.
   2.372  	 * */
   2.373 -	if ( (font->style | TTF_STYLE_UNDERLINE ) != ( prev_style | TTF_STYLE_UNDERLINE )) {
   2.374 +	if ( (font->style | TTF_STYLE_NO_GLYPH_CHANGE ) != ( prev_style | TTF_STYLE_NO_GLYPH_CHANGE )) {
   2.375  		Flush_Cache( font );
   2.376  	}
   2.377  }
     3.1 --- a/SDL_ttf.h	Fri Oct 16 13:39:46 2009 +0000
     3.2 +++ b/SDL_ttf.h	Sat Oct 17 18:16:33 2009 +0000
     3.3 @@ -91,14 +91,12 @@
     3.4  extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize);
     3.5  extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index);
     3.6  
     3.7 -/* Set and retrieve the font style
     3.8 -   This font style is implemented by modifying the font glyphs, and
     3.9 -   doesn't reflect any inherent properties of the truetype font file.
    3.10 -*/
    3.11 +/* Set and retrieve the font style */
    3.12  #define TTF_STYLE_NORMAL	0x00
    3.13  #define TTF_STYLE_BOLD		0x01
    3.14  #define TTF_STYLE_ITALIC	0x02
    3.15  #define TTF_STYLE_UNDERLINE	0x04
    3.16 +#define TTF_STYLE_STRIKETHROUGH	0x08
    3.17  extern DECLSPEC int SDLCALL TTF_GetFontStyle(const TTF_Font *font);
    3.18  extern DECLSPEC void SDLCALL TTF_SetFontStyle(TTF_Font *font, int style);
    3.19  extern DECLSPEC int SDLCALL TTF_GetFontOutline(const TTF_Font *font);