1951 lines
56 KiB
C
1951 lines
56 KiB
C
/* $Xorg: bitscale.c,v 1.5 2001/02/09 02:04:02 xorgcvs Exp $ */
|
|
/*
|
|
|
|
Copyright 1991, 1994, 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
other dealings in this Software without prior written authorization
|
|
from The Open Group.
|
|
|
|
*/
|
|
/* $XFree86: xc/lib/font/bitmap/bitscale.c,v 3.30 2003/05/27 22:26:48 tsi Exp $ */
|
|
|
|
/*
|
|
* Author: Keith Packard, MIT X Consortium
|
|
*/
|
|
|
|
#include "fntfilst.h"
|
|
#include "bitmap.h"
|
|
#include "fontutil.h"
|
|
#ifndef FONTMODULE
|
|
#ifdef _XOPEN_SOURCE
|
|
#include <math.h>
|
|
#else
|
|
#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
|
|
#include <math.h>
|
|
#undef _XOPEN_SOURCE
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef MAX
|
|
#define MAX(a,b) (((a)>(b)) ? a : b)
|
|
#endif
|
|
|
|
/* Should get this from elsewhere */
|
|
extern unsigned long serverGeneration;
|
|
|
|
static void bitmapUnloadScalable (FontPtr pFont);
|
|
static void ScaleBitmap ( FontPtr pFont, CharInfoPtr opci,
|
|
CharInfoPtr pci, double *inv_xform,
|
|
double widthMult, double heightMult );
|
|
static FontPtr BitmapScaleBitmaps(FontPtr pf, FontPtr opf,
|
|
double widthMult, double heightMult,
|
|
FontScalablePtr vals);
|
|
static FontPtr PrinterScaleBitmaps(FontPtr pf, FontPtr opf,
|
|
double widthMult, double heightMult,
|
|
FontScalablePtr vals);
|
|
|
|
enum scaleType {
|
|
atom, truncate_atom, pixel_size, point_size, resolution_x,
|
|
resolution_y, average_width, scaledX, scaledY, unscaled, fontname,
|
|
raw_ascent, raw_descent, raw_pixelsize, raw_pointsize,
|
|
raw_average_width, uncomputed
|
|
};
|
|
|
|
typedef struct _fontProp {
|
|
char *name;
|
|
Atom atom;
|
|
enum scaleType type;
|
|
} fontProp;
|
|
|
|
typedef FontPtr (*ScaleFunc) ( FontPtr /* pf */,
|
|
FontPtr /* opf */,
|
|
double /* widthMult */,
|
|
double /* heightMult */,
|
|
FontScalablePtr /* vals */);
|
|
|
|
/* These next two arrays must be kept in step with the renderer array */
|
|
ScaleFunc scale[] =
|
|
{
|
|
#ifdef PCFFORMAT
|
|
BitmapScaleBitmaps,
|
|
BitmapScaleBitmaps,
|
|
#ifdef X_GZIP_FONT_COMPRESSION
|
|
BitmapScaleBitmaps,
|
|
#endif
|
|
#endif
|
|
#ifdef SNFFORMAT
|
|
BitmapScaleBitmaps,
|
|
BitmapScaleBitmaps,
|
|
#ifdef X_GZIP_FONT_COMPRESSION
|
|
BitmapScaleBitmaps,
|
|
#endif
|
|
#endif
|
|
#ifdef BDFFORMAT
|
|
BitmapScaleBitmaps,
|
|
BitmapScaleBitmaps,
|
|
#ifdef X_GZIP_FONT_COMPRESSION
|
|
BitmapScaleBitmaps,
|
|
#endif
|
|
#endif
|
|
#ifdef PCFFORMAT
|
|
PrinterScaleBitmaps,
|
|
#endif
|
|
};
|
|
|
|
static FontEntryPtr FindBestToScale ( FontPathElementPtr fpe,
|
|
FontEntryPtr entry,
|
|
FontScalablePtr vals,
|
|
FontScalablePtr best,
|
|
double *dxp, double *dyp,
|
|
double *sdxp, double *sdyp,
|
|
FontPathElementPtr *fpep );
|
|
static FontEntryPtr FindPmfToScale ( FontPathElementPtr fpe,
|
|
FontEntryPtr entry,
|
|
FontScalablePtr vals,
|
|
FontScalablePtr best,
|
|
double *dxp, double *dyp,
|
|
double *sdxp, double *sdyp,
|
|
FontPathElementPtr *fpep );
|
|
|
|
typedef FontEntryPtr (*FindToScale) (FontPathElementPtr fpe,
|
|
FontEntryPtr entry,
|
|
FontScalablePtr vals,
|
|
FontScalablePtr best,
|
|
double *dxp, double *dyp,
|
|
double *sdxp, double *sdyp,
|
|
FontPathElementPtr *fpep);
|
|
FindToScale find_scale[] =
|
|
{
|
|
FindBestToScale,
|
|
FindBestToScale,
|
|
#ifdef X_GZIP_FONT_COMPRESSION
|
|
FindBestToScale,
|
|
#endif
|
|
FindBestToScale,
|
|
FindBestToScale,
|
|
#ifdef X_GZIP_FONT_COMPRESSION
|
|
FindBestToScale,
|
|
#endif
|
|
FindBestToScale,
|
|
FindBestToScale,
|
|
#ifdef X_GZIP_FONT_COMPRESSION
|
|
FindBestToScale,
|
|
#endif
|
|
FindPmfToScale,
|
|
};
|
|
|
|
static unsigned long bitscaleGeneration = 0; /* initialization flag */
|
|
|
|
static fontProp fontNamePropTable[] = {
|
|
{ "FOUNDRY", 0, atom },
|
|
{ "FAMILY_NAME", 0, atom },
|
|
{ "WEIGHT_NAME", 0, atom },
|
|
{ "SLANT", 0, atom },
|
|
{ "SETWIDTH_NAME", 0, atom },
|
|
{ "ADD_STYLE_NAME", 0, atom },
|
|
{ "PIXEL_SIZE", 0, pixel_size },
|
|
{ "POINT_SIZE", 0, point_size },
|
|
{ "RESOLUTION_X", 0, resolution_x },
|
|
{ "RESOLUTION_Y", 0, resolution_y },
|
|
{ "SPACING", 0, atom },
|
|
{ "AVERAGE_WIDTH", 0, average_width },
|
|
{ "CHARSET_REGISTRY", 0, atom },
|
|
{ "CHARSET_ENCODING", 0, truncate_atom },
|
|
{ "FONT", 0, fontname },
|
|
{ "RAW_ASCENT", 0, raw_ascent },
|
|
{ "RAW_DESCENT", 0, raw_descent },
|
|
{ "RAW_PIXEL_SIZE", 0, raw_pixelsize },
|
|
{ "RAW_POINT_SIZE", 0, raw_pointsize },
|
|
{ "RAW_AVERAGE_WIDTH", 0, raw_average_width }
|
|
};
|
|
|
|
#define TRANSFORM_POINT(matrix, x, y, dest) \
|
|
((dest)[0] = (matrix)[0] * (x) + (matrix)[2] * (y), \
|
|
(dest)[1] = (matrix)[1] * (x) + (matrix)[3] * (y))
|
|
|
|
#define CHECK_EXTENT(lsb, rsb, desc, asc, data) \
|
|
((lsb) > (data)[0] ? (lsb) = (data)[0] : 0 , \
|
|
(rsb) < (data)[0] ? (rsb) = (data)[0] : 0, \
|
|
(-desc) > (data)[1] ? (desc) = -(data)[1] : 0 , \
|
|
(asc) < (data)[1] ? (asc) = (data)[1] : 0)
|
|
|
|
#define NPROPS (sizeof(fontNamePropTable) / sizeof(fontProp))
|
|
|
|
/* Warning: order of the next two tables is critically interdependent.
|
|
Location of "unscaled" properties at the end of fontPropTable[]
|
|
is important. */
|
|
|
|
static fontProp fontPropTable[] = {
|
|
{ "MIN_SPACE", 0, scaledX },
|
|
{ "NORM_SPACE", 0, scaledX },
|
|
{ "MAX_SPACE", 0, scaledX },
|
|
{ "END_SPACE", 0, scaledX },
|
|
{ "AVG_CAPITAL_WIDTH", 0, scaledX },
|
|
{ "AVG_LOWERCASE_WIDTH", 0, scaledX },
|
|
{ "QUAD_WIDTH", 0, scaledX },
|
|
{ "FIGURE_WIDTH", 0, scaledX },
|
|
{ "SUPERSCRIPT_X", 0, scaledX },
|
|
{ "SUPERSCRIPT_Y", 0, scaledY },
|
|
{ "SUBSCRIPT_X", 0, scaledX },
|
|
{ "SUBSCRIPT_Y", 0, scaledY },
|
|
{ "SUPERSCRIPT_SIZE", 0, scaledY },
|
|
{ "SUBSCRIPT_SIZE", 0, scaledY },
|
|
{ "SMALL_CAP_SIZE", 0, scaledY },
|
|
{ "UNDERLINE_POSITION", 0, scaledY },
|
|
{ "UNDERLINE_THICKNESS", 0, scaledY },
|
|
{ "STRIKEOUT_ASCENT", 0, scaledY },
|
|
{ "STRIKEOUT_DESCENT", 0, scaledY },
|
|
{ "CAP_HEIGHT", 0, scaledY },
|
|
{ "X_HEIGHT", 0, scaledY },
|
|
{ "ITALIC_ANGLE", 0, unscaled },
|
|
{ "RELATIVE_SETWIDTH", 0, unscaled },
|
|
{ "RELATIVE_WEIGHT", 0, unscaled },
|
|
{ "WEIGHT", 0, unscaled },
|
|
{ "DESTINATION", 0, unscaled },
|
|
{ "PCL_FONT_NAME", 0, unscaled },
|
|
{ "_ADOBE_POSTSCRIPT_FONTNAME", 0, unscaled }
|
|
};
|
|
|
|
/* sleazy way to shut up the compiler */
|
|
#define zerohack (enum scaleType)0
|
|
|
|
static fontProp rawFontPropTable[] = {
|
|
{ "RAW_MIN_SPACE", 0, },
|
|
{ "RAW_NORM_SPACE", 0, },
|
|
{ "RAW_MAX_SPACE", 0, },
|
|
{ "RAW_END_SPACE", 0, },
|
|
{ "RAW_AVG_CAPITAL_WIDTH", 0, },
|
|
{ "RAW_AVG_LOWERCASE_WIDTH", 0, },
|
|
{ "RAW_QUAD_WIDTH", 0, },
|
|
{ "RAW_FIGURE_WIDTH", 0, },
|
|
{ "RAW_SUPERSCRIPT_X", 0, },
|
|
{ "RAW_SUPERSCRIPT_Y", 0, },
|
|
{ "RAW_SUBSCRIPT_X", 0, },
|
|
{ "RAW_SUBSCRIPT_Y", 0, },
|
|
{ "RAW_SUPERSCRIPT_SIZE", 0, },
|
|
{ "RAW_SUBSCRIPT_SIZE", 0, },
|
|
{ "RAW_SMALL_CAP_SIZE", 0, },
|
|
{ "RAW_UNDERLINE_POSITION", 0, },
|
|
{ "RAW_UNDERLINE_THICKNESS", 0, },
|
|
{ "RAW_STRIKEOUT_ASCENT", 0, },
|
|
{ "RAW_STRIKEOUT_DESCENT", 0, },
|
|
{ "RAW_CAP_HEIGHT", 0, },
|
|
{ "RAW_X_HEIGHT", 0, }
|
|
};
|
|
|
|
static void
|
|
initFontPropTable(void)
|
|
{
|
|
int i;
|
|
fontProp *t;
|
|
|
|
i = sizeof(fontNamePropTable) / sizeof(fontProp);
|
|
for (t = fontNamePropTable; i; i--, t++)
|
|
t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
|
|
|
|
i = sizeof(fontPropTable) / sizeof(fontProp);
|
|
for (t = fontPropTable; i; i--, t++)
|
|
t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
|
|
|
|
i = sizeof(rawFontPropTable) / sizeof(fontProp);
|
|
for (t = rawFontPropTable; i; i--, t++)
|
|
t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
|
|
}
|
|
|
|
#if 0
|
|
static FontEntryPtr
|
|
GetScalableEntry (FontPathElementPtr fpe, FontNamePtr name)
|
|
{
|
|
FontDirectoryPtr dir;
|
|
|
|
dir = (FontDirectoryPtr) fpe->private;
|
|
return FontFileFindNameInDir (&dir->scalable, name);
|
|
}
|
|
#endif
|
|
|
|
static double
|
|
get_matrix_horizontal_component(double *matrix)
|
|
{
|
|
return hypot(matrix[0], matrix[1]);
|
|
}
|
|
|
|
static double
|
|
get_matrix_vertical_component(double *matrix)
|
|
{
|
|
return hypot(matrix[2], matrix[3]);
|
|
}
|
|
|
|
|
|
static Bool
|
|
ComputeScaleFactors(FontScalablePtr from, FontScalablePtr to,
|
|
double *dx, double *dy, double *sdx, double *sdy,
|
|
double *rescale_x)
|
|
{
|
|
double srcpixelset, destpixelset, srcpixel, destpixel;
|
|
|
|
srcpixelset = get_matrix_horizontal_component(from->pixel_matrix);
|
|
destpixelset = get_matrix_horizontal_component(to->pixel_matrix);
|
|
srcpixel = get_matrix_vertical_component(from->pixel_matrix);
|
|
destpixel = get_matrix_vertical_component(to->pixel_matrix);
|
|
|
|
if (srcpixelset >= EPS)
|
|
{
|
|
*dx = destpixelset / srcpixelset;
|
|
*sdx = 1000.0 / srcpixelset;
|
|
}
|
|
else
|
|
*sdx = *dx = 0;
|
|
|
|
*rescale_x = 1.0;
|
|
|
|
/* If client specified a width, it overrides setsize; in this
|
|
context, we interpret width as applying to the font before any
|
|
rotation, even though that's not what is ultimately returned in
|
|
the width field. */
|
|
if (from->width > 0 && to->width > 0 && fabs(*dx) > EPS)
|
|
{
|
|
double rescale = (double)to->width / (double)from->width;
|
|
|
|
/* If the client specified a transformation matrix, the rescaling
|
|
for width does *not* override the setsize. Instead, just check
|
|
for consistency between the setsize from the matrix and the
|
|
setsize that would result from rescaling according to the width.
|
|
This assumes (perhaps naively) that the width is correctly
|
|
reported in the name. As an interesting side effect, this test
|
|
may result in choosing a different source bitmap (one that
|
|
scales consistently between the setsize *and* the width) than it
|
|
would choose if a width were not specified. Sort of a hidden
|
|
multiple-master functionality. */
|
|
if ((to->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
|
|
(to->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY)
|
|
{
|
|
/* Reject if resulting width difference is >= 1 pixel */
|
|
if (fabs(rescale * from->width - *dx * from->width) >= 10)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
*rescale_x = rescale/(*dx);
|
|
*dx = rescale;
|
|
}
|
|
}
|
|
|
|
if (srcpixel >= EPS)
|
|
{
|
|
*dy = destpixel / srcpixel;
|
|
*sdy = 1000.0 / srcpixel;
|
|
}
|
|
else
|
|
*sdy = *dy = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* favor enlargement over reduction because of aliasing resulting
|
|
from reduction */
|
|
#define SCORE(m,s) \
|
|
if (m >= 1.0) { \
|
|
if (m == 1.0) \
|
|
score += (16 * s); \
|
|
else if (m == 2.0) \
|
|
score += (4 * s); \
|
|
else \
|
|
score += (int)(((double)(3 * s)) / m); \
|
|
} else { \
|
|
score += (int)(((double)(2 * s)) * m); \
|
|
}
|
|
|
|
/* don't need to favor enlargement when looking for bitmap that can
|
|
be used unscalable */
|
|
#define SCORE2(m,s) \
|
|
if (m >= 1.0) \
|
|
score += (int)(((double)(8 * s)) / m); \
|
|
else \
|
|
score += (int)(((double)(8 * s)) * m);
|
|
|
|
static FontEntryPtr
|
|
FindBestToScale(FontPathElementPtr fpe, FontEntryPtr entry,
|
|
FontScalablePtr vals, FontScalablePtr best,
|
|
double *dxp, double *dyp,
|
|
double *sdxp, double *sdyp,
|
|
FontPathElementPtr *fpep)
|
|
{
|
|
FontScalableRec temp;
|
|
int source, i;
|
|
int best_score, best_unscaled_score,
|
|
score;
|
|
double dx = 0.0, sdx = 0.0, dx_amount = 0.0,
|
|
dy = 0.0, sdy = 0.0, dy_amount = 0.0,
|
|
best_dx = 0.0, best_sdx = 0.0, best_dx_amount = 0.0,
|
|
best_dy = 0.0, best_sdy = 0.0, best_dy_amount = 0.0,
|
|
best_unscaled_sdx = 0.0, best_unscaled_sdy = 0.0,
|
|
rescale_x = 0.0, best_rescale_x = 0.0,
|
|
best_unscaled_rescale_x = 0.0;
|
|
FontEntryPtr zero;
|
|
FontNameRec zeroName;
|
|
char zeroChars[MAXFONTNAMELEN];
|
|
FontDirectoryPtr dir;
|
|
FontScaledPtr scaled;
|
|
FontScalableExtraPtr extra;
|
|
FontScaledPtr best_scaled, best_unscaled;
|
|
FontPathElementPtr best_fpe = NULL, best_unscaled_fpe = NULL;
|
|
FontEntryPtr bitmap = NULL;
|
|
FontEntryPtr result;
|
|
int aliascount = 20;
|
|
FontPathElementPtr bitmap_fpe = NULL;
|
|
FontNameRec xlfdName;
|
|
|
|
/* find the best match */
|
|
rescale_x = 1.0;
|
|
best_scaled = 0;
|
|
best_score = 0;
|
|
best_unscaled = 0;
|
|
best_unscaled_score = -1;
|
|
best_dx_amount = best_dy_amount = HUGE_VAL;
|
|
memcpy (zeroChars, entry->name.name, entry->name.length);
|
|
zeroChars[entry->name.length] = '\0';
|
|
zeroName.name = zeroChars;
|
|
FontParseXLFDName (zeroChars, &temp, FONT_XLFD_REPLACE_ZERO);
|
|
zeroName.length = strlen (zeroChars);
|
|
zeroName.ndashes = entry->name.ndashes;
|
|
xlfdName.name = vals->xlfdName;
|
|
xlfdName.length = strlen(xlfdName.name);
|
|
xlfdName.ndashes = FontFileCountDashes(xlfdName.name, xlfdName.length);
|
|
restart_bestscale_loop: ;
|
|
/*
|
|
* Look through all the registered bitmap sources for
|
|
* the same zero name as ours; entries along that one
|
|
* can be scaled as desired.
|
|
*/
|
|
for (source = 0; source < FontFileBitmapSources.count; source++)
|
|
{
|
|
/* There might already be a bitmap that satisfies the request
|
|
but didn't have a zero name that was found by the scalable
|
|
font matching logic. Keep track if there is. */
|
|
if (bitmap == NULL && vals->xlfdName != NULL)
|
|
{
|
|
bitmap_fpe = FontFileBitmapSources.fpe[source];
|
|
dir = (FontDirectoryPtr) bitmap_fpe->private;
|
|
bitmap = FontFileFindNameInDir (&dir->nonScalable, &xlfdName);
|
|
if (bitmap && bitmap->type != FONT_ENTRY_BITMAP)
|
|
{
|
|
if (bitmap->type == FONT_ENTRY_ALIAS && aliascount > 0)
|
|
{
|
|
aliascount--;
|
|
xlfdName.name = bitmap->u.alias.resolved;
|
|
xlfdName.length = strlen(xlfdName.name);
|
|
xlfdName.ndashes = FontFileCountDashes(xlfdName.name,
|
|
xlfdName.length);
|
|
bitmap = NULL;
|
|
goto restart_bestscale_loop;
|
|
}
|
|
else
|
|
bitmap = NULL;
|
|
}
|
|
}
|
|
|
|
if (FontFileBitmapSources.fpe[source] == fpe)
|
|
zero = entry;
|
|
else
|
|
{
|
|
dir = (FontDirectoryPtr) FontFileBitmapSources.fpe[source]->private;
|
|
zero = FontFileFindNameInDir (&dir->scalable, &zeroName);
|
|
if (!zero)
|
|
continue;
|
|
}
|
|
extra = zero->u.scalable.extra;
|
|
for (i = 0; i < extra->numScaled; i++)
|
|
{
|
|
scaled = &extra->scaled[i];
|
|
if (!scaled->bitmap)
|
|
continue;
|
|
if (!ComputeScaleFactors(&scaled->vals, vals, &dx, &dy, &sdx, &sdy,
|
|
&rescale_x))
|
|
continue;
|
|
score = 0;
|
|
dx_amount = dx;
|
|
dy_amount = dy;
|
|
SCORE(dy_amount, 10);
|
|
SCORE(dx_amount, 1);
|
|
if ((score > best_score) ||
|
|
((score == best_score) &&
|
|
((dy_amount < best_dy_amount) ||
|
|
((dy_amount == best_dy_amount) &&
|
|
(dx_amount < best_dx_amount)))))
|
|
{
|
|
best_fpe = FontFileBitmapSources.fpe[source];
|
|
best_scaled = scaled;
|
|
best_score = score;
|
|
best_dx = dx;
|
|
best_dy = dy;
|
|
best_sdx = sdx;
|
|
best_sdy = sdy;
|
|
best_dx_amount = dx_amount;
|
|
best_dy_amount = dy_amount;
|
|
best_rescale_x = rescale_x;
|
|
}
|
|
/* Is this font a candidate for use without ugly rescaling? */
|
|
if (fabs(dx) > EPS && fabs(dy) > EPS &&
|
|
fabs(vals->pixel_matrix[0] * rescale_x -
|
|
scaled->vals.pixel_matrix[0]) < 1 &&
|
|
fabs(vals->pixel_matrix[1] * rescale_x -
|
|
scaled->vals.pixel_matrix[1]) < EPS &&
|
|
fabs(vals->pixel_matrix[2] -
|
|
scaled->vals.pixel_matrix[2]) < EPS &&
|
|
fabs(vals->pixel_matrix[3] -
|
|
scaled->vals.pixel_matrix[3]) < 1)
|
|
{
|
|
/* Yes. The pixel sizes are close on the diagonal and
|
|
extremely close off the diagonal. */
|
|
score = 0;
|
|
SCORE2(vals->pixel_matrix[3] /
|
|
scaled->vals.pixel_matrix[3], 10);
|
|
SCORE2(vals->pixel_matrix[0] * rescale_x /
|
|
scaled->vals.pixel_matrix[0], 1);
|
|
if (score > best_unscaled_score)
|
|
{
|
|
best_unscaled_fpe = FontFileBitmapSources.fpe[source];
|
|
best_unscaled = scaled;
|
|
best_unscaled_sdx = sdx / dx;
|
|
best_unscaled_sdy = sdy / dy;
|
|
best_unscaled_score = score;
|
|
best_unscaled_rescale_x = rescale_x;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (best_unscaled)
|
|
{
|
|
*best = best_unscaled->vals;
|
|
*fpep = best_unscaled_fpe;
|
|
*dxp = 1.0;
|
|
*dyp = 1.0;
|
|
*sdxp = best_unscaled_sdx;
|
|
*sdyp = best_unscaled_sdy;
|
|
rescale_x = best_unscaled_rescale_x;
|
|
result = best_unscaled->bitmap;
|
|
}
|
|
else if (best_scaled)
|
|
{
|
|
*best = best_scaled->vals;
|
|
*fpep = best_fpe;
|
|
*dxp = best_dx;
|
|
*dyp = best_dy;
|
|
*sdxp = best_sdx;
|
|
*sdyp = best_sdy;
|
|
rescale_x = best_rescale_x;
|
|
result = best_scaled->bitmap;
|
|
}
|
|
else
|
|
result = NULL;
|
|
|
|
if (bitmap != NULL && (result == NULL || *dxp != 1.0 || *dyp != 1.0))
|
|
{
|
|
*fpep = bitmap_fpe;
|
|
FontParseXLFDName (bitmap->name.name, best, FONT_XLFD_REPLACE_NONE);
|
|
if (ComputeScaleFactors(best, best, dxp, dyp, sdxp, sdyp, &rescale_x))
|
|
result = bitmap;
|
|
else
|
|
result = NULL;
|
|
}
|
|
|
|
if (result && rescale_x != 1.0)
|
|
{
|
|
/* We have rescaled horizontally due to an XLFD width field. Change
|
|
the matrix appropriately */
|
|
vals->pixel_matrix[0] *= rescale_x;
|
|
vals->pixel_matrix[1] *= rescale_x;
|
|
#ifdef NOTDEF
|
|
/* This would force the pointsize and pixelsize fields in the
|
|
FONT property to display as matrices to more accurately
|
|
report the font being supplied. It might also break existing
|
|
applications that expect a single number in that field. */
|
|
vals->values_supplied =
|
|
vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) |
|
|
PIXELSIZE_ARRAY;
|
|
#else /* NOTDEF */
|
|
vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK;
|
|
#endif /* NOTDEF */
|
|
/* Recompute and reround the FontScalablePtr values after
|
|
rescaling for the new width. */
|
|
FontFileCompleteXLFD(vals, vals);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static FontEntryPtr
|
|
FindPmfToScale(FontPathElementPtr fpe, FontEntryPtr entry,
|
|
FontScalablePtr vals, FontScalablePtr best,
|
|
double *dxp, double *dyp,
|
|
double *sdxp, double *sdyp,
|
|
FontPathElementPtr *fpep)
|
|
{
|
|
FontEntryPtr result = NULL;
|
|
FontScaledPtr scaled;
|
|
FontScalableExtraPtr extra;
|
|
int i;
|
|
|
|
extra = entry->u.scalable.extra;
|
|
for (i = 0; i < extra->numScaled; i++)
|
|
{
|
|
double rescale_x;
|
|
|
|
scaled = &extra->scaled[i];
|
|
if (!scaled->bitmap)
|
|
continue;
|
|
if (!ComputeScaleFactors(&scaled->vals, vals, dxp, dyp, sdxp, sdyp,
|
|
&rescale_x))
|
|
continue;
|
|
*best = scaled->vals;
|
|
*fpep = fpe;
|
|
result = scaled->bitmap;
|
|
if (rescale_x != 1.0)
|
|
{
|
|
/* We have rescaled horizontally due to an XLFD width field. Change
|
|
the matrix appropriately */
|
|
vals->pixel_matrix[0] *= rescale_x;
|
|
vals->pixel_matrix[1] *= rescale_x;
|
|
#ifdef NOTDEF
|
|
/* This would force the pointsize and pixelsize fields in the
|
|
FONT property to display as matrices to more accurately
|
|
report the font being supplied. It might also break existing
|
|
applications that expect a single number in that field. */
|
|
vals->values_supplied =
|
|
vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) |
|
|
PIXELSIZE_ARRAY;
|
|
#else /* NOTDEF */
|
|
vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK;
|
|
#endif /* NOTDEF */
|
|
/* Recompute and reround the FontScalablePtr values after
|
|
rescaling for the new width. */
|
|
FontFileCompleteXLFD(vals, vals);
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static long
|
|
doround(double x)
|
|
{
|
|
return (x >= 0) ? (long)(x + .5) : (long)(x - .5);
|
|
}
|
|
|
|
static int
|
|
computeProps(FontPropPtr pf, char *wasStringProp,
|
|
FontPropPtr npf, char *isStringProp,
|
|
unsigned int nprops, double xfactor, double yfactor,
|
|
double sXfactor, double sYfactor)
|
|
{
|
|
int n;
|
|
int count;
|
|
fontProp *t;
|
|
double rawfactor = 0.0;
|
|
|
|
for (count = 0; nprops > 0; nprops--, pf++, wasStringProp++) {
|
|
n = sizeof(fontPropTable) / sizeof(fontProp);
|
|
for (t = fontPropTable; n && (t->atom != pf->name); n--, t++);
|
|
if (!n)
|
|
continue;
|
|
|
|
switch (t->type) {
|
|
case scaledX:
|
|
npf->value = doround(xfactor * (double)pf->value);
|
|
rawfactor = sXfactor;
|
|
break;
|
|
case scaledY:
|
|
npf->value = doround(yfactor * (double)pf->value);
|
|
rawfactor = sYfactor;
|
|
break;
|
|
case unscaled:
|
|
npf->value = pf->value;
|
|
npf->name = pf->name;
|
|
npf++;
|
|
count++;
|
|
*isStringProp++ = *wasStringProp;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (t->type != unscaled)
|
|
{
|
|
npf->name = pf->name;
|
|
npf++;
|
|
count++;
|
|
npf->value = doround(rawfactor * (double)pf->value);
|
|
npf->name = rawFontPropTable[t - fontPropTable].atom;
|
|
npf++;
|
|
count++;
|
|
*isStringProp++ = *wasStringProp;
|
|
*isStringProp++ = *wasStringProp;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
static int
|
|
ComputeScaledProperties(FontInfoPtr sourceFontInfo, /* the font to be scaled */
|
|
char *name, /* name of resulting font */
|
|
FontScalablePtr vals,
|
|
double dx, double dy, /* scale factors in x and y */
|
|
double sdx, double sdy, /* directions */
|
|
long sWidth, /* 1000-pixel average width */
|
|
FontPropPtr *pProps, /* returns properties;
|
|
preallocated */
|
|
char **pIsStringProp) /* return booleans;
|
|
preallocated */
|
|
{
|
|
int n;
|
|
char *ptr1 = NULL, *ptr2 = NULL;
|
|
char *ptr3;
|
|
FontPropPtr fp;
|
|
fontProp *fpt;
|
|
char *isStringProp;
|
|
int nProps;
|
|
|
|
if (bitscaleGeneration != serverGeneration) {
|
|
initFontPropTable();
|
|
bitscaleGeneration = serverGeneration;
|
|
}
|
|
nProps = NPROPS + 1 + sizeof(fontPropTable) / sizeof(fontProp) +
|
|
sizeof(rawFontPropTable) / sizeof(fontProp);
|
|
fp = (FontPropPtr) xalloc(sizeof(FontPropRec) * nProps);
|
|
*pProps = fp;
|
|
if (!fp) {
|
|
fprintf(stderr, "Error: Couldn't allocate font properties (%ld*%d)\n",
|
|
(unsigned long)sizeof(FontPropRec), nProps);
|
|
return 1;
|
|
}
|
|
isStringProp = (char *) xalloc (nProps);
|
|
*pIsStringProp = isStringProp;
|
|
if (!isStringProp)
|
|
{
|
|
fprintf(stderr, "Error: Couldn't allocate isStringProp (%d)\n", nProps);
|
|
xfree (fp);
|
|
return 1;
|
|
}
|
|
ptr2 = name;
|
|
for (fpt = fontNamePropTable, n = NPROPS;
|
|
n;
|
|
fp++, fpt++, n--, isStringProp++)
|
|
{
|
|
|
|
if (*ptr2)
|
|
{
|
|
ptr1 = ptr2 + 1;
|
|
if (!(ptr2 = strchr(ptr1, '-'))) ptr2 = strchr(ptr1, '\0');
|
|
}
|
|
|
|
*isStringProp = 0;
|
|
switch (fpt->type) {
|
|
case atom:
|
|
fp->value = MakeAtom(ptr1, ptr2 - ptr1, TRUE);
|
|
*isStringProp = 1;
|
|
break;
|
|
case truncate_atom:
|
|
for (ptr3 = ptr1; *ptr3; ptr3++)
|
|
if (*ptr3 == '[')
|
|
break;
|
|
if (!*ptr3) ptr3 = ptr2;
|
|
fp->value = MakeAtom(ptr1, ptr3 - ptr1, TRUE);
|
|
*isStringProp = 1;
|
|
break;
|
|
case pixel_size:
|
|
fp->value = doround(vals->pixel_matrix[3]);
|
|
break;
|
|
case point_size:
|
|
fp->value = doround(vals->point_matrix[3] * 10.0);
|
|
break;
|
|
case resolution_x:
|
|
fp->value = vals->x;
|
|
break;
|
|
case resolution_y:
|
|
fp->value = vals->y;
|
|
break;
|
|
case average_width:
|
|
fp->value = vals->width;
|
|
break;
|
|
case fontname:
|
|
fp->value = MakeAtom(name, strlen(name), TRUE);
|
|
*isStringProp = 1;
|
|
break;
|
|
case raw_ascent:
|
|
fp->value = sourceFontInfo->fontAscent * sdy;
|
|
break;
|
|
case raw_descent:
|
|
fp->value = sourceFontInfo->fontDescent * sdy;
|
|
break;
|
|
case raw_pointsize:
|
|
fp->value = (long)(72270.0 / (double)vals->y + .5);
|
|
break;
|
|
case raw_pixelsize:
|
|
fp->value = 1000;
|
|
break;
|
|
case raw_average_width:
|
|
fp->value = sWidth;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
fp->name = fpt->atom;
|
|
}
|
|
n = NPROPS;
|
|
n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp,
|
|
fp, isStringProp, sourceFontInfo->nprops, dx, dy,
|
|
sdx, sdy);
|
|
return n;
|
|
}
|
|
|
|
|
|
static int
|
|
compute_xform_matrix(FontScalablePtr vals, double dx, double dy,
|
|
double *xform, double *inv_xform,
|
|
double *xmult, double *ymult)
|
|
{
|
|
double det;
|
|
double pixel = get_matrix_vertical_component(vals->pixel_matrix);
|
|
double pixelset = get_matrix_horizontal_component(vals->pixel_matrix);
|
|
|
|
if (pixel < EPS || pixelset < EPS) return 0;
|
|
|
|
/* Initialize the transformation matrix to the scaling factors */
|
|
xform[0] = dx / pixelset;
|
|
xform[1] = xform[2] = 0.0;
|
|
xform[3] = dy / pixel;
|
|
|
|
/* Inline matrix multiply -- somewhat ugly to minimize register usage */
|
|
#define MULTIPLY_XFORM(a,b,c,d) \
|
|
{ \
|
|
register double aa = (a), bb = (b), cc = (c), dd = (d); \
|
|
register double temp; \
|
|
temp = aa * xform[0] + cc * xform[1]; \
|
|
aa = aa * xform[2] + cc * xform[3]; \
|
|
xform[1] = bb * xform[0] + dd * xform[1]; \
|
|
xform[3] = bb * xform[2] + dd * xform[3]; \
|
|
xform[0] = temp; \
|
|
xform[2] = aa; \
|
|
}
|
|
|
|
/* Rescale the transformation matrix for size of source font */
|
|
MULTIPLY_XFORM(vals->pixel_matrix[0],
|
|
vals->pixel_matrix[1],
|
|
vals->pixel_matrix[2],
|
|
vals->pixel_matrix[3]);
|
|
|
|
*xmult = xform[0];
|
|
*ymult = xform[3];
|
|
|
|
|
|
if (inv_xform == NULL) return 1;
|
|
|
|
/* Compute the determinant for use in inverting the matrix. */
|
|
det = xform[0] * xform[3] - xform[1] * xform[2];
|
|
|
|
/* If the determinant is tiny or zero, give up */
|
|
if (fabs(det) < EPS) return 0;
|
|
|
|
/* Compute the inverse */
|
|
inv_xform[0] = xform[3] / det;
|
|
inv_xform[1] = -xform[1] / det;
|
|
inv_xform[2] = -xform[2] / det;
|
|
inv_xform[3] = xform[0] / det;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* ScaleFont
|
|
* returns a pointer to the new scaled font, or NULL (due to AllocError).
|
|
*/
|
|
static FontPtr
|
|
ScaleFont(FontPtr opf, /* originating font */
|
|
double widthMult, /* glyphs width scale factor */
|
|
double heightMult, /* glyphs height scale factor */
|
|
double sWidthMult, /* scalable glyphs width scale factor */
|
|
double sHeightMult, /* scalable glyphs height scale factor */
|
|
FontScalablePtr vals,
|
|
double *newWidthMult, /* return: X component of glyphs width
|
|
scale factor */
|
|
double *newHeightMult, /* return: Y component of glyphs height
|
|
scale factor */
|
|
long *sWidth) /* return: average 1000-pixel width */
|
|
{
|
|
FontPtr pf;
|
|
FontInfoPtr pfi,
|
|
opfi;
|
|
BitmapFontPtr bitmapFont,
|
|
obitmapFont;
|
|
CharInfoPtr pci,
|
|
opci;
|
|
int nchars = 0; /* how many characters in the font */
|
|
int i;
|
|
int firstCol, lastCol, firstRow, lastRow;
|
|
double xform[4], inv_xform[4];
|
|
double xmult, ymult;
|
|
int totalwidth = 0, totalchars = 0;
|
|
#define OLDINDEX(i) (((i)/(lastCol - firstCol + 1) + \
|
|
firstRow - opf->info.firstRow) * \
|
|
(opf->info.lastCol - opf->info.firstCol + 1) + \
|
|
(i)%(lastCol - firstCol + 1) + \
|
|
firstCol - opf->info.firstCol)
|
|
|
|
*sWidth = 0;
|
|
|
|
opfi = &opf->info;
|
|
obitmapFont = (BitmapFontPtr) opf->fontPrivate;
|
|
|
|
bitmapFont = 0;
|
|
if (!(pf = CreateFontRec())) {
|
|
fprintf(stderr, "Error: Couldn't allocate FontRec (%ld)\n",
|
|
(unsigned long)sizeof(FontRec));
|
|
goto bail;
|
|
}
|
|
pf->refcnt = 0;
|
|
pf->bit = opf->bit;
|
|
pf->byte = opf->byte;
|
|
pf->glyph = opf->glyph;
|
|
pf->scan = opf->scan;
|
|
|
|
pf->get_glyphs = bitmapGetGlyphs;
|
|
pf->get_metrics = bitmapGetMetrics;
|
|
pf->unload_font = bitmapUnloadScalable;
|
|
pf->unload_glyphs = NULL;
|
|
|
|
pfi = &pf->info;
|
|
*pfi = *opfi;
|
|
/* If charset subsetting specified in vals, determine what our range
|
|
needs to be for the output font */
|
|
if (vals->nranges)
|
|
{
|
|
int i;
|
|
|
|
pfi->allExist = 0;
|
|
firstCol = 255;
|
|
lastCol = 0;
|
|
firstRow = 255;
|
|
lastRow = 0;
|
|
|
|
for (i = 0; i < vals->nranges; i++)
|
|
{
|
|
if (vals->ranges[i].min_char_high != vals->ranges[i].max_char_high)
|
|
{
|
|
firstCol = opfi->firstCol;
|
|
lastCol = opfi->lastCol;
|
|
}
|
|
if (firstCol > vals->ranges[i].min_char_low)
|
|
firstCol = vals->ranges[i].min_char_low;
|
|
if (lastCol < vals->ranges[i].max_char_low)
|
|
lastCol = vals->ranges[i].max_char_low;
|
|
if (firstRow > vals->ranges[i].min_char_high)
|
|
firstRow = vals->ranges[i].min_char_high;
|
|
if (lastRow < vals->ranges[i].max_char_high)
|
|
lastRow = vals->ranges[i].max_char_high;
|
|
}
|
|
|
|
if (firstCol > lastCol || firstRow > lastRow)
|
|
goto bail;
|
|
|
|
if (firstCol < opfi->firstCol)
|
|
firstCol = opfi->firstCol;
|
|
if (lastCol > opfi->lastCol)
|
|
lastCol = opfi->lastCol;
|
|
if (firstRow < opfi->firstRow)
|
|
firstRow = opfi->firstRow;
|
|
if (lastRow > opfi->lastRow)
|
|
lastRow = opfi->lastRow;
|
|
}
|
|
else
|
|
{
|
|
firstCol = opfi->firstCol;
|
|
lastCol = opfi->lastCol;
|
|
firstRow = opfi->firstRow;
|
|
lastRow = opfi->lastRow;
|
|
}
|
|
|
|
bitmapFont = (BitmapFontPtr) xalloc(sizeof(BitmapFontRec));
|
|
if (!bitmapFont) {
|
|
fprintf(stderr, "Error: Couldn't allocate bitmapFont (%ld)\n",
|
|
(unsigned long)sizeof(BitmapFontRec));
|
|
goto bail;
|
|
}
|
|
nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
|
|
pfi->firstRow = firstRow;
|
|
pfi->lastRow = lastRow;
|
|
pfi->firstCol = firstCol;
|
|
pfi->lastCol = lastCol;
|
|
pf->fontPrivate = (pointer) bitmapFont;
|
|
bitmapFont->version_num = obitmapFont->version_num;
|
|
bitmapFont->num_chars = nchars;
|
|
bitmapFont->num_tables = obitmapFont->num_tables;
|
|
bitmapFont->metrics = 0;
|
|
bitmapFont->ink_metrics = 0;
|
|
bitmapFont->bitmaps = 0;
|
|
bitmapFont->encoding = 0;
|
|
bitmapFont->bitmapExtra = 0;
|
|
bitmapFont->pDefault = 0;
|
|
bitmapFont->metrics = (CharInfoPtr) xalloc(nchars * sizeof(CharInfoRec));
|
|
if (!bitmapFont->metrics) {
|
|
fprintf(stderr, "Error: Couldn't allocate metrics (%d*%ld)\n",
|
|
nchars, (unsigned long)sizeof(CharInfoRec));
|
|
goto bail;
|
|
}
|
|
bitmapFont->encoding =
|
|
(CharInfoPtr **) xcalloc(NUM_SEGMENTS(nchars),
|
|
sizeof(CharInfoPtr*));
|
|
if (!bitmapFont->encoding) {
|
|
fprintf(stderr, "Error: Couldn't allocate encoding (%d*%ld)\n",
|
|
nchars, (unsigned long)sizeof(CharInfoPtr));
|
|
goto bail;
|
|
}
|
|
|
|
#undef MAXSHORT
|
|
#define MAXSHORT 32767
|
|
#undef MINSHORT
|
|
#define MINSHORT -32768
|
|
|
|
pfi->anamorphic = FALSE;
|
|
if (heightMult != widthMult)
|
|
pfi->anamorphic = TRUE;
|
|
pfi->cachable = TRUE;
|
|
|
|
if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
|
|
inv_xform, &xmult, &ymult))
|
|
goto bail;
|
|
|
|
pfi->fontAscent = opfi->fontAscent * ymult;
|
|
pfi->fontDescent = opfi->fontDescent * ymult;
|
|
|
|
pfi->minbounds.leftSideBearing = MAXSHORT;
|
|
pfi->minbounds.rightSideBearing = MAXSHORT;
|
|
pfi->minbounds.ascent = MAXSHORT;
|
|
pfi->minbounds.descent = MAXSHORT;
|
|
pfi->minbounds.characterWidth = MAXSHORT;
|
|
pfi->minbounds.attributes = MAXSHORT;
|
|
|
|
pfi->maxbounds.leftSideBearing = MINSHORT;
|
|
pfi->maxbounds.rightSideBearing = MINSHORT;
|
|
pfi->maxbounds.ascent = MINSHORT;
|
|
pfi->maxbounds.descent = MINSHORT;
|
|
pfi->maxbounds.characterWidth = MINSHORT;
|
|
pfi->maxbounds.attributes = MINSHORT;
|
|
|
|
/* Compute the transformation and inverse transformation matrices.
|
|
Can fail if the determinant is zero. */
|
|
|
|
pci = bitmapFont->metrics;
|
|
for (i = 0; i < nchars; i++)
|
|
{
|
|
if ((opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i))))
|
|
{
|
|
double newlsb, newrsb, newdesc, newasc, point[2];
|
|
|
|
#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))
|
|
#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8))
|
|
|
|
if (vals->nranges)
|
|
{
|
|
int row = i / (lastCol - firstCol + 1) + firstRow;
|
|
int col = i % (lastCol - firstCol + 1) + firstCol;
|
|
int ch = (row << 8) + col;
|
|
int j;
|
|
for (j = 0; j < vals->nranges; j++)
|
|
if (ch >= minchar(vals->ranges[j]) &&
|
|
ch <= maxchar(vals->ranges[j]))
|
|
break;
|
|
if (j == vals->nranges)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (opci->metrics.leftSideBearing == 0 &&
|
|
opci->metrics.rightSideBearing == 0 &&
|
|
opci->metrics.ascent == 0 &&
|
|
opci->metrics.descent == 0 &&
|
|
opci->metrics.characterWidth == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) {
|
|
bitmapFont->encoding[SEGMENT_MAJOR(i)]=
|
|
(CharInfoPtr*)xcalloc(BITMAP_FONT_SEGMENT_SIZE,
|
|
sizeof(CharInfoPtr));
|
|
if(!bitmapFont->encoding[SEGMENT_MAJOR(i)])
|
|
goto bail;
|
|
}
|
|
ACCESSENCODINGL(bitmapFont->encoding, i) = pci;
|
|
|
|
/* Compute new extents for this glyph */
|
|
TRANSFORM_POINT(xform,
|
|
opci->metrics.leftSideBearing,
|
|
-opci->metrics.descent,
|
|
point);
|
|
newlsb = point[0];
|
|
newrsb = newlsb;
|
|
newdesc = -point[1];
|
|
newasc = -newdesc;
|
|
TRANSFORM_POINT(xform,
|
|
opci->metrics.leftSideBearing,
|
|
opci->metrics.ascent,
|
|
point);
|
|
CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
|
|
TRANSFORM_POINT(xform,
|
|
opci->metrics.rightSideBearing,
|
|
-opci->metrics.descent,
|
|
point);
|
|
CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
|
|
TRANSFORM_POINT(xform,
|
|
opci->metrics.rightSideBearing,
|
|
opci->metrics.ascent,
|
|
point);
|
|
CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
|
|
|
|
pci->metrics.leftSideBearing = (int)floor(newlsb);
|
|
pci->metrics.rightSideBearing = (int)floor(newrsb + .5);
|
|
pci->metrics.descent = (int)ceil(newdesc);
|
|
pci->metrics.ascent = (int)floor(newasc + .5);
|
|
/* Accumulate total width of characters before transformation,
|
|
to ascertain predominant direction of font. */
|
|
totalwidth += opci->metrics.characterWidth;
|
|
pci->metrics.characterWidth =
|
|
doround((double)opci->metrics.characterWidth * xmult);
|
|
pci->metrics.attributes =
|
|
doround((double)opci->metrics.characterWidth * sWidthMult);
|
|
if (!pci->metrics.characterWidth)
|
|
{
|
|
/* Since transformation may shrink width, height, and
|
|
escapement to zero, make sure existing characters
|
|
are not mistaken for undefined characters. */
|
|
|
|
if (pci->metrics.rightSideBearing ==
|
|
pci->metrics.leftSideBearing)
|
|
pci->metrics.rightSideBearing++;
|
|
if (pci->metrics.ascent == -pci->metrics.descent)
|
|
pci->metrics.ascent++;
|
|
}
|
|
|
|
pci++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* For each character, set the per-character metrics, scale the glyph, and
|
|
* check per-font minbounds and maxbounds character information.
|
|
*/
|
|
|
|
pci = bitmapFont->metrics;
|
|
for (i = 0; i < nchars; i++)
|
|
{
|
|
if ((pci = ACCESSENCODING(bitmapFont->encoding,i)) &&
|
|
(opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i))))
|
|
{
|
|
totalchars++;
|
|
*sWidth += abs((int)(INT16)pci->metrics.attributes);
|
|
#define MINMAX(field) \
|
|
if (pfi->minbounds.field > pci->metrics.field) \
|
|
pfi->minbounds.field = pci->metrics.field; \
|
|
if (pfi->maxbounds.field < pci->metrics.field) \
|
|
pfi->maxbounds.field = pci->metrics.field
|
|
|
|
MINMAX(leftSideBearing);
|
|
MINMAX(rightSideBearing);
|
|
MINMAX(ascent);
|
|
MINMAX(descent);
|
|
MINMAX(characterWidth);
|
|
|
|
/* Hack: Cast attributes into a signed quantity. Tread lightly
|
|
for now and don't go changing the global Xproto.h file */
|
|
if ((INT16)pfi->minbounds.attributes >
|
|
(INT16)pci->metrics.attributes)
|
|
pfi->minbounds.attributes = pci->metrics.attributes;
|
|
if ((INT16)pfi->maxbounds.attributes <
|
|
(INT16)pci->metrics.attributes)
|
|
pfi->maxbounds.attributes = pci->metrics.attributes;
|
|
#undef MINMAX
|
|
}
|
|
}
|
|
pfi->ink_minbounds = pfi->minbounds;
|
|
pfi->ink_maxbounds = pfi->maxbounds;
|
|
if (totalchars)
|
|
{
|
|
*sWidth = (*sWidth * 10 + totalchars / 2) / totalchars;
|
|
if (totalwidth < 0)
|
|
{
|
|
/* Dominant direction is R->L */
|
|
*sWidth = -*sWidth;
|
|
}
|
|
|
|
if (pfi->minbounds.characterWidth == pfi->maxbounds.characterWidth)
|
|
vals->width = pfi->minbounds.characterWidth * 10;
|
|
else
|
|
vals->width = doround((double)*sWidth * vals->pixel_matrix[0] /
|
|
1000.0);
|
|
}
|
|
else
|
|
{
|
|
vals->width = 0;
|
|
*sWidth = 0;
|
|
}
|
|
FontComputeInfoAccelerators (pfi);
|
|
|
|
if (pfi->defaultCh != (unsigned short) NO_SUCH_CHAR) {
|
|
unsigned int r,
|
|
c,
|
|
cols;
|
|
|
|
r = pfi->defaultCh >> 8;
|
|
c = pfi->defaultCh & 0xFF;
|
|
if (pfi->firstRow <= r && r <= pfi->lastRow &&
|
|
pfi->firstCol <= c && c <= pfi->lastCol) {
|
|
cols = pfi->lastCol - pfi->firstCol + 1;
|
|
r = r - pfi->firstRow;
|
|
c = c - pfi->firstCol;
|
|
bitmapFont->pDefault =
|
|
ACCESSENCODING(bitmapFont->encoding, r * cols + c);
|
|
}
|
|
}
|
|
|
|
*newWidthMult = xmult;
|
|
*newHeightMult = ymult;
|
|
return pf;
|
|
bail:
|
|
if (pf)
|
|
xfree(pf);
|
|
if (bitmapFont) {
|
|
xfree(bitmapFont->metrics);
|
|
xfree(bitmapFont->ink_metrics);
|
|
xfree(bitmapFont->bitmaps);
|
|
if(bitmapFont->encoding)
|
|
for(i=0; i<NUM_SEGMENTS(nchars); i++)
|
|
xfree(bitmapFont->encoding[i]);
|
|
xfree(bitmapFont->encoding);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
ScaleBitmap(FontPtr pFont, CharInfoPtr opci, CharInfoPtr pci,
|
|
double *inv_xform, double widthMult, double heightMult)
|
|
{
|
|
register char *bitmap, /* The bits */
|
|
*newBitmap;
|
|
register int bpr, /* Padding information */
|
|
newBpr;
|
|
int width, /* Extents information */
|
|
height,
|
|
newWidth,
|
|
newHeight;
|
|
register int row, /* Loop variables */
|
|
col;
|
|
INT32 deltaX, /* Increments for resampling loop */
|
|
deltaY;
|
|
INT32 xValue, /* Subscripts for resampling loop */
|
|
yValue;
|
|
double point[2];
|
|
unsigned char *char_grayscale = 0;
|
|
INT32 *diffusion_workspace = NULL, *thisrow = NULL,
|
|
*nextrow = NULL, pixmult = 0;
|
|
int box_x = 0, box_y = 0;
|
|
|
|
static unsigned char masklsb[] =
|
|
{ 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
|
|
static unsigned char maskmsb[] =
|
|
{ 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
|
|
unsigned char *mask = (pFont->bit == LSBFirst ? masklsb : maskmsb);
|
|
|
|
|
|
bitmap = opci->bits;
|
|
newBitmap = pci->bits;
|
|
width = GLYPHWIDTHPIXELS(opci);
|
|
height = GLYPHHEIGHTPIXELS(opci);
|
|
newWidth = GLYPHWIDTHPIXELS(pci);
|
|
newHeight = GLYPHHEIGHTPIXELS(pci);
|
|
if (!newWidth || !newHeight || !width || !height)
|
|
return;
|
|
|
|
bpr = BYTES_PER_ROW(width, pFont->glyph);
|
|
newBpr = BYTES_PER_ROW(newWidth, pFont->glyph);
|
|
|
|
if (widthMult > 0.0 && heightMult > 0.0 &&
|
|
(widthMult < 1.0 || heightMult < 1.0))
|
|
{
|
|
/* We are reducing in one or both dimensions. In an attempt to
|
|
reduce aliasing, we'll antialias by passing the original
|
|
glyph through a low-pass box filter (which results in a
|
|
grayscale image), then use error diffusion to create bitonal
|
|
output in the resampling loop. */
|
|
|
|
/* First compute the sizes of the box filter */
|
|
widthMult = ceil(1.0 / widthMult);
|
|
heightMult = ceil(1.0 / heightMult);
|
|
box_x = width / 2;
|
|
box_y = height / 2;
|
|
if (widthMult < (double)box_x) box_x = (int)widthMult;
|
|
if (heightMult < (double)box_y) box_y = (int)heightMult;
|
|
/* The pixmult value (below) is used to darken the image before
|
|
we perform error diffusion: a necessary concession to the
|
|
fact that it's very difficult to generate readable halftoned
|
|
glyphs. The degree of darkening is proportional to the size
|
|
of the blurring filter, hence inversely proportional to the
|
|
darkness of the lightest gray that results from antialiasing.
|
|
The result is that characters that exercise this logic (those
|
|
generated by reducing from a larger source font) tend to err
|
|
on the side of being too bold instead of being too light to
|
|
be readable. */
|
|
pixmult = box_x * box_y * 192;
|
|
|
|
if (box_x > 1 || box_y > 1)
|
|
{
|
|
/* Looks like we need to anti-alias. Create a workspace to
|
|
contain the grayscale character plus an additional row and
|
|
column for scratch */
|
|
char_grayscale =
|
|
(unsigned char *)xalloc((width + 1) * (height + 1));
|
|
if (char_grayscale)
|
|
{
|
|
diffusion_workspace =
|
|
(INT32 *)xalloc((newWidth + 2) * 2 * sizeof(int));
|
|
if (!diffusion_workspace)
|
|
{
|
|
fprintf(stderr, "Warning: Couldn't allocate diffusion"
|
|
" workspace (%ld)\n",
|
|
(newWidth + 2) * 2 * (unsigned long)sizeof(int));
|
|
xfree(char_grayscale);
|
|
char_grayscale = (unsigned char *)0;
|
|
}
|
|
/* Initialize our error diffusion workspace for later use */
|
|
bzero((char *)diffusion_workspace + sizeof(INT32),
|
|
(newWidth + 3) * sizeof(int));
|
|
thisrow = diffusion_workspace + 1;
|
|
nextrow = diffusion_workspace + newWidth + 3;
|
|
} else {
|
|
fprintf(stderr, "Warning: Couldn't allocate character grayscale (%d)\n", (width + 1) * (height + 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (char_grayscale)
|
|
{
|
|
/* We will be doing antialiasing. First copy the bitmap into
|
|
our buffer, mapping input range [0,1] to output range
|
|
[0,255]. */
|
|
register unsigned char *srcptr, *dstptr;
|
|
srcptr = (unsigned char *)bitmap;
|
|
dstptr = char_grayscale;
|
|
for (row = 0; row < height; row++)
|
|
{
|
|
for (col = 0; col < width; col++)
|
|
*dstptr++ = (srcptr[col >> 3] & mask[col & 0x7]) ? 255 : 0;
|
|
srcptr += bpr; /* On to next row of source */
|
|
dstptr++; /* Skip scratch column in dest */
|
|
}
|
|
if (box_x > 1)
|
|
{
|
|
/* Our box filter has a width > 1... let's filter the rows */
|
|
|
|
int right_width = box_x / 2;
|
|
int left_width = box_x - right_width - 1;
|
|
|
|
for (row = 0; row < height; row++)
|
|
{
|
|
int sum = 0;
|
|
int left_size = 0, right_size = 0;
|
|
|
|
srcptr = char_grayscale + (width + 1) * row;
|
|
dstptr = char_grayscale + (width + 1) * height; /* scratch */
|
|
|
|
/* We've computed the shape of our full box filter. Now
|
|
compute the right-hand part of the moving sum */
|
|
for (right_size = 0; right_size < right_width; right_size++)
|
|
sum += srcptr[right_size];
|
|
|
|
/* Now start moving the sum, growing the box filter, and
|
|
dropping averages into our scratch buffer */
|
|
for (left_size = 0; left_size < left_width; left_size++)
|
|
{
|
|
sum += srcptr[right_width];
|
|
*dstptr++ = sum / (left_size + right_width + 1);
|
|
srcptr++;
|
|
}
|
|
|
|
/* The box filter has reached full width... continue
|
|
computation of moving average until the right side
|
|
hits the wall. */
|
|
for (col = left_size; col + right_size < width; col++)
|
|
{
|
|
sum += srcptr[right_width];
|
|
*dstptr++ = sum / box_x;
|
|
sum -= srcptr[-left_width];
|
|
srcptr++;
|
|
}
|
|
|
|
/* Collapse the right side of the box filter */
|
|
for (; right_size > 0; right_size--)
|
|
{
|
|
*dstptr++ = sum / (left_width + right_size);
|
|
sum -= srcptr[-left_width];
|
|
srcptr++;
|
|
}
|
|
|
|
/* Done with the row... copy dest back over source */
|
|
memmove(char_grayscale + (width + 1) * row,
|
|
char_grayscale + (width + 1) * height,
|
|
width);
|
|
}
|
|
}
|
|
if (box_y > 1)
|
|
{
|
|
/* Our box filter has a height > 1... let's filter the columns */
|
|
|
|
int bottom_height = box_y / 2;
|
|
int top_height = box_y - bottom_height - 1;
|
|
|
|
for (col = 0; col < width; col++)
|
|
{
|
|
int sum = 0;
|
|
int top_size = 0, bottom_size = 0;
|
|
|
|
srcptr = char_grayscale + col;
|
|
dstptr = char_grayscale + width; /* scratch */
|
|
|
|
/* We've computed the shape of our full box filter. Now
|
|
compute the bottom part of the moving sum */
|
|
for (bottom_size = 0;
|
|
bottom_size < bottom_height;
|
|
bottom_size++)
|
|
sum += srcptr[bottom_size * (width + 1)];
|
|
|
|
/* Now start moving the sum, growing the box filter, and
|
|
dropping averages into our scratch buffer */
|
|
for (top_size = 0; top_size < top_height; top_size++)
|
|
{
|
|
sum += srcptr[bottom_height * (width + 1)];
|
|
*dstptr = sum / (top_size + bottom_height + 1);
|
|
dstptr += width + 1;
|
|
srcptr += width + 1;
|
|
}
|
|
|
|
/* The box filter has reached full height... continue
|
|
computation of moving average until the bottom
|
|
hits the wall. */
|
|
for (row = top_size; row + bottom_size < height; row++)
|
|
{
|
|
sum += srcptr[bottom_height * (width + 1)];
|
|
*dstptr = sum / box_y;
|
|
dstptr += width + 1;
|
|
sum -= srcptr[-top_height * (width + 1)];
|
|
srcptr += width + 1;
|
|
}
|
|
|
|
/* Collapse the bottom of the box filter */
|
|
for (; bottom_size > 0; bottom_size--)
|
|
{
|
|
*dstptr = sum / (top_height + bottom_size);
|
|
dstptr += width + 1;
|
|
sum -= srcptr[-top_height * (width + 1)];
|
|
srcptr += width + 1;
|
|
}
|
|
|
|
/* Done with the column... copy dest back over source */
|
|
|
|
dstptr = char_grayscale + col;
|
|
srcptr = char_grayscale + width; /* scratch */
|
|
for (row = 0; row < height; row++)
|
|
{
|
|
*dstptr = *srcptr;
|
|
dstptr += width + 1;
|
|
srcptr += width + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Increase the grayvalue to increase ink a bit */
|
|
srcptr = char_grayscale;
|
|
for (row = 0; row < height; row++)
|
|
{
|
|
for (col = 0; col < width; col++)
|
|
{
|
|
register int pixvalue = (int)*srcptr * pixmult / 256;
|
|
if (pixvalue > 255) pixvalue = 255;
|
|
*srcptr = pixvalue;
|
|
srcptr++;
|
|
}
|
|
srcptr++;
|
|
}
|
|
}
|
|
|
|
/* Compute the increment values for the resampling loop */
|
|
TRANSFORM_POINT(inv_xform, 1, 0, point);
|
|
deltaX = (INT32)(point[0] * 65536.0);
|
|
deltaY = (INT32)(-point[1] * 65536.0);
|
|
|
|
/* Resampling loop: resamples original glyph for generation of new
|
|
glyph in transformed coordinate system. */
|
|
|
|
for (row = 0; row < newHeight; row++)
|
|
{
|
|
/* Compute inverse transformation for start of this row */
|
|
TRANSFORM_POINT(inv_xform,
|
|
(double)(pci->metrics.leftSideBearing) + .5,
|
|
(double)(pci->metrics.ascent - row) - .5,
|
|
point);
|
|
|
|
/* Adjust for coordinate system to get resampling point */
|
|
point[0] -= opci->metrics.leftSideBearing;
|
|
point[1] = opci->metrics.ascent - point[1];
|
|
|
|
/* Convert to integer coordinates */
|
|
xValue = (INT32)(point[0] * 65536.0);
|
|
yValue = (INT32)(point[1] * 65536.0);
|
|
|
|
if (char_grayscale)
|
|
{
|
|
INT32 *temp;
|
|
for (col = 0; col < newWidth; col++)
|
|
{
|
|
register int x = xValue >> 16, y = yValue >> 16;
|
|
int pixvalue, error;
|
|
|
|
pixvalue = ((x >= 0 && x < width && y >= 0 && y < height) ?
|
|
char_grayscale[x + y * (width + 1)] : 0) +
|
|
thisrow[col] / 16;
|
|
if (pixvalue > 255) pixvalue = 255;
|
|
else if (pixvalue < 0) pixvalue = 0;
|
|
|
|
/* Choose the bit value and set resulting error value */
|
|
if (pixvalue >= 128)
|
|
{
|
|
newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7];
|
|
error = pixvalue - 255;
|
|
}
|
|
else
|
|
error = -pixvalue;
|
|
|
|
/* Diffuse the error */
|
|
thisrow[col + 1] += error * 7;
|
|
nextrow[col - 1] += error * 3;
|
|
nextrow[col] += error * 5;
|
|
nextrow[col + 1] = error;
|
|
|
|
xValue += deltaX;
|
|
yValue += deltaY;
|
|
}
|
|
|
|
/* Add in error values that fell off either end */
|
|
nextrow[0] += nextrow[-1];
|
|
nextrow[newWidth - 2] += thisrow[newWidth];
|
|
nextrow[newWidth - 1] += nextrow[newWidth];
|
|
nextrow[newWidth] = 0;
|
|
|
|
temp = nextrow;
|
|
nextrow = thisrow;
|
|
thisrow = temp;
|
|
nextrow[-1] = nextrow[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
for (col = 0; col < newWidth; col++)
|
|
{
|
|
register int x = xValue >> 16, y = yValue >> 16;
|
|
|
|
if (x >= 0 && x < width && y >= 0 && y < height)
|
|
{
|
|
/* Use point-sampling for rescaling. */
|
|
|
|
if (bitmap[(x >> 3) + y * bpr] & mask[x & 0x7])
|
|
newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7];
|
|
}
|
|
|
|
xValue += deltaX;
|
|
yValue += deltaY;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (char_grayscale)
|
|
{
|
|
xfree(char_grayscale);
|
|
xfree(diffusion_workspace);
|
|
}
|
|
}
|
|
|
|
static FontPtr
|
|
BitmapScaleBitmaps(FontPtr pf, /* scaled font */
|
|
FontPtr opf, /* originating font */
|
|
double widthMult, /* glyphs width scale factor */
|
|
double heightMult, /* glyphs height scale factor */
|
|
FontScalablePtr vals)
|
|
{
|
|
register int i;
|
|
int nchars = 0;
|
|
char *glyphBytes;
|
|
BitmapFontPtr bitmapFont,
|
|
obitmapFont;
|
|
CharInfoPtr pci,
|
|
opci;
|
|
FontInfoPtr pfi;
|
|
int glyph;
|
|
unsigned bytestoalloc = 0;
|
|
int firstCol, lastCol, firstRow, lastRow;
|
|
|
|
double xform[4], inv_xform[4];
|
|
double xmult, ymult;
|
|
|
|
bitmapFont = (BitmapFontPtr) pf->fontPrivate;
|
|
obitmapFont = (BitmapFontPtr) opf->fontPrivate;
|
|
|
|
if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
|
|
inv_xform, &xmult, &ymult))
|
|
goto bail;
|
|
|
|
pfi = &pf->info;
|
|
firstCol = pfi->firstCol;
|
|
lastCol = pfi->lastCol;
|
|
firstRow = pfi->firstRow;
|
|
lastRow = pfi->lastRow;
|
|
|
|
nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
|
|
glyph = pf->glyph;
|
|
for (i = 0; i < nchars; i++)
|
|
{
|
|
if ((pci = ACCESSENCODING(bitmapFont->encoding, i)))
|
|
bytestoalloc += BYTES_FOR_GLYPH(pci, glyph);
|
|
}
|
|
|
|
/* Do we add the font malloc stuff for VALUE ADDED ? */
|
|
/* Will need to remember to free in the Unload routine */
|
|
|
|
|
|
bitmapFont->bitmaps = (char *) xalloc(bytestoalloc);
|
|
if (!bitmapFont->bitmaps) {
|
|
fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc);
|
|
goto bail;
|
|
}
|
|
bzero(bitmapFont->bitmaps, bytestoalloc);
|
|
|
|
glyphBytes = bitmapFont->bitmaps;
|
|
for (i = 0; i < nchars; i++)
|
|
{
|
|
if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) &&
|
|
(opci = ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i))))
|
|
{
|
|
pci->bits = glyphBytes;
|
|
ScaleBitmap (pf, opci, pci, inv_xform,
|
|
widthMult, heightMult);
|
|
glyphBytes += BYTES_FOR_GLYPH(pci, glyph);
|
|
}
|
|
}
|
|
return pf;
|
|
|
|
bail:
|
|
if (pf)
|
|
xfree(pf);
|
|
if (bitmapFont) {
|
|
xfree(bitmapFont->metrics);
|
|
xfree(bitmapFont->ink_metrics);
|
|
xfree(bitmapFont->bitmaps);
|
|
if(bitmapFont->encoding)
|
|
for(i=0; i<NUM_SEGMENTS(nchars); i++)
|
|
xfree(bitmapFont->encoding[i]);
|
|
xfree(bitmapFont->encoding);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static FontPtr
|
|
PrinterScaleBitmaps(FontPtr pf, /* scaled font */
|
|
FontPtr opf, /* originating font */
|
|
double widthMult, /* glyphs width scale factor */
|
|
double heightMult, /* glyphs height scale factor */
|
|
FontScalablePtr vals)
|
|
{
|
|
register int i;
|
|
int nchars = 0;
|
|
char *glyphBytes;
|
|
BitmapFontPtr bitmapFont,
|
|
obitmapFont;
|
|
CharInfoPtr pci;
|
|
FontInfoPtr pfi;
|
|
int glyph;
|
|
unsigned bytestoalloc = 0;
|
|
int firstCol, lastCol, firstRow, lastRow;
|
|
|
|
double xform[4], inv_xform[4];
|
|
double xmult, ymult;
|
|
|
|
bitmapFont = (BitmapFontPtr) pf->fontPrivate;
|
|
obitmapFont = (BitmapFontPtr) opf->fontPrivate;
|
|
|
|
if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
|
|
inv_xform, &xmult, &ymult))
|
|
goto bail;
|
|
|
|
pfi = &pf->info;
|
|
firstCol = pfi->firstCol;
|
|
lastCol = pfi->lastCol;
|
|
firstRow = pfi->firstRow;
|
|
lastRow = pfi->lastRow;
|
|
|
|
nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
|
|
glyph = pf->glyph;
|
|
for (i = 0; i < nchars; i++)
|
|
{
|
|
if ((pci = ACCESSENCODING(bitmapFont->encoding, i)))
|
|
bytestoalloc = MAX(bytestoalloc,BYTES_FOR_GLYPH(pci, glyph));
|
|
}
|
|
|
|
/* Do we add the font malloc stuff for VALUE ADDED ? */
|
|
/* Will need to remember to free in the Unload routine */
|
|
|
|
|
|
bitmapFont->bitmaps = (char *) xalloc(bytestoalloc);
|
|
if (!bitmapFont->bitmaps) {
|
|
fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc);
|
|
goto bail;
|
|
}
|
|
bzero(bitmapFont->bitmaps, bytestoalloc);
|
|
|
|
glyphBytes = bitmapFont->bitmaps;
|
|
for (i = 0; i < nchars; i++)
|
|
{
|
|
if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) &&
|
|
(ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i))))
|
|
{
|
|
pci->bits = glyphBytes;
|
|
}
|
|
}
|
|
return pf;
|
|
|
|
bail:
|
|
if (pf)
|
|
xfree(pf);
|
|
if (bitmapFont) {
|
|
xfree(bitmapFont->metrics);
|
|
xfree(bitmapFont->ink_metrics);
|
|
xfree(bitmapFont->bitmaps);
|
|
if(bitmapFont->encoding)
|
|
for(i=0; i<NUM_SEGMENTS(nchars); i++)
|
|
xfree(bitmapFont->encoding[i]);
|
|
xfree(bitmapFont->encoding);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef NOTDEF
|
|
/*
|
|
* exported interfaces
|
|
*/
|
|
|
|
FontFileLoadName(FontFileDirPtr *dirs, int ndirs, char *name, FontPtr *pfont,
|
|
fsBitmapFormat format, fsBitmapFormatMask fmask)
|
|
{
|
|
FontFileNamePtr fname;
|
|
char full_name[1024];
|
|
int ret = BadFontName;
|
|
int i;
|
|
|
|
i = 0;
|
|
while (i < ndirs) {
|
|
if (fname = FontFileFindNameInDir(dirs[i], name)) {
|
|
if (!fname->alias) {
|
|
if (!fname->font) {
|
|
strcpy(full_name, dirs[i]->dir);
|
|
strcat(full_name, fname->file);
|
|
ret = FontFileLoad(pfont, full_name, format, fmask);
|
|
if (ret == Successful) {
|
|
fname->font = *pfont;
|
|
(*pfont)->fpePrivate = (pointer) fname;
|
|
}
|
|
return ret;
|
|
}
|
|
*pfont = fname->font;
|
|
return Successful;
|
|
}
|
|
name = fname->file;
|
|
i = 0;
|
|
} else
|
|
i++;
|
|
}
|
|
return BadFontName;
|
|
}
|
|
#endif
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
BitmapOpenScalable (FontPathElementPtr fpe,
|
|
FontPtr *pFont,
|
|
int flags,
|
|
FontEntryPtr entry,
|
|
char *fileName, /* unused */
|
|
FontScalablePtr vals,
|
|
fsBitmapFormat format,
|
|
fsBitmapFormatMask fmask,
|
|
FontPtr non_cachable_font) /* We don't do licensing */
|
|
{
|
|
FontScalableRec best;
|
|
FontPtr font = NullFont;
|
|
double dx, sdx,
|
|
dy, sdy,
|
|
savedX, savedY;
|
|
FontPropPtr props;
|
|
char *isStringProp;
|
|
int propCount;
|
|
int status;
|
|
long sWidth;
|
|
|
|
FontEntryPtr scaleFrom;
|
|
FontPathElementPtr scaleFPE;
|
|
FontPtr sourceFont;
|
|
char fontName[MAXFONTNAMELEN];
|
|
|
|
/* Can't deal with mix-endian fonts yet */
|
|
|
|
#ifdef NOTDEF /* XXX need better test */
|
|
if ((format & BitmapFormatByteOrderMask) !=
|
|
(format & BitmapFormatBitOrderMask))
|
|
return NullFontFileName;
|
|
#endif
|
|
|
|
/* Reject outrageously small font sizes to keep the math from
|
|
blowing up. */
|
|
if (get_matrix_vertical_component(vals->pixel_matrix) < 1.0 ||
|
|
get_matrix_horizontal_component(vals->pixel_matrix) < 1.0)
|
|
return BadFontName;
|
|
|
|
scaleFrom = (*find_scale[BitmapGetRenderIndex(entry->u.bitmap.renderer)])
|
|
(fpe, entry, vals, &best, &dx, &dy, &sdx, &sdy, &scaleFPE);
|
|
|
|
if (!scaleFrom)
|
|
return BadFontName;
|
|
|
|
status = FontFileOpenBitmap(scaleFPE, &sourceFont, LoadAll, scaleFrom,
|
|
format, fmask);
|
|
|
|
if (status != Successful)
|
|
return BadFontName;
|
|
|
|
if (!vals->width)
|
|
vals->width = best.width * dx;
|
|
|
|
/* Compute the scaled font */
|
|
|
|
savedX = dx;
|
|
savedY = dy;
|
|
font = ScaleFont(sourceFont, dx, dy, sdx, sdy, vals, &dx, &dy, &sWidth);
|
|
if (font)
|
|
font = (*scale[ BitmapGetRenderIndex(entry->u.bitmap.renderer) ])
|
|
(font, sourceFont, savedX, savedY, vals);
|
|
|
|
if (!font)
|
|
{
|
|
if (!sourceFont->refcnt)
|
|
FontFileCloseFont((FontPathElementPtr) 0, sourceFont);
|
|
return AllocError;
|
|
}
|
|
|
|
/* Prepare font properties for the new font */
|
|
|
|
strcpy (fontName, scaleFrom->name.name);
|
|
FontParseXLFDName (fontName, vals, FONT_XLFD_REPLACE_VALUE);
|
|
|
|
propCount = ComputeScaledProperties(&sourceFont->info, fontName, vals,
|
|
dx, dy, sdx, sdy, sWidth, &props,
|
|
&isStringProp);
|
|
|
|
if (!sourceFont->refcnt)
|
|
FontFileCloseFont((FontPathElementPtr) 0, sourceFont);
|
|
|
|
if (propCount && (!props || !isStringProp))
|
|
{
|
|
font->info.nprops = 0;
|
|
font->info.props = (FontPropPtr)0;
|
|
font->info.isStringProp = (char *)0;
|
|
bitmapUnloadScalable(font);
|
|
return AllocError;
|
|
}
|
|
|
|
font->info.props = props;
|
|
font->info.nprops = propCount;
|
|
font->info.isStringProp = isStringProp;
|
|
|
|
*pFont = font;
|
|
return Successful;
|
|
}
|
|
|
|
int
|
|
BitmapGetInfoScalable (FontPathElementPtr fpe,
|
|
FontInfoPtr pFontInfo,
|
|
FontEntryPtr entry,
|
|
FontNamePtr fontName,
|
|
char *fileName,
|
|
FontScalablePtr vals)
|
|
{
|
|
FontPtr pfont;
|
|
int flags = 0;
|
|
long format = 0; /* It doesn't matter what format for just info */
|
|
long fmask = 0;
|
|
int ret;
|
|
|
|
ret = BitmapOpenScalable(fpe, &pfont, flags, entry, fileName, vals,
|
|
format, fmask, NULL);
|
|
if (ret != Successful)
|
|
return ret;
|
|
*pFontInfo = pfont->info;
|
|
|
|
pfont->info.nprops = 0;
|
|
pfont->info.props = NULL;
|
|
pfont->info.isStringProp = NULL;
|
|
|
|
(*pfont->unload_font)(pfont);
|
|
return Successful;
|
|
}
|
|
|
|
static void
|
|
bitmapUnloadScalable (FontPtr pFont)
|
|
{
|
|
BitmapFontPtr bitmapFont;
|
|
FontInfoPtr pfi;
|
|
int i, nencoding;
|
|
|
|
bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
|
|
pfi = &pFont->info;
|
|
xfree (pfi->props);
|
|
xfree (pfi->isStringProp);
|
|
if(bitmapFont->encoding) {
|
|
nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
|
|
(pFont->info.lastRow - pFont->info.firstRow + 1);
|
|
for(i=0; i<NUM_SEGMENTS(nencoding); i++)
|
|
xfree(bitmapFont->encoding[i]);
|
|
}
|
|
xfree (bitmapFont->encoding);
|
|
xfree (bitmapFont->bitmaps);
|
|
xfree (bitmapFont->ink_metrics);
|
|
xfree (bitmapFont->metrics);
|
|
xfree (pFont->fontPrivate);
|
|
DestroyFontRec (pFont);
|
|
}
|