Files
freetype/test/display.c
2023-08-27 18:03:45 +02:00

300 lines
12 KiB
C

/****************************************************************************/
/* */
/* The FreeType project -- a free and portable quality TrueType renderer. */
/* */
/* Copyright 1996-1999 by */
/* D. Turner, R.Wilhelm, and W. Lemberg */
/* */
/* display.c: Display component used by all test programs. */
/* */
/* This file is used to display glyphs and strings in a target window */
/* using the graphics drivers provided by gmain.c, gevents.h, etc. */
/* */
/* Its role is to be shared and heavely commented to let people understand */
/* how we do the job... */
/* */
/****************************************************************************/
#include <stdlib.h> /* malloc() and free() */
#include <string.h> /* memset() */
#include "display.h"
#include "freetype.h"
#include "gmain.h"
/* The target bitmap or pixmap -- covering the full display window/screen */
TT_Raster_Map Bit;
/* A smaller intermediate bitmap used to render individual glyphs when */
/* font smoothing mode is activated. It is then or-ed to `Bit'. */
TT_Raster_Map Small_Bit;
/* The magic of or-ing gray-levels: */
/* */
/* When gray-level mode (a.k.a. font-smoothing) is on, `Bit' is an 8-bit */
/* pixmap of the size of the display window or screen. */
/* */
/* The gray-level palette to use for display is system-dependent, and */
/* given by the "gray_palette" variable defined in 'gmain.c'. It is */
/* set up by the graphics driver, and we cannot assume anything about its */
/* values. */
/* */
/* The function TT_Get_Glyph_Pixmap() can use any palette to render each */
/* individual glyph, however we'll later need to "or" the glyph to */
/* the display pixmap `Bit' to be able to form strings of text by */
/* juxtaposing several glyphs together. */
/* */
/* If we use the gray_palette directly, we'll encounter trouble doing */
/* the "or". Example: */
/* */
/* Suppose that gray_palette = { 0, 32, 64, 128, 255 } */
/* */
/* Let's render a glyph with this palette and "or" it to */
/* the `Bit' pixmap. If, by chance, we superpose two distinct non-zero */
/* colors, we will get strange results, like 32+64 = 96, which isn't in */
/* our gray palette! */
/* */
/* There are two ways to solve this problem: */
/* */
/* - perform a "slow or" where we check all possible combinations */
/* and solve conflicts. */
/* */
/* - render all pixmaps using a special "virtual" palette that eases */
/* the "oring" process, then convert the whole display pixmap to */
/* "display" colors at once. */
/* */
/* We choose the second solution, of course; this means that: */
/* */
/* - the virtual palette used is simply = { 0, 1, 2, 3, 4 }, defined in */
/* the variable "palette" below. The `Bit' and `Small_Bit' pixmaps will */
/* always contain pixels within these values, with the exception of */
/* post-render display, where `Bit' will be converted to display values */
/* by the Convert_To_Display_Palette() function. */
/* */
/* - as or-ing values between 0 and 4 will give us values between */
/* 0 and 7, we use a second palette, called "bounding_palette" */
/* to maintain all values within the virtual palette. */
/* */
/* in effect bounding_palette = { 0, 1, 2, 3, 4, 4, 4, 4 } */
/* */
/* which means that (3|4) == 7 => 4 after bounding */
/* */
/* the virtual palette */
unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 };
/* Or-ing the possible palette values gets us from 0 to 7 */
/* We must bound check these... */
unsigned char bounded_palette[8] = { 0, 1, 2, 3, 4, 4, 4, 4 };
/* Clears the Bit bitmap/pixmap */
void Clear_Display( void )
{
memset( Bit.bitmap, 0, Bit.size );
}
/* Clears the Small_Bit pixmap */
void Clear_Small( void )
{
memset( Small_Bit.bitmap, 0, Small_Bit.size );
}
/* Initialize the display bitmap named Bit */
int Init_Display( int font_smoothing )
{
Bit.rows = vio_Height; /* the whole window */
Bit.width = vio_Width;
Bit.flow = TT_Flow_Up;
if ( font_smoothing )
Bit.cols = (Bit.width+3) & -4; /* must be 32-bits aligned */
else
Bit.cols = (Bit.width+7) >> 3;
Bit.size = (long)Bit.cols * Bit.rows;
if ( Bit.bitmap )
free( Bit.bitmap );
Bit.bitmap = malloc( (int)Bit.size );
if ( !Bit.bitmap )
return -1;
Clear_Display();
return 0;
}
/* Convert the display pixmap from virtual to display palette */
void Convert_To_Display_Palette( void )
{
unsigned char* p;
long i;
p = Bit.bitmap;
for ( i = 0; i < Bit.size; i++ )
{
*p = gray_palette[(int)*p];
p++;
}
}
/* Init Small Bitmap */
int Init_Small( int x_ppem, int y_ppem )
{
if ( Small_Bit.bitmap )
free( Small_Bit.bitmap );
Small_Bit.rows = y_ppem + 32;
Small_Bit.width = x_ppem + 32;
Small_Bit.cols = ( Small_Bit.width+3 ) & -4; /* pad to 32-bits */
Small_Bit.flow = TT_Flow_Up;
Small_Bit.size = (long)Small_Bit.rows * Small_Bit.cols;
Small_Bit.bitmap = malloc( (int)Small_Bit.size );
if ( Small_Bit.bitmap )
return -1;
Clear_Small();
return 0;
}
/* Render a single glyph into the display bit/pixmap */
/* */
/* Note that in b/w mode, we simply render the glyph directly into */
/* the display map, as the scan-line converter or-es the glyph into */
/* the target bitmap. */
/* */
/* In gray mode, however, the glyph is first rendered indivdually in */
/* the Small_Bit map, then 'or-ed' with bounding into the display */
/* pixmap. */
/* */
TT_Error Render_Single_Glyph( int font_smoothing,
TT_Glyph glyph,
int x_offset,
int y_offset )
{
if ( !font_smoothing )
return TT_Get_Glyph_Bitmap( glyph, &Bit,
(long)x_offset*64, (long)y_offset*64 );
else
{
TT_Glyph_Metrics metrics;
TT_Error error;
TT_F26Dot6 x, y, xmin, ymin, xmax, ymax;
int ioff, iread;
char *off, *read, *_off, *_read;
/* font-smoothing mode */
/* we begin by grid-fitting the bounding box */
TT_Get_Glyph_Metrics( glyph, &metrics );
xmin = metrics.bbox.xMin & -64;
ymin = metrics.bbox.yMin & -64;
xmax = (metrics.bbox.xMax+63) & -64;
ymax = (metrics.bbox.yMax+63) & -64;
/* now render the glyph in the small pixmap */
/* IMPORTANT NOTE: the offset parameters passed to the function */
/* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e., */
/* multiples of 64. HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */
/* This is why we _did_ grid-fit the bounding box, especially xmin */
/* and ymin. */
Clear_Small();
error = TT_Get_Glyph_Pixmap( glyph, &Small_Bit, -xmin, -ymin );
if ( error )
return error;
/* Blit-or the resulting small pixmap into the biggest one */
/* We do that by hand, and provide also clipping. */
xmin = (xmin >> 6) + x_offset;
ymin = (ymin >> 6) + y_offset;
xmax = (xmax >> 6) + x_offset;
ymax = (ymax >> 6) + y_offset;
/* Take care of comparing xmin and ymin with signed values! */
/* This was the cause of strange misplacements when Bit.rows */
/* was unsigned. */
if ( xmin >= (int)Bit.width ||
ymin >= (int)Bit.rows ||
xmax < 0 ||
ymax < 0 )
return TT_Err_Ok; /* nothing to do */
/* Note that the clipping check is performed _after_ rendering */
/* the glyph in the small bitmap to let this function return */
/* potential error codes for all glyphs, even hidden ones. */
/* In exotic glyphs, the bounding box may be larger than the */
/* size of the small pixmap. Take care of that here. */
if ( xmax-xmin + 1 > Small_Bit.width )
xmax = xmin + Small_Bit.width - 1;
if ( ymax-ymin + 1 > Small_Bit.rows )
ymax = ymin + Small_Bit.rows - 1;
/* set up clipping and cursors */
iread = 0;
if ( ymin < 0 )
{
iread -= ymin * Small_Bit.cols;
ioff = 0;
ymin = 0;
}
else
ioff = ymin * Bit.cols;
if ( ymax >= Bit.rows )
ymax = Bit.rows-1;
if ( xmin < 0 )
{
iread -= xmin;
xmin = 0;
}
else
ioff += xmin;
if ( xmax >= Bit.width )
xmax = Bit.width - 1;
_read = (char*)Small_Bit.bitmap + iread;
_off = (char*)Bit.bitmap + ioff;
for ( y = ymin; y <= ymax; y++ )
{
read = _read;
off = _off;
for ( x = xmin; x <= xmax; x++ )
{
*off = bounded_palette[*off | *read];
off++;
read++;
}
_read += Small_Bit.cols;
_off += Bit.cols;
}
return TT_Err_Ok;
}
}
/* End */