Skip to content

Commit

Permalink
Add functions to detect and configure Subpixel rendering mode
Browse files Browse the repository at this point in the history
 TTF_GetSubpixelMode()
 TTF_SetLcdFilter()
 TTF_SetLcdFilterWeights()
 TTF_SetLcdGeometry()

see libsdl-org#296
  • Loading branch information
1bsyl committed Aug 7, 2023
1 parent 1fe09e6 commit 71627c9
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 0 deletions.
87 changes: 87 additions & 0 deletions include/SDL3_ttf/SDL_ttf.h
Original file line number Diff line number Diff line change
Expand Up @@ -2326,6 +2326,93 @@ extern DECLSPEC int SDLCALL TTF_SetFontScriptName(TTF_Font *font, const char *sc
*/
extern DECLSPEC SDL_bool TTF_IsFontScalable(const TTF_Font *font);

/**
* Subpixel rendering mode
*
* \sa TTF_GetSubpixelMode
* \sa TTF_SetLcdGeometry
* \sa TTF_SetLcdFilter
* \sa TTF_SetLcdFilterWeights
*/
typedef enum
{
TTF_SUBPIXEL_MODE_UNKNOWN = 0, /* Unknown */
TTF_SUBPIXEL_MODE_HARMONY = 1, /* Harmony LCD rendering */
TTF_SUBPIXEL_MODE_CLEARTYPE_STYLE = 2, /* ClearType-style LCD rendering */
} TTF_SubpixelMode;

/**
* LCD filter, for ClearType-style LCD rendering
* mapping to FreeType FT_LcdFilter
*/
typedef enum
{
TTF_LCD_FILTER_NONE = 0,
TTF_LCD_FILTER_DEFAULT = 1,
TTF_LCD_FILTER_LIGHT = 2,
TTF_LCD_FILTER_LEGACY1 = 3,
TTF_LCD_FILTER_LEGACY = 4,
} TTF_LcdFilter;

/**
* Detect which subpixel rendering mode FreeType uses internally when LCD functions are used.
*
* \returns subpixel rendering mode
*
* \since This function is available since SDL_ttf 3.0.0
*
* \sa TTF_SetLcdGeometry
* \sa TTF_SetLcdFilter
* \sa TTF_SetLcdFilterWeights
*/
extern DECLSPEC TTF_SubpixelMode SDLCALL TTF_GetSubpixelMode(void);

/**
* Set parameters for Harmony LCD rendering.
*
* See FreeType function FT_Library_SetLcdGeometry for more details
* Remark: FT_Library_SetLcdGeometry's y coordinates are in reverse from the usual SDL notation (larger = upper as opposed to larger = lower).
*
* \param pixel_coordinates default positions of color subpixels
* \returns 0 on success, or -1 on error.
*
* \since This function is available since SDL_ttf 3.0.0
*
* \sa TTF_GetSubpixelMode
*/
extern DECLSPEC int SDLCALL TTF_SetLcdGeometry(const int pixel_coordinates[6]);

/**
* Set a filter for ClearType-style LCD rendering.
*
* See FreeType function FT_Library_SetLcdFilter for more details
*
* \params filter filter to use
* \returns 0 on success, or -1 on error.
*
* \since This function is available since SDL_ttf 3.0.0
*
* \sa TTF_GetSubpixelMode
* \sa TTF_LcdFilter
* \sa TTF_SetLcdFilterWeights
*/
extern DECLSPEC int SDLCALL TTF_SetLcdFilter(TTF_LcdFilter filter);

/**
* Set a custom filter for ClearType-style LCD rendering.
*
* See FreeType function FT_Library_SetLcdFilterWeights for more details
*
* \params weights A pointer to an array; the function copies the first five bytes and uses them to specify the filter weights in 1/256 units.
* \returns 0 on success, or -1 on error.
*
* \since This function is available since SDL_ttf 3.0.0
*
* \sa TTF_GetSubpixelMode
* \sa TTF_SetLcdFilter
*/
extern DECLSPEC int SDLCALL TTF_SetLcdFilterWeights(unsigned char *weights);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
Expand Down
142 changes: 142 additions & 0 deletions src/SDL_ttf.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include FT_GLYPH_H
#include FT_TRUETYPE_IDS_H
#include FT_IMAGE_H
#include FT_LCD_FILTER_H

/* Enable rendering with color
* Freetype may need to be compiled with FT_CONFIG_OPTION_USE_PNG */
Expand Down Expand Up @@ -4265,4 +4266,145 @@ SDL_bool TTF_IsFontScalable(const TTF_Font *font)
return SDL_FALSE;
}

