1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-04 04:50:22 +00:00

Merge pull request #431 from a740g/freetype-upgrade

Update FreeType to v2.13.2
This commit is contained in:
Samuel Gomes 2024-01-13 15:29:18 +05:30 committed by GitHub
commit 4c820fba21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
455 changed files with 234483 additions and 177025 deletions

View file

@ -263,7 +263,7 @@ else
endif
ifneq ($(filter y,$(DEP_FONT)),)
EXE_LIBS += $(FREETYPE_OBJS) $(FONT_OBJS)
EXE_LIBS += $(FONT_OBJS) $(FREETYPE_EXE_LIBS)
LICENSE_IN_USE += freetype_ftl
else

View file

@ -1,22 +1,40 @@
FREETYPE_SRCS := \
freetypeamalgam.c
FONT_SRCS := \
font.cpp
# We use the flat-directory compilation for FreeType as explained in:
# https://github.com/freetype/freetype/blob/master/docs/INSTALL.ANY
#
# When updating the library:
# 1. Flatten all directories inside "src" except "tools". Omit contents of "tools" entirely.
# 2. Then only copy all .c & .h files except:
# autofit.c, bdf.c, cff.c, ftbase.c, ftcache.c, gxvalid.c, gxvfgen.c,
# otvalid.c, pcf.c, pfr.c, pshinter.c, psnames.c, raster.c, sdf.c, sfnt.c,
# smooth.c, svg.c, truetype.c, type1.c, type1cid.c, type42.c
# 3. Copy the FreeType "include" directory *without* flattening!
# 4. Include <freetype/internal/compiler-macros.h> in "ftzopen.h".
# 5. Include <freetype/config/ftstdlib.h> in "zutil.h".
FONT_STUB_SRCS := \
stub_font.cpp
FREETYPE_SRCS := $(wildcard $(PATH_INTERNAL_C)/parts/video/font/freetype/*.c)
FREETYPE_OBJS := $(patsubst %.c,$(PATH_INTERNAL_C)/parts/video/font/%.o,$(FREETYPE_SRCS))
FREETYPE_INCLUDE := -I$(PATH_INTERNAL_C)/parts/video/font/freetype/include
FREETYPE_OBJS := $(FREETYPE_SRCS:.c=.o)
FREETYPE_LIB := $(PATH_INTERNAL_C)/parts/video/font/freetype/freetype.a
FONT_SRCS := font.cpp
FONT_STUB_SRCS := stub_font.cpp
FONT_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/video/font/%.o,$(FONT_SRCS))
FONT_STUB_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/video/font/%.o,$(FONT_STUB_SRCS))
$(PATH_INTERNAL_C)/parts/video/font/%.o: $(PATH_INTERNAL_C)/parts/video/font/%.c
$(CC) -O2 $(CFLAGS) -DDEPENDENCY_CONSOLE_ONLY -Wall $< -c -o $@
$(PATH_INTERNAL_C)/parts/video/font/%.o: $(PATH_INTERNAL_C)/parts/video/font/%.cpp
$(CXX) -O2 $(CXXFLAGS) -DDEPENDENCY_CONSOLE_ONLY -Wall $< -c -o $@
$(CXX) -O2 $(CXXFLAGS) $(FREETYPE_INCLUDE) -DDEPENDENCY_CONSOLE_ONLY -Wall $< -c -o $@
CLEAN_LIST += $(FREETYPE_OBJS) $(FONT_OBJS) $(FONT_STUB_OBJS)
$(PATH_INTERNAL_C)/parts/video/font/freetype/%.o: $(PATH_INTERNAL_C)/parts/video/font/freetype/%.c
$(CC) -O3 $(CFLAGS) $(FREETYPE_INCLUDE) -DFT2_BUILD_LIBRARY -Wall $< -c -o $@
$(FREETYPE_LIB): $(FREETYPE_OBJS)
$(AR) rcs $@ $(FREETYPE_OBJS)
FREETYPE_EXE_LIBS := $(FREETYPE_LIB)
CLEAN_LIST += $(FREETYPE_LIB) $(FREETYPE_OBJS) $(FONT_OBJS) $(FONT_STUB_OBJS)

View file

@ -6,13 +6,14 @@
#define FONT_DEBUG 0
#include "font.h"
#include "../../../libqb.h"
#include "freetypeamalgam.h"
#include "gui.h"
#include "image.h"
#include "libqb-common.h"
#include "mutex.h"
#include "rounding.h"
#include <cstdio>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <unordered_map>
#include <vector>

View file

@ -0,0 +1,192 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#ifndef Z_FREETYPE
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#endif
#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
/* use NO_DIVIDE if your processor does not do division in hardware --
try it both ways to see which is faster */
#ifdef NO_DIVIDE
/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
(thank you to John Reiser for pointing this out) */
# define CHOP(a) \
do { \
unsigned long tmp = a >> 16; \
a &= 0xffffUL; \
a += (tmp << 4) - tmp; \
} while (0)
# define MOD28(a) \
do { \
CHOP(a); \
if (a >= BASE) a -= BASE; \
} while (0)
# define MOD(a) \
do { \
CHOP(a); \
MOD28(a); \
} while (0)
# define MOD63(a) \
do { /* this assumes a is not negative */ \
z_off64_t tmp = a >> 32; \
a &= 0xffffffffL; \
a += (tmp << 8) - (tmp << 5) + tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
if (a >= BASE) a -= BASE; \
} while (0)
#else
# define MOD(a) a %= BASE
# define MOD28(a) a %= BASE
# define MOD63(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32_z(
uLong adler,
const Bytef *buf,
z_size_t len)
{
unsigned long sum2;
unsigned n;
/* split Adler-32 into component sums */
sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (len == 1) {
adler += buf[0];
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if (buf == Z_NULL)
return 1L;
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (len--) {
adler += *buf++;
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
MOD28(sum2); /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
n = NMAX / 16; /* NMAX is divisible by 16 */
do {
DO16(buf); /* 16 sums unrolled */
buf += 16;
} while (--n);
MOD(adler);
MOD(sum2);
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
DO16(buf);
buf += 16;
}
while (len--) {
adler += *buf++;
sum2 += adler;
}
MOD(adler);
MOD(sum2);
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32(
uLong adler,
const Bytef *buf,
uInt len)
{
return adler32_z(adler, buf, len);
}
#ifndef Z_FREETYPE
/* ========================================================================= */
local uLong adler32_combine_(
uLong adler1,
uLong adler2,
z_off64_t len2)
{
unsigned long sum1;
unsigned long sum2;
unsigned rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffffUL;
/* the derivation of this formula is left as an exercise for the reader */
MOD63(len2); /* assumes len2 >= 0 */
rem = (unsigned)len2;
sum1 = adler1 & 0xffff;
sum2 = rem * sum1;
MOD(sum2);
sum1 += (adler2 & 0xffff) + BASE - 1;
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32_combine(
uLong adler1,
uLong adler2,
z_off_t len2)
{
return adler32_combine_(adler1, adler2, len2);
}
uLong ZEXPORT adler32_combine64(
uLong adler1,
uLong adler2,
z_off64_t len2)
{
return adler32_combine_(adler1, adler2, len2);
}
#endif /* !Z_FREETYPE */

View file

@ -0,0 +1,779 @@
/* This file has been generated by the Perl script `afblue.pl', */
/* using data from file `afblue.dat'. */
/****************************************************************************
*
* afblue.c
*
* Auto-fitter data for blue strings (body).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "aftypes.h"
FT_LOCAL_ARRAY_DEF( char )
af_blue_strings[] =
{
/* */
'\xF0', '\x9E', '\xA4', '\x8C', ' ', '\xF0', '\x9E', '\xA4', '\x85', ' ', '\xF0', '\x9E', '\xA4', '\x88', ' ', '\xF0', '\x9E', '\xA4', '\x8F', ' ', '\xF0', '\x9E', '\xA4', '\x94', ' ', '\xF0', '\x9E', '\xA4', '\x9A', /* 𞤌 𞤅 𞤈 𞤏 𞤔 𞤚 */
'\0',
'\xF0', '\x9E', '\xA4', '\x82', ' ', '\xF0', '\x9E', '\xA4', '\x96', /* 𞤂 𞤖 */
'\0',
'\xF0', '\x9E', '\xA4', '\xAC', ' ', '\xF0', '\x9E', '\xA4', '\xAE', ' ', '\xF0', '\x9E', '\xA4', '\xBB', ' ', '\xF0', '\x9E', '\xA4', '\xBC', ' ', '\xF0', '\x9E', '\xA4', '\xBE', /* 𞤬 𞤮 𞤻 𞤼 𞤾 */
'\0',
'\xF0', '\x9E', '\xA4', '\xA4', ' ', '\xF0', '\x9E', '\xA4', '\xA8', ' ', '\xF0', '\x9E', '\xA4', '\xA9', ' ', '\xF0', '\x9E', '\xA4', '\xAD', ' ', '\xF0', '\x9E', '\xA4', '\xB4', ' ', '\xF0', '\x9E', '\xA4', '\xB8', ' ', '\xF0', '\x9E', '\xA4', '\xBA', ' ', '\xF0', '\x9E', '\xA5', '\x80', /* 𞤤 𞤨 𞤩 𞤭 𞤴 𞤸 𞤺 𞥀 */
'\0',
'\xD8', '\xA7', ' ', '\xD8', '\xA5', ' ', '\xD9', '\x84', ' ', '\xD9', '\x83', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8', /* ا إ ل ك ط ظ */
'\0',
'\xD8', '\xAA', ' ', '\xD8', '\xAB', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8', ' ', '\xD9', '\x83', /* ت ث ط ظ ك */
'\0',
'\xD9', '\x80', /* ـ */
'\0',
'\xD4', '\xB1', ' ', '\xD5', '\x84', ' ', '\xD5', '\x92', ' ', '\xD5', '\x8D', ' ', '\xD4', '\xB2', ' ', '\xD4', '\xB3', ' ', '\xD4', '\xB4', ' ', '\xD5', '\x95', /* Ա Մ Ւ Ս Բ Գ Դ Օ */
'\0',
'\xD5', '\x92', ' ', '\xD5', '\x88', ' ', '\xD4', '\xB4', ' ', '\xD5', '\x83', ' ', '\xD5', '\x87', ' ', '\xD5', '\x8D', ' ', '\xD5', '\x8F', ' ', '\xD5', '\x95', /* Ւ Ո Դ Ճ Շ Ս Տ Օ */
'\0',
'\xD5', '\xA5', ' ', '\xD5', '\xA7', ' ', '\xD5', '\xAB', ' ', '\xD5', '\xB4', ' ', '\xD5', '\xBE', ' ', '\xD6', '\x86', ' ', '\xD5', '\xB3', /* ե է ի մ վ ֆ ճ */
'\0',
'\xD5', '\xA1', ' ', '\xD5', '\xB5', ' ', '\xD6', '\x82', ' ', '\xD5', '\xBD', ' ', '\xD5', '\xA3', ' ', '\xD5', '\xB7', ' ', '\xD6', '\x80', ' ', '\xD6', '\x85', /* ա յ ւ ս գ շ ր օ */
'\0',
'\xD5', '\xB0', ' ', '\xD5', '\xB8', ' ', '\xD5', '\xB3', ' ', '\xD5', '\xA1', ' ', '\xD5', '\xA5', ' ', '\xD5', '\xAE', ' ', '\xD5', '\xBD', ' ', '\xD6', '\x85', /* հ ո ճ ա ե ծ ս օ */
'\0',
'\xD5', '\xA2', ' ', '\xD5', '\xA8', ' ', '\xD5', '\xAB', ' ', '\xD5', '\xAC', ' ', '\xD5', '\xB2', ' ', '\xD5', '\xBA', ' ', '\xD6', '\x83', ' ', '\xD6', '\x81', /* բ ը ի լ ղ պ փ ց */
'\0',
'\xF0', '\x90', '\xAC', '\x80', ' ', '\xF0', '\x90', '\xAC', '\x81', ' ', '\xF0', '\x90', '\xAC', '\x90', ' ', '\xF0', '\x90', '\xAC', '\x9B', /* 𐬀 𐬁 𐬐 𐬛 */
'\0',
'\xF0', '\x90', '\xAC', '\x80', ' ', '\xF0', '\x90', '\xAC', '\x81', /* 𐬀 𐬁 */
'\0',
'\xEA', '\x9A', '\xA7', ' ', '\xEA', '\x9A', '\xA8', ' ', '\xEA', '\x9B', '\x9B', ' ', '\xEA', '\x9B', '\x89', ' ', '\xEA', '\x9B', '\x81', ' ', '\xEA', '\x9B', '\x88', ' ', '\xEA', '\x9B', '\xAB', ' ', '\xEA', '\x9B', '\xAF', /* ꚧ ꚨ ꛛ ꛉ ꛁ ꛈ */
'\0',
'\xEA', '\x9A', '\xAD', ' ', '\xEA', '\x9A', '\xB3', ' ', '\xEA', '\x9A', '\xB6', ' ', '\xEA', '\x9B', '\xAC', ' ', '\xEA', '\x9A', '\xA2', ' ', '\xEA', '\x9A', '\xBD', ' ', '\xEA', '\x9B', '\xAF', ' ', '\xEA', '\x9B', '\xB2', /* ꚭ ꚳ ꚶ ꛬ ꚢ ꚽ ꛲ */
'\0',
'\xE0', '\xA6', '\x85', ' ', '\xE0', '\xA6', '\xA1', ' ', '\xE0', '\xA6', '\xA4', ' ', '\xE0', '\xA6', '\xA8', ' ', '\xE0', '\xA6', '\xAC', ' ', '\xE0', '\xA6', '\xAD', ' ', '\xE0', '\xA6', '\xB2', ' ', '\xE0', '\xA6', '\x95', /* অ ড ত ন ব ভ ল ক */
'\0',
'\xE0', '\xA6', '\x87', ' ', '\xE0', '\xA6', '\x9F', ' ', '\xE0', '\xA6', '\xA0', ' ', '\xE0', '\xA6', '\xBF', ' ', '\xE0', '\xA7', '\x80', ' ', '\xE0', '\xA7', '\x88', ' ', '\xE0', '\xA7', '\x97', /* ই ট ঠ ি ী ৈ ৗ */
'\0',
'\xE0', '\xA6', '\x93', ' ', '\xE0', '\xA6', '\x8F', ' ', '\xE0', '\xA6', '\xA1', ' ', '\xE0', '\xA6', '\xA4', ' ', '\xE0', '\xA6', '\xA8', ' ', '\xE0', '\xA6', '\xAC', ' ', '\xE0', '\xA6', '\xB2', ' ', '\xE0', '\xA6', '\x95', /* ও এ ড ত ন ব ল ক */
'\0',
'\xE1', '\x9D', '\x90', ' ', '\xE1', '\x9D', '\x88', /* ᝐ ᝈ */
'\0',
'\xE1', '\x9D', '\x85', ' ', '\xE1', '\x9D', '\x8A', ' ', '\xE1', '\x9D', '\x8E', /* ᝅ ᝊ ᝎ */
'\0',
'\xE1', '\x9D', '\x82', ' ', '\xE1', '\x9D', '\x83', ' ', '\xE1', '\x9D', '\x89', ' ', '\xE1', '\x9D', '\x8C', /* ᝂ ᝃ ᝉ ᝌ */
'\0',
'\xE1', '\x9D', '\x80', ' ', '\xE1', '\x9D', '\x83', ' ', '\xE1', '\x9D', '\x86', ' ', '\xE1', '\x9D', '\x89', ' ', '\xE1', '\x9D', '\x8B', ' ', '\xE1', '\x9D', '\x8F', ' ', '\xE1', '\x9D', '\x91', /* ᝀ ᝃ ᝆ ᝉ ᝋ ᝏ ᝑ */
'\0',
'\xE1', '\x97', '\x9C', ' ', '\xE1', '\x96', '\xB4', ' ', '\xE1', '\x90', '\x81', ' ', '\xE1', '\x92', '\xA3', ' ', '\xE1', '\x91', '\xAB', ' ', '\xE1', '\x91', '\x8E', ' ', '\xE1', '\x94', '\x91', ' ', '\xE1', '\x97', '\xB0', /* ᗜ ᐁ ᒣ ᑫ ᑎ ᔑ */
'\0',
'\xE1', '\x97', '\xB6', ' ', '\xE1', '\x96', '\xB5', ' ', '\xE1', '\x92', '\xA7', ' ', '\xE1', '\x90', '\x83', ' ', '\xE1', '\x91', '\x8C', ' ', '\xE1', '\x92', '\x8D', ' ', '\xE1', '\x94', '\x91', ' ', '\xE1', '\x97', '\xA2', /* ᗶ ᖵ ᒧ ᐃ ᔑ ᗢ */
'\0',
'\xE1', '\x93', '\x93', ' ', '\xE1', '\x93', '\x95', ' ', '\xE1', '\x93', '\x80', ' ', '\xE1', '\x93', '\x82', ' ', '\xE1', '\x93', '\x84', ' ', '\xE1', '\x95', '\x84', ' ', '\xE1', '\x95', '\x86', ' ', '\xE1', '\x98', '\xA3', /* ᓓ ᓕ ᓀ ᓂ ᓄ ᕄ ᕆ ᘣ */
'\0',
'\xE1', '\x95', '\x83', ' ', '\xE1', '\x93', '\x82', ' ', '\xE1', '\x93', '\x80', ' ', '\xE1', '\x95', '\x82', ' ', '\xE1', '\x93', '\x97', ' ', '\xE1', '\x93', '\x9A', ' ', '\xE1', '\x95', '\x86', ' ', '\xE1', '\x98', '\xA3', /* ᕃ ᓂ ᓀ ᕂ ᓗ ᓚ ᕆ ᘣ */
'\0',
'\xE1', '\x90', '\xAA', ' ', '\xE1', '\x99', '\x86', ' ', '\xE1', '\xA3', '\x98', ' ', '\xE1', '\x90', '\xA2', ' ', '\xE1', '\x92', '\xBE', ' ', '\xE1', '\xA3', '\x97', ' ', '\xE1', '\x94', '\x86', /* ᐪ ᙆ ᣘ ᐢ ᒾ ᣗ ᔆ */
'\0',
'\xE1', '\x99', '\x86', ' ', '\xE1', '\x97', '\xAE', ' ', '\xE1', '\x92', '\xBB', ' ', '\xE1', '\x90', '\x9E', ' ', '\xE1', '\x94', '\x86', ' ', '\xE1', '\x92', '\xA1', ' ', '\xE1', '\x92', '\xA2', ' ', '\xE1', '\x93', '\x91', /* ᙆ ᗮ ᒻ ᐞ ᔆ ᒡ ᒢ ᓑ */
'\0',
'\xF0', '\x90', '\x8A', '\xA7', ' ', '\xF0', '\x90', '\x8A', '\xAB', ' ', '\xF0', '\x90', '\x8A', '\xAC', ' ', '\xF0', '\x90', '\x8A', '\xAD', ' ', '\xF0', '\x90', '\x8A', '\xB1', ' ', '\xF0', '\x90', '\x8A', '\xBA', ' ', '\xF0', '\x90', '\x8A', '\xBC', ' ', '\xF0', '\x90', '\x8A', '\xBF', /* 𐊧 𐊫 𐊬 𐊭 𐊱 𐊺 𐊼 𐊿 */
'\0',
'\xF0', '\x90', '\x8A', '\xA3', ' ', '\xF0', '\x90', '\x8A', '\xA7', ' ', '\xF0', '\x90', '\x8A', '\xB7', ' ', '\xF0', '\x90', '\x8B', '\x80', ' ', '\xF0', '\x90', '\x8A', '\xAB', ' ', '\xF0', '\x90', '\x8A', '\xB8', ' ', '\xF0', '\x90', '\x8B', '\x89', /* 𐊣 𐊧 𐊷 𐋀 𐊫 𐊸 𐋉 */
'\0',
'\xF0', '\x91', '\x84', '\x83', ' ', '\xF0', '\x91', '\x84', '\x85', ' ', '\xF0', '\x91', '\x84', '\x89', ' ', '\xF0', '\x91', '\x84', '\x99', ' ', '\xF0', '\x91', '\x84', '\x97', /* 𑄃 𑄅 𑄉 𑄙 𑄗 */
'\0',
'\xF0', '\x91', '\x84', '\x85', ' ', '\xF0', '\x91', '\x84', '\x9B', ' ', '\xF0', '\x91', '\x84', '\x9D', ' ', '\xF0', '\x91', '\x84', '\x97', ' ', '\xF0', '\x91', '\x84', '\x93', /* 𑄅 𑄛 𑄝 𑄗 𑄓 */
'\0',
'\xF0', '\x91', '\x84', '\x96', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\x98', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\x99', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\xA4', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', ' ', '\xF0', '\x91', '\x84', '\xA5', '\xF0', '\x91', '\x84', '\xB3', '\xF0', '\x91', '\x84', '\xA2', /* 𑄖𑄳𑄢 𑄘𑄳𑄢 𑄙𑄳𑄢 𑄤𑄳𑄢 𑄥𑄳𑄢 */
'\0',
'\xE1', '\x8F', '\x86', ' ', '\xE1', '\x8E', '\xBB', ' ', '\xE1', '\x8E', '\xAC', ' ', '\xE1', '\x8F', '\x83', ' ', '\xE1', '\x8E', '\xA4', ' ', '\xE1', '\x8F', '\xA3', ' ', '\xE1', '\x8E', '\xA6', ' ', '\xE1', '\x8F', '\x95', /* Ꮖ Ꭴ Ꮳ Ꭶ */
'\0',
'\xEA', '\xAE', '\x92', ' ', '\xEA', '\xAE', '\xA4', ' ', '\xEA', '\xAE', '\xB6', ' ', '\xEA', '\xAD', '\xB4', ' ', '\xEA', '\xAD', '\xBE', ' ', '\xEA', '\xAE', '\x97', ' ', '\xEA', '\xAE', '\x9D', ' ', '\xEA', '\xAE', '\xBF', /* ꮒ ꮤ ꮶ ꭴ ꭾ ꮗ ꮝ ꮿ */
'\0',
'\xEA', '\xAE', '\x96', ' ', '\xEA', '\xAD', '\xBC', ' ', '\xEA', '\xAE', '\x93', ' ', '\xEA', '\xAE', '\xA0', ' ', '\xEA', '\xAE', '\xB3', ' ', '\xEA', '\xAD', '\xB6', ' ', '\xEA', '\xAE', '\xA5', ' ', '\xEA', '\xAE', '\xBB', /* ꮖ ꭼ ꮠ ꮳ ꭶ ꮥ ꮻ */
'\0',
'\xE1', '\x8F', '\xB8', ' ', '\xEA', '\xAE', '\x90', ' ', '\xEA', '\xAD', '\xB9', ' ', '\xEA', '\xAD', '\xBB', /* ᏸ ꮐ ꭹ ꭻ */
'\0',
'\xE2', '\xB2', '\x8C', ' ', '\xE2', '\xB2', '\x8E', ' ', '\xE2', '\xB2', '\xA0', ' ', '\xE2', '\xB3', '\x9E', ' ', '\xE2', '\xB2', '\x9E', ' ', '\xE2', '\xB2', '\x90', ' ', '\xE2', '\xB2', '\xA4', ' ', '\xE2', '\xB3', '\x8A', /* Ⲍ Ⲡ Ⳟ */
'\0',
'\xE2', '\xB3', '\x90', ' ', '\xE2', '\xB3', '\x98', ' ', '\xE2', '\xB3', '\x9E', ' ', '\xE2', '\xB2', '\x8E', ' ', '\xE2', '\xB2', '\x9E', ' ', '\xE2', '\xB2', '\x90', ' ', '\xE2', '\xB3', '\x9C', ' ', '\xE2', '\xB2', '\xB0', /* Ⳙ Ⳟ Ⲑ Ⳝ Ⲱ */
'\0',
'\xE2', '\xB2', '\x8D', ' ', '\xE2', '\xB2', '\x8F', ' ', '\xE2', '\xB2', '\xA1', ' ', '\xE2', '\xB3', '\x9F', ' ', '\xE2', '\xB2', '\x9F', ' ', '\xE2', '\xB2', '\x91', ' ', '\xE2', '\xB2', '\xA5', ' ', '\xE2', '\xB3', '\x8B', /* ⲍ ⲏ ⲡ ⳟ ⳋ */
'\0',
'\xE2', '\xB3', '\x91', ' ', '\xE2', '\xB3', '\x99', ' ', '\xE2', '\xB3', '\x9F', ' ', '\xE2', '\xB2', '\x8F', ' ', '\xE2', '\xB2', '\x9F', ' ', '\xE2', '\xB2', '\x91', ' ', '\xE2', '\xB3', '\x9D', ' ', '\xE2', '\xB3', '\x92', /* ⳑ ⳙ ⳟ ⲏ ⲑ ⳝ */
'\0',
'\xF0', '\x90', '\xA0', '\x8D', ' ', '\xF0', '\x90', '\xA0', '\x99', ' ', '\xF0', '\x90', '\xA0', '\xB3', ' ', '\xF0', '\x90', '\xA0', '\xB1', ' ', '\xF0', '\x90', '\xA0', '\x85', ' ', '\xF0', '\x90', '\xA0', '\x93', ' ', '\xF0', '\x90', '\xA0', '\xA3', ' ', '\xF0', '\x90', '\xA0', '\xA6', /* 𐠍 𐠙 𐠳 𐠱 𐠅 𐠓 𐠣 𐠦 */
'\0',
'\xF0', '\x90', '\xA0', '\x83', ' ', '\xF0', '\x90', '\xA0', '\x8A', ' ', '\xF0', '\x90', '\xA0', '\x9B', ' ', '\xF0', '\x90', '\xA0', '\xA3', ' ', '\xF0', '\x90', '\xA0', '\xB3', ' ', '\xF0', '\x90', '\xA0', '\xB5', ' ', '\xF0', '\x90', '\xA0', '\x90', /* 𐠃 𐠊 𐠛 𐠣 𐠳 𐠵 𐠐 */
'\0',
'\xF0', '\x90', '\xA0', '\x88', ' ', '\xF0', '\x90', '\xA0', '\x8F', ' ', '\xF0', '\x90', '\xA0', '\x96', /* 𐠈 𐠏 𐠖 */
'\0',
'\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\x9F', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD', /* Б В Е П З О С Э */
'\0',
'\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\xA8', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD', /* Б В Е Ш З О С Э */
'\0',
'\xD1', '\x85', ' ', '\xD0', '\xBF', ' ', '\xD0', '\xBD', ' ', '\xD1', '\x88', ' ', '\xD0', '\xB5', ' ', '\xD0', '\xB7', ' ', '\xD0', '\xBE', ' ', '\xD1', '\x81', /* х п н ш е з о с */
'\0',
'\xD1', '\x80', ' ', '\xD1', '\x83', ' ', '\xD1', '\x84', /* р у ф */
'\0',
'\xF0', '\x90', '\x90', '\x82', ' ', '\xF0', '\x90', '\x90', '\x84', ' ', '\xF0', '\x90', '\x90', '\x8B', ' ', '\xF0', '\x90', '\x90', '\x97', ' ', '\xF0', '\x90', '\x90', '\x91', /* 𐐂 𐐄 𐐋 𐐗 𐐑 */
'\0',
'\xF0', '\x90', '\x90', '\x80', ' ', '\xF0', '\x90', '\x90', '\x82', ' ', '\xF0', '\x90', '\x90', '\x84', ' ', '\xF0', '\x90', '\x90', '\x97', ' ', '\xF0', '\x90', '\x90', '\x9B', /* 𐐀 𐐂 𐐄 𐐗 𐐛 */
'\0',
'\xF0', '\x90', '\x90', '\xAA', ' ', '\xF0', '\x90', '\x90', '\xAC', ' ', '\xF0', '\x90', '\x90', '\xB3', ' ', '\xF0', '\x90', '\x90', '\xBF', ' ', '\xF0', '\x90', '\x90', '\xB9', /* 𐐪 𐐬 𐐳 𐐿 𐐹 */
'\0',
'\xF0', '\x90', '\x90', '\xA8', ' ', '\xF0', '\x90', '\x90', '\xAA', ' ', '\xF0', '\x90', '\x90', '\xAC', ' ', '\xF0', '\x90', '\x90', '\xBF', ' ', '\xF0', '\x90', '\x91', '\x83', /* 𐐨 𐐪 𐐬 𐐿 𐑃 */
'\0',
'\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xA8', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x89', ' ', '\xE0', '\xA4', '\x9B', ' ', '\xE0', '\xA4', '\x9F', ' ', '\xE0', '\xA4', '\xA0', ' ', '\xE0', '\xA4', '\xA1', /* क न म उ छ ट ठ ड */
'\0',
'\xE0', '\xA4', '\x88', ' ', '\xE0', '\xA4', '\x90', ' ', '\xE0', '\xA4', '\x93', ' ', '\xE0', '\xA4', '\x94', ' ', '\xE0', '\xA4', '\xBF', ' ', '\xE0', '\xA5', '\x80', ' ', '\xE0', '\xA5', '\x8B', ' ', '\xE0', '\xA5', '\x8C', /* ई ऐ ओ औ ि ी ो ौ */
'\0',
'\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x85', ' ', '\xE0', '\xA4', '\x86', ' ', '\xE0', '\xA4', '\xA5', ' ', '\xE0', '\xA4', '\xA7', ' ', '\xE0', '\xA4', '\xAD', ' ', '\xE0', '\xA4', '\xB6', /* क म अ आ थ ध भ श */
'\0',
'\xE0', '\xA5', '\x81', ' ', '\xE0', '\xA5', '\x83', /* ु ृ */
'\0',
'\xE1', '\x88', '\x80', ' ', '\xE1', '\x88', '\x83', ' ', '\xE1', '\x8B', '\x98', ' ', '\xE1', '\x8D', '\x90', ' ', '\xE1', '\x88', '\x9B', ' ', '\xE1', '\x89', '\xA0', ' ', '\xE1', '\x8B', '\x8B', ' ', '\xE1', '\x8B', '\x90', /* ሃ ዘ ፐ ማ በ ዋ */
'\0',
'\xE1', '\x88', '\x88', ' ', '\xE1', '\x88', '\x90', ' ', '\xE1', '\x89', '\xA0', ' ', '\xE1', '\x8B', '\x98', ' ', '\xE1', '\x88', '\x80', ' ', '\xE1', '\x88', '\xAA', ' ', '\xE1', '\x8B', '\x90', ' ', '\xE1', '\x8C', '\xA8', /* ለ ሐ በ ዘ ጨ */
'\0',
'\xE1', '\x83', '\x92', ' ', '\xE1', '\x83', '\x93', ' ', '\xE1', '\x83', '\x94', ' ', '\xE1', '\x83', '\x95', ' ', '\xE1', '\x83', '\x97', ' ', '\xE1', '\x83', '\x98', ' ', '\xE1', '\x83', '\x9D', ' ', '\xE1', '\x83', '\xA6', /* გ დ ე ვ თ ი ო ღ */
'\0',
'\xE1', '\x83', '\x90', ' ', '\xE1', '\x83', '\x96', ' ', '\xE1', '\x83', '\x9B', ' ', '\xE1', '\x83', '\xA1', ' ', '\xE1', '\x83', '\xA8', ' ', '\xE1', '\x83', '\xAB', ' ', '\xE1', '\x83', '\xAE', ' ', '\xE1', '\x83', '\x9E', /* ა ზ მ ს შ ძ ხ პ */
'\0',
'\xE1', '\x83', '\xA1', ' ', '\xE1', '\x83', '\xAE', ' ', '\xE1', '\x83', '\xA5', ' ', '\xE1', '\x83', '\x96', ' ', '\xE1', '\x83', '\x9B', ' ', '\xE1', '\x83', '\xA8', ' ', '\xE1', '\x83', '\xA9', ' ', '\xE1', '\x83', '\xAC', /* ს ხ ქ ზ მ შ ჩ წ */
'\0',
'\xE1', '\x83', '\x94', ' ', '\xE1', '\x83', '\x95', ' ', '\xE1', '\x83', '\x9F', ' ', '\xE1', '\x83', '\xA2', ' ', '\xE1', '\x83', '\xA3', ' ', '\xE1', '\x83', '\xA4', ' ', '\xE1', '\x83', '\xA5', ' ', '\xE1', '\x83', '\xA7', /* ე ვ ჟ ტ უ ფ ქ */
'\0',
'\xE1', '\x82', '\xB1', ' ', '\xE1', '\x82', '\xA7', ' ', '\xE1', '\x82', '\xB9', ' ', '\xE1', '\x82', '\xBC', ' ', '\xE1', '\x82', '\xA4', ' ', '\xE1', '\x82', '\xA5', ' ', '\xE1', '\x82', '\xB3', ' ', '\xE1', '\x82', '\xBA', /* Ⴑ Ⴇ Ⴙ Ⴜ Ⴄ Ⴅ Ⴓ Ⴚ */
'\0',
'\xE1', '\x82', '\xA4', ' ', '\xE1', '\x82', '\xA5', ' ', '\xE1', '\x82', '\xA7', ' ', '\xE1', '\x82', '\xA8', ' ', '\xE1', '\x82', '\xA6', ' ', '\xE1', '\x82', '\xB1', ' ', '\xE1', '\x82', '\xAA', ' ', '\xE1', '\x82', '\xAB', /* Ⴄ Ⴅ Ⴇ Ⴈ Ⴆ Ⴑ Ⴊ Ⴋ */
'\0',
'\xE2', '\xB4', '\x81', ' ', '\xE2', '\xB4', '\x97', ' ', '\xE2', '\xB4', '\x82', ' ', '\xE2', '\xB4', '\x84', ' ', '\xE2', '\xB4', '\x85', ' ', '\xE2', '\xB4', '\x87', ' ', '\xE2', '\xB4', '\x94', ' ', '\xE2', '\xB4', '\x96', /* ⴁ ⴗ ⴂ ⴄ ⴅ ⴇ ⴔ ⴖ */
'\0',
'\xE2', '\xB4', '\x88', ' ', '\xE2', '\xB4', '\x8C', ' ', '\xE2', '\xB4', '\x96', ' ', '\xE2', '\xB4', '\x8E', ' ', '\xE2', '\xB4', '\x83', ' ', '\xE2', '\xB4', '\x86', ' ', '\xE2', '\xB4', '\x8B', ' ', '\xE2', '\xB4', '\xA2', /* ⴈ ⴌ ⴖ ⴎ ⴃ ⴆ ⴋ ⴢ */
'\0',
'\xE2', '\xB4', '\x90', ' ', '\xE2', '\xB4', '\x91', ' ', '\xE2', '\xB4', '\x93', ' ', '\xE2', '\xB4', '\x95', ' ', '\xE2', '\xB4', '\x99', ' ', '\xE2', '\xB4', '\x9B', ' ', '\xE2', '\xB4', '\xA1', ' ', '\xE2', '\xB4', '\xA3', /* ⴐ ⴑ ⴓ ⴕ ⴙ ⴛ ⴡ ⴣ */
'\0',
'\xE2', '\xB4', '\x84', ' ', '\xE2', '\xB4', '\x85', ' ', '\xE2', '\xB4', '\x94', ' ', '\xE2', '\xB4', '\x95', ' ', '\xE2', '\xB4', '\x81', ' ', '\xE2', '\xB4', '\x82', ' ', '\xE2', '\xB4', '\x98', ' ', '\xE2', '\xB4', '\x9D', /* ⴄ ⴅ ⴔ ⴕ ⴁ ⴂ ⴘ ⴝ */
'\0',
'\xE1', '\xB2', '\x9C', ' ', '\xE1', '\xB2', '\x9F', ' ', '\xE1', '\xB2', '\xB3', ' ', '\xE1', '\xB2', '\xB8', ' ', '\xE1', '\xB2', '\x92', ' ', '\xE1', '\xB2', '\x94', ' ', '\xE1', '\xB2', '\x9D', ' ', '\xE1', '\xB2', '\xB4', /* Ნ Ჟ Ჳ Ჸ Გ Ე Ო Ჴ */
'\0',
'\xE1', '\xB2', '\x98', ' ', '\xE1', '\xB2', '\xB2', ' ', '\xE1', '\xB2', '\x9D', ' ', '\xE1', '\xB2', '\xA9', ' ', '\xE1', '\xB2', '\x9B', ' ', '\xE1', '\xB2', '\xA8', ' ', '\xE1', '\xB2', '\xAF', ' ', '\xE1', '\xB2', '\xBD', /* Ი Ჲ Ო Ჩ Მ Შ Ჯ Ჽ */
'\0',
'\xE2', '\xB0', '\x85', ' ', '\xE2', '\xB0', '\x94', ' ', '\xE2', '\xB0', '\xAA', ' ', '\xE2', '\xB0', '\x84', ' ', '\xE2', '\xB0', '\x82', ' ', '\xE2', '\xB0', '\x8A', ' ', '\xE2', '\xB0', '\xAB', ' ', '\xE2', '\xB0', '\x8B', /* Ⰵ Ⱄ Ⱚ Ⰴ Ⰲ Ⰺ Ⱛ Ⰻ */
'\0',
'\xE2', '\xB0', '\x85', ' ', '\xE2', '\xB0', '\x84', ' ', '\xE2', '\xB0', '\x82', ' ', '\xE2', '\xB0', '\xAA', ' ', '\xE2', '\xB0', '\x9E', ' ', '\xE2', '\xB0', '\xA1', ' ', '\xE2', '\xB0', '\x8A', ' ', '\xE2', '\xB0', '\x94', /* Ⰵ Ⰴ Ⰲ Ⱚ Ⱎ Ⱑ Ⰺ Ⱄ */
'\0',
'\xE2', '\xB0', '\xB5', ' ', '\xE2', '\xB1', '\x84', ' ', '\xE2', '\xB1', '\x9A', ' ', '\xE2', '\xB0', '\xB4', ' ', '\xE2', '\xB0', '\xB2', ' ', '\xE2', '\xB0', '\xBA', ' ', '\xE2', '\xB1', '\x9B', ' ', '\xE2', '\xB0', '\xBB', /* ⰵ ⱄ ⱚ ⰴ ⰲ ⰺ ⱛ ⰻ */
'\0',
'\xE2', '\xB0', '\xB5', ' ', '\xE2', '\xB0', '\xB4', ' ', '\xE2', '\xB0', '\xB2', ' ', '\xE2', '\xB1', '\x9A', ' ', '\xE2', '\xB1', '\x8E', ' ', '\xE2', '\xB1', '\x91', ' ', '\xE2', '\xB0', '\xBA', ' ', '\xE2', '\xB1', '\x84', /* ⰵ ⰴ ⰲ ⱚ ⱎ ⱑ ⰺ ⱄ */
'\0',
'\xF0', '\x90', '\x8C', '\xB2', ' ', '\xF0', '\x90', '\x8C', '\xB6', ' ', '\xF0', '\x90', '\x8D', '\x80', ' ', '\xF0', '\x90', '\x8D', '\x84', ' ', '\xF0', '\x90', '\x8C', '\xB4', ' ', '\xF0', '\x90', '\x8D', '\x83', ' ', '\xF0', '\x90', '\x8D', '\x88', ' ', '\xF0', '\x90', '\x8C', '\xBE', /* 𐌲 𐌶 𐍀 𐍄 𐌴 𐍃 𐍈 𐌾 */
'\0',
'\xF0', '\x90', '\x8C', '\xB6', ' ', '\xF0', '\x90', '\x8C', '\xB4', ' ', '\xF0', '\x90', '\x8D', '\x83', ' ', '\xF0', '\x90', '\x8D', '\x88', /* 𐌶 𐌴 𐍃 𐍈 */
'\0',
'\xCE', '\x93', ' ', '\xCE', '\x92', ' ', '\xCE', '\x95', ' ', '\xCE', '\x96', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F', ' ', '\xCE', '\xA9', /* Γ Β Ε Ζ Θ Ο Ω */
'\0',
'\xCE', '\x92', ' ', '\xCE', '\x94', ' ', '\xCE', '\x96', ' ', '\xCE', '\x9E', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F', /* Β Δ Ζ Ξ Θ Ο */
'\0',
'\xCE', '\xB2', ' ', '\xCE', '\xB8', ' ', '\xCE', '\xB4', ' ', '\xCE', '\xB6', ' ', '\xCE', '\xBB', ' ', '\xCE', '\xBE', /* β θ δ ζ λ ξ */
'\0',
'\xCE', '\xB1', ' ', '\xCE', '\xB5', ' ', '\xCE', '\xB9', ' ', '\xCE', '\xBF', ' ', '\xCF', '\x80', ' ', '\xCF', '\x83', ' ', '\xCF', '\x84', ' ', '\xCF', '\x89', /* α ε ι ο π σ τ ω */
'\0',
'\xCE', '\xB2', ' ', '\xCE', '\xB3', ' ', '\xCE', '\xB7', ' ', '\xCE', '\xBC', ' ', '\xCF', '\x81', ' ', '\xCF', '\x86', ' ', '\xCF', '\x87', ' ', '\xCF', '\x88', /* β γ η μ ρ φ χ ψ */
'\0',
'\xE0', '\xAA', '\xA4', ' ', '\xE0', '\xAA', '\xA8', ' ', '\xE0', '\xAA', '\x8B', ' ', '\xE0', '\xAA', '\x8C', ' ', '\xE0', '\xAA', '\x9B', ' ', '\xE0', '\xAA', '\x9F', ' ', '\xE0', '\xAA', '\xB0', ' ', '\xE0', '\xAB', '\xA6', /* ત ન ઋ ઌ છ ટ ર */
'\0',
'\xE0', '\xAA', '\x96', ' ', '\xE0', '\xAA', '\x97', ' ', '\xE0', '\xAA', '\x98', ' ', '\xE0', '\xAA', '\x9E', ' ', '\xE0', '\xAA', '\x87', ' ', '\xE0', '\xAA', '\x88', ' ', '\xE0', '\xAA', '\xA0', ' ', '\xE0', '\xAA', '\x9C', /* ખ ગ ઘ ઞ ઇ ઈ ઠ જ */
'\0',
'\xE0', '\xAA', '\x88', ' ', '\xE0', '\xAA', '\x8A', ' ', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAB', '\x80', ' ', '\xE0', '\xAA', '\xB2', '\xE0', '\xAB', '\x80', ' ', '\xE0', '\xAA', '\xB6', '\xE0', '\xAB', '\x8D', '\xE0', '\xAA', '\x9A', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAA', '\x9C', '\xE0', '\xAA', '\xBF', ' ', '\xE0', '\xAA', '\xB8', '\xE0', '\xAB', '\x80', /* ઈ ઊ િ ી લી શ્ચિ જિ સી */
'\0',
'\xE0', '\xAB', '\x81', ' ', '\xE0', '\xAB', '\x83', ' ', '\xE0', '\xAB', '\x84', ' ', '\xE0', '\xAA', '\x96', '\xE0', '\xAB', '\x81', ' ', '\xE0', '\xAA', '\x9B', '\xE0', '\xAB', '\x83', ' ', '\xE0', '\xAA', '\x9B', '\xE0', '\xAB', '\x84', /* ુ ૃ ૄ ખુ છૃ છૄ */
'\0',
'\xE0', '\xAB', '\xA6', ' ', '\xE0', '\xAB', '\xA7', ' ', '\xE0', '\xAB', '\xA8', ' ', '\xE0', '\xAB', '\xA9', ' ', '\xE0', '\xAB', '\xAD', /* ૧ ૨ ૩ ૭ */
'\0',
'\xE0', '\xA8', '\x95', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x99', ' ', '\xE0', '\xA8', '\x9A', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA4', ' ', '\xE0', '\xA8', '\xA7', ' ', '\xE0', '\xA8', '\xB8', /* ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ */
'\0',
'\xE0', '\xA8', '\x95', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x99', ' ', '\xE0', '\xA8', '\x9A', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA4', ' ', '\xE0', '\xA8', '\xA7', ' ', '\xE0', '\xA8', '\xB8', /* ਕ ਗ ਙ ਚ ਜ ਤ ਧ ਸ */
'\0',
'\xE0', '\xA8', '\x87', ' ', '\xE0', '\xA8', '\x88', ' ', '\xE0', '\xA8', '\x89', ' ', '\xE0', '\xA8', '\x8F', ' ', '\xE0', '\xA8', '\x93', ' ', '\xE0', '\xA9', '\xB3', ' ', '\xE0', '\xA8', '\xBF', ' ', '\xE0', '\xA9', '\x80', /* ਇ ਈ ਉ ਏ ਓ ੳ ਿ ੀ */
'\0',
'\xE0', '\xA8', '\x85', ' ', '\xE0', '\xA8', '\x8F', ' ', '\xE0', '\xA8', '\x93', ' ', '\xE0', '\xA8', '\x97', ' ', '\xE0', '\xA8', '\x9C', ' ', '\xE0', '\xA8', '\xA0', ' ', '\xE0', '\xA8', '\xB0', ' ', '\xE0', '\xA8', '\xB8', /* ਅ ਏ ਓ ਗ ਜ ਠ ਰ ਸ */
'\0',
'\xE0', '\xA9', '\xA6', ' ', '\xE0', '\xA9', '\xA7', ' ', '\xE0', '\xA9', '\xA8', ' ', '\xE0', '\xA9', '\xA9', ' ', '\xE0', '\xA9', '\xAD', /* ੨ ੩ ੭ */
'\0',
'\xD7', '\x91', ' ', '\xD7', '\x93', ' ', '\xD7', '\x94', ' ', '\xD7', '\x97', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1', /* ב ד ה ח ך כ ם ס */
'\0',
'\xD7', '\x91', ' ', '\xD7', '\x98', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1', ' ', '\xD7', '\xA6', /* ב ט כ ם ס צ */
'\0',
'\xD7', '\xA7', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9F', ' ', '\xD7', '\xA3', ' ', '\xD7', '\xA5', /* ק ך ן ף ץ */
'\0',
'\xE0', '\xB2', '\x87', ' ', '\xE0', '\xB2', '\x8A', ' ', '\xE0', '\xB2', '\x90', ' ', '\xE0', '\xB2', '\xA3', ' ', '\xE0', '\xB2', '\xB8', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xA8', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xA6', '\xE0', '\xB2', '\xBE', ' ', '\xE0', '\xB2', '\xB0', '\xE0', '\xB2', '\xBE', /* ಇ ಊ ಐ ಣ ಸಾ ನಾ ದಾ ರಾ */
'\0',
'\xE0', '\xB2', '\x85', ' ', '\xE0', '\xB2', '\x89', ' ', '\xE0', '\xB2', '\x8E', ' ', '\xE0', '\xB2', '\xB2', ' ', '\xE0', '\xB3', '\xA6', ' ', '\xE0', '\xB3', '\xA8', ' ', '\xE0', '\xB3', '\xAC', ' ', '\xE0', '\xB3', '\xAD', /* ಅ ಉ ಎ ಲ ೨ ೬ ೭ */
'\0',
'\xEA', '\xA4', '\x85', ' ', '\xEA', '\xA4', '\x8F', ' ', '\xEA', '\xA4', '\x81', ' ', '\xEA', '\xA4', '\x8B', ' ', '\xEA', '\xA4', '\x80', ' ', '\xEA', '\xA4', '\x8D', /* ꤅ ꤏ ꤁ ꤋ ꤀ ꤍ */
'\0',
'\xEA', '\xA4', '\x88', ' ', '\xEA', '\xA4', '\x98', ' ', '\xEA', '\xA4', '\x80', ' ', '\xEA', '\xA4', '\x8D', ' ', '\xEA', '\xA4', '\xA2', /* ꤈ ꤘ ꤀ ꤍ ꤢ */
'\0',
'\xEA', '\xA4', '\x96', ' ', '\xEA', '\xA4', '\xA1', /* ꤖ ꤡ */
'\0',
'\xEA', '\xA4', '\x91', ' ', '\xEA', '\xA4', '\x9C', ' ', '\xEA', '\xA4', '\x9E', /* ꤑ ꤜ ꤞ */
'\0',
'\xEA', '\xA4', '\x91', '\xEA', '\xA4', '\xAC', ' ', '\xEA', '\xA4', '\x9C', '\xEA', '\xA4', '\xAD', ' ', '\xEA', '\xA4', '\x94', '\xEA', '\xA4', '\xAC', /* ꤑ꤬ ꤜ꤭ ꤔ꤬ */
'\0',
'\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x91', ' ', '\xE1', '\x9E', '\x93', ' ', '\xE1', '\x9E', '\xA7', ' ', '\xE1', '\x9E', '\xA9', ' ', '\xE1', '\x9E', '\xB6', /* ខ ទ ន ឧ ឩ ា */
'\0',
'\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x80', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x82', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x90', /* ក្ក ក្ខ ក្គ ក្ថ */
'\0',
'\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x83', ' ', '\xE1', '\x9E', '\x85', ' ', '\xE1', '\x9E', '\x8B', ' ', '\xE1', '\x9E', '\x94', ' ', '\xE1', '\x9E', '\x98', ' ', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xB2', /* ខ ឃ ច ឋ ប ម យ ឲ */
'\0',
'\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', ' ', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\xB2', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xA2', '\xE1', '\x9E', '\xBF', /* ត្រ រៀ ឲ្យ អឿ */
'\0',
'\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x83', ' ', '\xE1', '\x9E', '\x84', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x85', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9E', '\xBF', ' ', '\xE1', '\x9E', '\x9B', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9E', '\xBF', /* ន្ត្រៃ ង្ខ្យ ក្បៀ ច្រៀ ន្តឿ ល្បឿ */
'\0',
'\xE1', '\xA7', '\xA0', ' ', '\xE1', '\xA7', '\xA1', /* ᧠ ᧡ */
'\0',
'\xE1', '\xA7', '\xB6', ' ', '\xE1', '\xA7', '\xB9', /* ᧶ ᧹ */
'\0',
'\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\x94', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\xA1', ' ', '\xE0', '\xBA', '\xA5', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\x87', /* າ ດ ອ ມ ລ ວ ຣ ງ */
'\0',
'\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\x9A', ' ', '\xE0', '\xBA', '\x8D', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\xAE', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA2', /* າ ອ ບ ຍ ຣ ຮ ວ ຢ */
'\0',
'\xE0', '\xBA', '\x9B', ' ', '\xE0', '\xBA', '\xA2', ' ', '\xE0', '\xBA', '\x9F', ' ', '\xE0', '\xBA', '\x9D', /* ປ ຢ ຟ ຝ */
'\0',
'\xE0', '\xBB', '\x82', ' ', '\xE0', '\xBB', '\x84', ' ', '\xE0', '\xBB', '\x83', /* ໂ ໄ ໃ */
'\0',
'\xE0', '\xBA', '\x87', ' ', '\xE0', '\xBA', '\x8A', ' ', '\xE0', '\xBA', '\x96', ' ', '\xE0', '\xBA', '\xBD', ' ', '\xE0', '\xBB', '\x86', ' ', '\xE0', '\xBA', '\xAF', /* ງ ຊ ຖ ຽ ໆ ຯ */
'\0',
'T', ' ', 'H', ' ', 'E', ' ', 'Z', ' ', 'O', ' ', 'C', ' ', 'Q', ' ', 'S', /* T H E Z O C Q S */
'\0',
'H', ' ', 'E', ' ', 'Z', ' ', 'L', ' ', 'O', ' ', 'C', ' ', 'U', ' ', 'S', /* H E Z L O C U S */
'\0',
'f', ' ', 'i', ' ', 'j', ' ', 'k', ' ', 'd', ' ', 'b', ' ', 'h', /* f i j k d b h */
'\0',
'u', ' ', 'v', ' ', 'x', ' ', 'z', ' ', 'o', ' ', 'e', ' ', 's', ' ', 'c', /* u v x z o e s c */
'\0',
'n', ' ', 'r', ' ', 'x', ' ', 'z', ' ', 'o', ' ', 'e', ' ', 's', ' ', 'c', /* n r x z o e s c */
'\0',
'p', ' ', 'q', ' ', 'g', ' ', 'j', ' ', 'y', /* p q g j y */
'\0',
'\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x85', ' ', '\xE2', '\x82', '\x87', ' ', '\xE2', '\x82', '\x88', /* ₀ ₃ ₅ ₇ ₈ */
'\0',
'\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x81', ' ', '\xE2', '\x82', '\x82', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x88', /* ₀ ₁ ₂ ₃ ₈ */
'\0',
'\xE1', '\xB5', '\xA2', ' ', '\xE2', '\xB1', '\xBC', ' ', '\xE2', '\x82', '\x95', ' ', '\xE2', '\x82', '\x96', ' ', '\xE2', '\x82', '\x97', /* ᵢ ⱼ ₕ ₖ ₗ */
'\0',
'\xE2', '\x82', '\x90', ' ', '\xE2', '\x82', '\x91', ' ', '\xE2', '\x82', '\x92', ' ', '\xE2', '\x82', '\x93', ' ', '\xE2', '\x82', '\x99', ' ', '\xE2', '\x82', '\x9B', ' ', '\xE1', '\xB5', '\xA5', ' ', '\xE1', '\xB5', '\xA4', ' ', '\xE1', '\xB5', '\xA3', /* ₐ ₑ ₒ ₓ ₙ ₛ ᵥ ᵤ ᵣ */
'\0',
'\xE1', '\xB5', '\xA6', ' ', '\xE1', '\xB5', '\xA7', ' ', '\xE1', '\xB5', '\xA8', ' ', '\xE1', '\xB5', '\xA9', ' ', '\xE2', '\x82', '\x9A', /* ᵦ ᵧ ᵨ ᵩ ₚ */
'\0',
'\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB3', ' ', '\xE2', '\x81', '\xB5', ' ', '\xE2', '\x81', '\xB7', ' ', '\xE1', '\xB5', '\x80', ' ', '\xE1', '\xB4', '\xB4', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xBC', /* ⁰ ³ ⁵ ⁷ ᵀ ᴴ ᴱ ᴼ */
'\0',
'\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB9', ' ', '\xC2', '\xB2', ' ', '\xC2', '\xB3', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xB8', ' ', '\xE1', '\xB4', '\xBC', ' ', '\xE1', '\xB5', '\x81', /* ⁰ ¹ ² ³ ᴱ ᴸ ᴼ ᵁ */
'\0',
'\xE1', '\xB5', '\x87', ' ', '\xE1', '\xB5', '\x88', ' ', '\xE1', '\xB5', '\x8F', ' ', '\xCA', '\xB0', ' ', '\xCA', '\xB2', ' ', '\xE1', '\xB6', '\xA0', ' ', '\xE2', '\x81', '\xB1', /* ᵇ ᵈ ᵏ ʰ ʲ ᶠ ⁱ */
'\0',
'\xE1', '\xB5', '\x89', ' ', '\xE1', '\xB5', '\x92', ' ', '\xCA', '\xB3', ' ', '\xCB', '\xA2', ' ', '\xCB', '\xA3', ' ', '\xE1', '\xB6', '\x9C', ' ', '\xE1', '\xB6', '\xBB', /* ᵉ ᵒ ʳ ˢ ˣ ᶜ ᶻ */
'\0',
'\xE1', '\xB5', '\x96', ' ', '\xCA', '\xB8', ' ', '\xE1', '\xB5', '\x8D', /* ᵖ ʸ ᵍ */
'\0',
'\xEA', '\x93', '\xA1', ' ', '\xEA', '\x93', '\xA7', ' ', '\xEA', '\x93', '\xB1', ' ', '\xEA', '\x93', '\xB6', ' ', '\xEA', '\x93', '\xA9', ' ', '\xEA', '\x93', '\x9A', ' ', '\xEA', '\x93', '\xB5', ' ', '\xEA', '\x93', '\xB3', /* ꓱ ꓶ ꓩ */
'\0',
'\xEA', '\x93', '\x95', ' ', '\xEA', '\x93', '\x9C', ' ', '\xEA', '\x93', '\x9E', ' ', '\xEA', '\x93', '\xA1', ' ', '\xEA', '\x93', '\x9B', ' ', '\xEA', '\x93', '\xA2', ' ', '\xEA', '\x93', '\xB3', ' ', '\xEA', '\x93', '\xB4', /* ꓕ */
'\0',
'\xE0', '\xB4', '\x92', ' ', '\xE0', '\xB4', '\x9F', ' ', '\xE0', '\xB4', '\xA0', ' ', '\xE0', '\xB4', '\xB1', ' ', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xAA', ' ', '\xE0', '\xB4', '\x9A', '\xE0', '\xB5', '\x8D', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xAA', '\xE0', '\xB5', '\x8D', '\xE0', '\xB4', '\xAA', /* ഒ ട റ ച പ ച്ച പ്പ */
'\0',
'\xE0', '\xB4', '\x9F', ' ', '\xE0', '\xB4', '\xA0', ' ', '\xE0', '\xB4', '\xA7', ' ', '\xE0', '\xB4', '\xB6', ' ', '\xE0', '\xB4', '\x98', ' ', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xA5', ' ', '\xE0', '\xB4', '\xB2', /* ട ധ ശ ഘ ച ഥ ല */
'\0',
'\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x9F', /* 𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹟 */
'\0',
'\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x92', ' ', '\xF0', '\x96', '\xB9', '\x93', /* 𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹒 𖹓 */
'\0',
'\xF0', '\x96', '\xB9', '\xA4', ' ', '\xF0', '\x96', '\xB9', '\xAC', ' ', '\xF0', '\x96', '\xB9', '\xA7', ' ', '\xF0', '\x96', '\xB9', '\xB4', ' ', '\xF0', '\x96', '\xB9', '\xB6', ' ', '\xF0', '\x96', '\xB9', '\xBE', /* 𖹤 𖹬 𖹧 𖹴 𖹶 𖹾 */
'\0',
'\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB9', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAE', /* 𖹠 𖹡 𖹢 𖹹 𖹳 𖹮 */
'\0',
'\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAD', ' ', '\xF0', '\x96', '\xB9', '\xBD', /* 𖹠 𖹡 𖹢 𖹳 𖹭 𖹽 */
'\0',
'\xF0', '\x96', '\xB9', '\xA5', ' ', '\xF0', '\x96', '\xB9', '\xA8', ' ', '\xF0', '\x96', '\xB9', '\xA9', /* 𖹥 𖹨 𖹩 */
'\0',
'\xF0', '\x96', '\xBA', '\x80', ' ', '\xF0', '\x96', '\xBA', '\x85', ' ', '\xF0', '\x96', '\xBA', '\x88', ' ', '\xF0', '\x96', '\xBA', '\x84', ' ', '\xF0', '\x96', '\xBA', '\x8D', /* 𖺀 𖺅 𖺈 𖺄 𖺍 */
'\0',
'\xE1', '\xA0', '\xB3', ' ', '\xE1', '\xA0', '\xB4', ' ', '\xE1', '\xA0', '\xB6', ' ', '\xE1', '\xA0', '\xBD', ' ', '\xE1', '\xA1', '\x82', ' ', '\xE1', '\xA1', '\x8A', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xA1', '\xE2', '\x80', '\x8D', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xB3', '\xE2', '\x80', '\x8D', /* ᠳ ᠴ ᠶ ᠽ ᡂ ᡊ ‍ᡡ‍ ‍ᡳ‍ */
'\0',
'\xE1', '\xA1', '\x83', /* ᡃ */
'\0',
'\xE1', '\x80', '\x81', ' ', '\xE1', '\x80', '\x82', ' ', '\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\xA5', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B', /* ခ ဂ င ဒ ၥ ၊ ။ */
'\0',
'\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x8E', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x95', ' ', '\xE1', '\x80', '\x97', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B', /* င ဎ ဒ ပ ဗ ၊ ။ */
'\0',
'\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xBC', ' ', '\xE1', '\x81', '\x8D', ' ', '\xE1', '\x81', '\x8F', ' ', '\xE1', '\x81', '\x86', ' ', '\xE1', '\x80', '\xAB', ' ', '\xE1', '\x80', '\xAD', /* ဩ ြ ၍ ၏ ၆ ါ ိ */
'\0',
'\xE1', '\x80', '\x89', ' ', '\xE1', '\x80', '\x8A', ' ', '\xE1', '\x80', '\xA5', ' ', '\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xA8', ' ', '\xE1', '\x81', '\x82', ' ', '\xE1', '\x81', '\x85', ' ', '\xE1', '\x81', '\x89', /* ဉ ည ဥ ဩ ဨ ၂ ၅ ၉ */
'\0',
'\xDF', '\x90', ' ', '\xDF', '\x89', ' ', '\xDF', '\x92', ' ', '\xDF', '\x9F', ' ', '\xDF', '\x96', ' ', '\xDF', '\x9C', ' ', '\xDF', '\xA0', ' ', '\xDF', '\xA5', /* ߐ ߉ ߒ ߟ ߖ ߜ ߠ ߥ */
'\0',
'\xDF', '\x80', ' ', '\xDF', '\x98', ' ', '\xDF', '\xA1', ' ', '\xDF', '\xA0', ' ', '\xDF', '\xA5', /* ߀ ߘ ߡ ߠ ߥ */
'\0',
'\xDF', '\x8F', ' ', '\xDF', '\x9B', ' ', '\xDF', '\x8B', /* ߏ ߛ ߋ */
'\0',
'\xDF', '\x8E', ' ', '\xDF', '\x8F', ' ', '\xDF', '\x9B', ' ', '\xDF', '\x8B', /* ߎ ߏ ߛ ߋ */
'\0',
'\xE1', '\xB1', '\x9B', ' ', '\xE1', '\xB1', '\x9C', ' ', '\xE1', '\xB1', '\x9D', ' ', '\xE1', '\xB1', '\xA1', ' ', '\xE1', '\xB1', '\xA2', ' ', '\xE1', '\xB1', '\xA5', /* ᱛ ᱜ ᱝ ᱡ ᱢ ᱥ */
'\0',
'\xF0', '\x90', '\xB0', '\x97', ' ', '\xF0', '\x90', '\xB0', '\x98', ' ', '\xF0', '\x90', '\xB0', '\xA7', /* 𐰗 𐰘 𐰧 */
'\0',
'\xF0', '\x90', '\xB0', '\x89', ' ', '\xF0', '\x90', '\xB0', '\x97', ' ', '\xF0', '\x90', '\xB0', '\xA6', ' ', '\xF0', '\x90', '\xB0', '\xA7', /* 𐰉 𐰗 𐰦 𐰧 */
'\0',
'\xF0', '\x90', '\x92', '\xBE', ' ', '\xF0', '\x90', '\x93', '\x8D', ' ', '\xF0', '\x90', '\x93', '\x92', ' ', '\xF0', '\x90', '\x93', '\x93', ' ', '\xF0', '\x90', '\x92', '\xBB', ' ', '\xF0', '\x90', '\x93', '\x82', ' ', '\xF0', '\x90', '\x92', '\xB5', ' ', '\xF0', '\x90', '\x93', '\x86', /* 𐒾 𐓍 𐓒 𐓓 𐒻 𐓂 𐒵 𐓆 */
'\0',
'\xF0', '\x90', '\x92', '\xB0', ' ', '\xF0', '\x90', '\x93', '\x8D', ' ', '\xF0', '\x90', '\x93', '\x82', ' ', '\xF0', '\x90', '\x92', '\xBF', ' ', '\xF0', '\x90', '\x93', '\x8E', ' ', '\xF0', '\x90', '\x92', '\xB9', /* 𐒰 𐓍 𐓂 𐒿 𐓎 𐒹 */
'\0',
'\xF0', '\x90', '\x92', '\xBC', ' ', '\xF0', '\x90', '\x92', '\xBD', ' ', '\xF0', '\x90', '\x92', '\xBE', /* 𐒼 𐒽 𐒾 */
'\0',
'\xF0', '\x90', '\x93', '\xB5', ' ', '\xF0', '\x90', '\x93', '\xB6', ' ', '\xF0', '\x90', '\x93', '\xBA', ' ', '\xF0', '\x90', '\x93', '\xBB', ' ', '\xF0', '\x90', '\x93', '\x9D', ' ', '\xF0', '\x90', '\x93', '\xA3', ' ', '\xF0', '\x90', '\x93', '\xAA', ' ', '\xF0', '\x90', '\x93', '\xAE', /* 𐓵 𐓶 𐓺 𐓻 𐓝 𐓣 𐓪 𐓮 */
'\0',
'\xF0', '\x90', '\x93', '\x98', ' ', '\xF0', '\x90', '\x93', '\x9A', ' ', '\xF0', '\x90', '\x93', '\xA3', ' ', '\xF0', '\x90', '\x93', '\xB5', ' ', '\xF0', '\x90', '\x93', '\xA1', ' ', '\xF0', '\x90', '\x93', '\xA7', ' ', '\xF0', '\x90', '\x93', '\xAA', ' ', '\xF0', '\x90', '\x93', '\xB6', /* 𐓘 𐓚 𐓣 𐓵 𐓡 𐓧 𐓪 𐓶 */
'\0',
'\xF0', '\x90', '\x93', '\xA4', ' ', '\xF0', '\x90', '\x93', '\xA6', ' ', '\xF0', '\x90', '\x93', '\xB8', ' ', '\xF0', '\x90', '\x93', '\xB9', ' ', '\xF0', '\x90', '\x93', '\x9B', /* 𐓤 𐓦 𐓸 𐓹 𐓛 */
'\0',
'\xF0', '\x90', '\x93', '\xA4', ' ', '\xF0', '\x90', '\x93', '\xA5', ' ', '\xF0', '\x90', '\x93', '\xA6', /* 𐓤 𐓥 𐓦 */
'\0',
'\xF0', '\x90', '\x92', '\x86', ' ', '\xF0', '\x90', '\x92', '\x89', ' ', '\xF0', '\x90', '\x92', '\x90', ' ', '\xF0', '\x90', '\x92', '\x92', ' ', '\xF0', '\x90', '\x92', '\x98', ' ', '\xF0', '\x90', '\x92', '\x9B', ' ', '\xF0', '\x90', '\x92', '\xA0', ' ', '\xF0', '\x90', '\x92', '\xA3', /* 𐒆 𐒉 𐒐 𐒒 𐒘 𐒛 𐒠 𐒣 */
'\0',
'\xF0', '\x90', '\x92', '\x80', ' ', '\xF0', '\x90', '\x92', '\x82', ' ', '\xF0', '\x90', '\x92', '\x86', ' ', '\xF0', '\x90', '\x92', '\x88', ' ', '\xF0', '\x90', '\x92', '\x8A', ' ', '\xF0', '\x90', '\x92', '\x92', ' ', '\xF0', '\x90', '\x92', '\xA0', ' ', '\xF0', '\x90', '\x92', '\xA9', /* 𐒀 𐒂 𐒆 𐒈 𐒊 𐒒 𐒠 𐒩 */
'\0',
'\xF0', '\x90', '\xB4', '\x83', ' ', '\xF0', '\x90', '\xB4', '\x80', ' ', '\xF0', '\x90', '\xB4', '\x86', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', /* 𐴃 𐴀 𐴆 𐴖 𐴕 */
'\0',
'\xF0', '\x90', '\xB4', '\x94', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', ' ', '\xF0', '\x90', '\xB4', '\x91', ' ', '\xF0', '\x90', '\xB4', '\x90', /* 𐴔 𐴖 𐴕 𐴑 𐴐 */
'\0',
'\xD9', '\x80', /* ـ */
'\0',
'\xEA', '\xA2', '\x9C', ' ', '\xEA', '\xA2', '\x9E', ' ', '\xEA', '\xA2', '\xB3', ' ', '\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\x96', ' ', '\xEA', '\xA2', '\x92', ' ', '\xEA', '\xA2', '\x9D', ' ', '\xEA', '\xA2', '\x9B', /* ꢜ ꢞ ꢳ ꢂ ꢖ ꢒ ꢝ ꢛ */
'\0',
'\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\xA8', ' ', '\xEA', '\xA2', '\xBA', ' ', '\xEA', '\xA2', '\xA4', ' ', '\xEA', '\xA2', '\x8E', /* ꢂ ꢨ ꢺ ꢤ ꢎ */
'\0',
'\xF0', '\x90', '\x91', '\x95', ' ', '\xF0', '\x90', '\x91', '\x99', /* 𐑕 𐑙 */
'\0',
'\xF0', '\x90', '\x91', '\x94', ' ', '\xF0', '\x90', '\x91', '\x96', ' ', '\xF0', '\x90', '\x91', '\x97', ' ', '\xF0', '\x90', '\x91', '\xB9', ' ', '\xF0', '\x90', '\x91', '\xBB', /* 𐑔 𐑖 𐑗 𐑹 𐑻 */
'\0',
'\xF0', '\x90', '\x91', '\x9F', ' ', '\xF0', '\x90', '\x91', '\xA3', /* 𐑟 𐑣 */
'\0',
'\xF0', '\x90', '\x91', '\xB1', ' ', '\xF0', '\x90', '\x91', '\xB2', ' ', '\xF0', '\x90', '\x91', '\xB3', ' ', '\xF0', '\x90', '\x91', '\xB4', ' ', '\xF0', '\x90', '\x91', '\xB8', ' ', '\xF0', '\x90', '\x91', '\xBA', ' ', '\xF0', '\x90', '\x91', '\xBC', /* 𐑱 𐑲 𐑳 𐑴 𐑸 𐑺 𐑼 */
'\0',
'\xF0', '\x90', '\x91', '\xB4', ' ', '\xF0', '\x90', '\x91', '\xBB', ' ', '\xF0', '\x90', '\x91', '\xB9', /* 𐑴 𐑻 𐑹 */
'\0',
'\xE0', '\xB6', '\x89', ' ', '\xE0', '\xB6', '\x9A', ' ', '\xE0', '\xB6', '\x9D', ' ', '\xE0', '\xB6', '\xB3', ' ', '\xE0', '\xB6', '\xB4', ' ', '\xE0', '\xB6', '\xBA', ' ', '\xE0', '\xB6', '\xBD', ' ', '\xE0', '\xB7', '\x86', /* ඉ ක ඝ ඳ ප ය ල ෆ */
'\0',
'\xE0', '\xB6', '\x91', ' ', '\xE0', '\xB6', '\x94', ' ', '\xE0', '\xB6', '\x9D', ' ', '\xE0', '\xB6', '\xA2', ' ', '\xE0', '\xB6', '\xA7', ' ', '\xE0', '\xB6', '\xAE', ' ', '\xE0', '\xB6', '\xB0', ' ', '\xE0', '\xB6', '\xBB', /* එ ඔ ඝ ජ ට ථ ධ ර */
'\0',
'\xE0', '\xB6', '\xAF', ' ', '\xE0', '\xB6', '\xB3', ' ', '\xE0', '\xB6', '\x8B', ' ', '\xE0', '\xB6', '\xBD', ' ', '\xE0', '\xB6', '\xAD', '\xE0', '\xB7', '\x96', ' ', '\xE0', '\xB6', '\xAD', '\xE0', '\xB7', '\x94', ' ', '\xE0', '\xB6', '\xB6', '\xE0', '\xB7', '\x94', ' ', '\xE0', '\xB6', '\xAF', '\xE0', '\xB7', '\x94', /* ද ඳ උ ල තූ තු බු දු */
'\0',
'\xE1', '\xAE', '\x8B', ' ', '\xE1', '\xAE', '\x9E', ' ', '\xE1', '\xAE', '\xAE', ' ', '\xE1', '\xAE', '\xBD', ' ', '\xE1', '\xAE', '\xB0', ' ', '\xE1', '\xAE', '\x88', /* ᮋ ᮞ ᮮ ᮽ ᮰ ᮈ */
'\0',
'\xE1', '\xAE', '\x84', ' ', '\xE1', '\xAE', '\x94', ' ', '\xE1', '\xAE', '\x95', ' ', '\xE1', '\xAE', '\x97', ' ', '\xE1', '\xAE', '\xB0', ' ', '\xE1', '\xAE', '\x86', ' ', '\xE1', '\xAE', '\x88', ' ', '\xE1', '\xAE', '\x89', /* ᮄ ᮔ ᮕ ᮗ ᮰ ᮆ ᮈ ᮉ */
'\0',
'\xE1', '\xAE', '\xBC', ' ', '\xE1', '\xB3', '\x84', /* ᮼ ᳄ */
'\0',
'\xEA', '\xAA', '\x86', ' ', '\xEA', '\xAA', '\x94', ' ', '\xEA', '\xAA', '\x92', ' ', '\xEA', '\xAA', '\x96', ' ', '\xEA', '\xAA', '\xAB', /* ꪆ ꪔ ꪒ ꪖ ꪫ */
'\0',
'\xEA', '\xAA', '\x89', ' ', '\xEA', '\xAA', '\xAB', ' ', '\xEA', '\xAA', '\xAE', /* ꪉ ꪫ ꪮ */
'\0',
'\xE0', '\xAE', '\x89', ' ', '\xE0', '\xAE', '\x92', ' ', '\xE0', '\xAE', '\x93', ' ', '\xE0', '\xAE', '\xB1', ' ', '\xE0', '\xAE', '\x88', ' ', '\xE0', '\xAE', '\x95', ' ', '\xE0', '\xAE', '\x99', ' ', '\xE0', '\xAE', '\x9A', /* உ ஒ ஓ ற ஈ க ங ச */
'\0',
'\xE0', '\xAE', '\x95', ' ', '\xE0', '\xAE', '\x9A', ' ', '\xE0', '\xAE', '\xB2', ' ', '\xE0', '\xAE', '\xB6', ' ', '\xE0', '\xAE', '\x89', ' ', '\xE0', '\xAE', '\x99', ' ', '\xE0', '\xAE', '\x9F', ' ', '\xE0', '\xAE', '\xAA', /* க ச ல ஶ உ ங ட ப */
'\0',
'\xE0', '\xB0', '\x87', ' ', '\xE0', '\xB0', '\x8C', ' ', '\xE0', '\xB0', '\x99', ' ', '\xE0', '\xB0', '\x9E', ' ', '\xE0', '\xB0', '\xA3', ' ', '\xE0', '\xB0', '\xB1', ' ', '\xE0', '\xB1', '\xAF', /* ఇ ఌ ఙ ఞ ణ ఱ ౯ */
'\0',
'\xE0', '\xB0', '\x85', ' ', '\xE0', '\xB0', '\x95', ' ', '\xE0', '\xB0', '\x9A', ' ', '\xE0', '\xB0', '\xB0', ' ', '\xE0', '\xB0', '\xBD', ' ', '\xE0', '\xB1', '\xA8', ' ', '\xE0', '\xB1', '\xAC', /* అ క చ ర ఽ ౨ ౬ */
'\0',
'\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB9', '\x80', ' ', '\xE0', '\xB9', '\x81', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\x81', ' ', '\xE0', '\xB8', '\xB2', /* บ เ แ อ ก า */
'\0',
'\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\xA9', ' ', '\xE0', '\xB8', '\xAF', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\xA2', ' ', '\xE0', '\xB8', '\xAE', /* บ ป ษ ฯ อ ย ฮ */
'\0',
'\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\x9D', ' ', '\xE0', '\xB8', '\x9F', /* ป ฝ ฟ */
'\0',
'\xE0', '\xB9', '\x82', ' ', '\xE0', '\xB9', '\x83', ' ', '\xE0', '\xB9', '\x84', /* โ ใ ไ */
'\0',
'\xE0', '\xB8', '\x8E', ' ', '\xE0', '\xB8', '\x8F', ' ', '\xE0', '\xB8', '\xA4', ' ', '\xE0', '\xB8', '\xA6', /* ฎ ฏ ฤ ฦ */
'\0',
'\xE0', '\xB8', '\x8D', ' ', '\xE0', '\xB8', '\x90', /* ญ ฐ */
'\0',
'\xE0', '\xB9', '\x90', ' ', '\xE0', '\xB9', '\x91', ' ', '\xE0', '\xB9', '\x93', /* ๑ ๓ */
'\0',
'\xE2', '\xB5', '\x94', ' ', '\xE2', '\xB5', '\x99', ' ', '\xE2', '\xB5', '\x9B', ' ', '\xE2', '\xB5', '\x9E', ' ', '\xE2', '\xB4', '\xB5', ' ', '\xE2', '\xB4', '\xBC', ' ', '\xE2', '\xB4', '\xB9', ' ', '\xE2', '\xB5', '\x8E', /* ⵙ ⵛ ⵞ ⴵ ⴼ ⵎ */
'\0',
'\xEA', '\x97', '\x8D', ' ', '\xEA', '\x98', '\x96', ' ', '\xEA', '\x98', '\x99', ' ', '\xEA', '\x98', '\x9C', ' ', '\xEA', '\x96', '\x9C', ' ', '\xEA', '\x96', '\x9D', ' ', '\xEA', '\x94', '\x85', ' ', '\xEA', '\x95', '\xA2', /* ꗍ ꘖ ꘙ ꘜ ꖜ ꖝ ꔅ ꕢ */
'\0',
'\xEA', '\x97', '\x8D', ' ', '\xEA', '\x98', '\x96', ' ', '\xEA', '\x98', '\x99', ' ', '\xEA', '\x97', '\x9E', ' ', '\xEA', '\x94', '\x85', ' ', '\xEA', '\x95', '\xA2', ' ', '\xEA', '\x96', '\x9C', ' ', '\xEA', '\x94', '\x86', /* ꗍ ꘖ ꘙ ꗞ ꔅ ꕢ ꖜ ꔆ */
#ifdef AF_CONFIG_OPTION_CJK
'\0',
'\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0', /* 他 们 你 來 們 到 和 地 */
' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB8', '\xAD', ' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x83', /* 对 對 就 席 我 时 時 會 */
' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\x88', '\xB0', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99', /* 来 為 能 舰 說 说 这 這 */
' ', '\xE9', '\xBD', '\x8A', ' ', '|', /* 齊 | */
' ', '\xE5', '\x86', '\x9B', ' ', '\xE5', '\x90', '\x8C', ' ', '\xE5', '\xB7', '\xB2', ' ', '\xE6', '\x84', '\xBF', ' ', '\xE6', '\x97', '\xA2', ' ', '\xE6', '\x98', '\x9F', ' ', '\xE6', '\x98', '\xAF', ' ', '\xE6', '\x99', '\xAF', /* 军 同 已 愿 既 星 是 景 */
' ', '\xE6', '\xB0', '\x91', ' ', '\xE7', '\x85', '\xA7', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\xA8', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\xA6', '\x81', /* 民 照 现 現 理 用 置 要 */
' ', '\xE8', '\xBB', '\x8D', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x85', '\x8D', ' ', '\xE9', '\x87', '\x8C', ' ', '\xE9', '\x96', '\x8B', ' ', '\xE9', '\x9B', '\xB7', ' ', '\xE9', '\x9C', '\xB2', ' ', '\xE9', '\x9D', '\xA2', /* 軍 那 配 里 開 雷 露 面 */
' ', '\xE9', '\xA1', '\xBE', /* 顾 */
'\0',
'\xE4', '\xB8', '\xAA', ' ', '\xE4', '\xB8', '\xBA', ' ', '\xE4', '\xBA', '\xBA', ' ', '\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xA5', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', /* 个 为 人 他 以 们 你 來 */
' ', '\xE5', '\x80', '\x8B', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\xA4', '\xA7', ' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1', /* 個 們 到 和 大 对 對 就 */
' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x89', ' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\xA6', '\x81', ' ', '\xE8', '\xAA', '\xAA', /* 我 时 時 有 来 為 要 說 */
' ', '\xE8', '\xAF', '\xB4', ' ', '|', /* 说 | */
' ', '\xE4', '\xB8', '\xBB', ' ', '\xE4', '\xBA', '\x9B', ' ', '\xE5', '\x9B', '\xA0', ' ', '\xE5', '\xAE', '\x83', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x84', '\x8F', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\x9F', /* 主 些 因 它 想 意 理 生 */
' ', '\xE7', '\x95', '\xB6', ' ', '\xE7', '\x9C', '\x8B', ' ', '\xE7', '\x9D', '\x80', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\x80', '\x85', ' ', '\xE8', '\x87', '\xAA', ' ', '\xE8', '\x91', '\x97', ' ', '\xE8', '\xA3', '\xA1', /* 當 看 着 置 者 自 著 裡 */
' ', '\xE8', '\xBF', '\x87', ' ', '\xE8', '\xBF', '\x98', ' ', '\xE8', '\xBF', '\x9B', ' ', '\xE9', '\x80', '\xB2', ' ', '\xE9', '\x81', '\x8E', ' ', '\xE9', '\x81', '\x93', ' ', '\xE9', '\x82', '\x84', ' ', '\xE9', '\x87', '\x8C', /* 过 还 进 進 過 道 還 里 */
' ', '\xE9', '\x9D', '\xA2', /* 面 */
#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
'\0',
' ', '\xE4', '\xBA', '\x9B', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0', /* 些 们 你 來 們 到 和 地 */
' ', '\xE5', '\xA5', '\xB9', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB9', '\xB4', ' ', '\xE5', '\xBE', '\x97', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x9C', '\x80', /* 她 将 將 就 年 得 情 最 */
' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE7', '\x90', '\x86', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99', /* 样 樣 理 能 說 说 这 這 */
' ', '\xE9', '\x80', '\x9A', ' ', '|', /* 通 | */
' ', '\xE5', '\x8D', '\xB3', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x90', '\xA7', ' ', '\xE5', '\x90', '\xAC', ' ', '\xE5', '\x91', '\xA2', ' ', '\xE5', '\x93', '\x81', ' ', '\xE5', '\x93', '\x8D', ' ', '\xE5', '\x97', '\x8E', /* 即 吗 吧 听 呢 品 响 嗎 */
' ', '\xE5', '\xB8', '\x88', ' ', '\xE5', '\xB8', '\xAB', ' ', '\xE6', '\x94', '\xB6', ' ', '\xE6', '\x96', '\xAD', ' ', '\xE6', '\x96', '\xB7', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE7', '\x9C', '\xBC', ' ', '\xE9', '\x96', '\x93', /* 师 師 收 断 斷 明 眼 間 */
' ', '\xE9', '\x97', '\xB4', ' ', '\xE9', '\x99', '\x85', ' ', '\xE9', '\x99', '\x88', ' ', '\xE9', '\x99', '\x90', ' ', '\xE9', '\x99', '\xA4', ' ', '\xE9', '\x99', '\xB3', ' ', '\xE9', '\x9A', '\x8F', ' ', '\xE9', '\x9A', '\x9B', /* 间 际 陈 限 除 陳 随 際 */
' ', '\xE9', '\x9A', '\xA8', /* 隨 */
'\0',
'\xE4', '\xBA', '\x8B', ' ', '\xE5', '\x89', '\x8D', ' ', '\xE5', '\xAD', '\xB8', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x88', '\x96', /* 事 前 學 将 將 情 想 或 */
' ', '\xE6', '\x94', '\xBF', ' ', '\xE6', '\x96', '\xAF', ' ', '\xE6', '\x96', '\xB0', ' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE6', '\xB0', '\x91', ' ', '\xE6', '\xB2', '\x92', ' ', '\xE6', '\xB2', '\xA1', /* 政 斯 新 样 樣 民 沒 没 */
' ', '\xE7', '\x84', '\xB6', ' ', '\xE7', '\x89', '\xB9', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x83', ' ', '\xE7', '\xAC', '\xAC', ' ', '\xE7', '\xB6', '\x93', ' ', '\xE8', '\xB0', '\x81', /* 然 特 现 現 球 第 經 谁 */
' ', '\xE8', '\xB5', '\xB7', ' ', '|', /* 起 | */
' ', '\xE4', '\xBE', '\x8B', ' ', '\xE5', '\x88', '\xA5', ' ', '\xE5', '\x88', '\xAB', ' ', '\xE5', '\x88', '\xB6', ' ', '\xE5', '\x8A', '\xA8', ' ', '\xE5', '\x8B', '\x95', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x97', '\x8E', /* 例 別 别 制 动 動 吗 嗎 */
' ', '\xE5', '\xA2', '\x9E', ' ', '\xE6', '\x8C', '\x87', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE6', '\x9C', '\x9D', ' ', '\xE6', '\x9C', '\x9F', ' ', '\xE6', '\x9E', '\x84', ' ', '\xE7', '\x89', '\xA9', ' ', '\xE7', '\xA1', '\xAE', /* 增 指 明 朝 期 构 物 确 */
' ', '\xE7', '\xA7', '\x8D', ' ', '\xE8', '\xAA', '\xBF', ' ', '\xE8', '\xB0', '\x83', ' ', '\xE8', '\xB2', '\xBB', ' ', '\xE8', '\xB4', '\xB9', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x83', '\xBD', ' ', '\xE9', '\x96', '\x93', /* 种 調 调 費 费 那 都 間 */
' ', '\xE9', '\x97', '\xB4', /* 间 */
#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
#endif /* AF_CONFIG_OPTION_CJK */
'\0',
};
/* stringsets are specific to styles */
FT_LOCAL_ARRAY_DEF( AF_Blue_StringRec )
af_blue_stringsets[] =
{
/* */
{ AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_ARABIC_BOTTOM, 0 },
{ AF_BLUE_STRING_ARABIC_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_AVESTAN_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_BAMUM_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_BAMUM_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_BENGALI_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_BENGALI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_BENGALI_BASE, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_NEUTRAL |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_BENGALI_BASE, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_BUHID_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_BUHID_LARGE, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_BUHID_SMALL, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_BUHID_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_CHAKMA_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CHAKMA_BOTTOM, 0 },
{ AF_BLUE_STRING_CHAKMA_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 },
{ AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CARIAN_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_CHEROKEE_CAPITAL, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CHEROKEE_CAPITAL, 0 },
{ AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CHEROKEE_SMALL, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_CHEROKEE_SMALL, 0 },
{ AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CYPRIOT_BOTTOM, 0 },
{ AF_BLUE_STRING_CYPRIOT_SMALL, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CYPRIOT_SMALL, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_CYRILLIC_SMALL, 0 },
{ AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_DEVANAGARI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_DEVANAGARI_BASE, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_NEUTRAL |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_DEVANAGARI_BASE, 0 },
{ AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM, 0 },
{ AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER, 0 },
{ AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM, 0 },
{ AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM, 0 },
{ AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GOTHIC_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_GREEK_SMALL, 0 },
{ AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_GUJARATI_BOTTOM, 0 },
{ AF_BLUE_STRING_GUJARATI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GUJARATI_DESCENDER, 0 },
{ AF_BLUE_STRING_GUJARATI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_GURMUKHI_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GURMUKHI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_GURMUKHI_BASE, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_NEUTRAL |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_GURMUKHI_BOTTOM, 0 },
{ AF_BLUE_STRING_GURMUKHI_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_LONG },
{ AF_BLUE_STRING_HEBREW_BOTTOM, 0 },
{ AF_BLUE_STRING_HEBREW_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_KANNADA_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_KAYAH_LI_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_KAYAH_LI_BOTTOM, 0 },
{ AF_BLUE_STRING_KAYAH_LI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_KAYAH_LI_DESCENDER, 0 },
{ AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_KHMER_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP, AF_BLUE_PROPERTY_LATIN_SUB_TOP },
{ AF_BLUE_STRING_KHMER_BOTTOM, 0 },
{ AF_BLUE_STRING_KHMER_DESCENDER, 0 },
{ AF_BLUE_STRING_KHMER_LARGE_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_LAO_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_LAO_BOTTOM, 0 },
{ AF_BLUE_STRING_LAO_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LAO_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 },
{ AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 },
{ AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_LISU_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_MALAYALAM_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_MYANMAR_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_MYANMAR_BOTTOM, 0 },
{ AF_BLUE_STRING_MYANMAR_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_MYANMAR_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_NKO_BOTTOM, 0 },
{ AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_OL_CHIKI, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_OLD_TURKIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 },
{ AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 },
{ AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_OSMANYA_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_ROHINGYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_ROHINGYA_BOTTOM, 0 },
{ AF_BLUE_STRING_ROHINGYA_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 },
{ AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 },
{ AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_SINHALA_BOTTOM, 0 },
{ AF_BLUE_STRING_SINHALA_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_SUNDANESE_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_SUNDANESE_BOTTOM, 0 },
{ AF_BLUE_STRING_SUNDANESE_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_TAMIL_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_TAMIL_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_TAI_VIET_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_TAI_VIET_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_TELUGU_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_TELUGU_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_THAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_X_HEIGHT },
{ AF_BLUE_STRING_THAI_BOTTOM, 0 },
{ AF_BLUE_STRING_THAI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_THAI_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_THAI_DESCENDER, 0 },
{ AF_BLUE_STRING_THAI_LARGE_DESCENDER, 0 },
{ AF_BLUE_STRING_THAI_DIGIT_TOP, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_TIFINAGH, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_VAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_VAI_BOTTOM, 0 },
{ AF_BLUE_STRING_MAX, 0 },
#ifdef AF_CONFIG_OPTION_CJK
{ AF_BLUE_STRING_CJK_TOP, AF_BLUE_PROPERTY_CJK_TOP },
{ AF_BLUE_STRING_CJK_BOTTOM, 0 },
#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
{ AF_BLUE_STRING_CJK_LEFT, AF_BLUE_PROPERTY_CJK_HORIZ },
{ AF_BLUE_STRING_CJK_RIGHT, AF_BLUE_PROPERTY_CJK_HORIZ |
AF_BLUE_PROPERTY_CJK_RIGHT },
#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
{ AF_BLUE_STRING_MAX, 0 },
#endif /* AF_CONFIG_OPTION_CJK */
};
/* END */

View file

@ -0,0 +1,429 @@
/* This file has been generated by the Perl script `afblue.pl', */
/* using data from file `afblue.dat'. */
/****************************************************************************
*
* afblue.h
*
* Auto-fitter data for blue strings (specification).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFBLUE_H_
#define AFBLUE_H_
FT_BEGIN_HEADER
/* an auxiliary macro to decode a UTF-8 character -- since we only use */
/* hard-coded, self-converted data, no error checking is performed */
#define GET_UTF8_CHAR( ch, p ) \
do \
{ \
ch = (unsigned char)*p++; \
if ( ch >= 0x80 ) \
{ \
FT_UInt len_; \
\
\
if ( ch < 0xE0 ) \
{ \
len_ = 1; \
ch &= 0x1F; \
} \
else if ( ch < 0xF0 ) \
{ \
len_ = 2; \
ch &= 0x0F; \
} \
else \
{ \
len_ = 3; \
ch &= 0x07; \
} \
\
for ( ; len_ > 0; len_-- ) \
ch = ( ch << 6 ) | ( *p++ & 0x3F ); \
} \
} while ( 0 )
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** B L U E S T R I N G S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* At the bottommost level, we define strings for finding blue zones. */
#define AF_BLUE_STRING_MAX_LEN 51
/* The AF_Blue_String enumeration values are offsets into the */
/* `af_blue_strings' array. */
typedef enum AF_Blue_String_
{
AF_BLUE_STRING_ADLAM_CAPITAL_TOP = 0,
AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM = 30,
AF_BLUE_STRING_ADLAM_SMALL_TOP = 40,
AF_BLUE_STRING_ADLAM_SMALL_BOTTOM = 65,
AF_BLUE_STRING_ARABIC_TOP = 105,
AF_BLUE_STRING_ARABIC_BOTTOM = 123,
AF_BLUE_STRING_ARABIC_JOIN = 138,
AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP = 141,
AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM = 165,
AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER = 189,
AF_BLUE_STRING_ARMENIAN_SMALL_TOP = 210,
AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM = 234,
AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER = 258,
AF_BLUE_STRING_AVESTAN_TOP = 282,
AF_BLUE_STRING_AVESTAN_BOTTOM = 302,
AF_BLUE_STRING_BAMUM_TOP = 312,
AF_BLUE_STRING_BAMUM_BOTTOM = 344,
AF_BLUE_STRING_BENGALI_BASE = 376,
AF_BLUE_STRING_BENGALI_TOP = 408,
AF_BLUE_STRING_BENGALI_HEAD = 436,
AF_BLUE_STRING_BUHID_TOP = 468,
AF_BLUE_STRING_BUHID_LARGE = 476,
AF_BLUE_STRING_BUHID_SMALL = 488,
AF_BLUE_STRING_BUHID_BOTTOM = 504,
AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP = 532,
AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM = 564,
AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP = 596,
AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM = 628,
AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP = 660,
AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM = 688,
AF_BLUE_STRING_CARIAN_TOP = 720,
AF_BLUE_STRING_CARIAN_BOTTOM = 760,
AF_BLUE_STRING_CHAKMA_TOP = 795,
AF_BLUE_STRING_CHAKMA_BOTTOM = 820,
AF_BLUE_STRING_CHAKMA_DESCENDER = 845,
AF_BLUE_STRING_CHEROKEE_CAPITAL = 910,
AF_BLUE_STRING_CHEROKEE_SMALL_ASCENDER = 942,
AF_BLUE_STRING_CHEROKEE_SMALL = 974,
AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER = 1006,
AF_BLUE_STRING_COPTIC_CAPITAL_TOP = 1022,
AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM = 1054,
AF_BLUE_STRING_COPTIC_SMALL_TOP = 1086,
AF_BLUE_STRING_COPTIC_SMALL_BOTTOM = 1118,
AF_BLUE_STRING_CYPRIOT_TOP = 1150,
AF_BLUE_STRING_CYPRIOT_BOTTOM = 1190,
AF_BLUE_STRING_CYPRIOT_SMALL = 1225,
AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP = 1240,
AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM = 1264,
AF_BLUE_STRING_CYRILLIC_SMALL = 1288,
AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER = 1312,
AF_BLUE_STRING_DESERET_CAPITAL_TOP = 1321,
AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM = 1346,
AF_BLUE_STRING_DESERET_SMALL_TOP = 1371,
AF_BLUE_STRING_DESERET_SMALL_BOTTOM = 1396,
AF_BLUE_STRING_DEVANAGARI_BASE = 1421,
AF_BLUE_STRING_DEVANAGARI_TOP = 1453,
AF_BLUE_STRING_DEVANAGARI_HEAD = 1485,
AF_BLUE_STRING_DEVANAGARI_BOTTOM = 1517,
AF_BLUE_STRING_ETHIOPIC_TOP = 1525,
AF_BLUE_STRING_ETHIOPIC_BOTTOM = 1557,
AF_BLUE_STRING_GEORGIAN_MKHEDRULI_TOP = 1589,
AF_BLUE_STRING_GEORGIAN_MKHEDRULI_BOTTOM = 1621,
AF_BLUE_STRING_GEORGIAN_MKHEDRULI_ASCENDER = 1653,
AF_BLUE_STRING_GEORGIAN_MKHEDRULI_DESCENDER = 1685,
AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_TOP = 1717,
AF_BLUE_STRING_GEORGIAN_ASOMTAVRULI_BOTTOM = 1749,
AF_BLUE_STRING_GEORGIAN_NUSKHURI_TOP = 1781,
AF_BLUE_STRING_GEORGIAN_NUSKHURI_BOTTOM = 1813,
AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER = 1845,
AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER = 1877,
AF_BLUE_STRING_GEORGIAN_MTAVRULI_TOP = 1909,
AF_BLUE_STRING_GEORGIAN_MTAVRULI_BOTTOM = 1941,
AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP = 1973,
AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM = 2005,
AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP = 2037,
AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM = 2069,
AF_BLUE_STRING_GOTHIC_TOP = 2101,
AF_BLUE_STRING_GOTHIC_BOTTOM = 2141,
AF_BLUE_STRING_GREEK_CAPITAL_TOP = 2161,
AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM = 2182,
AF_BLUE_STRING_GREEK_SMALL_BETA_TOP = 2200,
AF_BLUE_STRING_GREEK_SMALL = 2218,
AF_BLUE_STRING_GREEK_SMALL_DESCENDER = 2242,
AF_BLUE_STRING_GUJARATI_TOP = 2266,
AF_BLUE_STRING_GUJARATI_BOTTOM = 2298,
AF_BLUE_STRING_GUJARATI_ASCENDER = 2330,
AF_BLUE_STRING_GUJARATI_DESCENDER = 2380,
AF_BLUE_STRING_GUJARATI_DIGIT_TOP = 2413,
AF_BLUE_STRING_GURMUKHI_BASE = 2433,
AF_BLUE_STRING_GURMUKHI_HEAD = 2465,
AF_BLUE_STRING_GURMUKHI_TOP = 2497,
AF_BLUE_STRING_GURMUKHI_BOTTOM = 2529,
AF_BLUE_STRING_GURMUKHI_DIGIT_TOP = 2561,
AF_BLUE_STRING_HEBREW_TOP = 2581,
AF_BLUE_STRING_HEBREW_BOTTOM = 2605,
AF_BLUE_STRING_HEBREW_DESCENDER = 2623,
AF_BLUE_STRING_KANNADA_TOP = 2638,
AF_BLUE_STRING_KANNADA_BOTTOM = 2682,
AF_BLUE_STRING_KAYAH_LI_TOP = 2714,
AF_BLUE_STRING_KAYAH_LI_BOTTOM = 2738,
AF_BLUE_STRING_KAYAH_LI_ASCENDER = 2758,
AF_BLUE_STRING_KAYAH_LI_DESCENDER = 2766,
AF_BLUE_STRING_KAYAH_LI_LARGE_DESCENDER = 2778,
AF_BLUE_STRING_KHMER_TOP = 2799,
AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP = 2823,
AF_BLUE_STRING_KHMER_BOTTOM = 2863,
AF_BLUE_STRING_KHMER_DESCENDER = 2895,
AF_BLUE_STRING_KHMER_LARGE_DESCENDER = 2929,
AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP = 3016,
AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM = 3024,
AF_BLUE_STRING_LAO_TOP = 3032,
AF_BLUE_STRING_LAO_BOTTOM = 3064,
AF_BLUE_STRING_LAO_ASCENDER = 3096,
AF_BLUE_STRING_LAO_LARGE_ASCENDER = 3112,
AF_BLUE_STRING_LAO_DESCENDER = 3124,
AF_BLUE_STRING_LATIN_CAPITAL_TOP = 3148,
AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM = 3164,
AF_BLUE_STRING_LATIN_SMALL_F_TOP = 3180,
AF_BLUE_STRING_LATIN_SMALL_TOP = 3194,
AF_BLUE_STRING_LATIN_SMALL_BOTTOM = 3210,
AF_BLUE_STRING_LATIN_SMALL_DESCENDER = 3226,
AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP = 3236,
AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM = 3256,
AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP = 3276,
AF_BLUE_STRING_LATIN_SUBS_SMALL = 3296,
AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER = 3332,
AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP = 3352,
AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM = 3383,
AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP = 3412,
AF_BLUE_STRING_LATIN_SUPS_SMALL = 3438,
AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER = 3463,
AF_BLUE_STRING_LISU_TOP = 3474,
AF_BLUE_STRING_LISU_BOTTOM = 3506,
AF_BLUE_STRING_MALAYALAM_TOP = 3538,
AF_BLUE_STRING_MALAYALAM_BOTTOM = 3582,
AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP = 3614,
AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM = 3649,
AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP = 3689,
AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP = 3719,
AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM = 3749,
AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER = 3779,
AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP = 3794,
AF_BLUE_STRING_MONGOLIAN_TOP_BASE = 3819,
AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE = 3863,
AF_BLUE_STRING_MYANMAR_TOP = 3867,
AF_BLUE_STRING_MYANMAR_BOTTOM = 3899,
AF_BLUE_STRING_MYANMAR_ASCENDER = 3931,
AF_BLUE_STRING_MYANMAR_DESCENDER = 3959,
AF_BLUE_STRING_NKO_TOP = 3991,
AF_BLUE_STRING_NKO_BOTTOM = 4015,
AF_BLUE_STRING_NKO_SMALL_TOP = 4030,
AF_BLUE_STRING_NKO_SMALL_BOTTOM = 4039,
AF_BLUE_STRING_OL_CHIKI = 4051,
AF_BLUE_STRING_OLD_TURKIC_TOP = 4075,
AF_BLUE_STRING_OLD_TURKIC_BOTTOM = 4090,
AF_BLUE_STRING_OSAGE_CAPITAL_TOP = 4110,
AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM = 4150,
AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER = 4180,
AF_BLUE_STRING_OSAGE_SMALL_TOP = 4195,
AF_BLUE_STRING_OSAGE_SMALL_BOTTOM = 4235,
AF_BLUE_STRING_OSAGE_SMALL_ASCENDER = 4275,
AF_BLUE_STRING_OSAGE_SMALL_DESCENDER = 4300,
AF_BLUE_STRING_OSMANYA_TOP = 4315,
AF_BLUE_STRING_OSMANYA_BOTTOM = 4355,
AF_BLUE_STRING_ROHINGYA_TOP = 4395,
AF_BLUE_STRING_ROHINGYA_BOTTOM = 4420,
AF_BLUE_STRING_ROHINGYA_JOIN = 4445,
AF_BLUE_STRING_SAURASHTRA_TOP = 4448,
AF_BLUE_STRING_SAURASHTRA_BOTTOM = 4480,
AF_BLUE_STRING_SHAVIAN_TOP = 4500,
AF_BLUE_STRING_SHAVIAN_BOTTOM = 4510,
AF_BLUE_STRING_SHAVIAN_DESCENDER = 4535,
AF_BLUE_STRING_SHAVIAN_SMALL_TOP = 4545,
AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM = 4580,
AF_BLUE_STRING_SINHALA_TOP = 4595,
AF_BLUE_STRING_SINHALA_BOTTOM = 4627,
AF_BLUE_STRING_SINHALA_DESCENDER = 4659,
AF_BLUE_STRING_SUNDANESE_TOP = 4703,
AF_BLUE_STRING_SUNDANESE_BOTTOM = 4727,
AF_BLUE_STRING_SUNDANESE_DESCENDER = 4759,
AF_BLUE_STRING_TAI_VIET_TOP = 4767,
AF_BLUE_STRING_TAI_VIET_BOTTOM = 4787,
AF_BLUE_STRING_TAMIL_TOP = 4799,
AF_BLUE_STRING_TAMIL_BOTTOM = 4831,
AF_BLUE_STRING_TELUGU_TOP = 4863,
AF_BLUE_STRING_TELUGU_BOTTOM = 4891,
AF_BLUE_STRING_THAI_TOP = 4919,
AF_BLUE_STRING_THAI_BOTTOM = 4943,
AF_BLUE_STRING_THAI_ASCENDER = 4971,
AF_BLUE_STRING_THAI_LARGE_ASCENDER = 4983,
AF_BLUE_STRING_THAI_DESCENDER = 4995,
AF_BLUE_STRING_THAI_LARGE_DESCENDER = 5011,
AF_BLUE_STRING_THAI_DIGIT_TOP = 5019,
AF_BLUE_STRING_TIFINAGH = 5031,
AF_BLUE_STRING_VAI_TOP = 5063,
AF_BLUE_STRING_VAI_BOTTOM = 5095,
af_blue_1_1 = 5126,
#ifdef AF_CONFIG_OPTION_CJK
AF_BLUE_STRING_CJK_TOP = af_blue_1_1 + 1,
AF_BLUE_STRING_CJK_BOTTOM = af_blue_1_1 + 203,
af_blue_1_1_1 = af_blue_1_1 + 404,
#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
AF_BLUE_STRING_CJK_LEFT = af_blue_1_1_1 + 1,
AF_BLUE_STRING_CJK_RIGHT = af_blue_1_1_1 + 204,
af_blue_1_1_2 = af_blue_1_1_1 + 405,
#else
af_blue_1_1_2 = af_blue_1_1_1 + 0,
#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
af_blue_1_2 = af_blue_1_1_2 + 0,
#else
af_blue_1_2 = af_blue_1_1 + 0,
#endif /* AF_CONFIG_OPTION_CJK */
AF_BLUE_STRING_MAX /* do not remove */
} AF_Blue_String;
FT_LOCAL_ARRAY( char )
af_blue_strings[];
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** B L U E S T R I N G S E T S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* The next level is to group blue strings into style-specific sets. */
/* Properties are specific to a writing system. We assume that a given */
/* blue string can't be used in more than a single writing system, which */
/* is a safe bet. */
#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */
#define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 )
#define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 )
#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 )
#define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 )
#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */
#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */
#define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP
#define AF_BLUE_STRINGSET_MAX_LEN 8
/* The AF_Blue_Stringset enumeration values are offsets into the */
/* `af_blue_stringsets' array. */
typedef enum AF_Blue_Stringset_
{
AF_BLUE_STRINGSET_ADLM = 0,
AF_BLUE_STRINGSET_ARAB = 5,
AF_BLUE_STRINGSET_ARMN = 9,
AF_BLUE_STRINGSET_AVST = 16,
AF_BLUE_STRINGSET_BAMU = 19,
AF_BLUE_STRINGSET_BENG = 22,
AF_BLUE_STRINGSET_BUHD = 27,
AF_BLUE_STRINGSET_CAKM = 32,
AF_BLUE_STRINGSET_CANS = 36,
AF_BLUE_STRINGSET_CARI = 43,
AF_BLUE_STRINGSET_CHER = 46,
AF_BLUE_STRINGSET_COPT = 53,
AF_BLUE_STRINGSET_CPRT = 58,
AF_BLUE_STRINGSET_CYRL = 63,
AF_BLUE_STRINGSET_DEVA = 69,
AF_BLUE_STRINGSET_DSRT = 75,
AF_BLUE_STRINGSET_ETHI = 80,
AF_BLUE_STRINGSET_GEOR = 83,
AF_BLUE_STRINGSET_GEOK = 90,
AF_BLUE_STRINGSET_GLAG = 97,
AF_BLUE_STRINGSET_GOTH = 102,
AF_BLUE_STRINGSET_GREK = 105,
AF_BLUE_STRINGSET_GUJR = 112,
AF_BLUE_STRINGSET_GURU = 118,
AF_BLUE_STRINGSET_HEBR = 124,
AF_BLUE_STRINGSET_KNDA = 128,
AF_BLUE_STRINGSET_KALI = 131,
AF_BLUE_STRINGSET_KHMR = 137,
AF_BLUE_STRINGSET_KHMS = 143,
AF_BLUE_STRINGSET_LAO = 146,
AF_BLUE_STRINGSET_LATN = 152,
AF_BLUE_STRINGSET_LATB = 159,
AF_BLUE_STRINGSET_LATP = 166,
AF_BLUE_STRINGSET_LISU = 173,
AF_BLUE_STRINGSET_MLYM = 176,
AF_BLUE_STRINGSET_MEDF = 179,
AF_BLUE_STRINGSET_MONG = 187,
AF_BLUE_STRINGSET_MYMR = 190,
AF_BLUE_STRINGSET_NKOO = 195,
AF_BLUE_STRINGSET_NONE = 200,
AF_BLUE_STRINGSET_OLCK = 201,
AF_BLUE_STRINGSET_ORKH = 204,
AF_BLUE_STRINGSET_OSGE = 207,
AF_BLUE_STRINGSET_OSMA = 215,
AF_BLUE_STRINGSET_ROHG = 218,
AF_BLUE_STRINGSET_SAUR = 222,
AF_BLUE_STRINGSET_SHAW = 225,
AF_BLUE_STRINGSET_SINH = 231,
AF_BLUE_STRINGSET_SUND = 235,
AF_BLUE_STRINGSET_TAML = 239,
AF_BLUE_STRINGSET_TAVT = 242,
AF_BLUE_STRINGSET_TELU = 245,
AF_BLUE_STRINGSET_THAI = 248,
AF_BLUE_STRINGSET_TFNG = 256,
AF_BLUE_STRINGSET_VAII = 259,
af_blue_2_1 = 262,
#ifdef AF_CONFIG_OPTION_CJK
AF_BLUE_STRINGSET_HANI = af_blue_2_1 + 0,
af_blue_2_1_1 = af_blue_2_1 + 2,
#ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
af_blue_2_1_2 = af_blue_2_1_1 + 2,
#else
af_blue_2_1_2 = af_blue_2_1_1 + 0,
#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
af_blue_2_2 = af_blue_2_1_2 + 1,
#else
af_blue_2_2 = af_blue_2_1 + 0,
#endif /* AF_CONFIG_OPTION_CJK */
AF_BLUE_STRINGSET_MAX /* do not remove */
} AF_Blue_Stringset;
typedef struct AF_Blue_StringRec_
{
AF_Blue_String string;
FT_UShort properties;
} AF_Blue_StringRec;
FT_LOCAL_ARRAY( AF_Blue_StringRec )
af_blue_stringsets[];
/* */
FT_END_HEADER
#endif /* AFBLUE_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,141 @@
/****************************************************************************
*
* afcjk.h
*
* Auto-fitter hinting routines for CJK writing system (specification).
*
* Copyright (C) 2006-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFCJK_H_
#define AFCJK_H_
#include "afhints.h"
#include "aflatin.h"
FT_BEGIN_HEADER
/* the CJK-specific writing system */
AF_DECLARE_WRITING_SYSTEM_CLASS( af_cjk_writing_system_class )
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** C J K G L O B A L M E T R I C S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*
* CJK glyphs tend to fill the square. So we have both vertical and
* horizontal blue zones. But some glyphs have flat bounding strokes that
* leave some space between neighbour glyphs.
*/
#define AF_CJK_IS_TOP_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_CJK_TOP )
#define AF_CJK_IS_HORIZ_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_CJK_HORIZ )
#define AF_CJK_IS_RIGHT_BLUE AF_CJK_IS_TOP_BLUE
#define AF_CJK_MAX_WIDTHS 16
#define AF_CJK_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */
#define AF_CJK_BLUE_TOP ( 1U << 1 ) /* result of AF_CJK_IS_TOP_BLUE */
#define AF_CJK_BLUE_ADJUSTMENT ( 1U << 2 ) /* used for scale adjustment */
/* optimization */
typedef struct AF_CJKBlueRec_
{
AF_WidthRec ref;
AF_WidthRec shoot; /* undershoot */
FT_UInt flags;
} AF_CJKBlueRec, *AF_CJKBlue;
typedef struct AF_CJKAxisRec_
{
FT_Fixed scale;
FT_Pos delta;
FT_UInt width_count; /* number of used widths */
AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; /* widths array */
FT_Pos edge_distance_threshold; /* used for creating edges */
FT_Pos standard_width; /* the default stem thickness */
FT_Bool extra_light; /* is standard width very light? */
/* used for horizontal metrics too for CJK */
FT_Bool control_overshoot;
FT_UInt blue_count;
AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX];
FT_Fixed org_scale;
FT_Pos org_delta;
} AF_CJKAxisRec, *AF_CJKAxis;
typedef struct AF_CJKMetricsRec_
{
AF_StyleMetricsRec root;
FT_UInt units_per_em;
AF_CJKAxisRec axis[AF_DIMENSION_MAX];
} AF_CJKMetricsRec, *AF_CJKMetrics;
#ifdef AF_CONFIG_OPTION_CJK
FT_LOCAL( FT_Error )
af_cjk_metrics_init( AF_StyleMetrics metrics,
FT_Face face );
FT_LOCAL( void )
af_cjk_metrics_scale( AF_StyleMetrics metrics,
AF_Scaler scaler );
FT_LOCAL( FT_Error )
af_cjk_hints_init( AF_GlyphHints hints,
AF_StyleMetrics metrics );
FT_LOCAL( FT_Error )
af_cjk_hints_apply( FT_UInt glyph_index,
AF_GlyphHints hints,
FT_Outline* outline,
AF_StyleMetrics metrics );
/* shared; called from afindic.c */
FT_LOCAL( void )
af_cjk_metrics_check_digits( AF_CJKMetrics metrics,
FT_Face face );
FT_LOCAL( void )
af_cjk_metrics_init_widths( AF_CJKMetrics metrics,
FT_Face face );
#endif /* AF_CONFIG_OPTION_CJK */
/* */
FT_END_HEADER
#endif /* AFCJK_H_ */
/* END */

View file

@ -0,0 +1,105 @@
/****************************************************************************
*
* afcover.h
*
* Auto-fitter coverages (specification only).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/* This header file can be included multiple times. */
/* Define `COVERAGE' as needed. */
/* Add new coverages here. The first and second arguments are the */
/* coverage name in lowercase and uppercase, respectively, followed */
/* by a description string. The last four arguments are the four */
/* characters defining the corresponding OpenType feature. */
#if 0
/* XXX: It's not possible to define blue zone characters in advance. */
COVERAGE( alternative_fractions, ALTERNATIVE_FRACTIONS,
"alternative fractions",
'a', 'f', 'r', 'c' )
#endif
COVERAGE( petite_capitals_from_capitals, PETITE_CAPITALS_FROM_CAPITALS,
"petite capitals from capitals",
'c', '2', 'c', 'p' )
COVERAGE( small_capitals_from_capitals, SMALL_CAPITALS_FROM_CAPITALS,
"small capitals from capitals",
'c', '2', 's', 'c' )
#if 0
/* XXX: Only digits are in this coverage, however, both normal style */
/* and oldstyle representation forms are possible. */
COVERAGE( denominators, DENOMINATORS,
"denominators",
'd', 'n', 'o', 'm' )
#endif
#if 0
/* XXX: It's not possible to define blue zone characters in advance. */
COVERAGE( fractions, FRACTIONS,
"fractions",
'f', 'r', 'a', 'c' )
#endif
#if 0
/* XXX: Only digits are in this coverage, however, both normal style */
/* and oldstyle representation forms are possible. */
COVERAGE( numerators, NUMERATORS,
"numerators",
'n', 'u', 'm', 'r' )
#endif
COVERAGE( ordinals, ORDINALS,
"ordinals",
'o', 'r', 'd', 'n' )
COVERAGE( petite_capitals, PETITE_CAPITALS,
"petite capitals",
'p', 'c', 'a', 'p' )
COVERAGE( ruby, RUBY,
"ruby",
'r', 'u', 'b', 'y' )
COVERAGE( scientific_inferiors, SCIENTIFIC_INFERIORS,
"scientific inferiors",
's', 'i', 'n', 'f' )
COVERAGE( small_capitals, SMALL_CAPITALS,
"small capitals",
's', 'm', 'c', 'p' )
COVERAGE( subscript, SUBSCRIPT,
"subscript",
's', 'u', 'b', 's' )
COVERAGE( superscript, SUPERSCRIPT,
"superscript",
's', 'u', 'p', 's' )
COVERAGE( titling, TITLING,
"titling",
't', 'i', 't', 'l' )
#if 0
/* to be always excluded */
COVERAGE(nalt, 'n', 'a', 'l', 't'); /* Alternate Annotation Forms (?) */
COVERAGE(ornm, 'o', 'r', 'n', 'm'); /* Ornaments (?) */
#endif
/* END */

View file

@ -0,0 +1,77 @@
/****************************************************************************
*
* afdummy.c
*
* Auto-fitter dummy routines to be used if no hinting should be
* performed (body).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "afdummy.h"
#include "afhints.h"
#include "aferrors.h"
static FT_Error
af_dummy_hints_init( AF_GlyphHints hints,
AF_StyleMetrics metrics )
{
af_glyph_hints_rescale( hints, metrics );
hints->x_scale = metrics->scaler.x_scale;
hints->y_scale = metrics->scaler.y_scale;
hints->x_delta = metrics->scaler.x_delta;
hints->y_delta = metrics->scaler.y_delta;
return FT_Err_Ok;
}
static FT_Error
af_dummy_hints_apply( FT_UInt glyph_index,
AF_GlyphHints hints,
FT_Outline* outline,
AF_StyleMetrics metrics )
{
FT_Error error;
FT_UNUSED( glyph_index );
FT_UNUSED( metrics );
error = af_glyph_hints_reload( hints, outline );
if ( !error )
af_glyph_hints_save( hints, outline );
return error;
}
AF_DEFINE_WRITING_SYSTEM_CLASS(
af_dummy_writing_system_class,
AF_WRITING_SYSTEM_DUMMY,
sizeof ( AF_StyleMetricsRec ),
(AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */
(AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */
(AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
(AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */
(AF_WritingSystem_InitHintsFunc) af_dummy_hints_init, /* style_hints_init */
(AF_WritingSystem_ApplyHintsFunc) af_dummy_hints_apply /* style_hints_apply */
)
/* END */

View file

@ -0,0 +1,40 @@
/****************************************************************************
*
* afdummy.h
*
* Auto-fitter dummy routines to be used if no hinting should be
* performed (specification).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFDUMMY_H_
#define AFDUMMY_H_
#include "aftypes.h"
FT_BEGIN_HEADER
/* A dummy writing system used when no hinting should be performed. */
AF_DECLARE_WRITING_SYSTEM_CLASS( af_dummy_writing_system_class )
/* */
FT_END_HEADER
#endif /* AFDUMMY_H_ */
/* END */

View file

@ -0,0 +1,42 @@
/****************************************************************************
*
* aferrors.h
*
* Autofitter error codes (specification only).
*
* Copyright (C) 2005-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* This file is used to define the Autofitter error enumeration
* constants.
*
*/
#ifndef AFERRORS_H_
#define AFERRORS_H_
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX AF_Err_
#define FT_ERR_BASE FT_Mod_Err_Autofit
#include <freetype/fterrors.h>
#endif /* AFERRORS_H_ */
/* END */

View file

@ -0,0 +1,513 @@
/****************************************************************************
*
* afglobal.c
*
* Auto-fitter routines to compute global hinting values (body).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "afglobal.h"
#include "afranges.h"
#include "afshaper.h"
#include "afws-decl.h"
#include <freetype/internal/ftdebug.h>
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT afglobal
#include "aferrors.h"
#undef SCRIPT
#define SCRIPT( s, S, d, h, H, ss ) \
AF_DEFINE_SCRIPT_CLASS( \
af_ ## s ## _script_class, \
AF_SCRIPT_ ## S, \
af_ ## s ## _uniranges, \
af_ ## s ## _nonbase_uniranges, \
AF_ ## H, \
ss )
#include "afscript.h"
#undef STYLE
#define STYLE( s, S, d, ws, sc, ss, c ) \
AF_DEFINE_STYLE_CLASS( \
af_ ## s ## _style_class, \
AF_STYLE_ ## S, \
ws, \
sc, \
ss, \
c )
#include "afstyles.h"
#undef WRITING_SYSTEM
#define WRITING_SYSTEM( ws, WS ) \
&af_ ## ws ## _writing_system_class,
FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass )
af_writing_system_classes[] =
{
#include "afws-iter.h"
NULL /* do not remove */
};
#undef SCRIPT
#define SCRIPT( s, S, d, h, H, ss ) \
&af_ ## s ## _script_class,
FT_LOCAL_ARRAY_DEF( AF_ScriptClass )
af_script_classes[] =
{
#include "afscript.h"
NULL /* do not remove */
};
#undef STYLE
#define STYLE( s, S, d, ws, sc, ss, c ) \
&af_ ## s ## _style_class,
FT_LOCAL_ARRAY_DEF( AF_StyleClass )
af_style_classes[] =
{
#include "afstyles.h"
NULL /* do not remove */
};
#ifdef FT_DEBUG_LEVEL_TRACE
#undef STYLE
#define STYLE( s, S, d, ws, sc, ss, c ) #s,
FT_LOCAL_ARRAY_DEF( char* )
af_style_names[] =
{
#include "afstyles.h"
};
#endif /* FT_DEBUG_LEVEL_TRACE */
/* Compute the style index of each glyph within a given face. */
static FT_Error
af_face_globals_compute_style_coverage( AF_FaceGlobals globals )
{
FT_Error error;
FT_Face face = globals->face;
FT_CharMap old_charmap = face->charmap;
FT_UShort* gstyles = globals->glyph_styles;
FT_UShort ss;
FT_UShort dflt = 0xFFFFU; /* a non-valid value */
FT_UInt i;
/* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */
for ( i = 0; i < globals->glyph_count; i++ )
gstyles[i] = AF_STYLE_UNASSIGNED;
error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
if ( error )
{
/*
* Ignore this error; we simply use the fallback style.
* XXX: Shouldn't we rather disable hinting?
*/
error = FT_Err_Ok;
goto Exit;
}
/* scan each style in a Unicode charmap */
for ( ss = 0; af_style_classes[ss]; ss++ )
{
AF_StyleClass style_class =
af_style_classes[ss];
AF_ScriptClass script_class =
af_script_classes[style_class->script];
AF_Script_UniRange range;
if ( !script_class->script_uni_ranges )
continue;
/*
* Scan all Unicode points in the range and set the corresponding
* glyph style index.
*/
if ( style_class->coverage == AF_COVERAGE_DEFAULT )
{
if ( style_class->script == globals->module->default_script )
dflt = ss;
for ( range = script_class->script_uni_ranges;
range->first != 0;
range++ )
{
FT_ULong charcode = range->first;
FT_UInt gindex;
gindex = FT_Get_Char_Index( face, charcode );
if ( gindex != 0 &&
gindex < globals->glyph_count &&
( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
gstyles[gindex] = ss;
for (;;)
{
charcode = FT_Get_Next_Char( face, charcode, &gindex );
if ( gindex == 0 || charcode > range->last )
break;
if ( gindex < globals->glyph_count &&
( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
gstyles[gindex] = ss;
}
}
/* do the same for the script's non-base characters */
for ( range = script_class->script_uni_nonbase_ranges;
range->first != 0;
range++ )
{
FT_ULong charcode = range->first;
FT_UInt gindex;
gindex = FT_Get_Char_Index( face, charcode );
if ( gindex != 0 &&
gindex < globals->glyph_count &&
( gstyles[gindex] & AF_STYLE_MASK ) == ss )
gstyles[gindex] |= AF_NONBASE;
for (;;)
{
charcode = FT_Get_Next_Char( face, charcode, &gindex );
if ( gindex == 0 || charcode > range->last )
break;
if ( gindex < globals->glyph_count &&
( gstyles[gindex] & AF_STYLE_MASK ) == ss )
gstyles[gindex] |= AF_NONBASE;
}
}
}
else
{
/* get glyphs not directly addressable by cmap */
af_shaper_get_coverage( globals, style_class, gstyles, 0 );
}
}
/* handle the remaining default OpenType features ... */
for ( ss = 0; af_style_classes[ss]; ss++ )
{
AF_StyleClass style_class = af_style_classes[ss];
if ( style_class->coverage == AF_COVERAGE_DEFAULT )
af_shaper_get_coverage( globals, style_class, gstyles, 0 );
}
/* ... and finally the default OpenType features of the default script */
af_shaper_get_coverage( globals, af_style_classes[dflt], gstyles, 1 );
/* mark ASCII digits */
for ( i = 0x30; i <= 0x39; i++ )
{
FT_UInt gindex = FT_Get_Char_Index( face, i );
if ( gindex != 0 && gindex < globals->glyph_count )
gstyles[gindex] |= AF_DIGIT;
}
Exit:
/*
* By default, all uncovered glyphs are set to the fallback style.
* XXX: Shouldn't we disable hinting or do something similar?
*/
if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED )
{
FT_UInt nn;
for ( nn = 0; nn < globals->glyph_count; nn++ )
{
if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
{
gstyles[nn] &= ~AF_STYLE_MASK;
gstyles[nn] |= globals->module->fallback_style;
}
}
}
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( "\n" ));
FT_TRACE4(( "style coverage\n" ));
FT_TRACE4(( "==============\n" ));
FT_TRACE4(( "\n" ));
for ( ss = 0; af_style_classes[ss]; ss++ )
{
AF_StyleClass style_class = af_style_classes[ss];
FT_UInt count = 0;
FT_UInt idx;
FT_TRACE4(( "%s:\n", af_style_names[style_class->style] ));
for ( idx = 0; idx < globals->glyph_count; idx++ )
{
if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style )
{
if ( !( count % 10 ) )
FT_TRACE4(( " " ));
FT_TRACE4(( " %d", idx ));
count++;
if ( !( count % 10 ) )
FT_TRACE4(( "\n" ));
}
}
if ( !count )
FT_TRACE4(( " (none)\n" ));
if ( count % 10 )
FT_TRACE4(( "\n" ));
}
#endif /* FT_DEBUG_LEVEL_TRACE */
face->charmap = old_charmap;
return error;
}
FT_LOCAL_DEF( FT_Error )
af_face_globals_new( FT_Face face,
AF_FaceGlobals *aglobals,
AF_Module module )
{
FT_Error error;
FT_Memory memory;
AF_FaceGlobals globals = NULL;
memory = face->memory;
/* we allocate an AF_FaceGlobals structure together */
/* with the glyph_styles array */
if ( FT_QALLOC( globals,
sizeof ( *globals ) +
(FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) )
goto Exit;
FT_ZERO( &globals->metrics );
globals->face = face;
globals->glyph_count = (FT_UInt)face->num_glyphs;
/* right after the globals structure come the glyph styles */
globals->glyph_styles = (FT_UShort*)( globals + 1 );
globals->module = module;
globals->stem_darkening_for_ppem = 0;
globals->darken_x = 0;
globals->darken_y = 0;
globals->standard_vertical_width = 0;
globals->standard_horizontal_width = 0;
globals->scale_down_factor = 0;
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
globals->hb_font = hb_ft_font_create_( face, NULL );
globals->hb_buf = hb_buffer_create();
#endif
error = af_face_globals_compute_style_coverage( globals );
if ( error )
{
af_face_globals_free( globals );
globals = NULL;
}
else
globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX;
Exit:
*aglobals = globals;
return error;
}
FT_LOCAL_DEF( void )
af_face_globals_free( void* globals_ )
{
AF_FaceGlobals globals = (AF_FaceGlobals)globals_;
if ( globals )
{
FT_Memory memory = globals->face->memory;
FT_UInt nn;
for ( nn = 0; nn < AF_STYLE_MAX; nn++ )
{
if ( globals->metrics[nn] )
{
AF_StyleClass style_class =
af_style_classes[nn];
AF_WritingSystemClass writing_system_class =
af_writing_system_classes[style_class->writing_system];
if ( writing_system_class->style_metrics_done )
writing_system_class->style_metrics_done( globals->metrics[nn] );
FT_FREE( globals->metrics[nn] );
}
}
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
hb_font_destroy( globals->hb_font );
hb_buffer_destroy( globals->hb_buf );
#endif
/* no need to free `globals->glyph_styles'; */
/* it is part of the `globals' array */
FT_FREE( globals );
}
}
FT_LOCAL_DEF( FT_Error )
af_face_globals_get_metrics( AF_FaceGlobals globals,
FT_UInt gindex,
FT_UInt options,
AF_StyleMetrics *ametrics )
{
AF_StyleMetrics metrics = NULL;
AF_Style style = (AF_Style)options;
AF_WritingSystemClass writing_system_class;
AF_StyleClass style_class;
FT_Error error = FT_Err_Ok;
if ( gindex >= globals->glyph_count )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
/* if we have a forced style (via `options'), use it, */
/* otherwise look into `glyph_styles' array */
if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX )
style = (AF_Style)( globals->glyph_styles[gindex] &
AF_STYLE_UNASSIGNED );
Again:
style_class = af_style_classes[style];
writing_system_class = af_writing_system_classes
[style_class->writing_system];
metrics = globals->metrics[style];
if ( !metrics )
{
/* create the global metrics object if necessary */
FT_Memory memory = globals->face->memory;
if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) )
goto Exit;
metrics->style_class = style_class;
metrics->globals = globals;
if ( writing_system_class->style_metrics_init )
{
error = writing_system_class->style_metrics_init( metrics,
globals->face );
if ( error )
{
if ( writing_system_class->style_metrics_done )
writing_system_class->style_metrics_done( metrics );
FT_FREE( metrics );
/* internal error code -1 indicates */
/* that no blue zones have been found */
if ( error == -1 )
{
style = (AF_Style)( globals->glyph_styles[gindex] &
AF_STYLE_UNASSIGNED );
/* IMPORTANT: Clear the error code, see
* https://gitlab.freedesktop.org/freetype/freetype/-/issues/1063
*/
error = FT_Err_Ok;
goto Again;
}
goto Exit;
}
}
globals->metrics[style] = metrics;
}
Exit:
*ametrics = metrics;
return error;
}
FT_LOCAL_DEF( FT_Bool )
af_face_globals_is_digit( AF_FaceGlobals globals,
FT_UInt gindex )
{
if ( gindex < globals->glyph_count )
return FT_BOOL( globals->glyph_styles[gindex] & AF_DIGIT );
return FT_BOOL( 0 );
}
/* END */

View file

@ -0,0 +1,173 @@
/****************************************************************************
*
* afglobal.h
*
* Auto-fitter routines to compute global hinting values
* (specification).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFGLOBAL_H_
#define AFGLOBAL_H_
#include "aftypes.h"
#include "afmodule.h"
#include "afshaper.h"
FT_BEGIN_HEADER
FT_LOCAL_ARRAY( AF_WritingSystemClass )
af_writing_system_classes[];
#undef SCRIPT
#define SCRIPT( s, S, d, h, H, ss ) \
AF_DECLARE_SCRIPT_CLASS( af_ ## s ## _script_class )
#include "afscript.h"
FT_LOCAL_ARRAY( AF_ScriptClass )
af_script_classes[];
#undef STYLE
#define STYLE( s, S, d, ws, sc, ss, c ) \
AF_DECLARE_STYLE_CLASS( af_ ## s ## _style_class )
#include "afstyles.h"
FT_LOCAL_ARRAY( AF_StyleClass )
af_style_classes[];
#ifdef FT_DEBUG_LEVEL_TRACE
FT_LOCAL_ARRAY( char* )
af_style_names[];
#endif
/*
* Default values and flags for both autofitter globals (found in
* AF_ModuleRec) and face globals (in AF_FaceGlobalsRec).
*/
/* index of fallback style in `af_style_classes' */
#ifdef AF_CONFIG_OPTION_CJK
#define AF_STYLE_FALLBACK AF_STYLE_HANI_DFLT
#else
#define AF_STYLE_FALLBACK AF_STYLE_NONE_DFLT
#endif
/* default script for OpenType; ignored if HarfBuzz isn't used */
#define AF_SCRIPT_DEFAULT AF_SCRIPT_LATN
/* a bit mask for AF_DIGIT and AF_NONBASE */
#define AF_STYLE_MASK 0x3FFF
/* an uncovered glyph */
#define AF_STYLE_UNASSIGNED AF_STYLE_MASK
/* if this flag is set, we have an ASCII digit */
#define AF_DIGIT 0x8000U
/* if this flag is set, we have a non-base character */
#define AF_NONBASE 0x4000U
/* `increase-x-height' property */
#define AF_PROP_INCREASE_X_HEIGHT_MIN 6
#define AF_PROP_INCREASE_X_HEIGHT_MAX 0
/************************************************************************/
/************************************************************************/
/***** *****/
/***** F A C E G L O B A L S *****/
/***** *****/
/************************************************************************/
/************************************************************************/
/*
* Note that glyph_styles[] maps each glyph to an index into the
* `af_style_classes' array.
*
*/
typedef struct AF_FaceGlobalsRec_
{
FT_Face face;
FT_UInt glyph_count; /* unsigned face->num_glyphs */
FT_UShort* glyph_styles;
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
hb_font_t* hb_font;
hb_buffer_t* hb_buf; /* for feature comparison */
#endif
/* per-face auto-hinter properties */
FT_UInt increase_x_height;
AF_StyleMetrics metrics[AF_STYLE_MAX];
/* Compute darkening amount once per size. Use this to check whether */
/* darken_{x,y} needs to be recomputed. */
FT_UShort stem_darkening_for_ppem;
/* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_HORZ] */
/* to compute the darkening amount. */
FT_Pos standard_vertical_width;
/* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_VERT] */
/* to compute the darkening amount. */
FT_Pos standard_horizontal_width;
/* The actual amount to darken a glyph along the X axis. */
FT_Pos darken_x;
/* The actual amount to darken a glyph along the Y axis. */
FT_Pos darken_y;
/* Amount to scale down by to keep emboldened points */
/* on the Y-axis in pre-computed blue zones. */
FT_Fixed scale_down_factor;
AF_Module module; /* to access global properties */
} AF_FaceGlobalsRec;
/*
* model the global hints data for a given face, decomposed into
* style-specific items
*/
FT_LOCAL( FT_Error )
af_face_globals_new( FT_Face face,
AF_FaceGlobals *aglobals,
AF_Module module );
FT_LOCAL( FT_Error )
af_face_globals_get_metrics( AF_FaceGlobals globals,
FT_UInt gindex,
FT_UInt options,
AF_StyleMetrics *ametrics );
FT_LOCAL( void )
af_face_globals_free( void* globals );
FT_LOCAL( FT_Bool )
af_face_globals_is_digit( AF_FaceGlobals globals,
FT_UInt gindex );
/* */
FT_END_HEADER
#endif /* AFGLOBAL_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,467 @@
/****************************************************************************
*
* afhints.h
*
* Auto-fitter hinting routines (specification).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFHINTS_H_
#define AFHINTS_H_
#include "aftypes.h"
FT_BEGIN_HEADER
/*
* The definition of outline glyph hints. These are shared by all
* writing system analysis routines (until now).
*/
typedef enum AF_Dimension_
{
AF_DIMENSION_HORZ = 0, /* x coordinates, */
/* i.e., vertical segments & edges */
AF_DIMENSION_VERT = 1, /* y coordinates, */
/* i.e., horizontal segments & edges */
AF_DIMENSION_MAX /* do not remove */
} AF_Dimension;
/* hint directions -- the values are computed so that two vectors are */
/* in opposite directions iff `dir1 + dir2 == 0' */
typedef enum AF_Direction_
{
AF_DIR_NONE = 4,
AF_DIR_RIGHT = 1,
AF_DIR_LEFT = -1,
AF_DIR_UP = 2,
AF_DIR_DOWN = -2
} AF_Direction;
/*
* The following explanations are mostly taken from the article
*
* Real-Time Grid Fitting of Typographic Outlines
*
* by David Turner and Werner Lemberg
*
* https://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf
*
* with appropriate updates.
*
*
* Segments
*
* `af_{cjk,latin,...}_hints_compute_segments' are the functions to
* find segments in an outline.
*
* A segment is a series of at least two consecutive points that are
* approximately aligned along a coordinate axis. The analysis to do
* so is specific to a writing system.
*
*
* Edges
*
* `af_{cjk,latin,...}_hints_compute_edges' are the functions to find
* edges.
*
* As soon as segments are defined, the auto-hinter groups them into
* edges. An edge corresponds to a single position on the main
* dimension that collects one or more segments (allowing for a small
* threshold).
*
* As an example, the `latin' writing system first tries to grid-fit
* edges, then to align segments on the edges unless it detects that
* they form a serif.
*
*
* A H
* | |
* | |
* | |
* | |
* C | | F
* +------<-----+ +-----<------+
* | B G |
* | |
* | |
* +--------------->------------------+
* D E
*
*
* Stems
*
* Stems are detected by `af_{cjk,latin,...}_hint_edges'.
*
* Segments need to be `linked' to other ones in order to detect stems.
* A stem is made of two segments that face each other in opposite
* directions and that are sufficiently close to each other. Using
* vocabulary from the TrueType specification, stem segments form a
* `black distance'.
*
* In the above ASCII drawing, the horizontal segments are BC, DE, and
* FG; the vertical segments are AB, CD, EF, and GH.
*
* Each segment has at most one `best' candidate to form a black
* distance, or no candidate at all. Notice that two distinct segments
* can have the same candidate, which frequently means a serif.
*
* A stem is recognized by the following condition:
*
* best segment_1 = segment_2 && best segment_2 = segment_1
*
* The best candidate is stored in field `link' in structure
* `AF_Segment'.
*
* In the above ASCII drawing, the best candidate for both AB and CD is
* GH, while the best candidate for GH is AB. Similarly, the best
* candidate for EF and GH is AB, while the best candidate for AB is
* GH.
*
* The detection and handling of stems is dependent on the writing
* system.
*
*
* Serifs
*
* Serifs are detected by `af_{cjk,latin,...}_hint_edges'.
*
* In comparison to a stem, a serif (as handled by the auto-hinter
* module that takes care of the `latin' writing system) has
*
* best segment_1 = segment_2 && best segment_2 != segment_1
*
* where segment_1 corresponds to the serif segment (CD and EF in the
* above ASCII drawing).
*
* The best candidate is stored in field `serif' in structure
* `AF_Segment' (and `link' is set to NULL).
*
*
* Touched points
*
* A point is called `touched' if it has been processed somehow by the
* auto-hinter. It basically means that it shouldn't be moved again
* (or moved only under certain constraints to preserve the already
* applied processing).
*
*
* Flat and round segments
*
* Segments are `round' or `flat', depending on the series of points
* that define them. A segment is round if the next and previous point
* of an extremum (which can be either a single point or sequence of
* points) are both conic or cubic control points. Otherwise, a
* segment with an extremum is flat.
*
*
* Strong Points
*
* Experience has shown that points not part of an edge need to be
* interpolated linearly between their two closest edges, even if these
* are not part of the contour of those particular points. Typical
* candidates for this are
*
* - angle points (i.e., points where the `in' and `out' direction
* differ greatly)
*
* - inflection points (i.e., where the `in' and `out' angles are the
* same, but the curvature changes sign) [currently, such points
* aren't handled specially in the auto-hinter]
*
* `af_glyph_hints_align_strong_points' is the function that takes
* care of such situations; it is equivalent to the TrueType `IP'
* hinting instruction.
*
*
* Weak Points
*
* Other points in the outline must be interpolated using the
* coordinates of their previous and next unfitted contour neighbours.
* These are called `weak points' and are touched by the function
* `af_glyph_hints_align_weak_points', equivalent to the TrueType `IUP'
* hinting instruction. Typical candidates are control points and
* points on the contour without a major direction.
*
* The major effect is to reduce possible distortion caused by
* alignment of edges and strong points, thus weak points are processed
* after strong points.
*/
/* point hint flags */
#define AF_FLAG_NONE 0
/* point type flags */
#define AF_FLAG_CONIC ( 1U << 0 )
#define AF_FLAG_CUBIC ( 1U << 1 )
#define AF_FLAG_CONTROL ( AF_FLAG_CONIC | AF_FLAG_CUBIC )
/* point touch flags */
#define AF_FLAG_TOUCH_X ( 1U << 2 )
#define AF_FLAG_TOUCH_Y ( 1U << 3 )
/* candidates for weak interpolation have this flag set */
#define AF_FLAG_WEAK_INTERPOLATION ( 1U << 4 )
/* the distance to the next point is very small */
#define AF_FLAG_NEAR ( 1U << 5 )
/* edge hint flags */
#define AF_EDGE_NORMAL 0
#define AF_EDGE_ROUND ( 1U << 0 )
#define AF_EDGE_SERIF ( 1U << 1 )
#define AF_EDGE_DONE ( 1U << 2 )
#define AF_EDGE_NEUTRAL ( 1U << 3 ) /* edge aligns to a neutral blue zone */
typedef struct AF_PointRec_* AF_Point;
typedef struct AF_SegmentRec_* AF_Segment;
typedef struct AF_EdgeRec_* AF_Edge;
typedef struct AF_PointRec_
{
FT_UShort flags; /* point flags used by hinter */
FT_Char in_dir; /* direction of inwards vector */
FT_Char out_dir; /* direction of outwards vector */
FT_Pos ox, oy; /* original, scaled position */
FT_Short fx, fy; /* original, unscaled position (in font units) */
FT_Pos x, y; /* current position */
FT_Pos u, v; /* current (x,y) or (y,x) depending on context */
AF_Point next; /* next point in contour */
AF_Point prev; /* previous point in contour */
#ifdef FT_DEBUG_AUTOFIT
/* track `before' and `after' edges for strong points */
AF_Edge before[2];
AF_Edge after[2];
#endif
} AF_PointRec;
typedef struct AF_SegmentRec_
{
FT_Byte flags; /* edge/segment flags for this segment */
FT_Char dir; /* segment direction */
FT_Short pos; /* position of segment */
FT_Short delta; /* deviation from segment position */
FT_Short min_coord; /* minimum coordinate of segment */
FT_Short max_coord; /* maximum coordinate of segment */
FT_Short height; /* the hinted segment height */
AF_Edge edge; /* the segment's parent edge */
AF_Segment edge_next; /* link to next segment in parent edge */
AF_Segment link; /* (stem) link segment */
AF_Segment serif; /* primary segment for serifs */
FT_Pos score; /* used during stem matching */
FT_Pos len; /* used during stem matching */
AF_Point first; /* first point in edge segment */
AF_Point last; /* last point in edge segment */
} AF_SegmentRec;
typedef struct AF_EdgeRec_
{
FT_Short fpos; /* original, unscaled position (in font units) */
FT_Pos opos; /* original, scaled position */
FT_Pos pos; /* current position */
FT_Byte flags; /* edge flags */
FT_Char dir; /* edge direction */
FT_Fixed scale; /* used to speed up interpolation between edges */
AF_Width blue_edge; /* non-NULL if this is a blue edge */
AF_Edge link; /* link edge */
AF_Edge serif; /* primary edge for serifs */
FT_Int score; /* used during stem matching */
AF_Segment first; /* first segment in edge */
AF_Segment last; /* last segment in edge */
} AF_EdgeRec;
#define AF_SEGMENTS_EMBEDDED 18 /* number of embedded segments */
#define AF_EDGES_EMBEDDED 12 /* number of embedded edges */
typedef struct AF_AxisHintsRec_
{
FT_UInt num_segments; /* number of used segments */
FT_UInt max_segments; /* number of allocated segments */
AF_Segment segments; /* segments array */
FT_UInt num_edges; /* number of used edges */
FT_UInt max_edges; /* number of allocated edges */
AF_Edge edges; /* edges array */
AF_Direction major_dir; /* either vertical or horizontal */
/* two arrays to avoid allocation penalty */
struct
{
AF_SegmentRec segments[AF_SEGMENTS_EMBEDDED];
AF_EdgeRec edges[AF_EDGES_EMBEDDED];
} embedded;
} AF_AxisHintsRec, *AF_AxisHints;
#define AF_POINTS_EMBEDDED 96 /* number of embedded points */
#define AF_CONTOURS_EMBEDDED 8 /* number of embedded contours */
typedef struct AF_GlyphHintsRec_
{
FT_Memory memory;
FT_Fixed x_scale;
FT_Pos x_delta;
FT_Fixed y_scale;
FT_Pos y_delta;
FT_Int max_points; /* number of allocated points */
FT_Int num_points; /* number of used points */
AF_Point points; /* points array */
FT_Int max_contours; /* number of allocated contours */
FT_Int num_contours; /* number of used contours */
AF_Point* contours; /* contours array */
AF_AxisHintsRec axis[AF_DIMENSION_MAX];
FT_UInt32 scaler_flags; /* copy of scaler flags */
FT_UInt32 other_flags; /* free for style-specific */
/* implementations */
AF_StyleMetrics metrics;
/* Two arrays to avoid allocation penalty. */
/* The `embedded' structure must be the last element! */
struct
{
AF_Point contours[AF_CONTOURS_EMBEDDED];
AF_PointRec points[AF_POINTS_EMBEDDED];
} embedded;
} AF_GlyphHintsRec;
#define AF_HINTS_TEST_SCALER( h, f ) ( (h)->scaler_flags & (f) )
#define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) )
#ifdef FT_DEBUG_AUTOFIT
#define AF_HINTS_DO_HORIZONTAL( h ) \
( !af_debug_disable_horz_hints_ && \
!AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) )
#define AF_HINTS_DO_VERTICAL( h ) \
( !af_debug_disable_vert_hints_ && \
!AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) )
#define AF_HINTS_DO_BLUES( h ) ( !af_debug_disable_blue_hints_ )
#else /* !FT_DEBUG_AUTOFIT */
#define AF_HINTS_DO_HORIZONTAL( h ) \
!AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL )
#define AF_HINTS_DO_VERTICAL( h ) \
!AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL )
#define AF_HINTS_DO_BLUES( h ) 1
#endif /* !FT_DEBUG_AUTOFIT */
#define AF_HINTS_DO_ADVANCE( h ) \
!AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE )
FT_LOCAL( AF_Direction )
af_direction_compute( FT_Pos dx,
FT_Pos dy );
FT_LOCAL( FT_Error )
af_axis_hints_new_segment( AF_AxisHints axis,
FT_Memory memory,
AF_Segment *asegment );
FT_LOCAL( FT_Error)
af_axis_hints_new_edge( AF_AxisHints axis,
FT_Int fpos,
AF_Direction dir,
FT_Bool top_to_bottom_hinting,
FT_Memory memory,
AF_Edge *edge );
FT_LOCAL( void )
af_glyph_hints_init( AF_GlyphHints hints,
FT_Memory memory );
FT_LOCAL( void )
af_glyph_hints_rescale( AF_GlyphHints hints,
AF_StyleMetrics metrics );
FT_LOCAL( FT_Error )
af_glyph_hints_reload( AF_GlyphHints hints,
FT_Outline* outline );
FT_LOCAL( void )
af_glyph_hints_save( AF_GlyphHints hints,
FT_Outline* outline );
FT_LOCAL( void )
af_glyph_hints_align_edge_points( AF_GlyphHints hints,
AF_Dimension dim );
FT_LOCAL( void )
af_glyph_hints_align_strong_points( AF_GlyphHints hints,
AF_Dimension dim );
FT_LOCAL( void )
af_glyph_hints_align_weak_points( AF_GlyphHints hints,
AF_Dimension dim );
FT_LOCAL( void )
af_glyph_hints_done( AF_GlyphHints hints );
/* */
#define AF_SEGMENT_LEN( seg ) ( (seg)->max_coord - (seg)->min_coord )
#define AF_SEGMENT_DIST( seg1, seg2 ) ( ( (seg1)->pos > (seg2)->pos ) \
? (seg1)->pos - (seg2)->pos \
: (seg2)->pos - (seg1)->pos )
FT_END_HEADER
#endif /* AFHINTS_H_ */
/* END */

View file

@ -0,0 +1,157 @@
/****************************************************************************
*
* afindic.c
*
* Auto-fitter hinting routines for Indic writing system (body).
*
* Copyright (C) 2007-2023 by
* Rahul Bhalerao <rahul.bhalerao@redhat.com>, <b.rahul.pm@gmail.com>.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "aftypes.h"
#include "aflatin.h"
#include "afcjk.h"
#ifdef AF_CONFIG_OPTION_INDIC
#include "afindic.h"
#include "aferrors.h"
static FT_Error
af_indic_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
FT_Face face )
{
AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
/* skip blue zone init in CJK routines */
FT_CharMap oldmap = face->charmap;
metrics->units_per_em = face->units_per_EM;
if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
face->charmap = NULL;
else
{
af_cjk_metrics_init_widths( metrics, face );
#if 0
/* either need indic specific blue_chars[] or just skip blue zones */
af_cjk_metrics_init_blues( metrics, face, af_cjk_blue_chars );
#endif
af_cjk_metrics_check_digits( metrics, face );
}
face->charmap = oldmap;
return FT_Err_Ok;
}
static void
af_indic_metrics_scale( AF_StyleMetrics metrics,
AF_Scaler scaler )
{
/* use CJK routines */
af_cjk_metrics_scale( metrics, scaler );
}
static FT_Error
af_indic_hints_init( AF_GlyphHints hints,
AF_StyleMetrics metrics )
{
/* use CJK routines */
return af_cjk_hints_init( hints, metrics );
}
static FT_Error
af_indic_hints_apply( FT_UInt glyph_index,
AF_GlyphHints hints,
FT_Outline* outline,
AF_StyleMetrics metrics )
{
/* use CJK routines */
return af_cjk_hints_apply( glyph_index, hints, outline, metrics );
}
/* Extract standard_width from writing system/script specific */
/* metrics class. */
static void
af_indic_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
FT_Pos* stdHW,
FT_Pos* stdVW )
{
AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
if ( stdHW )
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
if ( stdVW )
*stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** I N D I C S C R I P T C L A S S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
AF_DEFINE_WRITING_SYSTEM_CLASS(
af_indic_writing_system_class,
AF_WRITING_SYSTEM_INDIC,
sizeof ( AF_CJKMetricsRec ),
(AF_WritingSystem_InitMetricsFunc) af_indic_metrics_init, /* style_metrics_init */
(AF_WritingSystem_ScaleMetricsFunc)af_indic_metrics_scale, /* style_metrics_scale */
(AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
(AF_WritingSystem_GetStdWidthsFunc)af_indic_get_standard_widths, /* style_metrics_getstdw */
(AF_WritingSystem_InitHintsFunc) af_indic_hints_init, /* style_hints_init */
(AF_WritingSystem_ApplyHintsFunc) af_indic_hints_apply /* style_hints_apply */
)
#else /* !AF_CONFIG_OPTION_INDIC */
AF_DEFINE_WRITING_SYSTEM_CLASS(
af_indic_writing_system_class,
AF_WRITING_SYSTEM_INDIC,
sizeof ( AF_CJKMetricsRec ),
(AF_WritingSystem_InitMetricsFunc) NULL, /* style_metrics_init */
(AF_WritingSystem_ScaleMetricsFunc)NULL, /* style_metrics_scale */
(AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
(AF_WritingSystem_GetStdWidthsFunc)NULL, /* style_metrics_getstdw */
(AF_WritingSystem_InitHintsFunc) NULL, /* style_hints_init */
(AF_WritingSystem_ApplyHintsFunc) NULL /* style_hints_apply */
)
#endif /* !AF_CONFIG_OPTION_INDIC */
/* END */

View file

@ -0,0 +1,41 @@
/****************************************************************************
*
* afindic.h
*
* Auto-fitter hinting routines for Indic writing system
* (specification).
*
* Copyright (C) 2007-2023 by
* Rahul Bhalerao <rahul.bhalerao@redhat.com>, <b.rahul.pm@gmail.com>.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFINDIC_H_
#define AFINDIC_H_
#include "afhints.h"
FT_BEGIN_HEADER
/* the `indic' writing system */
AF_DECLARE_WRITING_SYSTEM_CLASS( af_indic_writing_system_class )
/* */
FT_END_HEADER
#endif /* AFINDIC_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,194 @@
/****************************************************************************
*
* aflatin.h
*
* Auto-fitter hinting routines for latin writing system
* (specification).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFLATIN_H_
#define AFLATIN_H_
#include "afhints.h"
FT_BEGIN_HEADER
/* the `latin' writing system */
AF_DECLARE_WRITING_SYSTEM_CLASS( af_latin_writing_system_class )
/* constants are given with units_per_em == 2048 in mind */
#define AF_LATIN_CONSTANT( metrics, c ) \
( ( (c) * (FT_Long)( (AF_LatinMetrics)(metrics) )->units_per_em ) / 2048 )
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** L A T I N G L O B A L M E T R I C S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*
* The following declarations could be embedded in the file `aflatin.c';
* they have been made semi-public to allow alternate writing system
* hinters to re-use some of them.
*/
#define AF_LATIN_IS_TOP_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_LATIN_TOP )
#define AF_LATIN_IS_SUB_TOP_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_LATIN_SUB_TOP )
#define AF_LATIN_IS_NEUTRAL_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_LATIN_NEUTRAL )
#define AF_LATIN_IS_X_HEIGHT_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT )
#define AF_LATIN_IS_LONG_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG )
#define AF_LATIN_MAX_WIDTHS 16
#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */
#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */
#define AF_LATIN_BLUE_SUB_TOP ( 1U << 2 ) /* we have a subscript top */
/* blue zone */
#define AF_LATIN_BLUE_NEUTRAL ( 1U << 3 ) /* we have neutral blue zone */
#define AF_LATIN_BLUE_ADJUSTMENT ( 1U << 4 ) /* used for scale adjustment */
/* optimization */
typedef struct AF_LatinBlueRec_
{
AF_WidthRec ref;
AF_WidthRec shoot;
FT_Pos ascender;
FT_Pos descender;
FT_UInt flags;
} AF_LatinBlueRec, *AF_LatinBlue;
typedef struct AF_LatinAxisRec_
{
FT_Fixed scale;
FT_Pos delta;
FT_UInt width_count; /* number of used widths */
AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]; /* widths array */
FT_Pos edge_distance_threshold; /* used for creating edges */
FT_Pos standard_width; /* the default stem thickness */
FT_Bool extra_light; /* is standard width very light? */
/* ignored for horizontal metrics */
FT_UInt blue_count;
AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX];
FT_Fixed org_scale;
FT_Pos org_delta;
} AF_LatinAxisRec, *AF_LatinAxis;
typedef struct AF_LatinMetricsRec_
{
AF_StyleMetricsRec root;
FT_UInt units_per_em;
AF_LatinAxisRec axis[AF_DIMENSION_MAX];
} AF_LatinMetricsRec, *AF_LatinMetrics;
FT_LOCAL( FT_Error )
af_latin_metrics_init( AF_StyleMetrics metrics,
FT_Face face );
FT_LOCAL( void )
af_latin_metrics_scale( AF_StyleMetrics metrics,
AF_Scaler scaler );
FT_LOCAL( void )
af_latin_metrics_init_widths( AF_LatinMetrics metrics,
FT_Face face );
FT_LOCAL( void )
af_latin_metrics_check_digits( AF_LatinMetrics metrics,
FT_Face face );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** L A T I N G L Y P H A N A L Y S I S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
#define AF_LATIN_HINTS_HORZ_SNAP ( 1U << 0 ) /* stem width snapping */
#define AF_LATIN_HINTS_VERT_SNAP ( 1U << 1 ) /* stem height snapping */
#define AF_LATIN_HINTS_STEM_ADJUST ( 1U << 2 ) /* stem width/height */
/* adjustment */
#define AF_LATIN_HINTS_MONO ( 1U << 3 ) /* monochrome rendering */
#define AF_LATIN_HINTS_DO_HORZ_SNAP( h ) \
AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_HORZ_SNAP )
#define AF_LATIN_HINTS_DO_VERT_SNAP( h ) \
AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_VERT_SNAP )
#define AF_LATIN_HINTS_DO_STEM_ADJUST( h ) \
AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_STEM_ADJUST )
#define AF_LATIN_HINTS_DO_MONO( h ) \
AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_MONO )
/*
* The next functions shouldn't normally be exported. However, other
* writing systems might like to use these functions as-is.
*/
FT_LOCAL( FT_Error )
af_latin_hints_compute_segments( AF_GlyphHints hints,
AF_Dimension dim );
FT_LOCAL( void )
af_latin_hints_link_segments( AF_GlyphHints hints,
FT_UInt width_count,
AF_WidthRec* widths,
AF_Dimension dim );
FT_LOCAL( FT_Error )
af_latin_hints_compute_edges( AF_GlyphHints hints,
AF_Dimension dim );
FT_LOCAL( FT_Error )
af_latin_hints_detect_features( AF_GlyphHints hints,
FT_UInt width_count,
AF_WidthRec* widths,
AF_Dimension dim );
/* */
FT_END_HEADER
#endif /* AFLATIN_H_ */
/* END */

View file

@ -0,0 +1,706 @@
/****************************************************************************
*
* afloader.c
*
* Auto-fitter glyph loading routines (body).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "afglobal.h"
#include "afloader.h"
#include "afhints.h"
#include "aferrors.h"
#include "afmodule.h"
#include <freetype/internal/ftcalc.h>
/* Initialize glyph loader. */
FT_LOCAL_DEF( void )
af_loader_init( AF_Loader loader,
AF_GlyphHints hints )
{
FT_ZERO( loader );
loader->hints = hints;
}
/* Reset glyph loader and compute globals if necessary. */
FT_LOCAL_DEF( FT_Error )
af_loader_reset( AF_Loader loader,
AF_Module module,
FT_Face face )
{
FT_Error error = FT_Err_Ok;
loader->face = face;
loader->globals = (AF_FaceGlobals)face->autohint.data;
if ( !loader->globals )
{
error = af_face_globals_new( face, &loader->globals, module );
if ( !error )
{
face->autohint.data = (FT_Pointer)loader->globals;
face->autohint.finalizer = af_face_globals_free;
}
}
return error;
}
/* Finalize glyph loader. */
FT_LOCAL_DEF( void )
af_loader_done( AF_Loader loader )
{
loader->face = NULL;
loader->globals = NULL;
loader->hints = NULL;
}
#define af_intToFixed( i ) \
( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
#define af_fixedToInt( x ) \
( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
#define af_floatToFixed( f ) \
( (FT_Fixed)( (f) * 65536.0 + 0.5 ) )
static FT_Error
af_loader_embolden_glyph_in_slot( AF_Loader loader,
FT_Face face,
AF_StyleMetrics style_metrics )
{
FT_Error error = FT_Err_Ok;
FT_GlyphSlot slot = face->glyph;
AF_FaceGlobals globals = loader->globals;
AF_WritingSystemClass writing_system_class;
FT_Size_Metrics* size_metrics = &face->size->internal->autohint_metrics;
FT_Pos stdVW = 0;
FT_Pos stdHW = 0;
FT_Bool size_changed = size_metrics->x_ppem !=
globals->stem_darkening_for_ppem;
FT_Fixed em_size = af_intToFixed( face->units_per_EM );
FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L };
/* Skip stem darkening for broken fonts. */
if ( !face->units_per_EM )
{
error = FT_ERR( Corrupted_Font_Header );
goto Exit;
}
/*
* We depend on the writing system (script analyzers) to supply
* standard widths for the script of the glyph we are looking at. If
* it can't deliver, stem darkening is disabled.
*/
writing_system_class =
af_writing_system_classes[style_metrics->style_class->writing_system];
if ( writing_system_class->style_metrics_getstdw )
writing_system_class->style_metrics_getstdw( style_metrics,
&stdHW,
&stdVW );
else
{
error = FT_ERR( Unimplemented_Feature );
goto Exit;
}
if ( size_changed ||
( stdVW > 0 && stdVW != globals->standard_vertical_width ) )
{
FT_Fixed darken_by_font_units_x, darken_x;
darken_by_font_units_x =
af_loader_compute_darkening( loader,
face,
stdVW ) ;
darken_x = FT_MulFix( darken_by_font_units_x,
size_metrics->x_scale );
globals->standard_vertical_width = stdVW;
globals->stem_darkening_for_ppem = size_metrics->x_ppem;
globals->darken_x = af_fixedToInt( darken_x );
}
if ( size_changed ||
( stdHW > 0 && stdHW != globals->standard_horizontal_width ) )
{
FT_Fixed darken_by_font_units_y, darken_y;
darken_by_font_units_y =
af_loader_compute_darkening( loader,
face,
stdHW ) ;
darken_y = FT_MulFix( darken_by_font_units_y,
size_metrics->y_scale );
globals->standard_horizontal_width = stdHW;
globals->stem_darkening_for_ppem = size_metrics->x_ppem;
globals->darken_y = af_fixedToInt( darken_y );
/*
* Scale outlines down on the Y-axis to keep them inside their blue
* zones. The stronger the emboldening, the stronger the downscaling
* (plus heuristical padding to prevent outlines still falling out
* their zones due to rounding).
*
* Reason: `FT_Outline_Embolden' works by shifting the rightmost
* points of stems farther to the right, and topmost points farther
* up. This positions points on the Y-axis outside their
* pre-computed blue zones and leads to distortion when applying the
* hints in the code further below. Code outside this emboldening
* block doesn't know we are presenting it with modified outlines the
* analyzer didn't see!
*
* An unfortunate side effect of downscaling is that the emboldening
* effect is slightly decreased. The loss becomes more pronounced
* versus the CFF driver at smaller sizes, e.g., at 9ppem and below.
*/
globals->scale_down_factor =
FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ),
em_size );
}
FT_Outline_EmboldenXY( &slot->outline,
globals->darken_x,
globals->darken_y );
scale_down_matrix.yy = globals->scale_down_factor;
FT_Outline_Transform( &slot->outline, &scale_down_matrix );
Exit:
return error;
}
/* Load the glyph at index into the current slot of a face and hint it. */
FT_LOCAL_DEF( FT_Error )
af_loader_load_glyph( AF_Loader loader,
AF_Module module,
FT_Face face,
FT_UInt glyph_index,
FT_Int32 load_flags )
{
FT_Error error;
FT_Size size = face->size;
FT_Size_Internal size_internal = size->internal;
FT_GlyphSlot slot = face->glyph;
FT_Slot_Internal slot_internal = slot->internal;
FT_GlyphLoader gloader = slot_internal->loader;
AF_GlyphHints hints = loader->hints;
AF_ScalerRec scaler;
AF_StyleMetrics style_metrics;
FT_UInt style_options = AF_STYLE_NONE_DFLT;
AF_StyleClass style_class;
AF_WritingSystemClass writing_system_class;
FT_ZERO( &scaler );
if ( !size_internal->autohint_metrics.x_scale ||
size_internal->autohint_mode != FT_LOAD_TARGET_MODE( load_flags ) )
{
/* switching between hinting modes usually means different scaling */
/* values; this later on enforces recomputation of everything */
/* related to the current size */
size_internal->autohint_mode = FT_LOAD_TARGET_MODE( load_flags );
size_internal->autohint_metrics = size->metrics;
#ifdef AF_CONFIG_OPTION_TT_SIZE_METRICS
{
FT_Size_Metrics* size_metrics = &size_internal->autohint_metrics;
/* set metrics to integer values and adjust scaling accordingly; */
/* this is the same setup as with TrueType fonts, cf. function */
/* `tt_size_reset' in file `ttobjs.c' */
size_metrics->ascender = FT_PIX_ROUND(
FT_MulFix( face->ascender,
size_metrics->y_scale ) );
size_metrics->descender = FT_PIX_ROUND(
FT_MulFix( face->descender,
size_metrics->y_scale ) );
size_metrics->height = FT_PIX_ROUND(
FT_MulFix( face->height,
size_metrics->y_scale ) );
size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6,
face->units_per_EM );
size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6,
face->units_per_EM );
size_metrics->max_advance = FT_PIX_ROUND(
FT_MulFix( face->max_advance_width,
size_metrics->x_scale ) );
}
#endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */
}
/*
* TODO: This code currently doesn't support fractional advance widths,
* i.e., placing hinted glyphs at anything other than integer
* x-positions. This is only relevant for the warper code, which
* scales and shifts glyphs to optimize blackness of stems (hinting on
* the x-axis by nature places things on pixel integers, hinting on the
* y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta
* values of the scaler would need to be adjusted.
*/
scaler.face = face;
scaler.x_scale = size_internal->autohint_metrics.x_scale;
scaler.x_delta = 0;
scaler.y_scale = size_internal->autohint_metrics.y_scale;
scaler.y_delta = 0;
scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
scaler.flags = 0;
/* note that the fallback style can't be changed anymore */
/* after the first call of `af_loader_load_glyph' */
error = af_loader_reset( loader, module, face );
if ( error )
goto Exit;
/*
* Glyphs (really code points) are assigned to scripts. Script
* analysis is done lazily: For each glyph that passes through here,
* the corresponding script analyzer is called, but returns immediately
* if it has been run already.
*/
error = af_face_globals_get_metrics( loader->globals, glyph_index,
style_options, &style_metrics );
if ( error )
goto Exit;
style_class = style_metrics->style_class;
writing_system_class =
af_writing_system_classes[style_class->writing_system];
loader->metrics = style_metrics;
if ( writing_system_class->style_metrics_scale )
writing_system_class->style_metrics_scale( style_metrics, &scaler );
else
style_metrics->scaler = scaler;
if ( writing_system_class->style_hints_init )
{
error = writing_system_class->style_hints_init( hints,
style_metrics );
if ( error )
goto Exit;
}
/*
* Do the main work of `af_loader_load_glyph'. Note that we never have
* to deal with composite glyphs as those get loaded into
* FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function.
* In the rare cases where FT_LOAD_NO_RECURSE is set, it implies
* FT_LOAD_NO_SCALE and as such the auto-hinter is never called.
*/
load_flags |= FT_LOAD_NO_SCALE |
FT_LOAD_IGNORE_TRANSFORM |
FT_LOAD_LINEAR_DESIGN;
load_flags &= ~FT_LOAD_RENDER;
error = FT_Load_Glyph( face, glyph_index, load_flags );
if ( error )
goto Exit;
/*
* Apply stem darkening (emboldening) here before hints are applied to
* the outline. Glyphs are scaled down proportionally to the
* emboldening so that curve points don't fall outside their
* precomputed blue zones.
*
* Any emboldening done by the font driver (e.g., the CFF driver)
* doesn't reach here because the autohinter loads the unprocessed
* glyphs in font units for analysis (functions `af_*_metrics_init_*')
* and then above to prepare it for the rasterizers by itself,
* independently of the font driver. So emboldening must be done here,
* within the autohinter.
*
* All glyphs to be autohinted pass through here one by one. The
* standard widths can therefore change from one glyph to the next,
* depending on what script a glyph is assigned to (each script has its
* own set of standard widths and other metrics). The darkening amount
* must therefore be recomputed for each size and
* `standard_{vertical,horizontal}_width' change.
*
* Ignore errors and carry on without emboldening.
*
*/
/* stem darkening only works well in `light' mode */
if ( scaler.render_mode == FT_RENDER_MODE_LIGHT &&
( !face->internal->no_stem_darkening ||
( face->internal->no_stem_darkening < 0 &&
!module->no_stem_darkening ) ) )
af_loader_embolden_glyph_in_slot( loader, face, style_metrics );
loader->transformed = slot_internal->glyph_transformed;
if ( loader->transformed )
{
FT_Matrix inverse;
loader->trans_matrix = slot_internal->glyph_matrix;
loader->trans_delta = slot_internal->glyph_delta;
inverse = loader->trans_matrix;
if ( !FT_Matrix_Invert( &inverse ) )
FT_Vector_Transform( &loader->trans_delta, &inverse );
}
switch ( slot->format )
{
case FT_GLYPH_FORMAT_OUTLINE:
/* translate the loaded glyph when an internal transform is needed */
if ( loader->transformed )
FT_Outline_Translate( &slot->outline,
loader->trans_delta.x,
loader->trans_delta.y );
/* compute original horizontal phantom points */
/* (and ignore vertical ones) */
loader->pp1.x = hints->x_delta;
loader->pp1.y = hints->y_delta;
loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
hints->x_scale ) + hints->x_delta;
loader->pp2.y = hints->y_delta;
/* be sure to check for spacing glyphs */
if ( slot->outline.n_points == 0 )
goto Hint_Metrics;
/* now load the slot image into the auto-outline */
/* and run the automatic hinting process */
if ( writing_system_class->style_hints_apply )
{
error = writing_system_class->style_hints_apply(
glyph_index,
hints,
&gloader->base.outline,
style_metrics );
if ( error )
goto Exit;
}
/* we now need to adjust the metrics according to the change in */
/* width/positioning that occurred during the hinting process */
if ( scaler.render_mode != FT_RENDER_MODE_LIGHT )
{
AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ];
if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
{
AF_Edge edge1 = axis->edges; /* leftmost edge */
AF_Edge edge2 = edge1 +
axis->num_edges - 1; /* rightmost edge */
FT_Pos old_rsb = loader->pp2.x - edge2->opos;
/* loader->pp1.x is always zero at this point of time */
FT_Pos old_lsb = edge1->opos; /* - loader->pp1.x */
FT_Pos new_lsb = edge1->pos;
/* remember unhinted values to later account */
/* for rounding errors */
FT_Pos pp1x_uh = new_lsb - old_lsb;
FT_Pos pp2x_uh = edge2->pos + old_rsb;
/* prefer too much space over too little space */
/* for very small sizes */
if ( old_lsb < 24 )
pp1x_uh -= 8;
if ( old_rsb < 24 )
pp2x_uh += 8;
loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
loader->pp1.x -= 64;
if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
loader->pp2.x += 64;
slot->lsb_delta = loader->pp1.x - pp1x_uh;
slot->rsb_delta = loader->pp2.x - pp2x_uh;
}
else
{
FT_Pos pp1x = loader->pp1.x;
FT_Pos pp2x = loader->pp2.x;
loader->pp1.x = FT_PIX_ROUND( pp1x );
loader->pp2.x = FT_PIX_ROUND( pp2x );
slot->lsb_delta = loader->pp1.x - pp1x;
slot->rsb_delta = loader->pp2.x - pp2x;
}
}
/* `light' mode uses integer advance widths */
/* but sets `lsb_delta' and `rsb_delta' */
else
{
FT_Pos pp1x = loader->pp1.x;
FT_Pos pp2x = loader->pp2.x;
loader->pp1.x = FT_PIX_ROUND( pp1x );
loader->pp2.x = FT_PIX_ROUND( pp2x );
slot->lsb_delta = loader->pp1.x - pp1x;
slot->rsb_delta = loader->pp2.x - pp2x;
}
break;
default:
/* we don't support other formats (yet?) */
error = FT_THROW( Unimplemented_Feature );
}
Hint_Metrics:
{
FT_BBox bbox;
FT_Vector vvector;
vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale );
vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale );
/* transform the hinted outline if needed */
if ( loader->transformed )
{
FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
FT_Vector_Transform( &vvector, &loader->trans_matrix );
}
/* we must translate our final outline by -pp1.x and compute */
/* the new metrics */
if ( loader->pp1.x )
FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
bbox.xMax = FT_PIX_CEIL( bbox.xMax );
bbox.yMax = FT_PIX_CEIL( bbox.yMax );
slot->metrics.width = bbox.xMax - bbox.xMin;
slot->metrics.height = bbox.yMax - bbox.yMin;
slot->metrics.horiBearingX = bbox.xMin;
slot->metrics.horiBearingY = bbox.yMax;
slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
/* for mono-width fonts (like Andale, Courier, etc.) we need */
/* to keep the original rounded advance width; ditto for */
/* digits if all have the same advance width */
if ( scaler.render_mode != FT_RENDER_MODE_LIGHT &&
( FT_IS_FIXED_WIDTH( slot->face ) ||
( af_face_globals_is_digit( loader->globals, glyph_index ) &&
style_metrics->digits_have_same_width ) ) )
{
slot->metrics.horiAdvance =
FT_MulFix( slot->metrics.horiAdvance,
style_metrics->scaler.x_scale );
/* Set delta values to 0. Otherwise code that uses them is */
/* going to ruin the fixed advance width. */
slot->lsb_delta = 0;
slot->rsb_delta = 0;
}
else
{
/* non-spacing glyphs must stay as-is */
if ( slot->metrics.horiAdvance )
slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
}
slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
style_metrics->scaler.y_scale );
slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
slot->format = FT_GLYPH_FORMAT_OUTLINE;
}
Exit:
return error;
}
/*
* Compute amount of font units the face should be emboldened by, in
* analogy to the CFF driver's `cf2_computeDarkening' function. See there
* for details of the algorithm.
*
* XXX: Currently a crude adaption of the original algorithm. Do better?
*/
FT_LOCAL_DEF( FT_Fixed )
af_loader_compute_darkening( AF_Loader loader,
FT_Face face,
FT_Pos standard_width )
{
AF_Module module = loader->globals->module;
FT_UShort units_per_EM;
FT_Fixed ppem, em_ratio;
FT_Fixed stem_width, stem_width_per_1000, scaled_stem, darken_amount;
FT_Int log_base_2;
FT_Int x1, y1, x2, y2, x3, y3, x4, y4;
ppem = FT_MAX( af_intToFixed( 4 ),
af_intToFixed( face->size->metrics.x_ppem ) );
units_per_EM = face->units_per_EM;
em_ratio = FT_DivFix( af_intToFixed( 1000 ),
af_intToFixed ( units_per_EM ) );
if ( em_ratio < af_floatToFixed( .01 ) )
{
/* If something goes wrong, don't embolden. */
return 0;
}
x1 = module->darken_params[0];
y1 = module->darken_params[1];
x2 = module->darken_params[2];
y2 = module->darken_params[3];
x3 = module->darken_params[4];
y3 = module->darken_params[5];
x4 = module->darken_params[6];
y4 = module->darken_params[7];
if ( standard_width <= 0 )
{
stem_width = af_intToFixed( 75 ); /* taken from cf2font.c */
stem_width_per_1000 = stem_width;
}
else
{
stem_width = af_intToFixed( standard_width );
stem_width_per_1000 = FT_MulFix( stem_width, em_ratio );
}
log_base_2 = FT_MSB( (FT_UInt32)stem_width_per_1000 ) +
FT_MSB( (FT_UInt32)ppem );
if ( log_base_2 >= 46 )
{
/* possible overflow */
scaled_stem = af_intToFixed( x4 );
}
else
scaled_stem = FT_MulFix( stem_width_per_1000, ppem );
/* now apply the darkening parameters */
if ( scaled_stem < af_intToFixed( x1 ) )
darken_amount = FT_DivFix( af_intToFixed( y1 ), ppem );
else if ( scaled_stem < af_intToFixed( x2 ) )
{
FT_Int xdelta = x2 - x1;
FT_Int ydelta = y2 - y1;
FT_Int x = stem_width_per_1000 -
FT_DivFix( af_intToFixed( x1 ), ppem );
if ( !xdelta )
goto Try_x3;
darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
FT_DivFix( af_intToFixed( y1 ), ppem );
}
else if ( scaled_stem < af_intToFixed( x3 ) )
{
Try_x3:
{
FT_Int xdelta = x3 - x2;
FT_Int ydelta = y3 - y2;
FT_Int x = stem_width_per_1000 -
FT_DivFix( af_intToFixed( x2 ), ppem );
if ( !xdelta )
goto Try_x4;
darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
FT_DivFix( af_intToFixed( y2 ), ppem );
}
}
else if ( scaled_stem < af_intToFixed( x4 ) )
{
Try_x4:
{
FT_Int xdelta = x4 - x3;
FT_Int ydelta = y4 - y3;
FT_Int x = stem_width_per_1000 -
FT_DivFix( af_intToFixed( x3 ), ppem );
if ( !xdelta )
goto Use_y4;
darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
FT_DivFix( af_intToFixed( y3 ), ppem );
}
}
else
{
Use_y4:
darken_amount = FT_DivFix( af_intToFixed( y4 ), ppem );
}
/* Convert darken_amount from per 1000 em to true character space. */
return FT_DivFix( darken_amount, em_ratio );
}
/* END */

View file

@ -0,0 +1,91 @@
/****************************************************************************
*
* afloader.h
*
* Auto-fitter glyph loading routines (specification).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFLOADER_H_
#define AFLOADER_H_
#include "afhints.h"
#include "afmodule.h"
#include "afglobal.h"
FT_BEGIN_HEADER
/*
* The autofitter module's (global) data structure to communicate with
* actual fonts. If necessary, `local' data like the current face, the
* current face's auto-hint data, or the current glyph's parameters
* relevant to auto-hinting are `swapped in'. Cf. functions like
* `af_loader_reset' and `af_loader_load_g'.
*/
typedef struct AF_LoaderRec_
{
/* current face data */
FT_Face face;
AF_FaceGlobals globals;
/* current glyph data */
AF_GlyphHints hints;
AF_StyleMetrics metrics;
FT_Bool transformed;
FT_Matrix trans_matrix;
FT_Vector trans_delta;
FT_Vector pp1;
FT_Vector pp2;
/* we don't handle vertical phantom points */
} AF_LoaderRec, *AF_Loader;
FT_LOCAL( void )
af_loader_init( AF_Loader loader,
AF_GlyphHints hints );
FT_LOCAL( FT_Error )
af_loader_reset( AF_Loader loader,
AF_Module module,
FT_Face face );
FT_LOCAL( void )
af_loader_done( AF_Loader loader );
FT_LOCAL( FT_Error )
af_loader_load_glyph( AF_Loader loader,
AF_Module module,
FT_Face face,
FT_UInt gindex,
FT_Int32 load_flags );
FT_LOCAL( FT_Fixed )
af_loader_compute_darkening( AF_Loader loader,
FT_Face face,
FT_Pos standard_width );
/* */
FT_END_HEADER
#endif /* AFLOADER_H_ */
/* END */

View file

@ -0,0 +1,527 @@
/****************************************************************************
*
* afmodule.c
*
* Auto-fitter module implementation (body).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "afglobal.h"
#include "afmodule.h"
#include "afloader.h"
#include "aferrors.h"
#ifdef FT_DEBUG_AUTOFIT
#ifndef FT_MAKE_OPTION_SINGLE_OBJECT
#ifdef __cplusplus
extern "C" {
#endif
extern void
af_glyph_hints_dump_segments( AF_GlyphHints hints,
FT_Bool to_stdout );
extern void
af_glyph_hints_dump_points( AF_GlyphHints hints,
FT_Bool to_stdout );
extern void
af_glyph_hints_dump_edges( AF_GlyphHints hints,
FT_Bool to_stdout );
#ifdef __cplusplus
}
#endif
#endif
int af_debug_disable_horz_hints_;
int af_debug_disable_vert_hints_;
int af_debug_disable_blue_hints_;
/* we use a global object instead of a local one for debugging */
static AF_GlyphHintsRec af_debug_hints_rec_[1];
void* af_debug_hints_ = af_debug_hints_rec_;
#endif
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/ftdriver.h>
#include <freetype/internal/services/svprop.h>
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT afmodule
static FT_Error
af_property_get_face_globals( FT_Face face,
AF_FaceGlobals* aglobals,
AF_Module module )
{
FT_Error error = FT_Err_Ok;
AF_FaceGlobals globals;
if ( !face )
return FT_THROW( Invalid_Face_Handle );
globals = (AF_FaceGlobals)face->autohint.data;
if ( !globals )
{
/* trigger computation of the global style data */
/* in case it hasn't been done yet */
error = af_face_globals_new( face, &globals, module );
if ( !error )
{
face->autohint.data = (FT_Pointer)globals;
face->autohint.finalizer = af_face_globals_free;
}
}
if ( !error )
*aglobals = globals;
return error;
}
static FT_Error
af_property_set( FT_Module ft_module,
const char* property_name,
const void* value,
FT_Bool value_is_string )
{
FT_Error error = FT_Err_Ok;
AF_Module module = (AF_Module)ft_module;
#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
FT_UNUSED( value_is_string );
#endif
if ( !ft_strcmp( property_name, "fallback-script" ) )
{
AF_Script* fallback_script;
FT_UInt ss;
#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
if ( value_is_string )
return FT_THROW( Invalid_Argument );
#endif
fallback_script = (AF_Script*)value;
/* We translate the fallback script to a fallback style that uses */
/* `fallback-script' as its script and `AF_COVERAGE_NONE' as its */
/* coverage value. */
for ( ss = 0; af_style_classes[ss]; ss++ )
{
AF_StyleClass style_class = af_style_classes[ss];
if ( style_class->script == *fallback_script &&
style_class->coverage == AF_COVERAGE_DEFAULT )
{
module->fallback_style = ss;
break;
}
}
if ( !af_style_classes[ss] )
{
FT_TRACE2(( "af_property_set: Invalid value %d for property `%s'\n",
*fallback_script, property_name ));
return FT_THROW( Invalid_Argument );
}
return error;
}
else if ( !ft_strcmp( property_name, "default-script" ) )
{
AF_Script* default_script;
#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
if ( value_is_string )
return FT_THROW( Invalid_Argument );
#endif
default_script = (AF_Script*)value;
module->default_script = *default_script;
return error;
}
else if ( !ft_strcmp( property_name, "increase-x-height" ) )
{
FT_Prop_IncreaseXHeight* prop;
AF_FaceGlobals globals;
#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
if ( value_is_string )
return FT_THROW( Invalid_Argument );
#endif
prop = (FT_Prop_IncreaseXHeight*)value;
error = af_property_get_face_globals( prop->face, &globals, module );
if ( !error )
globals->increase_x_height = prop->limit;
return error;
}
else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
{
FT_Int* darken_params;
FT_Int x1, y1, x2, y2, x3, y3, x4, y4;
#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
FT_Int dp[8];
if ( value_is_string )
{
const char* s = (const char*)value;
char* ep;
int i;
/* eight comma-separated numbers */
for ( i = 0; i < 7; i++ )
{
dp[i] = (FT_Int)ft_strtol( s, &ep, 10 );
if ( *ep != ',' || s == ep )
return FT_THROW( Invalid_Argument );
s = ep + 1;
}
dp[7] = (FT_Int)ft_strtol( s, &ep, 10 );
if ( !( *ep == '\0' || *ep == ' ' ) || s == ep )
return FT_THROW( Invalid_Argument );
darken_params = dp;
}
else
#endif
darken_params = (FT_Int*)value;
x1 = darken_params[0];
y1 = darken_params[1];
x2 = darken_params[2];
y2 = darken_params[3];
x3 = darken_params[4];
y3 = darken_params[5];
x4 = darken_params[6];
y4 = darken_params[7];
if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 ||
y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 ||
x1 > x2 || x2 > x3 || x3 > x4 ||
y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 )
return FT_THROW( Invalid_Argument );
module->darken_params[0] = x1;
module->darken_params[1] = y1;
module->darken_params[2] = x2;
module->darken_params[3] = y2;
module->darken_params[4] = x3;
module->darken_params[5] = y3;
module->darken_params[6] = x4;
module->darken_params[7] = y4;
return error;
}
else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
{
#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
if ( value_is_string )
{
const char* s = (const char*)value;
long nsd = ft_strtol( s, NULL, 10 );
if ( !nsd )
module->no_stem_darkening = FALSE;
else
module->no_stem_darkening = TRUE;
}
else
#endif
{
FT_Bool* no_stem_darkening = (FT_Bool*)value;
module->no_stem_darkening = *no_stem_darkening;
}
return error;
}
FT_TRACE2(( "af_property_set: missing property `%s'\n",
property_name ));
return FT_THROW( Missing_Property );
}
static FT_Error
af_property_get( FT_Module ft_module,
const char* property_name,
void* value )
{
FT_Error error = FT_Err_Ok;
AF_Module module = (AF_Module)ft_module;
if ( !ft_strcmp( property_name, "glyph-to-script-map" ) )
{
FT_Prop_GlyphToScriptMap* prop = (FT_Prop_GlyphToScriptMap*)value;
AF_FaceGlobals globals;
error = af_property_get_face_globals( prop->face, &globals, module );
if ( !error )
prop->map = globals->glyph_styles;
return error;
}
else if ( !ft_strcmp( property_name, "fallback-script" ) )
{
AF_Script* val = (AF_Script*)value;
AF_StyleClass style_class = af_style_classes[module->fallback_style];
*val = style_class->script;
return error;
}
else if ( !ft_strcmp( property_name, "default-script" ) )
{
AF_Script* val = (AF_Script*)value;
*val = module->default_script;
return error;
}
else if ( !ft_strcmp( property_name, "increase-x-height" ) )
{
FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value;
AF_FaceGlobals globals;
error = af_property_get_face_globals( prop->face, &globals, module );
if ( !error )
prop->limit = globals->increase_x_height;
return error;
}
else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
{
FT_Int* darken_params = module->darken_params;
FT_Int* val = (FT_Int*)value;
val[0] = darken_params[0];
val[1] = darken_params[1];
val[2] = darken_params[2];
val[3] = darken_params[3];
val[4] = darken_params[4];
val[5] = darken_params[5];
val[6] = darken_params[6];
val[7] = darken_params[7];
return error;
}
else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
{
FT_Bool no_stem_darkening = module->no_stem_darkening;
FT_Bool* val = (FT_Bool*)value;
*val = no_stem_darkening;
return error;
}
FT_TRACE2(( "af_property_get: missing property `%s'\n",
property_name ));
return FT_THROW( Missing_Property );
}
FT_DEFINE_SERVICE_PROPERTIESREC(
af_service_properties,
af_property_set, /* FT_Properties_SetFunc set_property */
af_property_get /* FT_Properties_GetFunc get_property */
)
FT_DEFINE_SERVICEDESCREC1(
af_services,
FT_SERVICE_ID_PROPERTIES, &af_service_properties )
FT_CALLBACK_DEF( FT_Module_Interface )
af_get_interface( FT_Module module,
const char* module_interface )
{
FT_UNUSED( module );
return ft_service_list_lookup( af_services, module_interface );
}
FT_CALLBACK_DEF( FT_Error )
af_autofitter_init( FT_Module ft_module ) /* AF_Module */
{
AF_Module module = (AF_Module)ft_module;
module->fallback_style = AF_STYLE_FALLBACK;
module->default_script = AF_SCRIPT_DEFAULT;
module->no_stem_darkening = TRUE;
module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
module->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2;
module->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2;
module->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3;
module->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3;
module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
return FT_Err_Ok;
}
FT_CALLBACK_DEF( void )
af_autofitter_done( FT_Module ft_module ) /* AF_Module */
{
FT_UNUSED( ft_module );
#ifdef FT_DEBUG_AUTOFIT
if ( af_debug_hints_rec_->memory )
af_glyph_hints_done( af_debug_hints_rec_ );
#endif
}
FT_CALLBACK_DEF( FT_Error )
af_autofitter_load_glyph( FT_AutoHinter module_,
FT_GlyphSlot slot,
FT_Size size,
FT_UInt glyph_index,
FT_Int32 load_flags )
{
AF_Module module = (AF_Module)module_;
FT_Error error = FT_Err_Ok;
FT_Memory memory = module->root.library->memory;
#ifdef FT_DEBUG_AUTOFIT
/* in debug mode, we use a global object that survives this routine */
AF_GlyphHints hints = af_debug_hints_rec_;
AF_LoaderRec loader[1];
FT_UNUSED( size );
if ( hints->memory )
af_glyph_hints_done( hints );
af_glyph_hints_init( hints, memory );
af_loader_init( loader, hints );
error = af_loader_load_glyph( loader, module, slot->face,
glyph_index, load_flags );
#ifdef FT_DEBUG_LEVEL_TRACE
if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] )
{
#endif
af_glyph_hints_dump_points( hints, 0 );
af_glyph_hints_dump_segments( hints, 0 );
af_glyph_hints_dump_edges( hints, 0 );
#ifdef FT_DEBUG_LEVEL_TRACE
}
#endif
af_loader_done( loader );
return error;
#else /* !FT_DEBUG_AUTOFIT */
AF_GlyphHintsRec hints[1];
AF_LoaderRec loader[1];
FT_UNUSED( size );
af_glyph_hints_init( hints, memory );
af_loader_init( loader, hints );
error = af_loader_load_glyph( loader, module, slot->face,
glyph_index, load_flags );
af_loader_done( loader );
af_glyph_hints_done( hints );
return error;
#endif /* !FT_DEBUG_AUTOFIT */
}
FT_DEFINE_AUTOHINTER_INTERFACE(
af_autofitter_interface,
NULL, /* FT_AutoHinter_GlobalResetFunc reset_face */
NULL, /* FT_AutoHinter_GlobalGetFunc get_global_hints */
NULL, /* FT_AutoHinter_GlobalDoneFunc done_global_hints */
af_autofitter_load_glyph /* FT_AutoHinter_GlyphLoadFunc load_glyph */
)
FT_DEFINE_MODULE(
autofit_module_class,
FT_MODULE_HINTER,
sizeof ( AF_ModuleRec ),
"autofitter",
0x10000L, /* version 1.0 of the autofitter */
0x20000L, /* requires FreeType 2.0 or above */
(const void*)&af_autofitter_interface,
af_autofitter_init, /* FT_Module_Constructor module_init */
af_autofitter_done, /* FT_Module_Destructor module_done */
af_get_interface /* FT_Module_Requester get_interface */
)
/* END */

View file

@ -0,0 +1,55 @@
/****************************************************************************
*
* afmodule.h
*
* Auto-fitter module implementation (specification).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFMODULE_H_
#define AFMODULE_H_
#include <freetype/internal/ftobjs.h>
#include <freetype/ftmodapi.h>
FT_BEGIN_HEADER
/*
* This is the `extended' FT_Module structure that holds the
* autofitter's global data.
*/
typedef struct AF_ModuleRec_
{
FT_ModuleRec root;
FT_UInt fallback_style;
AF_Script default_script;
FT_Bool no_stem_darkening;
FT_Int darken_params[8];
} AF_ModuleRec, *AF_Module;
FT_DECLARE_AUTOHINTER_INTERFACE( af_autofitter_interface )
FT_DECLARE_MODULE( autofit_module_class )
FT_END_HEADER
#endif /* AFMODULE_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,88 @@
/****************************************************************************
*
* afmparse.h
*
* AFM parser (specification).
*
* Copyright (C) 2006-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFMPARSE_H_
#define AFMPARSE_H_
#include <freetype/internal/psaux.h>
FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
afm_parser_init( AFM_Parser parser,
FT_Memory memory,
FT_Byte* base,
FT_Byte* limit );
FT_LOCAL( void )
afm_parser_done( AFM_Parser parser );
FT_LOCAL( FT_Error )
afm_parser_parse( AFM_Parser parser );
enum AFM_ValueType_
{
AFM_VALUE_TYPE_STRING,
AFM_VALUE_TYPE_NAME,
AFM_VALUE_TYPE_FIXED, /* real number */
AFM_VALUE_TYPE_INTEGER,
AFM_VALUE_TYPE_BOOL,
AFM_VALUE_TYPE_INDEX /* glyph index */
};
typedef struct AFM_ValueRec_
{
enum AFM_ValueType_ type;
union
{
char* s;
FT_Fixed f;
FT_Int i;
FT_UInt u;
FT_Bool b;
} u;
} AFM_ValueRec, *AFM_Value;
#define AFM_MAX_ARGUMENTS 5
FT_LOCAL( FT_Int )
afm_parser_read_vals( AFM_Parser parser,
AFM_Value vals,
FT_Int n );
/* read the next key from the next line or column */
FT_LOCAL( char* )
afm_parser_next_key( AFM_Parser parser,
FT_Bool line,
FT_Offset* len );
FT_END_HEADER
#endif /* AFMPARSE_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,47 @@
/****************************************************************************
*
* afranges.h
*
* Auto-fitter Unicode script ranges (specification).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFRANGES_H_
#define AFRANGES_H_
#include "aftypes.h"
FT_BEGIN_HEADER
#undef SCRIPT
#define SCRIPT( s, S, d, h, H, ss ) \
extern const AF_Script_UniRangeRec af_ ## s ## _uniranges[];
#include "afscript.h"
#undef SCRIPT
#define SCRIPT( s, S, d, h, H, ss ) \
extern const AF_Script_UniRangeRec af_ ## s ## _nonbase_uniranges[];
#include "afscript.h"
/* */
FT_END_HEADER
#endif /* AFRANGES_H_ */
/* END */

View file

@ -0,0 +1,408 @@
/****************************************************************************
*
* afscript.h
*
* Auto-fitter scripts (specification only).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/* The following part can be included multiple times. */
/* Define `SCRIPT' as needed. */
/* Add new scripts here. The first and second arguments are the */
/* script name in lowercase and uppercase, respectively, followed */
/* by a description string. Then comes the corresponding HarfBuzz */
/* script name tag, followed by a string of standard characters (to */
/* derive the standard width and height of stems). */
/* */
/* Note that fallback scripts only have a default style, thus we */
/* use `HB_SCRIPT_INVALID' as the HarfBuzz script name tag for */
/* them. */
SCRIPT( adlm, ADLM,
"Adlam",
HB_SCRIPT_ADLAM,
HINTING_BOTTOM_TO_TOP,
"\xF0\x9E\xA4\x8C \xF0\x9E\xA4\xAE" ) /* 𞤌 𞤮 */
SCRIPT( arab, ARAB,
"Arabic",
HB_SCRIPT_ARABIC,
HINTING_BOTTOM_TO_TOP,
"\xD9\x84 \xD8\xAD \xD9\x80" ) /* ل ح ـ */
SCRIPT( armn, ARMN,
"Armenian",
HB_SCRIPT_ARMENIAN,
HINTING_BOTTOM_TO_TOP,
"\xD5\xBD \xD5\x8D" ) /* ս Ս */
SCRIPT( avst, AVST,
"Avestan",
HB_SCRIPT_AVESTAN,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\xAC\x9A" ) /* 𐬚 */
SCRIPT( bamu, BAMU,
"Bamum",
HB_SCRIPT_BAMUM,
HINTING_BOTTOM_TO_TOP,
"\xEA\x9B\x81 \xEA\x9B\xAF" ) /* ꛁ */
/* there are no simple forms for letters; we thus use two digit shapes */
SCRIPT( beng, BENG,
"Bengali",
HB_SCRIPT_BENGALI,
HINTING_TOP_TO_BOTTOM,
"\xE0\xA7\xA6 \xE0\xA7\xAA" ) /* */
SCRIPT( buhd, BUHD,
"Buhid",
HB_SCRIPT_BUHID,
HINTING_BOTTOM_TO_TOP,
"\xE1\x9D\x8B \xE1\x9D\x8F" ) /* ᝋ ᝏ */
SCRIPT( cakm, CAKM,
"Chakma",
HB_SCRIPT_CHAKMA,
HINTING_BOTTOM_TO_TOP,
"\xF0\x91\x84\xA4 \xF0\x91\x84\x89 \xF0\x91\x84\x9B" ) /* 𑄤 𑄉 𑄛 */
SCRIPT( cans, CANS,
"Canadian Syllabics",
HB_SCRIPT_CANADIAN_SYLLABICS,
HINTING_BOTTOM_TO_TOP,
"\xE1\x91\x8C \xE1\x93\x9A" ) /* ᓚ */
SCRIPT( cari, CARI,
"Carian",
HB_SCRIPT_CARIAN,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\x8A\xAB \xF0\x90\x8B\x89" ) /* 𐊫 𐋉 */
SCRIPT( cher, CHER,
"Cherokee",
HB_SCRIPT_CHEROKEE,
HINTING_BOTTOM_TO_TOP,
"\xE1\x8E\xA4 \xE1\x8F\x85 \xEA\xAE\x95" ) /* Ꭴ Ꮕ ꮕ */
SCRIPT( copt, COPT,
"Coptic",
HB_SCRIPT_COPTIC,
HINTING_BOTTOM_TO_TOP,
"\xE2\xB2\x9E \xE2\xB2\x9F" ) /* */
SCRIPT( cprt, CPRT,
"Cypriot",
HB_SCRIPT_CYPRIOT,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\xA0\x85 \xF0\x90\xA0\xA3" ) /* 𐠅 𐠣 */
SCRIPT( cyrl, CYRL,
"Cyrillic",
HB_SCRIPT_CYRILLIC,
HINTING_BOTTOM_TO_TOP,
"\xD0\xBE \xD0\x9E" ) /* о О */
SCRIPT( deva, DEVA,
"Devanagari",
HB_SCRIPT_DEVANAGARI,
HINTING_TOP_TO_BOTTOM,
"\xE0\xA4\xA0 \xE0\xA4\xB5 \xE0\xA4\x9F" ) /* ठ व ट */
SCRIPT( dsrt, DSRT,
"Deseret",
HB_SCRIPT_DESERET,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\x90\x84 \xF0\x90\x90\xAC" ) /* 𐐄 𐐬 */
SCRIPT( ethi, ETHI,
"Ethiopic",
HB_SCRIPT_ETHIOPIC,
HINTING_BOTTOM_TO_TOP,
"\xE1\x8B\x90" ) /* */
SCRIPT( geor, GEOR,
"Georgian (Mkhedruli)",
HB_SCRIPT_GEORGIAN,
HINTING_BOTTOM_TO_TOP,
"\xE1\x83\x98 \xE1\x83\x94 \xE1\x83\x90 \xE1\xB2\xBF" ) /* ი ე ა Ი */
SCRIPT( geok, GEOK,
"Georgian (Khutsuri)",
HB_SCRIPT_INVALID,
HINTING_BOTTOM_TO_TOP,
"\xE1\x82\xB6 \xE1\x82\xB1 \xE2\xB4\x99" ) /* Ⴖ Ⴑ ⴙ */
SCRIPT( glag, GLAG,
"Glagolitic",
HB_SCRIPT_GLAGOLITIC,
HINTING_BOTTOM_TO_TOP,
"\xE2\xB0\x95 \xE2\xB1\x85" ) /* Ⱅ ⱅ */
SCRIPT( goth, GOTH,
"Gothic",
HB_SCRIPT_GOTHIC,
HINTING_TOP_TO_BOTTOM,
"\xF0\x90\x8C\xB4 \xF0\x90\x8C\xBE \xF0\x90\x8D\x83" ) /* 𐌴 𐌾 𐍃 */
SCRIPT( grek, GREK,
"Greek",
HB_SCRIPT_GREEK,
HINTING_BOTTOM_TO_TOP,
"\xCE\xBF \xCE\x9F" ) /* ο Ο */
SCRIPT( gujr, GUJR,
"Gujarati",
HB_SCRIPT_GUJARATI,
HINTING_BOTTOM_TO_TOP,
"\xE0\xAA\x9F \xE0\xAB\xA6" ) /* ટ */
SCRIPT( guru, GURU,
"Gurmukhi",
HB_SCRIPT_GURMUKHI,
HINTING_TOP_TO_BOTTOM,
"\xE0\xA8\xA0 \xE0\xA8\xB0 \xE0\xA9\xA6" ) /* ਠ ਰ */
SCRIPT( hebr, HEBR,
"Hebrew",
HB_SCRIPT_HEBREW,
HINTING_BOTTOM_TO_TOP,
"\xD7\x9D" ) /* ם */
SCRIPT( kali, KALI,
"Kayah Li",
HB_SCRIPT_KAYAH_LI,
HINTING_BOTTOM_TO_TOP,
"\xEA\xA4\x8D \xEA\xA4\x80" ) /* ꤍ ꤀ */
/* only digit zero has a simple shape in the Khmer script */
SCRIPT( khmr, KHMR,
"Khmer",
HB_SCRIPT_KHMER,
HINTING_BOTTOM_TO_TOP,
"\xE1\x9F\xA0" ) /* ០ */
SCRIPT( khms, KHMS,
"Khmer Symbols",
HB_SCRIPT_INVALID,
HINTING_BOTTOM_TO_TOP,
"\xE1\xA7\xA1 \xE1\xA7\xAA" ) /* ᧡ ᧪ */
SCRIPT( knda, KNDA,
"Kannada",
HB_SCRIPT_KANNADA,
HINTING_BOTTOM_TO_TOP,
"\xE0\xB3\xA6 \xE0\xB2\xAC" ) /* ಬ */
/* only digit zero has a simple shape in the Lao script */
SCRIPT( lao, LAO,
"Lao",
HB_SCRIPT_LAO,
HINTING_BOTTOM_TO_TOP,
"\xE0\xBB\x90" ) /* */
SCRIPT( latn, LATN,
"Latin",
HB_SCRIPT_LATIN,
HINTING_BOTTOM_TO_TOP,
"o O 0" )
SCRIPT( latb, LATB,
"Latin Subscript Fallback",
HB_SCRIPT_INVALID,
HINTING_BOTTOM_TO_TOP,
"\xE2\x82\x92 \xE2\x82\x80" ) /* ₒ ₀ */
SCRIPT( latp, LATP,
"Latin Superscript Fallback",
HB_SCRIPT_INVALID,
HINTING_BOTTOM_TO_TOP,
"\xE1\xB5\x92 \xE1\xB4\xBC \xE2\x81\xB0" ) /* ᵒ ᴼ ⁰ */
SCRIPT( lisu, LISU,
"Lisu",
HB_SCRIPT_LISU,
HINTING_BOTTOM_TO_TOP,
"\xEA\x93\xB3" ) /* */
SCRIPT( mlym, MLYM,
"Malayalam",
HB_SCRIPT_MALAYALAM,
HINTING_BOTTOM_TO_TOP,
"\xE0\xB4\xA0 \xE0\xB4\xB1" ) /* റ */
SCRIPT( medf, MEDF,
"Medefaidrin",
HB_SCRIPT_MEDEFAIDRIN,
HINTING_BOTTOM_TO_TOP,
"\xF0\x96\xB9\xA1 \xF0\x96\xB9\x9B \xF0\x96\xB9\xAF" ) /* 𖹡 𖹛 𖹯 */
SCRIPT( mong, MONG,
"Mongolian",
HB_SCRIPT_MONGOLIAN,
HINTING_TOP_TO_BOTTOM,
"\xE1\xA1\x82 \xE1\xA0\xAA" ) /* ᡂ ᠪ */
SCRIPT( mymr, MYMR,
"Myanmar",
HB_SCRIPT_MYANMAR,
HINTING_BOTTOM_TO_TOP,
"\xE1\x80\x9D \xE1\x80\x84 \xE1\x80\x82" ) /* င ဂ */
SCRIPT( nkoo, NKOO,
"N'Ko",
HB_SCRIPT_NKO,
HINTING_BOTTOM_TO_TOP,
"\xDF\x8B \xDF\x80" ) /* ߋ ߀ */
SCRIPT( none, NONE,
"no script",
HB_SCRIPT_INVALID,
HINTING_BOTTOM_TO_TOP,
"" )
SCRIPT( olck, OLCK,
"Ol Chiki",
HB_SCRIPT_OL_CHIKI,
HINTING_BOTTOM_TO_TOP,
"\xE1\xB1\x9B" ) /* ᱛ */
SCRIPT( orkh, ORKH,
"Old Turkic",
HB_SCRIPT_OLD_TURKIC,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\xB0\x97" ) /* 𐰗 */
SCRIPT( osge, OSGE,
"Osage",
HB_SCRIPT_OSAGE,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\x93\x82 \xF0\x90\x93\xAA" ) /* 𐓂 𐓪 */
SCRIPT( osma, OSMA,
"Osmanya",
HB_SCRIPT_OSMANYA,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\x92\x86 \xF0\x90\x92\xA0" ) /* 𐒆 𐒠 */
SCRIPT( rohg, ROHG,
"Hanifi Rohingya",
HB_SCRIPT_HANIFI_ROHINGYA,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\xB4\xB0" ) /* 𐴰 */
SCRIPT( saur, SAUR,
"Saurashtra",
HB_SCRIPT_SAURASHTRA,
HINTING_BOTTOM_TO_TOP,
"\xEA\xA2\x9D \xEA\xA3\x90" ) /* ꢝ ꣐ */
SCRIPT( shaw, SHAW,
"Shavian",
HB_SCRIPT_SHAVIAN,
HINTING_BOTTOM_TO_TOP,
"\xF0\x90\x91\xB4" ) /* 𐑴 */
SCRIPT( sinh, SINH,
"Sinhala",
HB_SCRIPT_SINHALA,
HINTING_BOTTOM_TO_TOP,
"\xE0\xB6\xA7" ) /* ට */
/* only digit zero has a simple (round) shape in the Sundanese script */
SCRIPT( sund, SUND,
"Sundanese",
HB_SCRIPT_SUNDANESE,
HINTING_BOTTOM_TO_TOP,
"\xE1\xAE\xB0" ) /* ᮰ */
/* only digit zero has a simple (round) shape in the Tamil script */
SCRIPT( taml, TAML,
"Tamil",
HB_SCRIPT_TAMIL,
HINTING_BOTTOM_TO_TOP,
"\xE0\xAF\xA6" ) /* */
SCRIPT( tavt, TAVT,
"Tai Viet",
HB_SCRIPT_TAI_VIET,
HINTING_BOTTOM_TO_TOP,
"\xEA\xAA\x92 \xEA\xAA\xAB" ) /* ꪒ ꪫ */
/* there are no simple forms for letters; we thus use two digit shapes */
SCRIPT( telu, TELU,
"Telugu",
HB_SCRIPT_TELUGU,
HINTING_BOTTOM_TO_TOP,
"\xE0\xB1\xA6 \xE0\xB1\xA7" ) /* ౧ */
SCRIPT( tfng, TFNG,
"Tifinagh",
HB_SCRIPT_TIFINAGH,
HINTING_BOTTOM_TO_TOP,
"\xE2\xB5\x94" ) /* */
SCRIPT( thai, THAI,
"Thai",
HB_SCRIPT_THAI,
HINTING_BOTTOM_TO_TOP,
"\xE0\xB8\xB2 \xE0\xB9\x85 \xE0\xB9\x90" ) /* า ๅ */
SCRIPT( vaii, VAII,
"Vai",
HB_SCRIPT_VAI,
HINTING_BOTTOM_TO_TOP,
"\xEA\x98\x93 \xEA\x96\x9C \xEA\x96\xB4" ) /* ꘓ ꖜ ꖴ */
#ifdef AF_CONFIG_OPTION_INDIC
SCRIPT( limb, LIMB,
"Limbu",
HB_SCRIPT_LIMBU,
HINTING_BOTTOM_TO_TOP,
"o" ) /* XXX */
SCRIPT( orya, ORYA,
"Oriya",
HB_SCRIPT_ORIYA,
HINTING_BOTTOM_TO_TOP,
"o" ) /* XXX */
SCRIPT( sylo, SYLO,
"Syloti Nagri",
HB_SCRIPT_SYLOTI_NAGRI,
HINTING_BOTTOM_TO_TOP,
"o" ) /* XXX */
SCRIPT( tibt, TIBT,
"Tibetan",
HB_SCRIPT_TIBETAN,
HINTING_BOTTOM_TO_TOP,
"o" ) /* XXX */
#endif /* AF_CONFIG_OPTION_INDIC */
#ifdef AF_CONFIG_OPTION_CJK
SCRIPT( hani, HANI,
"CJKV ideographs",
HB_SCRIPT_HAN,
HINTING_BOTTOM_TO_TOP,
"\xE7\x94\xB0 \xE5\x9B\x97" ) /* 田 囗 */
#endif /* AF_CONFIG_OPTION_CJK */
/* END */

View file

@ -0,0 +1,690 @@
/****************************************************************************
*
* afshaper.c
*
* HarfBuzz interface for accessing OpenType features (body).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/freetype.h>
#include <freetype/ftadvanc.h>
#include "afglobal.h"
#include "aftypes.h"
#include "afshaper.h"
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT afshaper
/*
* We use `sets' (in the HarfBuzz sense, which comes quite near to the
* usual mathematical meaning) to manage both lookups and glyph indices.
*
* 1. For each coverage, collect lookup IDs in a set. Note that an
* auto-hinter `coverage' is represented by one `feature', and a
* feature consists of an arbitrary number of (font specific) `lookup's
* that actually do the mapping job. Please check the OpenType
* specification for more details on features and lookups.
*
* 2. Create glyph ID sets from the corresponding lookup sets.
*
* 3. The glyph set corresponding to AF_COVERAGE_DEFAULT is computed
* with all lookups specific to the OpenType script activated. It
* relies on the order of AF_DEFINE_STYLE_CLASS entries so that
* special coverages (like `oldstyle figures') don't get overwritten.
*
*/
/* load coverage tags */
#undef COVERAGE
#define COVERAGE( name, NAME, description, \
tag1, tag2, tag3, tag4 ) \
static const hb_tag_t name ## _coverage[] = \
{ \
HB_TAG( tag1, tag2, tag3, tag4 ), \
HB_TAG_NONE \
};
#include "afcover.h"
/* define mapping between coverage tags and AF_Coverage */
#undef COVERAGE
#define COVERAGE( name, NAME, description, \
tag1, tag2, tag3, tag4 ) \
name ## _coverage,
static const hb_tag_t* coverages[] =
{
#include "afcover.h"
NULL /* AF_COVERAGE_DEFAULT */
};
/* load HarfBuzz script tags */
#undef SCRIPT
#define SCRIPT( s, S, d, h, H, ss ) h,
static const hb_script_t scripts[] =
{
#include "afscript.h"
};
FT_Error
af_shaper_get_coverage( AF_FaceGlobals globals,
AF_StyleClass style_class,
FT_UShort* gstyles,
FT_Bool default_script )
{
hb_face_t* face;
hb_set_t* gsub_lookups = NULL; /* GSUB lookups for a given script */
hb_set_t* gsub_glyphs = NULL; /* glyphs covered by GSUB lookups */
hb_set_t* gpos_lookups = NULL; /* GPOS lookups for a given script */
hb_set_t* gpos_glyphs = NULL; /* glyphs covered by GPOS lookups */
hb_script_t script;
const hb_tag_t* coverage_tags;
hb_tag_t script_tags[] = { HB_TAG_NONE,
HB_TAG_NONE,
HB_TAG_NONE,
HB_TAG_NONE };
hb_codepoint_t idx;
#ifdef FT_DEBUG_LEVEL_TRACE
int count;
#endif
if ( !globals || !style_class || !gstyles )
return FT_THROW( Invalid_Argument );
face = hb_font_get_face( globals->hb_font );
coverage_tags = coverages[style_class->coverage];
script = scripts[style_class->script];
/* Convert a HarfBuzz script tag into the corresponding OpenType */
/* tag or tags -- some Indic scripts like Devanagari have an old */
/* and a new set of features. */
{
unsigned int tags_count = 3;
hb_tag_t tags[3];
hb_ot_tags_from_script_and_language( script,
HB_LANGUAGE_INVALID,
&tags_count,
tags,
NULL,
NULL );
script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE;
script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE;
script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE;
}
/* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */
/* HB_TAG_NONE except for the default script. */
if ( default_script )
{
if ( script_tags[0] == HB_TAG_NONE )
script_tags[0] = HB_OT_TAG_DEFAULT_SCRIPT;
else
{
if ( script_tags[1] == HB_TAG_NONE )
script_tags[1] = HB_OT_TAG_DEFAULT_SCRIPT;
else if ( script_tags[1] != HB_OT_TAG_DEFAULT_SCRIPT )
script_tags[2] = HB_OT_TAG_DEFAULT_SCRIPT;
}
}
else
{
/* we use non-standard tags like `khms' for special purposes; */
/* HarfBuzz maps them to `DFLT', which we don't want to handle here */
if ( script_tags[0] == HB_OT_TAG_DEFAULT_SCRIPT )
goto Exit;
}
gsub_lookups = hb_set_create();
hb_ot_layout_collect_lookups( face,
HB_OT_TAG_GSUB,
script_tags,
NULL,
coverage_tags,
gsub_lookups );
if ( hb_set_is_empty( gsub_lookups ) )
goto Exit; /* nothing to do */
FT_TRACE4(( "GSUB lookups (style `%s'):\n",
af_style_names[style_class->style] ));
FT_TRACE4(( " " ));
#ifdef FT_DEBUG_LEVEL_TRACE
count = 0;
#endif
gsub_glyphs = hb_set_create();
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); )
{
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( " %d", idx ));
count++;
#endif
/* get output coverage of GSUB feature */
hb_ot_layout_lookup_collect_glyphs( face,
HB_OT_TAG_GSUB,
idx,
NULL,
NULL,
NULL,
gsub_glyphs );
}
#ifdef FT_DEBUG_LEVEL_TRACE
if ( !count )
FT_TRACE4(( " (none)" ));
FT_TRACE4(( "\n" ));
FT_TRACE4(( "\n" ));
#endif
FT_TRACE4(( "GPOS lookups (style `%s'):\n",
af_style_names[style_class->style] ));
FT_TRACE4(( " " ));
gpos_lookups = hb_set_create();
hb_ot_layout_collect_lookups( face,
HB_OT_TAG_GPOS,
script_tags,
NULL,
coverage_tags,
gpos_lookups );
#ifdef FT_DEBUG_LEVEL_TRACE
count = 0;
#endif
gpos_glyphs = hb_set_create();
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); )
{
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( " %d", idx ));
count++;
#endif
/* get input coverage of GPOS feature */
hb_ot_layout_lookup_collect_glyphs( face,
HB_OT_TAG_GPOS,
idx,
NULL,
gpos_glyphs,
NULL,
NULL );
}
#ifdef FT_DEBUG_LEVEL_TRACE
if ( !count )
FT_TRACE4(( " (none)" ));
FT_TRACE4(( "\n" ));
FT_TRACE4(( "\n" ));
#endif
/*
* We now check whether we can construct blue zones, using glyphs
* covered by the feature only. In case there is not a single zone
* (that is, not a single character is covered), we skip this coverage.
*
*/
if ( style_class->coverage != AF_COVERAGE_DEFAULT )
{
AF_Blue_Stringset bss = style_class->blue_stringset;
const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
FT_Bool found = 0;
for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
{
const char* p = &af_blue_strings[bs->string];
while ( *p )
{
hb_codepoint_t ch;
GET_UTF8_CHAR( ch, p );
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups,
&idx ); )
{
hb_codepoint_t gidx = FT_Get_Char_Index( globals->face, ch );
if ( hb_ot_layout_lookup_would_substitute( face, idx,
&gidx, 1, 1 ) )
{
found = 1;
break;
}
}
}
}
if ( !found )
{
FT_TRACE4(( " no blue characters found; style skipped\n" ));
goto Exit;
}
}
/*
* Various OpenType features might use the same glyphs at different
* vertical positions; for example, superscript and subscript glyphs
* could be the same. However, the auto-hinter is completely
* agnostic of OpenType features after the feature analysis has been
* completed: The engine then simply receives a glyph index and returns a
* hinted and usually rendered glyph.
*
* Consider the superscript feature of font `pala.ttf': Some of the
* glyphs are `real', that is, they have a zero vertical offset, but
* most of them are small caps glyphs shifted up to the superscript
* position (that is, the `sups' feature is present in both the GSUB and
* GPOS tables). The code for blue zones computation actually uses a
* feature's y offset so that the `real' glyphs get correct hints. But
* later on it is impossible to decide whether a glyph index belongs to,
* say, the small caps or superscript feature.
*
* For this reason, we don't assign a style to a glyph if the current
* feature covers the glyph in both the GSUB and the GPOS tables. This
* is quite a broad condition, assuming that
*
* (a) glyphs that get used in multiple features are present in a
* feature without vertical shift,
*
* and
*
* (b) a feature's GPOS data really moves the glyph vertically.
*
* Not fulfilling condition (a) makes a font larger; it would also
* reduce the number of glyphs that could be addressed directly without
* using OpenType features, so this assumption is rather strong.
*
* Condition (b) is much weaker, and there might be glyphs which get
* missed. However, the OpenType features we are going to handle are
* primarily located in GSUB, and HarfBuzz doesn't provide an API to
* directly get the necessary information from the GPOS table. A
* possible solution might be to directly parse the GPOS table to find
* out whether a glyph gets shifted vertically, but this is something I
* would like to avoid if not really necessary.
*
* Note that we don't follow this logic for the default coverage.
* Complex scripts like Devanagari have mandatory GPOS features to
* position many glyph elements, using mark-to-base or mark-to-ligature
* tables; the number of glyphs missed due to condition (b) would be far
* too large.
*
*/
if ( style_class->coverage != AF_COVERAGE_DEFAULT )
hb_set_subtract( gsub_glyphs, gpos_glyphs );
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( " glyphs without GPOS data (`*' means already assigned)" ));
count = 0;
#endif
for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); )
{
#ifdef FT_DEBUG_LEVEL_TRACE
if ( !( count % 10 ) )
{
FT_TRACE4(( "\n" ));
FT_TRACE4(( " " ));
}
FT_TRACE4(( " %d", idx ));
count++;
#endif
/* glyph indices returned by `hb_ot_layout_lookup_collect_glyphs' */
/* can be arbitrary: some fonts use fake indices for processing */
/* internal to GSUB or GPOS, which is fully valid */
if ( idx >= (hb_codepoint_t)globals->glyph_count )
continue;
if ( gstyles[idx] == AF_STYLE_UNASSIGNED )
gstyles[idx] = (FT_UShort)style_class->style;
#ifdef FT_DEBUG_LEVEL_TRACE
else
FT_TRACE4(( "*" ));
#endif
}
#ifdef FT_DEBUG_LEVEL_TRACE
if ( !count )
{
FT_TRACE4(( "\n" ));
FT_TRACE4(( " (none)" ));
}
FT_TRACE4(( "\n" ));
FT_TRACE4(( "\n" ));
#endif
Exit:
hb_set_destroy( gsub_lookups );
hb_set_destroy( gsub_glyphs );
hb_set_destroy( gpos_lookups );
hb_set_destroy( gpos_glyphs );
return FT_Err_Ok;
}
/* construct HarfBuzz features */
#undef COVERAGE
#define COVERAGE( name, NAME, description, \
tag1, tag2, tag3, tag4 ) \
static const hb_feature_t name ## _feature[] = \
{ \
{ \
HB_TAG( tag1, tag2, tag3, tag4 ), \
1, 0, (unsigned int)-1 \
} \
};
#include "afcover.h"
/* define mapping between HarfBuzz features and AF_Coverage */
#undef COVERAGE
#define COVERAGE( name, NAME, description, \
tag1, tag2, tag3, tag4 ) \
name ## _feature,
static const hb_feature_t* features[] =
{
#include "afcover.h"
NULL /* AF_COVERAGE_DEFAULT */
};
void*
af_shaper_buf_create( FT_Face face )
{
FT_UNUSED( face );
return (void*)hb_buffer_create();
}
void
af_shaper_buf_destroy( FT_Face face,
void* buf )
{
FT_UNUSED( face );
hb_buffer_destroy( (hb_buffer_t*)buf );
}
const char*
af_shaper_get_cluster( const char* p,
AF_StyleMetrics metrics,
void* buf_,
unsigned int* count )
{
AF_StyleClass style_class;
const hb_feature_t* feature;
FT_Int upem;
const char* q;
int len;
hb_buffer_t* buf = (hb_buffer_t*)buf_;
hb_font_t* font;
hb_codepoint_t dummy;
upem = (FT_Int)metrics->globals->face->units_per_EM;
style_class = metrics->style_class;
feature = features[style_class->coverage];
font = metrics->globals->hb_font;
/* we shape at a size of units per EM; this means font units */
hb_font_set_scale( font, upem, upem );
while ( *p == ' ' )
p++;
/* count bytes up to next space (or end of buffer) */
q = p;
while ( !( *q == ' ' || *q == '\0' ) )
GET_UTF8_CHAR( dummy, q );
len = (int)( q - p );
/* feed character(s) to the HarfBuzz buffer */
hb_buffer_clear_contents( buf );
hb_buffer_add_utf8( buf, p, len, 0, len );
/* we let HarfBuzz guess the script and writing direction */
hb_buffer_guess_segment_properties( buf );
/* shape buffer, which means conversion from character codes to */
/* glyph indices, possibly applying a feature */
hb_shape( font, buf, feature, feature ? 1 : 0 );
if ( feature )
{
hb_buffer_t* hb_buf = metrics->globals->hb_buf;
unsigned int gcount;
hb_glyph_info_t* ginfo;
unsigned int hb_gcount;
hb_glyph_info_t* hb_ginfo;
/* we have to check whether applying a feature does actually change */
/* glyph indices; otherwise the affected glyph or glyphs aren't */
/* available at all in the feature */
hb_buffer_clear_contents( hb_buf );
hb_buffer_add_utf8( hb_buf, p, len, 0, len );
hb_buffer_guess_segment_properties( hb_buf );
hb_shape( font, hb_buf, NULL, 0 );
ginfo = hb_buffer_get_glyph_infos( buf, &gcount );
hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount );
if ( gcount == hb_gcount )
{
unsigned int i;
for (i = 0; i < gcount; i++ )
if ( ginfo[i].codepoint != hb_ginfo[i].codepoint )
break;
if ( i == gcount )
{
/* both buffers have identical glyph indices */
hb_buffer_clear_contents( buf );
}
}
}
*count = hb_buffer_get_length( buf );
#ifdef FT_DEBUG_LEVEL_TRACE
if ( feature && *count > 1 )
FT_TRACE1(( "af_shaper_get_cluster:"
" input character mapped to multiple glyphs\n" ));
#endif
return q;
}
FT_ULong
af_shaper_get_elem( AF_StyleMetrics metrics,
void* buf_,
unsigned int idx,
FT_Long* advance,
FT_Long* y_offset )
{
hb_buffer_t* buf = (hb_buffer_t*)buf_;
hb_glyph_info_t* ginfo;
hb_glyph_position_t* gpos;
unsigned int gcount;
FT_UNUSED( metrics );
ginfo = hb_buffer_get_glyph_infos( buf, &gcount );
gpos = hb_buffer_get_glyph_positions( buf, &gcount );
if ( idx >= gcount )
return 0;
if ( advance )
*advance = gpos[idx].x_advance;
if ( y_offset )
*y_offset = gpos[idx].y_offset;
return ginfo[idx].codepoint;
}
#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
FT_Error
af_shaper_get_coverage( AF_FaceGlobals globals,
AF_StyleClass style_class,
FT_UShort* gstyles,
FT_Bool default_script )
{
FT_UNUSED( globals );
FT_UNUSED( style_class );
FT_UNUSED( gstyles );
FT_UNUSED( default_script );
return FT_Err_Ok;
}
void*
af_shaper_buf_create( FT_Face face )
{
FT_UNUSED( face );
return NULL;
}
void
af_shaper_buf_destroy( FT_Face face,
void* buf )
{
FT_UNUSED( face );
FT_UNUSED( buf );
}
const char*
af_shaper_get_cluster( const char* p,
AF_StyleMetrics metrics,
void* buf_,
unsigned int* count )
{
FT_Face face = metrics->globals->face;
FT_ULong ch, dummy = 0;
FT_ULong* buf = (FT_ULong*)buf_;
while ( *p == ' ' )
p++;
GET_UTF8_CHAR( ch, p );
/* since we don't have an engine to handle clusters, */
/* we scan the characters but return zero */
while ( !( *p == ' ' || *p == '\0' ) )
GET_UTF8_CHAR( dummy, p );
if ( dummy )
{
*buf = 0;
*count = 0;
}
else
{
*buf = FT_Get_Char_Index( face, ch );
*count = 1;
}
return p;
}
FT_ULong
af_shaper_get_elem( AF_StyleMetrics metrics,
void* buf_,
unsigned int idx,
FT_Long* advance,
FT_Long* y_offset )
{
FT_Face face = metrics->globals->face;
FT_ULong glyph_index = *(FT_ULong*)buf_;
FT_UNUSED( idx );
if ( advance )
FT_Get_Advance( face,
glyph_index,
FT_LOAD_NO_SCALE |
FT_LOAD_NO_HINTING |
FT_LOAD_IGNORE_TRANSFORM,
advance );
if ( y_offset )
*y_offset = 0;
return glyph_index;
}
#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
/* END */

View file

@ -0,0 +1,71 @@
/****************************************************************************
*
* afshaper.h
*
* HarfBuzz interface for accessing OpenType features (specification).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFSHAPER_H_
#define AFSHAPER_H_
#include <freetype/freetype.h>
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
#include <hb.h>
#include <hb-ot.h>
#include "ft-hb.h"
#endif
FT_BEGIN_HEADER
FT_Error
af_shaper_get_coverage( AF_FaceGlobals globals,
AF_StyleClass style_class,
FT_UShort* gstyles,
FT_Bool default_script );
void*
af_shaper_buf_create( FT_Face face );
void
af_shaper_buf_destroy( FT_Face face,
void* buf );
const char*
af_shaper_get_cluster( const char* p,
AF_StyleMetrics metrics,
void* buf_,
unsigned int* count );
FT_ULong
af_shaper_get_elem( AF_StyleMetrics metrics,
void* buf_,
unsigned int idx,
FT_Long* x_advance,
FT_Long* y_offset );
/* */
FT_END_HEADER
#endif /* AFSHAPER_H_ */
/* END */

View file

@ -0,0 +1,487 @@
/****************************************************************************
*
* afstyles.h
*
* Auto-fitter styles (specification only).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/* The following part can be included multiple times. */
/* Define `STYLE' as needed. */
/* Add new styles here. The first and second arguments are the */
/* style name in lowercase and uppercase, respectively, followed */
/* by a description string. The next arguments are the */
/* corresponding writing system, script, blue stringset, and */
/* coverage. */
/* */
/* Note that styles using `AF_COVERAGE_DEFAULT' should always */
/* come after styles with other coverages. Also note that */
/* fallback scripts only use `AF_COVERAGE_DEFAULT' for its */
/* style. */
/* */
/* Example: */
/* */
/* STYLE( cyrl_dflt, CYRL_DFLT, */
/* "Cyrillic default style", */
/* AF_WRITING_SYSTEM_LATIN, */
/* AF_SCRIPT_CYRL, */
/* AF_BLUE_STRINGSET_CYRL, */
/* AF_COVERAGE_DEFAULT ) */
#undef STYLE_LATIN
#define STYLE_LATIN( s, S, f, F, ds, df, C ) \
STYLE( s ## _ ## f, S ## _ ## F, \
ds " " df " style", \
AF_WRITING_SYSTEM_LATIN, \
AF_SCRIPT_ ## S, \
AF_BLUE_STRINGSET_ ## S, \
AF_COVERAGE_ ## C )
#undef META_STYLE_LATIN
#define META_STYLE_LATIN( s, S, ds ) \
STYLE_LATIN( s, S, c2cp, C2CP, ds, \
"petite capitals from capitals", \
PETITE_CAPITALS_FROM_CAPITALS ) \
STYLE_LATIN( s, S, c2sc, C2SC, ds, \
"small capitals from capitals", \
SMALL_CAPITALS_FROM_CAPITALS ) \
STYLE_LATIN( s, S, ordn, ORDN, ds, \
"ordinals", \
ORDINALS ) \
STYLE_LATIN( s, S, pcap, PCAP, ds, \
"petite capitals", \
PETITE_CAPITALS ) \
STYLE_LATIN( s, S, sinf, SINF, ds, \
"scientific inferiors", \
SCIENTIFIC_INFERIORS ) \
STYLE_LATIN( s, S, smcp, SMCP, ds, \
"small capitals", \
SMALL_CAPITALS ) \
STYLE_LATIN( s, S, subs, SUBS, ds, \
"subscript", \
SUBSCRIPT ) \
STYLE_LATIN( s, S, sups, SUPS, ds, \
"superscript", \
SUPERSCRIPT ) \
STYLE_LATIN( s, S, titl, TITL, ds, \
"titling", \
TITLING ) \
STYLE_LATIN( s, S, dflt, DFLT, ds, \
"default", \
DEFAULT )
STYLE( adlm_dflt, ADLM_DFLT,
"Adlam default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_ADLM,
AF_BLUE_STRINGSET_ADLM,
AF_COVERAGE_DEFAULT )
STYLE( arab_dflt, ARAB_DFLT,
"Arabic default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_ARAB,
AF_BLUE_STRINGSET_ARAB,
AF_COVERAGE_DEFAULT )
STYLE( armn_dflt, ARMN_DFLT,
"Armenian default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_ARMN,
AF_BLUE_STRINGSET_ARMN,
AF_COVERAGE_DEFAULT )
STYLE( avst_dflt, AVST_DFLT,
"Avestan default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_AVST,
AF_BLUE_STRINGSET_AVST,
AF_COVERAGE_DEFAULT )
STYLE( bamu_dflt, BAMU_DFLT,
"Bamum default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_BAMU,
AF_BLUE_STRINGSET_BAMU,
AF_COVERAGE_DEFAULT )
STYLE( beng_dflt, BENG_DFLT,
"Bengali default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_BENG,
AF_BLUE_STRINGSET_BENG,
AF_COVERAGE_DEFAULT )
STYLE( buhd_dflt, BUHD_DFLT,
"Buhid default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_BUHD,
AF_BLUE_STRINGSET_BUHD,
AF_COVERAGE_DEFAULT )
STYLE( cakm_dflt, CAKM_DFLT,
"Chakma default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_CAKM,
AF_BLUE_STRINGSET_CAKM,
AF_COVERAGE_DEFAULT )
STYLE( cans_dflt, CANS_DFLT,
"Canadian Syllabics default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_CANS,
AF_BLUE_STRINGSET_CANS,
AF_COVERAGE_DEFAULT )
STYLE( cari_dflt, CARI_DFLT,
"Carian default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_CARI,
AF_BLUE_STRINGSET_CARI,
AF_COVERAGE_DEFAULT )
STYLE( cher_dflt, CHER_DFLT,
"Cherokee default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_CHER,
AF_BLUE_STRINGSET_CHER,
AF_COVERAGE_DEFAULT )
STYLE( copt_dflt, COPT_DFLT,
"Coptic default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_COPT,
AF_BLUE_STRINGSET_COPT,
AF_COVERAGE_DEFAULT )
STYLE( cprt_dflt, CPRT_DFLT,
"Cypriot default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_CPRT,
AF_BLUE_STRINGSET_CPRT,
AF_COVERAGE_DEFAULT )
META_STYLE_LATIN( cyrl, CYRL, "Cyrillic" )
STYLE( deva_dflt, DEVA_DFLT,
"Devanagari default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_DEVA,
AF_BLUE_STRINGSET_DEVA,
AF_COVERAGE_DEFAULT )
STYLE( dsrt_dflt, DSRT_DFLT,
"Deseret default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_DSRT,
AF_BLUE_STRINGSET_DSRT,
AF_COVERAGE_DEFAULT )
STYLE( ethi_dflt, ETHI_DFLT,
"Ethiopic default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_ETHI,
AF_BLUE_STRINGSET_ETHI,
AF_COVERAGE_DEFAULT )
STYLE( geor_dflt, GEOR_DFLT,
"Georgian (Mkhedruli) default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_GEOR,
AF_BLUE_STRINGSET_GEOR,
AF_COVERAGE_DEFAULT )
STYLE( geok_dflt, GEOK_DFLT,
"Georgian (Khutsuri) default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_GEOK,
AF_BLUE_STRINGSET_GEOK,
AF_COVERAGE_DEFAULT )
STYLE( glag_dflt, GLAG_DFLT,
"Glagolitic default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_GLAG,
AF_BLUE_STRINGSET_GLAG,
AF_COVERAGE_DEFAULT )
STYLE( goth_dflt, GOTH_DFLT,
"Gothic default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_GOTH,
AF_BLUE_STRINGSET_GOTH,
AF_COVERAGE_DEFAULT )
META_STYLE_LATIN( grek, GREK, "Greek" )
STYLE( gujr_dflt, GUJR_DFLT,
"Gujarati default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_GUJR,
AF_BLUE_STRINGSET_GUJR,
AF_COVERAGE_DEFAULT )
STYLE( guru_dflt, GURU_DFLT,
"Gurmukhi default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_GURU,
AF_BLUE_STRINGSET_GURU,
AF_COVERAGE_DEFAULT )
STYLE( hebr_dflt, HEBR_DFLT,
"Hebrew default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_HEBR,
AF_BLUE_STRINGSET_HEBR,
AF_COVERAGE_DEFAULT )
STYLE( kali_dflt, KALI_DFLT,
"Kayah Li default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_KALI,
AF_BLUE_STRINGSET_KALI,
AF_COVERAGE_DEFAULT )
STYLE( khmr_dflt, KHMR_DFLT,
"Khmer default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_KHMR,
AF_BLUE_STRINGSET_KHMR,
AF_COVERAGE_DEFAULT )
STYLE( khms_dflt, KHMS_DFLT,
"Khmer Symbols default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_KHMS,
AF_BLUE_STRINGSET_KHMS,
AF_COVERAGE_DEFAULT )
STYLE( knda_dflt, KNDA_DFLT,
"Kannada default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_KNDA,
AF_BLUE_STRINGSET_KNDA,
AF_COVERAGE_DEFAULT )
STYLE( lao_dflt, LAO_DFLT,
"Lao default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_LAO,
AF_BLUE_STRINGSET_LAO,
AF_COVERAGE_DEFAULT )
META_STYLE_LATIN( latn, LATN, "Latin" )
STYLE( latb_dflt, LATB_DFLT,
"Latin subscript fallback default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_LATB,
AF_BLUE_STRINGSET_LATB,
AF_COVERAGE_DEFAULT )
STYLE( latp_dflt, LATP_DFLT,
"Latin superscript fallback default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_LATP,
AF_BLUE_STRINGSET_LATP,
AF_COVERAGE_DEFAULT )
STYLE( lisu_dflt, LISU_DFLT,
"Lisu default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_LISU,
AF_BLUE_STRINGSET_LISU,
AF_COVERAGE_DEFAULT )
STYLE( mlym_dflt, MLYM_DFLT,
"Malayalam default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_MLYM,
AF_BLUE_STRINGSET_MLYM,
AF_COVERAGE_DEFAULT )
STYLE( medf_dflt, MEDF_DFLT,
"Medefaidrin default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_MEDF,
AF_BLUE_STRINGSET_MEDF,
AF_COVERAGE_DEFAULT )
STYLE( mong_dflt, MONG_DFLT,
"Mongolian default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_MONG,
AF_BLUE_STRINGSET_MONG,
AF_COVERAGE_DEFAULT )
STYLE( mymr_dflt, MYMR_DFLT,
"Myanmar default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_MYMR,
AF_BLUE_STRINGSET_MYMR,
AF_COVERAGE_DEFAULT )
STYLE( nkoo_dflt, NKOO_DFLT,
"N'Ko default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_NKOO,
AF_BLUE_STRINGSET_NKOO,
AF_COVERAGE_DEFAULT )
STYLE( none_dflt, NONE_DFLT,
"no style",
AF_WRITING_SYSTEM_DUMMY,
AF_SCRIPT_NONE,
AF_BLUE_STRINGSET_NONE,
AF_COVERAGE_DEFAULT )
STYLE( olck_dflt, OLCK_DFLT,
"Ol Chiki default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_OLCK,
AF_BLUE_STRINGSET_OLCK,
AF_COVERAGE_DEFAULT )
STYLE( orkh_dflt, ORKH_DFLT,
"Old Turkic default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_ORKH,
AF_BLUE_STRINGSET_ORKH,
AF_COVERAGE_DEFAULT )
STYLE( osge_dflt, OSGE_DFLT,
"Osage default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_OSGE,
AF_BLUE_STRINGSET_OSGE,
AF_COVERAGE_DEFAULT )
STYLE( osma_dflt, OSMA_DFLT,
"Osmanya default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_OSMA,
AF_BLUE_STRINGSET_OSMA,
AF_COVERAGE_DEFAULT )
STYLE( rohg_dflt, ROHG_DFLT,
"Hanifi Rohingya default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_ROHG,
AF_BLUE_STRINGSET_ROHG,
AF_COVERAGE_DEFAULT )
STYLE( saur_dflt, SAUR_DFLT,
"Saurashtra default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_SAUR,
AF_BLUE_STRINGSET_SAUR,
AF_COVERAGE_DEFAULT )
STYLE( shaw_dflt, SHAW_DFLT,
"Shavian default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_SHAW,
AF_BLUE_STRINGSET_SHAW,
AF_COVERAGE_DEFAULT )
STYLE( sinh_dflt, SINH_DFLT,
"Sinhala default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_SINH,
AF_BLUE_STRINGSET_SINH,
AF_COVERAGE_DEFAULT )
STYLE( sund_dflt, SUND_DFLT,
"Sundanese default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_SUND,
AF_BLUE_STRINGSET_SUND,
AF_COVERAGE_DEFAULT )
STYLE( taml_dflt, TAML_DFLT,
"Tamil default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_TAML,
AF_BLUE_STRINGSET_TAML,
AF_COVERAGE_DEFAULT )
STYLE( tavt_dflt, TAVT_DFLT,
"Tai Viet default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_TAVT,
AF_BLUE_STRINGSET_TAVT,
AF_COVERAGE_DEFAULT )
STYLE( telu_dflt, TELU_DFLT,
"Telugu default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_TELU,
AF_BLUE_STRINGSET_TELU,
AF_COVERAGE_DEFAULT )
STYLE( tfng_dflt, TFNG_DFLT,
"Tifinagh default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_TFNG,
AF_BLUE_STRINGSET_TFNG,
AF_COVERAGE_DEFAULT )
STYLE( thai_dflt, THAI_DFLT,
"Thai default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_THAI,
AF_BLUE_STRINGSET_THAI,
AF_COVERAGE_DEFAULT )
STYLE( vaii_dflt, VAII_DFLT,
"Vai default style",
AF_WRITING_SYSTEM_LATIN,
AF_SCRIPT_VAII,
AF_BLUE_STRINGSET_VAII,
AF_COVERAGE_DEFAULT )
#ifdef AF_CONFIG_OPTION_INDIC
/* no blue stringset support for the Indic writing system yet */
#undef STYLE_DEFAULT_INDIC
#define STYLE_DEFAULT_INDIC( s, S, d ) \
STYLE( s ## _dflt, S ## _DFLT, \
d " default style", \
AF_WRITING_SYSTEM_INDIC, \
AF_SCRIPT_ ## S, \
(AF_Blue_Stringset)0, \
AF_COVERAGE_DEFAULT )
STYLE_DEFAULT_INDIC( limb, LIMB, "Limbu" )
STYLE_DEFAULT_INDIC( orya, ORYA, "Oriya" )
STYLE_DEFAULT_INDIC( sylo, SYLO, "Syloti Nagri" )
STYLE_DEFAULT_INDIC( tibt, TIBT, "Tibetan" )
#endif /* AF_CONFIG_OPTION_INDIC */
#ifdef AF_CONFIG_OPTION_CJK
STYLE( hani_dflt, HANI_DFLT,
"CJKV ideographs default style",
AF_WRITING_SYSTEM_CJK,
AF_SCRIPT_HANI,
AF_BLUE_STRINGSET_HANI,
AF_COVERAGE_DEFAULT )
#endif /* AF_CONFIG_OPTION_CJK */
/* END */

View file

@ -0,0 +1,511 @@
/****************************************************************************
*
* aftypes.h
*
* Auto-fitter types (specification only).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/*************************************************************************
*
* The auto-fitter is a complete rewrite of the old auto-hinter.
* Its main feature is the ability to differentiate between different
* writing systems and scripts in order to apply specific rules.
*
* The code has also been compartmentalized into several entities that
* should make algorithmic experimentation easier than with the old
* code.
*
*************************************************************************/
#ifndef AFTYPES_H_
#define AFTYPES_H_
#include <freetype/freetype.h>
#include <freetype/ftoutln.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include "afblue.h"
#ifdef FT_DEBUG_AUTOFIT
#include FT_CONFIG_STANDARD_LIBRARY_H
#endif
FT_BEGIN_HEADER
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** D E B U G G I N G *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
#ifdef FT_DEBUG_AUTOFIT
extern int af_debug_disable_horz_hints_;
extern int af_debug_disable_vert_hints_;
extern int af_debug_disable_blue_hints_;
extern void* af_debug_hints_;
#endif /* FT_DEBUG_AUTOFIT */
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** U T I L I T Y S T U F F *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct AF_WidthRec_
{
FT_Pos org; /* original position/width in font units */
FT_Pos cur; /* current/scaled position/width in device subpixels */
FT_Pos fit; /* current/fitted position/width in device subpixels */
} AF_WidthRec, *AF_Width;
FT_LOCAL( void )
af_sort_pos( FT_UInt count,
FT_Pos* table );
FT_LOCAL( void )
af_sort_and_quantize_widths( FT_UInt* count,
AF_Width widths,
FT_Pos threshold );
/*
* opaque handle to glyph-specific hints -- see `afhints.h' for more
* details
*/
typedef struct AF_GlyphHintsRec_* AF_GlyphHints;
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** S C A L E R S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*
* A scaler models the target pixel device that will receive the
* auto-hinted glyph image.
*/
#define AF_SCALER_FLAG_NO_HORIZONTAL 1U /* disable horizontal hinting */
#define AF_SCALER_FLAG_NO_VERTICAL 2U /* disable vertical hinting */
#define AF_SCALER_FLAG_NO_ADVANCE 4U /* disable advance hinting */
typedef struct AF_ScalerRec_
{
FT_Face face; /* source font face */
FT_Fixed x_scale; /* from font units to 1/64 device pixels */
FT_Fixed y_scale; /* from font units to 1/64 device pixels */
FT_Pos x_delta; /* in 1/64 device pixels */
FT_Pos y_delta; /* in 1/64 device pixels */
FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc. */
FT_UInt32 flags; /* additional control flags, see above */
} AF_ScalerRec, *AF_Scaler;
#define AF_SCALER_EQUAL_SCALES( a, b ) \
( (a)->x_scale == (b)->x_scale && \
(a)->y_scale == (b)->y_scale && \
(a)->x_delta == (b)->x_delta && \
(a)->y_delta == (b)->y_delta )
typedef struct AF_StyleMetricsRec_* AF_StyleMetrics;
/*
* This function parses an FT_Face to compute global metrics for
* a specific style.
*/
typedef FT_Error
(*AF_WritingSystem_InitMetricsFunc)( AF_StyleMetrics metrics,
FT_Face face );
typedef void
(*AF_WritingSystem_ScaleMetricsFunc)( AF_StyleMetrics metrics,
AF_Scaler scaler );
typedef void
(*AF_WritingSystem_DoneMetricsFunc)( AF_StyleMetrics metrics );
typedef void
(*AF_WritingSystem_GetStdWidthsFunc)( AF_StyleMetrics metrics,
FT_Pos* stdHW,
FT_Pos* stdVW );
typedef FT_Error
(*AF_WritingSystem_InitHintsFunc)( AF_GlyphHints hints,
AF_StyleMetrics metrics );
typedef FT_Error
(*AF_WritingSystem_ApplyHintsFunc)( FT_UInt glyph_index,
AF_GlyphHints hints,
FT_Outline* outline,
AF_StyleMetrics metrics );
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** W R I T I N G S Y S T E M S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*
* For the auto-hinter, a writing system consists of multiple scripts that
* can be handled similarly *in a typographical way*; the relationship is
* not based on history. For example, both the Greek and the unrelated
* Armenian scripts share the same features like ascender, descender,
* x-height, etc. Essentially, a writing system is covered by a
* submodule of the auto-fitter; it contains
*
* - a specific global analyzer that computes global metrics specific to
* the script (based on script-specific characters to identify ascender
* height, x-height, etc.),
*
* - a specific glyph analyzer that computes segments and edges for each
* glyph covered by the script,
*
* - a specific grid-fitting algorithm that distorts the scaled glyph
* outline according to the results of the glyph analyzer.
*/
#undef WRITING_SYSTEM
#define WRITING_SYSTEM( ws, WS ) \
AF_WRITING_SYSTEM_ ## WS,
/* The list of known writing systems. */
typedef enum AF_WritingSystem_
{
#include "afws-iter.h"
AF_WRITING_SYSTEM_MAX /* do not remove */
} AF_WritingSystem;
typedef struct AF_WritingSystemClassRec_
{
AF_WritingSystem writing_system;
FT_Offset style_metrics_size;
AF_WritingSystem_InitMetricsFunc style_metrics_init;
AF_WritingSystem_ScaleMetricsFunc style_metrics_scale;
AF_WritingSystem_DoneMetricsFunc style_metrics_done;
AF_WritingSystem_GetStdWidthsFunc style_metrics_getstdw;
AF_WritingSystem_InitHintsFunc style_hints_init;
AF_WritingSystem_ApplyHintsFunc style_hints_apply;
} AF_WritingSystemClassRec;
typedef const AF_WritingSystemClassRec* AF_WritingSystemClass;
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** S C R I P T S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*
* Each script is associated with two sets of Unicode ranges to test
* whether the font face supports the script, and which non-base
* characters the script contains.
*
* We use four-letter script tags from the OpenType specification,
* extended by `NONE', which indicates `no script'.
*/
#undef SCRIPT
#define SCRIPT( s, S, d, h, H, ss ) \
AF_SCRIPT_ ## S,
/* The list of known scripts. */
typedef enum AF_Script_
{
#include "afscript.h"
AF_SCRIPT_MAX /* do not remove */
} AF_Script;
typedef struct AF_Script_UniRangeRec_
{
FT_UInt32 first;
FT_UInt32 last;
} AF_Script_UniRangeRec;
#define AF_UNIRANGE_REC( a, b ) { (FT_UInt32)(a), (FT_UInt32)(b) }
typedef const AF_Script_UniRangeRec* AF_Script_UniRange;
typedef struct AF_ScriptClassRec_
{
AF_Script script;
/* last element in the ranges must be { 0, 0 } */
AF_Script_UniRange script_uni_ranges;
AF_Script_UniRange script_uni_nonbase_ranges;
FT_Bool top_to_bottom_hinting;
const char* standard_charstring; /* for default width and height */
} AF_ScriptClassRec;
typedef const AF_ScriptClassRec* AF_ScriptClass;
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** C O V E R A G E S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*
* Usually, a font contains more glyphs than can be addressed by its
* character map.
*
* In the PostScript font world, encoding vectors specific to a given
* task are used to select such glyphs, and these glyphs can be often
* recognized by having a suffix in its glyph names. For example, a
* superscript glyph `A' might be called `A.sup'. Unfortunately, this
* naming scheme is not standardized and thus unusable for us.
*
* In the OpenType world, a better solution was invented, namely
* `features', which cleanly separate a character's input encoding from
* the corresponding glyph's appearance, and which don't use glyph names
* at all. For our purposes, and slightly generalized, an OpenType
* feature is a name of a mapping that maps character codes to
* non-standard glyph indices (features get used for other things also).
* For example, the `sups' feature provides superscript glyphs, thus
* mapping character codes like `A' or `B' to superscript glyph
* representation forms. How this mapping happens is completely
* uninteresting to us.
*
* For the auto-hinter, a `coverage' represents all glyphs of an OpenType
* feature collected in a set (as listed below) that can be hinted
* together. To continue the above example, superscript glyphs must not
* be hinted together with normal glyphs because the blue zones
* completely differ.
*
* Note that FreeType itself doesn't compute coverages; it only provides
* the glyphs addressable by the default Unicode character map. Instead,
* we use the HarfBuzz library (if available), which has many functions
* exactly for this purpose.
*
* AF_COVERAGE_DEFAULT is special: It should cover everything that isn't
* listed separately (including the glyphs addressable by the character
* map). In case HarfBuzz isn't available, it exactly covers the glyphs
* addressable by the character map.
*
*/
#undef COVERAGE
#define COVERAGE( name, NAME, description, \
tag1, tag2, tag3, tag4 ) \
AF_COVERAGE_ ## NAME,
typedef enum AF_Coverage_
{
#include "afcover.h"
AF_COVERAGE_DEFAULT
} AF_Coverage;
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** S T Y L E S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*
* The topmost structure for modelling the auto-hinter glyph input data
* is a `style class', grouping everything together.
*/
#undef STYLE
#define STYLE( s, S, d, ws, sc, ss, c ) \
AF_STYLE_ ## S,
/* The list of known styles. */
typedef enum AF_Style_
{
#include "afstyles.h"
AF_STYLE_MAX /* do not remove */
} AF_Style;
typedef struct AF_StyleClassRec_
{
AF_Style style;
AF_WritingSystem writing_system;
AF_Script script;
AF_Blue_Stringset blue_stringset;
AF_Coverage coverage;
} AF_StyleClassRec;
typedef const AF_StyleClassRec* AF_StyleClass;
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** S T Y L E M E T R I C S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals;
/* This is the main structure that combines everything. Autofit modules */
/* specific to writing systems derive their structures from it, for */
/* example `AF_LatinMetrics'. */
typedef struct AF_StyleMetricsRec_
{
AF_StyleClass style_class;
AF_ScalerRec scaler;
FT_Bool digits_have_same_width;
AF_FaceGlobals globals; /* to access properties */
} AF_StyleMetricsRec;
#define AF_HINTING_BOTTOM_TO_TOP 0
#define AF_HINTING_TOP_TO_BOTTOM 1
/* Declare and define vtables for classes */
#define AF_DECLARE_WRITING_SYSTEM_CLASS( writing_system_class ) \
FT_CALLBACK_TABLE const AF_WritingSystemClassRec \
writing_system_class;
#define AF_DEFINE_WRITING_SYSTEM_CLASS( \
writing_system_class, \
system, \
m_size, \
m_init, \
m_scale, \
m_done, \
m_stdw, \
h_init, \
h_apply ) \
FT_CALLBACK_TABLE_DEF \
const AF_WritingSystemClassRec writing_system_class = \
{ \
system, \
\
m_size, \
\
m_init, \
m_scale, \
m_done, \
m_stdw, \
\
h_init, \
h_apply \
};
#define AF_DECLARE_SCRIPT_CLASS( script_class ) \
FT_CALLBACK_TABLE const AF_ScriptClassRec \
script_class;
#define AF_DEFINE_SCRIPT_CLASS( \
script_class, \
script, \
ranges, \
nonbase_ranges, \
top_to_bottom, \
std_charstring ) \
FT_CALLBACK_TABLE_DEF \
const AF_ScriptClassRec script_class = \
{ \
script, \
ranges, \
nonbase_ranges, \
top_to_bottom, \
std_charstring, \
};
#define AF_DECLARE_STYLE_CLASS( style_class ) \
FT_CALLBACK_TABLE const AF_StyleClassRec \
style_class;
#define AF_DEFINE_STYLE_CLASS( \
style_class, \
style, \
writing_system, \
script, \
blue_stringset, \
coverage ) \
FT_CALLBACK_TABLE_DEF \
const AF_StyleClassRec style_class = \
{ \
style, \
writing_system, \
script, \
blue_stringset, \
coverage \
};
/* */
FT_END_HEADER
#endif /* AFTYPES_H_ */
/* END */

View file

@ -0,0 +1,33 @@
/****************************************************************************
*
* afws-decl.h
*
* Auto-fitter writing system declarations (specification only).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef AFWS_DECL_H_
#define AFWS_DECL_H_
/* Since preprocessor directives can't create other preprocessor */
/* directives, we have to include the header files manually. */
#include "afdummy.h"
#include "aflatin.h"
#include "afcjk.h"
#include "afindic.h"
#endif /* AFWS_DECL_H_ */
/* END */

View file

@ -0,0 +1,31 @@
/****************************************************************************
*
* afws-iter.h
*
* Auto-fitter writing systems iterator (specification only).
*
* Copyright (C) 2013-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/* This header may be included multiple times. */
/* Define `WRITING_SYSTEM' as needed. */
/* Add new writing systems here. The arguments are the writing system */
/* name in lowercase and uppercase, respectively. */
WRITING_SYSTEM( dummy, DUMMY )
WRITING_SYSTEM( latin, LATIN )
WRITING_SYSTEM( cjk, CJK )
WRITING_SYSTEM( indic, INDIC )
/* END */

View file

@ -0,0 +1,253 @@
/*
* Copyright 2000 Computing Research Labs, New Mexico State University
* Copyright 2001-2004, 2011 Francesco Zappa Nardelli
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY 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.
*/
#ifndef BDF_H_
#define BDF_H_
/*
* Based on bdf.h,v 1.16 2000/03/16 20:08:51 mleisher
*/
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/fthash.h>
FT_BEGIN_HEADER
/* Imported from bdfP.h */
#define _bdf_glyph_modified( map, e ) \
( (map)[(e) >> 5] & ( 1UL << ( (e) & 31 ) ) )
#define _bdf_set_glyph_modified( map, e ) \
( (map)[(e) >> 5] |= ( 1UL << ( (e) & 31 ) ) )
#define _bdf_clear_glyph_modified( map, e ) \
( (map)[(e) >> 5] &= ~( 1UL << ( (e) & 31 ) ) )
/* end of bdfP.h */
/**************************************************************************
*
* BDF font options macros and types.
*
*/
#define BDF_CORRECT_METRICS 0x01 /* Correct invalid metrics when loading. */
#define BDF_KEEP_COMMENTS 0x02 /* Preserve the font comments. */
#define BDF_KEEP_UNENCODED 0x04 /* Keep the unencoded glyphs. */
#define BDF_PROPORTIONAL 0x08 /* Font has proportional spacing. */
#define BDF_MONOWIDTH 0x10 /* Font has mono width. */
#define BDF_CHARCELL 0x20 /* Font has charcell spacing. */
#define BDF_ALL_SPACING ( BDF_PROPORTIONAL | \
BDF_MONOWIDTH | \
BDF_CHARCELL )
#define BDF_DEFAULT_LOAD_OPTIONS ( BDF_CORRECT_METRICS | \
BDF_KEEP_COMMENTS | \
BDF_KEEP_UNENCODED | \
BDF_PROPORTIONAL )
typedef struct bdf_options_t_
{
int correct_metrics;
int keep_unencoded;
int keep_comments;
int font_spacing;
} bdf_options_t;
/* Callback function type for unknown configuration options. */
typedef int
(*bdf_options_callback_t)( bdf_options_t* opts,
char** params,
unsigned long nparams,
void* client_data );
/**************************************************************************
*
* BDF font property macros and types.
*
*/
#define BDF_ATOM 1
#define BDF_INTEGER 2
#define BDF_CARDINAL 3
/* This structure represents a particular property of a font. */
/* There are a set of defaults and each font has their own. */
typedef struct bdf_property_t_
{
const char* name; /* Name of the property. */
int format; /* Format of the property. */
int builtin; /* A builtin property. */
union
{
char* atom;
long l;
unsigned long ul;
} value; /* Value of the property. */
} bdf_property_t;
/**************************************************************************
*
* BDF font metric and glyph types.
*
*/
typedef struct bdf_bbx_t_
{
unsigned short width;
unsigned short height;
short x_offset;
short y_offset;
short ascent;
short descent;
} bdf_bbx_t;
typedef struct bdf_glyph_t_
{
char* name; /* Glyph name. */
unsigned long encoding; /* Glyph encoding. */
unsigned short swidth; /* Scalable width. */
unsigned short dwidth; /* Device width. */
bdf_bbx_t bbx; /* Glyph bounding box. */
unsigned char* bitmap; /* Glyph bitmap. */
unsigned long bpr; /* Number of bytes used per row. */
unsigned short bytes; /* Number of bytes used for the bitmap. */
} bdf_glyph_t;
typedef struct bdf_font_t_
{
char* name; /* Name of the font. */
bdf_bbx_t bbx; /* Font bounding box. */
unsigned long point_size; /* Point size of the font. */
unsigned long resolution_x; /* Font horizontal resolution. */
unsigned long resolution_y; /* Font vertical resolution. */
int spacing; /* Font spacing value. */
unsigned short monowidth; /* Logical width for monowidth font. */
unsigned long default_char; /* Encoding of the default glyph. */
long font_ascent; /* Font ascent. */
long font_descent; /* Font descent. */
unsigned long glyphs_size; /* Glyph structures allocated. */
unsigned long glyphs_used; /* Glyph structures used. */
bdf_glyph_t* glyphs; /* Glyphs themselves. */
unsigned long unencoded_size; /* Unencoded glyph struct. allocated. */
unsigned long unencoded_used; /* Unencoded glyph struct. used. */
bdf_glyph_t* unencoded; /* Unencoded glyphs themselves. */
unsigned long props_size; /* Font properties allocated. */
unsigned long props_used; /* Font properties used. */
bdf_property_t* props; /* Font properties themselves. */
char* comments; /* Font comments. */
unsigned long comments_len; /* Length of comment string. */
void* internal; /* Internal data for the font. */
unsigned short bpp; /* Bits per pixel. */
FT_Memory memory;
bdf_property_t* user_props;
unsigned long nuser_props;
FT_HashRec proptbl;
} bdf_font_t;
/**************************************************************************
*
* Types for load/save callbacks.
*
*/
/* Error codes. */
#define BDF_MISSING_START -1
#define BDF_MISSING_FONTNAME -2
#define BDF_MISSING_SIZE -3
#define BDF_MISSING_CHARS -4
#define BDF_MISSING_STARTCHAR -5
#define BDF_MISSING_ENCODING -6
#define BDF_MISSING_BBX -7
#define BDF_OUT_OF_MEMORY -20
#define BDF_INVALID_LINE -100
/**************************************************************************
*
* BDF font API.
*
*/
FT_LOCAL( FT_Error )
bdf_load_font( FT_Stream stream,
FT_Memory memory,
bdf_options_t* opts,
bdf_font_t* *font );
FT_LOCAL( void )
bdf_free_font( bdf_font_t* font );
FT_LOCAL( bdf_property_t * )
bdf_get_font_property( bdf_font_t* font,
const char* name );
FT_END_HEADER
#endif /* BDF_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,72 @@
/* bdfdrivr.h
FreeType font driver for bdf fonts
Copyright (C) 2001, 2002, 2003, 2004 by
Francesco Zappa Nardelli
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
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
AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef BDFDRIVR_H_
#define BDFDRIVR_H_
#include <freetype/internal/ftdrv.h>
#include "bdf.h"
FT_BEGIN_HEADER
typedef struct BDF_encoding_el_
{
FT_ULong enc;
FT_UShort glyph;
} BDF_encoding_el;
typedef struct BDF_FaceRec_
{
FT_FaceRec root;
char* charset_encoding;
char* charset_registry;
bdf_font_t* bdffont;
BDF_encoding_el* en_table;
FT_UInt default_glyph;
} BDF_FaceRec, *BDF_Face;
FT_EXPORT_VAR( const FT_Driver_ClassRec ) bdf_driver_class;
FT_END_HEADER
#endif /* BDFDRIVR_H_ */
/* END */

View file

@ -0,0 +1,45 @@
/*
* Copyright 2001, 2002, 2012 Francesco Zappa Nardelli
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY 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.
*/
/**************************************************************************
*
* This file is used to define the BDF error enumeration constants.
*
*/
#ifndef BDFERROR_H_
#define BDFERROR_H_
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX BDF_Err_
#define FT_ERR_BASE FT_Mod_Err_BDF
#include <freetype/fterrors.h>
#endif /* BDFERROR_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,230 @@
/****************************************************************************
*
* cffcmap.c
*
* CFF character mapping table (cmap) support (body).
*
* Copyright (C) 2002-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftdebug.h>
#include "cffcmap.h"
#include "cffload.h"
#include "cfferrs.h"
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_CALLBACK_DEF( FT_Error )
cff_cmap_encoding_init( FT_CMap cmap,
FT_Pointer pointer )
{
CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
CFF_Font cff = (CFF_Font)face->extra.data;
CFF_Encoding encoding = &cff->encoding;
FT_UNUSED( pointer );
cffcmap->gids = encoding->codes;
return 0;
}
FT_CALLBACK_DEF( void )
cff_cmap_encoding_done( FT_CMap cmap )
{
CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
cffcmap->gids = NULL;
}
FT_CALLBACK_DEF( FT_UInt )
cff_cmap_encoding_char_index( FT_CMap cmap,
FT_UInt32 char_code )
{
CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
FT_UInt result = 0;
if ( char_code < 256 )
result = cffcmap->gids[char_code];
return result;
}
FT_CALLBACK_DEF( FT_UInt )
cff_cmap_encoding_char_next( FT_CMap cmap,
FT_UInt32 *pchar_code )
{
CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
FT_UInt result = 0;
FT_UInt32 char_code = *pchar_code;
while ( char_code < 255 )
{
result = cffcmap->gids[++char_code];
if ( result )
{
*pchar_code = char_code;
break;
}
}
return result;
}
FT_DEFINE_CMAP_CLASS(
cff_cmap_encoding_class_rec,
sizeof ( CFF_CMapStdRec ),
(FT_CMap_InitFunc) cff_cmap_encoding_init, /* init */
(FT_CMap_DoneFunc) cff_cmap_encoding_done, /* done */
(FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, /* char_index */
(FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, /* char_next */
(FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */
(FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */
(FT_CMap_VariantListFunc) NULL, /* variant_list */
(FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */
(FT_CMap_VariantCharListFunc) NULL /* variantchar_list */
)
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_CALLBACK_DEF( const char* )
cff_sid_to_glyph_name( void* face_, /* TT_Face */
FT_UInt idx )
{
TT_Face face = (TT_Face)face_;
CFF_Font cff = (CFF_Font)face->extra.data;
CFF_Charset charset = &cff->charset;
FT_UInt sid = charset->sids[idx];
return cff_index_get_sid_string( cff, sid );
}
FT_CALLBACK_DEF( FT_Error )
cff_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */
FT_Pointer pointer )
{
PS_Unicodes unicodes = (PS_Unicodes)cmap;
TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Memory memory = FT_FACE_MEMORY( face );
CFF_Font cff = (CFF_Font)face->extra.data;
CFF_Charset charset = &cff->charset;
FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
FT_UNUSED( pointer );
/* can't build Unicode map for CID-keyed font */
/* because we don't know glyph names. */
if ( !charset->sids )
return FT_THROW( No_Unicode_Glyph_Name );
if ( !psnames->unicodes_init )
return FT_THROW( Unimplemented_Feature );
return psnames->unicodes_init( memory,
unicodes,
cff->num_glyphs,
&cff_sid_to_glyph_name,
(PS_FreeGlyphNameFunc)NULL,
(FT_Pointer)face );
}
FT_CALLBACK_DEF( void )
cff_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */
{
PS_Unicodes unicodes = (PS_Unicodes)cmap;
FT_Face face = FT_CMAP_FACE( cmap );
FT_Memory memory = FT_FACE_MEMORY( face );
FT_FREE( unicodes->maps );
unicodes->num_maps = 0;
}
FT_CALLBACK_DEF( FT_UInt )
cff_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */
FT_UInt32 char_code )
{
PS_Unicodes unicodes = (PS_Unicodes)cmap;
TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
CFF_Font cff = (CFF_Font)face->extra.data;
FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
return psnames->unicodes_char_index( unicodes, char_code );
}
FT_CALLBACK_DEF( FT_UInt )
cff_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */
FT_UInt32 *pchar_code )
{
PS_Unicodes unicodes = (PS_Unicodes)cmap;
TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
CFF_Font cff = (CFF_Font)face->extra.data;
FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
return psnames->unicodes_char_next( unicodes, pchar_code );
}
FT_DEFINE_CMAP_CLASS(
cff_cmap_unicode_class_rec,
sizeof ( PS_UnicodesRec ),
(FT_CMap_InitFunc) cff_cmap_unicode_init, /* init */
(FT_CMap_DoneFunc) cff_cmap_unicode_done, /* done */
(FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, /* char_index */
(FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, /* char_next */
(FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */
(FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */
(FT_CMap_VariantListFunc) NULL, /* variant_list */
(FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */
(FT_CMap_VariantCharListFunc) NULL /* variantchar_list */
)
/* END */

View file

@ -0,0 +1,67 @@
/****************************************************************************
*
* cffcmap.h
*
* CFF character mapping table (cmap) support (specification).
*
* Copyright (C) 2002-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CFFCMAP_H_
#define CFFCMAP_H_
#include <freetype/internal/cffotypes.h>
FT_BEGIN_HEADER
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* standard (and expert) encoding cmaps */
typedef struct CFF_CMapStdRec_* CFF_CMapStd;
typedef struct CFF_CMapStdRec_
{
FT_CMapRec cmap;
FT_UShort* gids; /* up to 256 elements */
} CFF_CMapStdRec;
FT_DECLARE_CMAP_CLASS( cff_cmap_encoding_class_rec )
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* unicode (synthetic) cmaps */
FT_DECLARE_CMAP_CLASS( cff_cmap_unicode_class_rec )
FT_END_HEADER
#endif /* CFFCMAP_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,63 @@
/****************************************************************************
*
* cffdecode.h
*
* PostScript CFF (Type 2) decoding routines (specification).
*
* Copyright (C) 2017-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CFFDECODE_H_
#define CFFDECODE_H_
#include <freetype/internal/psaux.h>
FT_BEGIN_HEADER
FT_LOCAL( void )
cff_decoder_init( CFF_Decoder* decoder,
TT_Face face,
CFF_Size size,
CFF_GlyphSlot slot,
FT_Bool hinting,
FT_Render_Mode hint_mode,
CFF_Decoder_Get_Glyph_Callback get_callback,
CFF_Decoder_Free_Glyph_Callback free_callback );
FT_LOCAL( FT_Error )
cff_decoder_prepare( CFF_Decoder* decoder,
CFF_Size size,
FT_UInt glyph_index );
FT_LOCAL( FT_Int )
cff_lookup_glyph_by_stdcharcode( CFF_Font cff,
FT_Int charcode );
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
FT_LOCAL( FT_Error )
cff_decoder_parse_charstrings( CFF_Decoder* decoder,
FT_Byte* charstring_base,
FT_ULong charstring_len,
FT_Bool in_dict );
#endif
FT_END_HEADER
#endif
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
/****************************************************************************
*
* cffdrivr.h
*
* High-level OpenType driver interface (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CFFDRIVER_H_
#define CFFDRIVER_H_
#include <freetype/internal/ftdrv.h>
FT_BEGIN_HEADER
FT_DECLARE_DRIVER( cff_driver_class )
FT_END_HEADER
#endif /* CFFDRIVER_H_ */
/* END */

View file

@ -0,0 +1,42 @@
/****************************************************************************
*
* cfferrs.h
*
* CFF error codes (specification only).
*
* Copyright (C) 2001-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* This file is used to define the CFF error enumeration constants.
*
*/
#ifndef CFFERRS_H_
#define CFFERRS_H_
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX CFF_Err_
#define FT_ERR_BASE FT_Mod_Err_CFF
#include <freetype/fterrors.h>
#endif /* CFFERRS_H_ */
/* END */

View file

@ -0,0 +1,762 @@
/****************************************************************************
*
* cffgload.c
*
* OpenType Glyph Loader (body).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/sfnt.h>
#include <freetype/internal/ftcalc.h>
#include <freetype/internal/psaux.h>
#include <freetype/ftoutln.h>
#include <freetype/ftdriver.h>
#include "cffload.h"
#include "cffgload.h"
#include "cfferrs.h"
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
#define IS_DEFAULT_INSTANCE( _face ) \
( !( FT_IS_NAMED_INSTANCE( _face ) || \
FT_IS_VARIATION( _face ) ) )
#else
#define IS_DEFAULT_INSTANCE( _face ) 1
#endif
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT cffgload
FT_LOCAL_DEF( FT_Error )
cff_get_glyph_data( TT_Face face,
FT_UInt glyph_index,
FT_Byte** pointer,
FT_ULong* length )
{
#ifdef FT_CONFIG_OPTION_INCREMENTAL
/* For incremental fonts get the character data using the */
/* callback function. */
if ( face->root.internal->incremental_interface )
{
FT_Data data;
FT_Error error =
face->root.internal->incremental_interface->funcs->get_glyph_data(
face->root.internal->incremental_interface->object,
glyph_index, &data );
*pointer = (FT_Byte*)data.pointer;
*length = data.length;
return error;
}
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
{
CFF_Font cff = (CFF_Font)( face->extra.data );
return cff_index_access_element( &cff->charstrings_index, glyph_index,
pointer, length );
}
}
FT_LOCAL_DEF( void )
cff_free_glyph_data( TT_Face face,
FT_Byte** pointer,
FT_ULong length )
{
#ifndef FT_CONFIG_OPTION_INCREMENTAL
FT_UNUSED( length );
#endif
#ifdef FT_CONFIG_OPTION_INCREMENTAL
/* For incremental fonts get the character data using the */
/* callback function. */
if ( face->root.internal->incremental_interface )
{
FT_Data data;
data.pointer = *pointer;
data.length = (FT_UInt)length;
face->root.internal->incremental_interface->funcs->free_glyph_data(
face->root.internal->incremental_interface->object, &data );
}
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
{
CFF_Font cff = (CFF_Font)( face->extra.data );
cff_index_forget_element( &cff->charstrings_index, pointer );
}
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/********** *********/
/********** *********/
/********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
/********** *********/
/********** The following code is in charge of computing *********/
/********** the maximum advance width of the font. It *********/
/********** quickly processes each glyph charstring to *********/
/********** extract the value from either a `sbw' or `seac' *********/
/********** operator. *********/
/********** *********/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#if 0 /* unused until we support pure CFF fonts */
FT_LOCAL_DEF( FT_Error )
cff_compute_max_advance( TT_Face face,
FT_Int* max_advance )
{
FT_Error error = FT_Err_Ok;
CFF_Decoder decoder;
FT_Int glyph_index;
CFF_Font cff = (CFF_Font)face->other;
PSAux_Service psaux = (PSAux_Service)face->psaux;
const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs;
*max_advance = 0;
/* Initialize load decoder */
decoder_funcs->init( &decoder, face, 0, 0, 0, 0, 0, 0 );
decoder.builder.metrics_only = 1;
decoder.builder.load_points = 0;
/* For each glyph, parse the glyph charstring and extract */
/* the advance width. */
for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
glyph_index++ )
{
FT_Byte* charstring;
FT_ULong charstring_len;
/* now get load the unscaled outline */
error = cff_get_glyph_data( face, glyph_index,
&charstring, &charstring_len );
if ( !error )
{
error = decoder_funcs->prepare( &decoder, size, glyph_index );
if ( !error )
error = decoder_funcs->parse_charstrings_old( &decoder,
charstring,
charstring_len,
0 );
cff_free_glyph_data( face, &charstring, &charstring_len );
}
/* ignore the error if one has occurred -- skip to next glyph */
error = FT_Err_Ok;
}
*max_advance = decoder.builder.advance.x;
return FT_Err_Ok;
}
#endif /* 0 */
FT_LOCAL_DEF( FT_Error )
cff_slot_load( CFF_GlyphSlot glyph,
CFF_Size size,
FT_UInt glyph_index,
FT_Int32 load_flags )
{
FT_Error error;
CFF_Decoder decoder;
PS_Decoder psdecoder;
TT_Face face = (TT_Face)glyph->root.face;
FT_Bool hinting, scaled, force_scaling;
CFF_Font cff = (CFF_Font)face->extra.data;
PSAux_Service psaux = (PSAux_Service)face->psaux;
const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs;
FT_Matrix font_matrix;
FT_Vector font_offset;
force_scaling = FALSE;
/* in a CID-keyed font, consider `glyph_index' as a CID and map */
/* it immediately to the real glyph_index -- if it isn't a */
/* subsetted font, glyph_indices and CIDs are identical, though */
if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
cff->charset.cids )
{
/* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */
if ( glyph_index != 0 )
{
glyph_index = cff_charset_cid_to_gindex( &cff->charset,
glyph_index );
if ( glyph_index == 0 )
return FT_THROW( Invalid_Argument );
}
}
else if ( glyph_index >= cff->num_glyphs )
return FT_THROW( Invalid_Argument );
if ( load_flags & FT_LOAD_NO_RECURSE )
load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
glyph->x_scale = 0x10000L;
glyph->y_scale = 0x10000L;
if ( size )
{
glyph->x_scale = size->root.metrics.x_scale;
glyph->y_scale = size->root.metrics.y_scale;
}
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
/* try to load embedded bitmap if any */
/* */
/* XXX: The convention should be emphasized in */
/* the documents because it can be confusing. */
if ( size )
{
CFF_Face cff_face = (CFF_Face)size->root.face;
SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt;
FT_Stream stream = cff_face->root.stream;
if ( size->strike_index != 0xFFFFFFFFUL &&
( load_flags & FT_LOAD_NO_BITMAP ) == 0 &&
IS_DEFAULT_INSTANCE( size->root.face ) )
{
TT_SBit_MetricsRec metrics;
error = sfnt->load_sbit_image( face,
size->strike_index,
glyph_index,
(FT_UInt)load_flags,
stream,
&glyph->root.bitmap,
&metrics );
if ( !error )
{
FT_Bool has_vertical_info;
FT_UShort advance;
FT_Short dummy;
glyph->root.outline.n_points = 0;
glyph->root.outline.n_contours = 0;
glyph->root.metrics.width = (FT_Pos)metrics.width * 64;
glyph->root.metrics.height = (FT_Pos)metrics.height * 64;
glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX * 64;
glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY * 64;
glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance * 64;
glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX * 64;
glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY * 64;
glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance * 64;
glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
{
glyph->root.bitmap_left = metrics.vertBearingX;
glyph->root.bitmap_top = metrics.vertBearingY;
}
else
{
glyph->root.bitmap_left = metrics.horiBearingX;
glyph->root.bitmap_top = metrics.horiBearingY;
}
/* compute linear advance widths */
(void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
glyph_index,
&dummy,
&advance );
glyph->root.linearHoriAdvance = advance;
has_vertical_info = FT_BOOL(
face->vertical_info &&
face->vertical.number_Of_VMetrics > 0 );
/* get the vertical metrics from the vmtx table if we have one */
if ( has_vertical_info )
{
(void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
glyph_index,
&dummy,
&advance );
glyph->root.linearVertAdvance = advance;
}
else
{
/* make up vertical ones */
if ( face->os2.version != 0xFFFFU )
glyph->root.linearVertAdvance = (FT_Pos)
( face->os2.sTypoAscender - face->os2.sTypoDescender );
else
glyph->root.linearVertAdvance = (FT_Pos)
( face->horizontal.Ascender - face->horizontal.Descender );
}
return error;
}
}
}
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
/* return immediately if we only want the embedded bitmaps */
if ( load_flags & FT_LOAD_SBITS_ONLY )
return FT_THROW( Invalid_Argument );
#ifdef FT_CONFIG_OPTION_SVG
/* check for OT-SVG */
if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
( load_flags & FT_LOAD_COLOR ) &&
face->svg )
{
/*
* We load the SVG document and try to grab the advances from the
* table. For the bearings we rely on the presetting hook to do that.
*/
SFNT_Service sfnt = (SFNT_Service)face->sfnt;
if ( size && (size->root.metrics.x_ppem < 1 ||
size->root.metrics.y_ppem < 1 ) )
{
error = FT_THROW( Invalid_Size_Handle );
return error;
}
FT_TRACE3(( "Trying to load SVG glyph\n" ));
error = sfnt->load_svg_doc( (FT_GlyphSlot)glyph, glyph_index );
if ( !error )
{
FT_Fixed x_scale = size->root.metrics.x_scale;
FT_Fixed y_scale = size->root.metrics.y_scale;
FT_Short dummy;
FT_UShort advanceX;
FT_UShort advanceY;
FT_TRACE3(( "Successfully loaded SVG glyph\n" ));
glyph->root.format = FT_GLYPH_FORMAT_SVG;
/*
* If horizontal or vertical advances are not present in the table,
* this is a problem with the font since the standard requires them.
* However, we are graceful and calculate the values by ourselves
* for the vertical case.
*/
sfnt->get_metrics( face,
FALSE,
glyph_index,
&dummy,
&advanceX );
sfnt->get_metrics( face,
TRUE,
glyph_index,
&dummy,
&advanceY );
glyph->root.linearHoriAdvance = advanceX;
glyph->root.linearVertAdvance = advanceY;
glyph->root.metrics.horiAdvance = FT_MulFix( advanceX, x_scale );
glyph->root.metrics.vertAdvance = FT_MulFix( advanceY, y_scale );
return error;
}
FT_TRACE3(( "Failed to load SVG glyph\n" ));
}
#endif /* FT_CONFIG_OPTION_SVG */
/* if we have a CID subfont, use its matrix (which has already */
/* been multiplied with the root matrix) */
/* this scaling is only relevant if the PS hinter isn't active */
if ( cff->num_subfonts )
{
FT_Long top_upm, sub_upm;
FT_Byte fd_index = cff_fd_select_get( &cff->fd_select,
glyph_index );
if ( fd_index >= cff->num_subfonts )
fd_index = (FT_Byte)( cff->num_subfonts - 1 );
top_upm = (FT_Long)cff->top_font.font_dict.units_per_em;
sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em;
font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix;
font_offset = cff->subfonts[fd_index]->font_dict.font_offset;
if ( top_upm != sub_upm )
{
glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm );
glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm );
force_scaling = TRUE;
}
}
else
{
font_matrix = cff->top_font.font_dict.font_matrix;
font_offset = cff->top_font.font_dict.font_offset;
}
glyph->root.outline.n_points = 0;
glyph->root.outline.n_contours = 0;
/* top-level code ensures that FT_LOAD_NO_HINTING is set */
/* if FT_LOAD_NO_SCALE is active */
hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
glyph->hint = hinting;
glyph->scaled = scaled;
glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */
{
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face );
#endif
FT_Byte* charstring;
FT_ULong charstring_len;
decoder_funcs->init( &decoder, face, size, glyph, hinting,
FT_LOAD_TARGET_MODE( load_flags ),
cff_get_glyph_data,
cff_free_glyph_data );
/* this is for pure CFFs */
if ( load_flags & FT_LOAD_ADVANCE_ONLY )
decoder.width_only = TRUE;
decoder.builder.no_recurse =
FT_BOOL( load_flags & FT_LOAD_NO_RECURSE );
/* this function also checks for a valid subfont index */
error = decoder_funcs->prepare( &decoder, size, glyph_index );
if ( error )
goto Glyph_Build_Finished;
/* now load the unscaled outline */
error = cff_get_glyph_data( face, glyph_index,
&charstring, &charstring_len );
if ( error )
goto Glyph_Build_Finished;
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
/* choose which CFF renderer to use */
if ( driver->hinting_engine == FT_HINTING_FREETYPE )
error = decoder_funcs->parse_charstrings_old( &decoder,
charstring,
charstring_len,
0 );
else
#endif
{
psaux->ps_decoder_init( &psdecoder, &decoder, FALSE );
error = decoder_funcs->parse_charstrings( &psdecoder,
charstring,
charstring_len );
/* Adobe's engine uses 16.16 numbers everywhere; */
/* as a consequence, glyphs larger than 2000ppem get rejected */
if ( FT_ERR_EQ( error, Glyph_Too_Big ) )
{
/* this time, we retry unhinted and scale up the glyph later on */
/* (the engine uses and sets the hardcoded value 0x10000 / 64 = */
/* 0x400 for both `x_scale' and `y_scale' in this case) */
hinting = FALSE;
force_scaling = TRUE;
glyph->hint = hinting;
error = decoder_funcs->parse_charstrings( &psdecoder,
charstring,
charstring_len );
}
}
cff_free_glyph_data( face, &charstring, charstring_len );
if ( error )
goto Glyph_Build_Finished;
#ifdef FT_CONFIG_OPTION_INCREMENTAL
/* Control data and length may not be available for incremental */
/* fonts. */
if ( face->root.internal->incremental_interface )
{
glyph->root.control_data = NULL;
glyph->root.control_len = 0;
}
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
/* We set control_data and control_len if charstrings is loaded. */
/* See how charstring loads at cff_index_access_element() in */
/* cffload.c. */
{
CFF_Index csindex = &cff->charstrings_index;
if ( csindex->offsets )
{
glyph->root.control_data = csindex->bytes +
csindex->offsets[glyph_index] - 1;
glyph->root.control_len = (FT_Long)charstring_len;
}
}
Glyph_Build_Finished:
/* save new glyph tables, if no error */
if ( !error )
decoder.builder.funcs.done( &decoder.builder );
/* XXX: anything to do for broken glyph entry? */
}
#ifdef FT_CONFIG_OPTION_INCREMENTAL
/* Incremental fonts can optionally override the metrics. */
if ( !error &&
face->root.internal->incremental_interface &&
face->root.internal->incremental_interface->funcs->get_glyph_metrics )
{
FT_Incremental_MetricsRec metrics;
metrics.bearing_x = decoder.builder.left_bearing.x;
metrics.bearing_y = 0;
metrics.advance = decoder.builder.advance.x;
metrics.advance_v = decoder.builder.advance.y;
error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
face->root.internal->incremental_interface->object,
glyph_index, FALSE, &metrics );
decoder.builder.left_bearing.x = metrics.bearing_x;
decoder.builder.advance.x = metrics.advance;
decoder.builder.advance.y = metrics.advance_v;
}
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
if ( !error )
{
/* Now, set the metrics -- this is rather simple, as */
/* the left side bearing is the xMin, and the top side */
/* bearing the yMax. */
/* For composite glyphs, return only left side bearing and */
/* advance width. */
if ( load_flags & FT_LOAD_NO_RECURSE )
{
FT_Slot_Internal internal = glyph->root.internal;
glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
glyph->root.metrics.horiAdvance = decoder.glyph_width;
internal->glyph_matrix = font_matrix;
internal->glyph_delta = font_offset;
internal->glyph_transformed = 1;
}
else
{
FT_BBox cbox;
FT_Glyph_Metrics* metrics = &glyph->root.metrics;
FT_Bool has_vertical_info;
if ( face->horizontal.number_Of_HMetrics )
{
FT_Short horiBearingX = 0;
FT_UShort horiAdvance = 0;
( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
glyph_index,
&horiBearingX,
&horiAdvance );
metrics->horiAdvance = horiAdvance;
metrics->horiBearingX = horiBearingX;
glyph->root.linearHoriAdvance = horiAdvance;
}
else
{
/* copy the _unscaled_ advance width */
metrics->horiAdvance = decoder.glyph_width;
glyph->root.linearHoriAdvance = decoder.glyph_width;
}
glyph->root.internal->glyph_transformed = 0;
has_vertical_info = FT_BOOL( face->vertical_info &&
face->vertical.number_Of_VMetrics > 0 );
/* get the vertical metrics from the vmtx table if we have one */
if ( has_vertical_info )
{
FT_Short vertBearingY = 0;
FT_UShort vertAdvance = 0;
( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
glyph_index,
&vertBearingY,
&vertAdvance );
metrics->vertBearingY = vertBearingY;
metrics->vertAdvance = vertAdvance;
}
else
{
/* make up vertical ones */
if ( face->os2.version != 0xFFFFU )
metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender -
face->os2.sTypoDescender );
else
metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender -
face->horizontal.Descender );
}
glyph->root.linearVertAdvance = metrics->vertAdvance;
glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
glyph->root.outline.flags = 0;
if ( size && size->root.metrics.y_ppem < 24 )
glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
/* apply the font matrix, if any */
if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
font_matrix.xy != 0 || font_matrix.yx != 0 )
{
FT_Outline_Transform( &glyph->root.outline, &font_matrix );
metrics->horiAdvance = FT_MulFix( metrics->horiAdvance,
font_matrix.xx );
metrics->vertAdvance = FT_MulFix( metrics->vertAdvance,
font_matrix.yy );
}
if ( font_offset.x || font_offset.y )
{
FT_Outline_Translate( &glyph->root.outline,
font_offset.x,
font_offset.y );
metrics->horiAdvance += font_offset.x;
metrics->vertAdvance += font_offset.y;
}
if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
{
/* scale the outline and the metrics */
FT_Int n;
FT_Outline* cur = &glyph->root.outline;
FT_Vector* vec = cur->points;
FT_Fixed x_scale = glyph->x_scale;
FT_Fixed y_scale = glyph->y_scale;
/* First of all, scale the points */
if ( !hinting || !decoder.builder.hints_funcs )
for ( n = cur->n_points; n > 0; n--, vec++ )
{
vec->x = FT_MulFix( vec->x, x_scale );
vec->y = FT_MulFix( vec->y, y_scale );
}
/* Then scale the metrics */
metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
}
/* compute the other metrics */
FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
metrics->width = cbox.xMax - cbox.xMin;
metrics->height = cbox.yMax - cbox.yMin;
metrics->horiBearingX = cbox.xMin;
metrics->horiBearingY = cbox.yMax;
if ( has_vertical_info )
{
metrics->vertBearingX = metrics->horiBearingX -
metrics->horiAdvance / 2;
metrics->vertBearingY = FT_MulFix( metrics->vertBearingY,
glyph->y_scale );
}
else
{
if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
ft_synthesize_vertical_metrics( metrics,
metrics->vertAdvance );
}
}
}
return error;
}
/* END */

View file

@ -0,0 +1,62 @@
/****************************************************************************
*
* cffgload.h
*
* OpenType Glyph Loader (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CFFGLOAD_H_
#define CFFGLOAD_H_
#include <freetype/freetype.h>
#include <freetype/internal/cffotypes.h>
FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
cff_get_glyph_data( TT_Face face,
FT_UInt glyph_index,
FT_Byte** pointer,
FT_ULong* length );
FT_LOCAL( void )
cff_free_glyph_data( TT_Face face,
FT_Byte** pointer,
FT_ULong length );
#if 0 /* unused until we support pure CFF fonts */
/* Compute the maximum advance width of a font through quick parsing */
FT_LOCAL( FT_Error )
cff_compute_max_advance( TT_Face face,
FT_Int* max_advance );
#endif /* 0 */
FT_LOCAL( FT_Error )
cff_slot_load( CFF_GlyphSlot glyph,
CFF_Size size,
FT_UInt glyph_index,
FT_Int32 load_flags );
FT_END_HEADER
#endif /* CFFGLOAD_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,124 @@
/****************************************************************************
*
* cffload.h
*
* OpenType & CFF data/program tables loader (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CFFLOAD_H_
#define CFFLOAD_H_
#include <freetype/internal/cfftypes.h>
#include "cffparse.h"
#include <freetype/internal/cffotypes.h> /* for CFF_Face */
FT_BEGIN_HEADER
FT_LOCAL( FT_UShort )
cff_get_standard_encoding( FT_UInt charcode );
FT_LOCAL( FT_String* )
cff_index_get_string( CFF_Font font,
FT_UInt element );
FT_LOCAL( FT_String* )
cff_index_get_sid_string( CFF_Font font,
FT_UInt sid );
FT_LOCAL( FT_Error )
cff_index_access_element( CFF_Index idx,
FT_UInt element,
FT_Byte** pbytes,
FT_ULong* pbyte_len );
FT_LOCAL( void )
cff_index_forget_element( CFF_Index idx,
FT_Byte** pbytes );
FT_LOCAL( FT_String* )
cff_index_get_name( CFF_Font font,
FT_UInt element );
FT_LOCAL( FT_UInt )
cff_charset_cid_to_gindex( CFF_Charset charset,
FT_UInt cid );
FT_LOCAL( FT_Error )
cff_font_load( FT_Library library,
FT_Stream stream,
FT_Int face_index,
CFF_Font font,
CFF_Face face,
FT_Bool pure_cff,
FT_Bool cff2 );
FT_LOCAL( void )
cff_font_done( CFF_Font font );
FT_LOCAL( FT_Error )
cff_load_private_dict( CFF_Font font,
CFF_SubFont subfont,
FT_UInt lenNDV,
FT_Fixed* NDV );
FT_LOCAL( FT_Byte )
cff_fd_select_get( CFF_FDSelect fdselect,
FT_UInt glyph_index );
FT_LOCAL( FT_Bool )
cff_blend_check_vector( CFF_Blend blend,
FT_UInt vsindex,
FT_UInt lenNDV,
FT_Fixed* NDV );
FT_LOCAL( FT_Error )
cff_blend_build_vector( CFF_Blend blend,
FT_UInt vsindex,
FT_UInt lenNDV,
FT_Fixed* NDV );
FT_LOCAL( void )
cff_blend_clear( CFF_SubFont subFont );
FT_LOCAL( FT_Error )
cff_blend_doBlend( CFF_SubFont subfont,
CFF_Parser parser,
FT_UInt numBlends );
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_LOCAL( FT_Error )
cff_get_var_blend( FT_Face face,
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var );
FT_LOCAL( void )
cff_done_blend( FT_Face face );
#endif
FT_END_HEADER
#endif /* CFFLOAD_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,84 @@
/****************************************************************************
*
* cffobjs.h
*
* OpenType objects manager (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CFFOBJS_H_
#define CFFOBJS_H_
FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
cff_size_init( FT_Size size ); /* CFF_Size */
FT_LOCAL( void )
cff_size_done( FT_Size size ); /* CFF_Size */
FT_LOCAL( FT_Error )
cff_size_request( FT_Size size,
FT_Size_Request req );
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
FT_LOCAL( FT_Error )
cff_size_select( FT_Size size,
FT_ULong strike_index );
#endif
FT_LOCAL( void )
cff_slot_done( FT_GlyphSlot slot );
FT_LOCAL( FT_Error )
cff_slot_init( FT_GlyphSlot slot );
/**************************************************************************
*
* Face functions
*/
FT_LOCAL( FT_Error )
cff_face_init( FT_Stream stream,
FT_Face face, /* CFF_Face */
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params );
FT_LOCAL( void )
cff_face_done( FT_Face face ); /* CFF_Face */
/**************************************************************************
*
* Driver functions
*/
FT_LOCAL( FT_Error )
cff_driver_init( FT_Module module ); /* PS_Driver */
FT_LOCAL( void )
cff_driver_done( FT_Module module ); /* PS_Driver */
FT_END_HEADER
#endif /* CFFOBJS_H_ */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,143 @@
/****************************************************************************
*
* cffparse.h
*
* CFF token stream parser (specification)
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CFFPARSE_H_
#define CFFPARSE_H_
#include <freetype/internal/cfftypes.h>
#include <freetype/internal/ftobjs.h>
FT_BEGIN_HEADER
/* CFF uses constant parser stack size; */
/* CFF2 can increase from default 193 */
#define CFF_MAX_STACK_DEPTH 96
/*
* There are plans to remove the `maxstack' operator in a forthcoming
* revision of the CFF2 specification, increasing the (then static) stack
* size to 513. By making the default stack size equal to the maximum
* stack size, the operator is essentially disabled, which has the
* desired effect in FreeType.
*/
#define CFF2_MAX_STACK 513
#define CFF2_DEFAULT_STACK 513
#define CFF_CODE_TOPDICT 0x1000
#define CFF_CODE_PRIVATE 0x2000
#define CFF2_CODE_TOPDICT 0x3000
#define CFF2_CODE_FONTDICT 0x4000
#define CFF2_CODE_PRIVATE 0x5000
typedef struct CFF_ParserRec_
{
FT_Library library;
FT_Byte* start;
FT_Byte* limit;
FT_Byte* cursor;
FT_Byte** stack;
FT_Byte** top;
FT_UInt stackSize; /* allocated size */
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
FT_ListRec t2_strings;
#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
FT_UInt object_code;
void* object;
FT_UShort num_designs; /* a copy of `CFF_FontRecDict->num_designs' */
FT_UShort num_axes; /* a copy of `CFF_FontRecDict->num_axes' */
} CFF_ParserRec, *CFF_Parser;
FT_LOCAL( FT_Long )
cff_parse_num( CFF_Parser parser,
FT_Byte** d );
FT_LOCAL( FT_Fixed )
cff_parse_fixed( CFF_Parser parser,
FT_Byte** d );
FT_LOCAL( FT_Error )
cff_parser_init( CFF_Parser parser,
FT_UInt code,
void* object,
FT_Library library,
FT_UInt stackSize,
FT_UShort num_designs,
FT_UShort num_axes );
FT_LOCAL( void )
cff_parser_done( CFF_Parser parser );
FT_LOCAL( FT_Error )
cff_parser_run( CFF_Parser parser,
FT_Byte* start,
FT_Byte* limit );
enum
{
cff_kind_none = 0,
cff_kind_num,
cff_kind_fixed,
cff_kind_fixed_thousand,
cff_kind_string,
cff_kind_bool,
cff_kind_delta,
cff_kind_callback,
cff_kind_blend,
cff_kind_max /* do not remove */
};
/* now generate handlers for the most simple fields */
typedef FT_Error (*CFF_Field_Reader)( CFF_Parser parser );
typedef struct CFF_Field_Handler_
{
int kind;
int code;
FT_UInt offset;
FT_Byte size;
CFF_Field_Reader reader;
FT_UInt array_max;
FT_UInt count_offset;
#ifdef FT_DEBUG_LEVEL_TRACE
const char* id;
#endif
} CFF_Field_Handler;
FT_END_HEADER
#endif /* CFFPARSE_H_ */
/* END */

View file

@ -0,0 +1,150 @@
/****************************************************************************
*
* cfftoken.h
*
* CFF token definitions (specification only).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_FontRecDictRec
#undef CFFCODE
#define CFFCODE CFF_CODE_TOPDICT
CFF_FIELD_STRING ( 0, version, "Version" )
CFF_FIELD_STRING ( 1, notice, "Notice" )
CFF_FIELD_STRING ( 0x100, copyright, "Copyright" )
CFF_FIELD_STRING ( 2, full_name, "FullName" )
CFF_FIELD_STRING ( 3, family_name, "FamilyName" )
CFF_FIELD_STRING ( 4, weight, "Weight" )
CFF_FIELD_BOOL ( 0x101, is_fixed_pitch, "isFixedPitch" )
CFF_FIELD_FIXED ( 0x102, italic_angle, "ItalicAngle" )
CFF_FIELD_FIXED ( 0x103, underline_position, "UnderlinePosition" )
CFF_FIELD_FIXED ( 0x104, underline_thickness, "UnderlineThickness" )
CFF_FIELD_NUM ( 0x105, paint_type, "PaintType" )
CFF_FIELD_NUM ( 0x106, charstring_type, "CharstringType" )
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
CFF_FIELD_NUM ( 13, unique_id, "UniqueID" )
CFF_FIELD_CALLBACK( 5, font_bbox, "FontBBox" )
CFF_FIELD_NUM ( 0x108, stroke_width, "StrokeWidth" )
#if 0
CFF_FIELD_DELTA ( 14, xuid, 16, "XUID" )
#endif
CFF_FIELD_NUM ( 15, charset_offset, "charset" )
CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" )
CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
CFF_FIELD_NUM ( 0x114, synthetic_base, "SyntheticBase" )
CFF_FIELD_STRING ( 0x115, embedded_postscript, "PostScript" )
#if 0
CFF_FIELD_STRING ( 0x116, base_font_name, "BaseFontName" )
CFF_FIELD_DELTA ( 0x117, base_font_blend, 16, "BaseFontBlend" )
#endif
/* the next two operators were removed from the Type2 specification */
/* in version 16-March-2000 */
CFF_FIELD_CALLBACK( 0x118, multiple_master, "MultipleMaster" )
#if 0
CFF_FIELD_CALLBACK( 0x11A, blend_axis_types, "BlendAxisTypes" )
#endif
CFF_FIELD_CALLBACK( 0x11E, cid_ros, "ROS" )
CFF_FIELD_NUM ( 0x11F, cid_font_version, "CIDFontVersion" )
CFF_FIELD_NUM ( 0x120, cid_font_revision, "CIDFontRevision" )
CFF_FIELD_NUM ( 0x121, cid_font_type, "CIDFontType" )
CFF_FIELD_NUM ( 0x122, cid_count, "CIDCount" )
CFF_FIELD_NUM ( 0x123, cid_uid_base, "UIDBase" )
CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" )
CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" )
CFF_FIELD_STRING ( 0x126, cid_font_name, "FontName" )
#if 0
CFF_FIELD_NUM ( 0x127, chameleon, "Chameleon" )
#endif
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_PrivateRec
#undef CFFCODE
#define CFFCODE CFF_CODE_PRIVATE
CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" )
CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" )
CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" )
CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" )
CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" )
CFF_FIELD_NUM ( 10, standard_width, "StdHW" )
CFF_FIELD_NUM ( 11, standard_height, "StdVW" )
CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" )
CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" )
CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" )
CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" )
CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" )
CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" )
CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" )
CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" )
CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" )
CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" )
CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" )
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_FontRecDictRec
#undef CFFCODE
#define CFFCODE CFF2_CODE_TOPDICT
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" )
CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" )
CFF_FIELD_NUM ( 24, vstore_offset, "vstore" )
CFF_FIELD_CALLBACK( 25, maxstack, "maxstack" )
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_FontRecDictRec
#undef CFFCODE
#define CFFCODE CFF2_CODE_FONTDICT
CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_PrivateRec
#undef CFFCODE
#define CFFCODE CFF2_CODE_PRIVATE
CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" )
CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" )
CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" )
CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" )
CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" )
CFF_FIELD_NUM ( 10, standard_width, "StdHW" )
CFF_FIELD_NUM ( 11, standard_height, "StdVW" )
CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" )
CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" )
CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" )
CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" )
CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" )
CFF_FIELD_BLEND ( 23, "blend" )
CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" )
/* END */

View file

@ -0,0 +1,41 @@
/****************************************************************************
*
* ciderrs.h
*
* CID error codes (specification only).
*
* Copyright (C) 2001-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* This file is used to define the CID error enumeration constants.
*
*/
#ifndef CIDERRS_H_
#define CIDERRS_H_
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX CID_Err_
#define FT_ERR_BASE FT_Mod_Err_CID
#include <freetype/fterrors.h>
#endif /* CIDERRS_H_ */
/* END */

View file

@ -0,0 +1,618 @@
/****************************************************************************
*
* cidgload.c
*
* CID-keyed Type1 Glyph Loader (body).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "cidload.h"
#include "cidgload.h"
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftstream.h>
#include <freetype/ftoutln.h>
#include <freetype/internal/ftcalc.h>
#include <freetype/internal/psaux.h>
#include <freetype/internal/cfftypes.h>
#include <freetype/ftdriver.h>
#include "ciderrs.h"
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT cidgload
/*
* A helper function to compute FD number (`fd_select`), the offset to the
* head of the glyph data (`off1`), and the offset to the and of the glyph
* data (`off2`).
*
* The number how many times `cid_get_offset` is invoked can be controlled
* by the number of non-NULL arguments. If `fd_select` is non-NULL but
* `off1` and `off2` are NULL, `cid_get_offset` is invoked only for
* `fd_select`; `off1` and `off2` are not validated.
*
*/
FT_LOCAL_DEF( FT_Error )
cid_compute_fd_and_offsets( CID_Face face,
FT_UInt glyph_index,
FT_ULong* fd_select_p,
FT_ULong* off1_p,
FT_ULong* off2_p )
{
FT_Error error = FT_Err_Ok;
CID_FaceInfo cid = &face->cid;
FT_Stream stream = face->cid_stream;
FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes;
FT_Byte* p;
FT_Bool need_frame_exit = 0;
FT_ULong fd_select, off1, off2;
/* For ordinary fonts, read the CID font dictionary index */
/* and charstring offset from the CIDMap. */
if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
glyph_index * entry_len ) ||
FT_FRAME_ENTER( 2 * entry_len ) )
goto Exit;
need_frame_exit = 1;
p = (FT_Byte*)stream->cursor;
fd_select = cid_get_offset( &p, cid->fd_bytes );
off1 = cid_get_offset( &p, cid->gd_bytes );
p += cid->fd_bytes;
off2 = cid_get_offset( &p, cid->gd_bytes );
if ( fd_select_p )
*fd_select_p = fd_select;
if ( off1_p )
*off1_p = off1;
if ( off2_p )
*off2_p = off2;
if ( fd_select >= cid->num_dicts )
{
/*
* fd_select == 0xFF is often used to indicate that the CID
* has no charstring to be rendered, similar to GID = 0xFFFF
* in TrueType fonts.
*/
if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) ||
( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) )
{
FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n",
glyph_index ));
FT_TRACE1(( " FD number %ld is the maximum\n",
fd_select ));
FT_TRACE1(( " integer fitting into %d byte%s\n",
cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" ));
}
else
{
FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
glyph_index ));
FT_TRACE0(( " FD number %ld is larger\n",
fd_select ));
FT_TRACE0(( " than number of dictionaries (%d)\n",
cid->num_dicts ));
}
error = FT_THROW( Invalid_Offset );
goto Exit;
}
else if ( off2 > stream->size )
{
FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
glyph_index ));
FT_TRACE0(( " end of the glyph data\n" ));
FT_TRACE0(( " is beyond the data stream\n" ));
error = FT_THROW( Invalid_Offset );
goto Exit;
}
else if ( off1 > off2 )
{
FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
glyph_index ));
FT_TRACE0(( " the end position of glyph data\n" ));
FT_TRACE0(( " is set before the start position\n" ));
error = FT_THROW( Invalid_Offset );
}
Exit:
if ( need_frame_exit )
FT_FRAME_EXIT();
return error;
}
FT_CALLBACK_DEF( FT_Error )
cid_load_glyph( T1_Decoder decoder,
FT_UInt glyph_index )
{
CID_Face face = (CID_Face)decoder->builder.face;
CID_FaceInfo cid = &face->cid;
FT_Byte* p;
FT_ULong fd_select;
FT_Stream stream = face->cid_stream;
FT_Error error = FT_Err_Ok;
FT_Byte* charstring = NULL;
FT_Memory memory = face->root.memory;
FT_ULong glyph_length = 0;
PSAux_Service psaux = (PSAux_Service)face->psaux;
FT_Bool force_scaling = FALSE;
#ifdef FT_CONFIG_OPTION_INCREMENTAL
FT_Incremental_InterfaceRec *inc =
face->root.internal->incremental_interface;
#endif
FT_TRACE1(( "cid_load_glyph: glyph index %u\n", glyph_index ));
#ifdef FT_CONFIG_OPTION_INCREMENTAL
/* For incremental fonts get the character data using */
/* the callback function. */
if ( inc )
{
FT_Data glyph_data;
error = inc->funcs->get_glyph_data( inc->object,
glyph_index, &glyph_data );
if ( error || glyph_data.length < cid->fd_bytes )
goto Exit;
p = (FT_Byte*)glyph_data.pointer;
fd_select = cid_get_offset( &p, cid->fd_bytes );
glyph_length = glyph_data.length - cid->fd_bytes;
if ( !FT_QALLOC( charstring, glyph_length ) )
FT_MEM_COPY( charstring, glyph_data.pointer + cid->fd_bytes,
glyph_length );
inc->funcs->free_glyph_data( inc->object, &glyph_data );
if ( error )
goto Exit;
}
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
{
FT_ULong off1, off2;
error = cid_compute_fd_and_offsets( face, glyph_index,
&fd_select, &off1, &off2 );
if ( error )
goto Exit;
glyph_length = off2 - off1;
if ( glyph_length == 0 ||
FT_QALLOC( charstring, glyph_length ) ||
FT_STREAM_READ_AT( cid->data_offset + off1,
charstring, glyph_length ) )
goto Exit;
}
/* Now set up the subrs array and parse the charstrings. */
{
CID_FaceDict dict;
CID_Subrs cid_subrs = face->subrs + fd_select;
FT_UInt cs_offset;
/* Set up subrs */
decoder->num_subrs = cid_subrs->num_subrs;
decoder->subrs = cid_subrs->code;
decoder->subrs_len = 0;
decoder->subrs_hash = NULL;
/* Set up font matrix */
dict = cid->font_dicts + fd_select;
decoder->font_matrix = dict->font_matrix;
decoder->font_offset = dict->font_offset;
decoder->lenIV = dict->private_dict.lenIV;
/* Decode the charstring. */
/* Adjustment for seed bytes. */
cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0;
if ( cs_offset > glyph_length )
{
FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, "
"offset to the charstring is beyond glyph length\n",
glyph_index ));
error = FT_THROW( Invalid_Offset );
goto Exit;
}
/* Decrypt only if lenIV >= 0. */
if ( decoder->lenIV >= 0 )
psaux->t1_decrypt( charstring, glyph_length, 4330 );
/* choose which renderer to use */
#ifdef T1_CONFIG_OPTION_OLD_ENGINE
if ( ( (PS_Driver)FT_FACE_DRIVER( face ) )->hinting_engine ==
FT_HINTING_FREETYPE ||
decoder->builder.metrics_only )
error = psaux->t1_decoder_funcs->parse_charstrings_old(
decoder,
charstring + cs_offset,
glyph_length - cs_offset );
#else
if ( decoder->builder.metrics_only )
error = psaux->t1_decoder_funcs->parse_metrics(
decoder,
charstring + cs_offset,
glyph_length - cs_offset );
#endif
else
{
PS_Decoder psdecoder;
CFF_SubFontRec subfont;
psaux->ps_decoder_init( &psdecoder, decoder, TRUE );
psaux->t1_make_subfont( FT_FACE( face ),
&dict->private_dict,
&subfont );
psdecoder.current_subfont = &subfont;
error = psaux->t1_decoder_funcs->parse_charstrings(
&psdecoder,
charstring + cs_offset,
glyph_length - cs_offset );
/* Adobe's engine uses 16.16 numbers everywhere; */
/* as a consequence, glyphs larger than 2000ppem get rejected */
if ( FT_ERR_EQ( error, Glyph_Too_Big ) )
{
/* this time, we retry unhinted and scale up the glyph later on */
/* (the engine uses and sets the hardcoded value 0x10000 / 64 = */
/* 0x400 for both `x_scale' and `y_scale' in this case) */
((CID_GlyphSlot)decoder->builder.glyph)->hint = FALSE;
force_scaling = TRUE;
error = psaux->t1_decoder_funcs->parse_charstrings(
&psdecoder,
charstring + cs_offset,
glyph_length - cs_offset );
}
}
}
#ifdef FT_CONFIG_OPTION_INCREMENTAL
/* Incremental fonts can optionally override the metrics. */
if ( !error && inc && inc->funcs->get_glyph_metrics )
{
FT_Incremental_MetricsRec metrics;
metrics.bearing_x = FIXED_TO_INT( decoder->builder.left_bearing.x );
metrics.bearing_y = 0;
metrics.advance = FIXED_TO_INT( decoder->builder.advance.x );
metrics.advance_v = FIXED_TO_INT( decoder->builder.advance.y );
error = inc->funcs->get_glyph_metrics( inc->object,
glyph_index, FALSE, &metrics );
decoder->builder.left_bearing.x = INT_TO_FIXED( metrics.bearing_x );
decoder->builder.advance.x = INT_TO_FIXED( metrics.advance );
decoder->builder.advance.y = INT_TO_FIXED( metrics.advance_v );
}
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
Exit:
FT_FREE( charstring );
((CID_GlyphSlot)decoder->builder.glyph)->scaled = force_scaling;
return error;
}
#if 0
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/********** *********/
/********** *********/
/********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
/********** *********/
/********** The following code is in charge of computing *********/
/********** the maximum advance width of the font. It *********/
/********** quickly processes each glyph charstring to *********/
/********** extract the value from either a `sbw' or `seac' *********/
/********** operator. *********/
/********** *********/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL_DEF( FT_Error )
cid_face_compute_max_advance( CID_Face face,
FT_Int* max_advance )
{
FT_Error error;
T1_DecoderRec decoder;
FT_Int glyph_index;
PSAux_Service psaux = (PSAux_Service)face->psaux;
*max_advance = 0;
/* Initialize load decoder */
error = psaux->t1_decoder_funcs->init( &decoder,
(FT_Face)face,
0, /* size */
0, /* glyph slot */
0, /* glyph names! XXX */
0, /* blend == 0 */
0, /* hinting == 0 */
cid_load_glyph );
if ( error )
return error;
/* TODO: initialize decoder.len_buildchar and decoder.buildchar */
/* if we ever support CID-keyed multiple master fonts */
decoder.builder.metrics_only = 1;
decoder.builder.load_points = 0;
/* for each glyph, parse the glyph charstring and extract */
/* the advance width */
for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
glyph_index++ )
{
/* now get load the unscaled outline */
error = cid_load_glyph( &decoder, glyph_index );
/* ignore the error if one occurred - skip to next glyph */
}
*max_advance = FIXED_TO_INT( decoder.builder.advance.x );
psaux->t1_decoder_funcs->done( &decoder );
return FT_Err_Ok;
}
#endif /* 0 */
FT_LOCAL_DEF( FT_Error )
cid_slot_load_glyph( FT_GlyphSlot cidglyph, /* CID_GlyphSlot */
FT_Size cidsize, /* CID_Size */
FT_UInt glyph_index,
FT_Int32 load_flags )
{
CID_GlyphSlot glyph = (CID_GlyphSlot)cidglyph;
FT_Error error;
T1_DecoderRec decoder;
CID_Face face = (CID_Face)cidglyph->face;
FT_Bool hinting;
FT_Bool scaled;
PSAux_Service psaux = (PSAux_Service)face->psaux;
FT_Matrix font_matrix;
FT_Vector font_offset;
FT_Bool must_finish_decoder = FALSE;
if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
if ( load_flags & FT_LOAD_NO_RECURSE )
load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
glyph->x_scale = cidsize->metrics.x_scale;
glyph->y_scale = cidsize->metrics.y_scale;
cidglyph->outline.n_points = 0;
cidglyph->outline.n_contours = 0;
hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
( load_flags & FT_LOAD_NO_HINTING ) == 0 );
scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
glyph->hint = hinting;
glyph->scaled = scaled;
cidglyph->format = FT_GLYPH_FORMAT_OUTLINE;
error = psaux->t1_decoder_funcs->init( &decoder,
cidglyph->face,
cidsize,
cidglyph,
0, /* glyph names -- XXX */
0, /* blend == 0 */
hinting,
FT_LOAD_TARGET_MODE( load_flags ),
cid_load_glyph );
if ( error )
goto Exit;
/* TODO: initialize decoder.len_buildchar and decoder.buildchar */
/* if we ever support CID-keyed multiple master fonts */
must_finish_decoder = TRUE;
/* set up the decoder */
decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE );
error = cid_load_glyph( &decoder, glyph_index );
if ( error )
goto Exit;
/* copy flags back for forced scaling */
hinting = glyph->hint;
scaled = glyph->scaled;
font_matrix = decoder.font_matrix;
font_offset = decoder.font_offset;
/* save new glyph tables */
psaux->t1_decoder_funcs->done( &decoder );
must_finish_decoder = FALSE;
/* now set the metrics -- this is rather simple, as */
/* the left side bearing is the xMin, and the top side */
/* bearing the yMax */
cidglyph->outline.flags &= FT_OUTLINE_OWNER;
cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL;
/* for composite glyphs, return only left side bearing and */
/* advance width */
if ( load_flags & FT_LOAD_NO_RECURSE )
{
FT_Slot_Internal internal = cidglyph->internal;
cidglyph->metrics.horiBearingX =
FIXED_TO_INT( decoder.builder.left_bearing.x );
cidglyph->metrics.horiAdvance =
FIXED_TO_INT( decoder.builder.advance.x );
internal->glyph_matrix = font_matrix;
internal->glyph_delta = font_offset;
internal->glyph_transformed = 1;
}
else
{
FT_BBox cbox;
FT_Glyph_Metrics* metrics = &cidglyph->metrics;
/* copy the _unscaled_ advance width */
metrics->horiAdvance =
FIXED_TO_INT( decoder.builder.advance.x );
cidglyph->linearHoriAdvance =
FIXED_TO_INT( decoder.builder.advance.x );
cidglyph->internal->glyph_transformed = 0;
/* make up vertical ones */
metrics->vertAdvance = ( face->cid.font_bbox.yMax -
face->cid.font_bbox.yMin ) >> 16;
cidglyph->linearVertAdvance = metrics->vertAdvance;
cidglyph->format = FT_GLYPH_FORMAT_OUTLINE;
if ( cidsize->metrics.y_ppem < 24 )
cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
/* apply the font matrix, if any */
if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
font_matrix.xy != 0 || font_matrix.yx != 0 )
{
FT_Outline_Transform( &cidglyph->outline, &font_matrix );
metrics->horiAdvance = FT_MulFix( metrics->horiAdvance,
font_matrix.xx );
metrics->vertAdvance = FT_MulFix( metrics->vertAdvance,
font_matrix.yy );
}
if ( font_offset.x || font_offset.y )
{
FT_Outline_Translate( &cidglyph->outline,
font_offset.x,
font_offset.y );
metrics->horiAdvance += font_offset.x;
metrics->vertAdvance += font_offset.y;
}
if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || scaled )
{
/* scale the outline and the metrics */
FT_Int n;
FT_Outline* cur = decoder.builder.base;
FT_Vector* vec = cur->points;
FT_Fixed x_scale = glyph->x_scale;
FT_Fixed y_scale = glyph->y_scale;
/* First of all, scale the points */
if ( !hinting || !decoder.builder.hints_funcs )
for ( n = cur->n_points; n > 0; n--, vec++ )
{
vec->x = FT_MulFix( vec->x, x_scale );
vec->y = FT_MulFix( vec->y, y_scale );
}
/* Then scale the metrics */
metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
}
/* compute the other metrics */
FT_Outline_Get_CBox( &cidglyph->outline, &cbox );
metrics->width = cbox.xMax - cbox.xMin;
metrics->height = cbox.yMax - cbox.yMin;
metrics->horiBearingX = cbox.xMin;
metrics->horiBearingY = cbox.yMax;
if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
{
/* make up vertical ones */
ft_synthesize_vertical_metrics( metrics,
metrics->vertAdvance );
}
}
Exit:
if ( must_finish_decoder )
psaux->t1_decoder_funcs->done( &decoder );
return error;
}
/* END */

View file

@ -0,0 +1,58 @@
/****************************************************************************
*
* cidgload.h
*
* OpenType Glyph Loader (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CIDGLOAD_H_
#define CIDGLOAD_H_
#include "cidobjs.h"
FT_BEGIN_HEADER
#if 0
/* Compute the maximum advance width of a font through quick parsing */
FT_LOCAL( FT_Error )
cid_face_compute_max_advance( CID_Face face,
FT_Int* max_advance );
#endif /* 0 */
FT_LOCAL( FT_Error )
cid_slot_load_glyph( FT_GlyphSlot glyph, /* CID_Glyph_Slot */
FT_Size size, /* CID_Size */
FT_UInt glyph_index,
FT_Int32 load_flags );
FT_LOCAL( FT_Error )
cid_compute_fd_and_offsets( CID_Face face,
FT_UInt glyph_index,
FT_ULong* fd_select_p,
FT_ULong* off1_p,
FT_ULong* off2_p );
FT_END_HEADER
#endif /* CIDGLOAD_H_ */
/* END */

View file

@ -0,0 +1,950 @@
/****************************************************************************
*
* cidload.c
*
* CID-keyed Type1 font loader (body).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <ft2build.h>
#include <freetype/internal/ftdebug.h>
#include FT_CONFIG_CONFIG_H
#include <freetype/ftmm.h>
#include <freetype/internal/t1types.h>
#include <freetype/internal/psaux.h>
#include "cidload.h"
#include "ciderrs.h"
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT cidload
/* read a single offset */
FT_LOCAL_DEF( FT_ULong )
cid_get_offset( FT_Byte* *start,
FT_UInt offsize )
{
FT_ULong result;
FT_Byte* p = *start;
for ( result = 0; offsize > 0; offsize-- )
{
result <<= 8;
result |= *p++;
}
*start = p;
return result;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** TYPE 1 SYMBOL PARSING *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
static FT_Error
cid_load_keyword( CID_Face face,
CID_Loader* loader,
const T1_Field keyword )
{
FT_Error error;
CID_Parser* parser = &loader->parser;
FT_Byte* object;
void* dummy_object;
CID_FaceInfo cid = &face->cid;
/* if the keyword has a dedicated callback, call it */
if ( keyword->type == T1_FIELD_TYPE_CALLBACK )
{
FT_TRACE4(( " %s", keyword->ident ));
keyword->reader( (FT_Face)face, parser );
error = parser->root.error;
goto Exit;
}
/* we must now compute the address of our target object */
switch ( keyword->location )
{
case T1_FIELD_LOCATION_CID_INFO:
object = (FT_Byte*)cid;
break;
case T1_FIELD_LOCATION_FONT_INFO:
object = (FT_Byte*)&cid->font_info;
break;
case T1_FIELD_LOCATION_FONT_EXTRA:
object = (FT_Byte*)&face->font_extra;
break;
case T1_FIELD_LOCATION_BBOX:
object = (FT_Byte*)&cid->font_bbox;
break;
default:
{
CID_FaceDict dict;
if ( parser->num_dict >= cid->num_dicts )
{
FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n",
keyword->ident ));
error = FT_THROW( Syntax_Error );
goto Exit;
}
dict = cid->font_dicts + parser->num_dict;
switch ( keyword->location )
{
case T1_FIELD_LOCATION_PRIVATE:
object = (FT_Byte*)&dict->private_dict;
break;
default:
object = (FT_Byte*)dict;
}
}
}
FT_TRACE4(( " %s", keyword->ident ));
dummy_object = object;
/* now, load the keyword data in the object's field(s) */
if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
keyword->type == T1_FIELD_TYPE_FIXED_ARRAY )
error = cid_parser_load_field_table( &loader->parser, keyword,
&dummy_object );
else
error = cid_parser_load_field( &loader->parser,
keyword, &dummy_object );
FT_TRACE4(( "\n" ));
Exit:
return error;
}
FT_CALLBACK_DEF( void )
cid_parse_font_matrix( FT_Face face, /* CID_Face */
void* parser_ )
{
CID_Face cidface = (CID_Face)face;
CID_Parser* parser = (CID_Parser*)parser_;
CID_FaceDict dict;
FT_Fixed temp[6];
FT_Fixed temp_scale;
if ( parser->num_dict < cidface->cid.num_dicts )
{
FT_Matrix* matrix;
FT_Vector* offset;
FT_Int result;
dict = cidface->cid.font_dicts + parser->num_dict;
matrix = &dict->font_matrix;
offset = &dict->font_offset;
/* input is scaled by 1000 to accommodate default FontMatrix */
result = cid_parser_to_fixed_array( parser, 6, temp, 3 );
if ( result < 6 )
{
FT_ERROR(( "cid_parse_font_matrix: not enough matrix elements\n" ));
goto Exit;
}
FT_TRACE4(( " [%f %f %f %f %f %f]\n",
(double)temp[0] / 65536 / 1000,
(double)temp[1] / 65536 / 1000,
(double)temp[2] / 65536 / 1000,
(double)temp[3] / 65536 / 1000,
(double)temp[4] / 65536 / 1000,
(double)temp[5] / 65536 / 1000 ));
temp_scale = FT_ABS( temp[3] );
if ( temp_scale == 0 )
{
FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" ));
goto Exit;
}
/* atypical case */
if ( temp_scale != 0x10000L )
{
/* set units per EM based on FontMatrix values */
face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
temp[0] = FT_DivFix( temp[0], temp_scale );
temp[1] = FT_DivFix( temp[1], temp_scale );
temp[2] = FT_DivFix( temp[2], temp_scale );
temp[4] = FT_DivFix( temp[4], temp_scale );
temp[5] = FT_DivFix( temp[5], temp_scale );
temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
}
matrix->xx = temp[0];
matrix->yx = temp[1];
matrix->xy = temp[2];
matrix->yy = temp[3];
if ( !FT_Matrix_Check( matrix ) )
{
FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
parser->root.error = FT_THROW( Invalid_File_Format );
goto Exit;
}
/* note that the font offsets are expressed in integer font units */
offset->x = temp[4] >> 16;
offset->y = temp[5] >> 16;
}
Exit:
return;
}
FT_CALLBACK_DEF( void )
parse_fd_array( FT_Face face, /* CID_Face */
void* parser_ )
{
CID_Face cidface = (CID_Face)face;
CID_Parser* parser = (CID_Parser*)parser_;
CID_FaceInfo cid = &cidface->cid;
FT_Memory memory = FT_FACE_MEMORY( face );
FT_Stream stream = parser->stream;
FT_Error error = FT_Err_Ok;
FT_Long num_dicts, max_dicts;
num_dicts = cid_parser_to_int( parser );
if ( num_dicts < 0 || num_dicts > FT_INT_MAX )
{
FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" ));
goto Exit;
}
FT_TRACE4(( " %ld\n", num_dicts ));
/*
* A single entry in the FDArray must (at least) contain the following
* structure elements.
*
* %ADOBeginFontDict 18
* X dict begin 13
* /FontMatrix [X X X X] 22
* /Private X dict begin 22
* end 4
* end 4
* %ADOEndFontDict 16
*
* This needs 18+13+22+22+4+4+16=99 bytes or more. Normally, you also
* need a `dup X' at the very beginning and a `put' at the end, so a
* rough guess using 100 bytes as the minimum is justified.
*/
max_dicts = (FT_Long)( stream->size / 100 );
if ( num_dicts > max_dicts )
{
FT_TRACE0(( "parse_fd_array: adjusting FDArray size"
" (from %ld to %ld)\n",
num_dicts, max_dicts ));
num_dicts = max_dicts;
}
if ( !cid->font_dicts )
{
FT_UInt n;
if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) )
goto Exit;
cid->num_dicts = num_dicts;
/* set some default values (the same as for Type 1 fonts) */
for ( n = 0; n < cid->num_dicts; n++ )
{
CID_FaceDict dict = cid->font_dicts + n;
dict->private_dict.blue_shift = 7;
dict->private_dict.blue_fuzz = 1;
dict->private_dict.lenIV = 4;
dict->private_dict.expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
dict->private_dict.blue_scale = (FT_Fixed)(
0.039625 * 0x10000L * 1000 );
}
}
Exit:
return;
}
/* By mistake, `expansion_factor' appears both in PS_PrivateRec */
/* and CID_FaceDictRec (both are public header files and can't */
/* be thus changed). We simply copy the value. */
FT_CALLBACK_DEF( void )
parse_expansion_factor( FT_Face face, /* CID_Face */
void* parser_ )
{
CID_Face cidface = (CID_Face)face;
CID_Parser* parser = (CID_Parser*)parser_;
CID_FaceDict dict;
if ( parser->num_dict < cidface->cid.num_dicts )
{
dict = cidface->cid.font_dicts + parser->num_dict;
dict->expansion_factor = cid_parser_to_fixed( parser, 0 );
dict->private_dict.expansion_factor = dict->expansion_factor;
FT_TRACE4(( "%ld\n", dict->expansion_factor ));
}
return;
}
/* By mistake, `CID_FaceDictRec' doesn't contain a field for the */
/* `FontName' keyword. FreeType doesn't need it, but it is nice */
/* to catch it for producing better trace output. */
FT_CALLBACK_DEF( void )
parse_font_name( FT_Face face, /* CID_Face */
void* parser_ )
{
#ifdef FT_DEBUG_LEVEL_TRACE
CID_Face cidface = (CID_Face)face;
CID_Parser* parser = (CID_Parser*)parser_;
if ( parser->num_dict < cidface->cid.num_dicts )
{
T1_TokenRec token;
FT_UInt len;
cid_parser_to_token( parser, &token );
len = (FT_UInt)( token.limit - token.start );
if ( len )
FT_TRACE4(( " %.*s\n", len, token.start ));
else
FT_TRACE4(( " <no value>\n" ));
}
#else
FT_UNUSED( face );
FT_UNUSED( parser_ );
#endif
return;
}
static
const T1_FieldRec cid_field_records[] =
{
#include "cidtoken.h"
T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 )
T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix, 0 )
T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 )
T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 )
{ 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
};
static FT_Error
cid_parse_dict( CID_Face face,
CID_Loader* loader,
FT_Byte* base,
FT_ULong size )
{
CID_Parser* parser = &loader->parser;
parser->root.cursor = base;
parser->root.limit = base + size;
parser->root.error = FT_Err_Ok;
{
FT_Byte* cur = base;
FT_Byte* limit = cur + size;
for (;;)
{
FT_Byte* newlimit;
parser->root.cursor = cur;
cid_parser_skip_spaces( parser );
if ( parser->root.cursor >= limit )
newlimit = limit - 1 - 17;
else
newlimit = parser->root.cursor - 17;
/* look for `%ADOBeginFontDict' */
for ( ; cur < newlimit; cur++ )
{
if ( *cur == '%' &&
ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
{
/* if /FDArray was found, then cid->num_dicts is > 0, and */
/* we can start increasing parser->num_dict */
if ( face->cid.num_dicts > 0 )
{
parser->num_dict++;
#ifdef FT_DEBUG_LEVEL_TRACE
FT_TRACE4(( " FontDict %u", parser->num_dict ));
if ( parser->num_dict > face->cid.num_dicts )
FT_TRACE4(( " (ignored)" ));
FT_TRACE4(( "\n" ));
#endif
}
}
}
cur = parser->root.cursor;
/* no error can occur in cid_parser_skip_spaces */
if ( cur >= limit )
break;
cid_parser_skip_PS_token( parser );
if ( parser->root.cursor >= limit || parser->root.error )
break;
/* look for immediates */
if ( *cur == '/' && cur + 2 < limit )
{
FT_UInt len;
cur++;
len = (FT_UInt)( parser->root.cursor - cur );
if ( len > 0 && len < 22 )
{
/* now compare the immediate name to the keyword table */
T1_Field keyword = (T1_Field)cid_field_records;
for (;;)
{
FT_Byte* name;
name = (FT_Byte*)keyword->ident;
if ( !name )
break;
if ( cur[0] == name[0] &&
len == ft_strlen( (const char*)name ) )
{
FT_UInt n;
for ( n = 1; n < len; n++ )
if ( cur[n] != name[n] )
break;
if ( n >= len )
{
/* we found it - run the parsing callback */
parser->root.error = cid_load_keyword( face,
loader,
keyword );
if ( parser->root.error )
return parser->root.error;
break;
}
}
keyword++;
}
}
}
cur = parser->root.cursor;
}
if ( !face->cid.num_dicts )
{
FT_ERROR(( "cid_parse_dict: No font dictionary found\n" ));
return FT_THROW( Invalid_File_Format );
}
}
return parser->root.error;
}
/* read the subrmap and the subrs of each font dict */
static FT_Error
cid_read_subrs( CID_Face face )
{
CID_FaceInfo cid = &face->cid;
FT_Memory memory = face->root.memory;
FT_Stream stream = face->cid_stream;
FT_Error error;
FT_UInt n;
CID_Subrs subr;
FT_UInt max_offsets = 0;
FT_ULong* offsets = NULL;
PSAux_Service psaux = (PSAux_Service)face->psaux;
if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) )
goto Exit;
subr = face->subrs;
for ( n = 0; n < cid->num_dicts; n++, subr++ )
{
CID_FaceDict dict = cid->font_dicts + n;
FT_Int lenIV = dict->private_dict.lenIV;
FT_UInt count, num_subrs = dict->num_subrs;
FT_ULong data_len;
FT_Byte* p;
if ( !num_subrs )
continue;
/* reallocate offsets array if needed */
if ( num_subrs + 1 > max_offsets )
{
FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 );
if ( new_max <= max_offsets )
{
error = FT_THROW( Syntax_Error );
goto Fail;
}
if ( FT_QRENEW_ARRAY( offsets, max_offsets, new_max ) )
goto Fail;
max_offsets = new_max;
}
/* read the subrmap's offsets */
if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) ||
FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) )
goto Fail;
p = (FT_Byte*)stream->cursor;
for ( count = 0; count <= num_subrs; count++ )
offsets[count] = cid_get_offset( &p, dict->sd_bytes );
FT_FRAME_EXIT();
/* offsets must be ordered */
for ( count = 1; count <= num_subrs; count++ )
if ( offsets[count - 1] > offsets[count] )
{
FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" ));
error = FT_THROW( Invalid_File_Format );
goto Fail;
}
if ( offsets[num_subrs] > stream->size - cid->data_offset )
{
FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" ));
error = FT_THROW( Invalid_File_Format );
goto Fail;
}
/* now, compute the size of subrs charstrings, */
/* allocate, and read them */
data_len = offsets[num_subrs] - offsets[0];
if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) ||
FT_QALLOC( subr->code[0], data_len ) )
goto Fail;
if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) ||
FT_STREAM_READ( subr->code[0], data_len ) )
goto Fail;
/* set up pointers */
for ( count = 1; count <= num_subrs; count++ )
{
FT_ULong len;
len = offsets[count] - offsets[count - 1];
subr->code[count] = subr->code[count - 1] + len;
}
/* decrypt subroutines, but only if lenIV >= 0 */
if ( lenIV >= 0 )
{
for ( count = 0; count < num_subrs; count++ )
{
FT_ULong len;
len = offsets[count + 1] - offsets[count];
psaux->t1_decrypt( subr->code[count], len, 4330 );
}
}
subr->num_subrs = (FT_Int)num_subrs;
}
Exit:
FT_FREE( offsets );
return error;
Fail:
if ( face->subrs )
{
for ( n = 0; n < cid->num_dicts; n++ )
{
if ( face->subrs[n].code )
FT_FREE( face->subrs[n].code[0] );
FT_FREE( face->subrs[n].code );
}
FT_FREE( face->subrs );
}
goto Exit;
}
static void
cid_init_loader( CID_Loader* loader,
CID_Face face )
{
FT_UNUSED( face );
FT_ZERO( loader );
}
static void
cid_done_loader( CID_Loader* loader )
{
CID_Parser* parser = &loader->parser;
/* finalize parser */
cid_parser_done( parser );
}
static FT_Error
cid_hex_to_binary( FT_Byte* data,
FT_ULong data_len,
FT_ULong offset,
CID_Face face,
FT_ULong* data_written )
{
FT_Stream stream = face->root.stream;
FT_Error error;
FT_Byte buffer[256];
FT_Byte *p, *plimit;
FT_Byte *d = data, *dlimit;
FT_Byte val;
FT_Bool upper_nibble, done;
if ( FT_STREAM_SEEK( offset ) )
goto Exit;
dlimit = d + data_len;
p = buffer;
plimit = p;
upper_nibble = 1;
done = 0;
while ( d < dlimit )
{
if ( p >= plimit )
{
FT_ULong oldpos = FT_STREAM_POS();
FT_ULong size = stream->size - oldpos;
if ( size == 0 )
{
error = FT_THROW( Syntax_Error );
goto Exit;
}
if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) )
goto Exit;
p = buffer;
plimit = p + FT_STREAM_POS() - oldpos;
}
if ( ft_isdigit( *p ) )
val = (FT_Byte)( *p - '0' );
else if ( *p >= 'a' && *p <= 'f' )
val = (FT_Byte)( *p - 'a' + 10 );
else if ( *p >= 'A' && *p <= 'F' )
val = (FT_Byte)( *p - 'A' + 10 );
else if ( *p == ' ' ||
*p == '\t' ||
*p == '\r' ||
*p == '\n' ||
*p == '\f' ||
*p == '\0' )
{
p++;
continue;
}
else if ( *p == '>' )
{
val = 0;
done = 1;
}
else
{
error = FT_THROW( Syntax_Error );
goto Exit;
}
if ( upper_nibble )
*d = (FT_Byte)( val << 4 );
else
{
*d = (FT_Byte)( *d + val );
d++;
}
upper_nibble = (FT_Byte)( 1 - upper_nibble );
if ( done )
break;
p++;
}
error = FT_Err_Ok;
Exit:
*data_written = (FT_ULong)( d - data );
return error;
}
FT_LOCAL_DEF( FT_Error )
cid_face_open( CID_Face face,
FT_Int face_index )
{
CID_Loader loader;
CID_Parser* parser;
FT_Memory memory = face->root.memory;
FT_Error error;
FT_UInt n;
CID_FaceInfo cid = &face->cid;
FT_ULong binary_length;
cid_init_loader( &loader, face );
parser = &loader.parser;
error = cid_parser_new( parser, face->root.stream, face->root.memory,
(PSAux_Service)face->psaux );
if ( error )
goto Exit;
error = cid_parse_dict( face, &loader,
parser->postscript,
parser->postscript_len );
if ( error )
goto Exit;
if ( face_index < 0 )
goto Exit;
if ( FT_NEW( face->cid_stream ) )
goto Exit;
if ( parser->binary_length )
{
if ( parser->binary_length >
face->root.stream->size - parser->data_offset )
{
FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" ));
FT_TRACE0(( " (from %lu to %lu bytes)\n",
parser->binary_length,
face->root.stream->size - parser->data_offset ));
parser->binary_length = face->root.stream->size -
parser->data_offset;
}
/* we must convert the data section from hexadecimal to binary */
if ( FT_QALLOC( face->binary_data, parser->binary_length ) ||
FT_SET_ERROR( cid_hex_to_binary( face->binary_data,
parser->binary_length,
parser->data_offset,
face,
&binary_length ) ) )
goto Exit;
FT_Stream_OpenMemory( face->cid_stream,
face->binary_data, binary_length );
cid->data_offset = 0;
}
else
{
*face->cid_stream = *face->root.stream;
cid->data_offset = loader.parser.data_offset;
}
/* sanity tests */
if ( cid->gd_bytes == 0 )
{
FT_ERROR(( "cid_face_open:"
" Invalid `GDBytes' value\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
/* allow at most 32bit offsets */
if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 )
{
FT_ERROR(( "cid_face_open:"
" Values of `FDBytes' or `GDBytes' larger than 4\n" ));
FT_ERROR(( " "
" are not supported\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
binary_length = face->cid_stream->size - cid->data_offset;
if ( cid->cidmap_offset > binary_length )
{
FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
/* the initial pre-check prevents the multiplication overflow */
if ( cid->cid_count > FT_ULONG_MAX / 8 ||
cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) >
binary_length - cid->cidmap_offset )
{
FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
for ( n = 0; n < cid->num_dicts; n++ )
{
CID_FaceDict dict = cid->font_dicts + n;
/* the upper limits are ad-hoc values */
if ( dict->private_dict.blue_shift > 1000 ||
dict->private_dict.blue_shift < 0 )
{
FT_TRACE2(( "cid_face_open:"
" setting unlikely BlueShift value %d to default (7)\n",
dict->private_dict.blue_shift ));
dict->private_dict.blue_shift = 7;
}
if ( dict->private_dict.blue_fuzz > 1000 ||
dict->private_dict.blue_fuzz < 0 )
{
FT_TRACE2(( "cid_face_open:"
" setting unlikely BlueFuzz value %d to default (1)\n",
dict->private_dict.blue_fuzz ));
dict->private_dict.blue_fuzz = 1;
}
if ( dict->num_subrs && dict->sd_bytes == 0 )
{
FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
if ( dict->sd_bytes > 4 )
{
FT_ERROR(( "cid_face_open:"
" Values of `SDBytes' larger than 4"
" are not supported\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
if ( dict->subrmap_offset > binary_length )
{
FT_ERROR(( "cid_face_open: Invalid `SubrMapOffset' value\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
/* the initial pre-check prevents the multiplication overflow */
if ( dict->num_subrs > FT_UINT_MAX / 4 ||
dict->num_subrs * dict->sd_bytes >
binary_length - dict->subrmap_offset )
{
FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
}
/* we can now safely proceed */
error = cid_read_subrs( face );
Exit:
cid_done_loader( &loader );
return error;
}
/* END */

View file

@ -0,0 +1,52 @@
/****************************************************************************
*
* cidload.h
*
* CID-keyed Type1 font loader (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CIDLOAD_H_
#define CIDLOAD_H_
#include <freetype/internal/ftstream.h>
#include "cidparse.h"
FT_BEGIN_HEADER
typedef struct CID_Loader_
{
CID_Parser parser; /* parser used to read the stream */
FT_Int num_chars; /* number of characters in encoding */
} CID_Loader;
FT_LOCAL( FT_ULong )
cid_get_offset( FT_Byte** start,
FT_UInt offsize );
FT_LOCAL( FT_Error )
cid_face_open( CID_Face face,
FT_Int face_index );
FT_END_HEADER
#endif /* CIDLOAD_H_ */
/* END */

View file

@ -0,0 +1,543 @@
/****************************************************************************
*
* cidobjs.c
*
* CID objects manager (body).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftstream.h>
#include "cidgload.h"
#include "cidload.h"
#include <freetype/internal/services/svpscmap.h>
#include <freetype/internal/psaux.h>
#include <freetype/internal/pshints.h>
#include <freetype/ftdriver.h>
#include "ciderrs.h"
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT cidobjs
/**************************************************************************
*
* SLOT FUNCTIONS
*
*/
FT_LOCAL_DEF( void )
cid_slot_done( FT_GlyphSlot slot )
{
if ( slot->internal )
slot->internal->glyph_hints = NULL;
}
FT_LOCAL_DEF( FT_Error )
cid_slot_init( FT_GlyphSlot slot )
{
CID_Face face;
PSHinter_Service pshinter;
face = (CID_Face)slot->face;
pshinter = (PSHinter_Service)face->pshinter;
if ( pshinter )
{
FT_Module module;
module = FT_Get_Module( slot->library, "pshinter" );
if ( module )
{
T1_Hints_Funcs funcs;
funcs = pshinter->get_t1_funcs( module );
slot->internal->glyph_hints = (void*)funcs;
}
}
return 0;
}
/**************************************************************************
*
* SIZE FUNCTIONS
*
*/
static PSH_Globals_Funcs
cid_size_get_globals_funcs( CID_Size size )
{
CID_Face face = (CID_Face)size->root.face;
PSHinter_Service pshinter = (PSHinter_Service)face->pshinter;
FT_Module module;
module = FT_Get_Module( size->root.face->driver->root.library,
"pshinter" );
return ( module && pshinter && pshinter->get_globals_funcs )
? pshinter->get_globals_funcs( module )
: 0;
}
FT_LOCAL_DEF( void )
cid_size_done( FT_Size cidsize ) /* CID_Size */
{
CID_Size size = (CID_Size)cidsize;
if ( cidsize->internal->module_data )
{
PSH_Globals_Funcs funcs;
funcs = cid_size_get_globals_funcs( size );
if ( funcs )
funcs->destroy( (PSH_Globals)cidsize->internal->module_data );
cidsize->internal->module_data = NULL;
}
}
FT_LOCAL_DEF( FT_Error )
cid_size_init( FT_Size cidsize ) /* CID_Size */
{
CID_Size size = (CID_Size)cidsize;
FT_Error error = FT_Err_Ok;
PSH_Globals_Funcs funcs = cid_size_get_globals_funcs( size );
if ( funcs )
{
PSH_Globals globals;
CID_Face face = (CID_Face)cidsize->face;
CID_FaceDict dict = face->cid.font_dicts + face->root.face_index;
PS_Private priv = &dict->private_dict;
error = funcs->create( cidsize->face->memory, priv, &globals );
if ( !error )
cidsize->internal->module_data = globals;
}
return error;
}
FT_LOCAL_DEF( FT_Error )
cid_size_request( FT_Size size,
FT_Size_Request req )
{
FT_Error error;
PSH_Globals_Funcs funcs;
error = FT_Request_Metrics( size->face, req );
if ( error )
goto Exit;
funcs = cid_size_get_globals_funcs( (CID_Size)size );
if ( funcs )
funcs->set_scale( (PSH_Globals)size->internal->module_data,
size->metrics.x_scale,
size->metrics.y_scale,
0, 0 );
Exit:
return error;
}
/**************************************************************************
*
* FACE FUNCTIONS
*
*/
/**************************************************************************
*
* @Function:
* cid_face_done
*
* @Description:
* Finalizes a given face object.
*
* @Input:
* face ::
* A pointer to the face object to destroy.
*/
FT_LOCAL_DEF( void )
cid_face_done( FT_Face cidface ) /* CID_Face */
{
CID_Face face = (CID_Face)cidface;
FT_Memory memory;
CID_FaceInfo cid;
PS_FontInfo info;
if ( !face )
return;
cid = &face->cid;
info = &cid->font_info;
memory = cidface->memory;
/* release subrs */
if ( face->subrs )
{
FT_UInt n;
for ( n = 0; n < cid->num_dicts; n++ )
{
CID_Subrs subr = face->subrs + n;
if ( subr->code )
{
FT_FREE( subr->code[0] );
FT_FREE( subr->code );
}
}
FT_FREE( face->subrs );
}
/* release FontInfo strings */
FT_FREE( info->version );
FT_FREE( info->notice );
FT_FREE( info->full_name );
FT_FREE( info->family_name );
FT_FREE( info->weight );
/* release font dictionaries */
FT_FREE( cid->font_dicts );
cid->num_dicts = 0;
/* release other strings */
FT_FREE( cid->cid_font_name );
FT_FREE( cid->registry );
FT_FREE( cid->ordering );
cidface->family_name = NULL;
cidface->style_name = NULL;
FT_FREE( face->binary_data );
FT_FREE( face->cid_stream );
}
/**************************************************************************
*
* @Function:
* cid_face_init
*
* @Description:
* Initializes a given CID face object.
*
* @Input:
* stream ::
* Dummy argument for compatibility with the `FT_Face_InitFunc` API.
* Ignored. The stream should be passed through `face->root.stream`.
*
* face_index ::
* The index of the font face in the resource.
*
* num_params ::
* Number of additional generic parameters. Ignored.
*
* params ::
* Additional generic parameters. Ignored.
*
* @InOut:
* face ::
* The newly built face object.
*
* @Return:
* FreeType error code. 0 means success.
*/
FT_LOCAL_DEF( FT_Error )
cid_face_init( FT_Stream stream,
FT_Face cidface, /* CID_Face */
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params )
{
CID_Face face = (CID_Face)cidface;
FT_Error error;
PSAux_Service psaux;
PSHinter_Service pshinter;
FT_UNUSED( num_params );
FT_UNUSED( params );
FT_UNUSED( stream );
cidface->num_faces = 1;
psaux = (PSAux_Service)face->psaux;
if ( !psaux )
{
psaux = (PSAux_Service)FT_Get_Module_Interface(
FT_FACE_LIBRARY( face ), "psaux" );
if ( !psaux )
{
FT_ERROR(( "cid_face_init: cannot access `psaux' module\n" ));
error = FT_THROW( Missing_Module );
goto Exit;
}
face->psaux = psaux;
}
pshinter = (PSHinter_Service)face->pshinter;
if ( !pshinter )
{
pshinter = (PSHinter_Service)FT_Get_Module_Interface(
FT_FACE_LIBRARY( face ), "pshinter" );
face->pshinter = pshinter;
}
FT_TRACE2(( "CID driver\n" ));
/* open the tokenizer; this will also check the font format */
if ( FT_STREAM_SEEK( 0 ) )
goto Exit;
error = cid_face_open( face, face_index );
if ( error )
goto Exit;
/* if we just wanted to check the format, leave successfully now */
if ( face_index < 0 )
goto Exit;
/* check the face index */
/* XXX: handle CID fonts with more than a single face */
if ( ( face_index & 0xFFFF ) != 0 )
{
FT_ERROR(( "cid_face_init: invalid face index\n" ));
error = FT_THROW( Invalid_Argument );
goto Exit;
}
/* now load the font program into the face object */
/* initialize the face object fields */
/* set up root face fields */
{
CID_FaceInfo cid = &face->cid;
PS_FontInfo info = &cid->font_info;
cidface->num_glyphs = (FT_Long)cid->cid_count;
cidface->num_charmaps = 0;
cidface->face_index = face_index & 0xFFFF;
cidface->face_flags |= FT_FACE_FLAG_SCALABLE | /* scalable outlines */
FT_FACE_FLAG_HORIZONTAL | /* horizontal data */
FT_FACE_FLAG_HINTER; /* has native hinter */
if ( info->is_fixed_pitch )
cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
/*
* For the sfnt-wrapped CID fonts for MacOS, currently,
* its `cmap' tables are ignored, and the content in
* its `CID ' table is treated the same as naked CID-keyed
* font. See ft_lookup_PS_in_sfnt_stream().
*/
cidface->face_flags |= FT_FACE_FLAG_CID_KEYED;
/* XXX: TODO: add kerning with .afm support */
/* get style name -- be careful, some broken fonts only */
/* have a /FontName dictionary entry! */
cidface->family_name = info->family_name;
/* assume "Regular" style if we don't know better */
cidface->style_name = (char *)"Regular";
if ( cidface->family_name )
{
char* full = info->full_name;
char* family = cidface->family_name;
if ( full )
{
while ( *full )
{
if ( *full == *family )
{
family++;
full++;
}
else
{
if ( *full == ' ' || *full == '-' )
full++;
else if ( *family == ' ' || *family == '-' )
family++;
else
{
if ( !*family )
cidface->style_name = full;
break;
}
}
}
}
}
else
{
/* do we have a `/FontName'? */
if ( cid->cid_font_name )
cidface->family_name = cid->cid_font_name;
}
/* compute style flags */
cidface->style_flags = 0;
if ( info->italic_angle )
cidface->style_flags |= FT_STYLE_FLAG_ITALIC;
if ( info->weight )
{
if ( !ft_strcmp( info->weight, "Bold" ) ||
!ft_strcmp( info->weight, "Black" ) )
cidface->style_flags |= FT_STYLE_FLAG_BOLD;
}
/* no embedded bitmap support */
cidface->num_fixed_sizes = 0;
cidface->available_sizes = NULL;
cidface->bbox.xMin = cid->font_bbox.xMin >> 16;
cidface->bbox.yMin = cid->font_bbox.yMin >> 16;
/* no `U' suffix here to 0xFFFF! */
cidface->bbox.xMax = ( cid->font_bbox.xMax + 0xFFFF ) >> 16;
cidface->bbox.yMax = ( cid->font_bbox.yMax + 0xFFFF ) >> 16;
if ( !cidface->units_per_EM )
cidface->units_per_EM = 1000;
cidface->ascender = (FT_Short)( cidface->bbox.yMax );
cidface->descender = (FT_Short)( cidface->bbox.yMin );
cidface->height = (FT_Short)( ( cidface->units_per_EM * 12 ) / 10 );
if ( cidface->height < cidface->ascender - cidface->descender )
cidface->height = (FT_Short)( cidface->ascender - cidface->descender );
cidface->underline_position = (FT_Short)info->underline_position;
cidface->underline_thickness = (FT_Short)info->underline_thickness;
}
Exit:
return error;
}
/**************************************************************************
*
* @Function:
* cid_driver_init
*
* @Description:
* Initializes a given CID driver object.
*
* @Input:
* driver ::
* A handle to the target driver object.
*
* @Return:
* FreeType error code. 0 means success.
*/
FT_LOCAL_DEF( FT_Error )
cid_driver_init( FT_Module module )
{
PS_Driver driver = (PS_Driver)module;
FT_UInt32 seed;
/* set default property values, cf. `ftt1drv.h' */
driver->hinting_engine = FT_HINTING_ADOBE;
driver->no_stem_darkening = TRUE;
driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2;
driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2;
driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3;
driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3;
driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
/* compute random seed from some memory addresses */
seed = (FT_UInt32)( (FT_Offset)(char*)&seed ^
(FT_Offset)(char*)&module ^
(FT_Offset)(char*)module->memory );
seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 );
driver->random_seed = (FT_Int32)seed;
if ( driver->random_seed < 0 )
driver->random_seed = -driver->random_seed;
else if ( driver->random_seed == 0 )
driver->random_seed = 123456789;
return FT_Err_Ok;
}
/**************************************************************************
*
* @Function:
* cid_driver_done
*
* @Description:
* Finalizes a given CID driver.
*
* @Input:
* driver ::
* A handle to the target CID driver.
*/
FT_LOCAL_DEF( void )
cid_driver_done( FT_Module driver )
{
FT_UNUSED( driver );
}
/* END */

View file

@ -0,0 +1,154 @@
/****************************************************************************
*
* cidobjs.h
*
* CID objects manager (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CIDOBJS_H_
#define CIDOBJS_H_
#include <ft2build.h>
#include <freetype/internal/ftobjs.h>
#include FT_CONFIG_CONFIG_H
#include <freetype/internal/t1types.h>
FT_BEGIN_HEADER
/* The following structures must be defined by the hinter */
typedef struct CID_Size_Hints_ CID_Size_Hints;
typedef struct CID_Glyph_Hints_ CID_Glyph_Hints;
/**************************************************************************
*
* @Type:
* CID_Driver
*
* @Description:
* A handle to a Type 1 driver object.
*/
typedef struct CID_DriverRec_* CID_Driver;
/**************************************************************************
*
* @Type:
* CID_Size
*
* @Description:
* A handle to a Type 1 size object.
*/
typedef struct CID_SizeRec_* CID_Size;
/**************************************************************************
*
* @Type:
* CID_GlyphSlot
*
* @Description:
* A handle to a Type 1 glyph slot object.
*/
typedef struct CID_GlyphSlotRec_* CID_GlyphSlot;
/**************************************************************************
*
* @Type:
* CID_CharMap
*
* @Description:
* A handle to a Type 1 character mapping object.
*
* @Note:
* The Type 1 format doesn't use a charmap but an encoding table.
* The driver is responsible for making up charmap objects
* corresponding to these tables.
*/
typedef struct CID_CharMapRec_* CID_CharMap;
/**************************************************************************
*
* HERE BEGINS THE TYPE 1 SPECIFIC STUFF
*
*/
typedef struct CID_SizeRec_
{
FT_SizeRec root;
FT_Bool valid;
} CID_SizeRec;
typedef struct CID_GlyphSlotRec_
{
FT_GlyphSlotRec root;
FT_Bool hint;
FT_Bool scaled;
FT_Fixed x_scale;
FT_Fixed y_scale;
} CID_GlyphSlotRec;
FT_LOCAL( void )
cid_slot_done( FT_GlyphSlot slot );
FT_LOCAL( FT_Error )
cid_slot_init( FT_GlyphSlot slot );
FT_LOCAL( void )
cid_size_done( FT_Size size ); /* CID_Size */
FT_LOCAL( FT_Error )
cid_size_init( FT_Size size ); /* CID_Size */
FT_LOCAL( FT_Error )
cid_size_request( FT_Size size, /* CID_Size */
FT_Size_Request req );
FT_LOCAL( FT_Error )
cid_face_init( FT_Stream stream,
FT_Face face, /* CID_Face */
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params );
FT_LOCAL( void )
cid_face_done( FT_Face face ); /* CID_Face */
FT_LOCAL( FT_Error )
cid_driver_init( FT_Module driver );
FT_LOCAL( void )
cid_driver_done( FT_Module driver );
FT_END_HEADER
#endif /* CIDOBJS_H_ */
/* END */

View file

@ -0,0 +1,286 @@
/****************************************************************************
*
* cidparse.c
*
* CID-keyed Type1 parser (body).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftstream.h>
#include "cidparse.h"
#include "ciderrs.h"
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT cidparse
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** INPUT STREAM PARSER *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#define STARTDATA "StartData"
#define STARTDATA_LEN ( sizeof ( STARTDATA ) - 1 )
#define SFNTS "/sfnts"
#define SFNTS_LEN ( sizeof ( SFNTS ) - 1 )
FT_LOCAL_DEF( FT_Error )
cid_parser_new( CID_Parser* parser,
FT_Stream stream,
FT_Memory memory,
PSAux_Service psaux )
{
FT_Error error;
FT_ULong base_offset, offset, ps_len;
FT_Byte *cur, *limit;
FT_Byte *arg1, *arg2;
FT_ZERO( parser );
psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
parser->stream = stream;
base_offset = FT_STREAM_POS();
/* first of all, check the font format in the header */
if ( FT_FRAME_ENTER( 31 ) )
{
FT_TRACE2(( " not a CID-keyed font\n" ));
error = FT_THROW( Unknown_File_Format );
goto Exit;
}
if ( ft_strncmp( (char *)stream->cursor,
"%!PS-Adobe-3.0 Resource-CIDFont", 31 ) )
{
FT_TRACE2(( " not a CID-keyed font\n" ));
error = FT_THROW( Unknown_File_Format );
}
FT_FRAME_EXIT();
if ( error )
goto Exit;
Again:
/* now, read the rest of the file until we find */
/* `StartData' or `/sfnts' */
{
/*
* The algorithm is as follows (omitting the case with less than 256
* bytes to fill for simplicity).
*
* 1. Fill the buffer with 256 + STARTDATA_LEN bytes.
*
* 2. Search for the STARTDATA and SFNTS strings at positions
* buffer[0], buffer[1], ...,
* buffer[255 + STARTDATA_LEN - SFNTS_LEN].
*
* 3. Move the last STARTDATA_LEN bytes to buffer[0].
*
* 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN.
*
* 5. Repeat with step 2.
*
*/
FT_Byte buffer[256 + STARTDATA_LEN + 1];
/* values for the first loop */
FT_ULong read_len = 256 + STARTDATA_LEN;
FT_ULong read_offset = 0;
FT_Byte* p = buffer;
for ( offset = FT_STREAM_POS(); ; offset += 256 )
{
FT_ULong stream_len;
stream_len = stream->size - FT_STREAM_POS();
read_len = FT_MIN( read_len, stream_len );
if ( FT_STREAM_READ( p, read_len ) )
goto Exit;
/* ensure that we do not compare with data beyond the buffer */
p[read_len] = '\0';
limit = p + read_len - SFNTS_LEN;
for ( p = buffer; p < limit; p++ )
{
if ( p[0] == 'S' &&
ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 )
{
/* save offset of binary data after `StartData' */
offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
goto Found;
}
else if ( p[1] == 's' &&
ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 )
{
offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
goto Found;
}
}
if ( read_offset + read_len < STARTDATA_LEN )
{
FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" ));
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
FT_MEM_MOVE( buffer,
buffer + read_offset + read_len - STARTDATA_LEN,
STARTDATA_LEN );
/* values for the next loop */
read_len = 256;
read_offset = STARTDATA_LEN;
p = buffer + read_offset;
}
}
Found:
/* We have found the start of the binary data or the `/sfnts' token. */
/* Now rewind and extract the frame corresponding to this PostScript */
/* section. */
ps_len = offset - base_offset;
if ( FT_STREAM_SEEK( base_offset ) ||
FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
goto Exit;
parser->data_offset = offset;
parser->postscript_len = ps_len;
parser->root.base = parser->postscript;
parser->root.cursor = parser->postscript;
parser->root.limit = parser->root.cursor + ps_len;
parser->num_dict = FT_UINT_MAX;
/* Finally, we check whether `StartData' or `/sfnts' was real -- */
/* it could be in a comment or string. We also get the arguments */
/* of `StartData' to find out whether the data is represented in */
/* binary or hex format. */
arg1 = parser->root.cursor;
cid_parser_skip_PS_token( parser );
cid_parser_skip_spaces ( parser );
arg2 = parser->root.cursor;
cid_parser_skip_PS_token( parser );
cid_parser_skip_spaces ( parser );
limit = parser->root.limit;
cur = parser->root.cursor;
while ( cur <= limit - SFNTS_LEN )
{
if ( parser->root.error )
{
error = parser->root.error;
goto Exit;
}
if ( cur[0] == 'S' &&
cur <= limit - STARTDATA_LEN &&
ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 )
{
T1_TokenRec type_token;
FT_Long binary_length;
parser->root.cursor = arg1;
cid_parser_to_token( parser, &type_token );
if ( type_token.limit - type_token.start == 5 &&
ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 )
{
parser->root.cursor = arg2;
binary_length = cid_parser_to_int( parser );
if ( binary_length < 0 )
{
FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
error = FT_THROW( Invalid_File_Format );
}
else
parser->binary_length = (FT_ULong)binary_length;
}
goto Exit;
}
else if ( cur[1] == 's' &&
ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 )
{
FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" ));
error = FT_THROW( Unknown_File_Format );
goto Exit;
}
cid_parser_skip_PS_token( parser );
cid_parser_skip_spaces ( parser );
arg1 = arg2;
arg2 = cur;
cur = parser->root.cursor;
}
/* we haven't found the correct `StartData'; go back and continue */
/* searching */
FT_FRAME_RELEASE( parser->postscript );
if ( !FT_STREAM_SEEK( offset ) )
goto Again;
Exit:
return error;
}
#undef STARTDATA
#undef STARTDATA_LEN
#undef SFNTS
#undef SFNTS_LEN
FT_LOCAL_DEF( void )
cid_parser_done( CID_Parser* parser )
{
/* always free the private dictionary */
if ( parser->postscript )
{
FT_Stream stream = parser->stream;
FT_FRAME_RELEASE( parser->postscript );
}
parser->root.funcs.done( &parser->root );
}
/* END */

View file

@ -0,0 +1,130 @@
/****************************************************************************
*
* cidparse.h
*
* CID-keyed Type1 parser (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CIDPARSE_H_
#define CIDPARSE_H_
#include <freetype/internal/t1types.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/psaux.h>
FT_BEGIN_HEADER
/**************************************************************************
*
* @Struct:
* CID_Parser
*
* @Description:
* A CID_Parser is an object used to parse a Type 1 fonts very
* quickly.
*
* @Fields:
* root ::
* The root PS_ParserRec fields.
*
* stream ::
* The current input stream.
*
* postscript ::
* A pointer to the data to be parsed.
*
* postscript_len ::
* The length of the data to be parsed.
*
* data_offset ::
* The start position of the binary data (i.e., the
* end of the data to be parsed.
*
* binary_length ::
* The length of the data after the `StartData'
* command if the data format is hexadecimal.
*
* cid ::
* A structure which holds the information about
* the current font.
*
* num_dict ::
* The number of font dictionaries.
*/
typedef struct CID_Parser_
{
PS_ParserRec root;
FT_Stream stream;
FT_Byte* postscript;
FT_ULong postscript_len;
FT_ULong data_offset;
FT_ULong binary_length;
CID_FaceInfo cid;
FT_UInt num_dict;
} CID_Parser;
FT_LOCAL( FT_Error )
cid_parser_new( CID_Parser* parser,
FT_Stream stream,
FT_Memory memory,
PSAux_Service psaux );
FT_LOCAL( void )
cid_parser_done( CID_Parser* parser );
/**************************************************************************
*
* PARSING ROUTINES
*
*/
#define cid_parser_skip_spaces( p ) \
(p)->root.funcs.skip_spaces( &(p)->root )
#define cid_parser_skip_PS_token( p ) \
(p)->root.funcs.skip_PS_token( &(p)->root )
#define cid_parser_to_int( p ) (p)->root.funcs.to_int( &(p)->root )
#define cid_parser_to_fixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
#define cid_parser_to_coord_array( p, m, c ) \
(p)->root.funcs.to_coord_array( &(p)->root, m, c )
#define cid_parser_to_fixed_array( p, m, f, t ) \
(p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
#define cid_parser_to_token( p, t ) \
(p)->root.funcs.to_token( &(p)->root, t )
#define cid_parser_to_token_array( p, t, m, c ) \
(p)->root.funcs.to_token_array( &(p)->root, t, m, c )
#define cid_parser_load_field( p, f, o ) \
(p)->root.funcs.load_field( &(p)->root, f, o, 0, 0 )
#define cid_parser_load_field_table( p, f, o ) \
(p)->root.funcs.load_field_table( &(p)->root, f, o, 0, 0 )
FT_END_HEADER
#endif /* CIDPARSE_H_ */
/* END */

View file

@ -0,0 +1,274 @@
/****************************************************************************
*
* cidriver.c
*
* CID driver interface (body).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "cidriver.h"
#include "cidgload.h"
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftpsprop.h>
#include "ciderrs.h"
#include <freetype/internal/services/svpostnm.h>
#include <freetype/internal/services/svfntfmt.h>
#include <freetype/internal/services/svpsinfo.h>
#include <freetype/internal/services/svcid.h>
#include <freetype/internal/services/svprop.h>
#include <freetype/ftdriver.h>
#include <freetype/internal/psaux.h>
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT ciddriver
/*
* POSTSCRIPT NAME SERVICE
*
*/
FT_CALLBACK_DEF( const char* )
cid_get_postscript_name( FT_Face face ) /* CID_Face */
{
CID_Face cidface = (CID_Face)face;
const char* result = cidface->cid.cid_font_name;
if ( result && result[0] == '/' )
result++;
return result;
}
static const FT_Service_PsFontNameRec cid_service_ps_name =
{
(FT_PsName_GetFunc)cid_get_postscript_name /* get_ps_font_name */
};
/*
* POSTSCRIPT INFO SERVICE
*
*/
FT_CALLBACK_DEF( FT_Error )
cid_ps_get_font_info( FT_Face face, /* CID_Face */
PS_FontInfoRec* afont_info )
{
*afont_info = ( (CID_Face)face )->cid.font_info;
return FT_Err_Ok;
}
FT_CALLBACK_DEF( FT_Error )
cid_ps_get_font_extra( FT_Face face, /* CID_Face */
PS_FontExtraRec* afont_extra )
{
*afont_extra = ( (CID_Face)face )->font_extra;
return FT_Err_Ok;
}
static const FT_Service_PsInfoRec cid_service_ps_info =
{
cid_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */
cid_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */
/* unsupported with CID fonts */
NULL, /* PS_HasGlyphNamesFunc ps_has_glyph_names */
/* unsupported */
NULL, /* PS_GetFontPrivateFunc ps_get_font_private */
/* not implemented */
NULL /* PS_GetFontValueFunc ps_get_font_value */
};
/*
* CID INFO SERVICE
*
*/
FT_CALLBACK_DEF( FT_Error )
cid_get_ros( FT_Face face, /* CID_Face */
const char* *registry,
const char* *ordering,
FT_Int *supplement )
{
CID_Face cidface = (CID_Face)face;
CID_FaceInfo cid = &cidface->cid;
if ( registry )
*registry = cid->registry;
if ( ordering )
*ordering = cid->ordering;
if ( supplement )
*supplement = cid->supplement;
return FT_Err_Ok;
}
FT_CALLBACK_DEF( FT_Error )
cid_get_is_cid( FT_Face face, /* CID_Face */
FT_Bool *is_cid )
{
FT_Error error = FT_Err_Ok;
FT_UNUSED( face );
/*
* XXX: If the ROS is Adobe-Identity-H or -V,
* the font has no reliable information about
* its glyph collection. Should we not set
* *is_cid in such cases?
*/
if ( is_cid )
*is_cid = 1;
return error;
}
FT_CALLBACK_DEF( FT_Error )
cid_get_cid_from_glyph_index( FT_Face face, /* CID_Face */
FT_UInt glyph_index,
FT_UInt *cid )
{
FT_Error error = FT_Err_Ok;
CID_Face cidface = (CID_Face)face;
/*
* Currently, FreeType does not support incrementally-defined, CID-keyed
* fonts that store the glyph description data in a `/GlyphDirectory`
* array or dictionary. Fonts loaded by the incremental loading feature
* are thus not handled here.
*/
error = cid_compute_fd_and_offsets( cidface, glyph_index,
NULL, NULL, NULL );
if ( error )
*cid = 0;
else
*cid = glyph_index;
return error;
}
static const FT_Service_CIDRec cid_service_cid_info =
{
cid_get_ros,
/* FT_CID_GetRegistryOrderingSupplementFunc get_ros */
cid_get_is_cid,
/* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */
cid_get_cid_from_glyph_index
/* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */
};
/*
* PROPERTY SERVICE
*
*/
FT_DEFINE_SERVICE_PROPERTIESREC(
cid_service_properties,
ps_property_set, /* FT_Properties_SetFunc set_property */
ps_property_get /* FT_Properties_GetFunc get_property */
)
/*
* SERVICE LIST
*
*/
static const FT_ServiceDescRec cid_services[] =
{
{ FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CID },
{ FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cid_service_ps_name },
{ FT_SERVICE_ID_POSTSCRIPT_INFO, &cid_service_ps_info },
{ FT_SERVICE_ID_CID, &cid_service_cid_info },
{ FT_SERVICE_ID_PROPERTIES, &cid_service_properties },
{ NULL, NULL }
};
FT_CALLBACK_DEF( FT_Module_Interface )
cid_get_interface( FT_Module module,
const char* cid_interface )
{
FT_UNUSED( module );
return ft_service_list_lookup( cid_services, cid_interface );
}
FT_CALLBACK_TABLE_DEF
const FT_Driver_ClassRec t1cid_driver_class =
{
{
FT_MODULE_FONT_DRIVER |
FT_MODULE_DRIVER_SCALABLE |
FT_MODULE_DRIVER_HAS_HINTER,
sizeof ( PS_DriverRec ),
"t1cid", /* module name */
0x10000L, /* version 1.0 of driver */
0x20000L, /* requires FreeType 2.0 */
NULL, /* module-specific interface */
cid_driver_init, /* FT_Module_Constructor module_init */
cid_driver_done, /* FT_Module_Destructor module_done */
cid_get_interface /* FT_Module_Requester get_interface */
},
sizeof ( CID_FaceRec ),
sizeof ( CID_SizeRec ),
sizeof ( CID_GlyphSlotRec ),
cid_face_init, /* FT_Face_InitFunc init_face */
cid_face_done, /* FT_Face_DoneFunc done_face */
cid_size_init, /* FT_Size_InitFunc init_size */
cid_size_done, /* FT_Size_DoneFunc done_size */
cid_slot_init, /* FT_Slot_InitFunc init_slot */
cid_slot_done, /* FT_Slot_DoneFunc done_slot */
cid_slot_load_glyph, /* FT_Slot_LoadFunc load_glyph */
NULL, /* FT_Face_GetKerningFunc get_kerning */
NULL, /* FT_Face_AttachFunc attach_file */
NULL, /* FT_Face_GetAdvancesFunc get_advances */
cid_size_request, /* FT_Size_RequestFunc request_size */
NULL /* FT_Size_SelectFunc select_size */
};
/* END */

View file

@ -0,0 +1,36 @@
/****************************************************************************
*
* cidriver.h
*
* High-level CID driver interface (specification).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef CIDRIVER_H_
#define CIDRIVER_H_
#include <freetype/internal/ftdrv.h>
FT_BEGIN_HEADER
FT_CALLBACK_TABLE
const FT_Driver_ClassRec t1cid_driver_class;
FT_END_HEADER
#endif /* CIDRIVER_H_ */
/* END */

View file

@ -0,0 +1,115 @@
/****************************************************************************
*
* cidtoken.h
*
* CID token definitions (specification only).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#undef FT_STRUCTURE
#define FT_STRUCTURE CID_FaceInfoRec
#undef T1CODE
#define T1CODE T1_FIELD_LOCATION_CID_INFO
T1_FIELD_KEY ( "CIDFontName", cid_font_name, 0 )
T1_FIELD_FIXED ( "CIDFontVersion", cid_version, 0 )
T1_FIELD_NUM ( "CIDFontType", cid_font_type, 0 )
T1_FIELD_STRING ( "Registry", registry, 0 )
T1_FIELD_STRING ( "Ordering", ordering, 0 )
T1_FIELD_NUM ( "Supplement", supplement, 0 )
T1_FIELD_NUM ( "UIDBase", uid_base, 0 )
T1_FIELD_NUM_TABLE( "XUID", xuid, 16, 0 )
T1_FIELD_NUM ( "CIDMapOffset", cidmap_offset, 0 )
T1_FIELD_NUM ( "FDBytes", fd_bytes, 0 )
T1_FIELD_NUM ( "GDBytes", gd_bytes, 0 )
T1_FIELD_NUM ( "CIDCount", cid_count, 0 )
#undef FT_STRUCTURE
#define FT_STRUCTURE PS_FontInfoRec
#undef T1CODE
#define T1CODE T1_FIELD_LOCATION_FONT_INFO
T1_FIELD_STRING( "version", version, 0 )
T1_FIELD_STRING( "Notice", notice, 0 )
T1_FIELD_STRING( "FullName", full_name, 0 )
T1_FIELD_STRING( "FamilyName", family_name, 0 )
T1_FIELD_STRING( "Weight", weight, 0 )
T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 )
T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 )
T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 )
T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 )
#undef FT_STRUCTURE
#define FT_STRUCTURE PS_FontExtraRec
#undef T1CODE
#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA
T1_FIELD_NUM ( "FSType", fs_type, 0 )
#undef FT_STRUCTURE
#define FT_STRUCTURE CID_FaceDictRec
#undef T1CODE
#define T1CODE T1_FIELD_LOCATION_FONT_DICT
T1_FIELD_NUM ( "PaintType", paint_type, 0 )
T1_FIELD_NUM ( "FontType", font_type, 0 )
T1_FIELD_NUM ( "SubrMapOffset", subrmap_offset, 0 )
T1_FIELD_NUM ( "SDBytes", sd_bytes, 0 )
T1_FIELD_NUM ( "SubrCount", num_subrs, 0 )
T1_FIELD_NUM ( "lenBuildCharArray", len_buildchar, 0 )
T1_FIELD_FIXED( "ForceBoldThreshold", forcebold_threshold, 0 )
T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 )
#undef FT_STRUCTURE
#define FT_STRUCTURE PS_PrivateRec
#undef T1CODE
#define T1CODE T1_FIELD_LOCATION_PRIVATE
T1_FIELD_NUM ( "UniqueID", unique_id, 0 )
T1_FIELD_NUM ( "lenIV", lenIV, 0 )
T1_FIELD_NUM ( "LanguageGroup", language_group, 0 )
T1_FIELD_NUM ( "password", password, 0 )
T1_FIELD_FIXED_1000( "BlueScale", blue_scale, 0 )
T1_FIELD_NUM ( "BlueShift", blue_shift, 0 )
T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, 0 )
T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, 0 )
T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, 0 )
T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, 0 )
T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, 0 )
T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, 0 )
T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, 0 )
T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, 0 )
T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, 0 )
T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, 0 )
T1_FIELD_BOOL ( "ForceBold", force_bold, 0 )
#undef FT_STRUCTURE
#define FT_STRUCTURE FT_BBox
#undef T1CODE
#define T1CODE T1_FIELD_LOCATION_BBOX
T1_FIELD_BBOX( "FontBBox", xMin, 0 )
/* END */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,803 @@
// Copyright (c) 2019 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt
#define _XOPEN_SOURCE 600
#define _POSIX_C_SOURCE 200809L
#define _WIN32_WINNT 0x0600
// Needed on windows so that we can use sprintf without warning.
#define _CRT_SECURE_NO_WARNINGS
#include <dlg/output.h>
#include <dlg/dlg.h>
#include <wchar.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* const dlg_reset_sequence = "\033[0m";
const struct dlg_style dlg_default_output_styles[] = {
{dlg_text_style_italic, dlg_color_green, dlg_color_none},
{dlg_text_style_dim, dlg_color_gray, dlg_color_none},
{dlg_text_style_none, dlg_color_cyan, dlg_color_none},
{dlg_text_style_none, dlg_color_yellow, dlg_color_none},
{dlg_text_style_none, dlg_color_red, dlg_color_none},
{dlg_text_style_bold, dlg_color_red, dlg_color_none}
};
static void* xalloc(size_t size) {
void* ret = calloc(size, 1);
if(!ret) fprintf(stderr, "dlg: calloc returned NULL, probably crashing (size: %zu)\n", size);
return ret;
}
static void* xrealloc(void* ptr, size_t size) {
void* ret = realloc(ptr, size);
if(!ret) fprintf(stderr, "dlg: realloc returned NULL, probably crashing (size: %zu)\n", size);
return ret;
}
struct dlg_tag_func_pair {
const char* tag;
const char* func;
};
struct dlg_data {
const char** tags; // vec
struct dlg_tag_func_pair* pairs; // vec
char* buffer;
size_t buffer_size;
};
static dlg_handler g_handler = dlg_default_output;
static void* g_data = NULL;
static void dlg_free_data(void* data);
static struct dlg_data* dlg_create_data(void);
// platform-specific
#if defined(__unix__) || defined(__unix) || defined(__linux__) || defined(__APPLE__) || defined(__MACH__)
#define DLG_OS_UNIX
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
static pthread_key_t dlg_data_key;
static void dlg_main_cleanup(void) {
void* data = pthread_getspecific(dlg_data_key);
if(data) {
dlg_free_data(data);
pthread_setspecific(dlg_data_key, NULL);
}
}
static void init_data_key(void) {
pthread_key_create(&dlg_data_key, dlg_free_data);
atexit(dlg_main_cleanup);
}
static struct dlg_data* dlg_data(void) {
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
pthread_once(&key_once, init_data_key);
void* data = pthread_getspecific(dlg_data_key);
if(!data) {
data = dlg_create_data();
pthread_setspecific(dlg_data_key, data);
}
return (struct dlg_data*) data;
}
static void lock_file(FILE* file) {
flockfile(file);
}
static void unlock_file(FILE* file) {
funlockfile(file);
}
bool dlg_is_tty(FILE* stream) {
return isatty(fileno(stream));
}
static unsigned get_msecs(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_usec;
}
// platform switch -- end unix
#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64)
#define DLG_OS_WIN
#define WIN32_LEAN_AND_MEAN
#define DEFINE_CONSOLEV2_PROPERTIES
#include <windows.h>
#include <io.h>
// thanks for nothing, microsoft
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
// the max buffer size we will convert on the stack
#define DLG_MAX_STACK_BUF_SIZE 1024
static void WINAPI dlg_fls_destructor(void* data) {
dlg_free_data(data);
}
// TODO: error handling
static BOOL CALLBACK dlg_init_fls(PINIT_ONCE io, void* param, void** lpContext) {
(void) io;
(void) param;
**((DWORD**) lpContext) = FlsAlloc(dlg_fls_destructor);
return true;
}
static struct dlg_data* dlg_data(void) {
static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
static DWORD fls = 0;
void* flsp = (void*) &fls;
InitOnceExecuteOnce(&init_once, dlg_init_fls, NULL, &flsp);
void* data = FlsGetValue(fls);
if(!data) {
data = dlg_create_data();
FlsSetValue(fls, data);
}
return (struct dlg_data*) data;
}
static void lock_file(FILE* file) {
_lock_file(file);
}
static void unlock_file(FILE* file) {
_unlock_file(file);
}
bool dlg_is_tty(FILE* stream) {
return _isatty(_fileno(stream));
}
#ifdef DLG_WIN_CONSOLE
static bool init_ansi_console(void) {
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
if(out == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
return false;
DWORD outMode, errMode;
if(!GetConsoleMode(out, &outMode) || !GetConsoleMode(err, &errMode))
return false;
outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
errMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if(!SetConsoleMode(out, outMode) || !SetConsoleMode(out, errMode))
return false;
return true;
}
static bool win_write_heap(void* handle, int needed, const char* format, va_list args) {
char* buf1 = xalloc(3 * needed + 3 + (needed % 2));
wchar_t* buf2 = (wchar_t*) (buf1 + needed + 1 + (needed % 2));
vsnprintf(buf1, needed + 1, format, args);
needed = MultiByteToWideChar(CP_UTF8, 0, buf1, needed, buf2, needed + 1);
bool ret = (needed != 0 && WriteConsoleW(handle, buf2, needed, NULL, NULL) != 0);
free(buf1);
return ret;
}
static bool win_write_stack(void* handle, int needed, const char* format, va_list args) {
char buf1[DLG_MAX_STACK_BUF_SIZE];
wchar_t buf2[DLG_MAX_STACK_BUF_SIZE];
vsnprintf(buf1, needed + 1, format, args);
needed = MultiByteToWideChar(CP_UTF8, 0, buf1, needed, buf2, needed + 1);
return (needed != 0 && WriteConsoleW(handle, buf2, needed, NULL, NULL) != 0);
}
#endif // DLG_WIN_CONSOLE
static unsigned get_msecs() {
SYSTEMTIME st;
GetSystemTime(&st);
return st.wMilliseconds;
}
#else // platform switch -- end windows
#error Cannot determine platform (needed for color and utf-8 and stuff)
#endif
// general
void dlg_escape_sequence(struct dlg_style style, char buf[12]) {
int nums[3];
unsigned int count = 0;
if(style.fg != dlg_color_none) {
nums[count++] = style.fg + 30;
}
if(style.bg != dlg_color_none) {
nums[count++] = style.fg + 40;
}
if(style.style != dlg_text_style_none) {
nums[count++] = style.style;
}
switch(count) {
case 1: snprintf(buf, 12, "\033[%dm", nums[0]); break;
case 2: snprintf(buf, 12, "\033[%d;%dm", nums[0], nums[1]); break;
case 3: snprintf(buf, 12, "\033[%d;%d;%dm", nums[0], nums[1], nums[2]); break;
default: buf[0] = '\0'; break;
}
}
int dlg_vfprintf(FILE* stream, const char* format, va_list args) {
#if defined(DLG_OS_WIN) && defined(DLG_WIN_CONSOLE)
void* handle = NULL;
if(stream == stdout) {
handle = GetStdHandle(STD_OUTPUT_HANDLE);
} else if(stream == stderr) {
handle = GetStdHandle(STD_ERROR_HANDLE);
}
if(handle) {
va_list args_copy;
va_copy(args_copy, args);
int needed = vsnprintf(NULL, 0, format, args_copy);
va_end(args_copy);
if(needed < 0) {
return needed;
}
// We don't allocate too much on the stack
// but we also don't want to call alloc every logging call
// or use another cached buffer
if(needed >= DLG_MAX_STACK_BUF_SIZE) {
if(win_write_heap(handle, needed, format, args)) {
return needed;
}
} else {
if(win_write_stack(handle, needed, format, args)) {
return needed;
}
}
}
#endif
return vfprintf(stream, format, args);
}
int dlg_fprintf(FILE* stream, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = dlg_vfprintf(stream, format, args);
va_end(args);
return ret;
}
int dlg_styled_fprintf(FILE* stream, struct dlg_style style, const char* format, ...) {
char buf[12];
dlg_escape_sequence(style, buf);
fprintf(stream, "%s", buf);
va_list args;
va_start(args, format);
int ret = dlg_vfprintf(stream, format, args);
va_end(args);
fprintf(stream, "%s", dlg_reset_sequence);
return ret;
}
void dlg_generic_output(dlg_generic_output_handler output, void* data,
unsigned int features, const struct dlg_origin* origin, const char* string,
const struct dlg_style styles[6]) {
// We never print any dynamic content below so we can be sure at compile
// time that a buffer of size 64 is large enough.
char format_buf[64];
char* format = format_buf;
if(features & dlg_output_style) {
format += sprintf(format, "%%s");
}
if(features & (dlg_output_time | dlg_output_file_line | dlg_output_tags | dlg_output_func)) {
format += sprintf(format, "[");
}
bool first_meta = true;
if(features & dlg_output_time) {
format += sprintf(format, "%%h");
first_meta = false;
}
if(features & dlg_output_time_msecs) {
if(!first_meta) {
format += sprintf(format, ":");
}
format += sprintf(format, "%%m");
first_meta = false;
}
if(features & dlg_output_file_line) {
if(!first_meta) {
format += sprintf(format, " ");
}
format += sprintf(format, "%%o");
first_meta = false;
}
if(features & dlg_output_func) {
if(!first_meta) {
format += sprintf(format, " ");
}
format += sprintf(format, "%%f");
first_meta = false;
}
if(features & dlg_output_tags) {
if(!first_meta) {
format += sprintf(format, " ");
}
format += sprintf(format, "{%%t}");
first_meta = false;
}
if(features & (dlg_output_time | dlg_output_file_line | dlg_output_tags | dlg_output_func)) {
format += sprintf(format, "] ");
}
format += sprintf(format, "%%c");
if(features & dlg_output_newline) {
format += sprintf(format, "\n");
}
*format = '\0';
dlg_generic_outputf(output, data, format_buf, origin, string, styles);
}
void dlg_generic_outputf(dlg_generic_output_handler output, void* data,
const char* format_string, const struct dlg_origin* origin, const char* string,
const struct dlg_style styles[6]) {
bool reset_style = false;
for(const char* it = format_string; *it; it++) {
if(*it != '%') {
output(data, "%c", *it);
continue;
}
char next = *(it + 1); // must be valid since *it is not '\0'
if(next == 'h') {
time_t t = time(NULL);
struct tm tm_info;
#ifdef DLG_OS_WIN
if(localtime_s(&tm_info, &t)) {
#else
if(!localtime_r(&t, &tm_info)) {
#endif
output(data, "<DATE ERROR>");
} else {
char timebuf[32];
strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm_info);
output(data, "%s", timebuf);
}
it++;
} else if(next == 'm') {
output(data, "%06d", get_msecs());
it++;
} else if(next == 't') {
bool first_tag = true;
for(const char** tags = origin->tags; *tags; ++tags) {
if(!first_tag) {
output(data, ", ");
}
output(data, "%s", *tags);
first_tag = false;
}
++it;
} else if(next == 'f') {
output(data, "%s", origin->func);
++it;
} else if(next == 'o') {
output(data, "%s:%u", origin->file, origin->line);
++it;
} else if(next == 's') {
char buf[12];
dlg_escape_sequence(styles[origin->level], buf);
output(data, "%s", buf);
reset_style = true;
++it;
} else if(next == 'r') {
output(data, "%s", dlg_reset_sequence);
reset_style = false;
++it;
} else if(next == 'c') {
if(origin->expr && string) {
output(data, "assertion '%s' failed: '%s'", origin->expr, string);
} else if(origin->expr) {
output(data, "assertion '%s' failed", origin->expr);
} else if(string) {
output(data, "%s", string);
}
++it;
} else if(next == '%') {
output(data, "%s", "%");
++it;
} else {
// in this case it's a '%' without known format specifier following
output(data, "%s", "%");
}
}
if(reset_style) {
output(data, "%s", dlg_reset_sequence);
}
}
struct buf {
char* buf;
size_t* size;
};
static void print_size(void* size, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vsnprintf(NULL, 0, format, args);
va_end(args);
if(ret > 0) {
*((size_t*) size) += ret;
}
}
static void print_buf(void* dbuf, const char* format, ...) {
struct buf* buf = (struct buf*) dbuf;
va_list args;
va_start(args, format);
int printed = vsnprintf(buf->buf, *buf->size, format, args);
va_end(args);
if(printed > 0) {
*buf->size -= printed;
buf->buf += printed;
}
}
void dlg_generic_output_buf(char* buf, size_t* size, unsigned int features,
const struct dlg_origin* origin, const char* string,
const struct dlg_style styles[6]) {
if(buf) {
struct buf mbuf;
mbuf.buf = buf;
mbuf.size = size;
dlg_generic_output(print_buf, &mbuf, features, origin, string, styles);
} else {
*size = 0;
dlg_generic_output(print_size, size, features, origin, string, styles);
}
}
void dlg_generic_outputf_buf(char* buf, size_t* size, const char* format_string,
const struct dlg_origin* origin, const char* string,
const struct dlg_style styles[6]) {
if(buf) {
struct buf mbuf;
mbuf.buf = buf;
mbuf.size = size;
dlg_generic_outputf(print_buf, &mbuf, format_string, origin, string, styles);
} else {
*size = 0;
dlg_generic_outputf(print_size, size, format_string, origin, string, styles);
}
}
static void print_stream(void* stream, const char* format, ...) {
va_list args;
va_start(args, format);
dlg_vfprintf((FILE*) stream, format, args);
va_end(args);
}
void dlg_generic_output_stream(FILE* stream, unsigned int features,
const struct dlg_origin* origin, const char* string,
const struct dlg_style styles[6]) {
stream = stream ? stream : stdout;
if(features & dlg_output_threadsafe) {
lock_file(stream);
}
dlg_generic_output(print_stream, stream, features, origin, string, styles);
if(features & dlg_output_threadsafe) {
unlock_file(stream);
}
}
void dlg_generic_outputf_stream(FILE* stream, const char* format_string,
const struct dlg_origin* origin, const char* string,
const struct dlg_style styles[6], bool lock_stream) {
stream = stream ? stream : stdout;
if(lock_stream) {
lock_file(stream);
}
dlg_generic_outputf(print_stream, stream, format_string, origin, string, styles);
if(lock_stream) {
unlock_file(stream);
}
}
void dlg_default_output(const struct dlg_origin* origin, const char* string, void* data) {
FILE* stream = data ? (FILE*) data : stdout;
unsigned int features = dlg_output_file_line |
dlg_output_newline |
dlg_output_threadsafe;
#ifdef DLG_DEFAULT_OUTPUT_ALWAYS_COLOR
dlg_win_init_ansi();
features |= dlg_output_style;
#else
if(dlg_is_tty(stream) && dlg_win_init_ansi()) {
features |= dlg_output_style;
}
#endif
dlg_generic_output_stream(stream, features, origin, string, dlg_default_output_styles);
fflush(stream);
}
bool dlg_win_init_ansi(void) {
#if defined(DLG_OS_WIN) && defined(DLG_WIN_CONSOLE)
// TODO: use init once
static volatile LONG status = 0;
LONG res = InterlockedCompareExchange(&status, 1, 0);
if(res == 0) { // not initialized
InterlockedExchange(&status, 3 + init_ansi_console());
}
while(status == 1); // currently initialized in another thread, spinlock
return (status == 4);
#else
return true;
#endif
}
// small dynamic vec/array implementation
// Since the macros vec_init and vec_add[c]/vec_push might
// change the pointers value it must not be referenced somewhere else.
#define vec__raw(vec) (((unsigned int*) vec) - 2)
static void* vec_do_create(unsigned int typesize, unsigned int cap, unsigned int size) {
unsigned long a = (size > cap) ? size : cap;
void* ptr = xalloc(2 * sizeof(unsigned int) + a * typesize);
unsigned int* begin = (unsigned int*) ptr;
begin[0] = size * typesize;
begin[1] = a * typesize;
return begin + 2;
}
// NOTE: can be more efficient if we are allowed to reorder vector
static void vec_do_erase(void* vec, unsigned int pos, unsigned int size) {
unsigned int* begin = vec__raw(vec);
begin[0] -= size;
char* buf = (char*) vec;
memcpy(buf + pos, buf + pos + size, size);
}
static void* vec_do_add(void** vec, unsigned int size) {
unsigned int* begin = vec__raw(*vec);
unsigned int needed = begin[0] + size;
if(needed >= begin[1]) {
void* ptr = xrealloc(begin, sizeof(unsigned int) * 2 + needed * 2);
begin = (unsigned int*) ptr;
begin[1] = needed * 2;
(*vec) = begin + 2;
}
void* ptr = ((char*) (*vec)) + begin[0];
begin[0] += size;
return ptr;
}
#define vec_create(type, size) (type*) vec_do_create(sizeof(type), size * 2, size)
#define vec_create_reserve(type, size, capacity) (type*) vec_do_create(sizeof(type), capcity, size)
#define vec_init(array, size) array = vec_do_create(sizeof(*array), size * 2, size)
#define vec_init_reserve(array, size, capacity) *((void**) &array) = vec_do_create(sizeof(*array), capacity, size)
#define vec_free(vec) (free((vec) ? vec__raw(vec) : NULL), vec = NULL)
#define vec_erase_range(vec, pos, count) vec_do_erase(vec, pos * sizeof(*vec), count * sizeof(*vec))
#define vec_erase(vec, pos) vec_do_erase(vec, pos * sizeof(*vec), sizeof(*vec))
#define vec_size(vec) (vec__raw(vec)[0] / sizeof(*vec))
#define vec_capacity(vec) (vec_raw(vec)[1] / sizeof(*vec))
#define vec_add(vec) vec_do_add((void**) &vec, sizeof(*vec))
#define vec_addc(vec, count) (vec_do_add((void**) &vec, sizeof(*vec) * count))
#define vec_push(vec, value) (vec_do_add((void**) &vec, sizeof(*vec)), vec_last(vec) = (value))
#define vec_pop(vec) (vec__raw(vec)[0] -= sizeof(*vec))
#define vec_popc(vec, count) (vec__raw(vec)[0] -= sizeof(*vec) * count)
#define vec_clear(vec) (vec__raw(vec)[0] = 0)
#define vec_last(vec) (vec[vec_size(vec) - 1])
static struct dlg_data* dlg_create_data(void) {
struct dlg_data* data = (struct dlg_data*) xalloc(sizeof(struct dlg_data));
vec_init_reserve(data->tags, 0, 20);
vec_init_reserve(data->pairs, 0, 20);
data->buffer_size = 100;
data->buffer = (char*) xalloc(data->buffer_size);
return data;
}
static void dlg_free_data(void* ddata) {
struct dlg_data* data = (struct dlg_data*) ddata;
if(data) {
vec_free(data->pairs);
vec_free(data->tags);
free(data->buffer);
free(data);
}
}
void dlg_add_tag(const char* tag, const char* func) {
struct dlg_data* data = dlg_data();
struct dlg_tag_func_pair* pair =
(struct dlg_tag_func_pair*) vec_add(data->pairs);
pair->tag = tag;
pair->func = func;
}
bool dlg_remove_tag(const char* tag, const char* func) {
struct dlg_data* data = dlg_data();
for(unsigned int i = 0; i < vec_size(data->pairs); ++i) {
if(data->pairs[i].func == func && data->pairs[i].tag == tag) {
vec_erase(data->pairs, i);
return true;
}
}
return false;
}
char** dlg_thread_buffer(size_t** size) {
struct dlg_data* data = dlg_data();
if(size) {
*size = &data->buffer_size;
}
return &data->buffer;
}
void dlg_set_handler(dlg_handler handler, void* data) {
g_handler = handler;
g_data = data;
}
dlg_handler dlg_get_handler(void** data) {
*data = g_data;
return g_handler;
}
const char* dlg__printf_format(const char* str, ...) {
va_list vlist;
va_start(vlist, str);
va_list vlistcopy;
va_copy(vlistcopy, vlist);
int needed = vsnprintf(NULL, 0, str, vlist);
if(needed < 0) {
printf("dlg__printf_format: invalid format given\n");
va_end(vlist);
va_end(vlistcopy);
return NULL;
}
va_end(vlist);
size_t* buf_size;
char** buf = dlg_thread_buffer(&buf_size);
if(*buf_size <= (unsigned int) needed) {
*buf_size = (needed + 1) * 2;
*buf = (char*) xrealloc(*buf, *buf_size);
}
vsnprintf(*buf, *buf_size, str, vlistcopy);
va_end(vlistcopy);
return *buf;
}
void dlg__do_log(enum dlg_level lvl, const char* const* tags, const char* file, int line,
const char* func, const char* string, const char* expr) {
struct dlg_data* data = dlg_data();
unsigned int tag_count = 0;
// push default tags
while(tags[tag_count]) {
vec_push(data->tags, tags[tag_count++]);
}
// push current global tags
for(size_t i = 0; i < vec_size(data->pairs); ++i) {
const struct dlg_tag_func_pair pair = data->pairs[i];
if(pair.func == NULL || !strcmp(pair.func, func)) {
vec_push(data->tags, pair.tag);
}
}
// push call-specific tags, skip first terminating NULL
++tag_count;
while(tags[tag_count]) {
vec_push(data->tags, tags[tag_count++]);
}
vec_push(data->tags, NULL); // terminating NULL
struct dlg_origin origin;
origin.level = lvl;
origin.file = file;
origin.line = line;
origin.func = func;
origin.expr = expr;
origin.tags = data->tags;
g_handler(&origin, string, g_data);
vec_clear(data->tags);
}
#ifdef _MSC_VER
// shitty msvc compatbility
// meson gives us sane paths (separated by '/') while on MSVC,
// __FILE__ contains a '\\' separator.
static bool path_same(char a, char b) {
return (a == b) ||
(a == '/' && b == '\\') ||
(a == '\\' && b == '/');
}
#else
static inline bool path_same(char a, char b) {
return a == b;
}
#endif
const char* dlg__strip_root_path(const char* file, const char* base) {
if(!file) {
return NULL;
}
const char* saved = file;
if(*file == '.') { // relative path detected
while(*(++file) == '.' || *file == '/' || *file == '\\');
if(*file == '\0') { // weird case: purely relative path without file
return saved;
}
return file;
}
// strip base from file if it is given
if(base) {
char fn = *file;
char bn = *base;
while(bn != '\0' && path_same(fn, bn)) {
fn = *(++file);
bn = *(++base);
}
if(fn == '\0' || bn != '\0') { // weird case: base isn't prefix of file
return saved;
}
}
return file;
}

View file

@ -0,0 +1,32 @@
/****************************************************************************
*
* dlgwrap.c
*
* Wrapper file for the 'dlg' library (body only)
*
* Copyright (C) 2020-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <ft2build.h>
#include FT_CONFIG_OPTIONS_H
#ifdef FT_DEBUG_LOGGING
#define DLG_STATIC
#include "dlg.c"
#else
/* ANSI C doesn't like empty source files */
typedef int dlg_dummy_;
#endif
/* END */

View file

@ -0,0 +1,42 @@
/****************************************************************************
*
* fnterrs.h
*
* Win FNT/FON error codes (specification only).
*
* Copyright (C) 2001-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* This file is used to define the Windows FNT/FON error enumeration
* constants.
*
*/
#ifndef FNTERRS_H_
#define FNTERRS_H_
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX FNT_Err_
#define FT_ERR_BASE FT_Mod_Err_Winfonts
#include <freetype/fterrors.h>
#endif /* FNTERRS_H_ */
/* END */

View file

@ -0,0 +1,115 @@
/*
* Copyright © 2009, 2023 Red Hat, Inc.
* Copyright © 2015 Google, Inc.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod, Matthias Clasen
* Google Author(s): Behdad Esfahbod
*/
#include <freetype/freetype.h>
#include <freetype/tttables.h>
#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
#include "ft-hb.h"
/* The following three functions are a more or less verbatim
* copy of corresponding HarfBuzz code from hb-ft.cc
*/
static hb_blob_t *
hb_ft_reference_table_ (hb_face_t *face, hb_tag_t tag, void *user_data)
{
FT_Face ft_face = (FT_Face) user_data;
FT_Byte *buffer;
FT_ULong length = 0;
FT_Error error;
FT_UNUSED (face);
/* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
if (error)
return NULL;
buffer = (FT_Byte *) ft_smalloc (length);
if (!buffer)
return NULL;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
if (error)
{
free (buffer);
return NULL;
}
return hb_blob_create ((const char *) buffer, length,
HB_MEMORY_MODE_WRITABLE,
buffer, ft_sfree);
}
static hb_face_t *
hb_ft_face_create_ (FT_Face ft_face,
hb_destroy_func_t destroy)
{
hb_face_t *face;
if (!ft_face->stream->read) {
hb_blob_t *blob;
blob = hb_blob_create ((const char *) ft_face->stream->base,
(unsigned int) ft_face->stream->size,
HB_MEMORY_MODE_READONLY,
ft_face, destroy);
face = hb_face_create (blob, ft_face->face_index);
hb_blob_destroy (blob);
} else {
face = hb_face_create_for_tables (hb_ft_reference_table_, ft_face, destroy);
}
hb_face_set_index (face, ft_face->face_index);
hb_face_set_upem (face, ft_face->units_per_EM);
return face;
}
FT_LOCAL_DEF(hb_font_t *)
hb_ft_font_create_ (FT_Face ft_face,
hb_destroy_func_t destroy)
{
hb_font_t *font;
hb_face_t *face;
face = hb_ft_face_create_ (ft_face, destroy);
font = hb_font_create (face);
hb_face_destroy (face);
return font;
}
#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
/* ANSI C doesn't like empty source files */
typedef int ft_hb_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
/* END */

View file

@ -0,0 +1,48 @@
/*
* Copyright © 2009, 2023 Red Hat, Inc.
* Copyright © 2015 Google, Inc.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod, Matthias Clasen
* Google Author(s): Behdad Esfahbod
*/
#ifndef FT_HB_H
#define FT_HB_H
#include <hb.h>
#include <freetype/internal/compiler-macros.h>
#include <freetype/freetype.h>
FT_BEGIN_HEADER
FT_LOCAL(hb_font_t *)
hb_ft_font_create_ (FT_Face ft_face,
hb_destroy_func_t destroy);
FT_END_HEADER
#endif /* FT_HB_H */
/* END */

View file

@ -0,0 +1,174 @@
/****************************************************************************
*
* ftadvanc.c
*
* Quick computation of advance widths (body).
*
* Copyright (C) 2008-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftdebug.h>
#include <freetype/ftadvanc.h>
#include <freetype/internal/ftobjs.h>
static FT_Error
ft_face_scale_advances_( FT_Face face,
FT_Fixed* advances,
FT_UInt count,
FT_Int32 flags )
{
FT_Fixed scale;
FT_UInt nn;
if ( flags & FT_LOAD_NO_SCALE )
return FT_Err_Ok;
if ( !face->size )
return FT_THROW( Invalid_Size_Handle );
if ( flags & FT_LOAD_VERTICAL_LAYOUT )
scale = face->size->metrics.y_scale;
else
scale = face->size->metrics.x_scale;
/* this must be the same scaling as to get linear{Hori,Vert}Advance */
/* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c) */
for ( nn = 0; nn < count; nn++ )
advances[nn] = FT_MulDiv( advances[nn], scale, 64 );
return FT_Err_Ok;
}
/* at the moment, we can perform fast advance retrieval only in */
/* the following cases: */
/* */
/* - unscaled load */
/* - unhinted load */
/* - light-hinted load */
/* - if a variations font, it must have an `HVAR' or `VVAR' */
/* table (thus the old MM or GX fonts don't qualify; this */
/* gets checked by the driver-specific functions) */
#define LOAD_ADVANCE_FAST_CHECK( face, flags ) \
( flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) || \
FT_LOAD_TARGET_MODE( flags ) == FT_RENDER_MODE_LIGHT )
/* documentation is in ftadvanc.h */
FT_EXPORT_DEF( FT_Error )
FT_Get_Advance( FT_Face face,
FT_UInt gindex,
FT_Int32 flags,
FT_Fixed *padvance )
{
FT_Face_GetAdvancesFunc func;
if ( !face )
return FT_THROW( Invalid_Face_Handle );
if ( !padvance )
return FT_THROW( Invalid_Argument );
if ( gindex >= (FT_UInt)face->num_glyphs )
return FT_THROW( Invalid_Glyph_Index );
func = face->driver->clazz->get_advances;
if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) )
{
FT_Error error;
error = func( face, gindex, 1, flags, padvance );
if ( !error )
return ft_face_scale_advances_( face, padvance, 1, flags );
if ( FT_ERR_NEQ( error, Unimplemented_Feature ) )
return error;
}
return FT_Get_Advances( face, gindex, 1, flags, padvance );
}
/* documentation is in ftadvanc.h */
FT_EXPORT_DEF( FT_Error )
FT_Get_Advances( FT_Face face,
FT_UInt start,
FT_UInt count,
FT_Int32 flags,
FT_Fixed *padvances )
{
FT_Error error = FT_Err_Ok;
FT_Face_GetAdvancesFunc func;
FT_UInt num, end, nn;
FT_Int factor;
if ( !face )
return FT_THROW( Invalid_Face_Handle );
if ( !padvances )
return FT_THROW( Invalid_Argument );
num = (FT_UInt)face->num_glyphs;
end = start + count;
if ( start >= num || end < start || end > num )
return FT_THROW( Invalid_Glyph_Index );
if ( count == 0 )
return FT_Err_Ok;
func = face->driver->clazz->get_advances;
if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) )
{
error = func( face, start, count, flags, padvances );
if ( !error )
return ft_face_scale_advances_( face, padvances, count, flags );
if ( FT_ERR_NEQ( error, Unimplemented_Feature ) )
return error;
}
error = FT_Err_Ok;
if ( flags & FT_ADVANCE_FLAG_FAST_ONLY )
return FT_THROW( Unimplemented_Feature );
flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
factor = ( flags & FT_LOAD_NO_SCALE ) ? 1 : 1024;
for ( nn = 0; nn < count; nn++ )
{
error = FT_Load_Glyph( face, start + nn, flags );
if ( error )
break;
/* scale from 26.6 to 16.16, unless NO_SCALE was requested */
padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
? face->glyph->advance.y * factor
: face->glyph->advance.x * factor;
}
return error;
}
/* END */

View file

@ -0,0 +1,82 @@
/****************************************************************************
*
* ftbase.h
*
* Private functions used in the `base' module (specification).
*
* Copyright (C) 2008-2023 by
* David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef FTBASE_H_
#define FTBASE_H_
#include <freetype/internal/ftobjs.h>
FT_BEGIN_HEADER
FT_DECLARE_GLYPH( ft_bitmap_glyph_class )
FT_DECLARE_GLYPH( ft_outline_glyph_class )
FT_DECLARE_GLYPH( ft_svg_glyph_class )
#ifdef FT_CONFIG_OPTION_MAC_FONTS
/* MacOS resource fork cannot exceed 16MB at least for Carbon code; */
/* see https://support.microsoft.com/en-us/kb/130437 */
#define FT_MAC_RFORK_MAX_LEN 0x00FFFFFFUL
/* Assume the stream is sfnt-wrapped PS Type1 or sfnt-wrapped CID-keyed */
/* font, and try to load a face specified by the face_index. */
FT_LOCAL( FT_Error )
open_face_PS_from_sfnt_stream( FT_Library library,
FT_Stream stream,
FT_Long face_index,
FT_Int num_params,
FT_Parameter *params,
FT_Face *aface );
/* Create a new FT_Face given a buffer and a driver name. */
/* From ftmac.c. */
FT_LOCAL( FT_Error )
open_face_from_buffer( FT_Library library,
FT_Byte* base,
FT_ULong size,
FT_Long face_index,
const char* driver_name,
FT_Face *aface );
#if defined( FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK ) && \
!defined( FT_MACINTOSH )
/* Mac OS X/Darwin kernel often changes recommended method to access */
/* the resource fork and older methods makes the kernel issue the */
/* warning of deprecated method. To calm it down, the methods based */
/* on Darwin VFS should be grouped and skip the rest methods after */
/* the case the resource is opened but found to lack a font in it. */
FT_LOCAL( FT_Bool )
ft_raccess_rule_by_darwin_vfs( FT_Library library, FT_UInt rule_index );
#endif
#endif /* FT_CONFIG_OPTION_MAC_FONTS */
FT_END_HEADER
#endif /* FTBASE_H_ */
/* END */

View file

@ -0,0 +1,542 @@
/****************************************************************************
*
* ftbbox.c
*
* FreeType bbox computation (body).
*
* Copyright (C) 1996-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* This component has a _single_ role: to compute exact outline bounding
* boxes.
*
*/
#include <freetype/internal/ftdebug.h>
#include <freetype/ftbbox.h>
#include <freetype/ftimage.h>
#include <freetype/ftoutln.h>
#include <freetype/internal/ftcalc.h>
#include <freetype/internal/ftobjs.h>
typedef struct TBBox_Rec_
{
FT_Vector last;
FT_BBox bbox;
} TBBox_Rec;
#define FT_UPDATE_BBOX( p, bbox ) \
FT_BEGIN_STMNT \
if ( p->x < bbox.xMin ) \
bbox.xMin = p->x; \
if ( p->x > bbox.xMax ) \
bbox.xMax = p->x; \
if ( p->y < bbox.yMin ) \
bbox.yMin = p->y; \
if ( p->y > bbox.yMax ) \
bbox.yMax = p->y; \
FT_END_STMNT
#define CHECK_X( p, bbox ) \
( p->x < bbox.xMin || p->x > bbox.xMax )
#define CHECK_Y( p, bbox ) \
( p->y < bbox.yMin || p->y > bbox.yMax )
/**************************************************************************
*
* @Function:
* BBox_Move_To
*
* @Description:
* This function is used as a `move_to' emitter during
* FT_Outline_Decompose(). It simply records the destination point
* in `user->last'. We also update bbox in case contour starts with
* an implicit `on' point.
*
* @Input:
* to ::
* A pointer to the destination vector.
*
* @InOut:
* user ::
* A pointer to the current walk context.
*
* @Return:
* Always 0. Needed for the interface only.
*/
FT_CALLBACK_DEF( int )
BBox_Move_To( const FT_Vector* to,
void* user_ )
{
TBBox_Rec* user = (TBBox_Rec*)user_;
FT_UPDATE_BBOX( to, user->bbox );
user->last = *to;
return 0;
}
/**************************************************************************
*
* @Function:
* BBox_Line_To
*
* @Description:
* This function is used as a `line_to' emitter during
* FT_Outline_Decompose(). It simply records the destination point
* in `user->last'; no further computations are necessary because
* bbox already contains both explicit ends of the line segment.
*
* @Input:
* to ::
* A pointer to the destination vector.
*
* @InOut:
* user ::
* A pointer to the current walk context.
*
* @Return:
* Always 0. Needed for the interface only.
*/
FT_CALLBACK_DEF( int )
BBox_Line_To( const FT_Vector* to,
void* user_ )
{
TBBox_Rec* user = (TBBox_Rec*)user_;
user->last = *to;
return 0;
}
/**************************************************************************
*
* @Function:
* BBox_Conic_Check
*
* @Description:
* Find the extrema of a 1-dimensional conic Bezier curve and update
* a bounding range. This version uses direct computation, as it
* doesn't need square roots.
*
* @Input:
* y1 ::
* The start coordinate.
*
* y2 ::
* The coordinate of the control point.
*
* y3 ::
* The end coordinate.
*
* @InOut:
* min ::
* The address of the current minimum.
*
* max ::
* The address of the current maximum.
*/
static void
BBox_Conic_Check( FT_Pos y1,
FT_Pos y2,
FT_Pos y3,
FT_Pos* min,
FT_Pos* max )
{
/* This function is only called when a control off-point is outside */
/* the bbox that contains all on-points. It finds a local extremum */
/* within the segment, equal to (y1*y3 - y2*y2)/(y1 - 2*y2 + y3). */
/* Or, offsetting from y2, we get */
y1 -= y2;
y3 -= y2;
y2 += FT_MulDiv( y1, y3, y1 + y3 );
if ( y2 < *min )
*min = y2;
if ( y2 > *max )
*max = y2;
}
/**************************************************************************
*
* @Function:
* BBox_Conic_To
*
* @Description:
* This function is used as a `conic_to' emitter during
* FT_Outline_Decompose(). It checks a conic Bezier curve with the
* current bounding box, and computes its extrema if necessary to
* update it.
*
* @Input:
* control ::
* A pointer to a control point.
*
* to ::
* A pointer to the destination vector.
*
* @InOut:
* user ::
* The address of the current walk context.
*
* @Return:
* Always 0. Needed for the interface only.
*
* @Note:
* In the case of a non-monotonous arc, we compute directly the
* extremum coordinates, as it is sufficiently fast.
*/
FT_CALLBACK_DEF( int )
BBox_Conic_To( const FT_Vector* control,
const FT_Vector* to,
void* user_ )
{
TBBox_Rec* user = (TBBox_Rec*)user_;
/* in case `to' is implicit and not included in bbox yet */
FT_UPDATE_BBOX( to, user->bbox );
if ( CHECK_X( control, user->bbox ) )
BBox_Conic_Check( user->last.x,
control->x,
to->x,
&user->bbox.xMin,
&user->bbox.xMax );
if ( CHECK_Y( control, user->bbox ) )
BBox_Conic_Check( user->last.y,
control->y,
to->y,
&user->bbox.yMin,
&user->bbox.yMax );
user->last = *to;
return 0;
}
/**************************************************************************
*
* @Function:
* BBox_Cubic_Check
*
* @Description:
* Find the extrema of a 1-dimensional cubic Bezier curve and
* update a bounding range. This version uses iterative splitting
* because it is faster than the exact solution with square roots.
*
* @Input:
* p1 ::
* The start coordinate.
*
* p2 ::
* The coordinate of the first control point.
*
* p3 ::
* The coordinate of the second control point.
*
* p4 ::
* The end coordinate.
*
* @InOut:
* min ::
* The address of the current minimum.
*
* max ::
* The address of the current maximum.
*/
static FT_Pos
cubic_peak( FT_Pos q1,
FT_Pos q2,
FT_Pos q3,
FT_Pos q4 )
{
FT_Pos peak = 0;
FT_Int shift;
/* This function finds a peak of a cubic segment if it is above 0 */
/* using iterative bisection of the segment, or returns 0. */
/* The fixed-point arithmetic of bisection is inherently stable */
/* but may loose accuracy in the two lowest bits. To compensate, */
/* we upscale the segment if there is room. Large values may need */
/* to be downscaled to avoid overflows during bisection. */
/* It is called with either q2 or q3 positive, which is necessary */
/* for the peak to exist and avoids undefined FT_MSB. */
shift = 27 - FT_MSB( (FT_UInt32)( FT_ABS( q1 ) |
FT_ABS( q2 ) |
FT_ABS( q3 ) |
FT_ABS( q4 ) ) );
if ( shift > 0 )
{
/* upscaling too much just wastes time */
if ( shift > 2 )
shift = 2;
q1 *= 1 << shift;
q2 *= 1 << shift;
q3 *= 1 << shift;
q4 *= 1 << shift;
}
else
{
q1 >>= -shift;
q2 >>= -shift;
q3 >>= -shift;
q4 >>= -shift;
}
/* for a peak to exist above 0, the cubic segment must have */
/* at least one of its control off-points above 0. */
while ( q2 > 0 || q3 > 0 )
{
/* determine which half contains the maximum and split */
if ( q1 + q2 > q3 + q4 ) /* first half */
{
q4 = q4 + q3;
q3 = q3 + q2;
q2 = q2 + q1;
q4 = q4 + q3;
q3 = q3 + q2;
q4 = ( q4 + q3 ) >> 3;
q3 = q3 >> 2;
q2 = q2 >> 1;
}
else /* second half */
{
q1 = q1 + q2;
q2 = q2 + q3;
q3 = q3 + q4;
q1 = q1 + q2;
q2 = q2 + q3;
q1 = ( q1 + q2 ) >> 3;
q2 = q2 >> 2;
q3 = q3 >> 1;
}
/* check whether either end reached the maximum */
if ( q1 == q2 && q1 >= q3 )
{
peak = q1;
break;
}
if ( q3 == q4 && q2 <= q4 )
{
peak = q4;
break;
}
}
if ( shift > 0 )
peak >>= shift;
else
peak <<= -shift;
return peak;
}
static void
BBox_Cubic_Check( FT_Pos p1,
FT_Pos p2,
FT_Pos p3,
FT_Pos p4,
FT_Pos* min,
FT_Pos* max )
{
/* This function is only called when a control off-point is outside */
/* the bbox that contains all on-points. So at least one of the */
/* conditions below holds and cubic_peak is called with at least one */
/* non-zero argument. */
if ( p2 > *max || p3 > *max )
*max += cubic_peak( p1 - *max, p2 - *max, p3 - *max, p4 - *max );
/* now flip the signs to update the minimum */
if ( p2 < *min || p3 < *min )
*min -= cubic_peak( *min - p1, *min - p2, *min - p3, *min - p4 );
}
/**************************************************************************
*
* @Function:
* BBox_Cubic_To
*
* @Description:
* This function is used as a `cubic_to' emitter during
* FT_Outline_Decompose(). It checks a cubic Bezier curve with the
* current bounding box, and computes its extrema if necessary to
* update it.
*
* @Input:
* control1 ::
* A pointer to the first control point.
*
* control2 ::
* A pointer to the second control point.
*
* to ::
* A pointer to the destination vector.
*
* @InOut:
* user ::
* The address of the current walk context.
*
* @Return:
* Always 0. Needed for the interface only.
*
* @Note:
* In the case of a non-monotonous arc, we don't compute directly
* extremum coordinates, we subdivide instead.
*/
FT_CALLBACK_DEF( int )
BBox_Cubic_To( const FT_Vector* control1,
const FT_Vector* control2,
const FT_Vector* to,
void* user_ )
{
TBBox_Rec* user = (TBBox_Rec*)user_;
/* We don't need to check `to' since it is always an on-point, */
/* thus within the bbox. Only segments with an off-point outside */
/* the bbox can possibly reach new extreme values. */
if ( CHECK_X( control1, user->bbox ) ||
CHECK_X( control2, user->bbox ) )
BBox_Cubic_Check( user->last.x,
control1->x,
control2->x,
to->x,
&user->bbox.xMin,
&user->bbox.xMax );
if ( CHECK_Y( control1, user->bbox ) ||
CHECK_Y( control2, user->bbox ) )
BBox_Cubic_Check( user->last.y,
control1->y,
control2->y,
to->y,
&user->bbox.yMin,
&user->bbox.yMax );
user->last = *to;
return 0;
}
FT_DEFINE_OUTLINE_FUNCS(
bbox_interface,
(FT_Outline_MoveTo_Func) BBox_Move_To, /* move_to */
(FT_Outline_LineTo_Func) BBox_Line_To, /* line_to */
(FT_Outline_ConicTo_Func)BBox_Conic_To, /* conic_to */
(FT_Outline_CubicTo_Func)BBox_Cubic_To, /* cubic_to */
0, /* shift */
0 /* delta */
)
/* documentation is in ftbbox.h */
FT_EXPORT_DEF( FT_Error )
FT_Outline_Get_BBox( FT_Outline* outline,
FT_BBox *abbox )
{
FT_BBox cbox = { 0x7FFFFFFFL, 0x7FFFFFFFL,
-0x7FFFFFFFL, -0x7FFFFFFFL };
FT_BBox bbox = { 0x7FFFFFFFL, 0x7FFFFFFFL,
-0x7FFFFFFFL, -0x7FFFFFFFL };
FT_Vector* vec;
FT_UShort n;
if ( !abbox )
return FT_THROW( Invalid_Argument );
if ( !outline )
return FT_THROW( Invalid_Outline );
/* if outline is empty, return (0,0,0,0) */
if ( outline->n_points == 0 || outline->n_contours <= 0 )
{
abbox->xMin = abbox->xMax = 0;
abbox->yMin = abbox->yMax = 0;
return 0;
}
/* We compute the control box as well as the bounding box of */
/* all `on' points in the outline. Then, if the two boxes */
/* coincide, we exit immediately. */
vec = outline->points;
for ( n = 0; n < outline->n_points; n++ )
{
FT_UPDATE_BBOX( vec, cbox );
if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON )
FT_UPDATE_BBOX( vec, bbox );
vec++;
}
/* test two boxes for equality */
if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
{
/* the two boxes are different, now walk over the outline to */
/* get the Bezier arc extrema. */
FT_Error error;
TBBox_Rec user;
user.bbox = bbox;
error = FT_Outline_Decompose( outline, &bbox_interface, &user );
if ( error )
return error;
*abbox = user.bbox;
}
else
*abbox = bbox;
return FT_Err_Ok;
}
/* END */

View file

@ -0,0 +1,90 @@
/****************************************************************************
*
* ftbdf.c
*
* FreeType API for accessing BDF-specific strings (body).
*
* Copyright (C) 2002-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/services/svbdf.h>
/* documentation is in ftbdf.h */
FT_EXPORT_DEF( FT_Error )
FT_Get_BDF_Charset_ID( FT_Face face,
const char* *acharset_encoding,
const char* *acharset_registry )
{
FT_Error error;
const char* encoding = NULL;
const char* registry = NULL;
FT_Service_BDF service;
if ( !face )
return FT_THROW( Invalid_Face_Handle );
FT_FACE_FIND_SERVICE( face, service, BDF );
if ( service && service->get_charset_id )
error = service->get_charset_id( face, &encoding, &registry );
else
error = FT_THROW( Invalid_Argument );
if ( acharset_encoding )
*acharset_encoding = encoding;
if ( acharset_registry )
*acharset_registry = registry;
return error;
}
/* documentation is in ftbdf.h */
FT_EXPORT_DEF( FT_Error )
FT_Get_BDF_Property( FT_Face face,
const char* prop_name,
BDF_PropertyRec *aproperty )
{
FT_Error error;
FT_Service_BDF service;
if ( !face )
return FT_THROW( Invalid_Face_Handle );
if ( !aproperty )
return FT_THROW( Invalid_Argument );
aproperty->type = BDF_PROPERTY_TYPE_NONE;
FT_FACE_FIND_SERVICE( face, service, BDF );
if ( service && service->get_property )
error = service->get_property( face, prop_name, aproperty );
else
error = FT_THROW( Invalid_Argument );
return error;
}
/* END */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,535 @@
/****************************************************************************
*
* ftbzip2.c
*
* FreeType support for .bz2 compressed files.
*
* This optional component relies on libbz2. It should mainly be used to
* parse compressed PCF fonts, as found with many X11 server
* distributions.
*
* Copyright (C) 2010-2023 by
* Joel Klinghed.
*
* based on `src/gzip/ftgzip.c'
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftmemory.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/ftbzip2.h>
#include FT_CONFIG_STANDARD_LIBRARY_H
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX Bzip2_Err_
#define FT_ERR_BASE FT_Mod_Err_Bzip2
#include <freetype/fterrors.h>
#ifdef FT_CONFIG_OPTION_USE_BZIP2
#define BZ_NO_STDIO /* Do not need FILE */
#include <bzlib.h>
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** B Z I P 2 M E M O R Y M A N A G E M E N T *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
/* it is better to use FreeType memory routines instead of raw
'malloc/free' */
typedef void* (*alloc_func)( void*, int, int );
typedef void (*free_func) ( void*, void* );
static void*
ft_bzip2_alloc( void* memory_, /* FT_Memory */
int items,
int size )
{
FT_Memory memory = (FT_Memory)memory_;
FT_ULong sz = (FT_ULong)size * (FT_ULong)items;
FT_Error error;
FT_Pointer p = NULL;
FT_MEM_QALLOC( p, sz );
return p;
}
static void
ft_bzip2_free( void* memory_, /* FT_Memory */
void* address )
{
FT_Memory memory = (FT_Memory)memory_;
FT_MEM_FREE( address );
}
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** B Z I P 2 F I L E D E S C R I P T O R *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
#define FT_BZIP2_BUFFER_SIZE 4096
typedef struct FT_BZip2FileRec_
{
FT_Stream source; /* parent/source stream */
FT_Stream stream; /* embedding stream */
FT_Memory memory; /* memory allocator */
bz_stream bzstream; /* bzlib input stream */
FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */
FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */
FT_ULong pos; /* position in output */
FT_Byte* cursor;
FT_Byte* limit;
FT_Bool reset; /* reset before next read */
} FT_BZip2FileRec, *FT_BZip2File;
/* check and skip .bz2 header - we don't support `transparent' compression */
static FT_Error
ft_bzip2_check_header( FT_Stream stream )
{
FT_Error error = FT_Err_Ok;
FT_Byte head[4];
if ( FT_STREAM_SEEK( 0 ) ||
FT_STREAM_READ( head, 4 ) )
goto Exit;
/* head[0] && head[1] are the magic numbers; */
/* head[2] is the version, and head[3] the blocksize */
if ( head[0] != 0x42 ||
head[1] != 0x5A ||
head[2] != 0x68 ) /* only support bzip2 (huffman) */
{
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
Exit:
return error;
}
static FT_Error
ft_bzip2_file_init( FT_BZip2File zip,
FT_Stream stream,
FT_Stream source )
{
bz_stream* bzstream = &zip->bzstream;
FT_Error error = FT_Err_Ok;
zip->stream = stream;
zip->source = source;
zip->memory = stream->memory;
zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
zip->cursor = zip->limit;
zip->pos = 0;
zip->reset = 0;
/* check .bz2 header */
{
stream = source;
error = ft_bzip2_check_header( stream );
if ( error )
goto Exit;
if ( FT_STREAM_SEEK( 0 ) )
goto Exit;
}
/* initialize bzlib */
bzstream->bzalloc = ft_bzip2_alloc;
bzstream->bzfree = ft_bzip2_free;
bzstream->opaque = zip->memory;
bzstream->avail_in = 0;
bzstream->next_in = (char*)zip->buffer;
if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK ||
!bzstream->next_in )
error = FT_THROW( Invalid_File_Format );
Exit:
return error;
}
static void
ft_bzip2_file_done( FT_BZip2File zip )
{
bz_stream* bzstream = &zip->bzstream;
BZ2_bzDecompressEnd( bzstream );
/* clear the rest */
bzstream->bzalloc = NULL;
bzstream->bzfree = NULL;
bzstream->opaque = NULL;
bzstream->next_in = NULL;
bzstream->next_out = NULL;
bzstream->avail_in = 0;
bzstream->avail_out = 0;
zip->memory = NULL;
zip->source = NULL;
zip->stream = NULL;
}
static FT_Error
ft_bzip2_file_reset( FT_BZip2File zip )
{
FT_Stream stream = zip->source;
FT_Error error;
if ( !FT_STREAM_SEEK( 0 ) )
{
bz_stream* bzstream = &zip->bzstream;
BZ2_bzDecompressEnd( bzstream );
bzstream->avail_in = 0;
bzstream->next_in = (char*)zip->input;
bzstream->avail_out = 0;
bzstream->next_out = (char*)zip->buffer;
zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
zip->cursor = zip->limit;
zip->pos = 0;
zip->reset = 0;
BZ2_bzDecompressInit( bzstream, 0, 0 );
}
return error;
}
static FT_Error
ft_bzip2_file_fill_input( FT_BZip2File zip )
{
bz_stream* bzstream = &zip->bzstream;
FT_Stream stream = zip->source;
FT_ULong size;
if ( stream->read )
{
size = stream->read( stream, stream->pos, zip->input,
FT_BZIP2_BUFFER_SIZE );
if ( size == 0 )
{
zip->limit = zip->cursor;
return FT_THROW( Invalid_Stream_Operation );
}
}
else
{
size = stream->size - stream->pos;
if ( size > FT_BZIP2_BUFFER_SIZE )
size = FT_BZIP2_BUFFER_SIZE;
if ( size == 0 )
{
zip->limit = zip->cursor;
return FT_THROW( Invalid_Stream_Operation );
}
FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
}
stream->pos += size;
bzstream->next_in = (char*)zip->input;
bzstream->avail_in = size;
return FT_Err_Ok;
}
static FT_Error
ft_bzip2_file_fill_output( FT_BZip2File zip )
{
bz_stream* bzstream = &zip->bzstream;
FT_Error error = FT_Err_Ok;
zip->cursor = zip->buffer;
bzstream->next_out = (char*)zip->cursor;
bzstream->avail_out = FT_BZIP2_BUFFER_SIZE;
while ( bzstream->avail_out > 0 )
{
int err;
if ( bzstream->avail_in == 0 )
{
error = ft_bzip2_file_fill_input( zip );
if ( error )
break;
}
err = BZ2_bzDecompress( bzstream );
if ( err != BZ_OK )
{
zip->reset = 1;
if ( err == BZ_STREAM_END )
{
zip->limit = (FT_Byte*)bzstream->next_out;
if ( zip->limit == zip->cursor )
error = FT_THROW( Invalid_Stream_Operation );
break;
}
else
{
zip->limit = zip->cursor;
error = FT_THROW( Invalid_Stream_Operation );
break;
}
}
}
return error;
}
/* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */
static FT_Error
ft_bzip2_file_skip_output( FT_BZip2File zip,
FT_ULong count )
{
FT_Error error = FT_Err_Ok;
for (;;)
{
FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor );
if ( delta >= count )
delta = count;
zip->cursor += delta;
zip->pos += delta;
count -= delta;
if ( count == 0 )
break;
error = ft_bzip2_file_fill_output( zip );
if ( error )
break;
}
return error;
}
static FT_ULong
ft_bzip2_file_io( FT_BZip2File zip,
FT_ULong pos,
FT_Byte* buffer,
FT_ULong count )
{
FT_ULong result = 0;
FT_Error error;
/* Reset inflate stream if seeking backwards or bzip reported an error. */
/* Yes, that is not too efficient, but it saves memory :-) */
if ( pos < zip->pos || zip->reset )
{
error = ft_bzip2_file_reset( zip );
if ( error )
goto Exit;
}
/* skip unwanted bytes */
if ( pos > zip->pos )
{
error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
if ( error )
goto Exit;
}
if ( count == 0 )
goto Exit;
/* now read the data */
for (;;)
{
FT_ULong delta;
delta = (FT_ULong)( zip->limit - zip->cursor );
if ( delta >= count )
delta = count;
FT_MEM_COPY( buffer, zip->cursor, delta );
buffer += delta;
result += delta;
zip->cursor += delta;
zip->pos += delta;
count -= delta;
if ( count == 0 )
break;
error = ft_bzip2_file_fill_output( zip );
if ( error )
break;
}
Exit:
return result;
}
/***************************************************************************/
/***************************************************************************/
/***** *****/
/***** B Z E M B E D D I N G S T R E A M *****/
/***** *****/
/***************************************************************************/
/***************************************************************************/
static void
ft_bzip2_stream_close( FT_Stream stream )
{
FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
FT_Memory memory = stream->memory;
if ( zip )
{
/* finalize bzip file descriptor */
ft_bzip2_file_done( zip );
FT_FREE( zip );
stream->descriptor.pointer = NULL;
}
}
static unsigned long
ft_bzip2_stream_io( FT_Stream stream,
unsigned long offset,
unsigned char* buffer,
unsigned long count )
{
FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
return ft_bzip2_file_io( zip, offset, buffer, count );
}
FT_EXPORT_DEF( FT_Error )
FT_Stream_OpenBzip2( FT_Stream stream,
FT_Stream source )
{
FT_Error error;
FT_Memory memory;
FT_BZip2File zip = NULL;
if ( !stream || !source )
{
error = FT_THROW( Invalid_Stream_Handle );
goto Exit;
}
memory = source->memory;
/*
* check the header right now; this prevents allocating unnecessary
* objects when we don't need them
*/
error = ft_bzip2_check_header( source );
if ( error )
goto Exit;
FT_ZERO( stream );
stream->memory = memory;
if ( !FT_QNEW( zip ) )
{
error = ft_bzip2_file_init( zip, stream, source );
if ( error )
{
FT_FREE( zip );
goto Exit;
}
stream->descriptor.pointer = zip;
}
stream->size = 0x7FFFFFFFL; /* don't know the real size! */
stream->pos = 0;
stream->base = NULL;
stream->read = ft_bzip2_stream_io;
stream->close = ft_bzip2_stream_close;
Exit:
return error;
}
#else /* !FT_CONFIG_OPTION_USE_BZIP2 */
FT_EXPORT_DEF( FT_Error )
FT_Stream_OpenBzip2( FT_Stream stream,
FT_Stream source )
{
FT_UNUSED( stream );
FT_UNUSED( source );
return FT_THROW( Unimplemented_Feature );
}
#endif /* !FT_CONFIG_OPTION_USE_BZIP2 */
/* END */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,638 @@
/****************************************************************************
*
* ftcbasic.c
*
* The FreeType basic cache interface (body).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/ftcache.h>
#include "ftcglyph.h"
#include "ftcimage.h"
#include "ftcsbits.h"
#include "ftccback.h"
#include "ftcerror.h"
#undef FT_COMPONENT
#define FT_COMPONENT cache
/*
* Basic Families
*
*/
typedef struct FTC_BasicAttrRec_
{
FTC_ScalerRec scaler;
FT_UInt load_flags;
} FTC_BasicAttrRec, *FTC_BasicAttrs;
#define FTC_BASIC_ATTR_COMPARE( a, b ) \
FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
(a)->load_flags == (b)->load_flags )
#define FTC_BASIC_ATTR_HASH( a ) \
( FTC_SCALER_HASH( &(a)->scaler ) + 31 * (a)->load_flags )
typedef struct FTC_BasicQueryRec_
{
FTC_GQueryRec gquery;
FTC_BasicAttrRec attrs;
} FTC_BasicQueryRec, *FTC_BasicQuery;
typedef struct FTC_BasicFamilyRec_
{
FTC_FamilyRec family;
FTC_BasicAttrRec attrs;
} FTC_BasicFamilyRec, *FTC_BasicFamily;
FT_CALLBACK_DEF( FT_Bool )
ftc_basic_family_compare( FTC_MruNode ftcfamily,
FT_Pointer ftcquery )
{
FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
FTC_BasicQuery query = (FTC_BasicQuery)ftcquery;
return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs );
}
FT_CALLBACK_DEF( FT_Error )
ftc_basic_family_init( FTC_MruNode ftcfamily,
FT_Pointer ftcquery,
FT_Pointer ftccache )
{
FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
FTC_BasicQuery query = (FTC_BasicQuery)ftcquery;
FTC_Cache cache = (FTC_Cache)ftccache;
FTC_Family_Init( FTC_FAMILY( family ), cache );
family->attrs = query->attrs;
return 0;
}
FT_CALLBACK_DEF( FT_UInt )
ftc_basic_family_get_count( FTC_Family ftcfamily,
FTC_Manager manager )
{
FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
FT_Error error;
FT_Face face;
FT_UInt result = 0;
error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id,
&face );
if ( error || !face )
return result;
#ifdef FT_DEBUG_LEVEL_TRACE
if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
{
FT_TRACE1(( "ftc_basic_family_get_count:"
" the number of glyphs in this face is %ld,\n",
face->num_glyphs ));
FT_TRACE1(( " "
" which is too much and thus truncated\n" ));
}
#endif
result = (FT_UInt)face->num_glyphs;
return result;
}
FT_CALLBACK_DEF( FT_Error )
ftc_basic_family_load_bitmap( FTC_Family ftcfamily,
FT_UInt gindex,
FTC_Manager manager,
FT_Face *aface )
{
FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
FT_Error error;
FT_Size size;
error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
if ( !error )
{
FT_Face face = size->face;
error = FT_Load_Glyph(
face,
gindex,
(FT_Int)family->attrs.load_flags | FT_LOAD_RENDER );
if ( !error )
*aface = face;
}
return error;
}
FT_CALLBACK_DEF( FT_Error )
ftc_basic_family_load_glyph( FTC_Family ftcfamily,
FT_UInt gindex,
FTC_Cache cache,
FT_Glyph *aglyph )
{
FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily;
FT_Error error;
FTC_Scaler scaler = &family->attrs.scaler;
FT_Face face;
FT_Size size;
/* we will now load the glyph image */
error = FTC_Manager_LookupSize( cache->manager,
scaler,
&size );
if ( !error )
{
face = size->face;
error = FT_Load_Glyph( face,
gindex,
(FT_Int)family->attrs.load_flags );
if ( !error )
{
if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP ||
face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ||
face->glyph->format == FT_GLYPH_FORMAT_SVG )
{
/* ok, copy it */
FT_Glyph glyph;
error = FT_Get_Glyph( face->glyph, &glyph );
if ( !error )
{
*aglyph = glyph;
goto Exit;
}
}
else
error = FT_THROW( Invalid_Argument );
}
}
Exit:
return error;
}
FT_CALLBACK_DEF( FT_Bool )
ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode,
FT_Pointer ftcface_id,
FTC_Cache cache,
FT_Bool* list_changed )
{
FTC_GNode gnode = (FTC_GNode)ftcgnode;
FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
FTC_BasicFamily family = (FTC_BasicFamily)gnode->family;
FT_Bool result;
if ( list_changed )
*list_changed = FALSE;
result = FT_BOOL( family->attrs.scaler.face_id == face_id );
if ( result )
{
/* we must call this function to avoid this node from appearing
* in later lookups with the same face_id!
*/
FTC_GNode_UnselectFamily( gnode, cache );
}
return result;
}
/*
*
* basic image cache
*
*/
static
const FTC_IFamilyClassRec ftc_basic_image_family_class =
{
{
sizeof ( FTC_BasicFamilyRec ),
ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */
ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */
NULL, /* FTC_MruNode_ResetFunc node_reset */
NULL /* FTC_MruNode_DoneFunc node_done */
},
ftc_basic_family_load_glyph /* FTC_IFamily_LoadGlyphFunc family_load_glyph */
};
static
const FTC_GCacheClassRec ftc_basic_image_cache_class =
{
{
ftc_inode_new, /* FTC_Node_NewFunc node_new */
ftc_inode_weight, /* FTC_Node_WeightFunc node_weight */
ftc_gnode_compare, /* FTC_Node_CompareFunc node_compare */
ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */
ftc_inode_free, /* FTC_Node_FreeFunc node_free */
sizeof ( FTC_GCacheRec ),
ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */
ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */
},
(FTC_MruListClass)&ftc_basic_image_family_class
};
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_New( FTC_Manager manager,
FTC_ImageCache *acache )
{
return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
(FTC_GCache*)acache );
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_Lookup( FTC_ImageCache cache,
FTC_ImageType type,
FT_UInt gindex,
FT_Glyph *aglyph,
FTC_Node *anode )
{
FTC_BasicQueryRec query;
FTC_Node node = 0; /* make compiler happy */
FT_Error error;
FT_Offset hash;
/* some argument checks are delayed to `FTC_Cache_Lookup' */
if ( !aglyph )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
*aglyph = NULL;
if ( anode )
*anode = NULL;
/*
* Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
* but public `FT_ImageType->flags' is of type `FT_Int32'.
*
* On 16bit systems, higher bits of type->flags cannot be handled.
*/
#if 0xFFFFFFFFUL > FT_UINT_MAX
if ( (type->flags & (FT_ULong)FT_UINT_MAX) )
FT_TRACE1(( "FTC_ImageCache_Lookup:"
" higher bits in load_flags 0x%lx are dropped\n",
(FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
#endif
query.attrs.scaler.face_id = type->face_id;
query.attrs.scaler.width = type->width;
query.attrs.scaler.height = type->height;
query.attrs.load_flags = (FT_UInt)type->flags;
query.attrs.scaler.pixel = 1;
query.attrs.scaler.x_res = 0; /* make compilers happy */
query.attrs.scaler.y_res = 0;
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
ftc_gnode_compare,
hash, gindex,
&query,
node,
error );
#else
error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
hash, gindex,
FTC_GQUERY( &query ),
&node );
#endif
if ( !error )
{
*aglyph = FTC_INODE( node )->glyph;
if ( anode )
{
*anode = node;
node->ref_count++;
}
}
Exit:
return error;
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_ImageCache_LookupScaler( FTC_ImageCache cache,
FTC_Scaler scaler,
FT_ULong load_flags,
FT_UInt gindex,
FT_Glyph *aglyph,
FTC_Node *anode )
{
FTC_BasicQueryRec query;
FTC_Node node = 0; /* make compiler happy */
FT_Error error;
FT_Offset hash;
/* some argument checks are delayed to `FTC_Cache_Lookup' */
if ( !aglyph || !scaler )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
*aglyph = NULL;
if ( anode )
*anode = NULL;
/*
* Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
* but public `FT_Face->face_flags' is of type `FT_Long'.
*
* On long > int systems, higher bits of load_flags cannot be handled.
*/
#if FT_ULONG_MAX > FT_UINT_MAX
if ( load_flags > FT_UINT_MAX )
FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
" higher bits in load_flags 0x%lx are dropped\n",
load_flags & ~((FT_ULong)FT_UINT_MAX) ));
#endif
query.attrs.scaler = scaler[0];
query.attrs.load_flags = (FT_UInt)load_flags;
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
ftc_gnode_compare,
hash, gindex,
&query,
node,
error );
if ( !error )
{
*aglyph = FTC_INODE( node )->glyph;
if ( anode )
{
*anode = node;
node->ref_count++;
}
}
Exit:
return error;
}
/*
*
* basic small bitmap cache
*
*/
static
const FTC_SFamilyClassRec ftc_basic_sbit_family_class =
{
{
sizeof ( FTC_BasicFamilyRec ),
ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */
ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */
NULL, /* FTC_MruNode_ResetFunc node_reset */
NULL /* FTC_MruNode_DoneFunc node_done */
},
ftc_basic_family_get_count,
ftc_basic_family_load_bitmap
};
static
const FTC_GCacheClassRec ftc_basic_sbit_cache_class =
{
{
ftc_snode_new, /* FTC_Node_NewFunc node_new */
ftc_snode_weight, /* FTC_Node_WeightFunc node_weight */
ftc_snode_compare, /* FTC_Node_CompareFunc node_compare */
ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */
ftc_snode_free, /* FTC_Node_FreeFunc node_free */
sizeof ( FTC_GCacheRec ),
ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */
ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */
},
(FTC_MruListClass)&ftc_basic_sbit_family_class
};
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_New( FTC_Manager manager,
FTC_SBitCache *acache )
{
return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
(FTC_GCache*)acache );
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_Lookup( FTC_SBitCache cache,
FTC_ImageType type,
FT_UInt gindex,
FTC_SBit *ansbit,
FTC_Node *anode )
{
FT_Error error;
FTC_BasicQueryRec query;
FTC_Node node = 0; /* make compiler happy */
FT_Offset hash;
if ( anode )
*anode = NULL;
/* other argument checks delayed to `FTC_Cache_Lookup' */
if ( !ansbit )
return FT_THROW( Invalid_Argument );
*ansbit = NULL;
/*
* Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
* but public `FT_ImageType->flags' is of type `FT_Int32'.
*
* On 16bit systems, higher bits of type->flags cannot be handled.
*/
#if 0xFFFFFFFFUL > FT_UINT_MAX
if ( (type->flags & (FT_ULong)FT_UINT_MAX) )
FT_TRACE1(( "FTC_ImageCache_Lookup:"
" higher bits in load_flags 0x%lx are dropped\n",
(FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
#endif
query.attrs.scaler.face_id = type->face_id;
query.attrs.scaler.width = type->width;
query.attrs.scaler.height = type->height;
query.attrs.load_flags = (FT_UInt)type->flags;
query.attrs.scaler.pixel = 1;
query.attrs.scaler.x_res = 0; /* make compilers happy */
query.attrs.scaler.y_res = 0;
/* beware, the hash must be the same for all glyph ranges! */
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
gindex / FTC_SBIT_ITEMS_PER_NODE;
#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
ftc_snode_compare,
hash, gindex,
&query,
node,
error );
#else
error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
hash,
gindex,
FTC_GQUERY( &query ),
&node );
#endif
if ( error )
goto Exit;
*ansbit = FTC_SNODE( node )->sbits +
( gindex - FTC_GNODE( node )->gindex );
if ( anode )
{
*anode = node;
node->ref_count++;
}
Exit:
return error;
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_LookupScaler( FTC_SBitCache cache,
FTC_Scaler scaler,
FT_ULong load_flags,
FT_UInt gindex,
FTC_SBit *ansbit,
FTC_Node *anode )
{
FT_Error error;
FTC_BasicQueryRec query;
FTC_Node node = 0; /* make compiler happy */
FT_Offset hash;
if ( anode )
*anode = NULL;
/* other argument checks delayed to `FTC_Cache_Lookup' */
if ( !ansbit || !scaler )
return FT_THROW( Invalid_Argument );
*ansbit = NULL;
/*
* Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt',
* but public `FT_Face->face_flags' is of type `FT_Long'.
*
* On long > int systems, higher bits of load_flags cannot be handled.
*/
#if FT_ULONG_MAX > FT_UINT_MAX
if ( load_flags > FT_UINT_MAX )
FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
" higher bits in load_flags 0x%lx are dropped\n",
load_flags & ~((FT_ULong)FT_UINT_MAX) ));
#endif
query.attrs.scaler = scaler[0];
query.attrs.load_flags = (FT_UInt)load_flags;
/* beware, the hash must be the same for all glyph ranges! */
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
gindex / FTC_SBIT_ITEMS_PER_NODE;
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
ftc_snode_compare,
hash, gindex,
&query,
node,
error );
if ( error )
goto Exit;
*ansbit = FTC_SNODE( node )->sbits +
( gindex - FTC_GNODE( node )->gindex );
if ( anode )
{
*anode = node;
node->ref_count++;
}
Exit:
return error;
}
/* END */

View file

@ -0,0 +1,599 @@
/****************************************************************************
*
* ftccache.c
*
* The FreeType internal cache interface (body).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include "ftcmanag.h"
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include "ftccback.h"
#include "ftcerror.h"
#undef FT_COMPONENT
#define FT_COMPONENT cache
#define FTC_HASH_MAX_LOAD 2
#define FTC_HASH_MIN_LOAD 1
#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD )
/* this one _must_ be a power of 2! */
#define FTC_HASH_INITIAL_SIZE 8
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CACHE NODE DEFINITIONS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* add a new node to the head of the manager's circular MRU list */
static void
ftc_node_mru_link( FTC_Node node,
FTC_Manager manager )
{
void *nl = &manager->nodes_list;
FTC_MruNode_Prepend( (FTC_MruNode*)nl,
(FTC_MruNode)node );
manager->num_nodes++;
}
/* remove a node from the manager's MRU list */
static void
ftc_node_mru_unlink( FTC_Node node,
FTC_Manager manager )
{
void *nl = &manager->nodes_list;
FTC_MruNode_Remove( (FTC_MruNode*)nl,
(FTC_MruNode)node );
manager->num_nodes--;
}
#ifndef FTC_INLINE
/* move a node to the head of the manager's MRU list */
static void
ftc_node_mru_up( FTC_Node node,
FTC_Manager manager )
{
FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list,
(FTC_MruNode)node );
}
/* get a top bucket for specified hash from cache,
* body for FTC_NODE_TOP_FOR_HASH( cache, hash )
*/
FT_LOCAL_DEF( FTC_Node* )
ftc_get_top_node_for_hash( FTC_Cache cache,
FT_Offset hash )
{
FT_Offset idx;
idx = hash & cache->mask;
if ( idx >= cache->p )
idx = hash & ( cache->mask >> 1 );
return cache->buckets + idx;
}
#endif /* !FTC_INLINE */
/* Note that this function cannot fail. If we cannot re-size the
* buckets array appropriately, we simply degrade the hash table's
* performance!
*/
static void
ftc_cache_resize( FTC_Cache cache )
{
for (;;)
{
FTC_Node node, *pnode;
FT_UFast p = cache->p;
FT_UFast size = cache->mask + 1; /* available size */
FT_UFast half = size >> 1;
/* do we need to expand the buckets array? */
if ( cache->slack < 0 )
{
FTC_Node new_list = NULL;
/* try to expand the buckets array _before_ splitting
* the bucket lists
*/
if ( p == size )
{
FT_Memory memory = cache->memory;
FT_Error error;
/* if we can't expand the array, leave immediately */
if ( FT_QRENEW_ARRAY( cache->buckets, size, size * 2 ) )
break;
cache->mask = 2 * size - 1;
half = size;
}
/* the bucket to split */
pnode = cache->buckets + p - half;
for (;;)
{
node = *pnode;
if ( !node )
break;
if ( node->hash & half )
{
*pnode = node->link;
node->link = new_list;
new_list = node;
}
else
pnode = &node->link;
}
cache->buckets[p] = new_list;
cache->slack += FTC_HASH_MAX_LOAD;
cache->p = p + 1;
FT_TRACE2(( "ftc_cache_resize: cache %u increased to %u hashes\n",
cache->index, cache->p ));
}
/* do we need to shrink the buckets array? */
else if ( cache->slack > (FT_Long)p * FTC_HASH_SUB_LOAD )
{
FTC_Node old_list = cache->buckets[--p];
if ( p < FTC_HASH_INITIAL_SIZE )
break;
if ( p == half )
{
FT_Memory memory = cache->memory;
FT_Error error;
/* if we can't shrink the array, leave immediately */
if ( FT_QRENEW_ARRAY( cache->buckets, size, half ) )
break;
cache->mask = half - 1;
}
/* the bucket to merge */
pnode = cache->buckets + p - half;
while ( *pnode )
pnode = &(*pnode)->link;
*pnode = old_list;
cache->slack -= FTC_HASH_MAX_LOAD;
cache->p = p;
FT_TRACE2(( "ftc_cache_resize: cache %u decreased to %u hashes\n",
cache->index, cache->p ));
}
/* otherwise, the hash table is balanced */
else
break;
}
}
/* remove a node from its cache's hash table */
static void
ftc_node_hash_unlink( FTC_Node node0,
FTC_Cache cache )
{
FTC_Node *pnode = FTC_NODE_TOP_FOR_HASH( cache, node0->hash );
for (;;)
{
FTC_Node node = *pnode;
if ( !node )
{
FT_TRACE0(( "ftc_node_hash_unlink: unknown node\n" ));
return;
}
if ( node == node0 )
break;
pnode = &node->link;
}
*pnode = node0->link;
node0->link = NULL;
cache->slack++;
ftc_cache_resize( cache );
}
/* add a node to the `top' of its cache's hash table */
static void
ftc_node_hash_link( FTC_Node node,
FTC_Cache cache )
{
FTC_Node *pnode = FTC_NODE_TOP_FOR_HASH( cache, node->hash );
node->link = *pnode;
*pnode = node;
cache->slack--;
ftc_cache_resize( cache );
}
/* remove a node from the cache manager */
FT_LOCAL_DEF( void )
ftc_node_destroy( FTC_Node node,
FTC_Manager manager )
{
FTC_Cache cache;
#ifdef FT_DEBUG_ERROR
/* find node's cache */
if ( node->cache_index >= manager->num_caches )
{
FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" ));
return;
}
#endif
cache = manager->caches[node->cache_index];
#ifdef FT_DEBUG_ERROR
if ( !cache )
{
FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" ));
return;
}
#endif
manager->cur_weight -= cache->clazz.node_weight( node, cache );
/* remove node from mru list */
ftc_node_mru_unlink( node, manager );
/* remove node from cache's hash table */
ftc_node_hash_unlink( node, cache );
/* now finalize it */
cache->clazz.node_free( node, cache );
#if 0
/* check, just in case of general corruption :-) */
if ( manager->num_nodes == 0 )
FT_TRACE0(( "ftc_node_destroy: invalid cache node count (%u)\n",
manager->num_nodes ));
#endif
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** ABSTRACT CACHE CLASS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL_DEF( FT_Error )
ftc_cache_init( FTC_Cache cache )
{
FT_Memory memory = cache->memory;
FT_Error error;
cache->p = FTC_HASH_INITIAL_SIZE;
cache->mask = FTC_HASH_INITIAL_SIZE - 1;
cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE );
return error;
}
FT_LOCAL_DEF( FT_Error )
FTC_Cache_Init( FTC_Cache cache )
{
return ftc_cache_init( cache );
}
FT_LOCAL_DEF( void )
ftc_cache_done( FTC_Cache cache )
{
FT_Memory memory = cache->memory;
if ( cache->buckets )
{
FTC_Manager manager = cache->manager;
FT_UFast count = cache->p;
FT_UFast i;
for ( i = 0; i < count; i++ )
{
FTC_Node node = cache->buckets[i], next;
while ( node )
{
next = node->link;
node->link = NULL;
/* remove node from mru list */
ftc_node_mru_unlink( node, manager );
/* now finalize it */
manager->cur_weight -= cache->clazz.node_weight( node, cache );
cache->clazz.node_free( node, cache );
node = next;
}
}
}
FT_FREE( cache->buckets );
cache->p = 0;
cache->mask = 0;
cache->slack = 0;
}
FT_LOCAL_DEF( void )
FTC_Cache_Done( FTC_Cache cache )
{
ftc_cache_done( cache );
}
static void
ftc_cache_add( FTC_Cache cache,
FT_Offset hash,
FTC_Node node )
{
node->hash = hash;
node->cache_index = (FT_UShort)cache->index;
node->ref_count = 0;
ftc_node_hash_link( node, cache );
ftc_node_mru_link( node, cache->manager );
{
FTC_Manager manager = cache->manager;
manager->cur_weight += cache->clazz.node_weight( node, cache );
if ( manager->cur_weight >= manager->max_weight )
{
node->ref_count++;
FTC_Manager_Compress( manager );
node->ref_count--;
}
}
}
FT_LOCAL_DEF( FT_Error )
FTC_Cache_NewNode( FTC_Cache cache,
FT_Offset hash,
FT_Pointer query,
FTC_Node *anode )
{
FT_Error error;
FTC_Node node;
/*
* We use the FTC_CACHE_TRYLOOP macros to support out-of-memory
* errors (OOM) correctly, i.e., by flushing the cache progressively
* in order to make more room.
*/
FTC_CACHE_TRYLOOP( cache )
{
error = cache->clazz.node_new( &node, query, cache );
}
FTC_CACHE_TRYLOOP_END( NULL )
if ( error )
node = NULL;
else
{
/* don't assume that the cache has the same number of buckets, since
* our allocation request might have triggered global cache flushing
*/
ftc_cache_add( cache, hash, node );
}
*anode = node;
return error;
}
#ifndef FTC_INLINE
FT_LOCAL_DEF( FT_Error )
FTC_Cache_Lookup( FTC_Cache cache,
FT_Offset hash,
FT_Pointer query,
FTC_Node *anode )
{
FTC_Node* bucket;
FTC_Node* pnode;
FTC_Node node;
FT_Error error = FT_Err_Ok;
FT_Bool list_changed = FALSE;
FTC_Node_CompareFunc compare = cache->clazz.node_compare;
if ( !cache || !anode )
return FT_THROW( Invalid_Argument );
/* Go to the `top' node of the list sharing same masked hash */
bucket = pnode = FTC_NODE_TOP_FOR_HASH( cache, hash );
/* Lookup a node with exactly same hash and queried properties. */
/* NOTE: _nodcomp() may change the linked list to reduce memory. */
for (;;)
{
node = *pnode;
if ( !node )
goto NewNode;
if ( node->hash == hash &&
compare( node, query, cache, &list_changed ) )
break;
pnode = &node->link;
}
if ( list_changed )
{
/* Update bucket by modified linked list */
bucket = pnode = FTC_NODE_TOP_FOR_HASH( cache, hash );
/* Update pnode by modified linked list */
while ( *pnode != node )
{
if ( !*pnode )
{
FT_ERROR(( "FTC_Cache_Lookup: oops!!! node missing\n" ));
goto NewNode;
}
else
pnode = &(*pnode)->link;
}
}
/* Reorder the list to move the found node to the `top' */
if ( node != *bucket )
{
*pnode = node->link;
node->link = *bucket;
*bucket = node;
}
/* move to head of MRU list */
{
FTC_Manager manager = cache->manager;
if ( node != manager->nodes_list )
ftc_node_mru_up( node, manager );
}
*anode = node;
return error;
NewNode:
return FTC_Cache_NewNode( cache, hash, query, anode );
}
#endif /* !FTC_INLINE */
FT_LOCAL_DEF( void )
FTC_Cache_RemoveFaceID( FTC_Cache cache,
FTC_FaceID face_id )
{
FTC_Manager manager = cache->manager;
FTC_Node frees = NULL;
FT_UFast count = cache->p;
FT_UFast i;
for ( i = 0; i < count; i++ )
{
FTC_Node* pnode = cache->buckets + i;
for (;;)
{
FTC_Node node = *pnode;
FT_Bool list_changed = FALSE;
if ( !node )
break;
if ( cache->clazz.node_remove_faceid( node, face_id,
cache, &list_changed ) )
{
*pnode = node->link;
node->link = frees;
frees = node;
}
else
pnode = &node->link;
}
}
/* remove all nodes in the free list */
while ( frees )
{
FTC_Node node;
node = frees;
frees = node->link;
manager->cur_weight -= cache->clazz.node_weight( node, cache );
ftc_node_mru_unlink( node, manager );
cache->clazz.node_free( node, cache );
cache->slack++;
}
ftc_cache_resize( cache );
}
/* END */

View file

@ -0,0 +1,355 @@
/****************************************************************************
*
* ftccache.h
*
* FreeType internal cache interface (specification).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef FTCCACHE_H_
#define FTCCACHE_H_
#include <freetype/internal/compiler-macros.h>
#include "ftcmru.h"
FT_BEGIN_HEADER
#define FTC_FACE_ID_HASH( i ) \
( ( (FT_Offset)(i) >> 3 ) ^ ( (FT_Offset)(i) << 7 ) )
/* handle to cache object */
typedef struct FTC_CacheRec_* FTC_Cache;
/* handle to cache class */
typedef const struct FTC_CacheClassRec_* FTC_CacheClass;
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CACHE NODE DEFINITIONS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/**************************************************************************
*
* Each cache controls one or more cache nodes. Each node is part of
* the global_lru list of the manager. Its `data' field however is used
* as a reference count for now.
*
* A node can be anything, depending on the type of information held by
* the cache. It can be an individual glyph image, a set of bitmaps
* glyphs for a given size, some metrics, etc.
*
*/
/* structure size should be 20 bytes on 32-bits machines */
typedef struct FTC_NodeRec_
{
FTC_MruNodeRec mru; /* circular mru list pointer */
FTC_Node link; /* used for hashing */
FT_Offset hash; /* used for hashing too */
FT_UShort cache_index; /* index of cache the node belongs to */
FT_Short ref_count; /* reference count for this node */
} FTC_NodeRec;
#define FTC_NODE( x ) ( (FTC_Node)(x) )
#define FTC_NODE_P( x ) ( (FTC_Node*)(x) )
#define FTC_NODE_NEXT( x ) FTC_NODE( (x)->mru.next )
#define FTC_NODE_PREV( x ) FTC_NODE( (x)->mru.prev )
/* address the hash table entries */
#ifdef FTC_INLINE
#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \
( ( cache )->buckets + \
( ( ( ( hash ) & ( cache )->mask ) >= ( cache )->p ) \
? ( ( hash ) & ( ( cache )->mask >> 1 ) ) \
: ( ( hash ) & ( cache )->mask ) ) )
#else
FT_LOCAL( FTC_Node* )
ftc_get_top_node_for_hash( FTC_Cache cache,
FT_Offset hash );
#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \
ftc_get_top_node_for_hash( ( cache ), ( hash ) )
#endif
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CACHE DEFINITIONS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* initialize a new cache node */
typedef FT_Error
(*FTC_Node_NewFunc)( FTC_Node *pnode,
FT_Pointer query,
FTC_Cache cache );
typedef FT_Offset
(*FTC_Node_WeightFunc)( FTC_Node node,
FTC_Cache cache );
/* compare a node to a given key pair */
typedef FT_Bool
(*FTC_Node_CompareFunc)( FTC_Node node,
FT_Pointer key,
FTC_Cache cache,
FT_Bool* list_changed );
typedef void
(*FTC_Node_FreeFunc)( FTC_Node node,
FTC_Cache cache );
typedef FT_Error
(*FTC_Cache_InitFunc)( FTC_Cache cache );
typedef void
(*FTC_Cache_DoneFunc)( FTC_Cache cache );
typedef struct FTC_CacheClassRec_
{
FTC_Node_NewFunc node_new;
FTC_Node_WeightFunc node_weight;
FTC_Node_CompareFunc node_compare;
FTC_Node_CompareFunc node_remove_faceid;
FTC_Node_FreeFunc node_free;
FT_Offset cache_size;
FTC_Cache_InitFunc cache_init;
FTC_Cache_DoneFunc cache_done;
} FTC_CacheClassRec;
/* each cache really implements a hash table to manage its nodes */
/* the number of the table entries (buckets) can change dynamically */
/* each bucket contains a linked lists of nodes for a given hash */
typedef struct FTC_CacheRec_
{
FT_UFast p; /* hash table counter */
FT_UFast mask; /* hash table index range */
FT_Long slack;
FTC_Node* buckets;
FTC_CacheClassRec clazz; /* local copy, for speed */
FTC_Manager manager;
FT_Memory memory;
FT_UInt index; /* in manager's table */
FTC_CacheClass org_class; /* original class pointer */
} FTC_CacheRec;
#define FTC_CACHE( x ) ( (FTC_Cache)(x) )
#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) )
/* default cache initialize */
FT_LOCAL( FT_Error )
FTC_Cache_Init( FTC_Cache cache );
/* default cache finalizer */
FT_LOCAL( void )
FTC_Cache_Done( FTC_Cache cache );
/* Call this function to look up the cache. If no corresponding
* node is found, a new one is automatically created. This function
* is capable of flushing the cache adequately to make room for the
* new cache object.
*/
#ifndef FTC_INLINE
FT_LOCAL( FT_Error )
FTC_Cache_Lookup( FTC_Cache cache,
FT_Offset hash,
FT_Pointer query,
FTC_Node *anode );
#endif
FT_LOCAL( FT_Error )
FTC_Cache_NewNode( FTC_Cache cache,
FT_Offset hash,
FT_Pointer query,
FTC_Node *anode );
/* Remove all nodes that relate to a given face_id. This is useful
* when un-installing fonts. Note that if a cache node relates to
* the face_id but is locked (i.e., has `ref_count > 0'), the node
* will _not_ be destroyed, but its internal face_id reference will
* be modified.
*
* The final result will be that the node will never come back
* in further lookup requests, and will be flushed on demand from
* the cache normally when its reference count reaches 0.
*/
FT_LOCAL( void )
FTC_Cache_RemoveFaceID( FTC_Cache cache,
FTC_FaceID face_id );
#ifdef FTC_INLINE
#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \
FT_BEGIN_STMNT \
FTC_Node *_bucket, *_pnode, _node; \
FTC_Cache _cache = FTC_CACHE( cache ); \
FT_Offset _hash = (FT_Offset)(hash); \
FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \
FT_Bool _list_changed = FALSE; \
\
\
error = FT_Err_Ok; \
node = NULL; \
\
/* Go to the `top' node of the list sharing same masked hash */ \
_bucket = _pnode = FTC_NODE_TOP_FOR_HASH( _cache, _hash ); \
\
/* Look up a node with identical hash and queried properties. */ \
/* NOTE: _nodcomp() may change the linked list to reduce memory. */ \
for (;;) \
{ \
_node = *_pnode; \
if ( !_node ) \
goto NewNode_; \
\
if ( _node->hash == _hash && \
_nodcomp( _node, query, _cache, &_list_changed ) ) \
break; \
\
_pnode = &_node->link; \
} \
\
if ( _list_changed ) \
{ \
/* Update _bucket by possibly modified linked list */ \
_bucket = _pnode = FTC_NODE_TOP_FOR_HASH( _cache, _hash ); \
\
/* Update _pnode by possibly modified linked list */ \
while ( *_pnode != _node ) \
{ \
if ( !*_pnode ) \
{ \
FT_ERROR(( "FTC_CACHE_LOOKUP_CMP: oops!!! node missing\n" )); \
goto NewNode_; \
} \
else \
_pnode = &(*_pnode)->link; \
} \
} \
\
/* Reorder the list to move the found node to the `top' */ \
if ( _node != *_bucket ) \
{ \
*_pnode = _node->link; \
_node->link = *_bucket; \
*_bucket = _node; \
} \
\
/* Update MRU list */ \
{ \
FTC_Manager _manager = _cache->manager; \
void* _nl = &_manager->nodes_list; \
\
\
if ( _node != _manager->nodes_list ) \
FTC_MruNode_Up( (FTC_MruNode*)_nl, \
(FTC_MruNode)_node ); \
} \
goto Ok_; \
\
NewNode_: \
error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \
\
Ok_: \
node = _node; \
FT_END_STMNT
#else /* !FTC_INLINE */
#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \
FT_BEGIN_STMNT \
error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, \
(FTC_Node*)&(node) ); \
FT_END_STMNT
#endif /* !FTC_INLINE */
/*
* This macro, together with FTC_CACHE_TRYLOOP_END, defines a retry
* loop to flush the cache repeatedly in case of memory overflows.
*
* It is used when creating a new cache node, or within a lookup
* that needs to allocate data (e.g. the sbit cache lookup).
*
* Example:
*
* {
* FTC_CACHE_TRYLOOP( cache )
* error = load_data( ... );
* FTC_CACHE_TRYLOOP_END()
* }
*
*/
#define FTC_CACHE_TRYLOOP( cache ) \
{ \
FTC_Manager _try_manager = FTC_CACHE( cache )->manager; \
FT_UInt _try_count = 4; \
\
\
for (;;) \
{ \
FT_UInt _try_done;
#define FTC_CACHE_TRYLOOP_END( list_changed ) \
if ( !error || FT_ERR_NEQ( error, Out_Of_Memory ) ) \
break; \
\
_try_done = FTC_Manager_FlushN( _try_manager, _try_count ); \
if ( _try_done > 0 && list_changed != NULL ) \
*(FT_Bool*)( list_changed ) = TRUE; \
\
if ( _try_done == 0 ) \
break; \
\
if ( _try_done == _try_count ) \
{ \
_try_count *= 2; \
if ( _try_count < _try_done || \
_try_count > _try_manager->num_nodes ) \
_try_count = _try_manager->num_nodes; \
} \
} \
}
/* */
FT_END_HEADER
#endif /* FTCCACHE_H_ */
/* END */

View file

@ -0,0 +1,93 @@
/****************************************************************************
*
* ftccback.h
*
* Callback functions of the caching sub-system (specification only).
*
* Copyright (C) 2004-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#ifndef FTCCBACK_H_
#define FTCCBACK_H_
#include <freetype/ftcache.h>
#include "ftcmru.h"
#include "ftcimage.h"
#include "ftcmanag.h"
#include "ftcglyph.h"
#include "ftcsbits.h"
FT_BEGIN_HEADER
FT_LOCAL( void )
ftc_inode_free( FTC_Node inode,
FTC_Cache cache );
FT_LOCAL( FT_Error )
ftc_inode_new( FTC_Node *pinode,
FT_Pointer gquery,
FTC_Cache cache );
FT_LOCAL( FT_Offset )
ftc_inode_weight( FTC_Node inode,
FTC_Cache cache );
FT_LOCAL( void )
ftc_snode_free( FTC_Node snode,
FTC_Cache cache );
FT_LOCAL( FT_Error )
ftc_snode_new( FTC_Node *psnode,
FT_Pointer gquery,
FTC_Cache cache );
FT_LOCAL( FT_Offset )
ftc_snode_weight( FTC_Node snode,
FTC_Cache cache );
FT_LOCAL( FT_Bool )
ftc_snode_compare( FTC_Node snode,
FT_Pointer gquery,
FTC_Cache cache,
FT_Bool* list_changed );
FT_LOCAL( FT_Bool )
ftc_gnode_compare( FTC_Node gnode,
FT_Pointer gquery,
FTC_Cache cache,
FT_Bool* list_changed );
FT_LOCAL( FT_Error )
ftc_gcache_init( FTC_Cache cache );
FT_LOCAL( void )
ftc_gcache_done( FTC_Cache cache );
FT_LOCAL( FT_Error )
ftc_cache_init( FTC_Cache cache );
FT_LOCAL( void )
ftc_cache_done( FTC_Cache cache );
FT_LOCAL( void )
ftc_node_destroy( FTC_Node node,
FTC_Manager manager );
FT_END_HEADER
#endif /* FTCCBACK_H_ */
/* END */

View file

@ -0,0 +1,323 @@
/****************************************************************************
*
* ftccmap.c
*
* FreeType CharMap cache (body)
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/freetype.h>
#include <freetype/ftcache.h>
#include "ftcmanag.h"
#include <freetype/internal/ftmemory.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include "ftccback.h"
#include "ftcerror.h"
#undef FT_COMPONENT
#define FT_COMPONENT cache
/**************************************************************************
*
* Each FTC_CMapNode contains a simple array to map a range of character
* codes to equivalent glyph indices.
*
* For now, the implementation is very basic: Each node maps a range of
* 128 consecutive character codes to their corresponding glyph indices.
*
* We could do more complex things, but I don't think it is really very
* useful.
*
*/
/* number of glyph indices / character code per node */
#define FTC_CMAP_INDICES_MAX 128
/* compute a query/node hash */
#define FTC_CMAP_HASH( faceid, index, charcode ) \
( FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \
( (charcode) / FTC_CMAP_INDICES_MAX ) )
/* the charmap query */
typedef struct FTC_CMapQueryRec_
{
FTC_FaceID face_id;
FT_UInt cmap_index;
FT_UInt32 char_code;
} FTC_CMapQueryRec, *FTC_CMapQuery;
#define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x))
/* the cmap cache node */
typedef struct FTC_CMapNodeRec_
{
FTC_NodeRec node;
FTC_FaceID face_id;
FT_UInt cmap_index;
FT_UInt32 first; /* first character in node */
FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
} FTC_CMapNodeRec, *FTC_CMapNode;
#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
/* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
/* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
#define FTC_CMAP_UNKNOWN (FT_UInt16)~0
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CHARMAP NODES *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_CALLBACK_DEF( void )
ftc_cmap_node_free( FTC_Node ftcnode,
FTC_Cache cache )
{
FTC_CMapNode node = (FTC_CMapNode)ftcnode;
FT_Memory memory = cache->memory;
FT_FREE( node );
}
/* initialize a new cmap node */
FT_CALLBACK_DEF( FT_Error )
ftc_cmap_node_new( FTC_Node *ftcanode,
FT_Pointer ftcquery,
FTC_Cache cache )
{
FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode;
FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
FT_Error error;
FT_Memory memory = cache->memory;
FTC_CMapNode node = NULL;
FT_UInt nn;
if ( !FT_QNEW( node ) )
{
node->face_id = query->face_id;
node->cmap_index = query->cmap_index;
node->first = (query->char_code / FTC_CMAP_INDICES_MAX) *
FTC_CMAP_INDICES_MAX;
for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
node->indices[nn] = FTC_CMAP_UNKNOWN;
}
*anode = node;
return error;
}
/* compute the weight of a given cmap node */
FT_CALLBACK_DEF( FT_Offset )
ftc_cmap_node_weight( FTC_Node cnode,
FTC_Cache cache )
{
FT_UNUSED( cnode );
FT_UNUSED( cache );
return sizeof ( *cnode );
}
/* compare a cmap node to a given query */
FT_CALLBACK_DEF( FT_Bool )
ftc_cmap_node_compare( FTC_Node ftcnode,
FT_Pointer ftcquery,
FTC_Cache cache,
FT_Bool* list_changed )
{
FTC_CMapNode node = (FTC_CMapNode)ftcnode;
FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
FT_UNUSED( cache );
if ( list_changed )
*list_changed = FALSE;
if ( node->face_id == query->face_id &&
node->cmap_index == query->cmap_index )
{
FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first );
return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
}
return 0;
}
FT_CALLBACK_DEF( FT_Bool )
ftc_cmap_node_remove_faceid( FTC_Node ftcnode,
FT_Pointer ftcface_id,
FTC_Cache cache,
FT_Bool* list_changed )
{
FTC_CMapNode node = (FTC_CMapNode)ftcnode;
FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
FT_UNUSED( cache );
if ( list_changed )
*list_changed = FALSE;
return FT_BOOL( node->face_id == face_id );
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** GLYPH IMAGE CACHE *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
static
const FTC_CacheClassRec ftc_cmap_cache_class =
{
ftc_cmap_node_new, /* FTC_Node_NewFunc node_new */
ftc_cmap_node_weight, /* FTC_Node_WeightFunc node_weight */
ftc_cmap_node_compare, /* FTC_Node_CompareFunc node_compare */
ftc_cmap_node_remove_faceid, /* FTC_Node_CompareFunc node_remove_faceid */
ftc_cmap_node_free, /* FTC_Node_FreeFunc node_free */
sizeof ( FTC_CacheRec ),
ftc_cache_init, /* FTC_Cache_InitFunc cache_init */
ftc_cache_done, /* FTC_Cache_DoneFunc cache_done */
};
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_CMapCache_New( FTC_Manager manager,
FTC_CMapCache *acache )
{
return FTC_Manager_RegisterCache( manager,
&ftc_cmap_cache_class,
FTC_CACHE_P( acache ) );
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_UInt )
FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache,
FTC_FaceID face_id,
FT_Int cmap_index,
FT_UInt32 char_code )
{
FTC_Cache cache = FTC_CACHE( cmap_cache );
FTC_CMapQueryRec query;
FTC_Node node;
FT_Error error;
FT_UInt gindex = 0;
FT_Offset hash;
FT_Int no_cmap_change = 0;
if ( cmap_index < 0 )
{
/* Treat a negative cmap index as a special value, meaning that you */
/* don't want to change the FT_Face's character map through this */
/* call. This can be useful if the face requester callback already */
/* sets the face's charmap to the appropriate value. */
no_cmap_change = 1;
cmap_index = 0;
}
if ( !cache )
{
FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
return 0;
}
query.face_id = face_id;
query.cmap_index = (FT_UInt)cmap_index;
query.char_code = char_code;
hash = FTC_CMAP_HASH( face_id, (FT_UInt)cmap_index, char_code );
#if 1
FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
node, error );
#else
error = FTC_Cache_Lookup( cache, hash, &query, &node );
#endif
if ( error )
goto Exit;
FT_ASSERT( char_code - FTC_CMAP_NODE( node )->first <
FTC_CMAP_INDICES_MAX );
/* something rotten can happen with rogue clients */
if ( char_code - FTC_CMAP_NODE( node )->first >= FTC_CMAP_INDICES_MAX )
return 0; /* XXX: should return appropriate error */
gindex = FTC_CMAP_NODE( node )->indices[char_code -
FTC_CMAP_NODE( node )->first];
if ( gindex == FTC_CMAP_UNKNOWN )
{
FT_Face face;
gindex = 0;
error = FTC_Manager_LookupFace( cache->manager,
FTC_CMAP_NODE( node )->face_id,
&face );
if ( error )
goto Exit;
if ( cmap_index < face->num_charmaps )
{
FT_CharMap old = face->charmap;
FT_CharMap cmap = face->charmaps[cmap_index];
if ( !no_cmap_change )
face->charmap = cmap;
gindex = FT_Get_Char_Index( face, char_code );
if ( !no_cmap_change )
face->charmap = old;
}
FTC_CMAP_NODE( node )->indices[char_code -
FTC_CMAP_NODE( node )->first]
= (FT_UShort)gindex;
}
Exit:
return gindex;
}
/* END */

View file

@ -0,0 +1,42 @@
/****************************************************************************
*
* ftcerror.h
*
* Caching sub-system error codes (specification only).
*
* Copyright (C) 2001-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* This file is used to define the caching sub-system error enumeration
* constants.
*
*/
#ifndef FTCERROR_H_
#define FTCERROR_H_
#include <freetype/ftmoderr.h>
#undef FTERRORS_H_
#undef FT_ERR_PREFIX
#define FT_ERR_PREFIX FTC_Err_
#define FT_ERR_BASE FT_Mod_Err_Cache
#include <freetype/fterrors.h>
#endif /* FTCERROR_H_ */
/* END */

View file

@ -0,0 +1,204 @@
/****************************************************************************
*
* ftcglyph.c
*
* FreeType Glyph Image (FT_Glyph) cache (body).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftobjs.h>
#include <freetype/ftcache.h>
#include "ftcglyph.h"
#include <freetype/fterrors.h>
#include "ftccback.h"
#include "ftcerror.h"
/* create a new chunk node, setting its cache index and ref count */
FT_LOCAL_DEF( void )
FTC_GNode_Init( FTC_GNode gnode,
FT_UInt gindex,
FTC_Family family )
{
gnode->family = family;
gnode->gindex = gindex;
family->num_nodes++;
}
FT_LOCAL_DEF( void )
FTC_GNode_UnselectFamily( FTC_GNode gnode,
FTC_Cache cache )
{
FTC_Family family = gnode->family;
gnode->family = NULL;
if ( family && --family->num_nodes == 0 )
FTC_FAMILY_FREE( family, cache );
}
FT_LOCAL_DEF( void )
FTC_GNode_Done( FTC_GNode gnode,
FTC_Cache cache )
{
/* finalize the node */
gnode->gindex = 0;
FTC_GNode_UnselectFamily( gnode, cache );
}
FT_LOCAL_DEF( FT_Bool )
ftc_gnode_compare( FTC_Node ftcgnode,
FT_Pointer ftcgquery,
FTC_Cache cache,
FT_Bool* list_changed )
{
FTC_GNode gnode = (FTC_GNode)ftcgnode;
FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
FT_UNUSED( cache );
if ( list_changed )
*list_changed = FALSE;
return FT_BOOL( gnode->family == gquery->family &&
gnode->gindex == gquery->gindex );
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CHUNK SETS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL_DEF( void )
FTC_Family_Init( FTC_Family family,
FTC_Cache cache )
{
FTC_GCacheClass clazz = FTC_CACHE_GCACHE_CLASS( cache );
family->clazz = clazz->family_class;
family->num_nodes = 0;
family->cache = cache;
}
FT_LOCAL_DEF( FT_Error )
ftc_gcache_init( FTC_Cache cache )
{
FTC_GCache gcache = (FTC_GCache)cache;
FT_Error error;
error = FTC_Cache_Init( cache );
if ( !error )
{
FTC_GCacheClass clazz = (FTC_GCacheClass)cache->org_class;
FTC_MruList_Init( &gcache->families,
clazz->family_class,
0, /* no maximum here! */
cache,
cache->memory );
}
return error;
}
#if 0
FT_LOCAL_DEF( FT_Error )
FTC_GCache_Init( FTC_GCache gcache )
{
return ftc_gcache_init( FTC_CACHE( gcache ) );
}
#endif /* 0 */
FT_LOCAL_DEF( void )
ftc_gcache_done( FTC_Cache cache )
{
FTC_GCache gcache = (FTC_GCache)cache;
FTC_Cache_Done( cache );
FTC_MruList_Done( &gcache->families );
}
#if 0
FT_LOCAL_DEF( void )
FTC_GCache_Done( FTC_GCache gcache )
{
ftc_gcache_done( FTC_CACHE( gcache ) );
}
#endif /* 0 */
FT_LOCAL_DEF( FT_Error )
FTC_GCache_New( FTC_Manager manager,
FTC_GCacheClass clazz,
FTC_GCache *acache )
{
return FTC_Manager_RegisterCache( manager, (FTC_CacheClass)clazz,
(FTC_Cache*)acache );
}
#ifndef FTC_INLINE
FT_LOCAL_DEF( FT_Error )
FTC_GCache_Lookup( FTC_GCache gcache,
FT_Offset hash,
FT_UInt gindex,
FTC_GQuery query,
FTC_Node *anode )
{
FT_Error error;
query->gindex = gindex;
FTC_MRULIST_LOOKUP( &cache->families, query, query->family, error );
if ( !error )
{
FTC_Family family = query->family;
/* prevent the family from being destroyed too early when an */
/* out-of-memory condition occurs during glyph node initialization. */
family->num_nodes++;
error = FTC_Cache_Lookup( FTC_CACHE( gcache ), hash, query, anode );
if ( --family->num_nodes == 0 )
FTC_FAMILY_FREE( family, cache );
}
return error;
}
#endif /* !FTC_INLINE */
/* END */

View file

@ -0,0 +1,315 @@
/****************************************************************************
*
* ftcglyph.h
*
* FreeType abstract glyph cache (specification).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/*
*
* FTC_GCache is an _abstract_ cache object optimized to store glyph
* data. It works as follows:
*
* - It manages FTC_GNode objects. Each one of them can hold one or more
* glyph `items'. Item types are not specified in the FTC_GCache but
* in classes that extend it.
*
* - Glyph attributes, like face ID, character size, render mode, etc.,
* can be grouped into abstract `glyph families'. This avoids storing
* the attributes within the FTC_GCache, since it is likely that many
* FTC_GNodes will belong to the same family in typical uses.
*
* - Each FTC_GNode is thus an FTC_Node with two additional fields:
*
* * gindex: A glyph index, or the first index in a glyph range.
* * family: A pointer to a glyph `family'.
*
* - Family types are not fully specific in the FTC_Family type, but
* by classes that extend it.
*
* Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache.
* They share an FTC_Family sub-class called FTC_BasicFamily which is
* used to store the following data: face ID, pixel/point sizes, load
* flags. For more details see the file `src/cache/ftcbasic.c'.
*
* Client applications can extend FTC_GNode with their own FTC_GNode
* and FTC_Family sub-classes to implement more complex caches (e.g.,
* handling automatic synthesis, like obliquing & emboldening, colored
* glyphs, etc.).
*
* See also the FTC_ICache & FTC_SCache classes in `ftcimage.h' and
* `ftcsbits.h', which both extend FTC_GCache with additional
* optimizations.
*
* A typical FTC_GCache implementation must provide at least the
* following:
*
* - FTC_GNode sub-class, e.g. MyNode, with relevant methods:
* my_node_new (must call FTC_GNode_Init)
* my_node_free (must call FTC_GNode_Done)
* my_node_compare (must call ftc_gnode_compare)
* my_node_remove_faceid (must call ftc_gnode_unselect in case
* of match)
*
* - FTC_Family sub-class, e.g. MyFamily, with relevant methods:
* my_family_compare
* my_family_init
* my_family_reset (optional)
* my_family_done
*
* - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query
* data.
*
* - Constant structures for a FTC_GNodeClass.
*
* - MyCacheNew() can be implemented easily as a call to the convenience
* function FTC_GCache_New.
*
* - MyCacheLookup with a call to FTC_GCache_Lookup. This function will
* automatically:
*
* - Search for the corresponding family in the cache, or create
* a new one if necessary. Put it in FTC_GQUERY(myquery).family
*
* - Call FTC_Cache_Lookup.
*
* If it returns NULL, you should create a new node, then call
* ftc_cache_add as usual.
*/
/**************************************************************************
*
* Important: The functions defined in this file are only used to
* implement an abstract glyph cache class. You need to
* provide additional logic to implement a complete cache.
*
*/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/********* *********/
/********* WARNING, THIS IS BETA CODE. *********/
/********* *********/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#ifndef FTCGLYPH_H_
#define FTCGLYPH_H_
#include "ftcmanag.h"
FT_BEGIN_HEADER
/*
* We can group glyphs into `families'. Each family correspond to a
* given face ID, character size, transform, etc.
*
* Families are implemented as MRU list nodes. They are
* reference-counted.
*/
typedef struct FTC_FamilyRec_
{
FTC_MruNodeRec mrunode;
FT_UInt num_nodes; /* current number of nodes in this family */
FTC_Cache cache;
FTC_MruListClass clazz;
} FTC_FamilyRec, *FTC_Family;
#define FTC_FAMILY( x ) ( (FTC_Family)(x) )
#define FTC_FAMILY_P( x ) ( (FTC_Family*)(x) )
typedef struct FTC_GNodeRec_
{
FTC_NodeRec node;
FTC_Family family;
FT_UInt gindex;
} FTC_GNodeRec, *FTC_GNode;
#define FTC_GNODE( x ) ( (FTC_GNode)(x) )
#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) )
typedef struct FTC_GQueryRec_
{
FT_UInt gindex;
FTC_Family family;
} FTC_GQueryRec, *FTC_GQuery;
#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) )
/**************************************************************************
*
* These functions are exported so that they can be called from
* user-provided cache classes; otherwise, they are really part of the
* cache sub-system internals.
*/
/* must be called by derived FTC_Node_InitFunc routines */
FT_LOCAL( void )
FTC_GNode_Init( FTC_GNode node,
FT_UInt gindex, /* glyph index for node */
FTC_Family family );
/* call this function to clear a node's family -- this is necessary */
/* to implement the `node_remove_faceid' cache method correctly */
FT_LOCAL( void )
FTC_GNode_UnselectFamily( FTC_GNode gnode,
FTC_Cache cache );
/* must be called by derived FTC_Node_DoneFunc routines */
FT_LOCAL( void )
FTC_GNode_Done( FTC_GNode node,
FTC_Cache cache );
FT_LOCAL( void )
FTC_Family_Init( FTC_Family family,
FTC_Cache cache );
typedef struct FTC_GCacheRec_
{
FTC_CacheRec cache;
FTC_MruListRec families;
} FTC_GCacheRec, *FTC_GCache;
#define FTC_GCACHE( x ) ((FTC_GCache)(x))
#if 0
/* can be used as @FTC_Cache_InitFunc */
FT_LOCAL( FT_Error )
FTC_GCache_Init( FTC_GCache cache );
#endif
#if 0
/* can be used as @FTC_Cache_DoneFunc */
FT_LOCAL( void )
FTC_GCache_Done( FTC_GCache cache );
#endif
/* the glyph cache class adds fields for the family implementation */
typedef struct FTC_GCacheClassRec_
{
FTC_CacheClassRec clazz;
FTC_MruListClass family_class;
} FTC_GCacheClassRec;
typedef const FTC_GCacheClassRec* FTC_GCacheClass;
#define FTC_GCACHE_CLASS( x ) ((FTC_GCacheClass)(x))
#define FTC_CACHE_GCACHE_CLASS( x ) \
FTC_GCACHE_CLASS( FTC_CACHE( x )->org_class )
#define FTC_CACHE_FAMILY_CLASS( x ) \
( (FTC_MruListClass)FTC_CACHE_GCACHE_CLASS( x )->family_class )
/* convenience function; use it instead of FTC_Manager_Register_Cache */
FT_LOCAL( FT_Error )
FTC_GCache_New( FTC_Manager manager,
FTC_GCacheClass clazz,
FTC_GCache *acache );
#ifndef FTC_INLINE
FT_LOCAL( FT_Error )
FTC_GCache_Lookup( FTC_GCache cache,
FT_Offset hash,
FT_UInt gindex,
FTC_GQuery query,
FTC_Node *anode );
#endif
/* */
#define FTC_FAMILY_FREE( family, cache ) \
FTC_MruList_Remove( &FTC_GCACHE((cache))->families, \
(FTC_MruNode)(family) )
#ifdef FTC_INLINE
#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \
gindex, query, node, error ) \
FT_BEGIN_STMNT \
FTC_GCache _gcache = FTC_GCACHE( cache ); \
FTC_GQuery _gquery = (FTC_GQuery)( query ); \
FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \
FTC_MruNode _mrunode; \
\
\
_gquery->gindex = (gindex); \
\
FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare, \
_mrunode, error ); \
_gquery->family = FTC_FAMILY( _mrunode ); \
if ( !error ) \
{ \
FTC_Family _gqfamily = _gquery->family; \
\
\
_gqfamily->num_nodes++; \
\
FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \
\
if ( --_gqfamily->num_nodes == 0 ) \
FTC_FAMILY_FREE( _gqfamily, _gcache ); \
} \
FT_END_STMNT
/* */
#else /* !FTC_INLINE */
#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \
gindex, query, node, error ) \
FT_BEGIN_STMNT \
\
error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, \
FTC_GQUERY( query ), &node ); \
\
FT_END_STMNT
#endif /* !FTC_INLINE */
FT_END_HEADER
#endif /* FTCGLYPH_H_ */
/* END */

View file

@ -0,0 +1,117 @@
/****************************************************************************
*
* ftcid.c
*
* FreeType API for accessing CID font information.
*
* Copyright (C) 2007-2023 by
* Derek Clegg and Michael Toftdal.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/ftcid.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/services/svcid.h>
/* documentation is in ftcid.h */
FT_EXPORT_DEF( FT_Error )
FT_Get_CID_Registry_Ordering_Supplement( FT_Face face,
const char* *registry,
const char* *ordering,
FT_Int *supplement)
{
FT_Error error;
const char* r = NULL;
const char* o = NULL;
FT_Int s = 0;
error = FT_ERR( Invalid_Argument );
if ( face )
{
FT_Service_CID service;
FT_FACE_FIND_SERVICE( face, service, CID );
if ( service && service->get_ros )
error = service->get_ros( face, &r, &o, &s );
}
if ( registry )
*registry = r;
if ( ordering )
*ordering = o;
if ( supplement )
*supplement = s;
return error;
}
FT_EXPORT_DEF( FT_Error )
FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face,
FT_Bool *is_cid )
{
FT_Error error = FT_ERR( Invalid_Argument );
FT_Bool ic = 0;
if ( face )
{
FT_Service_CID service;
FT_FACE_FIND_SERVICE( face, service, CID );
if ( service && service->get_is_cid )
error = service->get_is_cid( face, &ic);
}
if ( is_cid )
*is_cid = ic;
return error;
}
FT_EXPORT_DEF( FT_Error )
FT_Get_CID_From_Glyph_Index( FT_Face face,
FT_UInt glyph_index,
FT_UInt *cid )
{
FT_Error error = FT_ERR( Invalid_Argument );
FT_UInt c = 0;
if ( face )
{
FT_Service_CID service;
FT_FACE_FIND_SERVICE( face, service, CID );
if ( service && service->get_cid_from_glyph_index )
error = service->get_cid_from_glyph_index( face, glyph_index, &c);
}
if ( cid )
*cid = c;
return error;
}
/* END */

View file

@ -0,0 +1,164 @@
/****************************************************************************
*
* ftcimage.c
*
* FreeType Image cache (body).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/ftcache.h>
#include "ftcimage.h"
#include <freetype/internal/ftmemory.h>
#include <freetype/internal/ftobjs.h>
#include "ftccback.h"
#include "ftcerror.h"
/* finalize a given glyph image node */
FT_LOCAL_DEF( void )
ftc_inode_free( FTC_Node ftcinode,
FTC_Cache cache )
{
FTC_INode inode = (FTC_INode)ftcinode;
FT_Memory memory = cache->memory;
if ( inode->glyph )
{
FT_Done_Glyph( inode->glyph );
inode->glyph = NULL;
}
FTC_GNode_Done( FTC_GNODE( inode ), cache );
FT_FREE( inode );
}
FT_LOCAL_DEF( void )
FTC_INode_Free( FTC_INode inode,
FTC_Cache cache )
{
ftc_inode_free( FTC_NODE( inode ), cache );
}
/* initialize a new glyph image node */
FT_LOCAL_DEF( FT_Error )
FTC_INode_New( FTC_INode *pinode,
FTC_GQuery gquery,
FTC_Cache cache )
{
FT_Memory memory = cache->memory;
FT_Error error;
FTC_INode inode = NULL;
if ( !FT_QNEW( inode ) )
{
FTC_GNode gnode = FTC_GNODE( inode );
FTC_Family family = gquery->family;
FT_UInt gindex = gquery->gindex;
FTC_IFamilyClass clazz = FTC_CACHE_IFAMILY_CLASS( cache );
/* initialize its inner fields */
FTC_GNode_Init( gnode, gindex, family );
inode->glyph = NULL;
/* we will now load the glyph image */
error = clazz->family_load_glyph( family, gindex, cache,
&inode->glyph );
if ( error )
{
FTC_INode_Free( inode, cache );
inode = NULL;
}
}
*pinode = inode;
return error;
}
FT_LOCAL_DEF( FT_Error )
ftc_inode_new( FTC_Node *ftcpinode,
FT_Pointer ftcgquery,
FTC_Cache cache )
{
FTC_INode *pinode = (FTC_INode*)ftcpinode;
FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
return FTC_INode_New( pinode, gquery, cache );
}
FT_LOCAL_DEF( FT_Offset )
ftc_inode_weight( FTC_Node ftcinode,
FTC_Cache ftccache )
{
FTC_INode inode = (FTC_INode)ftcinode;
FT_Offset size = 0;
FT_Glyph glyph = inode->glyph;
FT_UNUSED( ftccache );
switch ( glyph->format )
{
case FT_GLYPH_FORMAT_BITMAP:
{
FT_BitmapGlyph bitg;
bitg = (FT_BitmapGlyph)glyph;
size = bitg->bitmap.rows * (FT_Offset)FT_ABS( bitg->bitmap.pitch ) +
sizeof ( *bitg );
}
break;
case FT_GLYPH_FORMAT_OUTLINE:
{
FT_OutlineGlyph outg;
outg = (FT_OutlineGlyph)glyph;
size = (FT_Offset)outg->outline.n_points *
( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) +
(FT_Offset)outg->outline.n_contours * sizeof ( FT_Short ) +
sizeof ( *outg );
}
break;
default:
;
}
size += sizeof ( *inode );
return size;
}
#if 0
FT_LOCAL_DEF( FT_Offset )
FTC_INode_Weight( FTC_INode inode )
{
return ftc_inode_weight( FTC_NODE( inode ), NULL );
}
#endif /* 0 */
/* END */

View file

@ -0,0 +1,106 @@
/****************************************************************************
*
* ftcimage.h
*
* FreeType Generic Image cache (specification)
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/*
* FTC_ICache is an _abstract_ cache used to store a single FT_Glyph
* image per cache node.
*
* FTC_ICache extends FTC_GCache. For an implementation example,
* see FTC_ImageCache in `src/cache/ftbasic.c'.
*/
/**************************************************************************
*
* Each image cache really manages FT_Glyph objects.
*
*/
#ifndef FTCIMAGE_H_
#define FTCIMAGE_H_
#include <freetype/ftcache.h>
#include "ftcglyph.h"
FT_BEGIN_HEADER
/* the FT_Glyph image node type - we store only 1 glyph per node */
typedef struct FTC_INodeRec_
{
FTC_GNodeRec gnode;
FT_Glyph glyph;
} FTC_INodeRec, *FTC_INode;
#define FTC_INODE( x ) ( (FTC_INode)( x ) )
#define FTC_INODE_GINDEX( x ) FTC_GNODE( x )->gindex
#define FTC_INODE_FAMILY( x ) FTC_GNODE( x )->family
typedef FT_Error
(*FTC_IFamily_LoadGlyphFunc)( FTC_Family family,
FT_UInt gindex,
FTC_Cache cache,
FT_Glyph *aglyph );
typedef struct FTC_IFamilyClassRec_
{
FTC_MruListClassRec clazz;
FTC_IFamily_LoadGlyphFunc family_load_glyph;
} FTC_IFamilyClassRec;
typedef const FTC_IFamilyClassRec* FTC_IFamilyClass;
#define FTC_IFAMILY_CLASS( x ) ((FTC_IFamilyClass)(x))
#define FTC_CACHE_IFAMILY_CLASS( x ) \
FTC_IFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS( x )->family_class )
/* can be used as a @FTC_Node_FreeFunc */
FT_LOCAL( void )
FTC_INode_Free( FTC_INode inode,
FTC_Cache cache );
/* Can be used as @FTC_Node_NewFunc. `gquery.index' and `gquery.family'
* must be set correctly. This function will call the `family_load_glyph'
* method to load the FT_Glyph into the cache node.
*/
FT_LOCAL( FT_Error )
FTC_INode_New( FTC_INode *pinode,
FTC_GQuery gquery,
FTC_Cache cache );
#if 0
/* can be used as @FTC_Node_WeightFunc */
FT_LOCAL( FT_ULong )
FTC_INode_Weight( FTC_INode inode );
#endif
/* */
FT_END_HEADER
#endif /* FTCIMAGE_H_ */
/* END */

View file

@ -0,0 +1,696 @@
/****************************************************************************
*
* ftcmanag.c
*
* FreeType Cache Manager (body).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/ftcache.h>
#include "ftcmanag.h"
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/ftsizes.h>
#include "ftccback.h"
#include "ftcerror.h"
#undef FT_COMPONENT
#define FT_COMPONENT cache
static FT_Error
ftc_scaler_lookup_size( FTC_Manager manager,
FTC_Scaler scaler,
FT_Size *asize )
{
FT_Face face;
FT_Size size = NULL;
FT_Error error;
error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
if ( error )
goto Exit;
error = FT_New_Size( face, &size );
if ( error )
goto Exit;
FT_Activate_Size( size );
if ( scaler->pixel )
error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
else
error = FT_Set_Char_Size( face,
(FT_F26Dot6)scaler->width,
(FT_F26Dot6)scaler->height,
scaler->x_res,
scaler->y_res );
if ( error )
{
FT_Done_Size( size );
size = NULL;
}
Exit:
*asize = size;
return error;
}
typedef struct FTC_SizeNodeRec_
{
FTC_MruNodeRec node;
FT_Size size;
FTC_ScalerRec scaler;
} FTC_SizeNodeRec, *FTC_SizeNode;
#define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )
FT_CALLBACK_DEF( void )
ftc_size_node_done( FTC_MruNode ftcnode,
FT_Pointer data )
{
FTC_SizeNode node = (FTC_SizeNode)ftcnode;
FT_Size size = node->size;
FT_UNUSED( data );
if ( size )
FT_Done_Size( size );
}
FT_CALLBACK_DEF( FT_Bool )
ftc_size_node_compare( FTC_MruNode ftcnode,
FT_Pointer ftcscaler )
{
FTC_SizeNode node = (FTC_SizeNode)ftcnode;
FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
FTC_Scaler scaler0 = &node->scaler;
if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
{
FT_Activate_Size( node->size );
return 1;
}
return 0;
}
FT_CALLBACK_DEF( FT_Error )
ftc_size_node_init( FTC_MruNode ftcnode,
FT_Pointer ftcscaler,
FT_Pointer ftcmanager )
{
FTC_SizeNode node = (FTC_SizeNode)ftcnode;
FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
FTC_Manager manager = (FTC_Manager)ftcmanager;
node->scaler = scaler[0];
return ftc_scaler_lookup_size( manager, scaler, &node->size );
}
FT_CALLBACK_DEF( FT_Error )
ftc_size_node_reset( FTC_MruNode ftcnode,
FT_Pointer ftcscaler,
FT_Pointer ftcmanager )
{
FTC_SizeNode node = (FTC_SizeNode)ftcnode;
FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
FTC_Manager manager = (FTC_Manager)ftcmanager;
FT_Done_Size( node->size );
node->scaler = scaler[0];
return ftc_scaler_lookup_size( manager, scaler, &node->size );
}
static
const FTC_MruListClassRec ftc_size_list_class =
{
sizeof ( FTC_SizeNodeRec ),
ftc_size_node_compare, /* FTC_MruNode_CompareFunc node_compare */
ftc_size_node_init, /* FTC_MruNode_InitFunc node_init */
ftc_size_node_reset, /* FTC_MruNode_ResetFunc node_reset */
ftc_size_node_done /* FTC_MruNode_DoneFunc node_done */
};
/* helper function used by ftc_face_node_done */
static FT_Bool
ftc_size_node_compare_faceid( FTC_MruNode ftcnode,
FT_Pointer ftcface_id )
{
FTC_SizeNode node = (FTC_SizeNode)ftcnode;
FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
return FT_BOOL( node->scaler.face_id == face_id );
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_Manager_LookupSize( FTC_Manager manager,
FTC_Scaler scaler,
FT_Size *asize )
{
FT_Error error;
FTC_MruNode mrunode;
if ( !asize || !scaler )
return FT_THROW( Invalid_Argument );
*asize = NULL;
if ( !manager )
return FT_THROW( Invalid_Cache_Handle );
#ifdef FTC_INLINE
FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
mrunode, error );
#else
error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode );
#endif
if ( !error )
*asize = FTC_SIZE_NODE( mrunode )->size;
return error;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** FACE MRU IMPLEMENTATION *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct FTC_FaceNodeRec_
{
FTC_MruNodeRec node;
FTC_FaceID face_id;
FT_Face face;
} FTC_FaceNodeRec, *FTC_FaceNode;
#define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
FT_CALLBACK_DEF( FT_Error )
ftc_face_node_init( FTC_MruNode ftcnode,
FT_Pointer ftcface_id,
FT_Pointer ftcmanager )
{
FTC_FaceNode node = (FTC_FaceNode)ftcnode;
FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
FTC_Manager manager = (FTC_Manager)ftcmanager;
FT_Error error;
node->face_id = face_id;
error = manager->request_face( face_id,
manager->library,
manager->request_data,
&node->face );
if ( !error )
{
/* destroy initial size object; it will be re-created later */
if ( node->face->size )
FT_Done_Size( node->face->size );
}
return error;
}
FT_CALLBACK_DEF( void )
ftc_face_node_done( FTC_MruNode ftcnode,
FT_Pointer ftcmanager )
{
FTC_FaceNode node = (FTC_FaceNode)ftcnode;
FTC_Manager manager = (FTC_Manager)ftcmanager;
/* we must begin by removing all scalers for the target face */
/* from the manager's list */
FTC_MruList_RemoveSelection( &manager->sizes,
ftc_size_node_compare_faceid,
node->face_id );
/* all right, we can discard the face now */
FT_Done_Face( node->face );
node->face = NULL;
node->face_id = NULL;
}
FT_CALLBACK_DEF( FT_Bool )
ftc_face_node_compare( FTC_MruNode ftcnode,
FT_Pointer ftcface_id )
{
FTC_FaceNode node = (FTC_FaceNode)ftcnode;
FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
return FT_BOOL( node->face_id == face_id );
}
static
const FTC_MruListClassRec ftc_face_list_class =
{
sizeof ( FTC_FaceNodeRec),
ftc_face_node_compare, /* FTC_MruNode_CompareFunc node_compare */
ftc_face_node_init, /* FTC_MruNode_InitFunc node_init */
NULL, /* FTC_MruNode_ResetFunc node_reset */
ftc_face_node_done /* FTC_MruNode_DoneFunc node_done */
};
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_Manager_LookupFace( FTC_Manager manager,
FTC_FaceID face_id,
FT_Face *aface )
{
FT_Error error;
FTC_MruNode mrunode;
if ( !aface )
return FT_THROW( Invalid_Argument );
*aface = NULL;
if ( !manager )
return FT_THROW( Invalid_Cache_Handle );
/* we break encapsulation for the sake of speed */
#ifdef FTC_INLINE
FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
mrunode, error );
#else
error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode );
#endif
if ( !error )
*aface = FTC_FACE_NODE( mrunode )->face;
return error;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CACHE MANAGER ROUTINES *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_Manager_New( FT_Library library,
FT_UInt max_faces,
FT_UInt max_sizes,
FT_ULong max_bytes,
FTC_Face_Requester requester,
FT_Pointer req_data,
FTC_Manager *amanager )
{
FT_Error error;
FT_Memory memory;
FTC_Manager manager = NULL;
if ( !library )
return FT_THROW( Invalid_Library_Handle );
if ( !amanager || !requester )
return FT_THROW( Invalid_Argument );
memory = library->memory;
if ( FT_QNEW( manager ) )
goto Exit;
if ( max_faces == 0 )
max_faces = FTC_MAX_FACES_DEFAULT;
if ( max_sizes == 0 )
max_sizes = FTC_MAX_SIZES_DEFAULT;
if ( max_bytes == 0 )
max_bytes = FTC_MAX_BYTES_DEFAULT;
manager->library = library;
manager->memory = memory;
manager->max_weight = max_bytes;
manager->cur_weight = 0;
manager->request_face = requester;
manager->request_data = req_data;
FTC_MruList_Init( &manager->faces,
&ftc_face_list_class,
max_faces,
manager,
memory );
FTC_MruList_Init( &manager->sizes,
&ftc_size_list_class,
max_sizes,
manager,
memory );
manager->nodes_list = NULL;
manager->num_nodes = 0;
manager->num_caches = 0;
*amanager = manager;
Exit:
return error;
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( void )
FTC_Manager_Done( FTC_Manager manager )
{
FT_Memory memory;
FT_UInt idx;
if ( !manager || !manager->library )
return;
memory = manager->memory;
/* now discard all caches */
for ( idx = manager->num_caches; idx-- > 0; )
{
FTC_Cache cache = manager->caches[idx];
if ( cache )
{
cache->clazz.cache_done( cache );
FT_FREE( cache );
manager->caches[idx] = NULL;
}
}
manager->num_caches = 0;
/* discard faces and sizes */
FTC_MruList_Done( &manager->sizes );
FTC_MruList_Done( &manager->faces );
manager->library = NULL;
manager->memory = NULL;
FT_FREE( manager );
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( void )
FTC_Manager_Reset( FTC_Manager manager )
{
if ( !manager )
return;
FTC_MruList_Reset( &manager->sizes );
FTC_MruList_Reset( &manager->faces );
FTC_Manager_FlushN( manager, manager->num_nodes );
}
#ifdef FT_DEBUG_ERROR
static void
FTC_Manager_Check( FTC_Manager manager )
{
FTC_Node node, first;
first = manager->nodes_list;
/* check node weights */
if ( first )
{
FT_Offset weight = 0;
node = first;
do
{
FTC_Cache cache = manager->caches[node->cache_index];
if ( node->cache_index >= manager->num_caches )
FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %hu\n",
node->cache_index ));
else
weight += cache->clazz.node_weight( node, cache );
node = FTC_NODE_NEXT( node );
} while ( node != first );
if ( weight != manager->cur_weight )
FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
manager->cur_weight, weight ));
}
/* check circular list */
if ( first )
{
FT_UFast count = 0;
node = first;
do
{
count++;
node = FTC_NODE_NEXT( node );
} while ( node != first );
if ( count != manager->num_nodes )
FT_TRACE0(( "FTC_Manager_Check:"
" invalid cache node count %u instead of %u\n",
manager->num_nodes, count ));
}
}
#endif /* FT_DEBUG_ERROR */
/* `Compress' the manager's data, i.e., get rid of old cache nodes */
/* that are not referenced anymore in order to limit the total */
/* memory used by the cache. */
/* documentation is in ftcmanag.h */
FT_LOCAL_DEF( void )
FTC_Manager_Compress( FTC_Manager manager )
{
FTC_Node node, prev, first;
if ( !manager )
return;
first = manager->nodes_list;
#ifdef FT_DEBUG_ERROR
FTC_Manager_Check( manager );
FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %u\n",
manager->cur_weight, manager->max_weight,
manager->num_nodes ));
#endif
if ( manager->cur_weight < manager->max_weight || !first )
return;
/* go to last node -- it's a circular list */
prev = FTC_NODE_PREV( first );
do
{
node = prev;
prev = FTC_NODE_PREV( node );
if ( node->ref_count <= 0 )
ftc_node_destroy( node, manager );
} while ( node != first && manager->cur_weight > manager->max_weight );
}
/* documentation is in ftcmanag.h */
FT_LOCAL_DEF( FT_Error )
FTC_Manager_RegisterCache( FTC_Manager manager,
FTC_CacheClass clazz,
FTC_Cache *acache )
{
FT_Error error = FT_ERR( Invalid_Argument );
FTC_Cache cache = NULL;
if ( manager && clazz && acache )
{
FT_Memory memory = manager->memory;
if ( manager->num_caches >= FTC_MAX_CACHES )
{
error = FT_THROW( Too_Many_Caches );
FT_ERROR(( "FTC_Manager_RegisterCache:"
" too many registered caches\n" ));
goto Exit;
}
if ( !FT_QALLOC( cache, clazz->cache_size ) )
{
cache->manager = manager;
cache->memory = memory;
cache->clazz = clazz[0];
cache->org_class = clazz;
/* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
/* IF IT IS NOT SET CORRECTLY */
cache->index = manager->num_caches;
error = clazz->cache_init( cache );
if ( error )
{
clazz->cache_done( cache );
FT_FREE( cache );
goto Exit;
}
manager->caches[manager->num_caches++] = cache;
}
}
Exit:
if ( acache )
*acache = cache;
return error;
}
FT_LOCAL_DEF( FT_UInt )
FTC_Manager_FlushN( FTC_Manager manager,
FT_UInt count )
{
FTC_Node first = manager->nodes_list;
FTC_Node prev, node;
FT_UInt result = 0;
/* try to remove `count' nodes from the list */
if ( !first || !count )
return result;
/* go to last node -- it's a circular list */
prev = FTC_NODE_PREV( first );
do
{
node = prev;
prev = FTC_NODE_PREV( node );
/* don't touch locked nodes */
if ( node->ref_count <= 0 )
{
ftc_node_destroy( node, manager );
result++;
}
} while ( node != first && result < count );
return result;
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( void )
FTC_Manager_RemoveFaceID( FTC_Manager manager,
FTC_FaceID face_id )
{
FT_UInt nn;
if ( !manager )
return;
/* this will remove all FTC_SizeNode that correspond to
* the face_id as well
*/
FTC_MruList_RemoveSelection( &manager->faces,
ftc_face_node_compare,
face_id );
for ( nn = 0; nn < manager->num_caches; nn++ )
FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
}
/* documentation is in ftcache.h */
FT_EXPORT_DEF( void )
FTC_Node_Unref( FTC_Node node,
FTC_Manager manager )
{
if ( node &&
manager &&
node->cache_index < manager->num_caches )
node->ref_count--;
}
/* END */

View file

@ -0,0 +1,175 @@
/****************************************************************************
*
* ftcmanag.h
*
* FreeType Cache Manager (specification).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* A cache manager is in charge of the following:
*
* - Maintain a mapping between generic FTC_FaceIDs and live FT_Face
* objects. The mapping itself is performed through a user-provided
* callback. However, the manager maintains a small cache of FT_Face
* and FT_Size objects in order to speed up things considerably.
*
* - Manage one or more cache objects. Each cache is in charge of
* holding a varying number of `cache nodes'. Each cache node
* represents a minimal amount of individually accessible cached
* data. For example, a cache node can be an FT_Glyph image
* containing a vector outline, or some glyph metrics, or anything
* else.
*
* Each cache node has a certain size in bytes that is added to the
* total amount of `cache memory' within the manager.
*
* All cache nodes are located in a global LRU list, where the oldest
* node is at the tail of the list.
*
* Each node belongs to a single cache, and includes a reference
* count to avoid destroying it (due to caching).
*
*/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/********* *********/
/********* WARNING, THIS IS BETA CODE. *********/
/********* *********/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#ifndef FTCMANAG_H_
#define FTCMANAG_H_
#include <freetype/ftcache.h>
#include "ftcmru.h"
#include "ftccache.h"
FT_BEGIN_HEADER
/**************************************************************************
*
* @Section:
* cache_subsystem
*
*/
#define FTC_MAX_FACES_DEFAULT 2
#define FTC_MAX_SIZES_DEFAULT 4
#define FTC_MAX_BYTES_DEFAULT 200000L /* ~200kByte by default */
/* maximum number of caches registered in a single manager */
#define FTC_MAX_CACHES 16
typedef struct FTC_ManagerRec_
{
FT_Library library;
FT_Memory memory;
FTC_Node nodes_list;
FT_Offset max_weight;
FT_Offset cur_weight;
FT_UInt num_nodes;
FTC_Cache caches[FTC_MAX_CACHES];
FT_UInt num_caches;
FTC_MruListRec faces;
FTC_MruListRec sizes;
FT_Pointer request_data;
FTC_Face_Requester request_face;
} FTC_ManagerRec;
/**************************************************************************
*
* @Function:
* FTC_Manager_Compress
*
* @Description:
* This function is used to check the state of the cache manager if
* its `num_bytes' field is greater than its `max_bytes' field. It
* will flush as many old cache nodes as possible (ignoring cache
* nodes with a non-zero reference count).
*
* @InOut:
* manager ::
* A handle to the cache manager.
*
* @Note:
* Client applications should not call this function directly. It is
* normally invoked by specific cache implementations.
*
* The reason this function is exported is to allow client-specific
* cache classes.
*/
FT_LOCAL( void )
FTC_Manager_Compress( FTC_Manager manager );
/* try to flush `count' old nodes from the cache; return the number
* of really flushed nodes
*/
FT_LOCAL( FT_UInt )
FTC_Manager_FlushN( FTC_Manager manager,
FT_UInt count );
/* this must be used internally for the moment */
FT_LOCAL( FT_Error )
FTC_Manager_RegisterCache( FTC_Manager manager,
FTC_CacheClass clazz,
FTC_Cache *acache );
/* */
#define FTC_SCALER_COMPARE( a, b ) \
( (a)->face_id == (b)->face_id && \
(a)->width == (b)->width && \
(a)->height == (b)->height && \
((a)->pixel != 0) == ((b)->pixel != 0) && \
( (a)->pixel || \
( (a)->x_res == (b)->x_res && \
(a)->y_res == (b)->y_res ) ) )
#define FTC_SCALER_HASH( q ) \
( FTC_FACE_ID_HASH( (q)->face_id ) + \
(q)->width + (q)->height*7 + \
( (q)->pixel ? 0 : ( (q)->x_res*33 ^ (q)->y_res*61 ) ) )
/* */
FT_END_HEADER
#endif /* FTCMANAG_H_ */
/* END */

View file

@ -0,0 +1,352 @@
/****************************************************************************
*
* ftcmru.c
*
* FreeType MRU support (body).
*
* Copyright (C) 2003-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/ftcache.h>
#include "ftcmru.h"
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include "ftcerror.h"
FT_LOCAL_DEF( void )
FTC_MruNode_Prepend( FTC_MruNode *plist,
FTC_MruNode node )
{
FTC_MruNode first = *plist;
if ( first )
{
FTC_MruNode last = first->prev;
#ifdef FT_DEBUG_ERROR
{
FTC_MruNode cnode = first;
do
{
if ( cnode == node )
{
fprintf( stderr, "FTC_MruNode_Prepend: invalid action\n" );
exit( 2 );
}
cnode = cnode->next;
} while ( cnode != first );
}
#endif
first->prev = node;
last->next = node;
node->next = first;
node->prev = last;
}
else
{
node->next = node;
node->prev = node;
}
*plist = node;
}
FT_LOCAL_DEF( void )
FTC_MruNode_Up( FTC_MruNode *plist,
FTC_MruNode node )
{
FTC_MruNode first = *plist;
FT_ASSERT( first );
if ( first != node )
{
FTC_MruNode prev, next, last;
#ifdef FT_DEBUG_ERROR
{
FTC_MruNode cnode = first;
do
{
if ( cnode == node )
goto Ok;
cnode = cnode->next;
} while ( cnode != first );
fprintf( stderr, "FTC_MruNode_Up: invalid action\n" );
exit( 2 );
Ok:
}
#endif
prev = node->prev;
next = node->next;
prev->next = next;
next->prev = prev;
last = first->prev;
last->next = node;
first->prev = node;
node->next = first;
node->prev = last;
*plist = node;
}
}
FT_LOCAL_DEF( void )
FTC_MruNode_Remove( FTC_MruNode *plist,
FTC_MruNode node )
{
FTC_MruNode first = *plist;
FTC_MruNode prev, next;
FT_ASSERT( first );
#ifdef FT_DEBUG_ERROR
{
FTC_MruNode cnode = first;
do
{
if ( cnode == node )
goto Ok;
cnode = cnode->next;
} while ( cnode != first );
fprintf( stderr, "FTC_MruNode_Remove: invalid action\n" );
exit( 2 );
Ok:
}
#endif
prev = node->prev;
next = node->next;
prev->next = next;
next->prev = prev;
if ( node == next )
{
FT_ASSERT( first == node );
FT_ASSERT( prev == node );
*plist = NULL;
}
else if ( node == first )
*plist = next;
}
FT_LOCAL_DEF( void )
FTC_MruList_Init( FTC_MruList list,
FTC_MruListClass clazz,
FT_UInt max_nodes,
FT_Pointer data,
FT_Memory memory )
{
list->num_nodes = 0;
list->max_nodes = max_nodes;
list->nodes = NULL;
list->clazz = *clazz;
list->data = data;
list->memory = memory;
}
FT_LOCAL_DEF( void )
FTC_MruList_Reset( FTC_MruList list )
{
while ( list->nodes )
FTC_MruList_Remove( list, list->nodes );
FT_ASSERT( list->num_nodes == 0 );
}
FT_LOCAL_DEF( void )
FTC_MruList_Done( FTC_MruList list )
{
FTC_MruList_Reset( list );
}
#ifndef FTC_INLINE
FT_LOCAL_DEF( FTC_MruNode )
FTC_MruList_Find( FTC_MruList list,
FT_Pointer key )
{
FTC_MruNode_CompareFunc compare = list->clazz.node_compare;
FTC_MruNode first, node;
first = list->nodes;
node = NULL;
if ( first )
{
node = first;
do
{
if ( compare( node, key ) )
{
if ( node != first )
FTC_MruNode_Up( &list->nodes, node );
return node;
}
node = node->next;
} while ( node != first);
}
return NULL;
}
#endif
FT_LOCAL_DEF( FT_Error )
FTC_MruList_New( FTC_MruList list,
FT_Pointer key,
FTC_MruNode *anode )
{
FT_Error error;
FTC_MruNode node = NULL;
FT_Memory memory = list->memory;
if ( list->num_nodes >= list->max_nodes && list->max_nodes > 0 )
{
node = list->nodes->prev;
FT_ASSERT( node );
if ( list->clazz.node_reset )
{
FTC_MruNode_Up( &list->nodes, node );
error = list->clazz.node_reset( node, key, list->data );
if ( !error )
goto Exit;
}
FTC_MruNode_Remove( &list->nodes, node );
list->num_nodes--;
if ( list->clazz.node_done )
list->clazz.node_done( node, list->data );
}
/* zero new node in case of node_init failure */
else if ( FT_ALLOC( node, list->clazz.node_size ) )
goto Exit;
error = list->clazz.node_init( node, key, list->data );
if ( error )
goto Fail;
FTC_MruNode_Prepend( &list->nodes, node );
list->num_nodes++;
Exit:
*anode = node;
return error;
Fail:
if ( list->clazz.node_done )
list->clazz.node_done( node, list->data );
FT_FREE( node );
goto Exit;
}
#ifndef FTC_INLINE
FT_LOCAL_DEF( FT_Error )
FTC_MruList_Lookup( FTC_MruList list,
FT_Pointer key,
FTC_MruNode *anode )
{
FTC_MruNode node;
node = FTC_MruList_Find( list, key );
if ( !node )
return FTC_MruList_New( list, key, anode );
*anode = node;
return 0;
}
#endif /* FTC_INLINE */
FT_LOCAL_DEF( void )
FTC_MruList_Remove( FTC_MruList list,
FTC_MruNode node )
{
FTC_MruNode_Remove( &list->nodes, node );
list->num_nodes--;
{
FT_Memory memory = list->memory;
if ( list->clazz.node_done )
list->clazz.node_done( node, list->data );
FT_FREE( node );
}
}
FT_LOCAL_DEF( void )
FTC_MruList_RemoveSelection( FTC_MruList list,
FTC_MruNode_CompareFunc selection,
FT_Pointer key )
{
FTC_MruNode first = list->nodes;
FTC_MruNode prev, node;
if ( !first || !selection )
return;
prev = first->prev;
do
{
node = prev;
prev = node->prev;
if ( selection( node, key ) )
FTC_MruList_Remove( list, node );
} while ( node != first );
}
/* END */

View file

@ -0,0 +1,248 @@
/****************************************************************************
*
* ftcmru.h
*
* Simple MRU list-cache (specification).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/**************************************************************************
*
* An MRU is a list that cannot hold more than a certain number of
* elements (`max_elements'). All elements in the list are sorted in
* least-recently-used order, i.e., the `oldest' element is at the tail
* of the list.
*
* When doing a lookup (either through `Lookup()' or `Lookup_Node()'),
* the list is searched for an element with the corresponding key. If
* it is found, the element is moved to the head of the list and is
* returned.
*
* If no corresponding element is found, the lookup routine will try to
* obtain a new element with the relevant key. If the list is already
* full, the oldest element from the list is discarded and replaced by a
* new one; a new element is added to the list otherwise.
*
* Note that it is possible to pre-allocate the element list nodes.
* This is handy if `max_elements' is sufficiently small, as it saves
* allocations/releases during the lookup process.
*
*/
#ifndef FTCMRU_H_
#define FTCMRU_H_
#include <freetype/freetype.h>
#include <freetype/internal/compiler-macros.h>
#ifdef FREETYPE_H
#error "freetype.h of FreeType 1 has been loaded!"
#error "Please fix the directory search order for header files"
#error "so that freetype.h of FreeType 2 is found first."
#endif
#define xxFT_DEBUG_ERROR
#define FTC_INLINE
FT_BEGIN_HEADER
typedef struct FTC_MruNodeRec_* FTC_MruNode;
typedef struct FTC_MruNodeRec_
{
FTC_MruNode next;
FTC_MruNode prev;
} FTC_MruNodeRec;
FT_LOCAL( void )
FTC_MruNode_Prepend( FTC_MruNode *plist,
FTC_MruNode node );
FT_LOCAL( void )
FTC_MruNode_Up( FTC_MruNode *plist,
FTC_MruNode node );
FT_LOCAL( void )
FTC_MruNode_Remove( FTC_MruNode *plist,
FTC_MruNode node );
typedef struct FTC_MruListRec_* FTC_MruList;
typedef struct FTC_MruListClassRec_ const * FTC_MruListClass;
typedef FT_Bool
(*FTC_MruNode_CompareFunc)( FTC_MruNode node,
FT_Pointer key );
typedef FT_Error
(*FTC_MruNode_InitFunc)( FTC_MruNode node,
FT_Pointer key,
FT_Pointer data );
typedef FT_Error
(*FTC_MruNode_ResetFunc)( FTC_MruNode node,
FT_Pointer key,
FT_Pointer data );
typedef void
(*FTC_MruNode_DoneFunc)( FTC_MruNode node,
FT_Pointer data );
typedef struct FTC_MruListClassRec_
{
FT_Offset node_size;
FTC_MruNode_CompareFunc node_compare;
FTC_MruNode_InitFunc node_init;
FTC_MruNode_ResetFunc node_reset;
FTC_MruNode_DoneFunc node_done;
} FTC_MruListClassRec;
typedef struct FTC_MruListRec_
{
FT_UInt num_nodes;
FT_UInt max_nodes;
FTC_MruNode nodes;
FT_Pointer data;
FTC_MruListClassRec clazz;
FT_Memory memory;
} FTC_MruListRec;
FT_LOCAL( void )
FTC_MruList_Init( FTC_MruList list,
FTC_MruListClass clazz,
FT_UInt max_nodes,
FT_Pointer data,
FT_Memory memory );
FT_LOCAL( void )
FTC_MruList_Reset( FTC_MruList list );
FT_LOCAL( void )
FTC_MruList_Done( FTC_MruList list );
FT_LOCAL( FT_Error )
FTC_MruList_New( FTC_MruList list,
FT_Pointer key,
FTC_MruNode *anode );
FT_LOCAL( void )
FTC_MruList_Remove( FTC_MruList list,
FTC_MruNode node );
FT_LOCAL( void )
FTC_MruList_RemoveSelection( FTC_MruList list,
FTC_MruNode_CompareFunc selection,
FT_Pointer key );
#ifdef FTC_INLINE
#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error ) \
FT_BEGIN_STMNT \
FTC_MruNode* _pfirst = &(list)->nodes; \
FTC_MruNode_CompareFunc _compare = (FTC_MruNode_CompareFunc)(compare); \
FTC_MruNode _first, _node; \
\
\
error = FT_Err_Ok; \
_first = *(_pfirst); \
_node = NULL; \
\
if ( _first ) \
{ \
_node = _first; \
do \
{ \
if ( _compare( _node, (key) ) ) \
{ \
if ( _node != _first ) \
FTC_MruNode_Up( _pfirst, _node ); \
\
node = _node; \
goto MruOk_; \
} \
_node = _node->next; \
\
} while ( _node != _first); \
} \
\
error = FTC_MruList_New( (list), (key), (FTC_MruNode*)(void*)&(node) ); \
MruOk_: \
; \
FT_END_STMNT
#define FTC_MRULIST_LOOKUP( list, key, node, error ) \
FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error )
#else /* !FTC_INLINE */
FT_LOCAL( FTC_MruNode )
FTC_MruList_Find( FTC_MruList list,
FT_Pointer key );
FT_LOCAL( FT_Error )
FTC_MruList_Lookup( FTC_MruList list,
FT_Pointer key,
FTC_MruNode *pnode );
#define FTC_MRULIST_LOOKUP( list, key, node, error ) \
error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) )
#endif /* !FTC_INLINE */
#define FTC_MRULIST_LOOP( list, node ) \
FT_BEGIN_STMNT \
FTC_MruNode _first = (list)->nodes; \
\
\
if ( _first ) \
{ \
FTC_MruNode _node = _first; \
\
\
do \
{ \
*(FTC_MruNode*)&(node) = _node;
#define FTC_MRULIST_LOOP_END() \
_node = _node->next; \
\
} while ( _node != _first ); \
} \
FT_END_STMNT
/* */
FT_END_HEADER
#endif /* FTCMRU_H_ */
/* END */

View file

@ -0,0 +1,156 @@
/****************************************************************************
*
* ftcolor.c
*
* FreeType's glyph color management (body).
*
* Copyright (C) 2018-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/sfnt.h>
#include <freetype/internal/tttypes.h>
#include <freetype/ftcolor.h>
#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
static
const FT_Palette_Data null_palette_data = { 0, NULL, NULL, 0, NULL };
/* documentation is in ftcolor.h */
FT_EXPORT_DEF( FT_Error )
FT_Palette_Data_Get( FT_Face face,
FT_Palette_Data *apalette_data )
{
if ( !face )
return FT_THROW( Invalid_Face_Handle );
if ( !apalette_data)
return FT_THROW( Invalid_Argument );
if ( FT_IS_SFNT( face ) )
*apalette_data = ( (TT_Face)face )->palette_data;
else
*apalette_data = null_palette_data;
return FT_Err_Ok;
}
/* documentation is in ftcolor.h */
FT_EXPORT_DEF( FT_Error )
FT_Palette_Select( FT_Face face,
FT_UShort palette_index,
FT_Color* *apalette )
{
FT_Error error;
TT_Face ttface;
SFNT_Service sfnt;
if ( !face )
return FT_THROW( Invalid_Face_Handle );
if ( !FT_IS_SFNT( face ) )
{
if ( apalette )
*apalette = NULL;
return FT_Err_Ok;
}
ttface = (TT_Face)face;
sfnt = (SFNT_Service)ttface->sfnt;
error = sfnt->set_palette( ttface, palette_index );
if ( error )
return error;
ttface->palette_index = palette_index;
if ( apalette )
*apalette = ttface->palette;
return FT_Err_Ok;
}
/* documentation is in ftcolor.h */
FT_EXPORT_DEF( FT_Error )
FT_Palette_Set_Foreground_Color( FT_Face face,
FT_Color foreground_color )
{
TT_Face ttface;
if ( !face )
return FT_THROW( Invalid_Face_Handle );
if ( !FT_IS_SFNT( face ) )
return FT_Err_Ok;
ttface = (TT_Face)face;
ttface->foreground_color = foreground_color;
ttface->have_foreground_color = 1;
return FT_Err_Ok;
}
#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
FT_EXPORT_DEF( FT_Error )
FT_Palette_Data_Get( FT_Face face,
FT_Palette_Data *apalette_data )
{
FT_UNUSED( face );
FT_UNUSED( apalette_data );
return FT_THROW( Unimplemented_Feature );
}
FT_EXPORT_DEF( FT_Error )
FT_Palette_Select( FT_Face face,
FT_UShort palette_index,
FT_Color* *apalette )
{
FT_UNUSED( face );
FT_UNUSED( palette_index );
FT_UNUSED( apalette );
return FT_THROW( Unimplemented_Feature );
}
FT_EXPORT_DEF( FT_Error )
FT_Palette_Set_Foreground_Color( FT_Face face,
FT_Color foreground_color )
{
FT_UNUSED( face );
FT_UNUSED( foreground_color );
return FT_THROW( Unimplemented_Feature );
}
#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
/* END */

View file

@ -0,0 +1,414 @@
/****************************************************************************
*
* ftcsbits.c
*
* FreeType sbits manager (body).
*
* Copyright (C) 2000-2023 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
#include <freetype/ftcache.h>
#include "ftcsbits.h"
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/fterrors.h>
#include "ftccback.h"
#include "ftcerror.h"
#undef FT_COMPONENT
#define FT_COMPONENT cache
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** SBIT CACHE NODES *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
static FT_Error
ftc_sbit_copy_bitmap( FTC_SBit sbit,
FT_Bitmap* bitmap,
FT_Memory memory )
{
FT_Error error;
FT_Int pitch = bitmap->pitch;
FT_ULong size;
if ( pitch < 0 )
pitch = -pitch;
size = (FT_ULong)pitch * bitmap->rows;
if ( !FT_QALLOC( sbit->buffer, size ) )
FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
return error;
}
FT_LOCAL_DEF( void )
ftc_snode_free( FTC_Node ftcsnode,
FTC_Cache cache )
{
FTC_SNode snode = (FTC_SNode)ftcsnode;
FTC_SBit sbit = snode->sbits;
FT_UInt count = snode->count;
FT_Memory memory = cache->memory;
for ( ; count > 0; sbit++, count-- )
FT_FREE( sbit->buffer );
FTC_GNode_Done( FTC_GNODE( snode ), cache );
FT_FREE( snode );
}
FT_LOCAL_DEF( void )
FTC_SNode_Free( FTC_SNode snode,
FTC_Cache cache )
{
ftc_snode_free( FTC_NODE( snode ), cache );
}
/*
* This function tries to load a small bitmap within a given FTC_SNode.
* Note that it returns a non-zero error code _only_ in the case of
* out-of-memory condition. For all other errors (e.g., corresponding
* to a bad font file), this function will mark the sbit as `unavailable'
* and return a value of 0.
*
* You should also read the comment within the @ftc_snode_compare
* function below to see how out-of-memory is handled during a lookup.
*/
static FT_Error
ftc_snode_load( FTC_SNode snode,
FTC_Manager manager,
FT_UInt gindex,
FT_ULong *asize )
{
FT_Error error;
FTC_GNode gnode = FTC_GNODE( snode );
FTC_Family family = gnode->family;
FT_Face face;
FTC_SBit sbit;
FTC_SFamilyClass clazz;
if ( gindex - gnode->gindex >= snode->count )
{
FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
return FT_THROW( Invalid_Argument );
}
sbit = snode->sbits + ( gindex - gnode->gindex );
clazz = (FTC_SFamilyClass)family->clazz;
error = clazz->family_load_glyph( family, gindex, manager, &face );
if ( error )
goto BadGlyph;
{
FT_Int temp;
FT_GlyphSlot slot = face->glyph;
FT_Bitmap* bitmap = &slot->bitmap;
FT_Pos xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */
if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
{
FT_TRACE0(( "ftc_snode_load:"
" glyph loaded didn't return a bitmap\n" ));
goto BadGlyph;
}
/* Check whether our values fit into 8/16-bit containers! */
/* If this is not the case, our bitmap is too large */
/* and we will leave it as `missing' with sbit.buffer = 0 */
#define CHECK_CHAR( d ) ( temp = (FT_Char)d, (FT_Int) temp == (FT_Int) d )
#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, (FT_UInt)temp == (FT_UInt)d )
#define CHECK_SHRT( d ) ( temp = (FT_Short)d, (FT_Int)temp == (FT_Int) d )
/* horizontal advance in pixels */
xadvance = ( slot->advance.x + 32 ) >> 6;
yadvance = ( slot->advance.y + 32 ) >> 6;
if ( !CHECK_BYTE( bitmap->rows ) ||
!CHECK_BYTE( bitmap->width ) ||
!CHECK_SHRT( bitmap->pitch ) ||
!CHECK_CHAR( slot->bitmap_left ) ||
!CHECK_CHAR( slot->bitmap_top ) ||
!CHECK_CHAR( xadvance ) ||
!CHECK_CHAR( yadvance ) )
{
FT_TRACE2(( "ftc_snode_load:"
" glyph too large for small bitmap cache\n"));
goto BadGlyph;
}
sbit->width = (FT_Byte)bitmap->width;
sbit->height = (FT_Byte)bitmap->rows;
sbit->pitch = (FT_Short)bitmap->pitch;
sbit->left = (FT_Char)slot->bitmap_left;
sbit->top = (FT_Char)slot->bitmap_top;
sbit->xadvance = (FT_Char)xadvance;
sbit->yadvance = (FT_Char)yadvance;
sbit->format = (FT_Byte)bitmap->pixel_mode;
sbit->max_grays = (FT_Byte)( bitmap->num_grays - 1 );
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
{
/* take the bitmap ownership */
sbit->buffer = bitmap->buffer;
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
}
else
{
/* copy the bitmap into a new buffer -- ignore error */
error = ftc_sbit_copy_bitmap( sbit, bitmap, manager->memory );
}
/* now, compute size */
if ( asize )
*asize = (FT_ULong)FT_ABS( sbit->pitch ) * sbit->height;
} /* glyph loading successful */
/* ignore the errors that might have occurred -- */
/* we mark unloaded glyphs with `sbit.buffer == 0' */
/* and `width == 255', `height == 0' */
/* */
if ( error && FT_ERR_NEQ( error, Out_Of_Memory ) )
{
BadGlyph:
sbit->width = 255;
sbit->height = 0;
sbit->buffer = NULL;
error = FT_Err_Ok;
if ( asize )
*asize = 0;
}
return error;
}
FT_LOCAL_DEF( FT_Error )
FTC_SNode_New( FTC_SNode *psnode,
FTC_GQuery gquery,
FTC_Cache cache )
{
FT_Memory memory = cache->memory;
FT_Error error;
FTC_SNode snode = NULL;
FT_UInt gindex = gquery->gindex;
FTC_Family family = gquery->family;
FTC_SFamilyClass clazz = FTC_CACHE_SFAMILY_CLASS( cache );
FT_UInt total;
FT_UInt node_count;
total = clazz->family_get_count( family, cache->manager );
if ( total == 0 || gindex >= total )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
if ( !FT_QNEW( snode ) )
{
FT_UInt count, start;
start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
count = total - start;
if ( count > FTC_SBIT_ITEMS_PER_NODE )
count = FTC_SBIT_ITEMS_PER_NODE;
FTC_GNode_Init( FTC_GNODE( snode ), start, family );
snode->count = count;
for ( node_count = 0; node_count < count; node_count++ )
{
snode->sbits[node_count].width = 255;
snode->sbits[node_count].height = 0;
snode->sbits[node_count].buffer = NULL;
}
error = ftc_snode_load( snode,
cache->manager,
gindex,
NULL );
if ( error )
{
FTC_SNode_Free( snode, cache );
snode = NULL;
}
}
Exit:
*psnode = snode;
return error;
}
FT_LOCAL_DEF( FT_Error )
ftc_snode_new( FTC_Node *ftcpsnode,
FT_Pointer ftcgquery,
FTC_Cache cache )
{
FTC_SNode *psnode = (FTC_SNode*)ftcpsnode;
FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
return FTC_SNode_New( psnode, gquery, cache );
}
FT_LOCAL_DEF( FT_Offset )
ftc_snode_weight( FTC_Node ftcsnode,
FTC_Cache cache )
{
FTC_SNode snode = (FTC_SNode)ftcsnode;
FT_UInt count = snode->count;
FTC_SBit sbit = snode->sbits;
FT_Int pitch;
FT_Offset size;
FT_UNUSED( cache );
FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
/* the node itself */
size = sizeof ( *snode );
for ( ; count > 0; count--, sbit++ )
{
if ( sbit->buffer )
{
pitch = sbit->pitch;
if ( pitch < 0 )
pitch = -pitch;
/* add the size of a given glyph image */
size += (FT_Offset)pitch * sbit->height;
}
}
return size;
}
#if 0
FT_LOCAL_DEF( FT_Offset )
FTC_SNode_Weight( FTC_SNode snode )
{
return ftc_snode_weight( FTC_NODE( snode ), NULL );
}
#endif /* 0 */
FT_LOCAL_DEF( FT_Bool )
ftc_snode_compare( FTC_Node ftcsnode,
FT_Pointer ftcgquery,
FTC_Cache cache,
FT_Bool* list_changed )
{
FTC_SNode snode = (FTC_SNode)ftcsnode;
FTC_GQuery gquery = (FTC_GQuery)ftcgquery;
FTC_GNode gnode = FTC_GNODE( snode );
FT_UInt gindex = gquery->gindex;
FT_Bool result;
if ( list_changed )
*list_changed = FALSE;
result = FT_BOOL( gnode->family == gquery->family &&
gindex - gnode->gindex < snode->count );
if ( result )
{
/* check if we need to load the glyph bitmap now */
FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex );
/*
* The following code illustrates what to do when you want to
* perform operations that may fail within a lookup function.
*
* Here, we want to load a small bitmap on-demand; we thus
* need to call the `ftc_snode_load' function which may return
* a non-zero error code only when we are out of memory (OOM).
*
* The correct thing to do is to use @FTC_CACHE_TRYLOOP and
* @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
* that is capable of flushing the cache incrementally when
* an OOM errors occur.
*
* However, we need to `lock' the node before this operation to
* prevent it from being flushed within the loop.
*
* When we exit the loop, we unlock the node, then check the `error'
* variable. If it is non-zero, this means that the cache was
* completely flushed and that no usable memory was found to load
* the bitmap.
*
* We then prefer to return a value of 0 (i.e., NO MATCH). This
* ensures that the caller will try to allocate a new node.
* This operation consequently _fail_ and the lookup function
* returns the appropriate OOM error code.
*
* Note that `buffer == NULL && width == 255' is a hack used to
* tag `unavailable' bitmaps in the array. We should never try
* to load these.
*
*/
if ( !sbit->buffer && sbit->width == 255 )
{
FT_ULong size;
FT_Error error;
ftcsnode->ref_count++; /* lock node to prevent flushing */
/* in retry loop */
FTC_CACHE_TRYLOOP( cache )
{
error = ftc_snode_load( snode, cache->manager, gindex, &size );
}
FTC_CACHE_TRYLOOP_END( list_changed )
ftcsnode->ref_count--; /* unlock the node */
if ( error )
result = 0;
else
cache->manager->cur_weight += size;
}
}
return result;
}
/* END */

Some files were not shown because too many files have changed in this diff Show more