Save work.

This commit is contained in:
Michael R Sweet 2023-11-13 16:18:02 -05:00
parent 858cc101b6
commit 688810f143
No known key found for this signature in database
GPG Key ID: BE67C75EC81F3244
5 changed files with 329 additions and 18 deletions

1
.gitignore vendored
View File

@ -13,4 +13,5 @@
/pdfiototext /pdfiototext
/testpdfio /testpdfio
/testpdfio-*.pdf /testpdfio-*.pdf
/testttf
/x64 /x64

View File

@ -67,12 +67,14 @@ LIBOBJS = \
OBJS = \ OBJS = \
$(LIBOBJS) \ $(LIBOBJS) \
pdfiototext.o \ pdfiototext.o \
testpdfio.o testpdfio.o \
testttf.o
TARGETS = \ TARGETS = \
$(DSONAME) \ $(DSONAME) \
libpdfio.a \ libpdfio.a \
pdfiototext \ pdfiototext \
testpdfio testpdfio \
testttf
# Make everything # Make everything
@ -136,6 +138,7 @@ install-shared:
# Test everything # Test everything
test: testpdfio test: testpdfio
./testttf 2>test.log
./testpdfio 2>test.log ./testpdfio 2>test.log
valgrind: testpdfio valgrind: testpdfio
@ -182,10 +185,16 @@ testpdfio: testpdfio.o libpdfio.a
echo Linking $@... echo Linking $@...
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS) $(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
# TTF test program
testttf: ttf.o testttf.o
echo Linking $@...
$(CC) $(LDFLAGS) -o testttf ttf.o testttf.o $(LIBS)
# Dependencies # Dependencies
$(OBJS): pdfio.h pdfio-private.h Makefile $(OBJS): pdfio.h pdfio-private.h Makefile
pdfio-content.o: pdfio-content.h ttf.h pdfio-content.o: pdfio-content.h ttf.h
testttf.o: ttf.h
ttf.o: ttf.h ttf.o: ttf.h
# Make documentation using Codedoc <https://www.msweet.org/codedoc> # Make documentation using Codedoc <https://www.msweet.org/codedoc>

View File

@ -1466,8 +1466,8 @@ pdfioFileCreateFontObjFromFile(
else else
{ {
// Map to specified glyph... // Map to specified glyph...
*bufptr++ = (unsigned char)((cmap[i] + 1) >> 8); *bufptr++ = (unsigned char)(cmap[i] >> 8);
*bufptr++ = (unsigned char)((cmap[i] + 1) & 255); *bufptr++ = (unsigned char)(cmap[i] & 255);
} }
if (bufptr >= bufend) if (bufptr >= bufend)

305
testttf.c Normal file
View File

@ -0,0 +1,305 @@
//
// Unit test program for TTF library
//
// https://github.com/michaelrsweet/ttf
//
// Copyright © 2018-2023 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
// Usage:
//
// ./testttf [FILENAME]
//
#include <stdio.h>
#include "ttf.h"
//
// Local functions...
//
static void error_cb(void *data, const char *message);
static int test_font(const char *filename);
//
// 'main()' - Main entry for unit tests.
//
int // O - Exit status
main(int argc, // I - Number of command-line arguments
char *argv[]) // I - Command-line arguments
{
int i; // Looping var
int errors = 0; // Number of errors
if (argc > 1)
{
for (i = 1; i < argc; i ++)
errors += test_font(argv[i]);
}
else
{
// Test with the bundled TrueType files...
errors += test_font("testfiles/OpenSans-Bold.ttf");
errors += test_font("testfiles/OpenSans-Regular.ttf");
errors += test_font("testfiles/NotoSansJP-Regular.otf");
}
if (!errors)
puts("\nALL TESTS PASSED");
else
printf("\n%d TEST(S) FAILED\n", errors);
return (errors);
}
//
// 'error_cb()' - Error callback.
//
static void
error_cb(void *data, // I - User data (not used)
const char *message) // I - Message string
{
fprintf(stderr, "FAIL (%s)\n", message);
}
//
// 'test_font()' - Test a font file.
//
static int // O - Number of errors
test_font(const char *filename) // I - Font filename
{
int i, // Looping var
errors = 0; // Number of errors
ttf_t *font; // Font
const char *value; // Font (string) value
int intvalue; // Font (integer) value
float realvalue; // Font (real) value
ttf_rect_t bounds; // Bounds
ttf_rect_t extents; // Extents
size_t num_fonts; // Number of fonts
ttf_style_t style; // Font style
ttf_weight_t weight; // Font weight
static const char * const stretches[] =
{ // Font stretch strings
"TTF_STRETCH_NORMAL", // normal
"TTF_STRETCH_ULTRA_CONDENSED", // ultra-condensed
"TTF_STRETCH_EXTRA_CONDENSED", // extra-condensed
"TTF_STRETCH_CONDENSED", // condensed
"TTF_STRETCH_SEMI_CONDENSED", // semi-condensed
"TTF_STRETCH_SEMI_EXPANDED", // semi-expanded
"TTF_STRETCH_EXPANDED", // expanded
"TTF_STRETCH_EXTRA_EXPANDED", // extra-expanded
"TTF_STRETCH_ULTRA_EXPANDED" // ultra-expanded
};
static const char * const strings[] = // Test strings
{
"Hello, World!", // English
"مرحبا بالعالم!", // Arabic
"Bonjour le monde!", // French
"Γειά σου Κόσμε!", // Greek
"שלום עולם!", // Hebrew
"Привет мир!", // Russian
"こんにちは世界!" // Japanese
};
static const char * const styles[] = // Font style names
{
"TTF_STYLE_NORMAL",
"TTF_STYLE_ITALIC",
"TTF_STYLE_OBLIQUE"
};
printf("ttfCreate(\"%s\"): ", filename);
if ((font = ttfCreate(filename, 0, error_cb, NULL)) != NULL)
puts("PASS");
else
errors ++;
fputs("ttfGetAscent: ", stdout);
if ((intvalue = ttfGetAscent(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetBounds: ", stdout);
if (ttfGetBounds(font, &bounds))
{
printf("PASS (%g %g %g %g)\n", bounds.left, bounds.bottom, bounds.right, bounds.top);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetCapHeight: ", stdout);
if ((intvalue = ttfGetCapHeight(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetCopyright: ", stdout);
if ((value = ttfGetCopyright(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
for (i = 0; i < (int)(sizeof(strings) / sizeof(strings[0])); i ++)
{
printf("ttfGetExtents(\"%s\"): ", strings[i]);
if (ttfGetExtents(font, 12.0f, strings[i], &extents))
{
printf("PASS (%.1f %.1f %.1f %.1f)\n", extents.left, extents.bottom, extents.right, extents.top);
}
else
{
puts("FAIL");
errors ++;
}
}
fputs("ttfGetFamily: ", stdout);
if ((value = ttfGetFamily(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetItalicAngle: ", stdout);
if ((realvalue = ttfGetItalicAngle(font)) >= 0.0)
{
printf("PASS (%g)\n", realvalue);
}
else
{
printf("FAIL (%g)\n", realvalue);
errors ++;
}
fputs("ttfGetNumFonts: ", stdout);
if ((num_fonts = ttfGetNumFonts(font)) > 0)
{
printf("PASS (%u)\n", (unsigned)num_fonts);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetPostScriptName: ", stdout);
if ((value = ttfGetPostScriptName(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetStretch: ", stdout);
if ((intvalue = (int)ttfGetStretch(font)) >= TTF_STRETCH_NORMAL && intvalue <= TTF_STRETCH_ULTRA_EXPANDED)
{
printf("PASS (%s)\n", stretches[intvalue]);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetStyle: ", stdout);
if ((style = ttfGetStyle(font)) >= TTF_STYLE_NORMAL && style <= TTF_STYLE_ITALIC)
{
printf("PASS (%s)\n", styles[style]);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetVersion: ", stdout);
if ((value = ttfGetVersion(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetWeight: ", stdout);
if ((weight = ttfGetWeight(font)) >= 0)
{
printf("PASS (%u)\n", (unsigned)weight);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetWidth(' '): ", stdout);
if ((intvalue = ttfGetWidth(font, ' ')) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetXHeight: ", stdout);
if ((intvalue = ttfGetXHeight(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfIsFixedPitch: ", stdout);
if (ttfIsFixedPitch(font))
puts("PASS (true)");
else
puts("PASS (false)");
ttfDelete(font);
return (errors);
}

24
ttf.c
View File

@ -75,6 +75,7 @@ typedef __int64 ssize_t; // POSIX type not present on Windows...
// DEBUG is defined and is a no-op otherwise... // DEBUG is defined and is a no-op otherwise...
// //
#define DEBUG
#ifdef DEBUG #ifdef DEBUG
# define TTF_DEBUG(...) fprintf(stderr, __VA_ARGS__) # define TTF_DEBUG(...) fprintf(stderr, __VA_ARGS__)
#else #else
@ -448,7 +449,7 @@ ttfCreate(const char *filename, // I - Filename
font->cap_height = font->ascent; font->cap_height = font->ascent;
if (font->x_height == 0) if (font->x_height == 0)
font->x_height = 3 * font->ascent / 5; font->x_height = 3 * font->ascent / 5;
// Build a sparse glyph widths table... // Build a sparse glyph widths table...
font->min_char = -1; font->min_char = -1;
@ -458,7 +459,8 @@ ttfCreate(const char *filename, // I - Filename
if (font->cmap[i] >= 0) if (font->cmap[i] >= 0)
{ {
int bin = (int)i / 256, // Sub-array bin int bin = (int)i / 256, // Sub-array bin
glyph = font->cmap[i]; // Glyph index glyph = font->cmap[i] + 1;
// Glyph index (+1 to get past .notdef)
// Update min/max... // Update min/max...
if (font->min_char < 0) if (font->min_char < 0)
@ -687,9 +689,6 @@ ttfGetExtents(
ch = *s++; ch = *s++;
} }
// Issue #1: Offset past ".notdef"...
ch ++;
// Find its width... // Find its width...
if ((widths = font->widths[ch / 256]) != NULL) if ((widths = font->widths[ch / 256]) != NULL)
{ {
@ -855,17 +854,14 @@ int // O - Width in 1000ths
ttfGetWidth(ttf_t *font, // I - Font ttfGetWidth(ttf_t *font, // I - Font
int ch) // I - Unicode character int ch) // I - Unicode character
{ {
int bin; // Bin in widths array ch --;
int bin = ch >> 8; // Bin in widths array
// Range check input... // Range check input...
if (!font || ch < ' ' || ch == 0x7f) if (!font || ch < ' ' || ch == 0x7f)
return (0); return (0);
// Issue #1: Offset past ".notdef"...
ch ++;
bin = ch >> 8;
if (font->widths[bin]) if (font->widths[bin])
return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units)); return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units));
else if (font->widths[0]) // .notdef else if (font->widths[0]) // .notdef
@ -1309,17 +1305,17 @@ read_cmap(ttf_t *font) // I - Font
{ {
// Use an "obscure indexing trick" (words from the spec, not // Use an "obscure indexing trick" (words from the spec, not
// mine) to look up the glyph index... // mine) to look up the glyph index...
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount - 1; temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount;
if (temp < 0 || temp >= numGlyphIdArray || !glyphIdArray[temp]) if (temp < 0 || temp >= numGlyphIdArray)
glyph = -1; glyph = -1;
else else
glyph = ((glyphIdArray[temp] + segment->idDelta) & 65535) - 1; glyph = (glyphIdArray[temp] + segment->idDelta) & 65535;
} }
else else
{ {
// Just use idDelta to compute a glyph index... // Just use idDelta to compute a glyph index...
glyph = ((ch + segment->idDelta) & 65535) - 1; glyph = (ch + segment->idDelta) & 65535;
} }
cmapptr[ch] = glyph; cmapptr[ch] = glyph;