TTF_SubpixelMode TTF_GetSubpixelMode(void) {
static SDL_bool done = SDL_FALSE;
static TTF_SubpixelMode mode = TTF_SUBPIXEL_MODE_UNKNOWN;
FT_Error error;

if (done) {
return mode;
}

TTF_CHECK_INITIALIZED(TTF_SUBPIXEL_MODE_UNKNOWN);

/* Detect TTF_SUBPIXEL_MODE_HARMONY */
{
/* {{-21, 0}, {0, 0}, {21, 0}} is the default, corresponding to 3 color stripes shifted by a third of a pixel. This could be an RGB panel. */
FT_Vector sub[3];
sub[0].x = -21;
sub[0].y = 0;
sub[1].x = 0;
sub[1].y = 0;
sub[2].x = 21;
sub[2].y = 0;
error = FT_Library_SetLcdGeometry(library, sub);

if (error == FT_Err_Unimplemented_Feature) {
/* continue detection */
} else if (error) {
TTF_SetFTError("FT_Library_SetLcdGeometry", error);
return TTF_SUBPIXEL_MODE_UNKNOWN;
} else {
done = SDL_TRUE;
mode = TTF_SUBPIXEL_MODE_HARMONY;
return mode;
}
}


/* Detect TTF_SUBPIXEL_MODE_CLEARTYPE_STYLE */
{
error = FT_Library_SetLcdFilter(library, FT_LCD_FILTER_DEFAULT);
if (error == FT_Err_Unimplemented_Feature) {
/* continue detection */
} else if (error) {
TTF_SetFTError("FT_Library_SetLcdFilter", error);
return TTF_SUBPIXEL_MODE_UNKNOWN;
} else {
done = SDL_TRUE;
mode = TTF_SUBPIXEL_MODE_CLEARTYPE_STYLE;
return mode;
}
}

return TTF_SUBPIXEL_MODE_UNKNOWN;
}

int TTF_SetLcdFilter(TTF_LcdFilter filter) {
FT_LcdFilter ft_filter;
FT_Error error;
TTF_SubpixelMode mode;

TTF_CHECK_INITIALIZED(-1);

mode = TTF_GetSubpixelMode();
if (mode != TTF_SUBPIXEL_MODE_CLEARTYPE_STYLE) {
TTF_SetError("FreeType not using ClearType-style subpixel rendering (maybe FreeType is not compiled with FT_CONFIG_OPTION_SUBPIXEL_RENDERING)");
return -1;
}

if (filter == TTF_LCD_FILTER_NONE) {
ft_filter = FT_LCD_FILTER_NONE;
} else if (filter == TTF_LCD_FILTER_DEFAULT) {
ft_filter = FT_LCD_FILTER_DEFAULT;
} else if (filter == TTF_LCD_FILTER_LIGHT) {
ft_filter = FT_LCD_FILTER_LIGHT;
} else if (filter == TTF_LCD_FILTER_LEGACY1) {
ft_filter = FT_LCD_FILTER_LEGACY1;
} else if (filter == TTF_LCD_FILTER_LEGACY) {
ft_filter = FT_LCD_FILTER_LEGACY;
} else {
return SDL_InvalidParamError("filter");
}

error = FT_Library_SetLcdFilter(library, ft_filter);
if (error) {
TTF_SetFTError("FT_Library_SetLcdFilter", error);
return -1;
}
return 0;
}

int TTF_SetLcdFilterWeights(unsigned char *weights) {
FT_Error error;
TTF_SubpixelMode mode;

TTF_CHECK_INITIALIZED(-1);

mode = TTF_GetSubpixelMode();
if (mode != TTF_SUBPIXEL_MODE_CLEARTYPE_STYLE) {
TTF_SetError("FreeType not using ClearType-style subpixel rendering (maybe FreeType is not compiled with FT_CONFIG_OPTION_SUBPIXEL_RENDERING)");
return -1;
}

if (weights == NULL) {
return SDL_InvalidParamError("weights");
}

error = FT_Library_SetLcdFilterWeights(library, weights);
if (error) {
TTF_SetFTError("FT_Library_SetLcdFilterWeights", error);
return -1;
}
return 0;
}

int TTF_SetLcdGeometry(const int pixel_coordinates[6]) {
FT_Vector sub[3];
FT_Error error;
TTF_SubpixelMode mode;

TTF_CHECK_INITIALIZED(-1);

mode = TTF_GetSubpixelMode();
if (mode != TTF_SUBPIXEL_MODE_HARMONY) {
TTF_SetError("FreeType not using Harmony subpixel rendering (maybe FreeType library is compiled with FT_CONFIG_OPTION_SUBPIXEL_RENDERING)");
return -1;
}

sub[0].x = pixel_coordinates[0];
sub[0].y = pixel_coordinates[1];
sub[1].x = pixel_coordinates[2];
sub[1].y = pixel_coordinates[3];
sub[2].x = pixel_coordinates[4];
sub[2].y = pixel_coordinates[5];

error = FT_Library_SetLcdGeometry(library, sub);
if (error) {
TTF_SetFTError("FT_Library_SetLcdGeometry", error);
return -1;
}
return 0;
}

/* vi: set ts=4 sw=4 expandtab: */
4 changes: 4 additions & 0 deletions src/SDL_ttf.sym
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ SDL3_ttf_0.0.0 {
TTF_GetFontWrappedAlign;
TTF_GetFreeTypeVersion;
TTF_GetHarfBuzzVersion;
TTF_GetSubpixelMode;
TTF_GlyphIsProvided;
TTF_GlyphIsProvided32;
TTF_GlyphMetrics;
Expand Down Expand Up @@ -83,6 +84,9 @@ SDL3_ttf_0.0.0 {
TTF_SetFontSizeDPI;
TTF_SetFontStyle;
TTF_SetFontWrappedAlign;
TTF_SetLcdFilter;
TTF_SetLcdFilterWeights;
TTF_SetLcdGeometry;
TTF_SetScript;
TTF_SizeText;
TTF_SizeUNICODE;
Expand Down

0 comments on commit 71627c9

Please sign in to comment.